{"version":3,"file":"multipleProxies.mjs","names":[],"sources":["../../../src/proxy/multipleProxies.ts"],"sourcesContent":["import {\n  type NextFetchEvent,\n  type NextRequest,\n  NextResponse,\n} from 'next/server';\n\n/**\n * Utility to combine multiple Next.js proxies into one.\n *\n * It executes proxies in order, passing each result as the `response` argument\n * to the next proxy. Routing instructions (redirects / rewrites) and custom\n * response headers are merged across the entire chain, so a later proxy that\n * returns `NextResponse.next()` does not accidentally discard a rewrite set by\n * an earlier proxy.\n *\n * @example\n * import { multipleProxies, intlayerProxy } from \"next-intlayer/proxy\";\n * import { NextResponse } from \"next/server\";\n *\n * const authMiddleware = (req: NextRequest) => {\n *   if (!req.cookies.get(\"token\")) {\n *     return NextResponse.redirect(new URL(\"/login\", req.url));\n *   }\n *   return NextResponse.next();\n * };\n *\n * export default multipleProxies([\n *   intlayerProxy,\n *   authMiddleware,\n * ]);\n *\n * @param proxies - An array of proxy functions to execute in order.\n * @returns A single proxy function that runs all provided proxies.\n */\nexport const multipleProxies =\n  (\n    proxies: ((\n      req: NextRequest,\n      event?: NextFetchEvent,\n      response?: NextResponse\n    ) => NextResponse | Promise<NextResponse>)[]\n  ) =>\n  async (req: NextRequest, event?: NextFetchEvent, response?: NextResponse) => {\n    // Snapshots of each proxy's response headers, collected in order.\n    const proxyHeaders: Headers[] = [];\n    let finalStatus = 200;\n    let redirectLocation: string | null = null;\n\n    // Each proxy receives the previous proxy's result so it can inspect or\n    // augment it. Start with the caller-supplied response (or a plain next()).\n    let currentResponse: NextResponse = response ?? NextResponse.next();\n\n    for (const proxy of proxies) {\n      const result = await proxy(req, event, currentResponse);\n\n      // Bail immediately on server errors.\n      if (result.status >= 500) {\n        return result;\n      }\n\n      // Track the strongest redirect in the chain.\n      if (result.status >= 300 && result.status < 400) {\n        finalStatus = result.status;\n        const location = result.headers.get('location');\n        if (location) redirectLocation = location;\n      }\n\n      // Snapshot headers *now* to avoid later mutations to the same object\n      // corrupting already-recorded entries from earlier proxies.\n      proxyHeaders.push(new Headers(result.headers));\n      currentResponse = result;\n    }\n\n    // ── Merge all collected headers ───────────────────────────────────────────\n\n    // mergedHeaders: response headers visible to the browser / Next.js routing.\n    const mergedHeaders = new Headers();\n    // transmittedHeaders: request headers forwarded to the next route handler.\n    const transmittedHeaders = new Headers(req.headers);\n\n    proxyHeaders.forEach((headers) => {\n      for (const [key, value] of headers.entries()) {\n        // Routing headers must not be concatenated — last writer wins.\n        if (\n          key === 'x-middleware-rewrite' ||\n          key === 'x-middleware-request-redirect'\n        ) {\n          mergedHeaders.set(key, value);\n        } else {\n          mergedHeaders.append(key, value);\n        }\n\n        // x-middleware-request-<name> → forwarded as <name> to route handlers.\n        if (key.startsWith('x-middleware-request-')) {\n          const stripped = key.slice('x-middleware-request-'.length);\n          transmittedHeaders.set(stripped, value);\n        }\n      }\n    });\n\n    // ── Construct the final response ──────────────────────────────────────────\n\n    const redirectHeader = mergedHeaders.get('x-middleware-request-redirect');\n    const rewriteHeader = mergedHeaders.get('x-middleware-rewrite');\n\n    let finalResponse: NextResponse;\n\n    if (redirectHeader || redirectLocation) {\n      const rawRedirect = (redirectHeader ?? redirectLocation) as string;\n      const target = new URL(rawRedirect, req.url);\n      // Prevent open redirect: strip to same-origin path/search/hash if the\n      // resolved origin differs from the request origin.\n      const safeTarget =\n        target.origin === req.nextUrl.origin\n          ? target\n          : new URL(\n              `${target.pathname}${target.search}${target.hash}`,\n              req.url\n            );\n\n      finalResponse = NextResponse.redirect(safeTarget, {\n        status: finalStatus >= 300 ? finalStatus : 307,\n      });\n    } else if (rewriteHeader) {\n      finalResponse = NextResponse.rewrite(new URL(rewriteHeader, req.url), {\n        request: { headers: transmittedHeaders },\n      });\n    } else {\n      finalResponse = NextResponse.next({\n        request: { headers: transmittedHeaders },\n      });\n    }\n\n    // Copy all accumulated custom response headers onto the final response,\n    // skipping internal Next.js routing headers (already handled above).\n    mergedHeaders.forEach((value, key) => {\n      if (\n        key !== 'x-middleware-rewrite' &&\n        key !== 'x-middleware-request-redirect' &&\n        !key.startsWith('x-middleware-request-') &&\n        key !== 'location'\n      ) {\n        finalResponse.headers.set(key, value);\n      }\n    });\n\n    return finalResponse;\n  };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCA,MAAa,mBAET,YAMF,OAAO,KAAkB,OAAwB,aAA4B;CAE3E,MAAM,eAA0B,CAAC;CACjC,IAAI,cAAc;CAClB,IAAI,mBAAkC;CAItC,IAAI,kBAAgC,YAAY,aAAa,KAAK;CAElE,KAAK,MAAM,SAAS,SAAS;EAC3B,MAAM,SAAS,MAAM,MAAM,KAAK,OAAO,eAAe;EAGtD,IAAI,OAAO,UAAU,KACnB,OAAO;EAIT,IAAI,OAAO,UAAU,OAAO,OAAO,SAAS,KAAK;GAC/C,cAAc,OAAO;GACrB,MAAM,WAAW,OAAO,QAAQ,IAAI,UAAU;GAC9C,IAAI,UAAU,mBAAmB;EACnC;EAIA,aAAa,KAAK,IAAI,QAAQ,OAAO,OAAO,CAAC;EAC7C,kBAAkB;CACpB;CAKA,MAAM,gBAAgB,IAAI,QAAQ;CAElC,MAAM,qBAAqB,IAAI,QAAQ,IAAI,OAAO;CAElD,aAAa,SAAS,YAAY;EAChC,KAAK,MAAM,CAAC,KAAK,UAAU,QAAQ,QAAQ,GAAG;GAE5C,IACE,QAAQ,0BACR,QAAQ,iCAER,cAAc,IAAI,KAAK,KAAK;QAE5B,cAAc,OAAO,KAAK,KAAK;GAIjC,IAAI,IAAI,WAAW,uBAAuB,GAAG;IAC3C,MAAM,WAAW,IAAI,MAAM,EAA8B;IACzD,mBAAmB,IAAI,UAAU,KAAK;GACxC;EACF;CACF,CAAC;CAID,MAAM,iBAAiB,cAAc,IAAI,+BAA+B;CACxE,MAAM,gBAAgB,cAAc,IAAI,sBAAsB;CAE9D,IAAI;CAEJ,IAAI,kBAAkB,kBAAkB;EAEtC,MAAM,SAAS,IAAI,IADE,kBAAkB,kBACH,IAAI,GAAG;EAG3C,MAAM,aACJ,OAAO,WAAW,IAAI,QAAQ,SAC1B,SACA,IAAI,IACF,GAAG,OAAO,WAAW,OAAO,SAAS,OAAO,QAC5C,IAAI,GACN;EAEN,gBAAgB,aAAa,SAAS,YAAY,EAChD,QAAQ,eAAe,MAAM,cAAc,IAC7C,CAAC;CACH,OAAO,IAAI,eACT,gBAAgB,aAAa,QAAQ,IAAI,IAAI,eAAe,IAAI,GAAG,GAAG,EACpE,SAAS,EAAE,SAAS,mBAAmB,EACzC,CAAC;MAED,gBAAgB,aAAa,KAAK,EAChC,SAAS,EAAE,SAAS,mBAAmB,EACzC,CAAC;CAKH,cAAc,SAAS,OAAO,QAAQ;EACpC,IACE,QAAQ,0BACR,QAAQ,mCACR,CAAC,IAAI,WAAW,uBAAuB,KACvC,QAAQ,YAER,cAAc,QAAQ,IAAI,KAAK,KAAK;CAExC,CAAC;CAED,OAAO;AACT"}