next-api-layer 0.1.6 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/api.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { S as SanitizationConfig } from './createApiClient-BliWeW4X.cjs';
2
- export { f as ApiClient, g as ApiClientConfig, s as RequestOptions, r as createApiClient } from './createApiClient-BliWeW4X.cjs';
1
+ import { S as SanitizationConfig } from './createApiClient-Brlw1L7n.cjs';
2
+ export { f as ApiClient, g as ApiClientConfig, s as RequestOptions, r as createApiClient } from './createApiClient-Brlw1L7n.cjs';
3
3
  import 'next/server';
4
4
 
5
5
  /**
package/dist/api.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { S as SanitizationConfig } from './createApiClient-BliWeW4X.js';
2
- export { f as ApiClient, g as ApiClientConfig, s as RequestOptions, r as createApiClient } from './createApiClient-BliWeW4X.js';
1
+ import { S as SanitizationConfig } from './createApiClient-Brlw1L7n.js';
2
+ export { f as ApiClient, g as ApiClientConfig, s as RequestOptions, r as createApiClient } from './createApiClient-Brlw1L7n.js';
3
3
  import 'next/server';
4
4
 
5
5
  /**
@@ -65,6 +65,11 @@ interface I18nConfig {
65
65
  enabled: boolean;
66
66
  locales?: string[];
67
67
  defaultLocale?: string;
68
+ /**
69
+ * next-intl or similar i18n middleware function
70
+ * Library will call this and merge responses to preserve headers
71
+ */
72
+ middleware?: (request: NextRequest) => NextResponse | Promise<NextResponse>;
68
73
  }
69
74
 
70
75
  /** Result of auth validation passed to afterAuth hook */
@@ -65,6 +65,11 @@ interface I18nConfig {
65
65
  enabled: boolean;
66
66
  locales?: string[];
67
67
  defaultLocale?: string;
68
+ /**
69
+ * next-intl or similar i18n middleware function
70
+ * Library will call this and merge responses to preserve headers
71
+ */
72
+ middleware?: (request: NextRequest) => NextResponse | Promise<NextResponse>;
68
73
  }
69
74
 
70
75
  /** Result of auth validation passed to afterAuth hook */
package/dist/index.cjs CHANGED
@@ -1,3 +1,3 @@
1
- 'use strict';var chunkJEEL6S4O_cjs=require('./chunk-JEEL6S4O.cjs'),chunk6ENVQMWQ_cjs=require('./chunk-6ENVQMWQ.cjs'),server=require('next/server');function ie(){return typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID()+crypto.randomUUID():`${Date.now()}-${Math.random().toString(36).substring(2)}`}function ue(e){return `rl:${e.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||e.headers.get("x-real-ip")||"unknown"}`}function Q(e){if(!e.apiBaseUrl)throw new Error("next-api-layer: apiBaseUrl is required");if(!e.cookies?.user||!e.cookies?.guest)throw new Error("next-api-layer: cookies.user and cookies.guest are required");let t=e.apiBaseUrl.endsWith("/")?e.apiBaseUrl:`${e.apiBaseUrl}/`,f={...chunk6ENVQMWQ_cjs.a,...e.cookies.options},l={...chunk6ENVQMWQ_cjs.b,...e.endpoints},m={enabled:e.csrf?.enabled??false,strategy:e.csrf?.strategy??chunk6ENVQMWQ_cjs.g.strategy,secret:e.csrf?.secret??ie(),cookieName:e.csrf?.cookieName??chunk6ENVQMWQ_cjs.g.cookieName,headerName:e.csrf?.headerName??chunk6ENVQMWQ_cjs.g.headerName,ignoreMethods:e.csrf?.ignoreMethods??chunk6ENVQMWQ_cjs.g.ignoreMethods,trustSameSite:e.csrf?.trustSameSite??chunk6ENVQMWQ_cjs.g.trustSameSite},R={enabled:e.rateLimit?.enabled??false,windowMs:e.rateLimit?.windowMs??chunk6ENVQMWQ_cjs.h.windowMs,maxRequests:e.rateLimit?.maxRequests??chunk6ENVQMWQ_cjs.h.maxRequests,keyFn:e.rateLimit?.keyFn??ue,skipRoutes:e.rateLimit?.skipRoutes??chunk6ENVQMWQ_cjs.h.skipRoutes,onRateLimited:e.rateLimit?.onRateLimited},u={enabled:e.audit?.enabled??false,events:e.audit?.events??[...chunk6ENVQMWQ_cjs.i.events],logger:e.audit?.logger};return {...e,apiBaseUrl:t,_resolved:{cookieOptions:f,endpoints:l,csrf:m,rateLimit:R,audit:u}}}var $={parseAuthMe:e=>{let t=e;return !t?.success||!t?.data?null:{isValid:true,tokenType:t.data.type||"user",exp:t.data.exp||null,userData:t.data}},parseRefreshToken:e=>{let t=e;return t?.success&&t?.data?.accessToken?t.data.accessToken:null},parseGuestToken:e=>e?.data?.accessToken||null};function j(e){let{apiBaseUrl:t,_resolved:f,responseMappers:l}=e,{endpoints:m}=f,R={parseAuthMe:l?.parseAuthMe||$.parseAuthMe,parseRefreshToken:l?.parseRefreshToken||$.parseRefreshToken,parseGuestToken:l?.parseGuestToken||$.parseGuestToken};async function u(a){let i={isValid:false,tokenType:null,exp:null,userData:null};try{let n=await fetch(`${t}${m.validate}`,{headers:{Authorization:`Bearer ${a}`,"Content-Type":"application/json"},cache:"no-store"});if(!n.ok)return i;let s=await n.json().catch(()=>null),d=R.parseAuthMe(s);return !d||!d.isValid?i:d}catch{return i}}async function c(a){return u(a)}async function p(a){try{let i=await fetch(`${t}${m.refresh}`,{method:"POST",headers:{Authorization:`Bearer ${a}`,"Content-Type":"application/json"},cache:"no-store"});if(!i.ok)return {success:!1,newToken:null};let n=await i.json().catch(()=>null),s=R.parseRefreshToken(n);return s?{success:!0,newToken:s}:{success:!1,newToken:null}}catch{return {success:false,newToken:null}}}async function o(){let a=e.guestToken;if(!a?.enabled||!a.credentials)return null;try{let i=await fetch(`${t}${m.guest}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({username:a.credentials.username,password:a.credentials.password}),cache:"no-store"});if(!i.ok)return null;let n=await i.json().catch(()=>null);return R.parseGuestToken(n)}catch{return null}}return {validateToken:u,getTokenInfo:c,refreshToken:p,createGuestToken:o}}function ee(e,t){if(!t?.enabled)return null;let f=t.locales??[],l=t.defaultLocale,R=e.split("/").filter(Boolean)[0];return R&&f.includes(R)?R:l??null}function z(e,t){let{cookies:f,guestToken:l,access:m,i18n:R,_resolved:u}=e,{cookieOptions:c}=u;function p(r,x,h){r.cookies.get(h)?.value&&x.cookies.delete(h);}function o(r,x){return p(r,x,f.guest),p(r,x,f.user),x}function a(r,x=500){return new server.NextResponse(JSON.stringify({success:false,message:r}),{status:x,headers:{"Content-Type":"application/json"}})}function i(r){return (m?.authRoutes??[]).some(h=>r===h||r.startsWith(`${h}/`))}function n(r){return m?.protectedByDefault?!s(r)&&!i(r):(m?.protectedRoutes??[]).some(h=>r===h||r.startsWith(`${h}/`))}function s(r){return (m?.publicRoutes??[]).some(h=>r===h||r.startsWith(`${h}/`))}function d(r){let x=m?.allowedTokenTypes;return !x||x.length===0?true:r?x.includes(r):false}async function C(r,x){let{origin:h}=r.nextUrl;if(l?.enabled){let y=await t.createGuestToken();if(y){let N;return x?N=server.NextResponse.next():n(r.nextUrl.pathname)?N=server.NextResponse.redirect(new URL("/login",h)):N=server.NextResponse.next(),N.cookies.set(f.guest,y,{...c,maxAge:3600}),N}}return x?a("Token bulunamad\u0131",401):n(r.nextUrl.pathname)?server.NextResponse.redirect(new URL("/login",h)):server.NextResponse.next()}async function v(r,x,h,y,N){let{pathname:k,origin:g}=r.nextUrl,{isValid:S,tokenType:T,userData:A}=x,E=T===chunk6ENVQMWQ_cjs.c.GUEST;if(!S){if(h&&y){let D=await t.refreshToken(y);if(D.success&&D.newToken){let O=await t.getTokenInfo(D.newToken);if(O.isValid){let _=new Headers(r.headers);O.userData&&_.set(chunk6ENVQMWQ_cjs.e.AUTH_USER,JSON.stringify(O.userData)),_.set(chunk6ENVQMWQ_cjs.e.REFRESHED_TOKEN,D.newToken);let Z=ee(k,R);Z&&_.set(chunk6ENVQMWQ_cjs.e.LOCALE,Z);let I;return i(k)?I=server.NextResponse.redirect(new URL("/",g)):I=server.NextResponse.next({request:{headers:_}}),I.cookies.set(f.user,D.newToken,{...c,maxAge:c.maxAge}),p(r,I,f.guest),I}}}let P=await C(r,N);return P.cookies.get(f.guest)?.value?p(r,P,f.user):o(r,P),P}let U=new Headers(r.headers);A&&U.set(chunk6ENVQMWQ_cjs.e.AUTH_USER,JSON.stringify(A));let J=ee(k,R);if(J&&U.set(chunk6ENVQMWQ_cjs.e.LOCALE,J),!E&&!d(T)){if(N){let Y=a("Bu i\u015Flem i\xE7in yetkiniz yok",403);return o(r,Y)}let P=server.NextResponse.redirect(new URL("/login",g));return o(r,P)}if(E)return N?server.NextResponse.next({request:{headers:U}}):n(k)?server.NextResponse.redirect(new URL("/login",g)):server.NextResponse.next({request:{headers:U}});if(i(k))return server.NextResponse.redirect(new URL("/",g));let X=server.NextResponse.next({request:{headers:U}});return p(r,X,f.guest),X}return {deleteAllAuthCookies:o,jsonError:a,isAuthPage:i,isProtectedRoute:n,isPublicRoute:s,isTokenTypeAllowed:d,handleNoToken:C,handleValidationResult:v}}function K(e){async function t(u){let c=le();return `${await ce(e.secret,u,c)}.${c}`}function f(u){let c=u.method.toUpperCase();if(e.ignoreMethods.includes(c))return {valid:true};let p=e.strategy;if(p==="fetch-metadata"||p==="both"){let o=l(u);if(p==="fetch-metadata"||o.valid||o.reason!=="missing-headers")return o}return p==="double-submit"||p==="both"?m(u):{valid:true}}function l(u){let c=u.headers.get("sec-fetch-site");if(!c)return {valid:false,reason:"missing-headers"};if(c==="same-origin")return {valid:true};if(c==="none"){let p=u.method.toUpperCase();return e.ignoreMethods.includes(p)?{valid:true}:{valid:false,reason:"direct-navigation-unsafe-method"}}return c==="same-site"?e.trustSameSite?{valid:true}:{valid:false,reason:"same-site-not-trusted"}:c==="cross-site"?{valid:false,reason:"cross-site-request"}:{valid:false,reason:"unknown-sec-fetch-site"}}function m(u){let c=u.cookies.get(e.cookieName)?.value;if(!c)return {valid:false,reason:"missing-cookie-token"};let p=u.headers.get(e.headerName);return p?de(c,p)?c.split(".").length!==2?{valid:false,reason:"invalid-token-format"}:{valid:true}:{valid:false,reason:"token-mismatch"}:{valid:false,reason:"missing-header-token"}}async function R(u,c){let p=await t(c);return u.cookies.set(e.cookieName,p,{httpOnly:false,secure:process.env.NODE_ENV==="production",sameSite:"strict",path:"/"}),u}return {validateRequest:f,generateToken:t,attachCsrfCookie:R}}function le(){if(typeof crypto<"u"&&crypto.getRandomValues){let e=new Uint8Array(32);return crypto.getRandomValues(e),Array.from(e,t=>t.toString(16).padStart(2,"0")).join("")}return Math.random().toString(36).substring(2)+Date.now().toString(36)}async function ce(e,t,f){let l=`${t.length}!${t}!${f.length}!${f}`;if(typeof crypto<"u"&&crypto.subtle){let u=new TextEncoder,c=u.encode(e),p=u.encode(l),o=await crypto.subtle.importKey("raw",c,{name:"HMAC",hash:"SHA-256"},false,["sign"]),a=await crypto.subtle.sign("HMAC",o,p);return Array.from(new Uint8Array(a),i=>i.toString(16).padStart(2,"0")).join("")}let m=0,R=e+l;for(let u=0;u<R.length;u++){let c=R.charCodeAt(u);m=(m<<5)-m+c,m=m&m;}return Math.abs(m).toString(16)}function de(e,t){if(e.length!==t.length)return false;let f=0;for(let l=0;l<e.length;l++)f|=e.charCodeAt(l)^t.charCodeAt(l);return f===0}function W(e){let t=new Map,f=setInterval(()=>{let a=Date.now();for(let[i,n]of t)n.resetAt<=a&&t.delete(i);},e.windowMs);typeof process<"u"&&process.on&&process.on("beforeExit",()=>clearInterval(f));function l(a){return e.skipRoutes.some(i=>i.endsWith("*")?a.startsWith(i.slice(0,-1)):i.endsWith("**")?a.startsWith(i.slice(0,-2)):a===i)}function m(a){let i=a.nextUrl.pathname;if(l(i))return {allowed:true,remaining:e.maxRequests,resetAt:0,limit:e.maxRequests};let n=e.keyFn(a),s=Date.now(),d=t.get(n);if(!d||d.resetAt<=s)return d={count:1,resetAt:s+e.windowMs},t.set(n,d),{allowed:true,remaining:e.maxRequests-1,resetAt:d.resetAt,limit:e.maxRequests};d.count++;let C=Math.max(0,e.maxRequests-d.count);return {allowed:d.count<=e.maxRequests,remaining:C,resetAt:d.resetAt,limit:e.maxRequests}}function R(a,i){return a.headers.set("X-RateLimit-Limit",i.limit.toString()),a.headers.set("X-RateLimit-Remaining",i.remaining.toString()),a.headers.set("X-RateLimit-Reset",Math.ceil(i.resetAt/1e3).toString()),a}function u(a,i){if(e.onRateLimited){let s=e.onRateLimited(a);return R(s,i)}let n=server.NextResponse.json({success:false,message:"Too many requests. Please try again later.",retryAfter:Math.ceil((i.resetAt-Date.now())/1e3)},{status:429});return n.headers.set("Retry-After",Math.ceil((i.resetAt-Date.now())/1e3).toString()),R(n,i)}function c(a){t.delete(a);}function p(){t.clear();}function o(){return t.size}return {check:m,applyHeaders:R,createLimitedResponse:u,shouldSkip:l,reset:c,clear:p,size:o}}function q(e){function t(n){return e.enabled&&e.events.includes(n)}function f(n){return n.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||n.headers.get("x-real-ip")||null}async function l(n,s,d){if(!t(n))return;let C={type:n,timestamp:new Date,ip:f(s),userId:d.userId,path:s.nextUrl.pathname,method:s.method,success:d.success,metadata:d.metadata};if(e.logger)try{await e.logger(C);}catch(v){console.error("[next-api-layer] Audit logger error:",v);}}function m(n,s,d){return l("auth:success",n,{success:true,userId:s,metadata:d})}function R(n,s){return l("auth:fail",n,{success:false,metadata:s})}function u(n,s,d){return l("auth:refresh",n,{success:true,userId:s,metadata:d})}function c(n,s){return l("auth:guest",n,{success:true,metadata:s})}function p(n,s,d){return l("access:denied",n,{success:false,userId:s,metadata:d})}function o(n,s){return l("csrf:fail",n,{success:false,metadata:s})}function a(n,s){return l("rateLimit:exceeded",n,{success:false,metadata:s})}function i(n,s,d){return l("error",n,{success:false,metadata:{...d,error:s.message,stack:s.stack}})}return {emit:l,isEnabled:t,authSuccess:m,authFail:R,authRefresh:u,authGuest:c,accessDenied:p,csrfFail:o,rateLimitExceeded:a,error:i}}function te(e){let t=Q(e),f=j(t),l=z(t,f),m=K(t._resolved.csrf),R=W(t._resolved.rateLimit),u=q(t._resolved.audit);async function c(o){let{pathname:a,origin:i}=o.nextUrl,n=a.startsWith("/api");if(t._resolved.rateLimit.enabled){let g=R.check(o);if(!g.allowed)return await u.rateLimitExceeded(o,{limit:g.limit,resetAt:g.resetAt}),R.createLimitedResponse(o,g)}if(t._resolved.csrf.enabled){let g=m.validateRequest(o);if(!g.valid)return await u.csrfFail(o,{reason:g.reason}),server.NextResponse.json({success:false,message:"CSRF validation failed"},{status:403})}if(t.blockBrowserApiAccess&&n&&(o.headers.get("accept")||"").includes("text/html"))return server.NextResponse.redirect(new URL("/",i));if(t.beforeAuth){let g=await t.beforeAuth(o);if(g)return g}if((t.excludedPaths??[]).some(g=>a.startsWith(g)))return p(o,server.NextResponse.next(),{isAuthenticated:false,isGuest:false,tokenType:null,user:null});if(["/api/auth/login","/api/auth/logout","/api/auth/me","/api/auth/refresh","/api/auth/register"].includes(a))return p(o,server.NextResponse.next(),{isAuthenticated:false,isGuest:false,tokenType:null,user:null});let C=o.cookies?.get(t.cookies.user)?.value,v=o.cookies?.get(t.cookies.guest)?.value,r=C||v,x=!!C;if(!r){await u.authFail(o,{reason:"no-token"});let g=await l.handleNoToken(o,n);return p(o,g,{isAuthenticated:false,isGuest:false,tokenType:null,user:null})}let h=await f.getTokenInfo(r),y={isAuthenticated:h.isValid&&h.tokenType!=="guest",isGuest:h.isValid&&h.tokenType==="guest",tokenType:h.tokenType,user:h.userData};if(h.isValid)if(h.tokenType==="guest")await u.authGuest(o);else {let g=h.userData?.id?.toString();await u.authSuccess(o,g,{tokenType:h.tokenType});}else await u.authFail(o,{reason:"invalid-token"});let N=await l.handleValidationResult(o,h,x,r,n),k=await p(o,N,y);if(t._resolved.csrf.enabled&&y.isAuthenticated){let g=h.userData?.id?.toString()||r.slice(0,32);k=await m.attachCsrfCookie(k,g);}if(t._resolved.rateLimit.enabled){let g=R.check(o);k=R.applyHeaders(k,g);}return k}async function p(o,a,i){return t.afterAuth?t.afterAuth(o,a,i):a}return c.config=t,c.csrf=m,c.rateLimiter=R,c.audit=u,c}function pe(e,t){if(!t||t.length===0)return false;let f=e.replace(/^\/api\//,"").replace(/^\//,"");return t.some(l=>{if(l===f)return true;if(l.includes("*")){let m=l.replace(/\*\*/g,"<<<DOUBLE>>>").replace(/\*/g,"[^/]+").replace(/<<<DOUBLE>>>/g,".+");return new RegExp(`^${m}$`).test(f)}return false})}function ne(e){let{apiBaseUrl:t,userCookieName:f="auth_token",guestCookieName:l="guest_token",skipAuthByDefault:m=false,publicEndpoints:R=[],forwardHeaders:u=["content-type","accept","accept-language","x-requested-with"],excludeHeaders:c=["host","connection","cookie"],transformRequest:p,transformResponse:o}=e,a=t.replace(/\/$/,"");function i(s,d){return s.headers.get(chunk6ENVQMWQ_cjs.e.SKIP_AUTH)==="true"||pe(d,R)?true:m}async function n(s){try{let d=new URL(s.url),C=d.pathname.replace(/^\/api\/?/,""),v=new URL(`${a}/${C}`);v.search=d.search;let r=new Headers;if(u.forEach(T=>{let A=s.headers.get(T);A&&r.set(T,A);}),s.headers.forEach((T,A)=>{let E=A.toLowerCase();!c.includes(E)&&!r.has(A)&&r.set(A,T);}),!i(s,C)){let T=s.cookies.get(f)?.value,A=s.cookies.get(l)?.value,E=T||A;E&&r.set(chunk6ENVQMWQ_cjs.e.AUTHORIZATION,`Bearer ${E}`);}r.delete(chunk6ENVQMWQ_cjs.e.SKIP_AUTH);let x=p?await p(s,r):r,h=null;if(s.method!=="GET"&&s.method!=="HEAD"){let T=s.headers.get("content-type")||"";T.includes("application/json")?h=await s.text():T.includes("multipart/form-data")?h=await s.formData():h=await s.text();}let y=await fetch(v.toString(),{method:s.method,headers:x,body:h}),N=y.headers.get("content-type")||"",k;N.includes("application/json")?k=await y.text():k=await y.arrayBuffer();let g=new Headers;y.headers.forEach((T,A)=>{let E=A.toLowerCase();["transfer-encoding","connection","keep-alive"].includes(E)||g.set(A,T);});let S=new server.NextResponse(k,{status:y.status,statusText:y.statusText,headers:g});return o&&(S=await o(S)),S}catch(d){return console.error("[Proxy Error]",d),server.NextResponse.json({success:false,message:"Proxy error: Unable to connect to backend",error:d instanceof Error?d.message:"Unknown error"},{status:502})}}return n.config=e,n}
2
- Object.defineProperty(exports,"createApiClient",{enumerable:true,get:function(){return chunkJEEL6S4O_cjs.d}});Object.defineProperty(exports,"CSRF_SAFE_METHODS",{enumerable:true,get:function(){return chunk6ENVQMWQ_cjs.f}});Object.defineProperty(exports,"DEFAULT_AUDIT_CONFIG",{enumerable:true,get:function(){return chunk6ENVQMWQ_cjs.i}});Object.defineProperty(exports,"DEFAULT_COOKIE_OPTIONS",{enumerable:true,get:function(){return chunk6ENVQMWQ_cjs.a}});Object.defineProperty(exports,"DEFAULT_CSRF_CONFIG",{enumerable:true,get:function(){return chunk6ENVQMWQ_cjs.g}});Object.defineProperty(exports,"DEFAULT_ENDPOINTS",{enumerable:true,get:function(){return chunk6ENVQMWQ_cjs.b}});Object.defineProperty(exports,"DEFAULT_RATE_LIMIT_CONFIG",{enumerable:true,get:function(){return chunk6ENVQMWQ_cjs.h}});Object.defineProperty(exports,"ERROR_MESSAGES",{enumerable:true,get:function(){return chunk6ENVQMWQ_cjs.d}});Object.defineProperty(exports,"HEADERS",{enumerable:true,get:function(){return chunk6ENVQMWQ_cjs.e}});Object.defineProperty(exports,"TOKEN_TYPES",{enumerable:true,get:function(){return chunk6ENVQMWQ_cjs.c}});exports.createAuditLogger=q;exports.createAuthProxy=te;exports.createCsrfValidator=K;exports.createHandlers=z;exports.createProxyHandler=ne;exports.createRateLimiter=W;exports.createTokenValidation=j;//# sourceMappingURL=index.cjs.map
1
+ 'use strict';var chunkJEEL6S4O_cjs=require('./chunk-JEEL6S4O.cjs'),chunk6ENVQMWQ_cjs=require('./chunk-6ENVQMWQ.cjs'),server=require('next/server');function ue(){return typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID()+crypto.randomUUID():`${Date.now()}-${Math.random().toString(36).substring(2)}`}function le(e){return `rl:${e.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||e.headers.get("x-real-ip")||"unknown"}`}function Q(e){if(!e.apiBaseUrl)throw new Error("next-api-layer: apiBaseUrl is required");if(!e.cookies?.user||!e.cookies?.guest)throw new Error("next-api-layer: cookies.user and cookies.guest are required");let t=e.apiBaseUrl.endsWith("/")?e.apiBaseUrl:`${e.apiBaseUrl}/`,f={...chunk6ENVQMWQ_cjs.a,...e.cookies.options},r={...chunk6ENVQMWQ_cjs.b,...e.endpoints},p={enabled:e.csrf?.enabled??false,strategy:e.csrf?.strategy??chunk6ENVQMWQ_cjs.g.strategy,secret:e.csrf?.secret??ue(),cookieName:e.csrf?.cookieName??chunk6ENVQMWQ_cjs.g.cookieName,headerName:e.csrf?.headerName??chunk6ENVQMWQ_cjs.g.headerName,ignoreMethods:e.csrf?.ignoreMethods??chunk6ENVQMWQ_cjs.g.ignoreMethods,trustSameSite:e.csrf?.trustSameSite??chunk6ENVQMWQ_cjs.g.trustSameSite},R={enabled:e.rateLimit?.enabled??false,windowMs:e.rateLimit?.windowMs??chunk6ENVQMWQ_cjs.h.windowMs,maxRequests:e.rateLimit?.maxRequests??chunk6ENVQMWQ_cjs.h.maxRequests,keyFn:e.rateLimit?.keyFn??le,skipRoutes:e.rateLimit?.skipRoutes??chunk6ENVQMWQ_cjs.h.skipRoutes,onRateLimited:e.rateLimit?.onRateLimited},l={enabled:e.audit?.enabled??false,events:e.audit?.events??[...chunk6ENVQMWQ_cjs.i.events],logger:e.audit?.logger};return {...e,apiBaseUrl:t,_resolved:{cookieOptions:f,endpoints:r,csrf:p,rateLimit:R,audit:l}}}var $={parseAuthMe:e=>{let t=e;return !t?.success||!t?.data?null:{isValid:true,tokenType:t.data.type||"user",exp:t.data.exp||null,userData:t.data}},parseRefreshToken:e=>{let t=e;return t?.success&&t?.data?.accessToken?t.data.accessToken:null},parseGuestToken:e=>e?.data?.accessToken||null};function j(e){let{apiBaseUrl:t,_resolved:f,responseMappers:r}=e,{endpoints:p}=f,R={parseAuthMe:r?.parseAuthMe||$.parseAuthMe,parseRefreshToken:r?.parseRefreshToken||$.parseRefreshToken,parseGuestToken:r?.parseGuestToken||$.parseGuestToken};async function l(i){let u={isValid:false,tokenType:null,exp:null,userData:null};try{let s=await fetch(`${t}${p.validate}`,{headers:{Authorization:`Bearer ${i}`,"Content-Type":"application/json"},cache:"no-store"});if(!s.ok)return u;let n=await s.json().catch(()=>null),d=R.parseAuthMe(n);return !d||!d.isValid?u:d}catch{return u}}async function c(i){return l(i)}async function m(i){try{let u=await fetch(`${t}${p.refresh}`,{method:"POST",headers:{Authorization:`Bearer ${i}`,"Content-Type":"application/json"},cache:"no-store"});if(!u.ok)return {success:!1,newToken:null};let s=await u.json().catch(()=>null),n=R.parseRefreshToken(s);return n?{success:!0,newToken:n}:{success:!1,newToken:null}}catch{return {success:false,newToken:null}}}async function a(){let i=e.guestToken;if(!i?.enabled||!i.credentials)return null;try{let u=await fetch(`${t}${p.guest}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({username:i.credentials.username,password:i.credentials.password}),cache:"no-store"});if(!u.ok)return null;let s=await u.json().catch(()=>null);return R.parseGuestToken(s)}catch{return null}}return {validateToken:l,getTokenInfo:c,refreshToken:m,createGuestToken:a}}function ee(e,t){if(!t?.enabled)return null;let f=t.locales??[],r=t.defaultLocale,R=e.split("/").filter(Boolean)[0];return R&&f.includes(R)?R:r??null}function z(e,t){let{cookies:f,guestToken:r,access:p,i18n:R,_resolved:l}=e,{cookieOptions:c}=l;function m(o,x,h){o.cookies.get(h)?.value&&x.cookies.delete(h);}function a(o,x){return m(o,x,f.guest),m(o,x,f.user),x}function i(o,x=500){return new server.NextResponse(JSON.stringify({success:false,message:o}),{status:x,headers:{"Content-Type":"application/json"}})}function u(o){return (p?.authRoutes??[]).some(h=>o===h||o.startsWith(`${h}/`))}function s(o){return p?.protectedByDefault?!n(o)&&!u(o):(p?.protectedRoutes??[]).some(h=>o===h||o.startsWith(`${h}/`))}function n(o){return (p?.publicRoutes??[]).some(h=>o===h||o.startsWith(`${h}/`))}function d(o){let x=p?.allowedTokenTypes;return !x||x.length===0?true:o?x.includes(o):false}async function N(o,x){let{origin:h}=o.nextUrl;if(r?.enabled){let y=await t.createGuestToken();if(y){let E;return x?E=server.NextResponse.next():s(o.nextUrl.pathname)?E=server.NextResponse.redirect(new URL("/login",h)):E=server.NextResponse.next(),E.cookies.set(f.guest,y,{...c,maxAge:3600}),E}}return x?i("Token bulunamad\u0131",401):s(o.nextUrl.pathname)?server.NextResponse.redirect(new URL("/login",h)):server.NextResponse.next()}async function L(o,x,h,y,E){let{pathname:k,origin:g}=o.nextUrl,{isValid:S,tokenType:A,userData:w}=x,v=A===chunk6ENVQMWQ_cjs.c.GUEST;if(!S){if(h&&y){let H=await t.refreshToken(y);if(H.success&&H.newToken){let O=await t.getTokenInfo(H.newToken);if(O.isValid){let _=new Headers(o.headers);O.userData&&_.set(chunk6ENVQMWQ_cjs.e.AUTH_USER,JSON.stringify(O.userData)),_.set(chunk6ENVQMWQ_cjs.e.REFRESHED_TOKEN,H.newToken);let Z=ee(k,R);Z&&_.set(chunk6ENVQMWQ_cjs.e.LOCALE,Z);let D;return u(k)?D=server.NextResponse.redirect(new URL("/",g)):D=server.NextResponse.next({request:{headers:_}}),D.cookies.set(f.user,H.newToken,{...c,maxAge:c.maxAge}),m(o,D,f.guest),D}}}let P=await N(o,E);return P.cookies.get(f.guest)?.value?m(o,P,f.user):a(o,P),P}let U=new Headers(o.headers);w&&U.set(chunk6ENVQMWQ_cjs.e.AUTH_USER,JSON.stringify(w));let J=ee(k,R);if(J&&U.set(chunk6ENVQMWQ_cjs.e.LOCALE,J),!v&&!d(A)){if(E){let Y=i("Bu i\u015Flem i\xE7in yetkiniz yok",403);return a(o,Y)}let P=server.NextResponse.redirect(new URL("/login",g));return a(o,P)}if(v)return E?server.NextResponse.next({request:{headers:U}}):s(k)?server.NextResponse.redirect(new URL("/login",g)):server.NextResponse.next({request:{headers:U}});if(u(k))return server.NextResponse.redirect(new URL("/",g));let X=server.NextResponse.next({request:{headers:U}});return m(o,X,f.guest),X}return {deleteAllAuthCookies:a,jsonError:i,isAuthPage:u,isProtectedRoute:s,isPublicRoute:n,isTokenTypeAllowed:d,handleNoToken:N,handleValidationResult:L}}function K(e){async function t(l){let c=ce();return `${await de(e.secret,l,c)}.${c}`}function f(l){let c=l.method.toUpperCase();if(e.ignoreMethods.includes(c))return {valid:true};let m=e.strategy;if(m==="fetch-metadata"||m==="both"){let a=r(l);if(m==="fetch-metadata"||a.valid||a.reason!=="missing-headers")return a}return m==="double-submit"||m==="both"?p(l):{valid:true}}function r(l){let c=l.headers.get("sec-fetch-site");if(!c)return {valid:false,reason:"missing-headers"};if(c==="same-origin")return {valid:true};if(c==="none"){let m=l.method.toUpperCase();return e.ignoreMethods.includes(m)?{valid:true}:{valid:false,reason:"direct-navigation-unsafe-method"}}return c==="same-site"?e.trustSameSite?{valid:true}:{valid:false,reason:"same-site-not-trusted"}:c==="cross-site"?{valid:false,reason:"cross-site-request"}:{valid:false,reason:"unknown-sec-fetch-site"}}function p(l){let c=l.cookies.get(e.cookieName)?.value;if(!c)return {valid:false,reason:"missing-cookie-token"};let m=l.headers.get(e.headerName);return m?fe(c,m)?c.split(".").length!==2?{valid:false,reason:"invalid-token-format"}:{valid:true}:{valid:false,reason:"token-mismatch"}:{valid:false,reason:"missing-header-token"}}async function R(l,c){let m=await t(c);return l.cookies.set(e.cookieName,m,{httpOnly:false,secure:process.env.NODE_ENV==="production",sameSite:"strict",path:"/"}),l}return {validateRequest:f,generateToken:t,attachCsrfCookie:R}}function ce(){if(typeof crypto<"u"&&crypto.getRandomValues){let e=new Uint8Array(32);return crypto.getRandomValues(e),Array.from(e,t=>t.toString(16).padStart(2,"0")).join("")}return Math.random().toString(36).substring(2)+Date.now().toString(36)}async function de(e,t,f){let r=`${t.length}!${t}!${f.length}!${f}`;if(typeof crypto<"u"&&crypto.subtle){let l=new TextEncoder,c=l.encode(e),m=l.encode(r),a=await crypto.subtle.importKey("raw",c,{name:"HMAC",hash:"SHA-256"},false,["sign"]),i=await crypto.subtle.sign("HMAC",a,m);return Array.from(new Uint8Array(i),u=>u.toString(16).padStart(2,"0")).join("")}let p=0,R=e+r;for(let l=0;l<R.length;l++){let c=R.charCodeAt(l);p=(p<<5)-p+c,p=p&p;}return Math.abs(p).toString(16)}function fe(e,t){if(e.length!==t.length)return false;let f=0;for(let r=0;r<e.length;r++)f|=e.charCodeAt(r)^t.charCodeAt(r);return f===0}function W(e){let t=new Map,f=setInterval(()=>{let i=Date.now();for(let[u,s]of t)s.resetAt<=i&&t.delete(u);},e.windowMs);typeof process<"u"&&process.on&&process.on("beforeExit",()=>clearInterval(f));function r(i){return e.skipRoutes.some(u=>u.endsWith("*")?i.startsWith(u.slice(0,-1)):u.endsWith("**")?i.startsWith(u.slice(0,-2)):i===u)}function p(i){let u=i.nextUrl.pathname;if(r(u))return {allowed:true,remaining:e.maxRequests,resetAt:0,limit:e.maxRequests};let s=e.keyFn(i),n=Date.now(),d=t.get(s);if(!d||d.resetAt<=n)return d={count:1,resetAt:n+e.windowMs},t.set(s,d),{allowed:true,remaining:e.maxRequests-1,resetAt:d.resetAt,limit:e.maxRequests};d.count++;let N=Math.max(0,e.maxRequests-d.count);return {allowed:d.count<=e.maxRequests,remaining:N,resetAt:d.resetAt,limit:e.maxRequests}}function R(i,u){return i.headers.set("X-RateLimit-Limit",u.limit.toString()),i.headers.set("X-RateLimit-Remaining",u.remaining.toString()),i.headers.set("X-RateLimit-Reset",Math.ceil(u.resetAt/1e3).toString()),i}function l(i,u){if(e.onRateLimited){let n=e.onRateLimited(i);return R(n,u)}let s=server.NextResponse.json({success:false,message:"Too many requests. Please try again later.",retryAfter:Math.ceil((u.resetAt-Date.now())/1e3)},{status:429});return s.headers.set("Retry-After",Math.ceil((u.resetAt-Date.now())/1e3).toString()),R(s,u)}function c(i){t.delete(i);}function m(){t.clear();}function a(){return t.size}return {check:p,applyHeaders:R,createLimitedResponse:l,shouldSkip:r,reset:c,clear:m,size:a}}function q(e){function t(s){return e.enabled&&e.events.includes(s)}function f(s){return s.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||s.headers.get("x-real-ip")||null}async function r(s,n,d){if(!t(s))return;let N={type:s,timestamp:new Date,ip:f(n),userId:d.userId,path:n.nextUrl.pathname,method:n.method,success:d.success,metadata:d.metadata};if(e.logger)try{await e.logger(N);}catch(L){console.error("[next-api-layer] Audit logger error:",L);}}function p(s,n,d){return r("auth:success",s,{success:true,userId:n,metadata:d})}function R(s,n){return r("auth:fail",s,{success:false,metadata:n})}function l(s,n,d){return r("auth:refresh",s,{success:true,userId:n,metadata:d})}function c(s,n){return r("auth:guest",s,{success:true,metadata:n})}function m(s,n,d){return r("access:denied",s,{success:false,userId:n,metadata:d})}function a(s,n){return r("csrf:fail",s,{success:false,metadata:n})}function i(s,n){return r("rateLimit:exceeded",s,{success:false,metadata:n})}function u(s,n,d){return r("error",s,{success:false,metadata:{...d,error:n.message,stack:n.stack}})}return {emit:r,isEnabled:t,authSuccess:p,authFail:R,authRefresh:l,authGuest:c,accessDenied:m,csrfFail:a,rateLimitExceeded:i,error:u}}function te(e,t){let f=[chunk6ENVQMWQ_cjs.e.LOCALE,chunk6ENVQMWQ_cjs.e.AUTH_USER,chunk6ENVQMWQ_cjs.e.REFRESHED_TOKEN];for(let r of f){let p=e.headers.get(r);p&&!t.headers.has(r)&&t.headers.set(r,p);}return e.cookies.getAll().forEach(r=>{t.cookies.get(r.name)||t.cookies.set(r.name,r.value);}),t}function se(e){let t=Q(e),f=j(t),r=z(t,f),p=K(t._resolved.csrf),R=W(t._resolved.rateLimit),l=q(t._resolved.audit);async function c(a){let{pathname:i,origin:u}=a.nextUrl,s=i.startsWith("/api");if(t._resolved.rateLimit.enabled){let g=R.check(a);if(!g.allowed)return await l.rateLimitExceeded(a,{limit:g.limit,resetAt:g.resetAt}),R.createLimitedResponse(a,g)}if(t._resolved.csrf.enabled){let g=p.validateRequest(a);if(!g.valid)return await l.csrfFail(a,{reason:g.reason}),server.NextResponse.json({success:false,message:"CSRF validation failed"},{status:403})}if(t.blockBrowserApiAccess&&s&&(a.headers.get("accept")||"").includes("text/html"))return server.NextResponse.redirect(new URL("/",u));if(t.beforeAuth){let g=await t.beforeAuth(a);if(g)return g}if((t.excludedPaths??[]).some(g=>i.startsWith(g)))return m(a,server.NextResponse.next(),{isAuthenticated:false,isGuest:false,tokenType:null,user:null});if(["/api/auth/login","/api/auth/logout","/api/auth/me","/api/auth/refresh","/api/auth/register"].includes(i))return m(a,server.NextResponse.next(),{isAuthenticated:false,isGuest:false,tokenType:null,user:null});let N=a.cookies?.get(t.cookies.user)?.value,L=a.cookies?.get(t.cookies.guest)?.value,o=N||L,x=!!N;if(!o){await l.authFail(a,{reason:"no-token"});let g=await r.handleNoToken(a,s);return m(a,g,{isAuthenticated:false,isGuest:false,tokenType:null,user:null})}let h=await f.getTokenInfo(o),y={isAuthenticated:h.isValid&&h.tokenType!=="guest",isGuest:h.isValid&&h.tokenType==="guest",tokenType:h.tokenType,user:h.userData};if(h.isValid)if(h.tokenType==="guest")await l.authGuest(a);else {let g=h.userData?.id?.toString();await l.authSuccess(a,g,{tokenType:h.tokenType});}else await l.authFail(a,{reason:"invalid-token"});let E=await r.handleValidationResult(a,h,x,o,s),k=await m(a,E,y);if(t._resolved.csrf.enabled&&y.isAuthenticated){let g=h.userData?.id?.toString()||o.slice(0,32);k=await p.attachCsrfCookie(k,g);}if(t._resolved.rateLimit.enabled){let g=R.check(a);k=R.applyHeaders(k,g);}return k}async function m(a,i,u){let s=i;if(t.i18n?.middleware){let n=await Promise.resolve(t.i18n.middleware(a));s=te(i,n);}if(t.afterAuth){let n=await t.afterAuth(a,s,u);s=te(s,n);}return s}return c.config=t,c.csrf=p,c.rateLimiter=R,c.audit=l,c}function me(e,t){if(!t||t.length===0)return false;let f=e.replace(/^\/api\//,"").replace(/^\//,"");return t.some(r=>{if(r===f)return true;if(r.includes("*")){let p=r.replace(/\*\*/g,"<<<DOUBLE>>>").replace(/\*/g,"[^/]+").replace(/<<<DOUBLE>>>/g,".+");return new RegExp(`^${p}$`).test(f)}return false})}function re(e){let{apiBaseUrl:t,userCookieName:f="auth_token",guestCookieName:r="guest_token",skipAuthByDefault:p=false,publicEndpoints:R=[],forwardHeaders:l=["content-type","accept","accept-language","x-requested-with"],excludeHeaders:c=["host","connection","cookie"],transformRequest:m,transformResponse:a}=e,i=t.replace(/\/$/,"");function u(n,d){return n.headers.get(chunk6ENVQMWQ_cjs.e.SKIP_AUTH)==="true"||me(d,R)?true:p}async function s(n){try{let d=new URL(n.url),N=d.pathname.replace(/^\/api\/?/,""),L=new URL(`${i}/${N}`);L.search=d.search;let o=new Headers;if(l.forEach(A=>{let w=n.headers.get(A);w&&o.set(A,w);}),n.headers.forEach((A,w)=>{let v=w.toLowerCase();!c.includes(v)&&!o.has(w)&&o.set(w,A);}),!u(n,N)){let A=n.cookies.get(f)?.value,w=n.cookies.get(r)?.value,v=A||w;v&&o.set(chunk6ENVQMWQ_cjs.e.AUTHORIZATION,`Bearer ${v}`);}o.delete(chunk6ENVQMWQ_cjs.e.SKIP_AUTH);let x=m?await m(n,o):o,h=null;if(n.method!=="GET"&&n.method!=="HEAD"){let A=n.headers.get("content-type")||"";A.includes("application/json")?h=await n.text():A.includes("multipart/form-data")?h=await n.formData():h=await n.text();}let y=await fetch(L.toString(),{method:n.method,headers:x,body:h}),E=y.headers.get("content-type")||"",k;E.includes("application/json")?k=await y.text():k=await y.arrayBuffer();let g=new Headers;y.headers.forEach((A,w)=>{let v=w.toLowerCase();["transfer-encoding","connection","keep-alive"].includes(v)||g.set(w,A);});let S=new server.NextResponse(k,{status:y.status,statusText:y.statusText,headers:g});return a&&(S=await a(S)),S}catch(d){return console.error("[Proxy Error]",d),server.NextResponse.json({success:false,message:"Proxy error: Unable to connect to backend",error:d instanceof Error?d.message:"Unknown error"},{status:502})}}return s.config=e,s}
2
+ Object.defineProperty(exports,"createApiClient",{enumerable:true,get:function(){return chunkJEEL6S4O_cjs.d}});Object.defineProperty(exports,"CSRF_SAFE_METHODS",{enumerable:true,get:function(){return chunk6ENVQMWQ_cjs.f}});Object.defineProperty(exports,"DEFAULT_AUDIT_CONFIG",{enumerable:true,get:function(){return chunk6ENVQMWQ_cjs.i}});Object.defineProperty(exports,"DEFAULT_COOKIE_OPTIONS",{enumerable:true,get:function(){return chunk6ENVQMWQ_cjs.a}});Object.defineProperty(exports,"DEFAULT_CSRF_CONFIG",{enumerable:true,get:function(){return chunk6ENVQMWQ_cjs.g}});Object.defineProperty(exports,"DEFAULT_ENDPOINTS",{enumerable:true,get:function(){return chunk6ENVQMWQ_cjs.b}});Object.defineProperty(exports,"DEFAULT_RATE_LIMIT_CONFIG",{enumerable:true,get:function(){return chunk6ENVQMWQ_cjs.h}});Object.defineProperty(exports,"ERROR_MESSAGES",{enumerable:true,get:function(){return chunk6ENVQMWQ_cjs.d}});Object.defineProperty(exports,"HEADERS",{enumerable:true,get:function(){return chunk6ENVQMWQ_cjs.e}});Object.defineProperty(exports,"TOKEN_TYPES",{enumerable:true,get:function(){return chunk6ENVQMWQ_cjs.c}});exports.createAuditLogger=q;exports.createAuthProxy=se;exports.createCsrfValidator=K;exports.createHandlers=z;exports.createProxyHandler=re;exports.createRateLimiter=W;exports.createTokenValidation=j;//# sourceMappingURL=index.cjs.map
3
3
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/shared/config.ts","../src/proxy/tokenValidation.ts","../src/proxy/handlers.ts","../src/proxy/csrf.ts","../src/proxy/rateLimit.ts","../src/proxy/audit.ts","../src/proxy/createAuthProxy.ts","../src/proxy/createProxyHandler.ts"],"names":["generateCsrfSecret","defaultRateLimitKeyFn","req","resolveProxyConfig","config","apiBaseUrl","cookieOptions","DEFAULT_COOKIE_OPTIONS","endpoints","DEFAULT_ENDPOINTS","csrf","DEFAULT_CSRF_CONFIG","rateLimit","DEFAULT_RATE_LIMIT_CONFIG","audit","DEFAULT_AUDIT_CONFIG","defaultMappers","response","res","createTokenValidation","_resolved","responseMappers","mappers","validateToken","token","invalidResult","rawResponse","parsed","getTokenInfo","refreshToken","oldToken","newToken","createGuestToken","guestConfig","extractLocale","pathname","i18n","locales","defaultLocale","firstSegment","createHandlers","validation","cookies","guestToken","access","safeDeleteCookie","cookieName","deleteAllAuthCookies","jsonError","message","status","NextResponse","isAuthPage","route","isProtectedRoute","isPublicRoute","isTokenTypeAllowed","tokenType","allowedTypes","handleNoToken","isApiRoute","origin","guestAccessToken","handleValidationResult","tokenInfo","isUserToken","currentToken","isValid","userData","isGuest","TOKEN_TYPES","refreshResult","newTokenInfo","requestHeaders","HEADERS","locale","createCsrfValidator","generateToken","sessionId","randomValue","generateRandomValue","computeHmac","validateRequest","method","strategy","fetchResult","validateFetchMetadata","validateDoubleSubmit","secFetchSite","cookieToken","headerToken","constantTimeEqual","attachCsrfCookie","array","b","secret","encoder","keyData","messageData","key","signature","hash","str","i","char","a","result","createRateLimiter","store","cleanupInterval","now","entry","shouldSkip","pattern","check","remaining","applyHeaders","createLimitedResponse","reset","clear","size","createAuditLogger","isEnabled","type","getIp","emit","options","event","error","authSuccess","userId","metadata","authFail","authRefresh","authGuest","accessDenied","csrfFail","rateLimitExceeded","err","createAuthProxy","userConfig","handlers","rateLimiter","authProxy","rateLimitResult","csrfResult","beforeResult","path","applyAfterAuth","userToken","authResult","finalResponse","matchesPattern","endpoint","patterns","normalizedEndpoint","regexPattern","createProxyHandler","userCookieName","guestCookieName","skipAuthByDefault","publicEndpoints","forwardHeaders","excludeHeaders","transformRequest","transformResponse","baseUrl","shouldSkipAuth","handler","url","backendUrl","headers","headerName","value","lowerKey","finalHeaders","body","contentType","backendResponse","responseBody","responseHeaders"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\r\n * Config Resolver\r\n * Resolves and validates configuration with defaults\r\n */\r\n\r\nimport type { NextRequest } from 'next/server';\r\nimport type {\r\n AuthProxyConfig,\r\n InternalProxyConfig,\r\n ApiClientConfig,\r\n ResolvedCookieOptions,\r\n EndpointConfig,\r\n ResolvedCsrfConfig,\r\n ResolvedRateLimitConfig,\r\n ResolvedAuditConfig,\r\n AuditEventType,\r\n} from './types';\r\n\r\nimport {\r\n DEFAULT_COOKIE_OPTIONS,\r\n DEFAULT_ENDPOINTS,\r\n DEFAULT_CSRF_CONFIG,\r\n DEFAULT_RATE_LIMIT_CONFIG,\r\n DEFAULT_AUDIT_CONFIG,\r\n} from './constants';\r\n\r\n/**\r\n * Generates a random secret for CSRF HMAC signing\r\n */\r\nfunction generateCsrfSecret(): string {\r\n // Use crypto if available (Node.js)\r\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\r\n return crypto.randomUUID() + crypto.randomUUID();\r\n }\r\n // Fallback: timestamp + random\r\n return `${Date.now()}-${Math.random().toString(36).substring(2)}`;\r\n}\r\n\r\n/**\r\n * Default rate limit key function (IP-based)\r\n */\r\nfunction defaultRateLimitKeyFn(req: NextRequest): string {\r\n const forwarded = req.headers.get('x-forwarded-for');\r\n const ip = forwarded?.split(',')[0]?.trim() || \r\n req.headers.get('x-real-ip') || \r\n 'unknown';\r\n return `rl:${ip}`;\r\n}\r\n\r\n/**\r\n * Resolves proxy configuration with defaults\r\n */\r\nexport function resolveProxyConfig(config: AuthProxyConfig): InternalProxyConfig {\r\n // Validate required fields\r\n if (!config.apiBaseUrl) {\r\n throw new Error('next-api-layer: apiBaseUrl is required');\r\n }\r\n \r\n if (!config.cookies?.user || !config.cookies?.guest) {\r\n throw new Error('next-api-layer: cookies.user and cookies.guest are required');\r\n }\r\n\r\n // Ensure apiBaseUrl ends with /\r\n const apiBaseUrl = config.apiBaseUrl.endsWith('/')\r\n ? config.apiBaseUrl\r\n : `${config.apiBaseUrl}/`;\r\n\r\n // Resolve cookie options\r\n const cookieOptions: ResolvedCookieOptions = {\r\n ...DEFAULT_COOKIE_OPTIONS,\r\n ...config.cookies.options,\r\n };\r\n\r\n // Resolve endpoints\r\n const endpoints: Required<EndpointConfig> = {\r\n ...DEFAULT_ENDPOINTS,\r\n ...config.endpoints,\r\n };\r\n\r\n // Resolve CSRF config\r\n const csrf: ResolvedCsrfConfig = {\r\n enabled: config.csrf?.enabled ?? false,\r\n strategy: config.csrf?.strategy ?? DEFAULT_CSRF_CONFIG.strategy,\r\n secret: config.csrf?.secret ?? generateCsrfSecret(),\r\n cookieName: config.csrf?.cookieName ?? DEFAULT_CSRF_CONFIG.cookieName,\r\n headerName: config.csrf?.headerName ?? DEFAULT_CSRF_CONFIG.headerName,\r\n ignoreMethods: config.csrf?.ignoreMethods ?? DEFAULT_CSRF_CONFIG.ignoreMethods,\r\n trustSameSite: config.csrf?.trustSameSite ?? DEFAULT_CSRF_CONFIG.trustSameSite,\r\n };\r\n\r\n // Resolve rate limit config\r\n const rateLimit: ResolvedRateLimitConfig = {\r\n enabled: config.rateLimit?.enabled ?? false,\r\n windowMs: config.rateLimit?.windowMs ?? DEFAULT_RATE_LIMIT_CONFIG.windowMs,\r\n maxRequests: config.rateLimit?.maxRequests ?? DEFAULT_RATE_LIMIT_CONFIG.maxRequests,\r\n keyFn: config.rateLimit?.keyFn ?? defaultRateLimitKeyFn,\r\n skipRoutes: config.rateLimit?.skipRoutes ?? DEFAULT_RATE_LIMIT_CONFIG.skipRoutes,\r\n onRateLimited: config.rateLimit?.onRateLimited,\r\n };\r\n\r\n // Resolve audit config\r\n const audit: ResolvedAuditConfig = {\r\n enabled: config.audit?.enabled ?? false,\r\n events: config.audit?.events ?? [...DEFAULT_AUDIT_CONFIG.events] as AuditEventType[],\r\n logger: config.audit?.logger,\r\n };\r\n\r\n return {\r\n ...config,\r\n apiBaseUrl,\r\n _resolved: {\r\n cookieOptions,\r\n endpoints,\r\n csrf,\r\n rateLimit,\r\n audit,\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Resolves API client configuration with defaults\r\n */\r\nexport function resolveApiClientConfig(config: ApiClientConfig = {}) {\r\n return {\r\n sanitization: {\r\n enabled: config.sanitization?.enabled ?? true,\r\n allowedTags: config.sanitization?.allowedTags,\r\n skipFields: config.sanitization?.skipFields ?? [],\r\n skipEndpoints: config.sanitization?.skipEndpoints ?? [],\r\n },\r\n i18n: {\r\n enabled: config.i18n?.enabled ?? false,\r\n paramName: config.i18n?.paramName ?? 'lang',\r\n locales: config.i18n?.locales ?? [],\r\n defaultLocale: config.i18n?.defaultLocale ?? 'en',\r\n },\r\n auth: {\r\n skipByDefault: config.auth?.skipByDefault ?? false,\r\n publicEndpoints: config.auth?.publicEndpoints ?? [],\r\n },\r\n methodSpoofing: config.methodSpoofing ?? false,\r\n errorMessages: {\r\n noToken: config.errorMessages?.noToken ?? 'Token bulunamadı.',\r\n connectionError: config.errorMessages?.connectionError ?? 'Bağlantı hatası oluştu.',\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Type guard to check if a value is defined\r\n */\r\nexport function isDefined<T>(value: T | undefined | null): value is T {\r\n return value !== undefined && value !== null;\r\n}\r\n","/**\r\n * Token Validation\r\n * Handles token validation and refresh with backend API\r\n */\r\n\r\nimport type { \r\n TokenInfo, \r\n RefreshResult, \r\n AuthMeResponse, \r\n GuestTokenResponse,\r\n InternalProxyConfig,\r\n ResponseMappers,\r\n} from '../shared/types';\r\n\r\n/**\r\n * Default response parsers (standard format)\r\n */\r\nconst defaultMappers: Required<ResponseMappers> = {\r\n // Default: { success: true, data: { type, exp, ...user } }\r\n parseAuthMe: (response: unknown): TokenInfo | null => {\r\n const res = response as AuthMeResponse | null;\r\n if (!res?.success || !res?.data) {\r\n return null;\r\n }\r\n return {\r\n isValid: true,\r\n tokenType: res.data.type || 'user',\r\n exp: res.data.exp || null,\r\n userData: res.data,\r\n };\r\n },\r\n \r\n // Default: { success: true, data: { accessToken } }\r\n parseRefreshToken: (response: unknown): string | null => {\r\n const res = response as GuestTokenResponse | null;\r\n return res?.success && res?.data?.accessToken ? res.data.accessToken : null;\r\n },\r\n \r\n // Default: { success: true, data: { accessToken } }\r\n parseGuestToken: (response: unknown): string | null => {\r\n const res = response as GuestTokenResponse | null;\r\n return res?.data?.accessToken || null;\r\n },\r\n};\r\n\r\n/**\r\n * Creates token validation functions\r\n */\r\nexport function createTokenValidation(\r\n config: InternalProxyConfig\r\n) {\r\n const { apiBaseUrl, _resolved, responseMappers } = config;\r\n const { endpoints } = _resolved;\r\n \r\n // Merge custom mappers with defaults\r\n const mappers: Required<ResponseMappers> = {\r\n parseAuthMe: responseMappers?.parseAuthMe || defaultMappers.parseAuthMe,\r\n parseRefreshToken: responseMappers?.parseRefreshToken || defaultMappers.parseRefreshToken,\r\n parseGuestToken: responseMappers?.parseGuestToken || defaultMappers.parseGuestToken,\r\n };\r\n\r\n /**\r\n * Validates a token against the backend\r\n */\r\n async function validateToken(token: string): Promise<TokenInfo> {\r\n const invalidResult: TokenInfo = { isValid: false, tokenType: null, exp: null, userData: null };\r\n \r\n try {\r\n const res = await fetch(`${apiBaseUrl}${endpoints.validate}`, {\r\n headers: {\r\n 'Authorization': `Bearer ${token}`,\r\n 'Content-Type': 'application/json',\r\n },\r\n cache: 'no-store',\r\n });\r\n\r\n if (!res.ok) {\r\n return invalidResult;\r\n }\r\n\r\n const rawResponse: unknown = await res.json().catch(() => null);\r\n \r\n // Use custom or default mapper\r\n const parsed = mappers.parseAuthMe(rawResponse);\r\n \r\n if (!parsed || !parsed.isValid) {\r\n return invalidResult;\r\n }\r\n\r\n return parsed;\r\n } catch {\r\n return invalidResult;\r\n }\r\n }\r\n\r\n /**\r\n * Gets token info (validates with backend)\r\n */\r\n async function getTokenInfo(token: string): Promise<TokenInfo> {\r\n return validateToken(token);\r\n }\r\n\r\n /**\r\n * Refreshes a token\r\n */\r\n async function refreshToken(oldToken: string): Promise<RefreshResult> {\r\n try {\r\n const res = await fetch(`${apiBaseUrl}${endpoints.refresh}`, {\r\n method: 'POST',\r\n headers: {\r\n 'Authorization': `Bearer ${oldToken}`,\r\n 'Content-Type': 'application/json',\r\n },\r\n cache: 'no-store',\r\n });\r\n\r\n if (!res.ok) {\r\n return { success: false, newToken: null };\r\n }\r\n\r\n const rawResponse: unknown = await res.json().catch(() => null);\r\n \r\n // Use custom or default mapper\r\n const newToken = mappers.parseRefreshToken(rawResponse);\r\n\r\n if (!newToken) {\r\n return { success: false, newToken: null };\r\n }\r\n\r\n return { success: true, newToken };\r\n } catch {\r\n return { success: false, newToken: null };\r\n }\r\n }\r\n\r\n /**\r\n * Creates a guest token\r\n */\r\n async function createGuestToken(): Promise<string | null> {\r\n const guestConfig = config.guestToken;\r\n \r\n if (!guestConfig?.enabled || !guestConfig.credentials) {\r\n return null;\r\n }\r\n\r\n try {\r\n const res = await fetch(`${apiBaseUrl}${endpoints.guest}`, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({\r\n username: guestConfig.credentials.username,\r\n password: guestConfig.credentials.password,\r\n }),\r\n cache: 'no-store',\r\n });\r\n\r\n if (!res.ok) {\r\n return null;\r\n }\r\n\r\n const rawResponse: unknown = await res.json().catch(() => null);\r\n \r\n // Use custom or default mapper\r\n return mappers.parseGuestToken(rawResponse);\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n return {\r\n validateToken,\r\n getTokenInfo,\r\n refreshToken,\r\n createGuestToken,\r\n };\r\n}\r\n\r\nexport type TokenValidation = ReturnType<typeof createTokenValidation>;\r\n","/**\r\n * Proxy Handlers\r\n * Request handling logic for different scenarios\r\n */\r\n\r\nimport { NextRequest, NextResponse } from 'next/server';\r\nimport type { InternalProxyConfig, TokenInfo } from '../shared/types';\r\nimport { HEADERS, TOKEN_TYPES } from '../shared/constants';\r\nimport type { TokenValidation } from './tokenValidation';\r\n\r\n/**\r\n * Extracts locale from pathname based on i18n config\r\n * e.g., /en/dashboard → 'en', /dashboard → defaultLocale or null\r\n */\r\nfunction extractLocale(pathname: string, i18n?: InternalProxyConfig['i18n']): string | null {\r\n if (!i18n?.enabled) return null;\r\n \r\n const locales = i18n.locales ?? [];\r\n const defaultLocale = i18n.defaultLocale;\r\n \r\n // Extract first path segment\r\n const segments = pathname.split('/').filter(Boolean);\r\n const firstSegment = segments[0];\r\n \r\n // Check if it's a valid locale\r\n if (firstSegment && locales.includes(firstSegment)) {\r\n return firstSegment;\r\n }\r\n \r\n // Return default locale if provided\r\n return defaultLocale ?? null;\r\n}\r\n\r\n/**\r\n * Creates proxy handlers\r\n */\r\nexport function createHandlers(\r\n config: InternalProxyConfig,\r\n validation: TokenValidation\r\n) {\r\n const { cookies, guestToken, access, i18n, _resolved } = config;\r\n const { cookieOptions } = _resolved;\r\n\r\n /**\r\n * Safely deletes a cookie only if it exists in the request.\r\n * Prevents empty-value cookies from being created when deleting non-existent cookies.\r\n */\r\n function safeDeleteCookie(req: NextRequest, response: NextResponse, cookieName: string): void {\r\n if (req.cookies.get(cookieName)?.value) {\r\n response.cookies.delete(cookieName);\r\n }\r\n }\r\n\r\n /**\r\n * Deletes all auth cookies from response (only if they exist)\r\n */\r\n function deleteAllAuthCookies(req: NextRequest, response: NextResponse): NextResponse {\r\n safeDeleteCookie(req, response, cookies.guest);\r\n safeDeleteCookie(req, response, cookies.user);\r\n return response;\r\n }\r\n\r\n /**\r\n * Creates a JSON error response\r\n */\r\n function jsonError(message: string, status = 500): NextResponse {\r\n return new NextResponse(\r\n JSON.stringify({ success: false, message }),\r\n { status, headers: { 'Content-Type': 'application/json' } }\r\n );\r\n }\r\n\r\n /**\r\n * Checks if pathname is an auth page\r\n */\r\n function isAuthPage(pathname: string): boolean {\r\n const authRoutes = access?.authRoutes ?? [];\r\n return authRoutes.some(route => \r\n pathname === route || pathname.startsWith(`${route}/`)\r\n );\r\n }\r\n\r\n /**\r\n * Checks if pathname is a protected route\r\n */\r\n function isProtectedRoute(pathname: string): boolean {\r\n // If protectedByDefault is true, everything is protected except public/auth routes\r\n if (access?.protectedByDefault) {\r\n return !isPublicRoute(pathname) && !isAuthPage(pathname);\r\n }\r\n \r\n const protectedRoutes = access?.protectedRoutes ?? [];\r\n return protectedRoutes.some(route => \r\n pathname === route || pathname.startsWith(`${route}/`)\r\n );\r\n }\r\n\r\n /**\r\n * Checks if pathname is explicitly public\r\n */\r\n function isPublicRoute(pathname: string): boolean {\r\n const publicRoutes = access?.publicRoutes ?? [];\r\n return publicRoutes.some(route => \r\n pathname === route || pathname.startsWith(`${route}/`)\r\n );\r\n }\r\n\r\n /**\r\n * Checks if token type is allowed\r\n */\r\n function isTokenTypeAllowed(tokenType: string | null): boolean {\r\n const allowedTypes = access?.allowedTokenTypes;\r\n \r\n // If no restriction, all types allowed\r\n if (!allowedTypes || allowedTypes.length === 0) {\r\n return true;\r\n }\r\n \r\n return tokenType ? allowedTypes.includes(tokenType) : false;\r\n }\r\n\r\n /**\r\n * Handles request when no token is present\r\n */\r\n async function handleNoToken(\r\n req: NextRequest,\r\n isApiRoute: boolean\r\n ): Promise<NextResponse> {\r\n const { origin } = req.nextUrl;\r\n \r\n // Try to create guest token\r\n if (guestToken?.enabled) {\r\n const guestAccessToken = await validation.createGuestToken();\r\n \r\n if (guestAccessToken) {\r\n let response: NextResponse;\r\n \r\n if (isApiRoute) {\r\n response = NextResponse.next();\r\n } else if (isProtectedRoute(req.nextUrl.pathname)) {\r\n // Redirect to login if protected route\r\n response = NextResponse.redirect(new URL('/login', origin));\r\n } else {\r\n response = NextResponse.next();\r\n }\r\n \r\n response.cookies.set(cookies.guest, guestAccessToken, {\r\n ...cookieOptions,\r\n maxAge: 3600, // 1 hour default for guest tokens\r\n });\r\n \r\n return response;\r\n }\r\n }\r\n \r\n // No guest token - just continue or redirect\r\n if (isApiRoute) {\r\n return jsonError('Token bulunamadı', 401);\r\n }\r\n \r\n if (isProtectedRoute(req.nextUrl.pathname)) {\r\n return NextResponse.redirect(new URL('/login', origin));\r\n }\r\n \r\n return NextResponse.next();\r\n }\r\n\r\n /**\r\n * Handles token validation result\r\n */\r\n async function handleValidationResult(\r\n req: NextRequest,\r\n tokenInfo: TokenInfo,\r\n isUserToken: boolean,\r\n currentToken: string,\r\n isApiRoute: boolean\r\n ): Promise<NextResponse> {\r\n const { pathname, origin } = req.nextUrl;\r\n const { isValid, tokenType, userData } = tokenInfo;\r\n const isGuest = tokenType === TOKEN_TYPES.GUEST;\r\n\r\n // ===== TOKEN INVALID =====\r\n if (!isValid) {\r\n // Try refresh if user token\r\n if (isUserToken && currentToken) {\r\n const refreshResult = await validation.refreshToken(currentToken);\r\n \r\n if (refreshResult.success && refreshResult.newToken) {\r\n const newTokenInfo = await validation.getTokenInfo(refreshResult.newToken);\r\n \r\n if (newTokenInfo.isValid) {\r\n // Successful refresh\r\n const requestHeaders = new Headers(req.headers);\r\n \r\n if (newTokenInfo.userData) {\r\n requestHeaders.set(HEADERS.AUTH_USER, JSON.stringify(newTokenInfo.userData));\r\n }\r\n requestHeaders.set(HEADERS.REFRESHED_TOKEN, refreshResult.newToken);\r\n \r\n // Set locale header if i18n is enabled\r\n const locale = extractLocale(pathname, i18n);\r\n if (locale) {\r\n requestHeaders.set(HEADERS.LOCALE, locale);\r\n }\r\n\r\n let response: NextResponse;\r\n \r\n if (isAuthPage(pathname)) {\r\n response = NextResponse.redirect(new URL('/', origin));\r\n } else {\r\n response = NextResponse.next({ request: { headers: requestHeaders } });\r\n }\r\n\r\n response.cookies.set(cookies.user, refreshResult.newToken, {\r\n ...cookieOptions,\r\n maxAge: cookieOptions.maxAge,\r\n });\r\n safeDeleteCookie(req, response, cookies.guest);\r\n\r\n return response;\r\n }\r\n }\r\n }\r\n\r\n // Refresh failed or no user token - handle as no token\r\n const response = await handleNoToken(req, isApiRoute);\r\n \r\n // Check if handleNoToken created a new guest token\r\n const hasNewGuestToken = response.cookies.get(cookies.guest)?.value;\r\n \r\n if (!hasNewGuestToken) {\r\n // No new guest token created - delete all auth cookies\r\n deleteAllAuthCookies(req, response);\r\n } else {\r\n // New guest token created - only delete the invalid user cookie\r\n safeDeleteCookie(req, response, cookies.user);\r\n }\r\n \r\n return response;\r\n }\r\n\r\n // ===== TOKEN VALID =====\r\n const requestHeaders = new Headers(req.headers);\r\n \r\n if (userData) {\r\n requestHeaders.set(HEADERS.AUTH_USER, JSON.stringify(userData));\r\n }\r\n \r\n // Set locale header if i18n is enabled\r\n const locale = extractLocale(pathname, i18n);\r\n if (locale) {\r\n requestHeaders.set(HEADERS.LOCALE, locale);\r\n }\r\n\r\n // Check if token type is allowed\r\n if (!isGuest && !isTokenTypeAllowed(tokenType)) {\r\n if (isApiRoute) {\r\n const response = jsonError('Bu işlem için yetkiniz yok', 403);\r\n return deleteAllAuthCookies(req, response);\r\n }\r\n \r\n const response = NextResponse.redirect(new URL('/login', origin));\r\n return deleteAllAuthCookies(req, response);\r\n }\r\n\r\n // Guest token handling\r\n if (isGuest) {\r\n if (isApiRoute) {\r\n return NextResponse.next({ request: { headers: requestHeaders } });\r\n }\r\n\r\n // Protected routes require login\r\n if (isProtectedRoute(pathname)) {\r\n return NextResponse.redirect(new URL('/login', origin));\r\n }\r\n\r\n return NextResponse.next({ request: { headers: requestHeaders } });\r\n }\r\n\r\n // User token - block auth pages\r\n if (isAuthPage(pathname)) {\r\n return NextResponse.redirect(new URL('/', origin));\r\n }\r\n\r\n // Normal access\r\n const response = NextResponse.next({ request: { headers: requestHeaders } });\r\n safeDeleteCookie(req, response, cookies.guest);\r\n \r\n return response;\r\n }\r\n\r\n return {\r\n deleteAllAuthCookies,\r\n jsonError,\r\n isAuthPage,\r\n isProtectedRoute,\r\n isPublicRoute,\r\n isTokenTypeAllowed,\r\n handleNoToken,\r\n handleValidationResult,\r\n };\r\n}\r\n\r\nexport type Handlers = ReturnType<typeof createHandlers>;\r\n","/**\r\n * CSRF Protection\r\n * \r\n * Implements OWASP recommended CSRF protection:\r\n * - Fetch Metadata (Sec-Fetch-Site header) for modern browsers (98%+ coverage)\r\n * - Signed HMAC Double-Submit Cookie as fallback\r\n * \r\n * @see https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html\r\n */\r\n\r\nimport { NextRequest, NextResponse } from 'next/server';\r\nimport type { ResolvedCsrfConfig } from '../shared/types';\r\n\r\nexport interface CsrfValidationResult {\r\n valid: boolean;\r\n reason?: string;\r\n}\r\n\r\n/**\r\n * Creates CSRF validator functions\r\n */\r\nexport function createCsrfValidator(config: ResolvedCsrfConfig) {\r\n /**\r\n * Generate HMAC-signed CSRF token\r\n * Format: hmac.randomValue\r\n */\r\n async function generateToken(sessionId: string): Promise<string> {\r\n const randomValue = generateRandomValue();\r\n const hmac = await computeHmac(config.secret, sessionId, randomValue);\r\n return `${hmac}.${randomValue}`;\r\n }\r\n\r\n /**\r\n * Validate CSRF request using configured strategy\r\n */\r\n function validateRequest(req: NextRequest): CsrfValidationResult {\r\n const method = req.method.toUpperCase();\r\n \r\n // Skip safe methods\r\n if (config.ignoreMethods.includes(method)) {\r\n return { valid: true };\r\n }\r\n\r\n const strategy = config.strategy;\r\n \r\n // Fetch Metadata validation (primary, modern browsers)\r\n if (strategy === 'fetch-metadata' || strategy === 'both') {\r\n const fetchResult = validateFetchMetadata(req);\r\n \r\n if (strategy === 'fetch-metadata') {\r\n return fetchResult;\r\n }\r\n \r\n // 'both' strategy: if Fetch Metadata passes, we're good\r\n if (fetchResult.valid) {\r\n return fetchResult;\r\n }\r\n \r\n // 'both' strategy: if Fetch Metadata fails or not available, try double-submit\r\n if (fetchResult.reason === 'missing-headers') {\r\n // Fall through to double-submit\r\n } else {\r\n // Explicit cross-site rejection from Fetch Metadata\r\n return fetchResult;\r\n }\r\n }\r\n\r\n // Double-Submit Cookie validation (fallback)\r\n if (strategy === 'double-submit' || strategy === 'both') {\r\n return validateDoubleSubmit(req);\r\n }\r\n\r\n return { valid: true };\r\n }\r\n\r\n /**\r\n * Validate using Fetch Metadata headers (Sec-Fetch-Site)\r\n * @see https://web.dev/fetch-metadata/\r\n */\r\n function validateFetchMetadata(req: NextRequest): CsrfValidationResult {\r\n const secFetchSite = req.headers.get('sec-fetch-site');\r\n \r\n // No Fetch Metadata headers (older browser or stripped by proxy)\r\n if (!secFetchSite) {\r\n return { valid: false, reason: 'missing-headers' };\r\n }\r\n\r\n // Same-origin requests are always trusted\r\n if (secFetchSite === 'same-origin') {\r\n return { valid: true };\r\n }\r\n\r\n // None = direct navigation (bookmark, typed URL) - allow for GET\r\n if (secFetchSite === 'none') {\r\n const method = req.method.toUpperCase();\r\n if (config.ignoreMethods.includes(method)) {\r\n return { valid: true };\r\n }\r\n // Non-safe method from direct navigation is suspicious\r\n return { valid: false, reason: 'direct-navigation-unsafe-method' };\r\n }\r\n\r\n // Same-site: trust based on config\r\n if (secFetchSite === 'same-site') {\r\n if (config.trustSameSite) {\r\n return { valid: true };\r\n }\r\n // Conservative: don't trust same-site by default (subdomain takeover risk)\r\n return { valid: false, reason: 'same-site-not-trusted' };\r\n }\r\n\r\n // Cross-site: reject state-changing requests\r\n if (secFetchSite === 'cross-site') {\r\n return { valid: false, reason: 'cross-site-request' };\r\n }\r\n\r\n // Unknown value - be conservative\r\n return { valid: false, reason: 'unknown-sec-fetch-site' };\r\n }\r\n\r\n /**\r\n * Validate using Double-Submit Cookie pattern with HMAC\r\n */\r\n function validateDoubleSubmit(req: NextRequest): CsrfValidationResult {\r\n // Get token from cookie\r\n const cookieToken = req.cookies.get(config.cookieName)?.value;\r\n \r\n if (!cookieToken) {\r\n return { valid: false, reason: 'missing-cookie-token' };\r\n }\r\n\r\n // Get token from header (or form field)\r\n const headerToken = req.headers.get(config.headerName);\r\n \r\n if (!headerToken) {\r\n return { valid: false, reason: 'missing-header-token' };\r\n }\r\n\r\n // Tokens must match (constant-time comparison to prevent timing attacks)\r\n if (!constantTimeEqual(cookieToken, headerToken)) {\r\n return { valid: false, reason: 'token-mismatch' };\r\n }\r\n\r\n // Validate HMAC structure\r\n const parts = cookieToken.split('.');\r\n if (parts.length !== 2) {\r\n return { valid: false, reason: 'invalid-token-format' };\r\n }\r\n\r\n return { valid: true };\r\n }\r\n\r\n /**\r\n * Create response with CSRF cookie set\r\n */\r\n async function attachCsrfCookie(\r\n response: NextResponse, \r\n sessionId: string\r\n ): Promise<NextResponse> {\r\n const token = await generateToken(sessionId);\r\n \r\n response.cookies.set(config.cookieName, token, {\r\n httpOnly: false, // Must be readable by JS\r\n secure: process.env.NODE_ENV === 'production',\r\n sameSite: 'strict',\r\n path: '/',\r\n });\r\n\r\n return response;\r\n }\r\n\r\n return {\r\n validateRequest,\r\n generateToken,\r\n attachCsrfCookie,\r\n };\r\n}\r\n\r\n// ==================== Helper Functions ====================\r\n\r\n/**\r\n * Generate cryptographically random value\r\n */\r\nfunction generateRandomValue(): string {\r\n if (typeof crypto !== 'undefined' && crypto.getRandomValues) {\r\n const array = new Uint8Array(32);\r\n crypto.getRandomValues(array);\r\n return Array.from(array, b => b.toString(16).padStart(2, '0')).join('');\r\n }\r\n // Fallback (less secure, for edge cases)\r\n return Math.random().toString(36).substring(2) + Date.now().toString(36);\r\n}\r\n\r\n/**\r\n * Compute HMAC-SHA256\r\n */\r\nasync function computeHmac(\r\n secret: string, \r\n sessionId: string, \r\n randomValue: string\r\n): Promise<string> {\r\n const message = `${sessionId.length}!${sessionId}!${randomValue.length}!${randomValue}`;\r\n \r\n if (typeof crypto !== 'undefined' && crypto.subtle) {\r\n const encoder = new TextEncoder();\r\n const keyData = encoder.encode(secret);\r\n const messageData = encoder.encode(message);\r\n \r\n const key = await crypto.subtle.importKey(\r\n 'raw',\r\n keyData,\r\n { name: 'HMAC', hash: 'SHA-256' },\r\n false,\r\n ['sign']\r\n );\r\n \r\n const signature = await crypto.subtle.sign('HMAC', key, messageData);\r\n return Array.from(new Uint8Array(signature), b => \r\n b.toString(16).padStart(2, '0')\r\n ).join('');\r\n }\r\n \r\n // Fallback (less secure)\r\n let hash = 0;\r\n const str = secret + message;\r\n for (let i = 0; i < str.length; i++) {\r\n const char = str.charCodeAt(i);\r\n hash = ((hash << 5) - hash) + char;\r\n hash = hash & hash;\r\n }\r\n return Math.abs(hash).toString(16);\r\n}\r\n\r\n/**\r\n * Constant-time string comparison (prevents timing attacks)\r\n */\r\nfunction constantTimeEqual(a: string, b: string): boolean {\r\n if (a.length !== b.length) {\r\n return false;\r\n }\r\n \r\n let result = 0;\r\n for (let i = 0; i < a.length; i++) {\r\n result |= a.charCodeAt(i) ^ b.charCodeAt(i);\r\n }\r\n \r\n return result === 0;\r\n}\r\n\r\nexport type CsrfValidator = ReturnType<typeof createCsrfValidator>;\r\n","/**\r\n * Rate Limiting\r\n * \r\n * Implements token bucket algorithm for rate limiting.\r\n * In-memory store by default, designed for single-instance deployments.\r\n * \r\n * For horizontal scaling (multiple instances), use a custom store\r\n * with Redis or similar distributed cache.\r\n */\r\n\r\nimport { NextRequest, NextResponse } from 'next/server';\r\nimport type { ResolvedRateLimitConfig } from '../shared/types';\r\n\r\ninterface RateLimitEntry {\r\n count: number;\r\n resetAt: number;\r\n}\r\n\r\nexport interface RateLimitResult {\r\n allowed: boolean;\r\n remaining: number;\r\n resetAt: number;\r\n limit: number;\r\n}\r\n\r\n/**\r\n * Creates a rate limiter with in-memory store\r\n */\r\nexport function createRateLimiter(config: ResolvedRateLimitConfig) {\r\n // In-memory store\r\n const store = new Map<string, RateLimitEntry>();\r\n \r\n // Cleanup expired entries periodically\r\n const cleanupInterval = setInterval(() => {\r\n const now = Date.now();\r\n for (const [key, entry] of store) {\r\n if (entry.resetAt <= now) {\r\n store.delete(key);\r\n }\r\n }\r\n }, config.windowMs);\r\n\r\n // Prevent memory leak in long-running processes\r\n if (typeof process !== 'undefined' && process.on) {\r\n process.on('beforeExit', () => clearInterval(cleanupInterval));\r\n }\r\n\r\n /**\r\n * Check if route should skip rate limiting\r\n */\r\n function shouldSkip(pathname: string): boolean {\r\n return config.skipRoutes.some(pattern => {\r\n // Simple glob matching\r\n if (pattern.endsWith('*')) {\r\n return pathname.startsWith(pattern.slice(0, -1));\r\n }\r\n if (pattern.endsWith('**')) {\r\n return pathname.startsWith(pattern.slice(0, -2));\r\n }\r\n return pathname === pattern;\r\n });\r\n }\r\n\r\n /**\r\n * Check rate limit for request\r\n */\r\n function check(req: NextRequest): RateLimitResult {\r\n const pathname = req.nextUrl.pathname;\r\n \r\n // Skip if route matches skip patterns\r\n if (shouldSkip(pathname)) {\r\n return {\r\n allowed: true,\r\n remaining: config.maxRequests,\r\n resetAt: 0,\r\n limit: config.maxRequests,\r\n };\r\n }\r\n\r\n const key = config.keyFn(req);\r\n const now = Date.now();\r\n \r\n let entry = store.get(key);\r\n \r\n // New window or expired\r\n if (!entry || entry.resetAt <= now) {\r\n entry = {\r\n count: 1,\r\n resetAt: now + config.windowMs,\r\n };\r\n store.set(key, entry);\r\n \r\n return {\r\n allowed: true,\r\n remaining: config.maxRequests - 1,\r\n resetAt: entry.resetAt,\r\n limit: config.maxRequests,\r\n };\r\n }\r\n\r\n // Existing window\r\n entry.count++;\r\n \r\n const remaining = Math.max(0, config.maxRequests - entry.count);\r\n const allowed = entry.count <= config.maxRequests;\r\n \r\n return {\r\n allowed,\r\n remaining,\r\n resetAt: entry.resetAt,\r\n limit: config.maxRequests,\r\n };\r\n }\r\n\r\n /**\r\n * Apply rate limit headers to response\r\n */\r\n function applyHeaders(response: NextResponse, result: RateLimitResult): NextResponse {\r\n response.headers.set('X-RateLimit-Limit', result.limit.toString());\r\n response.headers.set('X-RateLimit-Remaining', result.remaining.toString());\r\n response.headers.set('X-RateLimit-Reset', Math.ceil(result.resetAt / 1000).toString());\r\n return response;\r\n }\r\n\r\n /**\r\n * Create rate limited response (429 Too Many Requests)\r\n */\r\n function createLimitedResponse(req: NextRequest, result: RateLimitResult): NextResponse {\r\n // User-provided handler\r\n if (config.onRateLimited) {\r\n const response = config.onRateLimited(req);\r\n return applyHeaders(response, result);\r\n }\r\n\r\n // Default response\r\n const response = NextResponse.json(\r\n {\r\n success: false,\r\n message: 'Too many requests. Please try again later.',\r\n retryAfter: Math.ceil((result.resetAt - Date.now()) / 1000),\r\n },\r\n { status: 429 }\r\n );\r\n\r\n response.headers.set('Retry-After', Math.ceil((result.resetAt - Date.now()) / 1000).toString());\r\n return applyHeaders(response, result);\r\n }\r\n\r\n /**\r\n * Reset rate limit for a key (useful for testing)\r\n */\r\n function reset(key: string): void {\r\n store.delete(key);\r\n }\r\n\r\n /**\r\n * Clear all rate limit entries\r\n */\r\n function clear(): void {\r\n store.clear();\r\n }\r\n\r\n /**\r\n * Get current store size (for monitoring)\r\n */\r\n function size(): number {\r\n return store.size;\r\n }\r\n\r\n return {\r\n check,\r\n applyHeaders,\r\n createLimitedResponse,\r\n shouldSkip,\r\n reset,\r\n clear,\r\n size,\r\n };\r\n}\r\n\r\nexport type RateLimiter = ReturnType<typeof createRateLimiter>;\r\n","/**\r\n * Audit Logging\r\n * \r\n * Event-based security audit logging system.\r\n * Emits events for authentication, access control, and security violations.\r\n */\r\n\r\nimport { NextRequest } from 'next/server';\r\nimport type { ResolvedAuditConfig, AuditEvent, AuditEventType } from '../shared/types';\r\n\r\n/**\r\n * Creates an audit logger instance\r\n */\r\nexport function createAuditLogger(config: ResolvedAuditConfig) {\r\n /**\r\n * Check if event type is enabled\r\n */\r\n function isEnabled(type: AuditEventType): boolean {\r\n return config.enabled && config.events.includes(type);\r\n }\r\n\r\n /**\r\n * Extract IP address from request\r\n */\r\n function getIp(req: NextRequest): string | null {\r\n return (\r\n req.headers.get('x-forwarded-for')?.split(',')[0]?.trim() ||\r\n req.headers.get('x-real-ip') ||\r\n null\r\n );\r\n }\r\n\r\n /**\r\n * Emit an audit event\r\n */\r\n async function emit(\r\n type: AuditEventType,\r\n req: NextRequest,\r\n options: {\r\n success: boolean;\r\n userId?: string;\r\n metadata?: Record<string, unknown>;\r\n }\r\n ): Promise<void> {\r\n if (!isEnabled(type)) {\r\n return;\r\n }\r\n\r\n const event: AuditEvent = {\r\n type,\r\n timestamp: new Date(),\r\n ip: getIp(req),\r\n userId: options.userId,\r\n path: req.nextUrl.pathname,\r\n method: req.method,\r\n success: options.success,\r\n metadata: options.metadata,\r\n };\r\n\r\n // Call user's logger\r\n if (config.logger) {\r\n try {\r\n await config.logger(event);\r\n } catch (error) {\r\n // Silently fail - don't break the request flow for logging errors\r\n console.error('[next-api-layer] Audit logger error:', error);\r\n }\r\n }\r\n }\r\n\r\n // ==================== Convenience Methods ====================\r\n\r\n /**\r\n * Log successful authentication\r\n */\r\n function authSuccess(req: NextRequest, userId?: string, metadata?: Record<string, unknown>) {\r\n return emit('auth:success', req, { success: true, userId, metadata });\r\n }\r\n\r\n /**\r\n * Log failed authentication\r\n */\r\n function authFail(req: NextRequest, metadata?: Record<string, unknown>) {\r\n return emit('auth:fail', req, { success: false, metadata });\r\n }\r\n\r\n /**\r\n * Log token refresh\r\n */\r\n function authRefresh(req: NextRequest, userId?: string, metadata?: Record<string, unknown>) {\r\n return emit('auth:refresh', req, { success: true, userId, metadata });\r\n }\r\n\r\n /**\r\n * Log guest token creation\r\n */\r\n function authGuest(req: NextRequest, metadata?: Record<string, unknown>) {\r\n return emit('auth:guest', req, { success: true, metadata });\r\n }\r\n\r\n /**\r\n * Log access denied\r\n */\r\n function accessDenied(req: NextRequest, userId?: string, metadata?: Record<string, unknown>) {\r\n return emit('access:denied', req, { success: false, userId, metadata });\r\n }\r\n\r\n /**\r\n * Log CSRF validation failure\r\n */\r\n function csrfFail(req: NextRequest, metadata?: Record<string, unknown>) {\r\n return emit('csrf:fail', req, { success: false, metadata });\r\n }\r\n\r\n /**\r\n * Log rate limit exceeded\r\n */\r\n function rateLimitExceeded(req: NextRequest, metadata?: Record<string, unknown>) {\r\n return emit('rateLimit:exceeded', req, { success: false, metadata });\r\n }\r\n\r\n /**\r\n * Log general error\r\n */\r\n function error(req: NextRequest, err: Error, metadata?: Record<string, unknown>) {\r\n return emit('error', req, { \r\n success: false, \r\n metadata: { \r\n ...metadata, \r\n error: err.message,\r\n stack: err.stack,\r\n } \r\n });\r\n }\r\n\r\n return {\r\n emit,\r\n isEnabled,\r\n // Convenience methods\r\n authSuccess,\r\n authFail,\r\n authRefresh,\r\n authGuest,\r\n accessDenied,\r\n csrfFail,\r\n rateLimitExceeded,\r\n error,\r\n };\r\n}\r\n\r\nexport type AuditLogger = ReturnType<typeof createAuditLogger>;\r\n","/**\r\n * createAuthProxy\r\n * Factory function to create Next.js middleware for external JWT authentication\r\n */\r\n\r\nimport { NextRequest, NextResponse } from 'next/server';\r\nimport type { AuthProxyConfig, AuthResult } from '../shared/types';\r\nimport { resolveProxyConfig } from '../shared/config';\r\nimport { createTokenValidation } from './tokenValidation';\r\nimport { createHandlers } from './handlers';\r\nimport { createCsrfValidator } from './csrf';\r\nimport { createRateLimiter } from './rateLimit';\r\nimport { createAuditLogger } from './audit';\r\n\r\n/**\r\n * Creates an authentication proxy middleware for Next.js\r\n * \r\n * @example\r\n * ```ts\r\n * // middleware.ts\r\n * import { createAuthProxy } from 'next-api-layer';\r\n * \r\n * const authProxy = createAuthProxy({\r\n * apiBaseUrl: process.env.API_BASE_URL!,\r\n * cookies: {\r\n * user: 'userAuthToken',\r\n * guest: 'guestAuthToken',\r\n * },\r\n * guestToken: {\r\n * enabled: true,\r\n * credentials: {\r\n * username: process.env.GUEST_USERNAME!,\r\n * password: process.env.GUEST_PASSWORD!,\r\n * },\r\n * },\r\n * access: {\r\n * protectedRoutes: ['/dashboard', '/profile'],\r\n * authRoutes: ['/login', '/register'],\r\n * },\r\n * // Security features\r\n * csrf: { enabled: true },\r\n * rateLimit: { enabled: true, maxRequests: 100 },\r\n * audit: { \r\n * enabled: true, \r\n * logger: (event) => console.log('[AUDIT]', event) \r\n * },\r\n * });\r\n * \r\n * export default authProxy;\r\n * \r\n * export const config = {\r\n * matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],\r\n * };\r\n * ```\r\n */\r\nexport function createAuthProxy(userConfig: AuthProxyConfig) {\r\n // Resolve config with defaults\r\n const config = resolveProxyConfig(userConfig);\r\n \r\n // Create validation functions\r\n const validation = createTokenValidation(config);\r\n \r\n // Create handlers\r\n const handlers = createHandlers(config, validation);\r\n\r\n // Create security modules\r\n const csrf = createCsrfValidator(config._resolved.csrf);\r\n const rateLimiter = createRateLimiter(config._resolved.rateLimit);\r\n const audit = createAuditLogger(config._resolved.audit);\r\n\r\n /**\r\n * The middleware function\r\n */\r\n async function authProxy(req: NextRequest): Promise<NextResponse> {\r\n const { pathname, origin } = req.nextUrl;\r\n const isApiRoute = pathname.startsWith('/api');\r\n\r\n // ============ Rate Limiting ============\r\n // Check early to protect against DoS\r\n if (config._resolved.rateLimit.enabled) {\r\n const rateLimitResult = rateLimiter.check(req);\r\n \r\n if (!rateLimitResult.allowed) {\r\n await audit.rateLimitExceeded(req, { \r\n limit: rateLimitResult.limit,\r\n resetAt: rateLimitResult.resetAt,\r\n });\r\n return rateLimiter.createLimitedResponse(req, rateLimitResult);\r\n }\r\n }\r\n\r\n // ============ CSRF Protection ============\r\n // Check before any state-changing operations\r\n if (config._resolved.csrf.enabled) {\r\n const csrfResult = csrf.validateRequest(req);\r\n \r\n if (!csrfResult.valid) {\r\n await audit.csrfFail(req, { reason: csrfResult.reason });\r\n return NextResponse.json(\r\n { success: false, message: 'CSRF validation failed' },\r\n { status: 403 }\r\n );\r\n }\r\n }\r\n\r\n // ============ Block Browser API Access ============\r\n // Prevents direct browser access to API routes (when Accept: text/html)\r\n if (config.blockBrowserApiAccess && isApiRoute) {\r\n const acceptHeader = req.headers.get('accept') || '';\r\n if (acceptHeader.includes('text/html')) {\r\n return NextResponse.redirect(new URL('/', origin));\r\n }\r\n }\r\n\r\n // ============ beforeAuth Hook ============\r\n // Allows user to handle request before auth validation\r\n if (config.beforeAuth) {\r\n const beforeResult = await config.beforeAuth(req);\r\n if (beforeResult) {\r\n return beforeResult; // User handled the request\r\n }\r\n }\r\n\r\n // Skip excluded paths\r\n const excludedPaths = config.excludedPaths ?? [];\r\n if (excludedPaths.some(path => pathname.startsWith(path))) {\r\n return applyAfterAuth(req, NextResponse.next(), { isAuthenticated: false, isGuest: false, tokenType: null, user: null });\r\n }\r\n\r\n // Skip auth API endpoints (they handle their own auth)\r\n const authApiPaths = [\r\n '/api/auth/login',\r\n '/api/auth/logout',\r\n '/api/auth/me',\r\n '/api/auth/refresh',\r\n '/api/auth/register',\r\n ];\r\n \r\n if (authApiPaths.includes(pathname)) {\r\n return applyAfterAuth(req, NextResponse.next(), { isAuthenticated: false, isGuest: false, tokenType: null, user: null });\r\n }\r\n\r\n // Get tokens from cookies\r\n const userToken = req.cookies?.get(config.cookies.user)?.value;\r\n const guestToken = req.cookies?.get(config.cookies.guest)?.value;\r\n const currentToken = userToken || guestToken;\r\n const isUserToken = !!userToken;\r\n\r\n // No token - handle appropriately\r\n if (!currentToken) {\r\n await audit.authFail(req, { reason: 'no-token' });\r\n const response = await handlers.handleNoToken(req, isApiRoute);\r\n return applyAfterAuth(req, response, { isAuthenticated: false, isGuest: false, tokenType: null, user: null });\r\n }\r\n\r\n // Validate token\r\n const tokenInfo = await validation.getTokenInfo(currentToken);\r\n \r\n // Build auth result for afterAuth hook\r\n const authResult: AuthResult = {\r\n isAuthenticated: tokenInfo.isValid && tokenInfo.tokenType !== 'guest',\r\n isGuest: tokenInfo.isValid && tokenInfo.tokenType === 'guest',\r\n tokenType: tokenInfo.tokenType,\r\n user: tokenInfo.userData,\r\n };\r\n\r\n // Audit logging based on validation result \r\n if (tokenInfo.isValid) {\r\n if (tokenInfo.tokenType === 'guest') {\r\n await audit.authGuest(req);\r\n } else {\r\n const userId = tokenInfo.userData?.id?.toString();\r\n await audit.authSuccess(req, userId, { tokenType: tokenInfo.tokenType });\r\n }\r\n } else {\r\n await audit.authFail(req, { reason: 'invalid-token' });\r\n }\r\n\r\n // Handle validation result\r\n const response = await handlers.handleValidationResult(\r\n req,\r\n tokenInfo,\r\n isUserToken,\r\n currentToken,\r\n isApiRoute\r\n );\r\n \r\n // Apply CSRF cookie if enabled (for authenticated requests)\r\n let finalResponse = await applyAfterAuth(req, response, authResult);\r\n \r\n if (config._resolved.csrf.enabled && authResult.isAuthenticated) {\r\n const sessionId = tokenInfo.userData?.id?.toString() || currentToken.slice(0, 32);\r\n finalResponse = await csrf.attachCsrfCookie(finalResponse, sessionId);\r\n }\r\n\r\n // Apply rate limit headers\r\n if (config._resolved.rateLimit.enabled) {\r\n const rateLimitResult = rateLimiter.check(req);\r\n finalResponse = rateLimiter.applyHeaders(finalResponse, rateLimitResult);\r\n }\r\n \r\n return finalResponse;\r\n }\r\n \r\n /**\r\n * Helper to apply afterAuth hook\r\n */\r\n async function applyAfterAuth(req: NextRequest, response: NextResponse, authResult: AuthResult): Promise<NextResponse> {\r\n if (config.afterAuth) {\r\n return config.afterAuth(req, response, authResult);\r\n }\r\n return response;\r\n }\r\n\r\n // Attach instances for debugging/testing\r\n authProxy.config = config;\r\n authProxy.csrf = csrf;\r\n authProxy.rateLimiter = rateLimiter;\r\n authProxy.audit = audit;\r\n\r\n return authProxy;\r\n}\r\n\r\nexport type AuthProxy = ReturnType<typeof createAuthProxy>;\r\n","/**\r\n * createProxyHandler\r\n * Factory function to create Next.js API route handlers that proxy requests to backend\r\n */\r\n\r\nimport { NextRequest, NextResponse } from 'next/server';\r\nimport { HEADERS } from '../shared/constants';\r\n\r\nexport interface ProxyHandlerConfig {\r\n /** Base URL of the backend API */\r\n apiBaseUrl: string;\r\n /** Cookie name for user auth token */\r\n userCookieName?: string;\r\n /** Cookie name for guest auth token */\r\n guestCookieName?: string;\r\n /** \r\n * Default behavior for auth - if true, all requests skip auth by default\r\n * Individual requests can override with X-Skip-Auth header\r\n */\r\n skipAuthByDefault?: boolean;\r\n /**\r\n * Public endpoints that should never include auth token (glob patterns)\r\n * e.g., ['news/*', 'public/**', 'categories']\r\n */\r\n publicEndpoints?: string[];\r\n /** Headers to forward from client request */\r\n forwardHeaders?: string[];\r\n /** Headers to exclude from forwarding */\r\n excludeHeaders?: string[];\r\n /** Custom request transformer */\r\n transformRequest?: (req: NextRequest, headers: Headers) => Headers | Promise<Headers>;\r\n /** Custom response transformer */\r\n transformResponse?: (response: Response) => Response | Promise<Response>;\r\n}\r\n\r\n/**\r\n * Check if endpoint matches any patterns (glob support)\r\n */\r\nfunction matchesPattern(endpoint: string, patterns: string[]): boolean {\r\n if (!patterns || patterns.length === 0) return false;\r\n \r\n // Normalize endpoint\r\n const normalizedEndpoint = endpoint\r\n .replace(/^\\/api\\//, '')\r\n .replace(/^\\//, '');\r\n \r\n return patterns.some(pattern => {\r\n if (pattern === normalizedEndpoint) return true;\r\n \r\n if (pattern.includes('*')) {\r\n const regexPattern = pattern\r\n .replace(/\\*\\*/g, '<<<DOUBLE>>>')\r\n .replace(/\\*/g, '[^/]+')\r\n .replace(/<<<DOUBLE>>>/g, '.+');\r\n const regex = new RegExp(`^${regexPattern}$`);\r\n return regex.test(normalizedEndpoint);\r\n }\r\n \r\n return false;\r\n });\r\n}\r\n\r\n/**\r\n * Creates a proxy handler for Next.js API routes\r\n * \r\n * @example\r\n * ```ts\r\n * // app/api/[...path]/route.ts\r\n * import { createProxyHandler } from 'next-api-layer';\r\n * \r\n * const handler = createProxyHandler({\r\n * apiBaseUrl: process.env.API_BASE_URL!,\r\n * userCookieName: 'auth_token',\r\n * guestCookieName: 'guest_token',\r\n * publicEndpoints: ['news/*', 'categories', 'public/**'],\r\n * });\r\n * \r\n * export const GET = handler;\r\n * export const POST = handler;\r\n * export const PUT = handler;\r\n * export const PATCH = handler;\r\n * export const DELETE = handler;\r\n * ```\r\n */\r\nexport function createProxyHandler(config: ProxyHandlerConfig) {\r\n const {\r\n apiBaseUrl,\r\n userCookieName = 'auth_token',\r\n guestCookieName = 'guest_token',\r\n skipAuthByDefault = false,\r\n publicEndpoints = [],\r\n forwardHeaders = ['content-type', 'accept', 'accept-language', 'x-requested-with'],\r\n excludeHeaders = ['host', 'connection', 'cookie'],\r\n transformRequest,\r\n transformResponse,\r\n } = config;\r\n\r\n // Normalize base URL (remove trailing slash)\r\n const baseUrl = apiBaseUrl.replace(/\\/$/, '');\r\n\r\n /**\r\n * Determine if auth should be skipped for this request\r\n */\r\n function shouldSkipAuth(req: NextRequest, endpoint: string): boolean {\r\n // Check X-Skip-Auth header from client\r\n const skipAuthHeader = req.headers.get(HEADERS.SKIP_AUTH);\r\n if (skipAuthHeader === 'true') {\r\n return true;\r\n }\r\n \r\n // Check if endpoint matches public patterns\r\n if (matchesPattern(endpoint, publicEndpoints)) {\r\n return true;\r\n }\r\n \r\n // Default behavior\r\n return skipAuthByDefault;\r\n }\r\n\r\n /**\r\n * The proxy handler function\r\n */\r\n async function handler(req: NextRequest): Promise<NextResponse> {\r\n try {\r\n // Extract endpoint from URL path (remove /api/ prefix)\r\n const url = new URL(req.url);\r\n const endpoint = url.pathname.replace(/^\\/api\\/?/, '');\r\n \r\n // Build backend URL\r\n const backendUrl = new URL(`${baseUrl}/${endpoint}`);\r\n backendUrl.search = url.search; // Forward query params\r\n\r\n // Build headers for backend request\r\n const headers = new Headers();\r\n \r\n // Forward allowed headers from original request\r\n forwardHeaders.forEach(headerName => {\r\n const value = req.headers.get(headerName);\r\n if (value) {\r\n headers.set(headerName, value);\r\n }\r\n });\r\n\r\n // Forward all headers except excluded ones\r\n req.headers.forEach((value, key) => {\r\n const lowerKey = key.toLowerCase();\r\n if (!excludeHeaders.includes(lowerKey) && !headers.has(key)) {\r\n headers.set(key, value);\r\n }\r\n });\r\n\r\n // Add Authorization header if auth is not skipped\r\n if (!shouldSkipAuth(req, endpoint)) {\r\n const userToken = req.cookies.get(userCookieName)?.value;\r\n const guestToken = req.cookies.get(guestCookieName)?.value;\r\n const token = userToken || guestToken;\r\n \r\n if (token) {\r\n headers.set(HEADERS.AUTHORIZATION, `Bearer ${token}`);\r\n }\r\n }\r\n\r\n // Remove skip-auth header (internal use only)\r\n headers.delete(HEADERS.SKIP_AUTH);\r\n\r\n // Allow custom request transformation\r\n const finalHeaders = transformRequest \r\n ? await transformRequest(req, headers) \r\n : headers;\r\n\r\n // Get request body if present\r\n let body: BodyInit | null = null;\r\n if (req.method !== 'GET' && req.method !== 'HEAD') {\r\n const contentType = req.headers.get('content-type') || '';\r\n \r\n if (contentType.includes('application/json')) {\r\n body = await req.text();\r\n } else if (contentType.includes('multipart/form-data')) {\r\n body = await req.formData();\r\n } else {\r\n body = await req.text();\r\n }\r\n }\r\n\r\n // Make request to backend\r\n const backendResponse = await fetch(backendUrl.toString(), {\r\n method: req.method,\r\n headers: finalHeaders,\r\n body,\r\n });\r\n\r\n // Get response body\r\n const contentType = backendResponse.headers.get('content-type') || '';\r\n let responseBody: ArrayBuffer | string;\r\n \r\n if (contentType.includes('application/json')) {\r\n responseBody = await backendResponse.text();\r\n } else {\r\n responseBody = await backendResponse.arrayBuffer();\r\n }\r\n\r\n // Build response headers (forward relevant ones)\r\n const responseHeaders = new Headers();\r\n backendResponse.headers.forEach((value, key) => {\r\n const lowerKey = key.toLowerCase();\r\n // Skip hop-by-hop headers\r\n if (!['transfer-encoding', 'connection', 'keep-alive'].includes(lowerKey)) {\r\n responseHeaders.set(key, value);\r\n }\r\n });\r\n\r\n // Create response\r\n let response = new NextResponse(responseBody, {\r\n status: backendResponse.status,\r\n statusText: backendResponse.statusText,\r\n headers: responseHeaders,\r\n });\r\n\r\n // Allow custom response transformation\r\n if (transformResponse) {\r\n response = await transformResponse(response) as NextResponse;\r\n }\r\n\r\n return response;\r\n } catch (error) {\r\n console.error('[Proxy Error]', error);\r\n \r\n return NextResponse.json(\r\n { \r\n success: false, \r\n message: 'Proxy error: Unable to connect to backend',\r\n error: error instanceof Error ? error.message : 'Unknown error',\r\n },\r\n { status: 502 }\r\n );\r\n }\r\n }\r\n\r\n // Attach config for debugging\r\n handler.config = config;\r\n\r\n return handler;\r\n}\r\n\r\nexport type ProxyHandler = ReturnType<typeof createProxyHandler>;\r\n"]}
1
+ {"version":3,"sources":["../src/shared/config.ts","../src/proxy/tokenValidation.ts","../src/proxy/handlers.ts","../src/proxy/csrf.ts","../src/proxy/rateLimit.ts","../src/proxy/audit.ts","../src/proxy/createAuthProxy.ts","../src/proxy/createProxyHandler.ts"],"names":["generateCsrfSecret","defaultRateLimitKeyFn","req","resolveProxyConfig","config","apiBaseUrl","cookieOptions","DEFAULT_COOKIE_OPTIONS","endpoints","DEFAULT_ENDPOINTS","csrf","DEFAULT_CSRF_CONFIG","rateLimit","DEFAULT_RATE_LIMIT_CONFIG","audit","DEFAULT_AUDIT_CONFIG","defaultMappers","response","res","createTokenValidation","_resolved","responseMappers","mappers","validateToken","token","invalidResult","rawResponse","parsed","getTokenInfo","refreshToken","oldToken","newToken","createGuestToken","guestConfig","extractLocale","pathname","i18n","locales","defaultLocale","firstSegment","createHandlers","validation","cookies","guestToken","access","safeDeleteCookie","cookieName","deleteAllAuthCookies","jsonError","message","status","NextResponse","isAuthPage","route","isProtectedRoute","isPublicRoute","isTokenTypeAllowed","tokenType","allowedTypes","handleNoToken","isApiRoute","origin","guestAccessToken","handleValidationResult","tokenInfo","isUserToken","currentToken","isValid","userData","isGuest","TOKEN_TYPES","refreshResult","newTokenInfo","requestHeaders","HEADERS","locale","createCsrfValidator","generateToken","sessionId","randomValue","generateRandomValue","computeHmac","validateRequest","method","strategy","fetchResult","validateFetchMetadata","validateDoubleSubmit","secFetchSite","cookieToken","headerToken","constantTimeEqual","attachCsrfCookie","array","b","secret","encoder","keyData","messageData","key","signature","hash","str","i","char","a","result","createRateLimiter","store","cleanupInterval","now","entry","shouldSkip","pattern","check","remaining","applyHeaders","createLimitedResponse","reset","clear","size","createAuditLogger","isEnabled","type","getIp","emit","options","event","error","authSuccess","userId","metadata","authFail","authRefresh","authGuest","accessDenied","csrfFail","rateLimitExceeded","err","mergeResponses","source","target","criticalHeaders","header","value","cookie","createAuthProxy","userConfig","handlers","rateLimiter","authProxy","rateLimitResult","csrfResult","beforeResult","path","applyMiddlewaresAndHooks","userToken","authResult","finalResponse","intlResponse","hookResponse","matchesPattern","endpoint","patterns","normalizedEndpoint","regexPattern","createProxyHandler","userCookieName","guestCookieName","skipAuthByDefault","publicEndpoints","forwardHeaders","excludeHeaders","transformRequest","transformResponse","baseUrl","shouldSkipAuth","handler","url","backendUrl","headers","headerName","lowerKey","finalHeaders","body","contentType","backendResponse","responseBody","responseHeaders"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\r\n * Config Resolver\r\n * Resolves and validates configuration with defaults\r\n */\r\n\r\nimport type { NextRequest } from 'next/server';\r\nimport type {\r\n AuthProxyConfig,\r\n InternalProxyConfig,\r\n ApiClientConfig,\r\n ResolvedCookieOptions,\r\n EndpointConfig,\r\n ResolvedCsrfConfig,\r\n ResolvedRateLimitConfig,\r\n ResolvedAuditConfig,\r\n AuditEventType,\r\n} from './types';\r\n\r\nimport {\r\n DEFAULT_COOKIE_OPTIONS,\r\n DEFAULT_ENDPOINTS,\r\n DEFAULT_CSRF_CONFIG,\r\n DEFAULT_RATE_LIMIT_CONFIG,\r\n DEFAULT_AUDIT_CONFIG,\r\n} from './constants';\r\n\r\n/**\r\n * Generates a random secret for CSRF HMAC signing\r\n */\r\nfunction generateCsrfSecret(): string {\r\n // Use crypto if available (Node.js)\r\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\r\n return crypto.randomUUID() + crypto.randomUUID();\r\n }\r\n // Fallback: timestamp + random\r\n return `${Date.now()}-${Math.random().toString(36).substring(2)}`;\r\n}\r\n\r\n/**\r\n * Default rate limit key function (IP-based)\r\n */\r\nfunction defaultRateLimitKeyFn(req: NextRequest): string {\r\n const forwarded = req.headers.get('x-forwarded-for');\r\n const ip = forwarded?.split(',')[0]?.trim() || \r\n req.headers.get('x-real-ip') || \r\n 'unknown';\r\n return `rl:${ip}`;\r\n}\r\n\r\n/**\r\n * Resolves proxy configuration with defaults\r\n */\r\nexport function resolveProxyConfig(config: AuthProxyConfig): InternalProxyConfig {\r\n // Validate required fields\r\n if (!config.apiBaseUrl) {\r\n throw new Error('next-api-layer: apiBaseUrl is required');\r\n }\r\n \r\n if (!config.cookies?.user || !config.cookies?.guest) {\r\n throw new Error('next-api-layer: cookies.user and cookies.guest are required');\r\n }\r\n\r\n // Ensure apiBaseUrl ends with /\r\n const apiBaseUrl = config.apiBaseUrl.endsWith('/')\r\n ? config.apiBaseUrl\r\n : `${config.apiBaseUrl}/`;\r\n\r\n // Resolve cookie options\r\n const cookieOptions: ResolvedCookieOptions = {\r\n ...DEFAULT_COOKIE_OPTIONS,\r\n ...config.cookies.options,\r\n };\r\n\r\n // Resolve endpoints\r\n const endpoints: Required<EndpointConfig> = {\r\n ...DEFAULT_ENDPOINTS,\r\n ...config.endpoints,\r\n };\r\n\r\n // Resolve CSRF config\r\n const csrf: ResolvedCsrfConfig = {\r\n enabled: config.csrf?.enabled ?? false,\r\n strategy: config.csrf?.strategy ?? DEFAULT_CSRF_CONFIG.strategy,\r\n secret: config.csrf?.secret ?? generateCsrfSecret(),\r\n cookieName: config.csrf?.cookieName ?? DEFAULT_CSRF_CONFIG.cookieName,\r\n headerName: config.csrf?.headerName ?? DEFAULT_CSRF_CONFIG.headerName,\r\n ignoreMethods: config.csrf?.ignoreMethods ?? DEFAULT_CSRF_CONFIG.ignoreMethods,\r\n trustSameSite: config.csrf?.trustSameSite ?? DEFAULT_CSRF_CONFIG.trustSameSite,\r\n };\r\n\r\n // Resolve rate limit config\r\n const rateLimit: ResolvedRateLimitConfig = {\r\n enabled: config.rateLimit?.enabled ?? false,\r\n windowMs: config.rateLimit?.windowMs ?? DEFAULT_RATE_LIMIT_CONFIG.windowMs,\r\n maxRequests: config.rateLimit?.maxRequests ?? DEFAULT_RATE_LIMIT_CONFIG.maxRequests,\r\n keyFn: config.rateLimit?.keyFn ?? defaultRateLimitKeyFn,\r\n skipRoutes: config.rateLimit?.skipRoutes ?? DEFAULT_RATE_LIMIT_CONFIG.skipRoutes,\r\n onRateLimited: config.rateLimit?.onRateLimited,\r\n };\r\n\r\n // Resolve audit config\r\n const audit: ResolvedAuditConfig = {\r\n enabled: config.audit?.enabled ?? false,\r\n events: config.audit?.events ?? [...DEFAULT_AUDIT_CONFIG.events] as AuditEventType[],\r\n logger: config.audit?.logger,\r\n };\r\n\r\n return {\r\n ...config,\r\n apiBaseUrl,\r\n _resolved: {\r\n cookieOptions,\r\n endpoints,\r\n csrf,\r\n rateLimit,\r\n audit,\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Resolves API client configuration with defaults\r\n */\r\nexport function resolveApiClientConfig(config: ApiClientConfig = {}) {\r\n return {\r\n sanitization: {\r\n enabled: config.sanitization?.enabled ?? true,\r\n allowedTags: config.sanitization?.allowedTags,\r\n skipFields: config.sanitization?.skipFields ?? [],\r\n skipEndpoints: config.sanitization?.skipEndpoints ?? [],\r\n },\r\n i18n: {\r\n enabled: config.i18n?.enabled ?? false,\r\n paramName: config.i18n?.paramName ?? 'lang',\r\n locales: config.i18n?.locales ?? [],\r\n defaultLocale: config.i18n?.defaultLocale ?? 'en',\r\n },\r\n auth: {\r\n skipByDefault: config.auth?.skipByDefault ?? false,\r\n publicEndpoints: config.auth?.publicEndpoints ?? [],\r\n },\r\n methodSpoofing: config.methodSpoofing ?? false,\r\n errorMessages: {\r\n noToken: config.errorMessages?.noToken ?? 'Token bulunamadı.',\r\n connectionError: config.errorMessages?.connectionError ?? 'Bağlantı hatası oluştu.',\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Type guard to check if a value is defined\r\n */\r\nexport function isDefined<T>(value: T | undefined | null): value is T {\r\n return value !== undefined && value !== null;\r\n}\r\n","/**\r\n * Token Validation\r\n * Handles token validation and refresh with backend API\r\n */\r\n\r\nimport type { \r\n TokenInfo, \r\n RefreshResult, \r\n AuthMeResponse, \r\n GuestTokenResponse,\r\n InternalProxyConfig,\r\n ResponseMappers,\r\n} from '../shared/types';\r\n\r\n/**\r\n * Default response parsers (standard format)\r\n */\r\nconst defaultMappers: Required<ResponseMappers> = {\r\n // Default: { success: true, data: { type, exp, ...user } }\r\n parseAuthMe: (response: unknown): TokenInfo | null => {\r\n const res = response as AuthMeResponse | null;\r\n if (!res?.success || !res?.data) {\r\n return null;\r\n }\r\n return {\r\n isValid: true,\r\n tokenType: res.data.type || 'user',\r\n exp: res.data.exp || null,\r\n userData: res.data,\r\n };\r\n },\r\n \r\n // Default: { success: true, data: { accessToken } }\r\n parseRefreshToken: (response: unknown): string | null => {\r\n const res = response as GuestTokenResponse | null;\r\n return res?.success && res?.data?.accessToken ? res.data.accessToken : null;\r\n },\r\n \r\n // Default: { success: true, data: { accessToken } }\r\n parseGuestToken: (response: unknown): string | null => {\r\n const res = response as GuestTokenResponse | null;\r\n return res?.data?.accessToken || null;\r\n },\r\n};\r\n\r\n/**\r\n * Creates token validation functions\r\n */\r\nexport function createTokenValidation(\r\n config: InternalProxyConfig\r\n) {\r\n const { apiBaseUrl, _resolved, responseMappers } = config;\r\n const { endpoints } = _resolved;\r\n \r\n // Merge custom mappers with defaults\r\n const mappers: Required<ResponseMappers> = {\r\n parseAuthMe: responseMappers?.parseAuthMe || defaultMappers.parseAuthMe,\r\n parseRefreshToken: responseMappers?.parseRefreshToken || defaultMappers.parseRefreshToken,\r\n parseGuestToken: responseMappers?.parseGuestToken || defaultMappers.parseGuestToken,\r\n };\r\n\r\n /**\r\n * Validates a token against the backend\r\n */\r\n async function validateToken(token: string): Promise<TokenInfo> {\r\n const invalidResult: TokenInfo = { isValid: false, tokenType: null, exp: null, userData: null };\r\n \r\n try {\r\n const res = await fetch(`${apiBaseUrl}${endpoints.validate}`, {\r\n headers: {\r\n 'Authorization': `Bearer ${token}`,\r\n 'Content-Type': 'application/json',\r\n },\r\n cache: 'no-store',\r\n });\r\n\r\n if (!res.ok) {\r\n return invalidResult;\r\n }\r\n\r\n const rawResponse: unknown = await res.json().catch(() => null);\r\n \r\n // Use custom or default mapper\r\n const parsed = mappers.parseAuthMe(rawResponse);\r\n \r\n if (!parsed || !parsed.isValid) {\r\n return invalidResult;\r\n }\r\n\r\n return parsed;\r\n } catch {\r\n return invalidResult;\r\n }\r\n }\r\n\r\n /**\r\n * Gets token info (validates with backend)\r\n */\r\n async function getTokenInfo(token: string): Promise<TokenInfo> {\r\n return validateToken(token);\r\n }\r\n\r\n /**\r\n * Refreshes a token\r\n */\r\n async function refreshToken(oldToken: string): Promise<RefreshResult> {\r\n try {\r\n const res = await fetch(`${apiBaseUrl}${endpoints.refresh}`, {\r\n method: 'POST',\r\n headers: {\r\n 'Authorization': `Bearer ${oldToken}`,\r\n 'Content-Type': 'application/json',\r\n },\r\n cache: 'no-store',\r\n });\r\n\r\n if (!res.ok) {\r\n return { success: false, newToken: null };\r\n }\r\n\r\n const rawResponse: unknown = await res.json().catch(() => null);\r\n \r\n // Use custom or default mapper\r\n const newToken = mappers.parseRefreshToken(rawResponse);\r\n\r\n if (!newToken) {\r\n return { success: false, newToken: null };\r\n }\r\n\r\n return { success: true, newToken };\r\n } catch {\r\n return { success: false, newToken: null };\r\n }\r\n }\r\n\r\n /**\r\n * Creates a guest token\r\n */\r\n async function createGuestToken(): Promise<string | null> {\r\n const guestConfig = config.guestToken;\r\n \r\n if (!guestConfig?.enabled || !guestConfig.credentials) {\r\n return null;\r\n }\r\n\r\n try {\r\n const res = await fetch(`${apiBaseUrl}${endpoints.guest}`, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({\r\n username: guestConfig.credentials.username,\r\n password: guestConfig.credentials.password,\r\n }),\r\n cache: 'no-store',\r\n });\r\n\r\n if (!res.ok) {\r\n return null;\r\n }\r\n\r\n const rawResponse: unknown = await res.json().catch(() => null);\r\n \r\n // Use custom or default mapper\r\n return mappers.parseGuestToken(rawResponse);\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n return {\r\n validateToken,\r\n getTokenInfo,\r\n refreshToken,\r\n createGuestToken,\r\n };\r\n}\r\n\r\nexport type TokenValidation = ReturnType<typeof createTokenValidation>;\r\n","/**\r\n * Proxy Handlers\r\n * Request handling logic for different scenarios\r\n */\r\n\r\nimport { NextRequest, NextResponse } from 'next/server';\r\nimport type { InternalProxyConfig, TokenInfo } from '../shared/types';\r\nimport { HEADERS, TOKEN_TYPES } from '../shared/constants';\r\nimport type { TokenValidation } from './tokenValidation';\r\n\r\n/**\r\n * Extracts locale from pathname based on i18n config\r\n * e.g., /en/dashboard → 'en', /dashboard → defaultLocale or null\r\n */\r\nfunction extractLocale(pathname: string, i18n?: InternalProxyConfig['i18n']): string | null {\r\n if (!i18n?.enabled) return null;\r\n \r\n const locales = i18n.locales ?? [];\r\n const defaultLocale = i18n.defaultLocale;\r\n \r\n // Extract first path segment\r\n const segments = pathname.split('/').filter(Boolean);\r\n const firstSegment = segments[0];\r\n \r\n // Check if it's a valid locale\r\n if (firstSegment && locales.includes(firstSegment)) {\r\n return firstSegment;\r\n }\r\n \r\n // Return default locale if provided\r\n return defaultLocale ?? null;\r\n}\r\n\r\n/**\r\n * Creates proxy handlers\r\n */\r\nexport function createHandlers(\r\n config: InternalProxyConfig,\r\n validation: TokenValidation\r\n) {\r\n const { cookies, guestToken, access, i18n, _resolved } = config;\r\n const { cookieOptions } = _resolved;\r\n\r\n /**\r\n * Safely deletes a cookie only if it exists in the request.\r\n * Prevents empty-value cookies from being created when deleting non-existent cookies.\r\n */\r\n function safeDeleteCookie(req: NextRequest, response: NextResponse, cookieName: string): void {\r\n if (req.cookies.get(cookieName)?.value) {\r\n response.cookies.delete(cookieName);\r\n }\r\n }\r\n\r\n /**\r\n * Deletes all auth cookies from response (only if they exist)\r\n */\r\n function deleteAllAuthCookies(req: NextRequest, response: NextResponse): NextResponse {\r\n safeDeleteCookie(req, response, cookies.guest);\r\n safeDeleteCookie(req, response, cookies.user);\r\n return response;\r\n }\r\n\r\n /**\r\n * Creates a JSON error response\r\n */\r\n function jsonError(message: string, status = 500): NextResponse {\r\n return new NextResponse(\r\n JSON.stringify({ success: false, message }),\r\n { status, headers: { 'Content-Type': 'application/json' } }\r\n );\r\n }\r\n\r\n /**\r\n * Checks if pathname is an auth page\r\n */\r\n function isAuthPage(pathname: string): boolean {\r\n const authRoutes = access?.authRoutes ?? [];\r\n return authRoutes.some(route => \r\n pathname === route || pathname.startsWith(`${route}/`)\r\n );\r\n }\r\n\r\n /**\r\n * Checks if pathname is a protected route\r\n */\r\n function isProtectedRoute(pathname: string): boolean {\r\n // If protectedByDefault is true, everything is protected except public/auth routes\r\n if (access?.protectedByDefault) {\r\n return !isPublicRoute(pathname) && !isAuthPage(pathname);\r\n }\r\n \r\n const protectedRoutes = access?.protectedRoutes ?? [];\r\n return protectedRoutes.some(route => \r\n pathname === route || pathname.startsWith(`${route}/`)\r\n );\r\n }\r\n\r\n /**\r\n * Checks if pathname is explicitly public\r\n */\r\n function isPublicRoute(pathname: string): boolean {\r\n const publicRoutes = access?.publicRoutes ?? [];\r\n return publicRoutes.some(route => \r\n pathname === route || pathname.startsWith(`${route}/`)\r\n );\r\n }\r\n\r\n /**\r\n * Checks if token type is allowed\r\n */\r\n function isTokenTypeAllowed(tokenType: string | null): boolean {\r\n const allowedTypes = access?.allowedTokenTypes;\r\n \r\n // If no restriction, all types allowed\r\n if (!allowedTypes || allowedTypes.length === 0) {\r\n return true;\r\n }\r\n \r\n return tokenType ? allowedTypes.includes(tokenType) : false;\r\n }\r\n\r\n /**\r\n * Handles request when no token is present\r\n */\r\n async function handleNoToken(\r\n req: NextRequest,\r\n isApiRoute: boolean\r\n ): Promise<NextResponse> {\r\n const { origin } = req.nextUrl;\r\n \r\n // Try to create guest token\r\n if (guestToken?.enabled) {\r\n const guestAccessToken = await validation.createGuestToken();\r\n \r\n if (guestAccessToken) {\r\n let response: NextResponse;\r\n \r\n if (isApiRoute) {\r\n response = NextResponse.next();\r\n } else if (isProtectedRoute(req.nextUrl.pathname)) {\r\n // Redirect to login if protected route\r\n response = NextResponse.redirect(new URL('/login', origin));\r\n } else {\r\n response = NextResponse.next();\r\n }\r\n \r\n response.cookies.set(cookies.guest, guestAccessToken, {\r\n ...cookieOptions,\r\n maxAge: 3600, // 1 hour default for guest tokens\r\n });\r\n \r\n return response;\r\n }\r\n }\r\n \r\n // No guest token - just continue or redirect\r\n if (isApiRoute) {\r\n return jsonError('Token bulunamadı', 401);\r\n }\r\n \r\n if (isProtectedRoute(req.nextUrl.pathname)) {\r\n return NextResponse.redirect(new URL('/login', origin));\r\n }\r\n \r\n return NextResponse.next();\r\n }\r\n\r\n /**\r\n * Handles token validation result\r\n */\r\n async function handleValidationResult(\r\n req: NextRequest,\r\n tokenInfo: TokenInfo,\r\n isUserToken: boolean,\r\n currentToken: string,\r\n isApiRoute: boolean\r\n ): Promise<NextResponse> {\r\n const { pathname, origin } = req.nextUrl;\r\n const { isValid, tokenType, userData } = tokenInfo;\r\n const isGuest = tokenType === TOKEN_TYPES.GUEST;\r\n\r\n // ===== TOKEN INVALID =====\r\n if (!isValid) {\r\n // Try refresh if user token\r\n if (isUserToken && currentToken) {\r\n const refreshResult = await validation.refreshToken(currentToken);\r\n \r\n if (refreshResult.success && refreshResult.newToken) {\r\n const newTokenInfo = await validation.getTokenInfo(refreshResult.newToken);\r\n \r\n if (newTokenInfo.isValid) {\r\n // Successful refresh\r\n const requestHeaders = new Headers(req.headers);\r\n \r\n if (newTokenInfo.userData) {\r\n requestHeaders.set(HEADERS.AUTH_USER, JSON.stringify(newTokenInfo.userData));\r\n }\r\n requestHeaders.set(HEADERS.REFRESHED_TOKEN, refreshResult.newToken);\r\n \r\n // Set locale header if i18n is enabled\r\n const locale = extractLocale(pathname, i18n);\r\n if (locale) {\r\n requestHeaders.set(HEADERS.LOCALE, locale);\r\n }\r\n\r\n let response: NextResponse;\r\n \r\n if (isAuthPage(pathname)) {\r\n response = NextResponse.redirect(new URL('/', origin));\r\n } else {\r\n response = NextResponse.next({ request: { headers: requestHeaders } });\r\n }\r\n\r\n response.cookies.set(cookies.user, refreshResult.newToken, {\r\n ...cookieOptions,\r\n maxAge: cookieOptions.maxAge,\r\n });\r\n safeDeleteCookie(req, response, cookies.guest);\r\n\r\n return response;\r\n }\r\n }\r\n }\r\n\r\n // Refresh failed or no user token - handle as no token\r\n const response = await handleNoToken(req, isApiRoute);\r\n \r\n // Check if handleNoToken created a new guest token\r\n const hasNewGuestToken = response.cookies.get(cookies.guest)?.value;\r\n \r\n if (!hasNewGuestToken) {\r\n // No new guest token created - delete all auth cookies\r\n deleteAllAuthCookies(req, response);\r\n } else {\r\n // New guest token created - only delete the invalid user cookie\r\n safeDeleteCookie(req, response, cookies.user);\r\n }\r\n \r\n return response;\r\n }\r\n\r\n // ===== TOKEN VALID =====\r\n const requestHeaders = new Headers(req.headers);\r\n \r\n if (userData) {\r\n requestHeaders.set(HEADERS.AUTH_USER, JSON.stringify(userData));\r\n }\r\n \r\n // Set locale header if i18n is enabled\r\n const locale = extractLocale(pathname, i18n);\r\n if (locale) {\r\n requestHeaders.set(HEADERS.LOCALE, locale);\r\n }\r\n\r\n // Check if token type is allowed\r\n if (!isGuest && !isTokenTypeAllowed(tokenType)) {\r\n if (isApiRoute) {\r\n const response = jsonError('Bu işlem için yetkiniz yok', 403);\r\n return deleteAllAuthCookies(req, response);\r\n }\r\n \r\n const response = NextResponse.redirect(new URL('/login', origin));\r\n return deleteAllAuthCookies(req, response);\r\n }\r\n\r\n // Guest token handling\r\n if (isGuest) {\r\n if (isApiRoute) {\r\n return NextResponse.next({ request: { headers: requestHeaders } });\r\n }\r\n\r\n // Protected routes require login\r\n if (isProtectedRoute(pathname)) {\r\n return NextResponse.redirect(new URL('/login', origin));\r\n }\r\n\r\n return NextResponse.next({ request: { headers: requestHeaders } });\r\n }\r\n\r\n // User token - block auth pages\r\n if (isAuthPage(pathname)) {\r\n return NextResponse.redirect(new URL('/', origin));\r\n }\r\n\r\n // Normal access\r\n const response = NextResponse.next({ request: { headers: requestHeaders } });\r\n safeDeleteCookie(req, response, cookies.guest);\r\n \r\n return response;\r\n }\r\n\r\n return {\r\n deleteAllAuthCookies,\r\n jsonError,\r\n isAuthPage,\r\n isProtectedRoute,\r\n isPublicRoute,\r\n isTokenTypeAllowed,\r\n handleNoToken,\r\n handleValidationResult,\r\n };\r\n}\r\n\r\nexport type Handlers = ReturnType<typeof createHandlers>;\r\n","/**\r\n * CSRF Protection\r\n * \r\n * Implements OWASP recommended CSRF protection:\r\n * - Fetch Metadata (Sec-Fetch-Site header) for modern browsers (98%+ coverage)\r\n * - Signed HMAC Double-Submit Cookie as fallback\r\n * \r\n * @see https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html\r\n */\r\n\r\nimport { NextRequest, NextResponse } from 'next/server';\r\nimport type { ResolvedCsrfConfig } from '../shared/types';\r\n\r\nexport interface CsrfValidationResult {\r\n valid: boolean;\r\n reason?: string;\r\n}\r\n\r\n/**\r\n * Creates CSRF validator functions\r\n */\r\nexport function createCsrfValidator(config: ResolvedCsrfConfig) {\r\n /**\r\n * Generate HMAC-signed CSRF token\r\n * Format: hmac.randomValue\r\n */\r\n async function generateToken(sessionId: string): Promise<string> {\r\n const randomValue = generateRandomValue();\r\n const hmac = await computeHmac(config.secret, sessionId, randomValue);\r\n return `${hmac}.${randomValue}`;\r\n }\r\n\r\n /**\r\n * Validate CSRF request using configured strategy\r\n */\r\n function validateRequest(req: NextRequest): CsrfValidationResult {\r\n const method = req.method.toUpperCase();\r\n \r\n // Skip safe methods\r\n if (config.ignoreMethods.includes(method)) {\r\n return { valid: true };\r\n }\r\n\r\n const strategy = config.strategy;\r\n \r\n // Fetch Metadata validation (primary, modern browsers)\r\n if (strategy === 'fetch-metadata' || strategy === 'both') {\r\n const fetchResult = validateFetchMetadata(req);\r\n \r\n if (strategy === 'fetch-metadata') {\r\n return fetchResult;\r\n }\r\n \r\n // 'both' strategy: if Fetch Metadata passes, we're good\r\n if (fetchResult.valid) {\r\n return fetchResult;\r\n }\r\n \r\n // 'both' strategy: if Fetch Metadata fails or not available, try double-submit\r\n if (fetchResult.reason === 'missing-headers') {\r\n // Fall through to double-submit\r\n } else {\r\n // Explicit cross-site rejection from Fetch Metadata\r\n return fetchResult;\r\n }\r\n }\r\n\r\n // Double-Submit Cookie validation (fallback)\r\n if (strategy === 'double-submit' || strategy === 'both') {\r\n return validateDoubleSubmit(req);\r\n }\r\n\r\n return { valid: true };\r\n }\r\n\r\n /**\r\n * Validate using Fetch Metadata headers (Sec-Fetch-Site)\r\n * @see https://web.dev/fetch-metadata/\r\n */\r\n function validateFetchMetadata(req: NextRequest): CsrfValidationResult {\r\n const secFetchSite = req.headers.get('sec-fetch-site');\r\n \r\n // No Fetch Metadata headers (older browser or stripped by proxy)\r\n if (!secFetchSite) {\r\n return { valid: false, reason: 'missing-headers' };\r\n }\r\n\r\n // Same-origin requests are always trusted\r\n if (secFetchSite === 'same-origin') {\r\n return { valid: true };\r\n }\r\n\r\n // None = direct navigation (bookmark, typed URL) - allow for GET\r\n if (secFetchSite === 'none') {\r\n const method = req.method.toUpperCase();\r\n if (config.ignoreMethods.includes(method)) {\r\n return { valid: true };\r\n }\r\n // Non-safe method from direct navigation is suspicious\r\n return { valid: false, reason: 'direct-navigation-unsafe-method' };\r\n }\r\n\r\n // Same-site: trust based on config\r\n if (secFetchSite === 'same-site') {\r\n if (config.trustSameSite) {\r\n return { valid: true };\r\n }\r\n // Conservative: don't trust same-site by default (subdomain takeover risk)\r\n return { valid: false, reason: 'same-site-not-trusted' };\r\n }\r\n\r\n // Cross-site: reject state-changing requests\r\n if (secFetchSite === 'cross-site') {\r\n return { valid: false, reason: 'cross-site-request' };\r\n }\r\n\r\n // Unknown value - be conservative\r\n return { valid: false, reason: 'unknown-sec-fetch-site' };\r\n }\r\n\r\n /**\r\n * Validate using Double-Submit Cookie pattern with HMAC\r\n */\r\n function validateDoubleSubmit(req: NextRequest): CsrfValidationResult {\r\n // Get token from cookie\r\n const cookieToken = req.cookies.get(config.cookieName)?.value;\r\n \r\n if (!cookieToken) {\r\n return { valid: false, reason: 'missing-cookie-token' };\r\n }\r\n\r\n // Get token from header (or form field)\r\n const headerToken = req.headers.get(config.headerName);\r\n \r\n if (!headerToken) {\r\n return { valid: false, reason: 'missing-header-token' };\r\n }\r\n\r\n // Tokens must match (constant-time comparison to prevent timing attacks)\r\n if (!constantTimeEqual(cookieToken, headerToken)) {\r\n return { valid: false, reason: 'token-mismatch' };\r\n }\r\n\r\n // Validate HMAC structure\r\n const parts = cookieToken.split('.');\r\n if (parts.length !== 2) {\r\n return { valid: false, reason: 'invalid-token-format' };\r\n }\r\n\r\n return { valid: true };\r\n }\r\n\r\n /**\r\n * Create response with CSRF cookie set\r\n */\r\n async function attachCsrfCookie(\r\n response: NextResponse, \r\n sessionId: string\r\n ): Promise<NextResponse> {\r\n const token = await generateToken(sessionId);\r\n \r\n response.cookies.set(config.cookieName, token, {\r\n httpOnly: false, // Must be readable by JS\r\n secure: process.env.NODE_ENV === 'production',\r\n sameSite: 'strict',\r\n path: '/',\r\n });\r\n\r\n return response;\r\n }\r\n\r\n return {\r\n validateRequest,\r\n generateToken,\r\n attachCsrfCookie,\r\n };\r\n}\r\n\r\n// ==================== Helper Functions ====================\r\n\r\n/**\r\n * Generate cryptographically random value\r\n */\r\nfunction generateRandomValue(): string {\r\n if (typeof crypto !== 'undefined' && crypto.getRandomValues) {\r\n const array = new Uint8Array(32);\r\n crypto.getRandomValues(array);\r\n return Array.from(array, b => b.toString(16).padStart(2, '0')).join('');\r\n }\r\n // Fallback (less secure, for edge cases)\r\n return Math.random().toString(36).substring(2) + Date.now().toString(36);\r\n}\r\n\r\n/**\r\n * Compute HMAC-SHA256\r\n */\r\nasync function computeHmac(\r\n secret: string, \r\n sessionId: string, \r\n randomValue: string\r\n): Promise<string> {\r\n const message = `${sessionId.length}!${sessionId}!${randomValue.length}!${randomValue}`;\r\n \r\n if (typeof crypto !== 'undefined' && crypto.subtle) {\r\n const encoder = new TextEncoder();\r\n const keyData = encoder.encode(secret);\r\n const messageData = encoder.encode(message);\r\n \r\n const key = await crypto.subtle.importKey(\r\n 'raw',\r\n keyData,\r\n { name: 'HMAC', hash: 'SHA-256' },\r\n false,\r\n ['sign']\r\n );\r\n \r\n const signature = await crypto.subtle.sign('HMAC', key, messageData);\r\n return Array.from(new Uint8Array(signature), b => \r\n b.toString(16).padStart(2, '0')\r\n ).join('');\r\n }\r\n \r\n // Fallback (less secure)\r\n let hash = 0;\r\n const str = secret + message;\r\n for (let i = 0; i < str.length; i++) {\r\n const char = str.charCodeAt(i);\r\n hash = ((hash << 5) - hash) + char;\r\n hash = hash & hash;\r\n }\r\n return Math.abs(hash).toString(16);\r\n}\r\n\r\n/**\r\n * Constant-time string comparison (prevents timing attacks)\r\n */\r\nfunction constantTimeEqual(a: string, b: string): boolean {\r\n if (a.length !== b.length) {\r\n return false;\r\n }\r\n \r\n let result = 0;\r\n for (let i = 0; i < a.length; i++) {\r\n result |= a.charCodeAt(i) ^ b.charCodeAt(i);\r\n }\r\n \r\n return result === 0;\r\n}\r\n\r\nexport type CsrfValidator = ReturnType<typeof createCsrfValidator>;\r\n","/**\r\n * Rate Limiting\r\n * \r\n * Implements token bucket algorithm for rate limiting.\r\n * In-memory store by default, designed for single-instance deployments.\r\n * \r\n * For horizontal scaling (multiple instances), use a custom store\r\n * with Redis or similar distributed cache.\r\n */\r\n\r\nimport { NextRequest, NextResponse } from 'next/server';\r\nimport type { ResolvedRateLimitConfig } from '../shared/types';\r\n\r\ninterface RateLimitEntry {\r\n count: number;\r\n resetAt: number;\r\n}\r\n\r\nexport interface RateLimitResult {\r\n allowed: boolean;\r\n remaining: number;\r\n resetAt: number;\r\n limit: number;\r\n}\r\n\r\n/**\r\n * Creates a rate limiter with in-memory store\r\n */\r\nexport function createRateLimiter(config: ResolvedRateLimitConfig) {\r\n // In-memory store\r\n const store = new Map<string, RateLimitEntry>();\r\n \r\n // Cleanup expired entries periodically\r\n const cleanupInterval = setInterval(() => {\r\n const now = Date.now();\r\n for (const [key, entry] of store) {\r\n if (entry.resetAt <= now) {\r\n store.delete(key);\r\n }\r\n }\r\n }, config.windowMs);\r\n\r\n // Prevent memory leak in long-running processes\r\n if (typeof process !== 'undefined' && process.on) {\r\n process.on('beforeExit', () => clearInterval(cleanupInterval));\r\n }\r\n\r\n /**\r\n * Check if route should skip rate limiting\r\n */\r\n function shouldSkip(pathname: string): boolean {\r\n return config.skipRoutes.some(pattern => {\r\n // Simple glob matching\r\n if (pattern.endsWith('*')) {\r\n return pathname.startsWith(pattern.slice(0, -1));\r\n }\r\n if (pattern.endsWith('**')) {\r\n return pathname.startsWith(pattern.slice(0, -2));\r\n }\r\n return pathname === pattern;\r\n });\r\n }\r\n\r\n /**\r\n * Check rate limit for request\r\n */\r\n function check(req: NextRequest): RateLimitResult {\r\n const pathname = req.nextUrl.pathname;\r\n \r\n // Skip if route matches skip patterns\r\n if (shouldSkip(pathname)) {\r\n return {\r\n allowed: true,\r\n remaining: config.maxRequests,\r\n resetAt: 0,\r\n limit: config.maxRequests,\r\n };\r\n }\r\n\r\n const key = config.keyFn(req);\r\n const now = Date.now();\r\n \r\n let entry = store.get(key);\r\n \r\n // New window or expired\r\n if (!entry || entry.resetAt <= now) {\r\n entry = {\r\n count: 1,\r\n resetAt: now + config.windowMs,\r\n };\r\n store.set(key, entry);\r\n \r\n return {\r\n allowed: true,\r\n remaining: config.maxRequests - 1,\r\n resetAt: entry.resetAt,\r\n limit: config.maxRequests,\r\n };\r\n }\r\n\r\n // Existing window\r\n entry.count++;\r\n \r\n const remaining = Math.max(0, config.maxRequests - entry.count);\r\n const allowed = entry.count <= config.maxRequests;\r\n \r\n return {\r\n allowed,\r\n remaining,\r\n resetAt: entry.resetAt,\r\n limit: config.maxRequests,\r\n };\r\n }\r\n\r\n /**\r\n * Apply rate limit headers to response\r\n */\r\n function applyHeaders(response: NextResponse, result: RateLimitResult): NextResponse {\r\n response.headers.set('X-RateLimit-Limit', result.limit.toString());\r\n response.headers.set('X-RateLimit-Remaining', result.remaining.toString());\r\n response.headers.set('X-RateLimit-Reset', Math.ceil(result.resetAt / 1000).toString());\r\n return response;\r\n }\r\n\r\n /**\r\n * Create rate limited response (429 Too Many Requests)\r\n */\r\n function createLimitedResponse(req: NextRequest, result: RateLimitResult): NextResponse {\r\n // User-provided handler\r\n if (config.onRateLimited) {\r\n const response = config.onRateLimited(req);\r\n return applyHeaders(response, result);\r\n }\r\n\r\n // Default response\r\n const response = NextResponse.json(\r\n {\r\n success: false,\r\n message: 'Too many requests. Please try again later.',\r\n retryAfter: Math.ceil((result.resetAt - Date.now()) / 1000),\r\n },\r\n { status: 429 }\r\n );\r\n\r\n response.headers.set('Retry-After', Math.ceil((result.resetAt - Date.now()) / 1000).toString());\r\n return applyHeaders(response, result);\r\n }\r\n\r\n /**\r\n * Reset rate limit for a key (useful for testing)\r\n */\r\n function reset(key: string): void {\r\n store.delete(key);\r\n }\r\n\r\n /**\r\n * Clear all rate limit entries\r\n */\r\n function clear(): void {\r\n store.clear();\r\n }\r\n\r\n /**\r\n * Get current store size (for monitoring)\r\n */\r\n function size(): number {\r\n return store.size;\r\n }\r\n\r\n return {\r\n check,\r\n applyHeaders,\r\n createLimitedResponse,\r\n shouldSkip,\r\n reset,\r\n clear,\r\n size,\r\n };\r\n}\r\n\r\nexport type RateLimiter = ReturnType<typeof createRateLimiter>;\r\n","/**\r\n * Audit Logging\r\n * \r\n * Event-based security audit logging system.\r\n * Emits events for authentication, access control, and security violations.\r\n */\r\n\r\nimport { NextRequest } from 'next/server';\r\nimport type { ResolvedAuditConfig, AuditEvent, AuditEventType } from '../shared/types';\r\n\r\n/**\r\n * Creates an audit logger instance\r\n */\r\nexport function createAuditLogger(config: ResolvedAuditConfig) {\r\n /**\r\n * Check if event type is enabled\r\n */\r\n function isEnabled(type: AuditEventType): boolean {\r\n return config.enabled && config.events.includes(type);\r\n }\r\n\r\n /**\r\n * Extract IP address from request\r\n */\r\n function getIp(req: NextRequest): string | null {\r\n return (\r\n req.headers.get('x-forwarded-for')?.split(',')[0]?.trim() ||\r\n req.headers.get('x-real-ip') ||\r\n null\r\n );\r\n }\r\n\r\n /**\r\n * Emit an audit event\r\n */\r\n async function emit(\r\n type: AuditEventType,\r\n req: NextRequest,\r\n options: {\r\n success: boolean;\r\n userId?: string;\r\n metadata?: Record<string, unknown>;\r\n }\r\n ): Promise<void> {\r\n if (!isEnabled(type)) {\r\n return;\r\n }\r\n\r\n const event: AuditEvent = {\r\n type,\r\n timestamp: new Date(),\r\n ip: getIp(req),\r\n userId: options.userId,\r\n path: req.nextUrl.pathname,\r\n method: req.method,\r\n success: options.success,\r\n metadata: options.metadata,\r\n };\r\n\r\n // Call user's logger\r\n if (config.logger) {\r\n try {\r\n await config.logger(event);\r\n } catch (error) {\r\n // Silently fail - don't break the request flow for logging errors\r\n console.error('[next-api-layer] Audit logger error:', error);\r\n }\r\n }\r\n }\r\n\r\n // ==================== Convenience Methods ====================\r\n\r\n /**\r\n * Log successful authentication\r\n */\r\n function authSuccess(req: NextRequest, userId?: string, metadata?: Record<string, unknown>) {\r\n return emit('auth:success', req, { success: true, userId, metadata });\r\n }\r\n\r\n /**\r\n * Log failed authentication\r\n */\r\n function authFail(req: NextRequest, metadata?: Record<string, unknown>) {\r\n return emit('auth:fail', req, { success: false, metadata });\r\n }\r\n\r\n /**\r\n * Log token refresh\r\n */\r\n function authRefresh(req: NextRequest, userId?: string, metadata?: Record<string, unknown>) {\r\n return emit('auth:refresh', req, { success: true, userId, metadata });\r\n }\r\n\r\n /**\r\n * Log guest token creation\r\n */\r\n function authGuest(req: NextRequest, metadata?: Record<string, unknown>) {\r\n return emit('auth:guest', req, { success: true, metadata });\r\n }\r\n\r\n /**\r\n * Log access denied\r\n */\r\n function accessDenied(req: NextRequest, userId?: string, metadata?: Record<string, unknown>) {\r\n return emit('access:denied', req, { success: false, userId, metadata });\r\n }\r\n\r\n /**\r\n * Log CSRF validation failure\r\n */\r\n function csrfFail(req: NextRequest, metadata?: Record<string, unknown>) {\r\n return emit('csrf:fail', req, { success: false, metadata });\r\n }\r\n\r\n /**\r\n * Log rate limit exceeded\r\n */\r\n function rateLimitExceeded(req: NextRequest, metadata?: Record<string, unknown>) {\r\n return emit('rateLimit:exceeded', req, { success: false, metadata });\r\n }\r\n\r\n /**\r\n * Log general error\r\n */\r\n function error(req: NextRequest, err: Error, metadata?: Record<string, unknown>) {\r\n return emit('error', req, { \r\n success: false, \r\n metadata: { \r\n ...metadata, \r\n error: err.message,\r\n stack: err.stack,\r\n } \r\n });\r\n }\r\n\r\n return {\r\n emit,\r\n isEnabled,\r\n // Convenience methods\r\n authSuccess,\r\n authFail,\r\n authRefresh,\r\n authGuest,\r\n accessDenied,\r\n csrfFail,\r\n rateLimitExceeded,\r\n error,\r\n };\r\n}\r\n\r\nexport type AuditLogger = ReturnType<typeof createAuditLogger>;\r\n","/**\r\n * createAuthProxy\r\n * Factory function to create Next.js middleware for external JWT authentication\r\n */\r\n\r\nimport { NextRequest, NextResponse } from 'next/server';\r\nimport type { AuthProxyConfig, AuthResult } from '../shared/types';\r\nimport { resolveProxyConfig } from '../shared/config';\r\nimport { createTokenValidation } from './tokenValidation';\r\nimport { createHandlers } from './handlers';\r\nimport { createCsrfValidator } from './csrf';\r\nimport { createRateLimiter } from './rateLimit';\r\nimport { createAuditLogger } from './audit';\r\nimport { HEADERS } from '../shared/constants';\r\n\r\n/**\r\n * Merge two NextResponse objects, preserving headers and cookies from both\r\n * Target response takes priority for conflicts\r\n */\r\nfunction mergeResponses(source: NextResponse, target: NextResponse): NextResponse {\r\n // Copy critical headers from source to target (if not already set)\r\n const criticalHeaders = [HEADERS.LOCALE, HEADERS.AUTH_USER, HEADERS.REFRESHED_TOKEN];\r\n \r\n for (const header of criticalHeaders) {\r\n const value = source.headers.get(header);\r\n if (value && !target.headers.has(header)) {\r\n target.headers.set(header, value);\r\n }\r\n }\r\n \r\n // Copy cookies from source to target (if not already set)\r\n source.cookies.getAll().forEach(cookie => {\r\n if (!target.cookies.get(cookie.name)) {\r\n target.cookies.set(cookie.name, cookie.value);\r\n }\r\n });\r\n \r\n return target;\r\n}\r\n\r\n/**\r\n * Creates an authentication proxy middleware for Next.js\r\n * \r\n * @example\r\n * ```ts\r\n * // middleware.ts\r\n * import { createAuthProxy } from 'next-api-layer';\r\n * \r\n * const authProxy = createAuthProxy({\r\n * apiBaseUrl: process.env.API_BASE_URL!,\r\n * cookies: {\r\n * user: 'userAuthToken',\r\n * guest: 'guestAuthToken',\r\n * },\r\n * guestToken: {\r\n * enabled: true,\r\n * credentials: {\r\n * username: process.env.GUEST_USERNAME!,\r\n * password: process.env.GUEST_PASSWORD!,\r\n * },\r\n * },\r\n * access: {\r\n * protectedRoutes: ['/dashboard', '/profile'],\r\n * authRoutes: ['/login', '/register'],\r\n * },\r\n * // Security features\r\n * csrf: { enabled: true },\r\n * rateLimit: { enabled: true, maxRequests: 100 },\r\n * audit: { \r\n * enabled: true, \r\n * logger: (event) => console.log('[AUDIT]', event) \r\n * },\r\n * });\r\n * \r\n * export default authProxy;\r\n * \r\n * export const config = {\r\n * matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],\r\n * };\r\n * ```\r\n */\r\nexport function createAuthProxy(userConfig: AuthProxyConfig) {\r\n // Resolve config with defaults\r\n const config = resolveProxyConfig(userConfig);\r\n \r\n // Create validation functions\r\n const validation = createTokenValidation(config);\r\n \r\n // Create handlers\r\n const handlers = createHandlers(config, validation);\r\n\r\n // Create security modules\r\n const csrf = createCsrfValidator(config._resolved.csrf);\r\n const rateLimiter = createRateLimiter(config._resolved.rateLimit);\r\n const audit = createAuditLogger(config._resolved.audit);\r\n\r\n /**\r\n * The middleware function\r\n */\r\n async function authProxy(req: NextRequest): Promise<NextResponse> {\r\n const { pathname, origin } = req.nextUrl;\r\n const isApiRoute = pathname.startsWith('/api');\r\n\r\n // ============ Rate Limiting ============\r\n // Check early to protect against DoS\r\n if (config._resolved.rateLimit.enabled) {\r\n const rateLimitResult = rateLimiter.check(req);\r\n \r\n if (!rateLimitResult.allowed) {\r\n await audit.rateLimitExceeded(req, { \r\n limit: rateLimitResult.limit,\r\n resetAt: rateLimitResult.resetAt,\r\n });\r\n return rateLimiter.createLimitedResponse(req, rateLimitResult);\r\n }\r\n }\r\n\r\n // ============ CSRF Protection ============\r\n // Check before any state-changing operations\r\n if (config._resolved.csrf.enabled) {\r\n const csrfResult = csrf.validateRequest(req);\r\n \r\n if (!csrfResult.valid) {\r\n await audit.csrfFail(req, { reason: csrfResult.reason });\r\n return NextResponse.json(\r\n { success: false, message: 'CSRF validation failed' },\r\n { status: 403 }\r\n );\r\n }\r\n }\r\n\r\n // ============ Block Browser API Access ============\r\n // Prevents direct browser access to API routes (when Accept: text/html)\r\n if (config.blockBrowserApiAccess && isApiRoute) {\r\n const acceptHeader = req.headers.get('accept') || '';\r\n if (acceptHeader.includes('text/html')) {\r\n return NextResponse.redirect(new URL('/', origin));\r\n }\r\n }\r\n\r\n // ============ beforeAuth Hook ============\r\n // Allows user to handle request before auth validation\r\n if (config.beforeAuth) {\r\n const beforeResult = await config.beforeAuth(req);\r\n if (beforeResult) {\r\n return beforeResult; // User handled the request\r\n }\r\n }\r\n\r\n // Skip excluded paths\r\n const excludedPaths = config.excludedPaths ?? [];\r\n if (excludedPaths.some(path => pathname.startsWith(path))) {\r\n return applyMiddlewaresAndHooks(req, NextResponse.next(), { isAuthenticated: false, isGuest: false, tokenType: null, user: null });\r\n }\r\n\r\n // Skip auth API endpoints (they handle their own auth)\r\n const authApiPaths = [\r\n '/api/auth/login',\r\n '/api/auth/logout',\r\n '/api/auth/me',\r\n '/api/auth/refresh',\r\n '/api/auth/register',\r\n ];\r\n \r\n if (authApiPaths.includes(pathname)) {\r\n return applyMiddlewaresAndHooks(req, NextResponse.next(), { isAuthenticated: false, isGuest: false, tokenType: null, user: null });\r\n }\r\n\r\n // Get tokens from cookies\r\n const userToken = req.cookies?.get(config.cookies.user)?.value;\r\n const guestToken = req.cookies?.get(config.cookies.guest)?.value;\r\n const currentToken = userToken || guestToken;\r\n const isUserToken = !!userToken;\r\n\r\n // No token - handle appropriately\r\n if (!currentToken) {\r\n await audit.authFail(req, { reason: 'no-token' });\r\n const response = await handlers.handleNoToken(req, isApiRoute);\r\n return applyMiddlewaresAndHooks(req, response, { isAuthenticated: false, isGuest: false, tokenType: null, user: null });\r\n }\r\n\r\n // Validate token\r\n const tokenInfo = await validation.getTokenInfo(currentToken);\r\n \r\n // Build auth result for afterAuth hook\r\n const authResult: AuthResult = {\r\n isAuthenticated: tokenInfo.isValid && tokenInfo.tokenType !== 'guest',\r\n isGuest: tokenInfo.isValid && tokenInfo.tokenType === 'guest',\r\n tokenType: tokenInfo.tokenType,\r\n user: tokenInfo.userData,\r\n };\r\n\r\n // Audit logging based on validation result \r\n if (tokenInfo.isValid) {\r\n if (tokenInfo.tokenType === 'guest') {\r\n await audit.authGuest(req);\r\n } else {\r\n const userId = tokenInfo.userData?.id?.toString();\r\n await audit.authSuccess(req, userId, { tokenType: tokenInfo.tokenType });\r\n }\r\n } else {\r\n await audit.authFail(req, { reason: 'invalid-token' });\r\n }\r\n\r\n // Handle validation result\r\n const response = await handlers.handleValidationResult(\r\n req,\r\n tokenInfo,\r\n isUserToken,\r\n currentToken,\r\n isApiRoute\r\n );\r\n \r\n // Apply CSRF cookie if enabled (for authenticated requests)\r\n let finalResponse = await applyMiddlewaresAndHooks(req, response, authResult);\r\n \r\n if (config._resolved.csrf.enabled && authResult.isAuthenticated) {\r\n const sessionId = tokenInfo.userData?.id?.toString() || currentToken.slice(0, 32);\r\n finalResponse = await csrf.attachCsrfCookie(finalResponse, sessionId);\r\n }\r\n\r\n // Apply rate limit headers\r\n if (config._resolved.rateLimit.enabled) {\r\n const rateLimitResult = rateLimiter.check(req);\r\n finalResponse = rateLimiter.applyHeaders(finalResponse, rateLimitResult);\r\n }\r\n \r\n return finalResponse;\r\n }\r\n \r\n /**\r\n * Helper to apply i18n middleware and afterAuth hook\r\n * Merges responses to preserve critical headers (x-locale, x-auth-user, etc.)\r\n */\r\n async function applyMiddlewaresAndHooks(req: NextRequest, response: NextResponse, authResult: AuthResult): Promise<NextResponse> {\r\n let finalResponse = response;\r\n \r\n // Apply i18n middleware if configured\r\n if (config.i18n?.middleware) {\r\n const intlResponse = await Promise.resolve(config.i18n.middleware(req));\r\n // Merge library's response headers into i18n response\r\n finalResponse = mergeResponses(response, intlResponse);\r\n }\r\n \r\n // Apply afterAuth hook if configured\r\n if (config.afterAuth) {\r\n const hookResponse = await config.afterAuth(req, finalResponse, authResult);\r\n // Merge previous response headers into hook's response\r\n finalResponse = mergeResponses(finalResponse, hookResponse);\r\n }\r\n \r\n return finalResponse;\r\n }\r\n\r\n // Attach instances for debugging/testing\r\n authProxy.config = config;\r\n authProxy.csrf = csrf;\r\n authProxy.rateLimiter = rateLimiter;\r\n authProxy.audit = audit;\r\n\r\n return authProxy;\r\n}\r\n\r\nexport type AuthProxy = ReturnType<typeof createAuthProxy>;\r\n\r\n","/**\r\n * createProxyHandler\r\n * Factory function to create Next.js API route handlers that proxy requests to backend\r\n */\r\n\r\nimport { NextRequest, NextResponse } from 'next/server';\r\nimport { HEADERS } from '../shared/constants';\r\n\r\nexport interface ProxyHandlerConfig {\r\n /** Base URL of the backend API */\r\n apiBaseUrl: string;\r\n /** Cookie name for user auth token */\r\n userCookieName?: string;\r\n /** Cookie name for guest auth token */\r\n guestCookieName?: string;\r\n /** \r\n * Default behavior for auth - if true, all requests skip auth by default\r\n * Individual requests can override with X-Skip-Auth header\r\n */\r\n skipAuthByDefault?: boolean;\r\n /**\r\n * Public endpoints that should never include auth token (glob patterns)\r\n * e.g., ['news/*', 'public/**', 'categories']\r\n */\r\n publicEndpoints?: string[];\r\n /** Headers to forward from client request */\r\n forwardHeaders?: string[];\r\n /** Headers to exclude from forwarding */\r\n excludeHeaders?: string[];\r\n /** Custom request transformer */\r\n transformRequest?: (req: NextRequest, headers: Headers) => Headers | Promise<Headers>;\r\n /** Custom response transformer */\r\n transformResponse?: (response: Response) => Response | Promise<Response>;\r\n}\r\n\r\n/**\r\n * Check if endpoint matches any patterns (glob support)\r\n */\r\nfunction matchesPattern(endpoint: string, patterns: string[]): boolean {\r\n if (!patterns || patterns.length === 0) return false;\r\n \r\n // Normalize endpoint\r\n const normalizedEndpoint = endpoint\r\n .replace(/^\\/api\\//, '')\r\n .replace(/^\\//, '');\r\n \r\n return patterns.some(pattern => {\r\n if (pattern === normalizedEndpoint) return true;\r\n \r\n if (pattern.includes('*')) {\r\n const regexPattern = pattern\r\n .replace(/\\*\\*/g, '<<<DOUBLE>>>')\r\n .replace(/\\*/g, '[^/]+')\r\n .replace(/<<<DOUBLE>>>/g, '.+');\r\n const regex = new RegExp(`^${regexPattern}$`);\r\n return regex.test(normalizedEndpoint);\r\n }\r\n \r\n return false;\r\n });\r\n}\r\n\r\n/**\r\n * Creates a proxy handler for Next.js API routes\r\n * \r\n * @example\r\n * ```ts\r\n * // app/api/[...path]/route.ts\r\n * import { createProxyHandler } from 'next-api-layer';\r\n * \r\n * const handler = createProxyHandler({\r\n * apiBaseUrl: process.env.API_BASE_URL!,\r\n * userCookieName: 'auth_token',\r\n * guestCookieName: 'guest_token',\r\n * publicEndpoints: ['news/*', 'categories', 'public/**'],\r\n * });\r\n * \r\n * export const GET = handler;\r\n * export const POST = handler;\r\n * export const PUT = handler;\r\n * export const PATCH = handler;\r\n * export const DELETE = handler;\r\n * ```\r\n */\r\nexport function createProxyHandler(config: ProxyHandlerConfig) {\r\n const {\r\n apiBaseUrl,\r\n userCookieName = 'auth_token',\r\n guestCookieName = 'guest_token',\r\n skipAuthByDefault = false,\r\n publicEndpoints = [],\r\n forwardHeaders = ['content-type', 'accept', 'accept-language', 'x-requested-with'],\r\n excludeHeaders = ['host', 'connection', 'cookie'],\r\n transformRequest,\r\n transformResponse,\r\n } = config;\r\n\r\n // Normalize base URL (remove trailing slash)\r\n const baseUrl = apiBaseUrl.replace(/\\/$/, '');\r\n\r\n /**\r\n * Determine if auth should be skipped for this request\r\n */\r\n function shouldSkipAuth(req: NextRequest, endpoint: string): boolean {\r\n // Check X-Skip-Auth header from client\r\n const skipAuthHeader = req.headers.get(HEADERS.SKIP_AUTH);\r\n if (skipAuthHeader === 'true') {\r\n return true;\r\n }\r\n \r\n // Check if endpoint matches public patterns\r\n if (matchesPattern(endpoint, publicEndpoints)) {\r\n return true;\r\n }\r\n \r\n // Default behavior\r\n return skipAuthByDefault;\r\n }\r\n\r\n /**\r\n * The proxy handler function\r\n */\r\n async function handler(req: NextRequest): Promise<NextResponse> {\r\n try {\r\n // Extract endpoint from URL path (remove /api/ prefix)\r\n const url = new URL(req.url);\r\n const endpoint = url.pathname.replace(/^\\/api\\/?/, '');\r\n \r\n // Build backend URL\r\n const backendUrl = new URL(`${baseUrl}/${endpoint}`);\r\n backendUrl.search = url.search; // Forward query params\r\n\r\n // Build headers for backend request\r\n const headers = new Headers();\r\n \r\n // Forward allowed headers from original request\r\n forwardHeaders.forEach(headerName => {\r\n const value = req.headers.get(headerName);\r\n if (value) {\r\n headers.set(headerName, value);\r\n }\r\n });\r\n\r\n // Forward all headers except excluded ones\r\n req.headers.forEach((value, key) => {\r\n const lowerKey = key.toLowerCase();\r\n if (!excludeHeaders.includes(lowerKey) && !headers.has(key)) {\r\n headers.set(key, value);\r\n }\r\n });\r\n\r\n // Add Authorization header if auth is not skipped\r\n if (!shouldSkipAuth(req, endpoint)) {\r\n const userToken = req.cookies.get(userCookieName)?.value;\r\n const guestToken = req.cookies.get(guestCookieName)?.value;\r\n const token = userToken || guestToken;\r\n \r\n if (token) {\r\n headers.set(HEADERS.AUTHORIZATION, `Bearer ${token}`);\r\n }\r\n }\r\n\r\n // Remove skip-auth header (internal use only)\r\n headers.delete(HEADERS.SKIP_AUTH);\r\n\r\n // Allow custom request transformation\r\n const finalHeaders = transformRequest \r\n ? await transformRequest(req, headers) \r\n : headers;\r\n\r\n // Get request body if present\r\n let body: BodyInit | null = null;\r\n if (req.method !== 'GET' && req.method !== 'HEAD') {\r\n const contentType = req.headers.get('content-type') || '';\r\n \r\n if (contentType.includes('application/json')) {\r\n body = await req.text();\r\n } else if (contentType.includes('multipart/form-data')) {\r\n body = await req.formData();\r\n } else {\r\n body = await req.text();\r\n }\r\n }\r\n\r\n // Make request to backend\r\n const backendResponse = await fetch(backendUrl.toString(), {\r\n method: req.method,\r\n headers: finalHeaders,\r\n body,\r\n });\r\n\r\n // Get response body\r\n const contentType = backendResponse.headers.get('content-type') || '';\r\n let responseBody: ArrayBuffer | string;\r\n \r\n if (contentType.includes('application/json')) {\r\n responseBody = await backendResponse.text();\r\n } else {\r\n responseBody = await backendResponse.arrayBuffer();\r\n }\r\n\r\n // Build response headers (forward relevant ones)\r\n const responseHeaders = new Headers();\r\n backendResponse.headers.forEach((value, key) => {\r\n const lowerKey = key.toLowerCase();\r\n // Skip hop-by-hop headers\r\n if (!['transfer-encoding', 'connection', 'keep-alive'].includes(lowerKey)) {\r\n responseHeaders.set(key, value);\r\n }\r\n });\r\n\r\n // Create response\r\n let response = new NextResponse(responseBody, {\r\n status: backendResponse.status,\r\n statusText: backendResponse.statusText,\r\n headers: responseHeaders,\r\n });\r\n\r\n // Allow custom response transformation\r\n if (transformResponse) {\r\n response = await transformResponse(response) as NextResponse;\r\n }\r\n\r\n return response;\r\n } catch (error) {\r\n console.error('[Proxy Error]', error);\r\n \r\n return NextResponse.json(\r\n { \r\n success: false, \r\n message: 'Proxy error: Unable to connect to backend',\r\n error: error instanceof Error ? error.message : 'Unknown error',\r\n },\r\n { status: 502 }\r\n );\r\n }\r\n }\r\n\r\n // Attach config for debugging\r\n handler.config = config;\r\n\r\n return handler;\r\n}\r\n\r\nexport type ProxyHandler = ReturnType<typeof createProxyHandler>;\r\n"]}
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { NextRequest, NextResponse } from 'next/server';
2
- import { R as ResolvedRateLimitConfig, a as ResolvedCsrfConfig, A as AuthProxyConfig, I as InternalProxyConfig, b as AuditEventType, c as ResolvedAuditConfig, T as TokenInfo, d as RefreshResult, C as CookieOptions, E as EndpointConfig } from './createApiClient-BliWeW4X.cjs';
3
- export { e as AccessConfig, f as ApiClient, g as ApiClientConfig, h as ApiResponse, i as AuditConfig, j as AuditEvent, k as AuthData, l as AuthResult, m as CookieConfig, n as CsrfConfig, G as GuestTokenConfig, o as I18nConfig, p as RateLimitConfig, q as ResponseMappers, S as SanitizationConfig, U as UserData, r as createApiClient } from './createApiClient-BliWeW4X.cjs';
2
+ import { R as ResolvedRateLimitConfig, a as ResolvedCsrfConfig, A as AuthProxyConfig, I as InternalProxyConfig, b as AuditEventType, c as ResolvedAuditConfig, T as TokenInfo, d as RefreshResult, C as CookieOptions, E as EndpointConfig } from './createApiClient-Brlw1L7n.cjs';
3
+ export { e as AccessConfig, f as ApiClient, g as ApiClientConfig, h as ApiResponse, i as AuditConfig, j as AuditEvent, k as AuthData, l as AuthResult, m as CookieConfig, n as CsrfConfig, G as GuestTokenConfig, o as I18nConfig, p as RateLimitConfig, q as ResponseMappers, S as SanitizationConfig, U as UserData, r as createApiClient } from './createApiClient-Brlw1L7n.cjs';
4
4
 
5
5
  /**
6
6
  * Rate Limiting
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { NextRequest, NextResponse } from 'next/server';
2
- import { R as ResolvedRateLimitConfig, a as ResolvedCsrfConfig, A as AuthProxyConfig, I as InternalProxyConfig, b as AuditEventType, c as ResolvedAuditConfig, T as TokenInfo, d as RefreshResult, C as CookieOptions, E as EndpointConfig } from './createApiClient-BliWeW4X.js';
3
- export { e as AccessConfig, f as ApiClient, g as ApiClientConfig, h as ApiResponse, i as AuditConfig, j as AuditEvent, k as AuthData, l as AuthResult, m as CookieConfig, n as CsrfConfig, G as GuestTokenConfig, o as I18nConfig, p as RateLimitConfig, q as ResponseMappers, S as SanitizationConfig, U as UserData, r as createApiClient } from './createApiClient-BliWeW4X.js';
2
+ import { R as ResolvedRateLimitConfig, a as ResolvedCsrfConfig, A as AuthProxyConfig, I as InternalProxyConfig, b as AuditEventType, c as ResolvedAuditConfig, T as TokenInfo, d as RefreshResult, C as CookieOptions, E as EndpointConfig } from './createApiClient-Brlw1L7n.js';
3
+ export { e as AccessConfig, f as ApiClient, g as ApiClientConfig, h as ApiResponse, i as AuditConfig, j as AuditEvent, k as AuthData, l as AuthResult, m as CookieConfig, n as CsrfConfig, G as GuestTokenConfig, o as I18nConfig, p as RateLimitConfig, q as ResponseMappers, S as SanitizationConfig, U as UserData, r as createApiClient } from './createApiClient-Brlw1L7n.js';
4
4
 
5
5
  /**
6
6
  * Rate Limiting
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- export{d as createApiClient}from'./chunk-NDZA32WH.js';import {c,e,a,b,g,h,i}from'./chunk-XBAO7FJN.js';export{f as CSRF_SAFE_METHODS,i as DEFAULT_AUDIT_CONFIG,a as DEFAULT_COOKIE_OPTIONS,g as DEFAULT_CSRF_CONFIG,b as DEFAULT_ENDPOINTS,h as DEFAULT_RATE_LIMIT_CONFIG,d as ERROR_MESSAGES,e as HEADERS,c as TOKEN_TYPES}from'./chunk-XBAO7FJN.js';import {NextResponse}from'next/server';function ie(){return typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID()+crypto.randomUUID():`${Date.now()}-${Math.random().toString(36).substring(2)}`}function ue(e){return `rl:${e.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||e.headers.get("x-real-ip")||"unknown"}`}function Q(e){if(!e.apiBaseUrl)throw new Error("next-api-layer: apiBaseUrl is required");if(!e.cookies?.user||!e.cookies?.guest)throw new Error("next-api-layer: cookies.user and cookies.guest are required");let t=e.apiBaseUrl.endsWith("/")?e.apiBaseUrl:`${e.apiBaseUrl}/`,f={...a,...e.cookies.options},l={...b,...e.endpoints},m={enabled:e.csrf?.enabled??false,strategy:e.csrf?.strategy??g.strategy,secret:e.csrf?.secret??ie(),cookieName:e.csrf?.cookieName??g.cookieName,headerName:e.csrf?.headerName??g.headerName,ignoreMethods:e.csrf?.ignoreMethods??g.ignoreMethods,trustSameSite:e.csrf?.trustSameSite??g.trustSameSite},R={enabled:e.rateLimit?.enabled??false,windowMs:e.rateLimit?.windowMs??h.windowMs,maxRequests:e.rateLimit?.maxRequests??h.maxRequests,keyFn:e.rateLimit?.keyFn??ue,skipRoutes:e.rateLimit?.skipRoutes??h.skipRoutes,onRateLimited:e.rateLimit?.onRateLimited},u={enabled:e.audit?.enabled??false,events:e.audit?.events??[...i.events],logger:e.audit?.logger};return {...e,apiBaseUrl:t,_resolved:{cookieOptions:f,endpoints:l,csrf:m,rateLimit:R,audit:u}}}var $={parseAuthMe:e=>{let t=e;return !t?.success||!t?.data?null:{isValid:true,tokenType:t.data.type||"user",exp:t.data.exp||null,userData:t.data}},parseRefreshToken:e=>{let t=e;return t?.success&&t?.data?.accessToken?t.data.accessToken:null},parseGuestToken:e=>e?.data?.accessToken||null};function j(e){let{apiBaseUrl:t,_resolved:f,responseMappers:l}=e,{endpoints:m}=f,R={parseAuthMe:l?.parseAuthMe||$.parseAuthMe,parseRefreshToken:l?.parseRefreshToken||$.parseRefreshToken,parseGuestToken:l?.parseGuestToken||$.parseGuestToken};async function u(a){let i={isValid:false,tokenType:null,exp:null,userData:null};try{let n=await fetch(`${t}${m.validate}`,{headers:{Authorization:`Bearer ${a}`,"Content-Type":"application/json"},cache:"no-store"});if(!n.ok)return i;let s=await n.json().catch(()=>null),d=R.parseAuthMe(s);return !d||!d.isValid?i:d}catch{return i}}async function c(a){return u(a)}async function p(a){try{let i=await fetch(`${t}${m.refresh}`,{method:"POST",headers:{Authorization:`Bearer ${a}`,"Content-Type":"application/json"},cache:"no-store"});if(!i.ok)return {success:!1,newToken:null};let n=await i.json().catch(()=>null),s=R.parseRefreshToken(n);return s?{success:!0,newToken:s}:{success:!1,newToken:null}}catch{return {success:false,newToken:null}}}async function o(){let a=e.guestToken;if(!a?.enabled||!a.credentials)return null;try{let i=await fetch(`${t}${m.guest}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({username:a.credentials.username,password:a.credentials.password}),cache:"no-store"});if(!i.ok)return null;let n=await i.json().catch(()=>null);return R.parseGuestToken(n)}catch{return null}}return {validateToken:u,getTokenInfo:c,refreshToken:p,createGuestToken:o}}function ee(e,t){if(!t?.enabled)return null;let f=t.locales??[],l=t.defaultLocale,R=e.split("/").filter(Boolean)[0];return R&&f.includes(R)?R:l??null}function z(e$1,t){let{cookies:f,guestToken:l,access:m,i18n:R,_resolved:u}=e$1,{cookieOptions:c$1}=u;function p(r,x,h){r.cookies.get(h)?.value&&x.cookies.delete(h);}function o(r,x){return p(r,x,f.guest),p(r,x,f.user),x}function a(r,x=500){return new NextResponse(JSON.stringify({success:false,message:r}),{status:x,headers:{"Content-Type":"application/json"}})}function i(r){return (m?.authRoutes??[]).some(h=>r===h||r.startsWith(`${h}/`))}function n(r){return m?.protectedByDefault?!s(r)&&!i(r):(m?.protectedRoutes??[]).some(h=>r===h||r.startsWith(`${h}/`))}function s(r){return (m?.publicRoutes??[]).some(h=>r===h||r.startsWith(`${h}/`))}function d(r){let x=m?.allowedTokenTypes;return !x||x.length===0?true:r?x.includes(r):false}async function C(r,x){let{origin:h}=r.nextUrl;if(l?.enabled){let y=await t.createGuestToken();if(y){let N;return x?N=NextResponse.next():n(r.nextUrl.pathname)?N=NextResponse.redirect(new URL("/login",h)):N=NextResponse.next(),N.cookies.set(f.guest,y,{...c$1,maxAge:3600}),N}}return x?a("Token bulunamad\u0131",401):n(r.nextUrl.pathname)?NextResponse.redirect(new URL("/login",h)):NextResponse.next()}async function v(r,x,h,y,N){let{pathname:k,origin:g}=r.nextUrl,{isValid:S,tokenType:T,userData:A}=x,E=T===c.GUEST;if(!S){if(h&&y){let D=await t.refreshToken(y);if(D.success&&D.newToken){let O=await t.getTokenInfo(D.newToken);if(O.isValid){let _=new Headers(r.headers);O.userData&&_.set(e.AUTH_USER,JSON.stringify(O.userData)),_.set(e.REFRESHED_TOKEN,D.newToken);let Z=ee(k,R);Z&&_.set(e.LOCALE,Z);let I;return i(k)?I=NextResponse.redirect(new URL("/",g)):I=NextResponse.next({request:{headers:_}}),I.cookies.set(f.user,D.newToken,{...c$1,maxAge:c$1.maxAge}),p(r,I,f.guest),I}}}let P=await C(r,N);return P.cookies.get(f.guest)?.value?p(r,P,f.user):o(r,P),P}let U=new Headers(r.headers);A&&U.set(e.AUTH_USER,JSON.stringify(A));let J=ee(k,R);if(J&&U.set(e.LOCALE,J),!E&&!d(T)){if(N){let Y=a("Bu i\u015Flem i\xE7in yetkiniz yok",403);return o(r,Y)}let P=NextResponse.redirect(new URL("/login",g));return o(r,P)}if(E)return N?NextResponse.next({request:{headers:U}}):n(k)?NextResponse.redirect(new URL("/login",g)):NextResponse.next({request:{headers:U}});if(i(k))return NextResponse.redirect(new URL("/",g));let X=NextResponse.next({request:{headers:U}});return p(r,X,f.guest),X}return {deleteAllAuthCookies:o,jsonError:a,isAuthPage:i,isProtectedRoute:n,isPublicRoute:s,isTokenTypeAllowed:d,handleNoToken:C,handleValidationResult:v}}function K(e){async function t(u){let c=le();return `${await ce(e.secret,u,c)}.${c}`}function f(u){let c=u.method.toUpperCase();if(e.ignoreMethods.includes(c))return {valid:true};let p=e.strategy;if(p==="fetch-metadata"||p==="both"){let o=l(u);if(p==="fetch-metadata"||o.valid||o.reason!=="missing-headers")return o}return p==="double-submit"||p==="both"?m(u):{valid:true}}function l(u){let c=u.headers.get("sec-fetch-site");if(!c)return {valid:false,reason:"missing-headers"};if(c==="same-origin")return {valid:true};if(c==="none"){let p=u.method.toUpperCase();return e.ignoreMethods.includes(p)?{valid:true}:{valid:false,reason:"direct-navigation-unsafe-method"}}return c==="same-site"?e.trustSameSite?{valid:true}:{valid:false,reason:"same-site-not-trusted"}:c==="cross-site"?{valid:false,reason:"cross-site-request"}:{valid:false,reason:"unknown-sec-fetch-site"}}function m(u){let c=u.cookies.get(e.cookieName)?.value;if(!c)return {valid:false,reason:"missing-cookie-token"};let p=u.headers.get(e.headerName);return p?de(c,p)?c.split(".").length!==2?{valid:false,reason:"invalid-token-format"}:{valid:true}:{valid:false,reason:"token-mismatch"}:{valid:false,reason:"missing-header-token"}}async function R(u,c){let p=await t(c);return u.cookies.set(e.cookieName,p,{httpOnly:false,secure:process.env.NODE_ENV==="production",sameSite:"strict",path:"/"}),u}return {validateRequest:f,generateToken:t,attachCsrfCookie:R}}function le(){if(typeof crypto<"u"&&crypto.getRandomValues){let e=new Uint8Array(32);return crypto.getRandomValues(e),Array.from(e,t=>t.toString(16).padStart(2,"0")).join("")}return Math.random().toString(36).substring(2)+Date.now().toString(36)}async function ce(e,t,f){let l=`${t.length}!${t}!${f.length}!${f}`;if(typeof crypto<"u"&&crypto.subtle){let u=new TextEncoder,c=u.encode(e),p=u.encode(l),o=await crypto.subtle.importKey("raw",c,{name:"HMAC",hash:"SHA-256"},false,["sign"]),a=await crypto.subtle.sign("HMAC",o,p);return Array.from(new Uint8Array(a),i=>i.toString(16).padStart(2,"0")).join("")}let m=0,R=e+l;for(let u=0;u<R.length;u++){let c=R.charCodeAt(u);m=(m<<5)-m+c,m=m&m;}return Math.abs(m).toString(16)}function de(e,t){if(e.length!==t.length)return false;let f=0;for(let l=0;l<e.length;l++)f|=e.charCodeAt(l)^t.charCodeAt(l);return f===0}function W(e){let t=new Map,f=setInterval(()=>{let a=Date.now();for(let[i,n]of t)n.resetAt<=a&&t.delete(i);},e.windowMs);typeof process<"u"&&process.on&&process.on("beforeExit",()=>clearInterval(f));function l(a){return e.skipRoutes.some(i=>i.endsWith("*")?a.startsWith(i.slice(0,-1)):i.endsWith("**")?a.startsWith(i.slice(0,-2)):a===i)}function m(a){let i=a.nextUrl.pathname;if(l(i))return {allowed:true,remaining:e.maxRequests,resetAt:0,limit:e.maxRequests};let n=e.keyFn(a),s=Date.now(),d=t.get(n);if(!d||d.resetAt<=s)return d={count:1,resetAt:s+e.windowMs},t.set(n,d),{allowed:true,remaining:e.maxRequests-1,resetAt:d.resetAt,limit:e.maxRequests};d.count++;let C=Math.max(0,e.maxRequests-d.count);return {allowed:d.count<=e.maxRequests,remaining:C,resetAt:d.resetAt,limit:e.maxRequests}}function R(a,i){return a.headers.set("X-RateLimit-Limit",i.limit.toString()),a.headers.set("X-RateLimit-Remaining",i.remaining.toString()),a.headers.set("X-RateLimit-Reset",Math.ceil(i.resetAt/1e3).toString()),a}function u(a,i){if(e.onRateLimited){let s=e.onRateLimited(a);return R(s,i)}let n=NextResponse.json({success:false,message:"Too many requests. Please try again later.",retryAfter:Math.ceil((i.resetAt-Date.now())/1e3)},{status:429});return n.headers.set("Retry-After",Math.ceil((i.resetAt-Date.now())/1e3).toString()),R(n,i)}function c(a){t.delete(a);}function p(){t.clear();}function o(){return t.size}return {check:m,applyHeaders:R,createLimitedResponse:u,shouldSkip:l,reset:c,clear:p,size:o}}function q(e){function t(n){return e.enabled&&e.events.includes(n)}function f(n){return n.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||n.headers.get("x-real-ip")||null}async function l(n,s,d){if(!t(n))return;let C={type:n,timestamp:new Date,ip:f(s),userId:d.userId,path:s.nextUrl.pathname,method:s.method,success:d.success,metadata:d.metadata};if(e.logger)try{await e.logger(C);}catch(v){console.error("[next-api-layer] Audit logger error:",v);}}function m(n,s,d){return l("auth:success",n,{success:true,userId:s,metadata:d})}function R(n,s){return l("auth:fail",n,{success:false,metadata:s})}function u(n,s,d){return l("auth:refresh",n,{success:true,userId:s,metadata:d})}function c(n,s){return l("auth:guest",n,{success:true,metadata:s})}function p(n,s,d){return l("access:denied",n,{success:false,userId:s,metadata:d})}function o(n,s){return l("csrf:fail",n,{success:false,metadata:s})}function a(n,s){return l("rateLimit:exceeded",n,{success:false,metadata:s})}function i(n,s,d){return l("error",n,{success:false,metadata:{...d,error:s.message,stack:s.stack}})}return {emit:l,isEnabled:t,authSuccess:m,authFail:R,authRefresh:u,authGuest:c,accessDenied:p,csrfFail:o,rateLimitExceeded:a,error:i}}function te(e){let t=Q(e),f=j(t),l=z(t,f),m=K(t._resolved.csrf),R=W(t._resolved.rateLimit),u=q(t._resolved.audit);async function c(o){let{pathname:a,origin:i}=o.nextUrl,n=a.startsWith("/api");if(t._resolved.rateLimit.enabled){let g=R.check(o);if(!g.allowed)return await u.rateLimitExceeded(o,{limit:g.limit,resetAt:g.resetAt}),R.createLimitedResponse(o,g)}if(t._resolved.csrf.enabled){let g=m.validateRequest(o);if(!g.valid)return await u.csrfFail(o,{reason:g.reason}),NextResponse.json({success:false,message:"CSRF validation failed"},{status:403})}if(t.blockBrowserApiAccess&&n&&(o.headers.get("accept")||"").includes("text/html"))return NextResponse.redirect(new URL("/",i));if(t.beforeAuth){let g=await t.beforeAuth(o);if(g)return g}if((t.excludedPaths??[]).some(g=>a.startsWith(g)))return p(o,NextResponse.next(),{isAuthenticated:false,isGuest:false,tokenType:null,user:null});if(["/api/auth/login","/api/auth/logout","/api/auth/me","/api/auth/refresh","/api/auth/register"].includes(a))return p(o,NextResponse.next(),{isAuthenticated:false,isGuest:false,tokenType:null,user:null});let C=o.cookies?.get(t.cookies.user)?.value,v=o.cookies?.get(t.cookies.guest)?.value,r=C||v,x=!!C;if(!r){await u.authFail(o,{reason:"no-token"});let g=await l.handleNoToken(o,n);return p(o,g,{isAuthenticated:false,isGuest:false,tokenType:null,user:null})}let h=await f.getTokenInfo(r),y={isAuthenticated:h.isValid&&h.tokenType!=="guest",isGuest:h.isValid&&h.tokenType==="guest",tokenType:h.tokenType,user:h.userData};if(h.isValid)if(h.tokenType==="guest")await u.authGuest(o);else {let g=h.userData?.id?.toString();await u.authSuccess(o,g,{tokenType:h.tokenType});}else await u.authFail(o,{reason:"invalid-token"});let N=await l.handleValidationResult(o,h,x,r,n),k=await p(o,N,y);if(t._resolved.csrf.enabled&&y.isAuthenticated){let g=h.userData?.id?.toString()||r.slice(0,32);k=await m.attachCsrfCookie(k,g);}if(t._resolved.rateLimit.enabled){let g=R.check(o);k=R.applyHeaders(k,g);}return k}async function p(o,a,i){return t.afterAuth?t.afterAuth(o,a,i):a}return c.config=t,c.csrf=m,c.rateLimiter=R,c.audit=u,c}function pe(e,t){if(!t||t.length===0)return false;let f=e.replace(/^\/api\//,"").replace(/^\//,"");return t.some(l=>{if(l===f)return true;if(l.includes("*")){let m=l.replace(/\*\*/g,"<<<DOUBLE>>>").replace(/\*/g,"[^/]+").replace(/<<<DOUBLE>>>/g,".+");return new RegExp(`^${m}$`).test(f)}return false})}function ne(e$1){let{apiBaseUrl:t,userCookieName:f="auth_token",guestCookieName:l="guest_token",skipAuthByDefault:m=false,publicEndpoints:R=[],forwardHeaders:u=["content-type","accept","accept-language","x-requested-with"],excludeHeaders:c=["host","connection","cookie"],transformRequest:p,transformResponse:o}=e$1,a=t.replace(/\/$/,"");function i(s,d){return s.headers.get(e.SKIP_AUTH)==="true"||pe(d,R)?true:m}async function n(s){try{let d=new URL(s.url),C=d.pathname.replace(/^\/api\/?/,""),v=new URL(`${a}/${C}`);v.search=d.search;let r=new Headers;if(u.forEach(T=>{let A=s.headers.get(T);A&&r.set(T,A);}),s.headers.forEach((T,A)=>{let E=A.toLowerCase();!c.includes(E)&&!r.has(A)&&r.set(A,T);}),!i(s,C)){let T=s.cookies.get(f)?.value,A=s.cookies.get(l)?.value,E=T||A;E&&r.set(e.AUTHORIZATION,`Bearer ${E}`);}r.delete(e.SKIP_AUTH);let x=p?await p(s,r):r,h=null;if(s.method!=="GET"&&s.method!=="HEAD"){let T=s.headers.get("content-type")||"";T.includes("application/json")?h=await s.text():T.includes("multipart/form-data")?h=await s.formData():h=await s.text();}let y=await fetch(v.toString(),{method:s.method,headers:x,body:h}),N=y.headers.get("content-type")||"",k;N.includes("application/json")?k=await y.text():k=await y.arrayBuffer();let g=new Headers;y.headers.forEach((T,A)=>{let E=A.toLowerCase();["transfer-encoding","connection","keep-alive"].includes(E)||g.set(A,T);});let S=new NextResponse(k,{status:y.status,statusText:y.statusText,headers:g});return o&&(S=await o(S)),S}catch(d){return console.error("[Proxy Error]",d),NextResponse.json({success:false,message:"Proxy error: Unable to connect to backend",error:d instanceof Error?d.message:"Unknown error"},{status:502})}}return n.config=e$1,n}
2
- export{q as createAuditLogger,te as createAuthProxy,K as createCsrfValidator,z as createHandlers,ne as createProxyHandler,W as createRateLimiter,j as createTokenValidation};//# sourceMappingURL=index.js.map
1
+ export{d as createApiClient}from'./chunk-NDZA32WH.js';import {c,e,a,b,g,h,i}from'./chunk-XBAO7FJN.js';export{f as CSRF_SAFE_METHODS,i as DEFAULT_AUDIT_CONFIG,a as DEFAULT_COOKIE_OPTIONS,g as DEFAULT_CSRF_CONFIG,b as DEFAULT_ENDPOINTS,h as DEFAULT_RATE_LIMIT_CONFIG,d as ERROR_MESSAGES,e as HEADERS,c as TOKEN_TYPES}from'./chunk-XBAO7FJN.js';import {NextResponse}from'next/server';function ue(){return typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID()+crypto.randomUUID():`${Date.now()}-${Math.random().toString(36).substring(2)}`}function le(e){return `rl:${e.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||e.headers.get("x-real-ip")||"unknown"}`}function Q(e){if(!e.apiBaseUrl)throw new Error("next-api-layer: apiBaseUrl is required");if(!e.cookies?.user||!e.cookies?.guest)throw new Error("next-api-layer: cookies.user and cookies.guest are required");let t=e.apiBaseUrl.endsWith("/")?e.apiBaseUrl:`${e.apiBaseUrl}/`,f={...a,...e.cookies.options},r={...b,...e.endpoints},p={enabled:e.csrf?.enabled??false,strategy:e.csrf?.strategy??g.strategy,secret:e.csrf?.secret??ue(),cookieName:e.csrf?.cookieName??g.cookieName,headerName:e.csrf?.headerName??g.headerName,ignoreMethods:e.csrf?.ignoreMethods??g.ignoreMethods,trustSameSite:e.csrf?.trustSameSite??g.trustSameSite},R={enabled:e.rateLimit?.enabled??false,windowMs:e.rateLimit?.windowMs??h.windowMs,maxRequests:e.rateLimit?.maxRequests??h.maxRequests,keyFn:e.rateLimit?.keyFn??le,skipRoutes:e.rateLimit?.skipRoutes??h.skipRoutes,onRateLimited:e.rateLimit?.onRateLimited},l={enabled:e.audit?.enabled??false,events:e.audit?.events??[...i.events],logger:e.audit?.logger};return {...e,apiBaseUrl:t,_resolved:{cookieOptions:f,endpoints:r,csrf:p,rateLimit:R,audit:l}}}var $={parseAuthMe:e=>{let t=e;return !t?.success||!t?.data?null:{isValid:true,tokenType:t.data.type||"user",exp:t.data.exp||null,userData:t.data}},parseRefreshToken:e=>{let t=e;return t?.success&&t?.data?.accessToken?t.data.accessToken:null},parseGuestToken:e=>e?.data?.accessToken||null};function j(e){let{apiBaseUrl:t,_resolved:f,responseMappers:r}=e,{endpoints:p}=f,R={parseAuthMe:r?.parseAuthMe||$.parseAuthMe,parseRefreshToken:r?.parseRefreshToken||$.parseRefreshToken,parseGuestToken:r?.parseGuestToken||$.parseGuestToken};async function l(i){let u={isValid:false,tokenType:null,exp:null,userData:null};try{let s=await fetch(`${t}${p.validate}`,{headers:{Authorization:`Bearer ${i}`,"Content-Type":"application/json"},cache:"no-store"});if(!s.ok)return u;let n=await s.json().catch(()=>null),d=R.parseAuthMe(n);return !d||!d.isValid?u:d}catch{return u}}async function c(i){return l(i)}async function m(i){try{let u=await fetch(`${t}${p.refresh}`,{method:"POST",headers:{Authorization:`Bearer ${i}`,"Content-Type":"application/json"},cache:"no-store"});if(!u.ok)return {success:!1,newToken:null};let s=await u.json().catch(()=>null),n=R.parseRefreshToken(s);return n?{success:!0,newToken:n}:{success:!1,newToken:null}}catch{return {success:false,newToken:null}}}async function a(){let i=e.guestToken;if(!i?.enabled||!i.credentials)return null;try{let u=await fetch(`${t}${p.guest}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({username:i.credentials.username,password:i.credentials.password}),cache:"no-store"});if(!u.ok)return null;let s=await u.json().catch(()=>null);return R.parseGuestToken(s)}catch{return null}}return {validateToken:l,getTokenInfo:c,refreshToken:m,createGuestToken:a}}function ee(e,t){if(!t?.enabled)return null;let f=t.locales??[],r=t.defaultLocale,R=e.split("/").filter(Boolean)[0];return R&&f.includes(R)?R:r??null}function z(e$1,t){let{cookies:f,guestToken:r,access:p,i18n:R,_resolved:l}=e$1,{cookieOptions:c$1}=l;function m(o,x,h){o.cookies.get(h)?.value&&x.cookies.delete(h);}function a(o,x){return m(o,x,f.guest),m(o,x,f.user),x}function i(o,x=500){return new NextResponse(JSON.stringify({success:false,message:o}),{status:x,headers:{"Content-Type":"application/json"}})}function u(o){return (p?.authRoutes??[]).some(h=>o===h||o.startsWith(`${h}/`))}function s(o){return p?.protectedByDefault?!n(o)&&!u(o):(p?.protectedRoutes??[]).some(h=>o===h||o.startsWith(`${h}/`))}function n(o){return (p?.publicRoutes??[]).some(h=>o===h||o.startsWith(`${h}/`))}function d(o){let x=p?.allowedTokenTypes;return !x||x.length===0?true:o?x.includes(o):false}async function N(o,x){let{origin:h}=o.nextUrl;if(r?.enabled){let y=await t.createGuestToken();if(y){let E;return x?E=NextResponse.next():s(o.nextUrl.pathname)?E=NextResponse.redirect(new URL("/login",h)):E=NextResponse.next(),E.cookies.set(f.guest,y,{...c$1,maxAge:3600}),E}}return x?i("Token bulunamad\u0131",401):s(o.nextUrl.pathname)?NextResponse.redirect(new URL("/login",h)):NextResponse.next()}async function L(o,x,h,y,E){let{pathname:k,origin:g}=o.nextUrl,{isValid:S,tokenType:A,userData:w}=x,v=A===c.GUEST;if(!S){if(h&&y){let H=await t.refreshToken(y);if(H.success&&H.newToken){let O=await t.getTokenInfo(H.newToken);if(O.isValid){let _=new Headers(o.headers);O.userData&&_.set(e.AUTH_USER,JSON.stringify(O.userData)),_.set(e.REFRESHED_TOKEN,H.newToken);let Z=ee(k,R);Z&&_.set(e.LOCALE,Z);let D;return u(k)?D=NextResponse.redirect(new URL("/",g)):D=NextResponse.next({request:{headers:_}}),D.cookies.set(f.user,H.newToken,{...c$1,maxAge:c$1.maxAge}),m(o,D,f.guest),D}}}let P=await N(o,E);return P.cookies.get(f.guest)?.value?m(o,P,f.user):a(o,P),P}let U=new Headers(o.headers);w&&U.set(e.AUTH_USER,JSON.stringify(w));let J=ee(k,R);if(J&&U.set(e.LOCALE,J),!v&&!d(A)){if(E){let Y=i("Bu i\u015Flem i\xE7in yetkiniz yok",403);return a(o,Y)}let P=NextResponse.redirect(new URL("/login",g));return a(o,P)}if(v)return E?NextResponse.next({request:{headers:U}}):s(k)?NextResponse.redirect(new URL("/login",g)):NextResponse.next({request:{headers:U}});if(u(k))return NextResponse.redirect(new URL("/",g));let X=NextResponse.next({request:{headers:U}});return m(o,X,f.guest),X}return {deleteAllAuthCookies:a,jsonError:i,isAuthPage:u,isProtectedRoute:s,isPublicRoute:n,isTokenTypeAllowed:d,handleNoToken:N,handleValidationResult:L}}function K(e){async function t(l){let c=ce();return `${await de(e.secret,l,c)}.${c}`}function f(l){let c=l.method.toUpperCase();if(e.ignoreMethods.includes(c))return {valid:true};let m=e.strategy;if(m==="fetch-metadata"||m==="both"){let a=r(l);if(m==="fetch-metadata"||a.valid||a.reason!=="missing-headers")return a}return m==="double-submit"||m==="both"?p(l):{valid:true}}function r(l){let c=l.headers.get("sec-fetch-site");if(!c)return {valid:false,reason:"missing-headers"};if(c==="same-origin")return {valid:true};if(c==="none"){let m=l.method.toUpperCase();return e.ignoreMethods.includes(m)?{valid:true}:{valid:false,reason:"direct-navigation-unsafe-method"}}return c==="same-site"?e.trustSameSite?{valid:true}:{valid:false,reason:"same-site-not-trusted"}:c==="cross-site"?{valid:false,reason:"cross-site-request"}:{valid:false,reason:"unknown-sec-fetch-site"}}function p(l){let c=l.cookies.get(e.cookieName)?.value;if(!c)return {valid:false,reason:"missing-cookie-token"};let m=l.headers.get(e.headerName);return m?fe(c,m)?c.split(".").length!==2?{valid:false,reason:"invalid-token-format"}:{valid:true}:{valid:false,reason:"token-mismatch"}:{valid:false,reason:"missing-header-token"}}async function R(l,c){let m=await t(c);return l.cookies.set(e.cookieName,m,{httpOnly:false,secure:process.env.NODE_ENV==="production",sameSite:"strict",path:"/"}),l}return {validateRequest:f,generateToken:t,attachCsrfCookie:R}}function ce(){if(typeof crypto<"u"&&crypto.getRandomValues){let e=new Uint8Array(32);return crypto.getRandomValues(e),Array.from(e,t=>t.toString(16).padStart(2,"0")).join("")}return Math.random().toString(36).substring(2)+Date.now().toString(36)}async function de(e,t,f){let r=`${t.length}!${t}!${f.length}!${f}`;if(typeof crypto<"u"&&crypto.subtle){let l=new TextEncoder,c=l.encode(e),m=l.encode(r),a=await crypto.subtle.importKey("raw",c,{name:"HMAC",hash:"SHA-256"},false,["sign"]),i=await crypto.subtle.sign("HMAC",a,m);return Array.from(new Uint8Array(i),u=>u.toString(16).padStart(2,"0")).join("")}let p=0,R=e+r;for(let l=0;l<R.length;l++){let c=R.charCodeAt(l);p=(p<<5)-p+c,p=p&p;}return Math.abs(p).toString(16)}function fe(e,t){if(e.length!==t.length)return false;let f=0;for(let r=0;r<e.length;r++)f|=e.charCodeAt(r)^t.charCodeAt(r);return f===0}function W(e){let t=new Map,f=setInterval(()=>{let i=Date.now();for(let[u,s]of t)s.resetAt<=i&&t.delete(u);},e.windowMs);typeof process<"u"&&process.on&&process.on("beforeExit",()=>clearInterval(f));function r(i){return e.skipRoutes.some(u=>u.endsWith("*")?i.startsWith(u.slice(0,-1)):u.endsWith("**")?i.startsWith(u.slice(0,-2)):i===u)}function p(i){let u=i.nextUrl.pathname;if(r(u))return {allowed:true,remaining:e.maxRequests,resetAt:0,limit:e.maxRequests};let s=e.keyFn(i),n=Date.now(),d=t.get(s);if(!d||d.resetAt<=n)return d={count:1,resetAt:n+e.windowMs},t.set(s,d),{allowed:true,remaining:e.maxRequests-1,resetAt:d.resetAt,limit:e.maxRequests};d.count++;let N=Math.max(0,e.maxRequests-d.count);return {allowed:d.count<=e.maxRequests,remaining:N,resetAt:d.resetAt,limit:e.maxRequests}}function R(i,u){return i.headers.set("X-RateLimit-Limit",u.limit.toString()),i.headers.set("X-RateLimit-Remaining",u.remaining.toString()),i.headers.set("X-RateLimit-Reset",Math.ceil(u.resetAt/1e3).toString()),i}function l(i,u){if(e.onRateLimited){let n=e.onRateLimited(i);return R(n,u)}let s=NextResponse.json({success:false,message:"Too many requests. Please try again later.",retryAfter:Math.ceil((u.resetAt-Date.now())/1e3)},{status:429});return s.headers.set("Retry-After",Math.ceil((u.resetAt-Date.now())/1e3).toString()),R(s,u)}function c(i){t.delete(i);}function m(){t.clear();}function a(){return t.size}return {check:p,applyHeaders:R,createLimitedResponse:l,shouldSkip:r,reset:c,clear:m,size:a}}function q(e){function t(s){return e.enabled&&e.events.includes(s)}function f(s){return s.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||s.headers.get("x-real-ip")||null}async function r(s,n,d){if(!t(s))return;let N={type:s,timestamp:new Date,ip:f(n),userId:d.userId,path:n.nextUrl.pathname,method:n.method,success:d.success,metadata:d.metadata};if(e.logger)try{await e.logger(N);}catch(L){console.error("[next-api-layer] Audit logger error:",L);}}function p(s,n,d){return r("auth:success",s,{success:true,userId:n,metadata:d})}function R(s,n){return r("auth:fail",s,{success:false,metadata:n})}function l(s,n,d){return r("auth:refresh",s,{success:true,userId:n,metadata:d})}function c(s,n){return r("auth:guest",s,{success:true,metadata:n})}function m(s,n,d){return r("access:denied",s,{success:false,userId:n,metadata:d})}function a(s,n){return r("csrf:fail",s,{success:false,metadata:n})}function i(s,n){return r("rateLimit:exceeded",s,{success:false,metadata:n})}function u(s,n,d){return r("error",s,{success:false,metadata:{...d,error:n.message,stack:n.stack}})}return {emit:r,isEnabled:t,authSuccess:p,authFail:R,authRefresh:l,authGuest:c,accessDenied:m,csrfFail:a,rateLimitExceeded:i,error:u}}function te(e$1,t){let f=[e.LOCALE,e.AUTH_USER,e.REFRESHED_TOKEN];for(let r of f){let p=e$1.headers.get(r);p&&!t.headers.has(r)&&t.headers.set(r,p);}return e$1.cookies.getAll().forEach(r=>{t.cookies.get(r.name)||t.cookies.set(r.name,r.value);}),t}function se(e){let t=Q(e),f=j(t),r=z(t,f),p=K(t._resolved.csrf),R=W(t._resolved.rateLimit),l=q(t._resolved.audit);async function c(a){let{pathname:i,origin:u}=a.nextUrl,s=i.startsWith("/api");if(t._resolved.rateLimit.enabled){let g=R.check(a);if(!g.allowed)return await l.rateLimitExceeded(a,{limit:g.limit,resetAt:g.resetAt}),R.createLimitedResponse(a,g)}if(t._resolved.csrf.enabled){let g=p.validateRequest(a);if(!g.valid)return await l.csrfFail(a,{reason:g.reason}),NextResponse.json({success:false,message:"CSRF validation failed"},{status:403})}if(t.blockBrowserApiAccess&&s&&(a.headers.get("accept")||"").includes("text/html"))return NextResponse.redirect(new URL("/",u));if(t.beforeAuth){let g=await t.beforeAuth(a);if(g)return g}if((t.excludedPaths??[]).some(g=>i.startsWith(g)))return m(a,NextResponse.next(),{isAuthenticated:false,isGuest:false,tokenType:null,user:null});if(["/api/auth/login","/api/auth/logout","/api/auth/me","/api/auth/refresh","/api/auth/register"].includes(i))return m(a,NextResponse.next(),{isAuthenticated:false,isGuest:false,tokenType:null,user:null});let N=a.cookies?.get(t.cookies.user)?.value,L=a.cookies?.get(t.cookies.guest)?.value,o=N||L,x=!!N;if(!o){await l.authFail(a,{reason:"no-token"});let g=await r.handleNoToken(a,s);return m(a,g,{isAuthenticated:false,isGuest:false,tokenType:null,user:null})}let h=await f.getTokenInfo(o),y={isAuthenticated:h.isValid&&h.tokenType!=="guest",isGuest:h.isValid&&h.tokenType==="guest",tokenType:h.tokenType,user:h.userData};if(h.isValid)if(h.tokenType==="guest")await l.authGuest(a);else {let g=h.userData?.id?.toString();await l.authSuccess(a,g,{tokenType:h.tokenType});}else await l.authFail(a,{reason:"invalid-token"});let E=await r.handleValidationResult(a,h,x,o,s),k=await m(a,E,y);if(t._resolved.csrf.enabled&&y.isAuthenticated){let g=h.userData?.id?.toString()||o.slice(0,32);k=await p.attachCsrfCookie(k,g);}if(t._resolved.rateLimit.enabled){let g=R.check(a);k=R.applyHeaders(k,g);}return k}async function m(a,i,u){let s=i;if(t.i18n?.middleware){let n=await Promise.resolve(t.i18n.middleware(a));s=te(i,n);}if(t.afterAuth){let n=await t.afterAuth(a,s,u);s=te(s,n);}return s}return c.config=t,c.csrf=p,c.rateLimiter=R,c.audit=l,c}function me(e,t){if(!t||t.length===0)return false;let f=e.replace(/^\/api\//,"").replace(/^\//,"");return t.some(r=>{if(r===f)return true;if(r.includes("*")){let p=r.replace(/\*\*/g,"<<<DOUBLE>>>").replace(/\*/g,"[^/]+").replace(/<<<DOUBLE>>>/g,".+");return new RegExp(`^${p}$`).test(f)}return false})}function re(e$1){let{apiBaseUrl:t,userCookieName:f="auth_token",guestCookieName:r="guest_token",skipAuthByDefault:p=false,publicEndpoints:R=[],forwardHeaders:l=["content-type","accept","accept-language","x-requested-with"],excludeHeaders:c=["host","connection","cookie"],transformRequest:m,transformResponse:a}=e$1,i=t.replace(/\/$/,"");function u(n,d){return n.headers.get(e.SKIP_AUTH)==="true"||me(d,R)?true:p}async function s(n){try{let d=new URL(n.url),N=d.pathname.replace(/^\/api\/?/,""),L=new URL(`${i}/${N}`);L.search=d.search;let o=new Headers;if(l.forEach(A=>{let w=n.headers.get(A);w&&o.set(A,w);}),n.headers.forEach((A,w)=>{let v=w.toLowerCase();!c.includes(v)&&!o.has(w)&&o.set(w,A);}),!u(n,N)){let A=n.cookies.get(f)?.value,w=n.cookies.get(r)?.value,v=A||w;v&&o.set(e.AUTHORIZATION,`Bearer ${v}`);}o.delete(e.SKIP_AUTH);let x=m?await m(n,o):o,h=null;if(n.method!=="GET"&&n.method!=="HEAD"){let A=n.headers.get("content-type")||"";A.includes("application/json")?h=await n.text():A.includes("multipart/form-data")?h=await n.formData():h=await n.text();}let y=await fetch(L.toString(),{method:n.method,headers:x,body:h}),E=y.headers.get("content-type")||"",k;E.includes("application/json")?k=await y.text():k=await y.arrayBuffer();let g=new Headers;y.headers.forEach((A,w)=>{let v=w.toLowerCase();["transfer-encoding","connection","keep-alive"].includes(v)||g.set(w,A);});let S=new NextResponse(k,{status:y.status,statusText:y.statusText,headers:g});return a&&(S=await a(S)),S}catch(d){return console.error("[Proxy Error]",d),NextResponse.json({success:false,message:"Proxy error: Unable to connect to backend",error:d instanceof Error?d.message:"Unknown error"},{status:502})}}return s.config=e$1,s}
2
+ export{q as createAuditLogger,se as createAuthProxy,K as createCsrfValidator,z as createHandlers,re as createProxyHandler,W as createRateLimiter,j as createTokenValidation};//# sourceMappingURL=index.js.map
3
3
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/shared/config.ts","../src/proxy/tokenValidation.ts","../src/proxy/handlers.ts","../src/proxy/csrf.ts","../src/proxy/rateLimit.ts","../src/proxy/audit.ts","../src/proxy/createAuthProxy.ts","../src/proxy/createProxyHandler.ts"],"names":["generateCsrfSecret","defaultRateLimitKeyFn","req","resolveProxyConfig","config","apiBaseUrl","cookieOptions","DEFAULT_COOKIE_OPTIONS","endpoints","DEFAULT_ENDPOINTS","csrf","DEFAULT_CSRF_CONFIG","rateLimit","DEFAULT_RATE_LIMIT_CONFIG","audit","DEFAULT_AUDIT_CONFIG","defaultMappers","response","res","createTokenValidation","_resolved","responseMappers","mappers","validateToken","token","invalidResult","rawResponse","parsed","getTokenInfo","refreshToken","oldToken","newToken","createGuestToken","guestConfig","extractLocale","pathname","i18n","locales","defaultLocale","firstSegment","createHandlers","validation","cookies","guestToken","access","safeDeleteCookie","cookieName","deleteAllAuthCookies","jsonError","message","status","NextResponse","isAuthPage","route","isProtectedRoute","isPublicRoute","isTokenTypeAllowed","tokenType","allowedTypes","handleNoToken","isApiRoute","origin","guestAccessToken","handleValidationResult","tokenInfo","isUserToken","currentToken","isValid","userData","isGuest","TOKEN_TYPES","refreshResult","newTokenInfo","requestHeaders","HEADERS","locale","createCsrfValidator","generateToken","sessionId","randomValue","generateRandomValue","computeHmac","validateRequest","method","strategy","fetchResult","validateFetchMetadata","validateDoubleSubmit","secFetchSite","cookieToken","headerToken","constantTimeEqual","attachCsrfCookie","array","b","secret","encoder","keyData","messageData","key","signature","hash","str","i","char","a","result","createRateLimiter","store","cleanupInterval","now","entry","shouldSkip","pattern","check","remaining","applyHeaders","createLimitedResponse","reset","clear","size","createAuditLogger","isEnabled","type","getIp","emit","options","event","error","authSuccess","userId","metadata","authFail","authRefresh","authGuest","accessDenied","csrfFail","rateLimitExceeded","err","createAuthProxy","userConfig","handlers","rateLimiter","authProxy","rateLimitResult","csrfResult","beforeResult","path","applyAfterAuth","userToken","authResult","finalResponse","matchesPattern","endpoint","patterns","normalizedEndpoint","regexPattern","createProxyHandler","userCookieName","guestCookieName","skipAuthByDefault","publicEndpoints","forwardHeaders","excludeHeaders","transformRequest","transformResponse","baseUrl","shouldSkipAuth","handler","url","backendUrl","headers","headerName","value","lowerKey","finalHeaders","body","contentType","backendResponse","responseBody","responseHeaders"],"mappings":"4XA6BA,SAASA,IAA6B,CAEpC,OAAI,OAAO,MAAA,CAAW,GAAA,EAAe,OAAO,UAAA,CACnC,MAAA,CAAO,YAAW,CAAI,MAAA,CAAO,YAAW,CAG1C,CAAA,EAAG,IAAA,CAAK,GAAA,EAAK,CAAA,CAAA,EAAI,KAAK,MAAA,EAAO,CAAE,SAAS,EAAE,CAAA,CAAE,UAAU,CAAC,CAAC,CAAA,CACjE,CAKA,SAASC,EAAAA,CAAsBC,EAA0B,CAKvD,OAAO,MAJWA,CAAAA,CAAI,OAAA,CAAQ,IAAI,iBAAiB,CAAA,EAC7B,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,GAAG,IAAA,EAAK,EAC/BA,EAAI,OAAA,CAAQ,GAAA,CAAI,WAAW,CAAA,EAC3B,SACI,EACjB,CAKO,SAASC,EAAmBC,CAAAA,CAA8C,CAE/E,GAAI,CAACA,CAAAA,CAAO,WACV,MAAM,IAAI,KAAA,CAAM,wCAAwC,CAAA,CAG1D,GAAI,CAACA,CAAAA,CAAO,OAAA,EAAS,MAAQ,CAACA,CAAAA,CAAO,SAAS,KAAA,CAC5C,MAAM,IAAI,KAAA,CAAM,6DAA6D,CAAA,CAI/E,IAAMC,CAAAA,CAAaD,CAAAA,CAAO,WAAW,QAAA,CAAS,GAAG,EAC7CA,CAAAA,CAAO,UAAA,CACP,CAAA,EAAGA,CAAAA,CAAO,UAAU,CAAA,CAAA,CAAA,CAGlBE,EAAuC,CAC3C,GAAGC,EACH,GAAGH,CAAAA,CAAO,QAAQ,OACpB,CAAA,CAGMI,EAAsC,CAC1C,GAAGC,EACH,GAAGL,CAAAA,CAAO,SACZ,CAAA,CAGMM,CAAAA,CAA2B,CAC/B,OAAA,CAASN,CAAAA,CAAO,IAAA,EAAM,OAAA,EAAW,KAAA,CACjC,QAAA,CAAUA,EAAO,IAAA,EAAM,QAAA,EAAYO,EAAoB,QAAA,CACvD,MAAA,CAAQP,EAAO,IAAA,EAAM,MAAA,EAAUJ,EAAAA,EAAmB,CAClD,UAAA,CAAYI,CAAAA,CAAO,MAAM,UAAA,EAAcO,CAAAA,CAAoB,WAC3D,UAAA,CAAYP,CAAAA,CAAO,MAAM,UAAA,EAAcO,CAAAA,CAAoB,UAAA,CAC3D,aAAA,CAAeP,CAAAA,CAAO,IAAA,EAAM,eAAiBO,CAAAA,CAAoB,aAAA,CACjE,cAAeP,CAAAA,CAAO,IAAA,EAAM,eAAiBO,CAAAA,CAAoB,aACnE,EAGMC,CAAAA,CAAqC,CACzC,QAASR,CAAAA,CAAO,SAAA,EAAW,SAAW,KAAA,CACtC,QAAA,CAAUA,EAAO,SAAA,EAAW,QAAA,EAAYS,CAAAA,CAA0B,QAAA,CAClE,WAAA,CAAaT,CAAAA,CAAO,WAAW,WAAA,EAAeS,CAAAA,CAA0B,YACxE,KAAA,CAAOT,CAAAA,CAAO,WAAW,KAAA,EAASH,EAAAA,CAClC,UAAA,CAAYG,CAAAA,CAAO,SAAA,EAAW,UAAA,EAAcS,EAA0B,UAAA,CACtE,aAAA,CAAeT,EAAO,SAAA,EAAW,aACnC,EAGMU,CAAAA,CAA6B,CACjC,OAAA,CAASV,CAAAA,CAAO,KAAA,EAAO,OAAA,EAAW,MAClC,MAAA,CAAQA,CAAAA,CAAO,OAAO,MAAA,EAAU,CAAC,GAAGW,CAAAA,CAAqB,MAAM,EAC/D,MAAA,CAAQX,CAAAA,CAAO,OAAO,MACxB,CAAA,CAEA,OAAO,CACL,GAAGA,EACH,UAAA,CAAAC,CAAAA,CACA,SAAA,CAAW,CACT,aAAA,CAAAC,CAAAA,CACA,UAAAE,CAAAA,CACA,IAAA,CAAAE,EACA,SAAA,CAAAE,CAAAA,CACA,MAAAE,CACF,CACF,CACF,CCrGA,IAAME,CAAAA,CAA4C,CAEhD,WAAA,CAAcC,CAAAA,EAAwC,CACpD,IAAMC,CAAAA,CAAMD,EACZ,OAAI,CAACC,CAAAA,EAAK,OAAA,EAAW,CAACA,CAAAA,EAAK,KAClB,IAAA,CAEF,CACL,QAAS,IAAA,CACT,SAAA,CAAWA,EAAI,IAAA,CAAK,IAAA,EAAQ,OAC5B,GAAA,CAAKA,CAAAA,CAAI,KAAK,GAAA,EAAO,IAAA,CACrB,SAAUA,CAAAA,CAAI,IAChB,CACF,CAAA,CAGA,iBAAA,CAAoBD,CAAAA,EAAqC,CACvD,IAAMC,CAAAA,CAAMD,EACZ,OAAOC,CAAAA,EAAK,SAAWA,CAAAA,EAAK,IAAA,EAAM,YAAcA,CAAAA,CAAI,IAAA,CAAK,WAAA,CAAc,IACzE,CAAA,CAGA,eAAA,CAAkBD,GACJA,CAAAA,EACA,IAAA,EAAM,aAAe,IAErC,CAAA,CAKO,SAASE,CAAAA,CACdf,CAAAA,CACA,CACA,GAAM,CAAE,UAAA,CAAAC,EAAY,SAAA,CAAAe,CAAAA,CAAW,gBAAAC,CAAgB,CAAA,CAAIjB,EAC7C,CAAE,SAAA,CAAAI,CAAU,CAAA,CAAIY,CAAAA,CAGhBE,EAAqC,CACzC,WAAA,CAAaD,GAAiB,WAAA,EAAeL,CAAAA,CAAe,YAC5D,iBAAA,CAAmBK,CAAAA,EAAiB,iBAAA,EAAqBL,CAAAA,CAAe,iBAAA,CACxE,eAAA,CAAiBK,GAAiB,eAAA,EAAmBL,CAAAA,CAAe,eACtE,CAAA,CAKA,eAAeO,EAAcC,CAAAA,CAAmC,CAC9D,IAAMC,CAAAA,CAA2B,CAAE,OAAA,CAAS,MAAO,SAAA,CAAW,IAAA,CAAM,IAAK,IAAA,CAAM,QAAA,CAAU,IAAK,CAAA,CAE9F,GAAI,CACF,IAAMP,CAAAA,CAAM,MAAM,MAAM,CAAA,EAAGb,CAAU,GAAGG,CAAAA,CAAU,QAAQ,GAAI,CAC5D,OAAA,CAAS,CACP,aAAA,CAAiB,CAAA,OAAA,EAAUgB,CAAK,GAChC,cAAA,CAAgB,kBAClB,EACA,KAAA,CAAO,UACT,CAAC,CAAA,CAED,GAAI,CAACN,CAAAA,CAAI,EAAA,CACP,OAAOO,EAGT,IAAMC,CAAAA,CAAuB,MAAMR,CAAAA,CAAI,IAAA,GAAO,KAAA,CAAM,IAAM,IAAI,CAAA,CAGxDS,CAAAA,CAASL,CAAAA,CAAQ,YAAYI,CAAW,CAAA,CAE9C,OAAI,CAACC,CAAAA,EAAU,CAACA,CAAAA,CAAO,OAAA,CACdF,CAAAA,CAGFE,CACT,CAAA,KAAQ,CACN,OAAOF,CACT,CACF,CAKA,eAAeG,CAAAA,CAAaJ,EAAmC,CAC7D,OAAOD,EAAcC,CAAK,CAC5B,CAKA,eAAeK,CAAAA,CAAaC,EAA0C,CACpE,GAAI,CACF,IAAMZ,CAAAA,CAAM,MAAM,KAAA,CAAM,CAAA,EAAGb,CAAU,GAAGG,CAAAA,CAAU,OAAO,GAAI,CAC3D,MAAA,CAAQ,OACR,OAAA,CAAS,CACP,aAAA,CAAiB,CAAA,OAAA,EAAUsB,CAAQ,CAAA,CAAA,CACnC,eAAgB,kBAClB,CAAA,CACA,MAAO,UACT,CAAC,EAED,GAAI,CAACZ,CAAAA,CAAI,EAAA,CACP,OAAO,CAAE,QAAS,CAAA,CAAA,CAAO,QAAA,CAAU,IAAK,CAAA,CAG1C,IAAMQ,EAAuB,MAAMR,CAAAA,CAAI,MAAK,CAAE,KAAA,CAAM,IAAM,IAAI,CAAA,CAGxDa,EAAWT,CAAAA,CAAQ,iBAAA,CAAkBI,CAAW,CAAA,CAEtD,OAAKK,CAAAA,CAIE,CAAE,OAAA,CAAS,CAAA,CAAA,CAAM,SAAAA,CAAS,CAAA,CAHxB,CAAE,OAAA,CAAS,CAAA,CAAA,CAAO,SAAU,IAAK,CAI5C,CAAA,KAAQ,CACN,OAAO,CAAE,QAAS,KAAA,CAAO,QAAA,CAAU,IAAK,CAC1C,CACF,CAKA,eAAeC,CAAAA,EAA2C,CACxD,IAAMC,CAAAA,CAAc7B,CAAAA,CAAO,WAE3B,GAAI,CAAC6B,GAAa,OAAA,EAAW,CAACA,EAAY,WAAA,CACxC,OAAO,KAGT,GAAI,CACF,IAAMf,CAAAA,CAAM,MAAM,MAAM,CAAA,EAAGb,CAAU,GAAGG,CAAAA,CAAU,KAAK,CAAA,CAAA,CAAI,CACzD,MAAA,CAAQ,MAAA,CACR,QAAS,CAAE,cAAA,CAAgB,kBAAmB,CAAA,CAC9C,IAAA,CAAM,KAAK,SAAA,CAAU,CACnB,QAAA,CAAUyB,CAAAA,CAAY,WAAA,CAAY,QAAA,CAClC,SAAUA,CAAAA,CAAY,WAAA,CAAY,QACpC,CAAC,CAAA,CACD,MAAO,UACT,CAAC,CAAA,CAED,GAAI,CAACf,CAAAA,CAAI,GACP,OAAO,IAAA,CAGT,IAAMQ,CAAAA,CAAuB,MAAMR,EAAI,IAAA,EAAK,CAAE,KAAA,CAAM,IAAM,IAAI,CAAA,CAG9D,OAAOI,CAAAA,CAAQ,eAAA,CAAgBI,CAAW,CAC5C,CAAA,KAAQ,CACN,OAAO,IACT,CACF,CAEA,OAAO,CACL,cAAAH,CAAAA,CACA,YAAA,CAAAK,EACA,YAAA,CAAAC,CAAAA,CACA,iBAAAG,CACF,CACF,CCjKA,SAASE,EAAAA,CAAcC,EAAkBC,CAAAA,CAAmD,CAC1F,GAAI,CAACA,CAAAA,EAAM,OAAA,CAAS,OAAO,IAAA,CAE3B,IAAMC,EAAUD,CAAAA,CAAK,OAAA,EAAW,EAAC,CAC3BE,CAAAA,CAAgBF,EAAK,aAAA,CAIrBG,CAAAA,CADWJ,EAAS,KAAA,CAAM,GAAG,EAAE,MAAA,CAAO,OAAO,EACrB,CAAC,CAAA,CAG/B,OAAII,CAAAA,EAAgBF,CAAAA,CAAQ,QAAA,CAASE,CAAY,CAAA,CACxCA,CAAAA,CAIFD,GAAiB,IAC1B,CAKO,SAASE,CAAAA,CACdpC,GAAAA,CACAqC,EACA,CACA,GAAM,CAAE,OAAA,CAAAC,CAAAA,CAAS,UAAA,CAAAC,EAAY,MAAA,CAAAC,CAAAA,CAAQ,KAAAR,CAAAA,CAAM,SAAA,CAAAhB,CAAU,CAAA,CAAIhB,GAAAA,CACnD,CAAE,aAAA,CAAAE,GAAc,CAAA,CAAIc,EAM1B,SAASyB,CAAAA,CAAiB3C,EAAkBe,CAAAA,CAAwB6B,CAAAA,CAA0B,CACxF5C,CAAAA,CAAI,OAAA,CAAQ,IAAI4C,CAAU,CAAA,EAAG,OAC/B7B,CAAAA,CAAS,OAAA,CAAQ,OAAO6B,CAAU,EAEtC,CAKA,SAASC,CAAAA,CAAqB7C,CAAAA,CAAkBe,CAAAA,CAAsC,CACpF,OAAA4B,EAAiB3C,CAAAA,CAAKe,CAAAA,CAAUyB,EAAQ,KAAK,CAAA,CAC7CG,EAAiB3C,CAAAA,CAAKe,CAAAA,CAAUyB,CAAAA,CAAQ,IAAI,CAAA,CACrCzB,CACT,CAKA,SAAS+B,CAAAA,CAAUC,EAAiBC,CAAAA,CAAS,GAAA,CAAmB,CAC9D,OAAO,IAAIC,YAAAA,CACT,IAAA,CAAK,SAAA,CAAU,CAAE,QAAS,KAAA,CAAO,OAAA,CAAAF,CAAQ,CAAC,CAAA,CAC1C,CAAE,MAAA,CAAAC,CAAAA,CAAQ,QAAS,CAAE,cAAA,CAAgB,kBAAmB,CAAE,CAC5D,CACF,CAKA,SAASE,EAAWjB,CAAAA,CAA2B,CAE7C,OAAA,CADmBS,CAAAA,EAAQ,UAAA,EAAc,IACvB,IAAA,CAAKS,CAAAA,EACrBlB,IAAakB,CAAAA,EAASlB,CAAAA,CAAS,WAAW,CAAA,EAAGkB,CAAK,CAAA,CAAA,CAAG,CACvD,CACF,CAKA,SAASC,CAAAA,CAAiBnB,CAAAA,CAA2B,CAEnD,OAAIS,CAAAA,EAAQ,mBACH,CAACW,CAAAA,CAAcpB,CAAQ,CAAA,EAAK,CAACiB,CAAAA,CAAWjB,CAAQ,CAAA,CAAA,CAGjCS,CAAAA,EAAQ,iBAAmB,EAAC,EAC7B,KAAKS,CAAAA,EAC1BlB,CAAAA,GAAakB,CAAAA,EAASlB,CAAAA,CAAS,UAAA,CAAW,CAAA,EAAGkB,CAAK,CAAA,CAAA,CAAG,CACvD,CACF,CAKA,SAASE,EAAcpB,CAAAA,CAA2B,CAEhD,OAAA,CADqBS,CAAAA,EAAQ,YAAA,EAAgB,IACzB,IAAA,CAAKS,CAAAA,EACvBlB,IAAakB,CAAAA,EAASlB,CAAAA,CAAS,WAAW,CAAA,EAAGkB,CAAK,CAAA,CAAA,CAAG,CACvD,CACF,CAKA,SAASG,CAAAA,CAAmBC,CAAAA,CAAmC,CAC7D,IAAMC,CAAAA,CAAed,GAAQ,iBAAA,CAG7B,OAAI,CAACc,CAAAA,EAAgBA,CAAAA,CAAa,MAAA,GAAW,EACpC,IAAA,CAGFD,CAAAA,CAAYC,EAAa,QAAA,CAASD,CAAS,EAAI,KACxD,CAKA,eAAeE,CAAAA,CACbzD,CAAAA,CACA0D,EACuB,CACvB,GAAM,CAAE,MAAA,CAAAC,CAAO,EAAI3D,CAAAA,CAAI,OAAA,CAGvB,GAAIyC,CAAAA,EAAY,OAAA,CAAS,CACvB,IAAMmB,CAAAA,CAAmB,MAAMrB,EAAW,gBAAA,EAAiB,CAE3D,GAAIqB,CAAAA,CAAkB,CACpB,IAAI7C,CAAAA,CAEJ,OAAI2C,CAAAA,CACF3C,EAAWkC,YAAAA,CAAa,IAAA,GACfG,CAAAA,CAAiBpD,CAAAA,CAAI,QAAQ,QAAQ,CAAA,CAE9Ce,CAAAA,CAAWkC,YAAAA,CAAa,QAAA,CAAS,IAAI,IAAI,QAAA,CAAUU,CAAM,CAAC,CAAA,CAE1D5C,CAAAA,CAAWkC,aAAa,IAAA,EAAK,CAG/BlC,EAAS,OAAA,CAAQ,GAAA,CAAIyB,EAAQ,KAAA,CAAOoB,CAAAA,CAAkB,CACpD,GAAGxD,GAAAA,CACH,OAAQ,IACV,CAAC,CAAA,CAEMW,CACT,CACF,CAGA,OAAI2C,CAAAA,CACKZ,CAAAA,CAAU,wBAAoB,GAAG,CAAA,CAGtCM,EAAiBpD,CAAAA,CAAI,OAAA,CAAQ,QAAQ,CAAA,CAChCiD,YAAAA,CAAa,QAAA,CAAS,IAAI,GAAA,CAAI,QAAA,CAAUU,CAAM,CAAC,CAAA,CAGjDV,aAAa,IAAA,EACtB,CAKA,eAAeY,CAAAA,CACb7D,CAAAA,CACA8D,EACAC,CAAAA,CACAC,CAAAA,CACAN,EACuB,CACvB,GAAM,CAAE,QAAA,CAAAzB,CAAAA,CAAU,OAAA0B,CAAO,CAAA,CAAI3D,EAAI,OAAA,CAC3B,CAAE,QAAAiE,CAAAA,CAAS,SAAA,CAAAV,EAAW,QAAA,CAAAW,CAAS,CAAA,CAAIJ,CAAAA,CACnCK,CAAAA,CAAUZ,CAAAA,GAAca,EAAY,KAAA,CAG1C,GAAI,CAACH,CAAAA,CAAS,CAEZ,GAAIF,CAAAA,EAAeC,CAAAA,CAAc,CAC/B,IAAMK,CAAAA,CAAgB,MAAM9B,EAAW,YAAA,CAAayB,CAAY,EAEhE,GAAIK,CAAAA,CAAc,SAAWA,CAAAA,CAAc,QAAA,CAAU,CACnD,IAAMC,CAAAA,CAAe,MAAM/B,EAAW,YAAA,CAAa8B,CAAAA,CAAc,QAAQ,CAAA,CAEzE,GAAIC,EAAa,OAAA,CAAS,CAExB,IAAMC,CAAAA,CAAiB,IAAI,OAAA,CAAQvE,EAAI,OAAO,CAAA,CAE1CsE,EAAa,QAAA,EACfC,CAAAA,CAAe,IAAIC,CAAAA,CAAQ,SAAA,CAAW,IAAA,CAAK,SAAA,CAAUF,CAAAA,CAAa,QAAQ,CAAC,CAAA,CAE7EC,CAAAA,CAAe,IAAIC,CAAAA,CAAQ,eAAA,CAAiBH,EAAc,QAAQ,CAAA,CAGlE,IAAMI,CAAAA,CAASzC,EAAAA,CAAcC,CAAAA,CAAUC,CAAI,CAAA,CACvCuC,CAAAA,EACFF,EAAe,GAAA,CAAIC,CAAAA,CAAQ,OAAQC,CAAM,CAAA,CAG3C,IAAI1D,CAAAA,CAEJ,OAAImC,CAAAA,CAAWjB,CAAQ,CAAA,CACrBlB,CAAAA,CAAWkC,aAAa,QAAA,CAAS,IAAI,IAAI,GAAA,CAAKU,CAAM,CAAC,CAAA,CAErD5C,CAAAA,CAAWkC,aAAa,IAAA,CAAK,CAAE,QAAS,CAAE,OAAA,CAASsB,CAAe,CAAE,CAAC,CAAA,CAGvExD,CAAAA,CAAS,OAAA,CAAQ,GAAA,CAAIyB,EAAQ,IAAA,CAAM6B,CAAAA,CAAc,SAAU,CACzD,GAAGjE,IACH,MAAA,CAAQA,GAAAA,CAAc,MACxB,CAAC,CAAA,CACDuC,CAAAA,CAAiB3C,EAAKe,CAAAA,CAAUyB,CAAAA,CAAQ,KAAK,CAAA,CAEtCzB,CACT,CACF,CACF,CAGA,IAAMA,CAAAA,CAAW,MAAM0C,CAAAA,CAAczD,EAAK0D,CAAU,CAAA,CAKpD,OAFyB3C,CAAAA,CAAS,OAAA,CAAQ,IAAIyB,CAAAA,CAAQ,KAAK,GAAG,KAAA,CAO5DG,CAAAA,CAAiB3C,EAAKe,CAAAA,CAAUyB,CAAAA,CAAQ,IAAI,CAAA,CAH5CK,CAAAA,CAAqB7C,EAAKe,CAAQ,CAAA,CAM7BA,CACT,CAGA,IAAMwD,CAAAA,CAAiB,IAAI,OAAA,CAAQvE,CAAAA,CAAI,OAAO,CAAA,CAE1CkE,CAAAA,EACFK,EAAe,GAAA,CAAIC,CAAAA,CAAQ,SAAA,CAAW,IAAA,CAAK,SAAA,CAAUN,CAAQ,CAAC,CAAA,CAIhE,IAAMO,EAASzC,EAAAA,CAAcC,CAAAA,CAAUC,CAAI,CAAA,CAM3C,GALIuC,CAAAA,EACFF,CAAAA,CAAe,GAAA,CAAIC,CAAAA,CAAQ,OAAQC,CAAM,CAAA,CAIvC,CAACN,CAAAA,EAAW,CAACb,EAAmBC,CAAS,CAAA,CAAG,CAC9C,GAAIG,CAAAA,CAAY,CACd,IAAM3C,CAAAA,CAAW+B,EAAU,oCAAA,CAA8B,GAAG,EAC5D,OAAOD,CAAAA,CAAqB7C,CAAAA,CAAKe,CAAQ,CAC3C,CAEA,IAAMA,CAAAA,CAAWkC,YAAAA,CAAa,SAAS,IAAI,GAAA,CAAI,SAAUU,CAAM,CAAC,CAAA,CAChE,OAAOd,CAAAA,CAAqB7C,CAAAA,CAAKe,CAAQ,CAC3C,CAGA,GAAIoD,CAAAA,CACF,OAAIT,EACKT,YAAAA,CAAa,IAAA,CAAK,CAAE,OAAA,CAAS,CAAE,OAAA,CAASsB,CAAe,CAAE,CAAC,EAI/DnB,CAAAA,CAAiBnB,CAAQ,EACpBgB,YAAAA,CAAa,QAAA,CAAS,IAAI,GAAA,CAAI,QAAA,CAAUU,CAAM,CAAC,CAAA,CAGjDV,YAAAA,CAAa,KAAK,CAAE,OAAA,CAAS,CAAE,OAAA,CAASsB,CAAe,CAAE,CAAC,CAAA,CAInE,GAAIrB,EAAWjB,CAAQ,CAAA,CACrB,OAAOgB,YAAAA,CAAa,QAAA,CAAS,IAAI,GAAA,CAAI,GAAA,CAAKU,CAAM,CAAC,CAAA,CAInD,IAAM5C,EAAWkC,YAAAA,CAAa,IAAA,CAAK,CAAE,OAAA,CAAS,CAAE,QAASsB,CAAe,CAAE,CAAC,CAAA,CAC3E,OAAA5B,CAAAA,CAAiB3C,EAAKe,CAAAA,CAAUyB,CAAAA,CAAQ,KAAK,CAAA,CAEtCzB,CACT,CAEA,OAAO,CACL,qBAAA8B,CAAAA,CACA,SAAA,CAAAC,EACA,UAAA,CAAAI,CAAAA,CACA,iBAAAE,CAAAA,CACA,aAAA,CAAAC,EACA,kBAAA,CAAAC,CAAAA,CACA,aAAA,CAAAG,CAAAA,CACA,sBAAA,CAAAI,CACF,CACF,CCxRO,SAASa,EAAoBxE,CAAAA,CAA4B,CAK9D,eAAeyE,CAAAA,CAAcC,CAAAA,CAAoC,CAC/D,IAAMC,CAAAA,CAAcC,EAAAA,GAEpB,OAAO,CAAA,EADM,MAAMC,EAAAA,CAAY7E,CAAAA,CAAO,OAAQ0E,CAAAA,CAAWC,CAAW,CACtD,CAAA,CAAA,EAAIA,CAAW,CAAA,CAC/B,CAKA,SAASG,CAAAA,CAAgBhF,EAAwC,CAC/D,IAAMiF,EAASjF,CAAAA,CAAI,MAAA,CAAO,aAAY,CAGtC,GAAIE,EAAO,aAAA,CAAc,QAAA,CAAS+E,CAAM,CAAA,CACtC,OAAO,CAAE,KAAA,CAAO,IAAK,CAAA,CAGvB,IAAMC,CAAAA,CAAWhF,CAAAA,CAAO,SAGxB,GAAIgF,CAAAA,GAAa,kBAAoBA,CAAAA,GAAa,MAAA,CAAQ,CACxD,IAAMC,CAAAA,CAAcC,CAAAA,CAAsBpF,CAAG,CAAA,CAY7C,GAVIkF,IAAa,gBAAA,EAKbC,CAAAA,CAAY,OAKZA,CAAAA,CAAY,MAAA,GAAW,kBAIzB,OAAOA,CAEX,CAGA,OAAID,CAAAA,GAAa,eAAA,EAAmBA,IAAa,MAAA,CACxCG,CAAAA,CAAqBrF,CAAG,CAAA,CAG1B,CAAE,MAAO,IAAK,CACvB,CAMA,SAASoF,CAAAA,CAAsBpF,EAAwC,CACrE,IAAMsF,EAAetF,CAAAA,CAAI,OAAA,CAAQ,IAAI,gBAAgB,CAAA,CAGrD,GAAI,CAACsF,CAAAA,CACH,OAAO,CAAE,KAAA,CAAO,KAAA,CAAO,OAAQ,iBAAkB,CAAA,CAInD,GAAIA,CAAAA,GAAiB,aAAA,CACnB,OAAO,CAAE,KAAA,CAAO,IAAK,EAIvB,GAAIA,CAAAA,GAAiB,OAAQ,CAC3B,IAAML,EAASjF,CAAAA,CAAI,MAAA,CAAO,WAAA,EAAY,CACtC,OAAIE,CAAAA,CAAO,cAAc,QAAA,CAAS+E,CAAM,EAC/B,CAAE,KAAA,CAAO,IAAK,CAAA,CAGhB,CAAE,KAAA,CAAO,KAAA,CAAO,MAAA,CAAQ,iCAAkC,CACnE,CAGA,OAAIK,IAAiB,WAAA,CACfpF,CAAAA,CAAO,cACF,CAAE,KAAA,CAAO,IAAK,CAAA,CAGhB,CAAE,KAAA,CAAO,MAAO,MAAA,CAAQ,uBAAwB,EAIrDoF,CAAAA,GAAiB,YAAA,CACZ,CAAE,KAAA,CAAO,KAAA,CAAO,MAAA,CAAQ,oBAAqB,CAAA,CAI/C,CAAE,MAAO,KAAA,CAAO,MAAA,CAAQ,wBAAyB,CAC1D,CAKA,SAASD,CAAAA,CAAqBrF,CAAAA,CAAwC,CAEpE,IAAMuF,CAAAA,CAAcvF,CAAAA,CAAI,QAAQ,GAAA,CAAIE,CAAAA,CAAO,UAAU,CAAA,EAAG,KAAA,CAExD,GAAI,CAACqF,CAAAA,CACH,OAAO,CAAE,KAAA,CAAO,MAAO,MAAA,CAAQ,sBAAuB,EAIxD,IAAMC,CAAAA,CAAcxF,EAAI,OAAA,CAAQ,GAAA,CAAIE,CAAAA,CAAO,UAAU,CAAA,CAErD,OAAKsF,EAKAC,EAAAA,CAAkBF,CAAAA,CAAaC,CAAW,CAAA,CAKjCD,CAAAA,CAAY,MAAM,GAAG,CAAA,CACzB,MAAA,GAAW,CAAA,CACZ,CAAE,KAAA,CAAO,MAAO,MAAA,CAAQ,sBAAuB,EAGjD,CAAE,KAAA,CAAO,IAAK,CAAA,CATZ,CAAE,KAAA,CAAO,KAAA,CAAO,MAAA,CAAQ,gBAAiB,EALzC,CAAE,KAAA,CAAO,MAAO,MAAA,CAAQ,sBAAuB,CAe1D,CAKA,eAAeG,EACb3E,CAAAA,CACA6D,CAAAA,CACuB,CACvB,IAAMtD,CAAAA,CAAQ,MAAMqD,CAAAA,CAAcC,CAAS,EAE3C,OAAA7D,CAAAA,CAAS,OAAA,CAAQ,GAAA,CAAIb,CAAAA,CAAO,UAAA,CAAYoB,EAAO,CAC7C,QAAA,CAAU,MACV,MAAA,CAAQ,OAAA,CAAQ,IAAI,QAAA,GAAa,YAAA,CACjC,QAAA,CAAU,QAAA,CACV,IAAA,CAAM,GACR,CAAC,CAAA,CAEMP,CACT,CAEA,OAAO,CACL,gBAAAiE,CAAAA,CACA,aAAA,CAAAL,CAAAA,CACA,gBAAA,CAAAe,CACF,CACF,CAOA,SAASZ,EAAAA,EAA8B,CACrC,GAAI,OAAO,OAAW,GAAA,EAAe,MAAA,CAAO,gBAAiB,CAC3D,IAAMa,EAAQ,IAAI,UAAA,CAAW,EAAE,CAAA,CAC/B,OAAA,MAAA,CAAO,gBAAgBA,CAAK,CAAA,CACrB,KAAA,CAAM,IAAA,CAAKA,CAAAA,CAAOC,CAAAA,EAAKA,EAAE,QAAA,CAAS,EAAE,EAAE,QAAA,CAAS,CAAA,CAAG,GAAG,CAAC,CAAA,CAAE,IAAA,CAAK,EAAE,CACxE,CAEA,OAAO,IAAA,CAAK,MAAA,GAAS,QAAA,CAAS,EAAE,EAAE,SAAA,CAAU,CAAC,CAAA,CAAI,IAAA,CAAK,GAAA,EAAI,CAAE,SAAS,EAAE,CACzE,CAKA,eAAeb,EAAAA,CACbc,EACAjB,CAAAA,CACAC,CAAAA,CACiB,CACjB,IAAM9B,CAAAA,CAAU,CAAA,EAAG6B,EAAU,MAAM,CAAA,CAAA,EAAIA,CAAS,CAAA,CAAA,EAAIC,CAAAA,CAAY,MAAM,CAAA,CAAA,EAAIA,CAAW,CAAA,CAAA,CAErF,GAAI,OAAO,MAAA,CAAW,KAAe,MAAA,CAAO,MAAA,CAAQ,CAClD,IAAMiB,CAAAA,CAAU,IAAI,WAAA,CACdC,CAAAA,CAAUD,CAAAA,CAAQ,MAAA,CAAOD,CAAM,CAAA,CAC/BG,EAAcF,CAAAA,CAAQ,MAAA,CAAO/C,CAAO,CAAA,CAEpCkD,CAAAA,CAAM,MAAM,MAAA,CAAO,MAAA,CAAO,SAAA,CAC9B,KAAA,CACAF,CAAAA,CACA,CAAE,KAAM,MAAA,CAAQ,IAAA,CAAM,SAAU,CAAA,CAChC,KAAA,CACA,CAAC,MAAM,CACT,EAEMG,CAAAA,CAAY,MAAM,OAAO,MAAA,CAAO,IAAA,CAAK,OAAQD,CAAAA,CAAKD,CAAW,EACnE,OAAO,KAAA,CAAM,IAAA,CAAK,IAAI,UAAA,CAAWE,CAAS,EAAGN,CAAAA,EAC3CA,CAAAA,CAAE,SAAS,EAAE,CAAA,CAAE,SAAS,CAAA,CAAG,GAAG,CAChC,CAAA,CAAE,IAAA,CAAK,EAAE,CACX,CAGA,IAAIO,EAAO,CAAA,CACLC,CAAAA,CAAMP,EAAS9C,CAAAA,CACrB,IAAA,IAASsD,CAAAA,CAAI,CAAA,CAAGA,CAAAA,CAAID,CAAAA,CAAI,OAAQC,CAAAA,EAAAA,CAAK,CACnC,IAAMC,CAAAA,CAAOF,CAAAA,CAAI,WAAWC,CAAC,CAAA,CAC7BF,GAASA,CAAAA,EAAQ,CAAA,EAAKA,EAAQG,CAAAA,CAC9BH,CAAAA,CAAOA,EAAOA,EAChB,CACA,OAAO,IAAA,CAAK,GAAA,CAAIA,CAAI,CAAA,CAAE,QAAA,CAAS,EAAE,CACnC,CAKA,SAASV,GAAkBc,CAAAA,CAAWX,CAAAA,CAAoB,CACxD,GAAIW,CAAAA,CAAE,MAAA,GAAWX,CAAAA,CAAE,MAAA,CACjB,OAAO,OAGT,IAAIY,CAAAA,CAAS,EACb,IAAA,IAASH,CAAAA,CAAI,EAAGA,CAAAA,CAAIE,CAAAA,CAAE,MAAA,CAAQF,CAAAA,EAAAA,CAC5BG,CAAAA,EAAUD,CAAAA,CAAE,WAAWF,CAAC,CAAA,CAAIT,EAAE,UAAA,CAAWS,CAAC,EAG5C,OAAOG,CAAAA,GAAW,CACpB,CC3NO,SAASC,CAAAA,CAAkBvG,CAAAA,CAAiC,CAEjE,IAAMwG,CAAAA,CAAQ,IAAI,GAAA,CAGZC,CAAAA,CAAkB,WAAA,CAAY,IAAM,CACxC,IAAMC,EAAM,IAAA,CAAK,GAAA,GACjB,IAAA,GAAW,CAACX,CAAAA,CAAKY,CAAK,CAAA,GAAKH,CAAAA,CACrBG,EAAM,OAAA,EAAWD,CAAAA,EACnBF,EAAM,MAAA,CAAOT,CAAG,EAGtB,CAAA,CAAG/F,CAAAA,CAAO,QAAQ,CAAA,CAGd,OAAO,OAAA,CAAY,KAAe,OAAA,CAAQ,EAAA,EAC5C,QAAQ,EAAA,CAAG,YAAA,CAAc,IAAM,aAAA,CAAcyG,CAAe,CAAC,CAAA,CAM/D,SAASG,EAAW7E,CAAAA,CAA2B,CAC7C,OAAO/B,CAAAA,CAAO,UAAA,CAAW,KAAK6G,CAAAA,EAExBA,CAAAA,CAAQ,QAAA,CAAS,GAAG,CAAA,CACf9E,CAAAA,CAAS,WAAW8E,CAAAA,CAAQ,KAAA,CAAM,EAAG,EAAE,CAAC,EAE7CA,CAAAA,CAAQ,QAAA,CAAS,IAAI,CAAA,CAChB9E,CAAAA,CAAS,UAAA,CAAW8E,EAAQ,KAAA,CAAM,CAAA,CAAG,EAAE,CAAC,CAAA,CAE1C9E,IAAa8E,CACrB,CACH,CAKA,SAASC,CAAAA,CAAMhH,CAAAA,CAAmC,CAChD,IAAMiC,CAAAA,CAAWjC,EAAI,OAAA,CAAQ,QAAA,CAG7B,GAAI8G,CAAAA,CAAW7E,CAAQ,EACrB,OAAO,CACL,QAAS,IAAA,CACT,SAAA,CAAW/B,EAAO,WAAA,CAClB,OAAA,CAAS,EACT,KAAA,CAAOA,CAAAA,CAAO,WAChB,CAAA,CAGF,IAAM+F,CAAAA,CAAM/F,EAAO,KAAA,CAAMF,CAAG,EACtB4G,CAAAA,CAAM,IAAA,CAAK,KAAI,CAEjBC,CAAAA,CAAQH,CAAAA,CAAM,GAAA,CAAIT,CAAG,CAAA,CAGzB,GAAI,CAACY,CAAAA,EAASA,EAAM,OAAA,EAAWD,CAAAA,CAC7B,OAAAC,CAAAA,CAAQ,CACN,KAAA,CAAO,CAAA,CACP,OAAA,CAASD,CAAAA,CAAM1G,EAAO,QACxB,CAAA,CACAwG,EAAM,GAAA,CAAIT,CAAAA,CAAKY,CAAK,CAAA,CAEb,CACL,QAAS,IAAA,CACT,SAAA,CAAW3G,EAAO,WAAA,CAAc,CAAA,CAChC,QAAS2G,CAAAA,CAAM,OAAA,CACf,MAAO3G,CAAAA,CAAO,WAChB,CAAA,CAIF2G,CAAAA,CAAM,KAAA,EAAA,CAEN,IAAMI,EAAY,IAAA,CAAK,GAAA,CAAI,EAAG/G,CAAAA,CAAO,WAAA,CAAc2G,EAAM,KAAK,CAAA,CAG9D,OAAO,CACL,OAAA,CAHcA,CAAAA,CAAM,OAAS3G,CAAAA,CAAO,WAAA,CAIpC,UAAA+G,CAAAA,CACA,OAAA,CAASJ,EAAM,OAAA,CACf,KAAA,CAAO3G,CAAAA,CAAO,WAChB,CACF,CAKA,SAASgH,CAAAA,CAAanG,CAAAA,CAAwByF,EAAuC,CACnF,OAAAzF,EAAS,OAAA,CAAQ,GAAA,CAAI,oBAAqByF,CAAAA,CAAO,KAAA,CAAM,UAAU,CAAA,CACjEzF,EAAS,OAAA,CAAQ,GAAA,CAAI,wBAAyByF,CAAAA,CAAO,SAAA,CAAU,QAAA,EAAU,CAAA,CACzEzF,CAAAA,CAAS,QAAQ,GAAA,CAAI,mBAAA,CAAqB,KAAK,IAAA,CAAKyF,CAAAA,CAAO,QAAU,GAAI,CAAA,CAAE,QAAA,EAAU,CAAA,CAC9EzF,CACT,CAKA,SAASoG,CAAAA,CAAsBnH,EAAkBwG,CAAAA,CAAuC,CAEtF,GAAItG,CAAAA,CAAO,aAAA,CAAe,CACxB,IAAMa,CAAAA,CAAWb,CAAAA,CAAO,cAAcF,CAAG,CAAA,CACzC,OAAOkH,CAAAA,CAAanG,CAAAA,CAAUyF,CAAM,CACtC,CAGA,IAAMzF,CAAAA,CAAWkC,YAAAA,CAAa,IAAA,CAC5B,CACE,OAAA,CAAS,KAAA,CACT,QAAS,4CAAA,CACT,UAAA,CAAY,KAAK,IAAA,CAAA,CAAMuD,CAAAA,CAAO,OAAA,CAAU,IAAA,CAAK,GAAA,EAAI,EAAK,GAAI,CAC5D,CAAA,CACA,CAAE,MAAA,CAAQ,GAAI,CAChB,CAAA,CAEA,OAAAzF,CAAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,aAAA,CAAe,KAAK,IAAA,CAAA,CAAMyF,CAAAA,CAAO,QAAU,IAAA,CAAK,GAAA,IAAS,GAAI,CAAA,CAAE,QAAA,EAAU,CAAA,CACvFU,CAAAA,CAAanG,EAAUyF,CAAM,CACtC,CAKA,SAASY,CAAAA,CAAMnB,EAAmB,CAChCS,CAAAA,CAAM,OAAOT,CAAG,EAClB,CAKA,SAASoB,CAAAA,EAAc,CACrBX,CAAAA,CAAM,KAAA,GACR,CAKA,SAASY,CAAAA,EAAe,CACtB,OAAOZ,CAAAA,CAAM,IACf,CAEA,OAAO,CACL,KAAA,CAAAM,CAAAA,CACA,aAAAE,CAAAA,CACA,qBAAA,CAAAC,CAAAA,CACA,UAAA,CAAAL,CAAAA,CACA,KAAA,CAAAM,EACA,KAAA,CAAAC,CAAAA,CACA,KAAAC,CACF,CACF,CCrKO,SAASC,CAAAA,CAAkBrH,CAAAA,CAA6B,CAI7D,SAASsH,CAAAA,CAAUC,EAA+B,CAChD,OAAOvH,EAAO,OAAA,EAAWA,CAAAA,CAAO,OAAO,QAAA,CAASuH,CAAI,CACtD,CAKA,SAASC,EAAM1H,CAAAA,CAAiC,CAC9C,OACEA,CAAAA,CAAI,OAAA,CAAQ,IAAI,iBAAiB,CAAA,EAAG,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,GAAG,IAAA,EAAK,EACxDA,EAAI,OAAA,CAAQ,GAAA,CAAI,WAAW,CAAA,EAC3B,IAEJ,CAKA,eAAe2H,CAAAA,CACbF,CAAAA,CACAzH,EACA4H,CAAAA,CAKe,CACf,GAAI,CAACJ,CAAAA,CAAUC,CAAI,CAAA,CACjB,OAGF,IAAMI,CAAAA,CAAoB,CACxB,IAAA,CAAAJ,EACA,SAAA,CAAW,IAAI,KACf,EAAA,CAAIC,CAAAA,CAAM1H,CAAG,CAAA,CACb,MAAA,CAAQ4H,EAAQ,MAAA,CAChB,IAAA,CAAM5H,EAAI,OAAA,CAAQ,QAAA,CAClB,OAAQA,CAAAA,CAAI,MAAA,CACZ,QAAS4H,CAAAA,CAAQ,OAAA,CACjB,QAAA,CAAUA,CAAAA,CAAQ,QACpB,CAAA,CAGA,GAAI1H,CAAAA,CAAO,MAAA,CACT,GAAI,CACF,MAAMA,EAAO,MAAA,CAAO2H,CAAK,EAC3B,CAAA,MAASC,CAAAA,CAAO,CAEd,QAAQ,KAAA,CAAM,sCAAA,CAAwCA,CAAK,EAC7D,CAEJ,CAOA,SAASC,CAAAA,CAAY/H,CAAAA,CAAkBgI,CAAAA,CAAiBC,CAAAA,CAAoC,CAC1F,OAAON,CAAAA,CAAK,cAAA,CAAgB3H,EAAK,CAAE,OAAA,CAAS,KAAM,MAAA,CAAAgI,CAAAA,CAAQ,QAAA,CAAAC,CAAS,CAAC,CACtE,CAKA,SAASC,CAAAA,CAASlI,EAAkBiI,CAAAA,CAAoC,CACtE,OAAON,CAAAA,CAAK,WAAA,CAAa3H,CAAAA,CAAK,CAAE,OAAA,CAAS,KAAA,CAAO,SAAAiI,CAAS,CAAC,CAC5D,CAKA,SAASE,EAAYnI,CAAAA,CAAkBgI,CAAAA,CAAiBC,CAAAA,CAAoC,CAC1F,OAAON,CAAAA,CAAK,eAAgB3H,CAAAA,CAAK,CAAE,QAAS,IAAA,CAAM,MAAA,CAAAgI,EAAQ,QAAA,CAAAC,CAAS,CAAC,CACtE,CAKA,SAASG,EAAUpI,CAAAA,CAAkBiI,CAAAA,CAAoC,CACvE,OAAON,CAAAA,CAAK,aAAc3H,CAAAA,CAAK,CAAE,QAAS,IAAA,CAAM,QAAA,CAAAiI,CAAS,CAAC,CAC5D,CAKA,SAASI,CAAAA,CAAarI,EAAkBgI,CAAAA,CAAiBC,CAAAA,CAAoC,CAC3F,OAAON,CAAAA,CAAK,eAAA,CAAiB3H,EAAK,CAAE,OAAA,CAAS,MAAO,MAAA,CAAAgI,CAAAA,CAAQ,SAAAC,CAAS,CAAC,CACxE,CAKA,SAASK,CAAAA,CAAStI,EAAkBiI,CAAAA,CAAoC,CACtE,OAAON,CAAAA,CAAK,WAAA,CAAa3H,EAAK,CAAE,OAAA,CAAS,KAAA,CAAO,QAAA,CAAAiI,CAAS,CAAC,CAC5D,CAKA,SAASM,EAAkBvI,CAAAA,CAAkBiI,CAAAA,CAAoC,CAC/E,OAAON,CAAAA,CAAK,qBAAsB3H,CAAAA,CAAK,CAAE,QAAS,KAAA,CAAO,QAAA,CAAAiI,CAAS,CAAC,CACrE,CAKA,SAASH,CAAAA,CAAM9H,CAAAA,CAAkBwI,CAAAA,CAAYP,CAAAA,CAAoC,CAC/E,OAAON,CAAAA,CAAK,OAAA,CAAS3H,EAAK,CACxB,OAAA,CAAS,MACT,QAAA,CAAU,CACR,GAAGiI,CAAAA,CACH,KAAA,CAAOO,CAAAA,CAAI,QACX,KAAA,CAAOA,CAAAA,CAAI,KACb,CACF,CAAC,CACH,CAEA,OAAO,CACL,IAAA,CAAAb,CAAAA,CACA,SAAA,CAAAH,EAEA,WAAA,CAAAO,CAAAA,CACA,SAAAG,CAAAA,CACA,WAAA,CAAAC,EACA,SAAA,CAAAC,CAAAA,CACA,aAAAC,CAAAA,CACA,QAAA,CAAAC,EACA,iBAAA,CAAAC,CAAAA,CACA,MAAAT,CACF,CACF,CC7FO,SAASW,EAAAA,CAAgBC,CAAAA,CAA6B,CAE3D,IAAMxI,CAAAA,CAASD,EAAmByI,CAAU,CAAA,CAGtCnG,EAAatB,CAAAA,CAAsBf,CAAM,EAGzCyI,CAAAA,CAAWrG,CAAAA,CAAepC,CAAAA,CAAQqC,CAAU,CAAA,CAG5C/B,CAAAA,CAAOkE,EAAoBxE,CAAAA,CAAO,SAAA,CAAU,IAAI,CAAA,CAChD0I,CAAAA,CAAcnC,EAAkBvG,CAAAA,CAAO,SAAA,CAAU,SAAS,CAAA,CAC1DU,CAAAA,CAAQ2G,CAAAA,CAAkBrH,EAAO,SAAA,CAAU,KAAK,EAKtD,eAAe2I,CAAAA,CAAU7I,EAAyC,CAChE,GAAM,CAAE,QAAA,CAAAiC,CAAAA,CAAU,MAAA,CAAA0B,CAAO,CAAA,CAAI3D,CAAAA,CAAI,QAC3B0D,CAAAA,CAAazB,CAAAA,CAAS,WAAW,MAAM,CAAA,CAI7C,GAAI/B,CAAAA,CAAO,SAAA,CAAU,SAAA,CAAU,QAAS,CACtC,IAAM4I,EAAkBF,CAAAA,CAAY,KAAA,CAAM5I,CAAG,CAAA,CAE7C,GAAI,CAAC8I,CAAAA,CAAgB,OAAA,CACnB,OAAA,MAAMlI,EAAM,iBAAA,CAAkBZ,CAAAA,CAAK,CACjC,KAAA,CAAO8I,CAAAA,CAAgB,MACvB,OAAA,CAASA,CAAAA,CAAgB,OAC3B,CAAC,CAAA,CACMF,CAAAA,CAAY,sBAAsB5I,CAAAA,CAAK8I,CAAe,CAEjE,CAIA,GAAI5I,EAAO,SAAA,CAAU,IAAA,CAAK,QAAS,CACjC,IAAM6I,EAAavI,CAAAA,CAAK,eAAA,CAAgBR,CAAG,CAAA,CAE3C,GAAI,CAAC+I,CAAAA,CAAW,KAAA,CACd,OAAA,MAAMnI,CAAAA,CAAM,QAAA,CAASZ,CAAAA,CAAK,CAAE,MAAA,CAAQ+I,CAAAA,CAAW,MAAO,CAAC,CAAA,CAChD9F,aAAa,IAAA,CAClB,CAAE,OAAA,CAAS,KAAA,CAAO,OAAA,CAAS,wBAAyB,EACpD,CAAE,MAAA,CAAQ,GAAI,CAChB,CAEJ,CAIA,GAAI/C,CAAAA,CAAO,qBAAA,EAAyBwD,CAAAA,EAAAA,CACb1D,CAAAA,CAAI,OAAA,CAAQ,IAAI,QAAQ,CAAA,EAAK,IACjC,QAAA,CAAS,WAAW,EACnC,OAAOiD,YAAAA,CAAa,SAAS,IAAI,GAAA,CAAI,IAAKU,CAAM,CAAC,EAMrD,GAAIzD,CAAAA,CAAO,WAAY,CACrB,IAAM8I,CAAAA,CAAe,MAAM9I,CAAAA,CAAO,UAAA,CAAWF,CAAG,CAAA,CAChD,GAAIgJ,EACF,OAAOA,CAEX,CAIA,GAAA,CADsB9I,CAAAA,CAAO,aAAA,EAAiB,EAAC,EAC7B,IAAA,CAAK+I,GAAQhH,CAAAA,CAAS,UAAA,CAAWgH,CAAI,CAAC,CAAA,CACtD,OAAOC,CAAAA,CAAelJ,CAAAA,CAAKiD,YAAAA,CAAa,IAAA,EAAK,CAAG,CAAE,gBAAiB,KAAA,CAAO,OAAA,CAAS,MAAO,SAAA,CAAW,IAAA,CAAM,KAAM,IAAK,CAAC,EAYzH,GARqB,CACnB,kBACA,kBAAA,CACA,cAAA,CACA,oBACA,oBACF,CAAA,CAEiB,SAAShB,CAAQ,CAAA,CAChC,OAAOiH,CAAAA,CAAelJ,CAAAA,CAAKiD,YAAAA,CAAa,MAAK,CAAG,CAAE,gBAAiB,KAAA,CAAO,OAAA,CAAS,MAAO,SAAA,CAAW,IAAA,CAAM,IAAA,CAAM,IAAK,CAAC,CAAA,CAIzH,IAAMkG,CAAAA,CAAYnJ,CAAAA,CAAI,SAAS,GAAA,CAAIE,CAAAA,CAAO,QAAQ,IAAI,CAAA,EAAG,KAAA,CACnDuC,CAAAA,CAAazC,CAAAA,CAAI,OAAA,EAAS,IAAIE,CAAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,EAAG,KAAA,CACrD8D,EAAemF,CAAAA,EAAa1G,CAAAA,CAC5BsB,CAAAA,CAAc,CAAC,CAACoF,CAAAA,CAGtB,GAAI,CAACnF,CAAAA,CAAc,CACjB,MAAMpD,CAAAA,CAAM,SAASZ,CAAAA,CAAK,CAAE,MAAA,CAAQ,UAAW,CAAC,CAAA,CAChD,IAAMe,CAAAA,CAAW,MAAM4H,EAAS,aAAA,CAAc3I,CAAAA,CAAK0D,CAAU,CAAA,CAC7D,OAAOwF,CAAAA,CAAelJ,CAAAA,CAAKe,CAAAA,CAAU,CAAE,gBAAiB,KAAA,CAAO,OAAA,CAAS,MAAO,SAAA,CAAW,IAAA,CAAM,KAAM,IAAK,CAAC,CAC9G,CAGA,IAAM+C,CAAAA,CAAY,MAAMvB,CAAAA,CAAW,YAAA,CAAayB,CAAY,CAAA,CAGtDoF,CAAAA,CAAyB,CAC7B,eAAA,CAAiBtF,CAAAA,CAAU,SAAWA,CAAAA,CAAU,SAAA,GAAc,QAC9D,OAAA,CAASA,CAAAA,CAAU,SAAWA,CAAAA,CAAU,SAAA,GAAc,QACtD,SAAA,CAAWA,CAAAA,CAAU,SAAA,CACrB,IAAA,CAAMA,CAAAA,CAAU,QAClB,EAGA,GAAIA,CAAAA,CAAU,QACZ,GAAIA,CAAAA,CAAU,YAAc,OAAA,CAC1B,MAAMlD,CAAAA,CAAM,SAAA,CAAUZ,CAAG,CAAA,CAAA,KACpB,CACL,IAAMgI,CAAAA,CAASlE,EAAU,QAAA,EAAU,EAAA,EAAI,UAAS,CAChD,MAAMlD,CAAAA,CAAM,WAAA,CAAYZ,CAAAA,CAAKgI,CAAAA,CAAQ,CAAE,SAAA,CAAWlE,CAAAA,CAAU,SAAU,CAAC,EACzE,MAEA,MAAMlD,CAAAA,CAAM,SAASZ,CAAAA,CAAK,CAAE,OAAQ,eAAgB,CAAC,EAIvD,IAAMe,CAAAA,CAAW,MAAM4H,CAAAA,CAAS,sBAAA,CAC9B3I,CAAAA,CACA8D,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACAN,CACF,CAAA,CAGI2F,CAAAA,CAAgB,MAAMH,CAAAA,CAAelJ,CAAAA,CAAKe,EAAUqI,CAAU,CAAA,CAElE,GAAIlJ,CAAAA,CAAO,SAAA,CAAU,IAAA,CAAK,SAAWkJ,CAAAA,CAAW,eAAA,CAAiB,CAC/D,IAAMxE,CAAAA,CAAYd,EAAU,QAAA,EAAU,EAAA,EAAI,QAAA,EAAS,EAAKE,CAAAA,CAAa,KAAA,CAAM,EAAG,EAAE,CAAA,CAChFqF,EAAgB,MAAM7I,CAAAA,CAAK,iBAAiB6I,CAAAA,CAAezE,CAAS,EACtE,CAGA,GAAI1E,EAAO,SAAA,CAAU,SAAA,CAAU,QAAS,CACtC,IAAM4I,EAAkBF,CAAAA,CAAY,KAAA,CAAM5I,CAAG,CAAA,CAC7CqJ,CAAAA,CAAgBT,CAAAA,CAAY,aAAaS,CAAAA,CAAeP,CAAe,EACzE,CAEA,OAAOO,CACT,CAKA,eAAeH,CAAAA,CAAelJ,CAAAA,CAAkBe,CAAAA,CAAwBqI,CAAAA,CAA+C,CACrH,OAAIlJ,CAAAA,CAAO,UACFA,CAAAA,CAAO,SAAA,CAAUF,EAAKe,CAAAA,CAAUqI,CAAU,CAAA,CAE5CrI,CACT,CAGA,OAAA8H,EAAU,MAAA,CAAS3I,CAAAA,CACnB2I,EAAU,IAAA,CAAOrI,CAAAA,CACjBqI,EAAU,WAAA,CAAcD,CAAAA,CACxBC,CAAAA,CAAU,KAAA,CAAQjI,CAAAA,CAEXiI,CACT,CCvLA,SAASS,GAAeC,CAAAA,CAAkBC,CAAAA,CAA6B,CACrE,GAAI,CAACA,CAAAA,EAAYA,EAAS,MAAA,GAAW,CAAA,CAAG,OAAO,MAAA,CAG/C,IAAMC,EAAqBF,CAAAA,CACxB,OAAA,CAAQ,UAAA,CAAY,EAAE,CAAA,CACtB,OAAA,CAAQ,MAAO,EAAE,CAAA,CAEpB,OAAOC,CAAAA,CAAS,IAAA,CAAKzC,GAAW,CAC9B,GAAIA,CAAAA,GAAY0C,CAAAA,CAAoB,OAAO,KAAA,CAE3C,GAAI1C,CAAAA,CAAQ,QAAA,CAAS,GAAG,CAAA,CAAG,CACzB,IAAM2C,CAAAA,CAAe3C,CAAAA,CAClB,QAAQ,OAAA,CAAS,cAAc,EAC/B,OAAA,CAAQ,KAAA,CAAO,OAAO,CAAA,CACtB,OAAA,CAAQ,gBAAiB,IAAI,CAAA,CAEhC,OADc,IAAI,MAAA,CAAO,CAAA,CAAA,EAAI2C,CAAY,CAAA,CAAA,CAAG,CAAA,CAC/B,KAAKD,CAAkB,CACtC,CAEA,OAAO,MACT,CAAC,CACH,CAwBO,SAASE,GAAmBzJ,GAAAA,CAA4B,CAC7D,GAAM,CACJ,UAAA,CAAAC,EACA,cAAA,CAAAyJ,CAAAA,CAAiB,YAAA,CACjB,eAAA,CAAAC,CAAAA,CAAkB,aAAA,CAClB,kBAAAC,CAAAA,CAAoB,KAAA,CACpB,gBAAAC,CAAAA,CAAkB,GAClB,cAAA,CAAAC,CAAAA,CAAiB,CAAC,cAAA,CAAgB,QAAA,CAAU,kBAAmB,kBAAkB,CAAA,CACjF,eAAAC,CAAAA,CAAiB,CAAC,OAAQ,YAAA,CAAc,QAAQ,CAAA,CAChD,gBAAA,CAAAC,CAAAA,CACA,iBAAA,CAAAC,CACF,CAAA,CAAIjK,GAAAA,CAGEkK,EAAUjK,CAAAA,CAAW,OAAA,CAAQ,MAAO,EAAE,CAAA,CAK5C,SAASkK,CAAAA,CAAerK,CAAAA,CAAkBuJ,CAAAA,CAA2B,CAQnE,OANuBvJ,CAAAA,CAAI,QAAQ,GAAA,CAAIwE,CAAAA,CAAQ,SAAS,CAAA,GACjC,MAAA,EAKnB8E,EAAAA,CAAeC,CAAAA,CAAUQ,CAAe,CAAA,CACnC,KAIFD,CACT,CAKA,eAAeQ,CAAAA,CAAQtK,CAAAA,CAAyC,CAC9D,GAAI,CAEF,IAAMuK,CAAAA,CAAM,IAAI,IAAIvK,CAAAA,CAAI,GAAG,EACrBuJ,CAAAA,CAAWgB,CAAAA,CAAI,SAAS,OAAA,CAAQ,WAAA,CAAa,EAAE,CAAA,CAG/CC,CAAAA,CAAa,IAAI,IAAI,CAAA,EAAGJ,CAAO,IAAIb,CAAQ,CAAA,CAAE,EACnDiB,CAAAA,CAAW,MAAA,CAASD,CAAAA,CAAI,MAAA,CAGxB,IAAME,CAAAA,CAAU,IAAI,OAAA,CAmBpB,GAhBAT,EAAe,OAAA,CAAQU,CAAAA,EAAc,CACnC,IAAMC,CAAAA,CAAQ3K,CAAAA,CAAI,OAAA,CAAQ,GAAA,CAAI0K,CAAU,EACpCC,CAAAA,EACFF,CAAAA,CAAQ,IAAIC,CAAAA,CAAYC,CAAK,EAEjC,CAAC,CAAA,CAGD3K,CAAAA,CAAI,OAAA,CAAQ,OAAA,CAAQ,CAAC2K,EAAO1E,CAAAA,GAAQ,CAClC,IAAM2E,CAAAA,CAAW3E,CAAAA,CAAI,aAAY,CAC7B,CAACgE,CAAAA,CAAe,QAAA,CAASW,CAAQ,CAAA,EAAK,CAACH,CAAAA,CAAQ,GAAA,CAAIxE,CAAG,CAAA,EACxDwE,CAAAA,CAAQ,IAAIxE,CAAAA,CAAK0E,CAAK,EAE1B,CAAC,CAAA,CAGG,CAACN,EAAerK,CAAAA,CAAKuJ,CAAQ,EAAG,CAClC,IAAMJ,EAAYnJ,CAAAA,CAAI,OAAA,CAAQ,GAAA,CAAI4J,CAAc,CAAA,EAAG,KAAA,CAC7CnH,EAAazC,CAAAA,CAAI,OAAA,CAAQ,IAAI6J,CAAe,CAAA,EAAG,MAC/CvI,CAAAA,CAAQ6H,CAAAA,EAAa1G,EAEvBnB,CAAAA,EACFmJ,CAAAA,CAAQ,IAAIjG,CAAAA,CAAQ,aAAA,CAAe,UAAUlD,CAAK,CAAA,CAAE,EAExD,CAGAmJ,CAAAA,CAAQ,MAAA,CAAOjG,CAAAA,CAAQ,SAAS,CAAA,CAGhC,IAAMqG,CAAAA,CAAeX,CAAAA,CACjB,MAAMA,CAAAA,CAAiBlK,CAAAA,CAAKyK,CAAO,CAAA,CACnCA,CAAAA,CAGAK,CAAAA,CAAwB,IAAA,CAC5B,GAAI9K,CAAAA,CAAI,SAAW,KAAA,EAASA,CAAAA,CAAI,SAAW,MAAA,CAAQ,CACjD,IAAM+K,CAAAA,CAAc/K,CAAAA,CAAI,OAAA,CAAQ,GAAA,CAAI,cAAc,CAAA,EAAK,GAEnD+K,CAAAA,CAAY,QAAA,CAAS,kBAAkB,CAAA,CACzCD,CAAAA,CAAO,MAAM9K,CAAAA,CAAI,IAAA,GACR+K,CAAAA,CAAY,QAAA,CAAS,qBAAqB,CAAA,CACnDD,CAAAA,CAAO,MAAM9K,CAAAA,CAAI,QAAA,GAEjB8K,CAAAA,CAAO,MAAM9K,CAAAA,CAAI,IAAA,GAErB,CAGA,IAAMgL,CAAAA,CAAkB,MAAM,MAAMR,CAAAA,CAAW,QAAA,GAAY,CACzD,MAAA,CAAQxK,CAAAA,CAAI,MAAA,CACZ,OAAA,CAAS6K,CAAAA,CACT,KAAAC,CACF,CAAC,EAGKC,CAAAA,CAAcC,CAAAA,CAAgB,QAAQ,GAAA,CAAI,cAAc,CAAA,EAAK,EAAA,CAC/DC,CAAAA,CAEAF,CAAAA,CAAY,SAAS,kBAAkB,CAAA,CACzCE,EAAe,MAAMD,CAAAA,CAAgB,MAAK,CAE1CC,CAAAA,CAAe,MAAMD,CAAAA,CAAgB,WAAA,GAIvC,IAAME,CAAAA,CAAkB,IAAI,OAAA,CAC5BF,CAAAA,CAAgB,QAAQ,OAAA,CAAQ,CAACL,CAAAA,CAAO1E,CAAAA,GAAQ,CAC9C,IAAM2E,EAAW3E,CAAAA,CAAI,WAAA,GAEhB,CAAC,mBAAA,CAAqB,aAAc,YAAY,CAAA,CAAE,QAAA,CAAS2E,CAAQ,CAAA,EACtEM,CAAAA,CAAgB,IAAIjF,CAAAA,CAAK0E,CAAK,EAElC,CAAC,CAAA,CAGD,IAAI5J,CAAAA,CAAW,IAAIkC,YAAAA,CAAagI,CAAAA,CAAc,CAC5C,MAAA,CAAQD,EAAgB,MAAA,CACxB,UAAA,CAAYA,EAAgB,UAAA,CAC5B,OAAA,CAASE,CACX,CAAC,CAAA,CAGD,OAAIf,CAAAA,GACFpJ,CAAAA,CAAW,MAAMoJ,EAAkBpJ,CAAQ,CAAA,CAAA,CAGtCA,CACT,CAAA,MAAS+G,CAAAA,CAAO,CACd,OAAA,OAAA,CAAQ,KAAA,CAAM,eAAA,CAAiBA,CAAK,CAAA,CAE7B7E,YAAAA,CAAa,KAClB,CACE,OAAA,CAAS,MACT,OAAA,CAAS,2CAAA,CACT,MAAO6E,CAAAA,YAAiB,KAAA,CAAQA,CAAAA,CAAM,OAAA,CAAU,eAClD,CAAA,CACA,CAAE,MAAA,CAAQ,GAAI,CAChB,CACF,CACF,CAGA,OAAAwC,CAAAA,CAAQ,MAAA,CAASpK,GAAAA,CAEVoK,CACT","file":"index.js","sourcesContent":["/**\r\n * Config Resolver\r\n * Resolves and validates configuration with defaults\r\n */\r\n\r\nimport type { NextRequest } from 'next/server';\r\nimport type {\r\n AuthProxyConfig,\r\n InternalProxyConfig,\r\n ApiClientConfig,\r\n ResolvedCookieOptions,\r\n EndpointConfig,\r\n ResolvedCsrfConfig,\r\n ResolvedRateLimitConfig,\r\n ResolvedAuditConfig,\r\n AuditEventType,\r\n} from './types';\r\n\r\nimport {\r\n DEFAULT_COOKIE_OPTIONS,\r\n DEFAULT_ENDPOINTS,\r\n DEFAULT_CSRF_CONFIG,\r\n DEFAULT_RATE_LIMIT_CONFIG,\r\n DEFAULT_AUDIT_CONFIG,\r\n} from './constants';\r\n\r\n/**\r\n * Generates a random secret for CSRF HMAC signing\r\n */\r\nfunction generateCsrfSecret(): string {\r\n // Use crypto if available (Node.js)\r\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\r\n return crypto.randomUUID() + crypto.randomUUID();\r\n }\r\n // Fallback: timestamp + random\r\n return `${Date.now()}-${Math.random().toString(36).substring(2)}`;\r\n}\r\n\r\n/**\r\n * Default rate limit key function (IP-based)\r\n */\r\nfunction defaultRateLimitKeyFn(req: NextRequest): string {\r\n const forwarded = req.headers.get('x-forwarded-for');\r\n const ip = forwarded?.split(',')[0]?.trim() || \r\n req.headers.get('x-real-ip') || \r\n 'unknown';\r\n return `rl:${ip}`;\r\n}\r\n\r\n/**\r\n * Resolves proxy configuration with defaults\r\n */\r\nexport function resolveProxyConfig(config: AuthProxyConfig): InternalProxyConfig {\r\n // Validate required fields\r\n if (!config.apiBaseUrl) {\r\n throw new Error('next-api-layer: apiBaseUrl is required');\r\n }\r\n \r\n if (!config.cookies?.user || !config.cookies?.guest) {\r\n throw new Error('next-api-layer: cookies.user and cookies.guest are required');\r\n }\r\n\r\n // Ensure apiBaseUrl ends with /\r\n const apiBaseUrl = config.apiBaseUrl.endsWith('/')\r\n ? config.apiBaseUrl\r\n : `${config.apiBaseUrl}/`;\r\n\r\n // Resolve cookie options\r\n const cookieOptions: ResolvedCookieOptions = {\r\n ...DEFAULT_COOKIE_OPTIONS,\r\n ...config.cookies.options,\r\n };\r\n\r\n // Resolve endpoints\r\n const endpoints: Required<EndpointConfig> = {\r\n ...DEFAULT_ENDPOINTS,\r\n ...config.endpoints,\r\n };\r\n\r\n // Resolve CSRF config\r\n const csrf: ResolvedCsrfConfig = {\r\n enabled: config.csrf?.enabled ?? false,\r\n strategy: config.csrf?.strategy ?? DEFAULT_CSRF_CONFIG.strategy,\r\n secret: config.csrf?.secret ?? generateCsrfSecret(),\r\n cookieName: config.csrf?.cookieName ?? DEFAULT_CSRF_CONFIG.cookieName,\r\n headerName: config.csrf?.headerName ?? DEFAULT_CSRF_CONFIG.headerName,\r\n ignoreMethods: config.csrf?.ignoreMethods ?? DEFAULT_CSRF_CONFIG.ignoreMethods,\r\n trustSameSite: config.csrf?.trustSameSite ?? DEFAULT_CSRF_CONFIG.trustSameSite,\r\n };\r\n\r\n // Resolve rate limit config\r\n const rateLimit: ResolvedRateLimitConfig = {\r\n enabled: config.rateLimit?.enabled ?? false,\r\n windowMs: config.rateLimit?.windowMs ?? DEFAULT_RATE_LIMIT_CONFIG.windowMs,\r\n maxRequests: config.rateLimit?.maxRequests ?? DEFAULT_RATE_LIMIT_CONFIG.maxRequests,\r\n keyFn: config.rateLimit?.keyFn ?? defaultRateLimitKeyFn,\r\n skipRoutes: config.rateLimit?.skipRoutes ?? DEFAULT_RATE_LIMIT_CONFIG.skipRoutes,\r\n onRateLimited: config.rateLimit?.onRateLimited,\r\n };\r\n\r\n // Resolve audit config\r\n const audit: ResolvedAuditConfig = {\r\n enabled: config.audit?.enabled ?? false,\r\n events: config.audit?.events ?? [...DEFAULT_AUDIT_CONFIG.events] as AuditEventType[],\r\n logger: config.audit?.logger,\r\n };\r\n\r\n return {\r\n ...config,\r\n apiBaseUrl,\r\n _resolved: {\r\n cookieOptions,\r\n endpoints,\r\n csrf,\r\n rateLimit,\r\n audit,\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Resolves API client configuration with defaults\r\n */\r\nexport function resolveApiClientConfig(config: ApiClientConfig = {}) {\r\n return {\r\n sanitization: {\r\n enabled: config.sanitization?.enabled ?? true,\r\n allowedTags: config.sanitization?.allowedTags,\r\n skipFields: config.sanitization?.skipFields ?? [],\r\n skipEndpoints: config.sanitization?.skipEndpoints ?? [],\r\n },\r\n i18n: {\r\n enabled: config.i18n?.enabled ?? false,\r\n paramName: config.i18n?.paramName ?? 'lang',\r\n locales: config.i18n?.locales ?? [],\r\n defaultLocale: config.i18n?.defaultLocale ?? 'en',\r\n },\r\n auth: {\r\n skipByDefault: config.auth?.skipByDefault ?? false,\r\n publicEndpoints: config.auth?.publicEndpoints ?? [],\r\n },\r\n methodSpoofing: config.methodSpoofing ?? false,\r\n errorMessages: {\r\n noToken: config.errorMessages?.noToken ?? 'Token bulunamadı.',\r\n connectionError: config.errorMessages?.connectionError ?? 'Bağlantı hatası oluştu.',\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Type guard to check if a value is defined\r\n */\r\nexport function isDefined<T>(value: T | undefined | null): value is T {\r\n return value !== undefined && value !== null;\r\n}\r\n","/**\r\n * Token Validation\r\n * Handles token validation and refresh with backend API\r\n */\r\n\r\nimport type { \r\n TokenInfo, \r\n RefreshResult, \r\n AuthMeResponse, \r\n GuestTokenResponse,\r\n InternalProxyConfig,\r\n ResponseMappers,\r\n} from '../shared/types';\r\n\r\n/**\r\n * Default response parsers (standard format)\r\n */\r\nconst defaultMappers: Required<ResponseMappers> = {\r\n // Default: { success: true, data: { type, exp, ...user } }\r\n parseAuthMe: (response: unknown): TokenInfo | null => {\r\n const res = response as AuthMeResponse | null;\r\n if (!res?.success || !res?.data) {\r\n return null;\r\n }\r\n return {\r\n isValid: true,\r\n tokenType: res.data.type || 'user',\r\n exp: res.data.exp || null,\r\n userData: res.data,\r\n };\r\n },\r\n \r\n // Default: { success: true, data: { accessToken } }\r\n parseRefreshToken: (response: unknown): string | null => {\r\n const res = response as GuestTokenResponse | null;\r\n return res?.success && res?.data?.accessToken ? res.data.accessToken : null;\r\n },\r\n \r\n // Default: { success: true, data: { accessToken } }\r\n parseGuestToken: (response: unknown): string | null => {\r\n const res = response as GuestTokenResponse | null;\r\n return res?.data?.accessToken || null;\r\n },\r\n};\r\n\r\n/**\r\n * Creates token validation functions\r\n */\r\nexport function createTokenValidation(\r\n config: InternalProxyConfig\r\n) {\r\n const { apiBaseUrl, _resolved, responseMappers } = config;\r\n const { endpoints } = _resolved;\r\n \r\n // Merge custom mappers with defaults\r\n const mappers: Required<ResponseMappers> = {\r\n parseAuthMe: responseMappers?.parseAuthMe || defaultMappers.parseAuthMe,\r\n parseRefreshToken: responseMappers?.parseRefreshToken || defaultMappers.parseRefreshToken,\r\n parseGuestToken: responseMappers?.parseGuestToken || defaultMappers.parseGuestToken,\r\n };\r\n\r\n /**\r\n * Validates a token against the backend\r\n */\r\n async function validateToken(token: string): Promise<TokenInfo> {\r\n const invalidResult: TokenInfo = { isValid: false, tokenType: null, exp: null, userData: null };\r\n \r\n try {\r\n const res = await fetch(`${apiBaseUrl}${endpoints.validate}`, {\r\n headers: {\r\n 'Authorization': `Bearer ${token}`,\r\n 'Content-Type': 'application/json',\r\n },\r\n cache: 'no-store',\r\n });\r\n\r\n if (!res.ok) {\r\n return invalidResult;\r\n }\r\n\r\n const rawResponse: unknown = await res.json().catch(() => null);\r\n \r\n // Use custom or default mapper\r\n const parsed = mappers.parseAuthMe(rawResponse);\r\n \r\n if (!parsed || !parsed.isValid) {\r\n return invalidResult;\r\n }\r\n\r\n return parsed;\r\n } catch {\r\n return invalidResult;\r\n }\r\n }\r\n\r\n /**\r\n * Gets token info (validates with backend)\r\n */\r\n async function getTokenInfo(token: string): Promise<TokenInfo> {\r\n return validateToken(token);\r\n }\r\n\r\n /**\r\n * Refreshes a token\r\n */\r\n async function refreshToken(oldToken: string): Promise<RefreshResult> {\r\n try {\r\n const res = await fetch(`${apiBaseUrl}${endpoints.refresh}`, {\r\n method: 'POST',\r\n headers: {\r\n 'Authorization': `Bearer ${oldToken}`,\r\n 'Content-Type': 'application/json',\r\n },\r\n cache: 'no-store',\r\n });\r\n\r\n if (!res.ok) {\r\n return { success: false, newToken: null };\r\n }\r\n\r\n const rawResponse: unknown = await res.json().catch(() => null);\r\n \r\n // Use custom or default mapper\r\n const newToken = mappers.parseRefreshToken(rawResponse);\r\n\r\n if (!newToken) {\r\n return { success: false, newToken: null };\r\n }\r\n\r\n return { success: true, newToken };\r\n } catch {\r\n return { success: false, newToken: null };\r\n }\r\n }\r\n\r\n /**\r\n * Creates a guest token\r\n */\r\n async function createGuestToken(): Promise<string | null> {\r\n const guestConfig = config.guestToken;\r\n \r\n if (!guestConfig?.enabled || !guestConfig.credentials) {\r\n return null;\r\n }\r\n\r\n try {\r\n const res = await fetch(`${apiBaseUrl}${endpoints.guest}`, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({\r\n username: guestConfig.credentials.username,\r\n password: guestConfig.credentials.password,\r\n }),\r\n cache: 'no-store',\r\n });\r\n\r\n if (!res.ok) {\r\n return null;\r\n }\r\n\r\n const rawResponse: unknown = await res.json().catch(() => null);\r\n \r\n // Use custom or default mapper\r\n return mappers.parseGuestToken(rawResponse);\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n return {\r\n validateToken,\r\n getTokenInfo,\r\n refreshToken,\r\n createGuestToken,\r\n };\r\n}\r\n\r\nexport type TokenValidation = ReturnType<typeof createTokenValidation>;\r\n","/**\r\n * Proxy Handlers\r\n * Request handling logic for different scenarios\r\n */\r\n\r\nimport { NextRequest, NextResponse } from 'next/server';\r\nimport type { InternalProxyConfig, TokenInfo } from '../shared/types';\r\nimport { HEADERS, TOKEN_TYPES } from '../shared/constants';\r\nimport type { TokenValidation } from './tokenValidation';\r\n\r\n/**\r\n * Extracts locale from pathname based on i18n config\r\n * e.g., /en/dashboard → 'en', /dashboard → defaultLocale or null\r\n */\r\nfunction extractLocale(pathname: string, i18n?: InternalProxyConfig['i18n']): string | null {\r\n if (!i18n?.enabled) return null;\r\n \r\n const locales = i18n.locales ?? [];\r\n const defaultLocale = i18n.defaultLocale;\r\n \r\n // Extract first path segment\r\n const segments = pathname.split('/').filter(Boolean);\r\n const firstSegment = segments[0];\r\n \r\n // Check if it's a valid locale\r\n if (firstSegment && locales.includes(firstSegment)) {\r\n return firstSegment;\r\n }\r\n \r\n // Return default locale if provided\r\n return defaultLocale ?? null;\r\n}\r\n\r\n/**\r\n * Creates proxy handlers\r\n */\r\nexport function createHandlers(\r\n config: InternalProxyConfig,\r\n validation: TokenValidation\r\n) {\r\n const { cookies, guestToken, access, i18n, _resolved } = config;\r\n const { cookieOptions } = _resolved;\r\n\r\n /**\r\n * Safely deletes a cookie only if it exists in the request.\r\n * Prevents empty-value cookies from being created when deleting non-existent cookies.\r\n */\r\n function safeDeleteCookie(req: NextRequest, response: NextResponse, cookieName: string): void {\r\n if (req.cookies.get(cookieName)?.value) {\r\n response.cookies.delete(cookieName);\r\n }\r\n }\r\n\r\n /**\r\n * Deletes all auth cookies from response (only if they exist)\r\n */\r\n function deleteAllAuthCookies(req: NextRequest, response: NextResponse): NextResponse {\r\n safeDeleteCookie(req, response, cookies.guest);\r\n safeDeleteCookie(req, response, cookies.user);\r\n return response;\r\n }\r\n\r\n /**\r\n * Creates a JSON error response\r\n */\r\n function jsonError(message: string, status = 500): NextResponse {\r\n return new NextResponse(\r\n JSON.stringify({ success: false, message }),\r\n { status, headers: { 'Content-Type': 'application/json' } }\r\n );\r\n }\r\n\r\n /**\r\n * Checks if pathname is an auth page\r\n */\r\n function isAuthPage(pathname: string): boolean {\r\n const authRoutes = access?.authRoutes ?? [];\r\n return authRoutes.some(route => \r\n pathname === route || pathname.startsWith(`${route}/`)\r\n );\r\n }\r\n\r\n /**\r\n * Checks if pathname is a protected route\r\n */\r\n function isProtectedRoute(pathname: string): boolean {\r\n // If protectedByDefault is true, everything is protected except public/auth routes\r\n if (access?.protectedByDefault) {\r\n return !isPublicRoute(pathname) && !isAuthPage(pathname);\r\n }\r\n \r\n const protectedRoutes = access?.protectedRoutes ?? [];\r\n return protectedRoutes.some(route => \r\n pathname === route || pathname.startsWith(`${route}/`)\r\n );\r\n }\r\n\r\n /**\r\n * Checks if pathname is explicitly public\r\n */\r\n function isPublicRoute(pathname: string): boolean {\r\n const publicRoutes = access?.publicRoutes ?? [];\r\n return publicRoutes.some(route => \r\n pathname === route || pathname.startsWith(`${route}/`)\r\n );\r\n }\r\n\r\n /**\r\n * Checks if token type is allowed\r\n */\r\n function isTokenTypeAllowed(tokenType: string | null): boolean {\r\n const allowedTypes = access?.allowedTokenTypes;\r\n \r\n // If no restriction, all types allowed\r\n if (!allowedTypes || allowedTypes.length === 0) {\r\n return true;\r\n }\r\n \r\n return tokenType ? allowedTypes.includes(tokenType) : false;\r\n }\r\n\r\n /**\r\n * Handles request when no token is present\r\n */\r\n async function handleNoToken(\r\n req: NextRequest,\r\n isApiRoute: boolean\r\n ): Promise<NextResponse> {\r\n const { origin } = req.nextUrl;\r\n \r\n // Try to create guest token\r\n if (guestToken?.enabled) {\r\n const guestAccessToken = await validation.createGuestToken();\r\n \r\n if (guestAccessToken) {\r\n let response: NextResponse;\r\n \r\n if (isApiRoute) {\r\n response = NextResponse.next();\r\n } else if (isProtectedRoute(req.nextUrl.pathname)) {\r\n // Redirect to login if protected route\r\n response = NextResponse.redirect(new URL('/login', origin));\r\n } else {\r\n response = NextResponse.next();\r\n }\r\n \r\n response.cookies.set(cookies.guest, guestAccessToken, {\r\n ...cookieOptions,\r\n maxAge: 3600, // 1 hour default for guest tokens\r\n });\r\n \r\n return response;\r\n }\r\n }\r\n \r\n // No guest token - just continue or redirect\r\n if (isApiRoute) {\r\n return jsonError('Token bulunamadı', 401);\r\n }\r\n \r\n if (isProtectedRoute(req.nextUrl.pathname)) {\r\n return NextResponse.redirect(new URL('/login', origin));\r\n }\r\n \r\n return NextResponse.next();\r\n }\r\n\r\n /**\r\n * Handles token validation result\r\n */\r\n async function handleValidationResult(\r\n req: NextRequest,\r\n tokenInfo: TokenInfo,\r\n isUserToken: boolean,\r\n currentToken: string,\r\n isApiRoute: boolean\r\n ): Promise<NextResponse> {\r\n const { pathname, origin } = req.nextUrl;\r\n const { isValid, tokenType, userData } = tokenInfo;\r\n const isGuest = tokenType === TOKEN_TYPES.GUEST;\r\n\r\n // ===== TOKEN INVALID =====\r\n if (!isValid) {\r\n // Try refresh if user token\r\n if (isUserToken && currentToken) {\r\n const refreshResult = await validation.refreshToken(currentToken);\r\n \r\n if (refreshResult.success && refreshResult.newToken) {\r\n const newTokenInfo = await validation.getTokenInfo(refreshResult.newToken);\r\n \r\n if (newTokenInfo.isValid) {\r\n // Successful refresh\r\n const requestHeaders = new Headers(req.headers);\r\n \r\n if (newTokenInfo.userData) {\r\n requestHeaders.set(HEADERS.AUTH_USER, JSON.stringify(newTokenInfo.userData));\r\n }\r\n requestHeaders.set(HEADERS.REFRESHED_TOKEN, refreshResult.newToken);\r\n \r\n // Set locale header if i18n is enabled\r\n const locale = extractLocale(pathname, i18n);\r\n if (locale) {\r\n requestHeaders.set(HEADERS.LOCALE, locale);\r\n }\r\n\r\n let response: NextResponse;\r\n \r\n if (isAuthPage(pathname)) {\r\n response = NextResponse.redirect(new URL('/', origin));\r\n } else {\r\n response = NextResponse.next({ request: { headers: requestHeaders } });\r\n }\r\n\r\n response.cookies.set(cookies.user, refreshResult.newToken, {\r\n ...cookieOptions,\r\n maxAge: cookieOptions.maxAge,\r\n });\r\n safeDeleteCookie(req, response, cookies.guest);\r\n\r\n return response;\r\n }\r\n }\r\n }\r\n\r\n // Refresh failed or no user token - handle as no token\r\n const response = await handleNoToken(req, isApiRoute);\r\n \r\n // Check if handleNoToken created a new guest token\r\n const hasNewGuestToken = response.cookies.get(cookies.guest)?.value;\r\n \r\n if (!hasNewGuestToken) {\r\n // No new guest token created - delete all auth cookies\r\n deleteAllAuthCookies(req, response);\r\n } else {\r\n // New guest token created - only delete the invalid user cookie\r\n safeDeleteCookie(req, response, cookies.user);\r\n }\r\n \r\n return response;\r\n }\r\n\r\n // ===== TOKEN VALID =====\r\n const requestHeaders = new Headers(req.headers);\r\n \r\n if (userData) {\r\n requestHeaders.set(HEADERS.AUTH_USER, JSON.stringify(userData));\r\n }\r\n \r\n // Set locale header if i18n is enabled\r\n const locale = extractLocale(pathname, i18n);\r\n if (locale) {\r\n requestHeaders.set(HEADERS.LOCALE, locale);\r\n }\r\n\r\n // Check if token type is allowed\r\n if (!isGuest && !isTokenTypeAllowed(tokenType)) {\r\n if (isApiRoute) {\r\n const response = jsonError('Bu işlem için yetkiniz yok', 403);\r\n return deleteAllAuthCookies(req, response);\r\n }\r\n \r\n const response = NextResponse.redirect(new URL('/login', origin));\r\n return deleteAllAuthCookies(req, response);\r\n }\r\n\r\n // Guest token handling\r\n if (isGuest) {\r\n if (isApiRoute) {\r\n return NextResponse.next({ request: { headers: requestHeaders } });\r\n }\r\n\r\n // Protected routes require login\r\n if (isProtectedRoute(pathname)) {\r\n return NextResponse.redirect(new URL('/login', origin));\r\n }\r\n\r\n return NextResponse.next({ request: { headers: requestHeaders } });\r\n }\r\n\r\n // User token - block auth pages\r\n if (isAuthPage(pathname)) {\r\n return NextResponse.redirect(new URL('/', origin));\r\n }\r\n\r\n // Normal access\r\n const response = NextResponse.next({ request: { headers: requestHeaders } });\r\n safeDeleteCookie(req, response, cookies.guest);\r\n \r\n return response;\r\n }\r\n\r\n return {\r\n deleteAllAuthCookies,\r\n jsonError,\r\n isAuthPage,\r\n isProtectedRoute,\r\n isPublicRoute,\r\n isTokenTypeAllowed,\r\n handleNoToken,\r\n handleValidationResult,\r\n };\r\n}\r\n\r\nexport type Handlers = ReturnType<typeof createHandlers>;\r\n","/**\r\n * CSRF Protection\r\n * \r\n * Implements OWASP recommended CSRF protection:\r\n * - Fetch Metadata (Sec-Fetch-Site header) for modern browsers (98%+ coverage)\r\n * - Signed HMAC Double-Submit Cookie as fallback\r\n * \r\n * @see https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html\r\n */\r\n\r\nimport { NextRequest, NextResponse } from 'next/server';\r\nimport type { ResolvedCsrfConfig } from '../shared/types';\r\n\r\nexport interface CsrfValidationResult {\r\n valid: boolean;\r\n reason?: string;\r\n}\r\n\r\n/**\r\n * Creates CSRF validator functions\r\n */\r\nexport function createCsrfValidator(config: ResolvedCsrfConfig) {\r\n /**\r\n * Generate HMAC-signed CSRF token\r\n * Format: hmac.randomValue\r\n */\r\n async function generateToken(sessionId: string): Promise<string> {\r\n const randomValue = generateRandomValue();\r\n const hmac = await computeHmac(config.secret, sessionId, randomValue);\r\n return `${hmac}.${randomValue}`;\r\n }\r\n\r\n /**\r\n * Validate CSRF request using configured strategy\r\n */\r\n function validateRequest(req: NextRequest): CsrfValidationResult {\r\n const method = req.method.toUpperCase();\r\n \r\n // Skip safe methods\r\n if (config.ignoreMethods.includes(method)) {\r\n return { valid: true };\r\n }\r\n\r\n const strategy = config.strategy;\r\n \r\n // Fetch Metadata validation (primary, modern browsers)\r\n if (strategy === 'fetch-metadata' || strategy === 'both') {\r\n const fetchResult = validateFetchMetadata(req);\r\n \r\n if (strategy === 'fetch-metadata') {\r\n return fetchResult;\r\n }\r\n \r\n // 'both' strategy: if Fetch Metadata passes, we're good\r\n if (fetchResult.valid) {\r\n return fetchResult;\r\n }\r\n \r\n // 'both' strategy: if Fetch Metadata fails or not available, try double-submit\r\n if (fetchResult.reason === 'missing-headers') {\r\n // Fall through to double-submit\r\n } else {\r\n // Explicit cross-site rejection from Fetch Metadata\r\n return fetchResult;\r\n }\r\n }\r\n\r\n // Double-Submit Cookie validation (fallback)\r\n if (strategy === 'double-submit' || strategy === 'both') {\r\n return validateDoubleSubmit(req);\r\n }\r\n\r\n return { valid: true };\r\n }\r\n\r\n /**\r\n * Validate using Fetch Metadata headers (Sec-Fetch-Site)\r\n * @see https://web.dev/fetch-metadata/\r\n */\r\n function validateFetchMetadata(req: NextRequest): CsrfValidationResult {\r\n const secFetchSite = req.headers.get('sec-fetch-site');\r\n \r\n // No Fetch Metadata headers (older browser or stripped by proxy)\r\n if (!secFetchSite) {\r\n return { valid: false, reason: 'missing-headers' };\r\n }\r\n\r\n // Same-origin requests are always trusted\r\n if (secFetchSite === 'same-origin') {\r\n return { valid: true };\r\n }\r\n\r\n // None = direct navigation (bookmark, typed URL) - allow for GET\r\n if (secFetchSite === 'none') {\r\n const method = req.method.toUpperCase();\r\n if (config.ignoreMethods.includes(method)) {\r\n return { valid: true };\r\n }\r\n // Non-safe method from direct navigation is suspicious\r\n return { valid: false, reason: 'direct-navigation-unsafe-method' };\r\n }\r\n\r\n // Same-site: trust based on config\r\n if (secFetchSite === 'same-site') {\r\n if (config.trustSameSite) {\r\n return { valid: true };\r\n }\r\n // Conservative: don't trust same-site by default (subdomain takeover risk)\r\n return { valid: false, reason: 'same-site-not-trusted' };\r\n }\r\n\r\n // Cross-site: reject state-changing requests\r\n if (secFetchSite === 'cross-site') {\r\n return { valid: false, reason: 'cross-site-request' };\r\n }\r\n\r\n // Unknown value - be conservative\r\n return { valid: false, reason: 'unknown-sec-fetch-site' };\r\n }\r\n\r\n /**\r\n * Validate using Double-Submit Cookie pattern with HMAC\r\n */\r\n function validateDoubleSubmit(req: NextRequest): CsrfValidationResult {\r\n // Get token from cookie\r\n const cookieToken = req.cookies.get(config.cookieName)?.value;\r\n \r\n if (!cookieToken) {\r\n return { valid: false, reason: 'missing-cookie-token' };\r\n }\r\n\r\n // Get token from header (or form field)\r\n const headerToken = req.headers.get(config.headerName);\r\n \r\n if (!headerToken) {\r\n return { valid: false, reason: 'missing-header-token' };\r\n }\r\n\r\n // Tokens must match (constant-time comparison to prevent timing attacks)\r\n if (!constantTimeEqual(cookieToken, headerToken)) {\r\n return { valid: false, reason: 'token-mismatch' };\r\n }\r\n\r\n // Validate HMAC structure\r\n const parts = cookieToken.split('.');\r\n if (parts.length !== 2) {\r\n return { valid: false, reason: 'invalid-token-format' };\r\n }\r\n\r\n return { valid: true };\r\n }\r\n\r\n /**\r\n * Create response with CSRF cookie set\r\n */\r\n async function attachCsrfCookie(\r\n response: NextResponse, \r\n sessionId: string\r\n ): Promise<NextResponse> {\r\n const token = await generateToken(sessionId);\r\n \r\n response.cookies.set(config.cookieName, token, {\r\n httpOnly: false, // Must be readable by JS\r\n secure: process.env.NODE_ENV === 'production',\r\n sameSite: 'strict',\r\n path: '/',\r\n });\r\n\r\n return response;\r\n }\r\n\r\n return {\r\n validateRequest,\r\n generateToken,\r\n attachCsrfCookie,\r\n };\r\n}\r\n\r\n// ==================== Helper Functions ====================\r\n\r\n/**\r\n * Generate cryptographically random value\r\n */\r\nfunction generateRandomValue(): string {\r\n if (typeof crypto !== 'undefined' && crypto.getRandomValues) {\r\n const array = new Uint8Array(32);\r\n crypto.getRandomValues(array);\r\n return Array.from(array, b => b.toString(16).padStart(2, '0')).join('');\r\n }\r\n // Fallback (less secure, for edge cases)\r\n return Math.random().toString(36).substring(2) + Date.now().toString(36);\r\n}\r\n\r\n/**\r\n * Compute HMAC-SHA256\r\n */\r\nasync function computeHmac(\r\n secret: string, \r\n sessionId: string, \r\n randomValue: string\r\n): Promise<string> {\r\n const message = `${sessionId.length}!${sessionId}!${randomValue.length}!${randomValue}`;\r\n \r\n if (typeof crypto !== 'undefined' && crypto.subtle) {\r\n const encoder = new TextEncoder();\r\n const keyData = encoder.encode(secret);\r\n const messageData = encoder.encode(message);\r\n \r\n const key = await crypto.subtle.importKey(\r\n 'raw',\r\n keyData,\r\n { name: 'HMAC', hash: 'SHA-256' },\r\n false,\r\n ['sign']\r\n );\r\n \r\n const signature = await crypto.subtle.sign('HMAC', key, messageData);\r\n return Array.from(new Uint8Array(signature), b => \r\n b.toString(16).padStart(2, '0')\r\n ).join('');\r\n }\r\n \r\n // Fallback (less secure)\r\n let hash = 0;\r\n const str = secret + message;\r\n for (let i = 0; i < str.length; i++) {\r\n const char = str.charCodeAt(i);\r\n hash = ((hash << 5) - hash) + char;\r\n hash = hash & hash;\r\n }\r\n return Math.abs(hash).toString(16);\r\n}\r\n\r\n/**\r\n * Constant-time string comparison (prevents timing attacks)\r\n */\r\nfunction constantTimeEqual(a: string, b: string): boolean {\r\n if (a.length !== b.length) {\r\n return false;\r\n }\r\n \r\n let result = 0;\r\n for (let i = 0; i < a.length; i++) {\r\n result |= a.charCodeAt(i) ^ b.charCodeAt(i);\r\n }\r\n \r\n return result === 0;\r\n}\r\n\r\nexport type CsrfValidator = ReturnType<typeof createCsrfValidator>;\r\n","/**\r\n * Rate Limiting\r\n * \r\n * Implements token bucket algorithm for rate limiting.\r\n * In-memory store by default, designed for single-instance deployments.\r\n * \r\n * For horizontal scaling (multiple instances), use a custom store\r\n * with Redis or similar distributed cache.\r\n */\r\n\r\nimport { NextRequest, NextResponse } from 'next/server';\r\nimport type { ResolvedRateLimitConfig } from '../shared/types';\r\n\r\ninterface RateLimitEntry {\r\n count: number;\r\n resetAt: number;\r\n}\r\n\r\nexport interface RateLimitResult {\r\n allowed: boolean;\r\n remaining: number;\r\n resetAt: number;\r\n limit: number;\r\n}\r\n\r\n/**\r\n * Creates a rate limiter with in-memory store\r\n */\r\nexport function createRateLimiter(config: ResolvedRateLimitConfig) {\r\n // In-memory store\r\n const store = new Map<string, RateLimitEntry>();\r\n \r\n // Cleanup expired entries periodically\r\n const cleanupInterval = setInterval(() => {\r\n const now = Date.now();\r\n for (const [key, entry] of store) {\r\n if (entry.resetAt <= now) {\r\n store.delete(key);\r\n }\r\n }\r\n }, config.windowMs);\r\n\r\n // Prevent memory leak in long-running processes\r\n if (typeof process !== 'undefined' && process.on) {\r\n process.on('beforeExit', () => clearInterval(cleanupInterval));\r\n }\r\n\r\n /**\r\n * Check if route should skip rate limiting\r\n */\r\n function shouldSkip(pathname: string): boolean {\r\n return config.skipRoutes.some(pattern => {\r\n // Simple glob matching\r\n if (pattern.endsWith('*')) {\r\n return pathname.startsWith(pattern.slice(0, -1));\r\n }\r\n if (pattern.endsWith('**')) {\r\n return pathname.startsWith(pattern.slice(0, -2));\r\n }\r\n return pathname === pattern;\r\n });\r\n }\r\n\r\n /**\r\n * Check rate limit for request\r\n */\r\n function check(req: NextRequest): RateLimitResult {\r\n const pathname = req.nextUrl.pathname;\r\n \r\n // Skip if route matches skip patterns\r\n if (shouldSkip(pathname)) {\r\n return {\r\n allowed: true,\r\n remaining: config.maxRequests,\r\n resetAt: 0,\r\n limit: config.maxRequests,\r\n };\r\n }\r\n\r\n const key = config.keyFn(req);\r\n const now = Date.now();\r\n \r\n let entry = store.get(key);\r\n \r\n // New window or expired\r\n if (!entry || entry.resetAt <= now) {\r\n entry = {\r\n count: 1,\r\n resetAt: now + config.windowMs,\r\n };\r\n store.set(key, entry);\r\n \r\n return {\r\n allowed: true,\r\n remaining: config.maxRequests - 1,\r\n resetAt: entry.resetAt,\r\n limit: config.maxRequests,\r\n };\r\n }\r\n\r\n // Existing window\r\n entry.count++;\r\n \r\n const remaining = Math.max(0, config.maxRequests - entry.count);\r\n const allowed = entry.count <= config.maxRequests;\r\n \r\n return {\r\n allowed,\r\n remaining,\r\n resetAt: entry.resetAt,\r\n limit: config.maxRequests,\r\n };\r\n }\r\n\r\n /**\r\n * Apply rate limit headers to response\r\n */\r\n function applyHeaders(response: NextResponse, result: RateLimitResult): NextResponse {\r\n response.headers.set('X-RateLimit-Limit', result.limit.toString());\r\n response.headers.set('X-RateLimit-Remaining', result.remaining.toString());\r\n response.headers.set('X-RateLimit-Reset', Math.ceil(result.resetAt / 1000).toString());\r\n return response;\r\n }\r\n\r\n /**\r\n * Create rate limited response (429 Too Many Requests)\r\n */\r\n function createLimitedResponse(req: NextRequest, result: RateLimitResult): NextResponse {\r\n // User-provided handler\r\n if (config.onRateLimited) {\r\n const response = config.onRateLimited(req);\r\n return applyHeaders(response, result);\r\n }\r\n\r\n // Default response\r\n const response = NextResponse.json(\r\n {\r\n success: false,\r\n message: 'Too many requests. Please try again later.',\r\n retryAfter: Math.ceil((result.resetAt - Date.now()) / 1000),\r\n },\r\n { status: 429 }\r\n );\r\n\r\n response.headers.set('Retry-After', Math.ceil((result.resetAt - Date.now()) / 1000).toString());\r\n return applyHeaders(response, result);\r\n }\r\n\r\n /**\r\n * Reset rate limit for a key (useful for testing)\r\n */\r\n function reset(key: string): void {\r\n store.delete(key);\r\n }\r\n\r\n /**\r\n * Clear all rate limit entries\r\n */\r\n function clear(): void {\r\n store.clear();\r\n }\r\n\r\n /**\r\n * Get current store size (for monitoring)\r\n */\r\n function size(): number {\r\n return store.size;\r\n }\r\n\r\n return {\r\n check,\r\n applyHeaders,\r\n createLimitedResponse,\r\n shouldSkip,\r\n reset,\r\n clear,\r\n size,\r\n };\r\n}\r\n\r\nexport type RateLimiter = ReturnType<typeof createRateLimiter>;\r\n","/**\r\n * Audit Logging\r\n * \r\n * Event-based security audit logging system.\r\n * Emits events for authentication, access control, and security violations.\r\n */\r\n\r\nimport { NextRequest } from 'next/server';\r\nimport type { ResolvedAuditConfig, AuditEvent, AuditEventType } from '../shared/types';\r\n\r\n/**\r\n * Creates an audit logger instance\r\n */\r\nexport function createAuditLogger(config: ResolvedAuditConfig) {\r\n /**\r\n * Check if event type is enabled\r\n */\r\n function isEnabled(type: AuditEventType): boolean {\r\n return config.enabled && config.events.includes(type);\r\n }\r\n\r\n /**\r\n * Extract IP address from request\r\n */\r\n function getIp(req: NextRequest): string | null {\r\n return (\r\n req.headers.get('x-forwarded-for')?.split(',')[0]?.trim() ||\r\n req.headers.get('x-real-ip') ||\r\n null\r\n );\r\n }\r\n\r\n /**\r\n * Emit an audit event\r\n */\r\n async function emit(\r\n type: AuditEventType,\r\n req: NextRequest,\r\n options: {\r\n success: boolean;\r\n userId?: string;\r\n metadata?: Record<string, unknown>;\r\n }\r\n ): Promise<void> {\r\n if (!isEnabled(type)) {\r\n return;\r\n }\r\n\r\n const event: AuditEvent = {\r\n type,\r\n timestamp: new Date(),\r\n ip: getIp(req),\r\n userId: options.userId,\r\n path: req.nextUrl.pathname,\r\n method: req.method,\r\n success: options.success,\r\n metadata: options.metadata,\r\n };\r\n\r\n // Call user's logger\r\n if (config.logger) {\r\n try {\r\n await config.logger(event);\r\n } catch (error) {\r\n // Silently fail - don't break the request flow for logging errors\r\n console.error('[next-api-layer] Audit logger error:', error);\r\n }\r\n }\r\n }\r\n\r\n // ==================== Convenience Methods ====================\r\n\r\n /**\r\n * Log successful authentication\r\n */\r\n function authSuccess(req: NextRequest, userId?: string, metadata?: Record<string, unknown>) {\r\n return emit('auth:success', req, { success: true, userId, metadata });\r\n }\r\n\r\n /**\r\n * Log failed authentication\r\n */\r\n function authFail(req: NextRequest, metadata?: Record<string, unknown>) {\r\n return emit('auth:fail', req, { success: false, metadata });\r\n }\r\n\r\n /**\r\n * Log token refresh\r\n */\r\n function authRefresh(req: NextRequest, userId?: string, metadata?: Record<string, unknown>) {\r\n return emit('auth:refresh', req, { success: true, userId, metadata });\r\n }\r\n\r\n /**\r\n * Log guest token creation\r\n */\r\n function authGuest(req: NextRequest, metadata?: Record<string, unknown>) {\r\n return emit('auth:guest', req, { success: true, metadata });\r\n }\r\n\r\n /**\r\n * Log access denied\r\n */\r\n function accessDenied(req: NextRequest, userId?: string, metadata?: Record<string, unknown>) {\r\n return emit('access:denied', req, { success: false, userId, metadata });\r\n }\r\n\r\n /**\r\n * Log CSRF validation failure\r\n */\r\n function csrfFail(req: NextRequest, metadata?: Record<string, unknown>) {\r\n return emit('csrf:fail', req, { success: false, metadata });\r\n }\r\n\r\n /**\r\n * Log rate limit exceeded\r\n */\r\n function rateLimitExceeded(req: NextRequest, metadata?: Record<string, unknown>) {\r\n return emit('rateLimit:exceeded', req, { success: false, metadata });\r\n }\r\n\r\n /**\r\n * Log general error\r\n */\r\n function error(req: NextRequest, err: Error, metadata?: Record<string, unknown>) {\r\n return emit('error', req, { \r\n success: false, \r\n metadata: { \r\n ...metadata, \r\n error: err.message,\r\n stack: err.stack,\r\n } \r\n });\r\n }\r\n\r\n return {\r\n emit,\r\n isEnabled,\r\n // Convenience methods\r\n authSuccess,\r\n authFail,\r\n authRefresh,\r\n authGuest,\r\n accessDenied,\r\n csrfFail,\r\n rateLimitExceeded,\r\n error,\r\n };\r\n}\r\n\r\nexport type AuditLogger = ReturnType<typeof createAuditLogger>;\r\n","/**\r\n * createAuthProxy\r\n * Factory function to create Next.js middleware for external JWT authentication\r\n */\r\n\r\nimport { NextRequest, NextResponse } from 'next/server';\r\nimport type { AuthProxyConfig, AuthResult } from '../shared/types';\r\nimport { resolveProxyConfig } from '../shared/config';\r\nimport { createTokenValidation } from './tokenValidation';\r\nimport { createHandlers } from './handlers';\r\nimport { createCsrfValidator } from './csrf';\r\nimport { createRateLimiter } from './rateLimit';\r\nimport { createAuditLogger } from './audit';\r\n\r\n/**\r\n * Creates an authentication proxy middleware for Next.js\r\n * \r\n * @example\r\n * ```ts\r\n * // middleware.ts\r\n * import { createAuthProxy } from 'next-api-layer';\r\n * \r\n * const authProxy = createAuthProxy({\r\n * apiBaseUrl: process.env.API_BASE_URL!,\r\n * cookies: {\r\n * user: 'userAuthToken',\r\n * guest: 'guestAuthToken',\r\n * },\r\n * guestToken: {\r\n * enabled: true,\r\n * credentials: {\r\n * username: process.env.GUEST_USERNAME!,\r\n * password: process.env.GUEST_PASSWORD!,\r\n * },\r\n * },\r\n * access: {\r\n * protectedRoutes: ['/dashboard', '/profile'],\r\n * authRoutes: ['/login', '/register'],\r\n * },\r\n * // Security features\r\n * csrf: { enabled: true },\r\n * rateLimit: { enabled: true, maxRequests: 100 },\r\n * audit: { \r\n * enabled: true, \r\n * logger: (event) => console.log('[AUDIT]', event) \r\n * },\r\n * });\r\n * \r\n * export default authProxy;\r\n * \r\n * export const config = {\r\n * matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],\r\n * };\r\n * ```\r\n */\r\nexport function createAuthProxy(userConfig: AuthProxyConfig) {\r\n // Resolve config with defaults\r\n const config = resolveProxyConfig(userConfig);\r\n \r\n // Create validation functions\r\n const validation = createTokenValidation(config);\r\n \r\n // Create handlers\r\n const handlers = createHandlers(config, validation);\r\n\r\n // Create security modules\r\n const csrf = createCsrfValidator(config._resolved.csrf);\r\n const rateLimiter = createRateLimiter(config._resolved.rateLimit);\r\n const audit = createAuditLogger(config._resolved.audit);\r\n\r\n /**\r\n * The middleware function\r\n */\r\n async function authProxy(req: NextRequest): Promise<NextResponse> {\r\n const { pathname, origin } = req.nextUrl;\r\n const isApiRoute = pathname.startsWith('/api');\r\n\r\n // ============ Rate Limiting ============\r\n // Check early to protect against DoS\r\n if (config._resolved.rateLimit.enabled) {\r\n const rateLimitResult = rateLimiter.check(req);\r\n \r\n if (!rateLimitResult.allowed) {\r\n await audit.rateLimitExceeded(req, { \r\n limit: rateLimitResult.limit,\r\n resetAt: rateLimitResult.resetAt,\r\n });\r\n return rateLimiter.createLimitedResponse(req, rateLimitResult);\r\n }\r\n }\r\n\r\n // ============ CSRF Protection ============\r\n // Check before any state-changing operations\r\n if (config._resolved.csrf.enabled) {\r\n const csrfResult = csrf.validateRequest(req);\r\n \r\n if (!csrfResult.valid) {\r\n await audit.csrfFail(req, { reason: csrfResult.reason });\r\n return NextResponse.json(\r\n { success: false, message: 'CSRF validation failed' },\r\n { status: 403 }\r\n );\r\n }\r\n }\r\n\r\n // ============ Block Browser API Access ============\r\n // Prevents direct browser access to API routes (when Accept: text/html)\r\n if (config.blockBrowserApiAccess && isApiRoute) {\r\n const acceptHeader = req.headers.get('accept') || '';\r\n if (acceptHeader.includes('text/html')) {\r\n return NextResponse.redirect(new URL('/', origin));\r\n }\r\n }\r\n\r\n // ============ beforeAuth Hook ============\r\n // Allows user to handle request before auth validation\r\n if (config.beforeAuth) {\r\n const beforeResult = await config.beforeAuth(req);\r\n if (beforeResult) {\r\n return beforeResult; // User handled the request\r\n }\r\n }\r\n\r\n // Skip excluded paths\r\n const excludedPaths = config.excludedPaths ?? [];\r\n if (excludedPaths.some(path => pathname.startsWith(path))) {\r\n return applyAfterAuth(req, NextResponse.next(), { isAuthenticated: false, isGuest: false, tokenType: null, user: null });\r\n }\r\n\r\n // Skip auth API endpoints (they handle their own auth)\r\n const authApiPaths = [\r\n '/api/auth/login',\r\n '/api/auth/logout',\r\n '/api/auth/me',\r\n '/api/auth/refresh',\r\n '/api/auth/register',\r\n ];\r\n \r\n if (authApiPaths.includes(pathname)) {\r\n return applyAfterAuth(req, NextResponse.next(), { isAuthenticated: false, isGuest: false, tokenType: null, user: null });\r\n }\r\n\r\n // Get tokens from cookies\r\n const userToken = req.cookies?.get(config.cookies.user)?.value;\r\n const guestToken = req.cookies?.get(config.cookies.guest)?.value;\r\n const currentToken = userToken || guestToken;\r\n const isUserToken = !!userToken;\r\n\r\n // No token - handle appropriately\r\n if (!currentToken) {\r\n await audit.authFail(req, { reason: 'no-token' });\r\n const response = await handlers.handleNoToken(req, isApiRoute);\r\n return applyAfterAuth(req, response, { isAuthenticated: false, isGuest: false, tokenType: null, user: null });\r\n }\r\n\r\n // Validate token\r\n const tokenInfo = await validation.getTokenInfo(currentToken);\r\n \r\n // Build auth result for afterAuth hook\r\n const authResult: AuthResult = {\r\n isAuthenticated: tokenInfo.isValid && tokenInfo.tokenType !== 'guest',\r\n isGuest: tokenInfo.isValid && tokenInfo.tokenType === 'guest',\r\n tokenType: tokenInfo.tokenType,\r\n user: tokenInfo.userData,\r\n };\r\n\r\n // Audit logging based on validation result \r\n if (tokenInfo.isValid) {\r\n if (tokenInfo.tokenType === 'guest') {\r\n await audit.authGuest(req);\r\n } else {\r\n const userId = tokenInfo.userData?.id?.toString();\r\n await audit.authSuccess(req, userId, { tokenType: tokenInfo.tokenType });\r\n }\r\n } else {\r\n await audit.authFail(req, { reason: 'invalid-token' });\r\n }\r\n\r\n // Handle validation result\r\n const response = await handlers.handleValidationResult(\r\n req,\r\n tokenInfo,\r\n isUserToken,\r\n currentToken,\r\n isApiRoute\r\n );\r\n \r\n // Apply CSRF cookie if enabled (for authenticated requests)\r\n let finalResponse = await applyAfterAuth(req, response, authResult);\r\n \r\n if (config._resolved.csrf.enabled && authResult.isAuthenticated) {\r\n const sessionId = tokenInfo.userData?.id?.toString() || currentToken.slice(0, 32);\r\n finalResponse = await csrf.attachCsrfCookie(finalResponse, sessionId);\r\n }\r\n\r\n // Apply rate limit headers\r\n if (config._resolved.rateLimit.enabled) {\r\n const rateLimitResult = rateLimiter.check(req);\r\n finalResponse = rateLimiter.applyHeaders(finalResponse, rateLimitResult);\r\n }\r\n \r\n return finalResponse;\r\n }\r\n \r\n /**\r\n * Helper to apply afterAuth hook\r\n */\r\n async function applyAfterAuth(req: NextRequest, response: NextResponse, authResult: AuthResult): Promise<NextResponse> {\r\n if (config.afterAuth) {\r\n return config.afterAuth(req, response, authResult);\r\n }\r\n return response;\r\n }\r\n\r\n // Attach instances for debugging/testing\r\n authProxy.config = config;\r\n authProxy.csrf = csrf;\r\n authProxy.rateLimiter = rateLimiter;\r\n authProxy.audit = audit;\r\n\r\n return authProxy;\r\n}\r\n\r\nexport type AuthProxy = ReturnType<typeof createAuthProxy>;\r\n","/**\r\n * createProxyHandler\r\n * Factory function to create Next.js API route handlers that proxy requests to backend\r\n */\r\n\r\nimport { NextRequest, NextResponse } from 'next/server';\r\nimport { HEADERS } from '../shared/constants';\r\n\r\nexport interface ProxyHandlerConfig {\r\n /** Base URL of the backend API */\r\n apiBaseUrl: string;\r\n /** Cookie name for user auth token */\r\n userCookieName?: string;\r\n /** Cookie name for guest auth token */\r\n guestCookieName?: string;\r\n /** \r\n * Default behavior for auth - if true, all requests skip auth by default\r\n * Individual requests can override with X-Skip-Auth header\r\n */\r\n skipAuthByDefault?: boolean;\r\n /**\r\n * Public endpoints that should never include auth token (glob patterns)\r\n * e.g., ['news/*', 'public/**', 'categories']\r\n */\r\n publicEndpoints?: string[];\r\n /** Headers to forward from client request */\r\n forwardHeaders?: string[];\r\n /** Headers to exclude from forwarding */\r\n excludeHeaders?: string[];\r\n /** Custom request transformer */\r\n transformRequest?: (req: NextRequest, headers: Headers) => Headers | Promise<Headers>;\r\n /** Custom response transformer */\r\n transformResponse?: (response: Response) => Response | Promise<Response>;\r\n}\r\n\r\n/**\r\n * Check if endpoint matches any patterns (glob support)\r\n */\r\nfunction matchesPattern(endpoint: string, patterns: string[]): boolean {\r\n if (!patterns || patterns.length === 0) return false;\r\n \r\n // Normalize endpoint\r\n const normalizedEndpoint = endpoint\r\n .replace(/^\\/api\\//, '')\r\n .replace(/^\\//, '');\r\n \r\n return patterns.some(pattern => {\r\n if (pattern === normalizedEndpoint) return true;\r\n \r\n if (pattern.includes('*')) {\r\n const regexPattern = pattern\r\n .replace(/\\*\\*/g, '<<<DOUBLE>>>')\r\n .replace(/\\*/g, '[^/]+')\r\n .replace(/<<<DOUBLE>>>/g, '.+');\r\n const regex = new RegExp(`^${regexPattern}$`);\r\n return regex.test(normalizedEndpoint);\r\n }\r\n \r\n return false;\r\n });\r\n}\r\n\r\n/**\r\n * Creates a proxy handler for Next.js API routes\r\n * \r\n * @example\r\n * ```ts\r\n * // app/api/[...path]/route.ts\r\n * import { createProxyHandler } from 'next-api-layer';\r\n * \r\n * const handler = createProxyHandler({\r\n * apiBaseUrl: process.env.API_BASE_URL!,\r\n * userCookieName: 'auth_token',\r\n * guestCookieName: 'guest_token',\r\n * publicEndpoints: ['news/*', 'categories', 'public/**'],\r\n * });\r\n * \r\n * export const GET = handler;\r\n * export const POST = handler;\r\n * export const PUT = handler;\r\n * export const PATCH = handler;\r\n * export const DELETE = handler;\r\n * ```\r\n */\r\nexport function createProxyHandler(config: ProxyHandlerConfig) {\r\n const {\r\n apiBaseUrl,\r\n userCookieName = 'auth_token',\r\n guestCookieName = 'guest_token',\r\n skipAuthByDefault = false,\r\n publicEndpoints = [],\r\n forwardHeaders = ['content-type', 'accept', 'accept-language', 'x-requested-with'],\r\n excludeHeaders = ['host', 'connection', 'cookie'],\r\n transformRequest,\r\n transformResponse,\r\n } = config;\r\n\r\n // Normalize base URL (remove trailing slash)\r\n const baseUrl = apiBaseUrl.replace(/\\/$/, '');\r\n\r\n /**\r\n * Determine if auth should be skipped for this request\r\n */\r\n function shouldSkipAuth(req: NextRequest, endpoint: string): boolean {\r\n // Check X-Skip-Auth header from client\r\n const skipAuthHeader = req.headers.get(HEADERS.SKIP_AUTH);\r\n if (skipAuthHeader === 'true') {\r\n return true;\r\n }\r\n \r\n // Check if endpoint matches public patterns\r\n if (matchesPattern(endpoint, publicEndpoints)) {\r\n return true;\r\n }\r\n \r\n // Default behavior\r\n return skipAuthByDefault;\r\n }\r\n\r\n /**\r\n * The proxy handler function\r\n */\r\n async function handler(req: NextRequest): Promise<NextResponse> {\r\n try {\r\n // Extract endpoint from URL path (remove /api/ prefix)\r\n const url = new URL(req.url);\r\n const endpoint = url.pathname.replace(/^\\/api\\/?/, '');\r\n \r\n // Build backend URL\r\n const backendUrl = new URL(`${baseUrl}/${endpoint}`);\r\n backendUrl.search = url.search; // Forward query params\r\n\r\n // Build headers for backend request\r\n const headers = new Headers();\r\n \r\n // Forward allowed headers from original request\r\n forwardHeaders.forEach(headerName => {\r\n const value = req.headers.get(headerName);\r\n if (value) {\r\n headers.set(headerName, value);\r\n }\r\n });\r\n\r\n // Forward all headers except excluded ones\r\n req.headers.forEach((value, key) => {\r\n const lowerKey = key.toLowerCase();\r\n if (!excludeHeaders.includes(lowerKey) && !headers.has(key)) {\r\n headers.set(key, value);\r\n }\r\n });\r\n\r\n // Add Authorization header if auth is not skipped\r\n if (!shouldSkipAuth(req, endpoint)) {\r\n const userToken = req.cookies.get(userCookieName)?.value;\r\n const guestToken = req.cookies.get(guestCookieName)?.value;\r\n const token = userToken || guestToken;\r\n \r\n if (token) {\r\n headers.set(HEADERS.AUTHORIZATION, `Bearer ${token}`);\r\n }\r\n }\r\n\r\n // Remove skip-auth header (internal use only)\r\n headers.delete(HEADERS.SKIP_AUTH);\r\n\r\n // Allow custom request transformation\r\n const finalHeaders = transformRequest \r\n ? await transformRequest(req, headers) \r\n : headers;\r\n\r\n // Get request body if present\r\n let body: BodyInit | null = null;\r\n if (req.method !== 'GET' && req.method !== 'HEAD') {\r\n const contentType = req.headers.get('content-type') || '';\r\n \r\n if (contentType.includes('application/json')) {\r\n body = await req.text();\r\n } else if (contentType.includes('multipart/form-data')) {\r\n body = await req.formData();\r\n } else {\r\n body = await req.text();\r\n }\r\n }\r\n\r\n // Make request to backend\r\n const backendResponse = await fetch(backendUrl.toString(), {\r\n method: req.method,\r\n headers: finalHeaders,\r\n body,\r\n });\r\n\r\n // Get response body\r\n const contentType = backendResponse.headers.get('content-type') || '';\r\n let responseBody: ArrayBuffer | string;\r\n \r\n if (contentType.includes('application/json')) {\r\n responseBody = await backendResponse.text();\r\n } else {\r\n responseBody = await backendResponse.arrayBuffer();\r\n }\r\n\r\n // Build response headers (forward relevant ones)\r\n const responseHeaders = new Headers();\r\n backendResponse.headers.forEach((value, key) => {\r\n const lowerKey = key.toLowerCase();\r\n // Skip hop-by-hop headers\r\n if (!['transfer-encoding', 'connection', 'keep-alive'].includes(lowerKey)) {\r\n responseHeaders.set(key, value);\r\n }\r\n });\r\n\r\n // Create response\r\n let response = new NextResponse(responseBody, {\r\n status: backendResponse.status,\r\n statusText: backendResponse.statusText,\r\n headers: responseHeaders,\r\n });\r\n\r\n // Allow custom response transformation\r\n if (transformResponse) {\r\n response = await transformResponse(response) as NextResponse;\r\n }\r\n\r\n return response;\r\n } catch (error) {\r\n console.error('[Proxy Error]', error);\r\n \r\n return NextResponse.json(\r\n { \r\n success: false, \r\n message: 'Proxy error: Unable to connect to backend',\r\n error: error instanceof Error ? error.message : 'Unknown error',\r\n },\r\n { status: 502 }\r\n );\r\n }\r\n }\r\n\r\n // Attach config for debugging\r\n handler.config = config;\r\n\r\n return handler;\r\n}\r\n\r\nexport type ProxyHandler = ReturnType<typeof createProxyHandler>;\r\n"]}
1
+ {"version":3,"sources":["../src/shared/config.ts","../src/proxy/tokenValidation.ts","../src/proxy/handlers.ts","../src/proxy/csrf.ts","../src/proxy/rateLimit.ts","../src/proxy/audit.ts","../src/proxy/createAuthProxy.ts","../src/proxy/createProxyHandler.ts"],"names":["generateCsrfSecret","defaultRateLimitKeyFn","req","resolveProxyConfig","config","apiBaseUrl","cookieOptions","DEFAULT_COOKIE_OPTIONS","endpoints","DEFAULT_ENDPOINTS","csrf","DEFAULT_CSRF_CONFIG","rateLimit","DEFAULT_RATE_LIMIT_CONFIG","audit","DEFAULT_AUDIT_CONFIG","defaultMappers","response","res","createTokenValidation","_resolved","responseMappers","mappers","validateToken","token","invalidResult","rawResponse","parsed","getTokenInfo","refreshToken","oldToken","newToken","createGuestToken","guestConfig","extractLocale","pathname","i18n","locales","defaultLocale","firstSegment","createHandlers","validation","cookies","guestToken","access","safeDeleteCookie","cookieName","deleteAllAuthCookies","jsonError","message","status","NextResponse","isAuthPage","route","isProtectedRoute","isPublicRoute","isTokenTypeAllowed","tokenType","allowedTypes","handleNoToken","isApiRoute","origin","guestAccessToken","handleValidationResult","tokenInfo","isUserToken","currentToken","isValid","userData","isGuest","TOKEN_TYPES","refreshResult","newTokenInfo","requestHeaders","HEADERS","locale","createCsrfValidator","generateToken","sessionId","randomValue","generateRandomValue","computeHmac","validateRequest","method","strategy","fetchResult","validateFetchMetadata","validateDoubleSubmit","secFetchSite","cookieToken","headerToken","constantTimeEqual","attachCsrfCookie","array","b","secret","encoder","keyData","messageData","key","signature","hash","str","i","char","a","result","createRateLimiter","store","cleanupInterval","now","entry","shouldSkip","pattern","check","remaining","applyHeaders","createLimitedResponse","reset","clear","size","createAuditLogger","isEnabled","type","getIp","emit","options","event","error","authSuccess","userId","metadata","authFail","authRefresh","authGuest","accessDenied","csrfFail","rateLimitExceeded","err","mergeResponses","source","target","criticalHeaders","header","value","cookie","createAuthProxy","userConfig","handlers","rateLimiter","authProxy","rateLimitResult","csrfResult","beforeResult","path","applyMiddlewaresAndHooks","userToken","authResult","finalResponse","intlResponse","hookResponse","matchesPattern","endpoint","patterns","normalizedEndpoint","regexPattern","createProxyHandler","userCookieName","guestCookieName","skipAuthByDefault","publicEndpoints","forwardHeaders","excludeHeaders","transformRequest","transformResponse","baseUrl","shouldSkipAuth","handler","url","backendUrl","headers","headerName","lowerKey","finalHeaders","body","contentType","backendResponse","responseBody","responseHeaders"],"mappings":"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","file":"index.js","sourcesContent":["/**\r\n * Config Resolver\r\n * Resolves and validates configuration with defaults\r\n */\r\n\r\nimport type { NextRequest } from 'next/server';\r\nimport type {\r\n AuthProxyConfig,\r\n InternalProxyConfig,\r\n ApiClientConfig,\r\n ResolvedCookieOptions,\r\n EndpointConfig,\r\n ResolvedCsrfConfig,\r\n ResolvedRateLimitConfig,\r\n ResolvedAuditConfig,\r\n AuditEventType,\r\n} from './types';\r\n\r\nimport {\r\n DEFAULT_COOKIE_OPTIONS,\r\n DEFAULT_ENDPOINTS,\r\n DEFAULT_CSRF_CONFIG,\r\n DEFAULT_RATE_LIMIT_CONFIG,\r\n DEFAULT_AUDIT_CONFIG,\r\n} from './constants';\r\n\r\n/**\r\n * Generates a random secret for CSRF HMAC signing\r\n */\r\nfunction generateCsrfSecret(): string {\r\n // Use crypto if available (Node.js)\r\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\r\n return crypto.randomUUID() + crypto.randomUUID();\r\n }\r\n // Fallback: timestamp + random\r\n return `${Date.now()}-${Math.random().toString(36).substring(2)}`;\r\n}\r\n\r\n/**\r\n * Default rate limit key function (IP-based)\r\n */\r\nfunction defaultRateLimitKeyFn(req: NextRequest): string {\r\n const forwarded = req.headers.get('x-forwarded-for');\r\n const ip = forwarded?.split(',')[0]?.trim() || \r\n req.headers.get('x-real-ip') || \r\n 'unknown';\r\n return `rl:${ip}`;\r\n}\r\n\r\n/**\r\n * Resolves proxy configuration with defaults\r\n */\r\nexport function resolveProxyConfig(config: AuthProxyConfig): InternalProxyConfig {\r\n // Validate required fields\r\n if (!config.apiBaseUrl) {\r\n throw new Error('next-api-layer: apiBaseUrl is required');\r\n }\r\n \r\n if (!config.cookies?.user || !config.cookies?.guest) {\r\n throw new Error('next-api-layer: cookies.user and cookies.guest are required');\r\n }\r\n\r\n // Ensure apiBaseUrl ends with /\r\n const apiBaseUrl = config.apiBaseUrl.endsWith('/')\r\n ? config.apiBaseUrl\r\n : `${config.apiBaseUrl}/`;\r\n\r\n // Resolve cookie options\r\n const cookieOptions: ResolvedCookieOptions = {\r\n ...DEFAULT_COOKIE_OPTIONS,\r\n ...config.cookies.options,\r\n };\r\n\r\n // Resolve endpoints\r\n const endpoints: Required<EndpointConfig> = {\r\n ...DEFAULT_ENDPOINTS,\r\n ...config.endpoints,\r\n };\r\n\r\n // Resolve CSRF config\r\n const csrf: ResolvedCsrfConfig = {\r\n enabled: config.csrf?.enabled ?? false,\r\n strategy: config.csrf?.strategy ?? DEFAULT_CSRF_CONFIG.strategy,\r\n secret: config.csrf?.secret ?? generateCsrfSecret(),\r\n cookieName: config.csrf?.cookieName ?? DEFAULT_CSRF_CONFIG.cookieName,\r\n headerName: config.csrf?.headerName ?? DEFAULT_CSRF_CONFIG.headerName,\r\n ignoreMethods: config.csrf?.ignoreMethods ?? DEFAULT_CSRF_CONFIG.ignoreMethods,\r\n trustSameSite: config.csrf?.trustSameSite ?? DEFAULT_CSRF_CONFIG.trustSameSite,\r\n };\r\n\r\n // Resolve rate limit config\r\n const rateLimit: ResolvedRateLimitConfig = {\r\n enabled: config.rateLimit?.enabled ?? false,\r\n windowMs: config.rateLimit?.windowMs ?? DEFAULT_RATE_LIMIT_CONFIG.windowMs,\r\n maxRequests: config.rateLimit?.maxRequests ?? DEFAULT_RATE_LIMIT_CONFIG.maxRequests,\r\n keyFn: config.rateLimit?.keyFn ?? defaultRateLimitKeyFn,\r\n skipRoutes: config.rateLimit?.skipRoutes ?? DEFAULT_RATE_LIMIT_CONFIG.skipRoutes,\r\n onRateLimited: config.rateLimit?.onRateLimited,\r\n };\r\n\r\n // Resolve audit config\r\n const audit: ResolvedAuditConfig = {\r\n enabled: config.audit?.enabled ?? false,\r\n events: config.audit?.events ?? [...DEFAULT_AUDIT_CONFIG.events] as AuditEventType[],\r\n logger: config.audit?.logger,\r\n };\r\n\r\n return {\r\n ...config,\r\n apiBaseUrl,\r\n _resolved: {\r\n cookieOptions,\r\n endpoints,\r\n csrf,\r\n rateLimit,\r\n audit,\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Resolves API client configuration with defaults\r\n */\r\nexport function resolveApiClientConfig(config: ApiClientConfig = {}) {\r\n return {\r\n sanitization: {\r\n enabled: config.sanitization?.enabled ?? true,\r\n allowedTags: config.sanitization?.allowedTags,\r\n skipFields: config.sanitization?.skipFields ?? [],\r\n skipEndpoints: config.sanitization?.skipEndpoints ?? [],\r\n },\r\n i18n: {\r\n enabled: config.i18n?.enabled ?? false,\r\n paramName: config.i18n?.paramName ?? 'lang',\r\n locales: config.i18n?.locales ?? [],\r\n defaultLocale: config.i18n?.defaultLocale ?? 'en',\r\n },\r\n auth: {\r\n skipByDefault: config.auth?.skipByDefault ?? false,\r\n publicEndpoints: config.auth?.publicEndpoints ?? [],\r\n },\r\n methodSpoofing: config.methodSpoofing ?? false,\r\n errorMessages: {\r\n noToken: config.errorMessages?.noToken ?? 'Token bulunamadı.',\r\n connectionError: config.errorMessages?.connectionError ?? 'Bağlantı hatası oluştu.',\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Type guard to check if a value is defined\r\n */\r\nexport function isDefined<T>(value: T | undefined | null): value is T {\r\n return value !== undefined && value !== null;\r\n}\r\n","/**\r\n * Token Validation\r\n * Handles token validation and refresh with backend API\r\n */\r\n\r\nimport type { \r\n TokenInfo, \r\n RefreshResult, \r\n AuthMeResponse, \r\n GuestTokenResponse,\r\n InternalProxyConfig,\r\n ResponseMappers,\r\n} from '../shared/types';\r\n\r\n/**\r\n * Default response parsers (standard format)\r\n */\r\nconst defaultMappers: Required<ResponseMappers> = {\r\n // Default: { success: true, data: { type, exp, ...user } }\r\n parseAuthMe: (response: unknown): TokenInfo | null => {\r\n const res = response as AuthMeResponse | null;\r\n if (!res?.success || !res?.data) {\r\n return null;\r\n }\r\n return {\r\n isValid: true,\r\n tokenType: res.data.type || 'user',\r\n exp: res.data.exp || null,\r\n userData: res.data,\r\n };\r\n },\r\n \r\n // Default: { success: true, data: { accessToken } }\r\n parseRefreshToken: (response: unknown): string | null => {\r\n const res = response as GuestTokenResponse | null;\r\n return res?.success && res?.data?.accessToken ? res.data.accessToken : null;\r\n },\r\n \r\n // Default: { success: true, data: { accessToken } }\r\n parseGuestToken: (response: unknown): string | null => {\r\n const res = response as GuestTokenResponse | null;\r\n return res?.data?.accessToken || null;\r\n },\r\n};\r\n\r\n/**\r\n * Creates token validation functions\r\n */\r\nexport function createTokenValidation(\r\n config: InternalProxyConfig\r\n) {\r\n const { apiBaseUrl, _resolved, responseMappers } = config;\r\n const { endpoints } = _resolved;\r\n \r\n // Merge custom mappers with defaults\r\n const mappers: Required<ResponseMappers> = {\r\n parseAuthMe: responseMappers?.parseAuthMe || defaultMappers.parseAuthMe,\r\n parseRefreshToken: responseMappers?.parseRefreshToken || defaultMappers.parseRefreshToken,\r\n parseGuestToken: responseMappers?.parseGuestToken || defaultMappers.parseGuestToken,\r\n };\r\n\r\n /**\r\n * Validates a token against the backend\r\n */\r\n async function validateToken(token: string): Promise<TokenInfo> {\r\n const invalidResult: TokenInfo = { isValid: false, tokenType: null, exp: null, userData: null };\r\n \r\n try {\r\n const res = await fetch(`${apiBaseUrl}${endpoints.validate}`, {\r\n headers: {\r\n 'Authorization': `Bearer ${token}`,\r\n 'Content-Type': 'application/json',\r\n },\r\n cache: 'no-store',\r\n });\r\n\r\n if (!res.ok) {\r\n return invalidResult;\r\n }\r\n\r\n const rawResponse: unknown = await res.json().catch(() => null);\r\n \r\n // Use custom or default mapper\r\n const parsed = mappers.parseAuthMe(rawResponse);\r\n \r\n if (!parsed || !parsed.isValid) {\r\n return invalidResult;\r\n }\r\n\r\n return parsed;\r\n } catch {\r\n return invalidResult;\r\n }\r\n }\r\n\r\n /**\r\n * Gets token info (validates with backend)\r\n */\r\n async function getTokenInfo(token: string): Promise<TokenInfo> {\r\n return validateToken(token);\r\n }\r\n\r\n /**\r\n * Refreshes a token\r\n */\r\n async function refreshToken(oldToken: string): Promise<RefreshResult> {\r\n try {\r\n const res = await fetch(`${apiBaseUrl}${endpoints.refresh}`, {\r\n method: 'POST',\r\n headers: {\r\n 'Authorization': `Bearer ${oldToken}`,\r\n 'Content-Type': 'application/json',\r\n },\r\n cache: 'no-store',\r\n });\r\n\r\n if (!res.ok) {\r\n return { success: false, newToken: null };\r\n }\r\n\r\n const rawResponse: unknown = await res.json().catch(() => null);\r\n \r\n // Use custom or default mapper\r\n const newToken = mappers.parseRefreshToken(rawResponse);\r\n\r\n if (!newToken) {\r\n return { success: false, newToken: null };\r\n }\r\n\r\n return { success: true, newToken };\r\n } catch {\r\n return { success: false, newToken: null };\r\n }\r\n }\r\n\r\n /**\r\n * Creates a guest token\r\n */\r\n async function createGuestToken(): Promise<string | null> {\r\n const guestConfig = config.guestToken;\r\n \r\n if (!guestConfig?.enabled || !guestConfig.credentials) {\r\n return null;\r\n }\r\n\r\n try {\r\n const res = await fetch(`${apiBaseUrl}${endpoints.guest}`, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({\r\n username: guestConfig.credentials.username,\r\n password: guestConfig.credentials.password,\r\n }),\r\n cache: 'no-store',\r\n });\r\n\r\n if (!res.ok) {\r\n return null;\r\n }\r\n\r\n const rawResponse: unknown = await res.json().catch(() => null);\r\n \r\n // Use custom or default mapper\r\n return mappers.parseGuestToken(rawResponse);\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n return {\r\n validateToken,\r\n getTokenInfo,\r\n refreshToken,\r\n createGuestToken,\r\n };\r\n}\r\n\r\nexport type TokenValidation = ReturnType<typeof createTokenValidation>;\r\n","/**\r\n * Proxy Handlers\r\n * Request handling logic for different scenarios\r\n */\r\n\r\nimport { NextRequest, NextResponse } from 'next/server';\r\nimport type { InternalProxyConfig, TokenInfo } from '../shared/types';\r\nimport { HEADERS, TOKEN_TYPES } from '../shared/constants';\r\nimport type { TokenValidation } from './tokenValidation';\r\n\r\n/**\r\n * Extracts locale from pathname based on i18n config\r\n * e.g., /en/dashboard → 'en', /dashboard → defaultLocale or null\r\n */\r\nfunction extractLocale(pathname: string, i18n?: InternalProxyConfig['i18n']): string | null {\r\n if (!i18n?.enabled) return null;\r\n \r\n const locales = i18n.locales ?? [];\r\n const defaultLocale = i18n.defaultLocale;\r\n \r\n // Extract first path segment\r\n const segments = pathname.split('/').filter(Boolean);\r\n const firstSegment = segments[0];\r\n \r\n // Check if it's a valid locale\r\n if (firstSegment && locales.includes(firstSegment)) {\r\n return firstSegment;\r\n }\r\n \r\n // Return default locale if provided\r\n return defaultLocale ?? null;\r\n}\r\n\r\n/**\r\n * Creates proxy handlers\r\n */\r\nexport function createHandlers(\r\n config: InternalProxyConfig,\r\n validation: TokenValidation\r\n) {\r\n const { cookies, guestToken, access, i18n, _resolved } = config;\r\n const { cookieOptions } = _resolved;\r\n\r\n /**\r\n * Safely deletes a cookie only if it exists in the request.\r\n * Prevents empty-value cookies from being created when deleting non-existent cookies.\r\n */\r\n function safeDeleteCookie(req: NextRequest, response: NextResponse, cookieName: string): void {\r\n if (req.cookies.get(cookieName)?.value) {\r\n response.cookies.delete(cookieName);\r\n }\r\n }\r\n\r\n /**\r\n * Deletes all auth cookies from response (only if they exist)\r\n */\r\n function deleteAllAuthCookies(req: NextRequest, response: NextResponse): NextResponse {\r\n safeDeleteCookie(req, response, cookies.guest);\r\n safeDeleteCookie(req, response, cookies.user);\r\n return response;\r\n }\r\n\r\n /**\r\n * Creates a JSON error response\r\n */\r\n function jsonError(message: string, status = 500): NextResponse {\r\n return new NextResponse(\r\n JSON.stringify({ success: false, message }),\r\n { status, headers: { 'Content-Type': 'application/json' } }\r\n );\r\n }\r\n\r\n /**\r\n * Checks if pathname is an auth page\r\n */\r\n function isAuthPage(pathname: string): boolean {\r\n const authRoutes = access?.authRoutes ?? [];\r\n return authRoutes.some(route => \r\n pathname === route || pathname.startsWith(`${route}/`)\r\n );\r\n }\r\n\r\n /**\r\n * Checks if pathname is a protected route\r\n */\r\n function isProtectedRoute(pathname: string): boolean {\r\n // If protectedByDefault is true, everything is protected except public/auth routes\r\n if (access?.protectedByDefault) {\r\n return !isPublicRoute(pathname) && !isAuthPage(pathname);\r\n }\r\n \r\n const protectedRoutes = access?.protectedRoutes ?? [];\r\n return protectedRoutes.some(route => \r\n pathname === route || pathname.startsWith(`${route}/`)\r\n );\r\n }\r\n\r\n /**\r\n * Checks if pathname is explicitly public\r\n */\r\n function isPublicRoute(pathname: string): boolean {\r\n const publicRoutes = access?.publicRoutes ?? [];\r\n return publicRoutes.some(route => \r\n pathname === route || pathname.startsWith(`${route}/`)\r\n );\r\n }\r\n\r\n /**\r\n * Checks if token type is allowed\r\n */\r\n function isTokenTypeAllowed(tokenType: string | null): boolean {\r\n const allowedTypes = access?.allowedTokenTypes;\r\n \r\n // If no restriction, all types allowed\r\n if (!allowedTypes || allowedTypes.length === 0) {\r\n return true;\r\n }\r\n \r\n return tokenType ? allowedTypes.includes(tokenType) : false;\r\n }\r\n\r\n /**\r\n * Handles request when no token is present\r\n */\r\n async function handleNoToken(\r\n req: NextRequest,\r\n isApiRoute: boolean\r\n ): Promise<NextResponse> {\r\n const { origin } = req.nextUrl;\r\n \r\n // Try to create guest token\r\n if (guestToken?.enabled) {\r\n const guestAccessToken = await validation.createGuestToken();\r\n \r\n if (guestAccessToken) {\r\n let response: NextResponse;\r\n \r\n if (isApiRoute) {\r\n response = NextResponse.next();\r\n } else if (isProtectedRoute(req.nextUrl.pathname)) {\r\n // Redirect to login if protected route\r\n response = NextResponse.redirect(new URL('/login', origin));\r\n } else {\r\n response = NextResponse.next();\r\n }\r\n \r\n response.cookies.set(cookies.guest, guestAccessToken, {\r\n ...cookieOptions,\r\n maxAge: 3600, // 1 hour default for guest tokens\r\n });\r\n \r\n return response;\r\n }\r\n }\r\n \r\n // No guest token - just continue or redirect\r\n if (isApiRoute) {\r\n return jsonError('Token bulunamadı', 401);\r\n }\r\n \r\n if (isProtectedRoute(req.nextUrl.pathname)) {\r\n return NextResponse.redirect(new URL('/login', origin));\r\n }\r\n \r\n return NextResponse.next();\r\n }\r\n\r\n /**\r\n * Handles token validation result\r\n */\r\n async function handleValidationResult(\r\n req: NextRequest,\r\n tokenInfo: TokenInfo,\r\n isUserToken: boolean,\r\n currentToken: string,\r\n isApiRoute: boolean\r\n ): Promise<NextResponse> {\r\n const { pathname, origin } = req.nextUrl;\r\n const { isValid, tokenType, userData } = tokenInfo;\r\n const isGuest = tokenType === TOKEN_TYPES.GUEST;\r\n\r\n // ===== TOKEN INVALID =====\r\n if (!isValid) {\r\n // Try refresh if user token\r\n if (isUserToken && currentToken) {\r\n const refreshResult = await validation.refreshToken(currentToken);\r\n \r\n if (refreshResult.success && refreshResult.newToken) {\r\n const newTokenInfo = await validation.getTokenInfo(refreshResult.newToken);\r\n \r\n if (newTokenInfo.isValid) {\r\n // Successful refresh\r\n const requestHeaders = new Headers(req.headers);\r\n \r\n if (newTokenInfo.userData) {\r\n requestHeaders.set(HEADERS.AUTH_USER, JSON.stringify(newTokenInfo.userData));\r\n }\r\n requestHeaders.set(HEADERS.REFRESHED_TOKEN, refreshResult.newToken);\r\n \r\n // Set locale header if i18n is enabled\r\n const locale = extractLocale(pathname, i18n);\r\n if (locale) {\r\n requestHeaders.set(HEADERS.LOCALE, locale);\r\n }\r\n\r\n let response: NextResponse;\r\n \r\n if (isAuthPage(pathname)) {\r\n response = NextResponse.redirect(new URL('/', origin));\r\n } else {\r\n response = NextResponse.next({ request: { headers: requestHeaders } });\r\n }\r\n\r\n response.cookies.set(cookies.user, refreshResult.newToken, {\r\n ...cookieOptions,\r\n maxAge: cookieOptions.maxAge,\r\n });\r\n safeDeleteCookie(req, response, cookies.guest);\r\n\r\n return response;\r\n }\r\n }\r\n }\r\n\r\n // Refresh failed or no user token - handle as no token\r\n const response = await handleNoToken(req, isApiRoute);\r\n \r\n // Check if handleNoToken created a new guest token\r\n const hasNewGuestToken = response.cookies.get(cookies.guest)?.value;\r\n \r\n if (!hasNewGuestToken) {\r\n // No new guest token created - delete all auth cookies\r\n deleteAllAuthCookies(req, response);\r\n } else {\r\n // New guest token created - only delete the invalid user cookie\r\n safeDeleteCookie(req, response, cookies.user);\r\n }\r\n \r\n return response;\r\n }\r\n\r\n // ===== TOKEN VALID =====\r\n const requestHeaders = new Headers(req.headers);\r\n \r\n if (userData) {\r\n requestHeaders.set(HEADERS.AUTH_USER, JSON.stringify(userData));\r\n }\r\n \r\n // Set locale header if i18n is enabled\r\n const locale = extractLocale(pathname, i18n);\r\n if (locale) {\r\n requestHeaders.set(HEADERS.LOCALE, locale);\r\n }\r\n\r\n // Check if token type is allowed\r\n if (!isGuest && !isTokenTypeAllowed(tokenType)) {\r\n if (isApiRoute) {\r\n const response = jsonError('Bu işlem için yetkiniz yok', 403);\r\n return deleteAllAuthCookies(req, response);\r\n }\r\n \r\n const response = NextResponse.redirect(new URL('/login', origin));\r\n return deleteAllAuthCookies(req, response);\r\n }\r\n\r\n // Guest token handling\r\n if (isGuest) {\r\n if (isApiRoute) {\r\n return NextResponse.next({ request: { headers: requestHeaders } });\r\n }\r\n\r\n // Protected routes require login\r\n if (isProtectedRoute(pathname)) {\r\n return NextResponse.redirect(new URL('/login', origin));\r\n }\r\n\r\n return NextResponse.next({ request: { headers: requestHeaders } });\r\n }\r\n\r\n // User token - block auth pages\r\n if (isAuthPage(pathname)) {\r\n return NextResponse.redirect(new URL('/', origin));\r\n }\r\n\r\n // Normal access\r\n const response = NextResponse.next({ request: { headers: requestHeaders } });\r\n safeDeleteCookie(req, response, cookies.guest);\r\n \r\n return response;\r\n }\r\n\r\n return {\r\n deleteAllAuthCookies,\r\n jsonError,\r\n isAuthPage,\r\n isProtectedRoute,\r\n isPublicRoute,\r\n isTokenTypeAllowed,\r\n handleNoToken,\r\n handleValidationResult,\r\n };\r\n}\r\n\r\nexport type Handlers = ReturnType<typeof createHandlers>;\r\n","/**\r\n * CSRF Protection\r\n * \r\n * Implements OWASP recommended CSRF protection:\r\n * - Fetch Metadata (Sec-Fetch-Site header) for modern browsers (98%+ coverage)\r\n * - Signed HMAC Double-Submit Cookie as fallback\r\n * \r\n * @see https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html\r\n */\r\n\r\nimport { NextRequest, NextResponse } from 'next/server';\r\nimport type { ResolvedCsrfConfig } from '../shared/types';\r\n\r\nexport interface CsrfValidationResult {\r\n valid: boolean;\r\n reason?: string;\r\n}\r\n\r\n/**\r\n * Creates CSRF validator functions\r\n */\r\nexport function createCsrfValidator(config: ResolvedCsrfConfig) {\r\n /**\r\n * Generate HMAC-signed CSRF token\r\n * Format: hmac.randomValue\r\n */\r\n async function generateToken(sessionId: string): Promise<string> {\r\n const randomValue = generateRandomValue();\r\n const hmac = await computeHmac(config.secret, sessionId, randomValue);\r\n return `${hmac}.${randomValue}`;\r\n }\r\n\r\n /**\r\n * Validate CSRF request using configured strategy\r\n */\r\n function validateRequest(req: NextRequest): CsrfValidationResult {\r\n const method = req.method.toUpperCase();\r\n \r\n // Skip safe methods\r\n if (config.ignoreMethods.includes(method)) {\r\n return { valid: true };\r\n }\r\n\r\n const strategy = config.strategy;\r\n \r\n // Fetch Metadata validation (primary, modern browsers)\r\n if (strategy === 'fetch-metadata' || strategy === 'both') {\r\n const fetchResult = validateFetchMetadata(req);\r\n \r\n if (strategy === 'fetch-metadata') {\r\n return fetchResult;\r\n }\r\n \r\n // 'both' strategy: if Fetch Metadata passes, we're good\r\n if (fetchResult.valid) {\r\n return fetchResult;\r\n }\r\n \r\n // 'both' strategy: if Fetch Metadata fails or not available, try double-submit\r\n if (fetchResult.reason === 'missing-headers') {\r\n // Fall through to double-submit\r\n } else {\r\n // Explicit cross-site rejection from Fetch Metadata\r\n return fetchResult;\r\n }\r\n }\r\n\r\n // Double-Submit Cookie validation (fallback)\r\n if (strategy === 'double-submit' || strategy === 'both') {\r\n return validateDoubleSubmit(req);\r\n }\r\n\r\n return { valid: true };\r\n }\r\n\r\n /**\r\n * Validate using Fetch Metadata headers (Sec-Fetch-Site)\r\n * @see https://web.dev/fetch-metadata/\r\n */\r\n function validateFetchMetadata(req: NextRequest): CsrfValidationResult {\r\n const secFetchSite = req.headers.get('sec-fetch-site');\r\n \r\n // No Fetch Metadata headers (older browser or stripped by proxy)\r\n if (!secFetchSite) {\r\n return { valid: false, reason: 'missing-headers' };\r\n }\r\n\r\n // Same-origin requests are always trusted\r\n if (secFetchSite === 'same-origin') {\r\n return { valid: true };\r\n }\r\n\r\n // None = direct navigation (bookmark, typed URL) - allow for GET\r\n if (secFetchSite === 'none') {\r\n const method = req.method.toUpperCase();\r\n if (config.ignoreMethods.includes(method)) {\r\n return { valid: true };\r\n }\r\n // Non-safe method from direct navigation is suspicious\r\n return { valid: false, reason: 'direct-navigation-unsafe-method' };\r\n }\r\n\r\n // Same-site: trust based on config\r\n if (secFetchSite === 'same-site') {\r\n if (config.trustSameSite) {\r\n return { valid: true };\r\n }\r\n // Conservative: don't trust same-site by default (subdomain takeover risk)\r\n return { valid: false, reason: 'same-site-not-trusted' };\r\n }\r\n\r\n // Cross-site: reject state-changing requests\r\n if (secFetchSite === 'cross-site') {\r\n return { valid: false, reason: 'cross-site-request' };\r\n }\r\n\r\n // Unknown value - be conservative\r\n return { valid: false, reason: 'unknown-sec-fetch-site' };\r\n }\r\n\r\n /**\r\n * Validate using Double-Submit Cookie pattern with HMAC\r\n */\r\n function validateDoubleSubmit(req: NextRequest): CsrfValidationResult {\r\n // Get token from cookie\r\n const cookieToken = req.cookies.get(config.cookieName)?.value;\r\n \r\n if (!cookieToken) {\r\n return { valid: false, reason: 'missing-cookie-token' };\r\n }\r\n\r\n // Get token from header (or form field)\r\n const headerToken = req.headers.get(config.headerName);\r\n \r\n if (!headerToken) {\r\n return { valid: false, reason: 'missing-header-token' };\r\n }\r\n\r\n // Tokens must match (constant-time comparison to prevent timing attacks)\r\n if (!constantTimeEqual(cookieToken, headerToken)) {\r\n return { valid: false, reason: 'token-mismatch' };\r\n }\r\n\r\n // Validate HMAC structure\r\n const parts = cookieToken.split('.');\r\n if (parts.length !== 2) {\r\n return { valid: false, reason: 'invalid-token-format' };\r\n }\r\n\r\n return { valid: true };\r\n }\r\n\r\n /**\r\n * Create response with CSRF cookie set\r\n */\r\n async function attachCsrfCookie(\r\n response: NextResponse, \r\n sessionId: string\r\n ): Promise<NextResponse> {\r\n const token = await generateToken(sessionId);\r\n \r\n response.cookies.set(config.cookieName, token, {\r\n httpOnly: false, // Must be readable by JS\r\n secure: process.env.NODE_ENV === 'production',\r\n sameSite: 'strict',\r\n path: '/',\r\n });\r\n\r\n return response;\r\n }\r\n\r\n return {\r\n validateRequest,\r\n generateToken,\r\n attachCsrfCookie,\r\n };\r\n}\r\n\r\n// ==================== Helper Functions ====================\r\n\r\n/**\r\n * Generate cryptographically random value\r\n */\r\nfunction generateRandomValue(): string {\r\n if (typeof crypto !== 'undefined' && crypto.getRandomValues) {\r\n const array = new Uint8Array(32);\r\n crypto.getRandomValues(array);\r\n return Array.from(array, b => b.toString(16).padStart(2, '0')).join('');\r\n }\r\n // Fallback (less secure, for edge cases)\r\n return Math.random().toString(36).substring(2) + Date.now().toString(36);\r\n}\r\n\r\n/**\r\n * Compute HMAC-SHA256\r\n */\r\nasync function computeHmac(\r\n secret: string, \r\n sessionId: string, \r\n randomValue: string\r\n): Promise<string> {\r\n const message = `${sessionId.length}!${sessionId}!${randomValue.length}!${randomValue}`;\r\n \r\n if (typeof crypto !== 'undefined' && crypto.subtle) {\r\n const encoder = new TextEncoder();\r\n const keyData = encoder.encode(secret);\r\n const messageData = encoder.encode(message);\r\n \r\n const key = await crypto.subtle.importKey(\r\n 'raw',\r\n keyData,\r\n { name: 'HMAC', hash: 'SHA-256' },\r\n false,\r\n ['sign']\r\n );\r\n \r\n const signature = await crypto.subtle.sign('HMAC', key, messageData);\r\n return Array.from(new Uint8Array(signature), b => \r\n b.toString(16).padStart(2, '0')\r\n ).join('');\r\n }\r\n \r\n // Fallback (less secure)\r\n let hash = 0;\r\n const str = secret + message;\r\n for (let i = 0; i < str.length; i++) {\r\n const char = str.charCodeAt(i);\r\n hash = ((hash << 5) - hash) + char;\r\n hash = hash & hash;\r\n }\r\n return Math.abs(hash).toString(16);\r\n}\r\n\r\n/**\r\n * Constant-time string comparison (prevents timing attacks)\r\n */\r\nfunction constantTimeEqual(a: string, b: string): boolean {\r\n if (a.length !== b.length) {\r\n return false;\r\n }\r\n \r\n let result = 0;\r\n for (let i = 0; i < a.length; i++) {\r\n result |= a.charCodeAt(i) ^ b.charCodeAt(i);\r\n }\r\n \r\n return result === 0;\r\n}\r\n\r\nexport type CsrfValidator = ReturnType<typeof createCsrfValidator>;\r\n","/**\r\n * Rate Limiting\r\n * \r\n * Implements token bucket algorithm for rate limiting.\r\n * In-memory store by default, designed for single-instance deployments.\r\n * \r\n * For horizontal scaling (multiple instances), use a custom store\r\n * with Redis or similar distributed cache.\r\n */\r\n\r\nimport { NextRequest, NextResponse } from 'next/server';\r\nimport type { ResolvedRateLimitConfig } from '../shared/types';\r\n\r\ninterface RateLimitEntry {\r\n count: number;\r\n resetAt: number;\r\n}\r\n\r\nexport interface RateLimitResult {\r\n allowed: boolean;\r\n remaining: number;\r\n resetAt: number;\r\n limit: number;\r\n}\r\n\r\n/**\r\n * Creates a rate limiter with in-memory store\r\n */\r\nexport function createRateLimiter(config: ResolvedRateLimitConfig) {\r\n // In-memory store\r\n const store = new Map<string, RateLimitEntry>();\r\n \r\n // Cleanup expired entries periodically\r\n const cleanupInterval = setInterval(() => {\r\n const now = Date.now();\r\n for (const [key, entry] of store) {\r\n if (entry.resetAt <= now) {\r\n store.delete(key);\r\n }\r\n }\r\n }, config.windowMs);\r\n\r\n // Prevent memory leak in long-running processes\r\n if (typeof process !== 'undefined' && process.on) {\r\n process.on('beforeExit', () => clearInterval(cleanupInterval));\r\n }\r\n\r\n /**\r\n * Check if route should skip rate limiting\r\n */\r\n function shouldSkip(pathname: string): boolean {\r\n return config.skipRoutes.some(pattern => {\r\n // Simple glob matching\r\n if (pattern.endsWith('*')) {\r\n return pathname.startsWith(pattern.slice(0, -1));\r\n }\r\n if (pattern.endsWith('**')) {\r\n return pathname.startsWith(pattern.slice(0, -2));\r\n }\r\n return pathname === pattern;\r\n });\r\n }\r\n\r\n /**\r\n * Check rate limit for request\r\n */\r\n function check(req: NextRequest): RateLimitResult {\r\n const pathname = req.nextUrl.pathname;\r\n \r\n // Skip if route matches skip patterns\r\n if (shouldSkip(pathname)) {\r\n return {\r\n allowed: true,\r\n remaining: config.maxRequests,\r\n resetAt: 0,\r\n limit: config.maxRequests,\r\n };\r\n }\r\n\r\n const key = config.keyFn(req);\r\n const now = Date.now();\r\n \r\n let entry = store.get(key);\r\n \r\n // New window or expired\r\n if (!entry || entry.resetAt <= now) {\r\n entry = {\r\n count: 1,\r\n resetAt: now + config.windowMs,\r\n };\r\n store.set(key, entry);\r\n \r\n return {\r\n allowed: true,\r\n remaining: config.maxRequests - 1,\r\n resetAt: entry.resetAt,\r\n limit: config.maxRequests,\r\n };\r\n }\r\n\r\n // Existing window\r\n entry.count++;\r\n \r\n const remaining = Math.max(0, config.maxRequests - entry.count);\r\n const allowed = entry.count <= config.maxRequests;\r\n \r\n return {\r\n allowed,\r\n remaining,\r\n resetAt: entry.resetAt,\r\n limit: config.maxRequests,\r\n };\r\n }\r\n\r\n /**\r\n * Apply rate limit headers to response\r\n */\r\n function applyHeaders(response: NextResponse, result: RateLimitResult): NextResponse {\r\n response.headers.set('X-RateLimit-Limit', result.limit.toString());\r\n response.headers.set('X-RateLimit-Remaining', result.remaining.toString());\r\n response.headers.set('X-RateLimit-Reset', Math.ceil(result.resetAt / 1000).toString());\r\n return response;\r\n }\r\n\r\n /**\r\n * Create rate limited response (429 Too Many Requests)\r\n */\r\n function createLimitedResponse(req: NextRequest, result: RateLimitResult): NextResponse {\r\n // User-provided handler\r\n if (config.onRateLimited) {\r\n const response = config.onRateLimited(req);\r\n return applyHeaders(response, result);\r\n }\r\n\r\n // Default response\r\n const response = NextResponse.json(\r\n {\r\n success: false,\r\n message: 'Too many requests. Please try again later.',\r\n retryAfter: Math.ceil((result.resetAt - Date.now()) / 1000),\r\n },\r\n { status: 429 }\r\n );\r\n\r\n response.headers.set('Retry-After', Math.ceil((result.resetAt - Date.now()) / 1000).toString());\r\n return applyHeaders(response, result);\r\n }\r\n\r\n /**\r\n * Reset rate limit for a key (useful for testing)\r\n */\r\n function reset(key: string): void {\r\n store.delete(key);\r\n }\r\n\r\n /**\r\n * Clear all rate limit entries\r\n */\r\n function clear(): void {\r\n store.clear();\r\n }\r\n\r\n /**\r\n * Get current store size (for monitoring)\r\n */\r\n function size(): number {\r\n return store.size;\r\n }\r\n\r\n return {\r\n check,\r\n applyHeaders,\r\n createLimitedResponse,\r\n shouldSkip,\r\n reset,\r\n clear,\r\n size,\r\n };\r\n}\r\n\r\nexport type RateLimiter = ReturnType<typeof createRateLimiter>;\r\n","/**\r\n * Audit Logging\r\n * \r\n * Event-based security audit logging system.\r\n * Emits events for authentication, access control, and security violations.\r\n */\r\n\r\nimport { NextRequest } from 'next/server';\r\nimport type { ResolvedAuditConfig, AuditEvent, AuditEventType } from '../shared/types';\r\n\r\n/**\r\n * Creates an audit logger instance\r\n */\r\nexport function createAuditLogger(config: ResolvedAuditConfig) {\r\n /**\r\n * Check if event type is enabled\r\n */\r\n function isEnabled(type: AuditEventType): boolean {\r\n return config.enabled && config.events.includes(type);\r\n }\r\n\r\n /**\r\n * Extract IP address from request\r\n */\r\n function getIp(req: NextRequest): string | null {\r\n return (\r\n req.headers.get('x-forwarded-for')?.split(',')[0]?.trim() ||\r\n req.headers.get('x-real-ip') ||\r\n null\r\n );\r\n }\r\n\r\n /**\r\n * Emit an audit event\r\n */\r\n async function emit(\r\n type: AuditEventType,\r\n req: NextRequest,\r\n options: {\r\n success: boolean;\r\n userId?: string;\r\n metadata?: Record<string, unknown>;\r\n }\r\n ): Promise<void> {\r\n if (!isEnabled(type)) {\r\n return;\r\n }\r\n\r\n const event: AuditEvent = {\r\n type,\r\n timestamp: new Date(),\r\n ip: getIp(req),\r\n userId: options.userId,\r\n path: req.nextUrl.pathname,\r\n method: req.method,\r\n success: options.success,\r\n metadata: options.metadata,\r\n };\r\n\r\n // Call user's logger\r\n if (config.logger) {\r\n try {\r\n await config.logger(event);\r\n } catch (error) {\r\n // Silently fail - don't break the request flow for logging errors\r\n console.error('[next-api-layer] Audit logger error:', error);\r\n }\r\n }\r\n }\r\n\r\n // ==================== Convenience Methods ====================\r\n\r\n /**\r\n * Log successful authentication\r\n */\r\n function authSuccess(req: NextRequest, userId?: string, metadata?: Record<string, unknown>) {\r\n return emit('auth:success', req, { success: true, userId, metadata });\r\n }\r\n\r\n /**\r\n * Log failed authentication\r\n */\r\n function authFail(req: NextRequest, metadata?: Record<string, unknown>) {\r\n return emit('auth:fail', req, { success: false, metadata });\r\n }\r\n\r\n /**\r\n * Log token refresh\r\n */\r\n function authRefresh(req: NextRequest, userId?: string, metadata?: Record<string, unknown>) {\r\n return emit('auth:refresh', req, { success: true, userId, metadata });\r\n }\r\n\r\n /**\r\n * Log guest token creation\r\n */\r\n function authGuest(req: NextRequest, metadata?: Record<string, unknown>) {\r\n return emit('auth:guest', req, { success: true, metadata });\r\n }\r\n\r\n /**\r\n * Log access denied\r\n */\r\n function accessDenied(req: NextRequest, userId?: string, metadata?: Record<string, unknown>) {\r\n return emit('access:denied', req, { success: false, userId, metadata });\r\n }\r\n\r\n /**\r\n * Log CSRF validation failure\r\n */\r\n function csrfFail(req: NextRequest, metadata?: Record<string, unknown>) {\r\n return emit('csrf:fail', req, { success: false, metadata });\r\n }\r\n\r\n /**\r\n * Log rate limit exceeded\r\n */\r\n function rateLimitExceeded(req: NextRequest, metadata?: Record<string, unknown>) {\r\n return emit('rateLimit:exceeded', req, { success: false, metadata });\r\n }\r\n\r\n /**\r\n * Log general error\r\n */\r\n function error(req: NextRequest, err: Error, metadata?: Record<string, unknown>) {\r\n return emit('error', req, { \r\n success: false, \r\n metadata: { \r\n ...metadata, \r\n error: err.message,\r\n stack: err.stack,\r\n } \r\n });\r\n }\r\n\r\n return {\r\n emit,\r\n isEnabled,\r\n // Convenience methods\r\n authSuccess,\r\n authFail,\r\n authRefresh,\r\n authGuest,\r\n accessDenied,\r\n csrfFail,\r\n rateLimitExceeded,\r\n error,\r\n };\r\n}\r\n\r\nexport type AuditLogger = ReturnType<typeof createAuditLogger>;\r\n","/**\r\n * createAuthProxy\r\n * Factory function to create Next.js middleware for external JWT authentication\r\n */\r\n\r\nimport { NextRequest, NextResponse } from 'next/server';\r\nimport type { AuthProxyConfig, AuthResult } from '../shared/types';\r\nimport { resolveProxyConfig } from '../shared/config';\r\nimport { createTokenValidation } from './tokenValidation';\r\nimport { createHandlers } from './handlers';\r\nimport { createCsrfValidator } from './csrf';\r\nimport { createRateLimiter } from './rateLimit';\r\nimport { createAuditLogger } from './audit';\r\nimport { HEADERS } from '../shared/constants';\r\n\r\n/**\r\n * Merge two NextResponse objects, preserving headers and cookies from both\r\n * Target response takes priority for conflicts\r\n */\r\nfunction mergeResponses(source: NextResponse, target: NextResponse): NextResponse {\r\n // Copy critical headers from source to target (if not already set)\r\n const criticalHeaders = [HEADERS.LOCALE, HEADERS.AUTH_USER, HEADERS.REFRESHED_TOKEN];\r\n \r\n for (const header of criticalHeaders) {\r\n const value = source.headers.get(header);\r\n if (value && !target.headers.has(header)) {\r\n target.headers.set(header, value);\r\n }\r\n }\r\n \r\n // Copy cookies from source to target (if not already set)\r\n source.cookies.getAll().forEach(cookie => {\r\n if (!target.cookies.get(cookie.name)) {\r\n target.cookies.set(cookie.name, cookie.value);\r\n }\r\n });\r\n \r\n return target;\r\n}\r\n\r\n/**\r\n * Creates an authentication proxy middleware for Next.js\r\n * \r\n * @example\r\n * ```ts\r\n * // middleware.ts\r\n * import { createAuthProxy } from 'next-api-layer';\r\n * \r\n * const authProxy = createAuthProxy({\r\n * apiBaseUrl: process.env.API_BASE_URL!,\r\n * cookies: {\r\n * user: 'userAuthToken',\r\n * guest: 'guestAuthToken',\r\n * },\r\n * guestToken: {\r\n * enabled: true,\r\n * credentials: {\r\n * username: process.env.GUEST_USERNAME!,\r\n * password: process.env.GUEST_PASSWORD!,\r\n * },\r\n * },\r\n * access: {\r\n * protectedRoutes: ['/dashboard', '/profile'],\r\n * authRoutes: ['/login', '/register'],\r\n * },\r\n * // Security features\r\n * csrf: { enabled: true },\r\n * rateLimit: { enabled: true, maxRequests: 100 },\r\n * audit: { \r\n * enabled: true, \r\n * logger: (event) => console.log('[AUDIT]', event) \r\n * },\r\n * });\r\n * \r\n * export default authProxy;\r\n * \r\n * export const config = {\r\n * matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],\r\n * };\r\n * ```\r\n */\r\nexport function createAuthProxy(userConfig: AuthProxyConfig) {\r\n // Resolve config with defaults\r\n const config = resolveProxyConfig(userConfig);\r\n \r\n // Create validation functions\r\n const validation = createTokenValidation(config);\r\n \r\n // Create handlers\r\n const handlers = createHandlers(config, validation);\r\n\r\n // Create security modules\r\n const csrf = createCsrfValidator(config._resolved.csrf);\r\n const rateLimiter = createRateLimiter(config._resolved.rateLimit);\r\n const audit = createAuditLogger(config._resolved.audit);\r\n\r\n /**\r\n * The middleware function\r\n */\r\n async function authProxy(req: NextRequest): Promise<NextResponse> {\r\n const { pathname, origin } = req.nextUrl;\r\n const isApiRoute = pathname.startsWith('/api');\r\n\r\n // ============ Rate Limiting ============\r\n // Check early to protect against DoS\r\n if (config._resolved.rateLimit.enabled) {\r\n const rateLimitResult = rateLimiter.check(req);\r\n \r\n if (!rateLimitResult.allowed) {\r\n await audit.rateLimitExceeded(req, { \r\n limit: rateLimitResult.limit,\r\n resetAt: rateLimitResult.resetAt,\r\n });\r\n return rateLimiter.createLimitedResponse(req, rateLimitResult);\r\n }\r\n }\r\n\r\n // ============ CSRF Protection ============\r\n // Check before any state-changing operations\r\n if (config._resolved.csrf.enabled) {\r\n const csrfResult = csrf.validateRequest(req);\r\n \r\n if (!csrfResult.valid) {\r\n await audit.csrfFail(req, { reason: csrfResult.reason });\r\n return NextResponse.json(\r\n { success: false, message: 'CSRF validation failed' },\r\n { status: 403 }\r\n );\r\n }\r\n }\r\n\r\n // ============ Block Browser API Access ============\r\n // Prevents direct browser access to API routes (when Accept: text/html)\r\n if (config.blockBrowserApiAccess && isApiRoute) {\r\n const acceptHeader = req.headers.get('accept') || '';\r\n if (acceptHeader.includes('text/html')) {\r\n return NextResponse.redirect(new URL('/', origin));\r\n }\r\n }\r\n\r\n // ============ beforeAuth Hook ============\r\n // Allows user to handle request before auth validation\r\n if (config.beforeAuth) {\r\n const beforeResult = await config.beforeAuth(req);\r\n if (beforeResult) {\r\n return beforeResult; // User handled the request\r\n }\r\n }\r\n\r\n // Skip excluded paths\r\n const excludedPaths = config.excludedPaths ?? [];\r\n if (excludedPaths.some(path => pathname.startsWith(path))) {\r\n return applyMiddlewaresAndHooks(req, NextResponse.next(), { isAuthenticated: false, isGuest: false, tokenType: null, user: null });\r\n }\r\n\r\n // Skip auth API endpoints (they handle their own auth)\r\n const authApiPaths = [\r\n '/api/auth/login',\r\n '/api/auth/logout',\r\n '/api/auth/me',\r\n '/api/auth/refresh',\r\n '/api/auth/register',\r\n ];\r\n \r\n if (authApiPaths.includes(pathname)) {\r\n return applyMiddlewaresAndHooks(req, NextResponse.next(), { isAuthenticated: false, isGuest: false, tokenType: null, user: null });\r\n }\r\n\r\n // Get tokens from cookies\r\n const userToken = req.cookies?.get(config.cookies.user)?.value;\r\n const guestToken = req.cookies?.get(config.cookies.guest)?.value;\r\n const currentToken = userToken || guestToken;\r\n const isUserToken = !!userToken;\r\n\r\n // No token - handle appropriately\r\n if (!currentToken) {\r\n await audit.authFail(req, { reason: 'no-token' });\r\n const response = await handlers.handleNoToken(req, isApiRoute);\r\n return applyMiddlewaresAndHooks(req, response, { isAuthenticated: false, isGuest: false, tokenType: null, user: null });\r\n }\r\n\r\n // Validate token\r\n const tokenInfo = await validation.getTokenInfo(currentToken);\r\n \r\n // Build auth result for afterAuth hook\r\n const authResult: AuthResult = {\r\n isAuthenticated: tokenInfo.isValid && tokenInfo.tokenType !== 'guest',\r\n isGuest: tokenInfo.isValid && tokenInfo.tokenType === 'guest',\r\n tokenType: tokenInfo.tokenType,\r\n user: tokenInfo.userData,\r\n };\r\n\r\n // Audit logging based on validation result \r\n if (tokenInfo.isValid) {\r\n if (tokenInfo.tokenType === 'guest') {\r\n await audit.authGuest(req);\r\n } else {\r\n const userId = tokenInfo.userData?.id?.toString();\r\n await audit.authSuccess(req, userId, { tokenType: tokenInfo.tokenType });\r\n }\r\n } else {\r\n await audit.authFail(req, { reason: 'invalid-token' });\r\n }\r\n\r\n // Handle validation result\r\n const response = await handlers.handleValidationResult(\r\n req,\r\n tokenInfo,\r\n isUserToken,\r\n currentToken,\r\n isApiRoute\r\n );\r\n \r\n // Apply CSRF cookie if enabled (for authenticated requests)\r\n let finalResponse = await applyMiddlewaresAndHooks(req, response, authResult);\r\n \r\n if (config._resolved.csrf.enabled && authResult.isAuthenticated) {\r\n const sessionId = tokenInfo.userData?.id?.toString() || currentToken.slice(0, 32);\r\n finalResponse = await csrf.attachCsrfCookie(finalResponse, sessionId);\r\n }\r\n\r\n // Apply rate limit headers\r\n if (config._resolved.rateLimit.enabled) {\r\n const rateLimitResult = rateLimiter.check(req);\r\n finalResponse = rateLimiter.applyHeaders(finalResponse, rateLimitResult);\r\n }\r\n \r\n return finalResponse;\r\n }\r\n \r\n /**\r\n * Helper to apply i18n middleware and afterAuth hook\r\n * Merges responses to preserve critical headers (x-locale, x-auth-user, etc.)\r\n */\r\n async function applyMiddlewaresAndHooks(req: NextRequest, response: NextResponse, authResult: AuthResult): Promise<NextResponse> {\r\n let finalResponse = response;\r\n \r\n // Apply i18n middleware if configured\r\n if (config.i18n?.middleware) {\r\n const intlResponse = await Promise.resolve(config.i18n.middleware(req));\r\n // Merge library's response headers into i18n response\r\n finalResponse = mergeResponses(response, intlResponse);\r\n }\r\n \r\n // Apply afterAuth hook if configured\r\n if (config.afterAuth) {\r\n const hookResponse = await config.afterAuth(req, finalResponse, authResult);\r\n // Merge previous response headers into hook's response\r\n finalResponse = mergeResponses(finalResponse, hookResponse);\r\n }\r\n \r\n return finalResponse;\r\n }\r\n\r\n // Attach instances for debugging/testing\r\n authProxy.config = config;\r\n authProxy.csrf = csrf;\r\n authProxy.rateLimiter = rateLimiter;\r\n authProxy.audit = audit;\r\n\r\n return authProxy;\r\n}\r\n\r\nexport type AuthProxy = ReturnType<typeof createAuthProxy>;\r\n\r\n","/**\r\n * createProxyHandler\r\n * Factory function to create Next.js API route handlers that proxy requests to backend\r\n */\r\n\r\nimport { NextRequest, NextResponse } from 'next/server';\r\nimport { HEADERS } from '../shared/constants';\r\n\r\nexport interface ProxyHandlerConfig {\r\n /** Base URL of the backend API */\r\n apiBaseUrl: string;\r\n /** Cookie name for user auth token */\r\n userCookieName?: string;\r\n /** Cookie name for guest auth token */\r\n guestCookieName?: string;\r\n /** \r\n * Default behavior for auth - if true, all requests skip auth by default\r\n * Individual requests can override with X-Skip-Auth header\r\n */\r\n skipAuthByDefault?: boolean;\r\n /**\r\n * Public endpoints that should never include auth token (glob patterns)\r\n * e.g., ['news/*', 'public/**', 'categories']\r\n */\r\n publicEndpoints?: string[];\r\n /** Headers to forward from client request */\r\n forwardHeaders?: string[];\r\n /** Headers to exclude from forwarding */\r\n excludeHeaders?: string[];\r\n /** Custom request transformer */\r\n transformRequest?: (req: NextRequest, headers: Headers) => Headers | Promise<Headers>;\r\n /** Custom response transformer */\r\n transformResponse?: (response: Response) => Response | Promise<Response>;\r\n}\r\n\r\n/**\r\n * Check if endpoint matches any patterns (glob support)\r\n */\r\nfunction matchesPattern(endpoint: string, patterns: string[]): boolean {\r\n if (!patterns || patterns.length === 0) return false;\r\n \r\n // Normalize endpoint\r\n const normalizedEndpoint = endpoint\r\n .replace(/^\\/api\\//, '')\r\n .replace(/^\\//, '');\r\n \r\n return patterns.some(pattern => {\r\n if (pattern === normalizedEndpoint) return true;\r\n \r\n if (pattern.includes('*')) {\r\n const regexPattern = pattern\r\n .replace(/\\*\\*/g, '<<<DOUBLE>>>')\r\n .replace(/\\*/g, '[^/]+')\r\n .replace(/<<<DOUBLE>>>/g, '.+');\r\n const regex = new RegExp(`^${regexPattern}$`);\r\n return regex.test(normalizedEndpoint);\r\n }\r\n \r\n return false;\r\n });\r\n}\r\n\r\n/**\r\n * Creates a proxy handler for Next.js API routes\r\n * \r\n * @example\r\n * ```ts\r\n * // app/api/[...path]/route.ts\r\n * import { createProxyHandler } from 'next-api-layer';\r\n * \r\n * const handler = createProxyHandler({\r\n * apiBaseUrl: process.env.API_BASE_URL!,\r\n * userCookieName: 'auth_token',\r\n * guestCookieName: 'guest_token',\r\n * publicEndpoints: ['news/*', 'categories', 'public/**'],\r\n * });\r\n * \r\n * export const GET = handler;\r\n * export const POST = handler;\r\n * export const PUT = handler;\r\n * export const PATCH = handler;\r\n * export const DELETE = handler;\r\n * ```\r\n */\r\nexport function createProxyHandler(config: ProxyHandlerConfig) {\r\n const {\r\n apiBaseUrl,\r\n userCookieName = 'auth_token',\r\n guestCookieName = 'guest_token',\r\n skipAuthByDefault = false,\r\n publicEndpoints = [],\r\n forwardHeaders = ['content-type', 'accept', 'accept-language', 'x-requested-with'],\r\n excludeHeaders = ['host', 'connection', 'cookie'],\r\n transformRequest,\r\n transformResponse,\r\n } = config;\r\n\r\n // Normalize base URL (remove trailing slash)\r\n const baseUrl = apiBaseUrl.replace(/\\/$/, '');\r\n\r\n /**\r\n * Determine if auth should be skipped for this request\r\n */\r\n function shouldSkipAuth(req: NextRequest, endpoint: string): boolean {\r\n // Check X-Skip-Auth header from client\r\n const skipAuthHeader = req.headers.get(HEADERS.SKIP_AUTH);\r\n if (skipAuthHeader === 'true') {\r\n return true;\r\n }\r\n \r\n // Check if endpoint matches public patterns\r\n if (matchesPattern(endpoint, publicEndpoints)) {\r\n return true;\r\n }\r\n \r\n // Default behavior\r\n return skipAuthByDefault;\r\n }\r\n\r\n /**\r\n * The proxy handler function\r\n */\r\n async function handler(req: NextRequest): Promise<NextResponse> {\r\n try {\r\n // Extract endpoint from URL path (remove /api/ prefix)\r\n const url = new URL(req.url);\r\n const endpoint = url.pathname.replace(/^\\/api\\/?/, '');\r\n \r\n // Build backend URL\r\n const backendUrl = new URL(`${baseUrl}/${endpoint}`);\r\n backendUrl.search = url.search; // Forward query params\r\n\r\n // Build headers for backend request\r\n const headers = new Headers();\r\n \r\n // Forward allowed headers from original request\r\n forwardHeaders.forEach(headerName => {\r\n const value = req.headers.get(headerName);\r\n if (value) {\r\n headers.set(headerName, value);\r\n }\r\n });\r\n\r\n // Forward all headers except excluded ones\r\n req.headers.forEach((value, key) => {\r\n const lowerKey = key.toLowerCase();\r\n if (!excludeHeaders.includes(lowerKey) && !headers.has(key)) {\r\n headers.set(key, value);\r\n }\r\n });\r\n\r\n // Add Authorization header if auth is not skipped\r\n if (!shouldSkipAuth(req, endpoint)) {\r\n const userToken = req.cookies.get(userCookieName)?.value;\r\n const guestToken = req.cookies.get(guestCookieName)?.value;\r\n const token = userToken || guestToken;\r\n \r\n if (token) {\r\n headers.set(HEADERS.AUTHORIZATION, `Bearer ${token}`);\r\n }\r\n }\r\n\r\n // Remove skip-auth header (internal use only)\r\n headers.delete(HEADERS.SKIP_AUTH);\r\n\r\n // Allow custom request transformation\r\n const finalHeaders = transformRequest \r\n ? await transformRequest(req, headers) \r\n : headers;\r\n\r\n // Get request body if present\r\n let body: BodyInit | null = null;\r\n if (req.method !== 'GET' && req.method !== 'HEAD') {\r\n const contentType = req.headers.get('content-type') || '';\r\n \r\n if (contentType.includes('application/json')) {\r\n body = await req.text();\r\n } else if (contentType.includes('multipart/form-data')) {\r\n body = await req.formData();\r\n } else {\r\n body = await req.text();\r\n }\r\n }\r\n\r\n // Make request to backend\r\n const backendResponse = await fetch(backendUrl.toString(), {\r\n method: req.method,\r\n headers: finalHeaders,\r\n body,\r\n });\r\n\r\n // Get response body\r\n const contentType = backendResponse.headers.get('content-type') || '';\r\n let responseBody: ArrayBuffer | string;\r\n \r\n if (contentType.includes('application/json')) {\r\n responseBody = await backendResponse.text();\r\n } else {\r\n responseBody = await backendResponse.arrayBuffer();\r\n }\r\n\r\n // Build response headers (forward relevant ones)\r\n const responseHeaders = new Headers();\r\n backendResponse.headers.forEach((value, key) => {\r\n const lowerKey = key.toLowerCase();\r\n // Skip hop-by-hop headers\r\n if (!['transfer-encoding', 'connection', 'keep-alive'].includes(lowerKey)) {\r\n responseHeaders.set(key, value);\r\n }\r\n });\r\n\r\n // Create response\r\n let response = new NextResponse(responseBody, {\r\n status: backendResponse.status,\r\n statusText: backendResponse.statusText,\r\n headers: responseHeaders,\r\n });\r\n\r\n // Allow custom response transformation\r\n if (transformResponse) {\r\n response = await transformResponse(response) as NextResponse;\r\n }\r\n\r\n return response;\r\n } catch (error) {\r\n console.error('[Proxy Error]', error);\r\n \r\n return NextResponse.json(\r\n { \r\n success: false, \r\n message: 'Proxy error: Unable to connect to backend',\r\n error: error instanceof Error ? error.message : 'Unknown error',\r\n },\r\n { status: 502 }\r\n );\r\n }\r\n }\r\n\r\n // Attach config for debugging\r\n handler.config = config;\r\n\r\n return handler;\r\n}\r\n\r\nexport type ProxyHandler = ReturnType<typeof createProxyHandler>;\r\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "next-api-layer",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "Production-grade API layer for Next.js with external JWT backend support",
5
5
  "keywords": [
6
6
  "nextjs",