From 1f0dfcb5ab7779aab7712114c5e34b30c38bef76 Mon Sep 17 00:00:00 2001 From: Xiang Date: Thu, 9 Apr 2026 15:05:05 +0800 Subject: [PATCH 1/6] fix(azure): prevents runtimes errors with the azure-swa preset --- src/presets/azure/runtime/_utils.ts | 20 +++++++++++++++++++- src/presets/azure/runtime/azure-swa.ts | 7 ++++--- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/presets/azure/runtime/_utils.ts b/src/presets/azure/runtime/_utils.ts index 919e959c56..fc9579ca55 100644 --- a/src/presets/azure/runtime/_utils.ts +++ b/src/presets/azure/runtime/_utils.ts @@ -1,4 +1,4 @@ -import type { Cookie } from "@azure/functions"; +import type { Cookie, HttpRequest } from "@azure/functions"; import { parse } from "cookie-es"; export function getAzureParsedCookiesFromHeaders(headers: Headers): Cookie[] { @@ -32,6 +32,24 @@ export function getAzureParsedCookiesFromHeaders(headers: Headers): Cookie[] { return azureCookies; } +export function resolveBaseUrl(req: HttpRequest) { + const forwardedProto = req.headers["x-forwarded-proto"]; + const forwardedHost = req.headers["x-forwarded-host"]; + const host = forwardedHost || req.headers["host"]; + if (host) { + return `${forwardedProto || "http"}://${host}`; + } + const originalUrl = req.headers["x-ms-original-url"]; + if (originalUrl) { + try { + return new URL(originalUrl).origin; + } catch { + // ignore invalid original URL + } + } + return "http://localhost"; +} + function parseNumberOrDate(expires: string) { const expiresAsNumber = parseNumber(expires); if (expiresAsNumber !== undefined) { diff --git a/src/presets/azure/runtime/azure-swa.ts b/src/presets/azure/runtime/azure-swa.ts index de7cf65860..9d4e178da1 100644 --- a/src/presets/azure/runtime/azure-swa.ts +++ b/src/presets/azure/runtime/azure-swa.ts @@ -1,7 +1,7 @@ import "#nitro/virtual/polyfills"; import { parseURL } from "ufo"; import { useNitroApp } from "nitro/app"; -import { getAzureParsedCookiesFromHeaders } from "./_utils.ts"; +import { getAzureParsedCookiesFromHeaders, resolveBaseUrl } from "./_utils.ts"; import type { HttpRequest, HttpResponse, HttpResponseSimple } from "@azure/functions"; @@ -19,8 +19,9 @@ export async function handle(context: { res: HttpResponse }, req: HttpRequest) { url = "/api/" + (req.params.url || ""); } - const request = new Request(url, { + const request = new Request(new URL(url, resolveBaseUrl(req)), { method: req.method || undefined, + headers: new Headers(req.headers), // https://github.com/Azure/azure-functions-nodejs-worker/issues/294 // https://github.com/Azure/azure-functions-host/issues/293 body: req.bufferBody ?? req.rawBody, @@ -32,7 +33,7 @@ export async function handle(context: { res: HttpResponse }, req: HttpRequest) { // (v4) https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-node?tabs=typescript%2Cwindows%2Cazure-cli&pivots=nodejs-model-v4#http-response context.res = { status: response.status, - body: response.body, + body: response.body ? Buffer.from(await response.arrayBuffer()) : undefined, cookies: getAzureParsedCookiesFromHeaders(response.headers), headers: Object.fromEntries( [...response.headers.entries()].filter(([key]) => key !== "set-cookie") From 8e53af329bb6702885488eb59bd9e0b5875ffac2 Mon Sep 17 00:00:00 2001 From: Xiang Date: Thu, 9 Apr 2026 15:05:19 +0800 Subject: [PATCH 2/6] docs(azure): update Azure Static Web Apps documentation for `azure-swa` preset and runtime configurations --- docs/2.deploy/20.providers/azure.md | 32 ++++++++++++++++------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/docs/2.deploy/20.providers/azure.md b/docs/2.deploy/20.providers/azure.md index 9a465a694e..6346c1258b 100644 --- a/docs/2.deploy/20.providers/azure.md +++ b/docs/2.deploy/20.providers/azure.md @@ -6,13 +6,13 @@ **Preset:** `azure-swa` -:read-more{title="Azure Static Web Apps" to="https://azure.microsoft.com/en-us/products/app-service/static"} +:read-more{title="Azure Static Web Apps" to="[https://azure.microsoft.com/en-us/products/app-service/static"}](https://azure.microsoft.com/en-us/products/app-service/static"}) ::note Integration with this provider is possible with [zero configuration](/deploy/#zero-config-providers). :: -[Azure Static Web Apps](https://azure.microsoft.com/en-us/products/app-service/static) are designed to be deployed continuously in a [GitHub Actions workflow](https://docs.microsoft.com/en-us/azure/static-web-apps/github-actions-workflow). By default, Nitro will detect this deployment environment and enable the `azure` preset. +[Azure Static Web Apps](https://azure.microsoft.com/en-us/products/app-service/static) are designed to be deployed continuously in a [GitHub Actions workflow](https://docs.microsoft.com/en-us/azure/static-web-apps/github-actions-workflow). By default, Nitro will detect this deployment environment and enable the `azure-swa` preset. ### Local preview @@ -21,7 +21,7 @@ Install [Azure Functions Core Tools](https://docs.microsoft.com/en-us/azure/azur You can invoke a development environment to preview before deploying. ```bash -NITRO_PRESET=azure npx nypm@latest build +NITRO_PRESET=azure-swa npx nypm@latest build npx @azure/static-web-apps-cli start .output/public --api-location .output/server ``` @@ -32,11 +32,14 @@ Azure Static Web Apps are [configured](https://learn.microsoft.com/en-us/azure/s Nitro automatically generates this configuration file whenever the application is built with the `azure` preset. Nitro will automatically add the following properties based on the following criteria: -| Property | Criteria | Default | -| --- | --- | --- | -| **[platform.apiRuntime](https://learn.microsoft.com/en-us/azure/static-web-apps/configuration#platform)** | Will automatically set to `node:16` or `node:14` depending on your package configuration. | `node:16` | -| **[navigationFallback.rewrite](https://learn.microsoft.com/en-us/azure/static-web-apps/configuration#fallback-routes)** | Is always `/api/server` | `/api/server` | -| **[routes](https://learn.microsoft.com/en-us/azure/static-web-apps/configuration#routes)** | All prerendered routes are added. Additionally, if you do not have an `index.html` file an empty one is created for you for compatibility purposes and also requests to `/index.html` are redirected to the root directory which is handled by `/api/server`. | `[]` | + + +| Property | Criteria | Default | +| ----------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- | +| **[platform.apiRuntime](https://learn.microsoft.com/en-us/azure/static-web-apps/configuration#platform)** | Uses `node:20` or `node:22` when `package.json` `engines.node` (or your current Node major version) matches those supported versions; otherwise falls back to `node:18`. | `node:18` | +| **[navigationFallback.rewrite](https://learn.microsoft.com/en-us/azure/static-web-apps/configuration#fallback-routes)** | Is always `/api/server` | `/api/server` | +| **[routes](https://learn.microsoft.com/en-us/azure/static-web-apps/configuration#routes)** | All prerendered routes are added. Additionally, if you do not have an `index.html` file an empty one is created for you for compatibility purposes and also requests to `/index.html` are redirected to the root directory which is handled by `/api/server`. | `[]` | + ### Custom configuration @@ -50,12 +53,14 @@ When you link your GitHub repository to Azure Static Web Apps, a workflow file i When you are asked to select your framework, select custom and provide the following information: -| Input | Value | -| --- | --- | -| **app_location** | '/' | -| **api_location** | '.output/server' | + +| Input | Value | +| ------------------- | ---------------- | +| **app_location** | '/' | +| **api_location** | '.output/server' | | **output_location** | '.output/public' | + If you miss this step, you can always find the build configuration section in your workflow and update the build configuration: ```yaml [.github/workflows/azure-static-web-apps-.yml] @@ -68,5 +73,4 @@ output_location: '.output/public' That's it! Now Azure Static Web Apps will automatically deploy your Nitro-powered application on push. -If you are using runtimeConfig, you will likely want to configure the corresponding [environment variables on Azure](https://docs.microsoft.com/en-us/azure/static-web-apps/application-settings). - +If you are using runtimeConfig, you will likely want to configure the corresponding [environment variables on Azure](https://docs.microsoft.com/en-us/azure/static-web-apps/application-settings). \ No newline at end of file From 3f929942f888854af52cb0e6460f513cefbaab63 Mon Sep 17 00:00:00 2001 From: Xiang Date: Thu, 9 Apr 2026 15:47:06 +0800 Subject: [PATCH 3/6] docs(azure): Update docs/2.deploy/20.providers/azure.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- docs/2.deploy/20.providers/azure.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/2.deploy/20.providers/azure.md b/docs/2.deploy/20.providers/azure.md index 6346c1258b..ec81bbcb4a 100644 --- a/docs/2.deploy/20.providers/azure.md +++ b/docs/2.deploy/20.providers/azure.md @@ -6,7 +6,7 @@ **Preset:** `azure-swa` -:read-more{title="Azure Static Web Apps" to="[https://azure.microsoft.com/en-us/products/app-service/static"}](https://azure.microsoft.com/en-us/products/app-service/static"}) +:read-more{title="Azure Static Web Apps" to="https://azure.microsoft.com/en-us/products/app-service/static"} ::note Integration with this provider is possible with [zero configuration](/deploy/#zero-config-providers). From c4884ede39469b9f92ccee1f86a05e5bd0a3e01e Mon Sep 17 00:00:00 2001 From: Xiang Date: Thu, 9 Apr 2026 19:31:14 +0800 Subject: [PATCH 4/6] docs(azure): Update docs/2.deploy/20.providers/azure.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- docs/2.deploy/20.providers/azure.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/2.deploy/20.providers/azure.md b/docs/2.deploy/20.providers/azure.md index ec81bbcb4a..568e3fa4f3 100644 --- a/docs/2.deploy/20.providers/azure.md +++ b/docs/2.deploy/20.providers/azure.md @@ -29,7 +29,7 @@ npx @azure/static-web-apps-cli start .output/public --api-location .output/serve Azure Static Web Apps are [configured](https://learn.microsoft.com/en-us/azure/static-web-apps/configuration) using the `staticwebapp.config.json` file. -Nitro automatically generates this configuration file whenever the application is built with the `azure` preset. +Nitro automatically generates this configuration file whenever the application is built with the `azure-swa` preset. Nitro will automatically add the following properties based on the following criteria: From 44b3b805aa7f7264816496520aa4d9e499876e7c Mon Sep 17 00:00:00 2001 From: Xiang Date: Thu, 16 Apr 2026 17:29:16 +0800 Subject: [PATCH 5/6] Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- src/presets/azure/runtime/_utils.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/presets/azure/runtime/_utils.ts b/src/presets/azure/runtime/_utils.ts index fc9579ca55..edf65a4369 100644 --- a/src/presets/azure/runtime/_utils.ts +++ b/src/presets/azure/runtime/_utils.ts @@ -37,7 +37,15 @@ export function resolveBaseUrl(req: HttpRequest) { const forwardedHost = req.headers["x-forwarded-host"]; const host = forwardedHost || req.headers["host"]; if (host) { - return `${forwardedProto || "http"}://${host}`; + const candidate = `${forwardedProto || "http"}://${host}`; + try { + return new URL(candidate).origin; + } catch (error) { + console.warn("[nitro] Invalid Azure SWA forwarded origin", { + candidate, + error, + }); + } } const originalUrl = req.headers["x-ms-original-url"]; if (originalUrl) { @@ -47,6 +55,8 @@ export function resolveBaseUrl(req: HttpRequest) { // ignore invalid original URL } } +} + } return "http://localhost"; } From 1f93ba779c94c2270bb1d24f511a405a7061b03a Mon Sep 17 00:00:00 2001 From: Xiang Date: Thu, 16 Apr 2026 17:39:40 +0800 Subject: [PATCH 6/6] Update src/presets/azure/runtime/_utils.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- src/presets/azure/runtime/_utils.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/presets/azure/runtime/_utils.ts b/src/presets/azure/runtime/_utils.ts index edf65a4369..4551c89167 100644 --- a/src/presets/azure/runtime/_utils.ts +++ b/src/presets/azure/runtime/_utils.ts @@ -55,8 +55,6 @@ export function resolveBaseUrl(req: HttpRequest) { // ignore invalid original URL } } -} - } return "http://localhost"; }