Skip to content

Commit 56b0b99

Browse files
Merge branch 'main' into armand/satteri-recipes
2 parents ca27346 + 0bdebeb commit 56b0b99

21 files changed

Lines changed: 2105 additions & 230 deletions

src/components/NavGrid/CardsNav.astro

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@ export interface Props {
2222
const { links, size, class: classes } = Astro.props as Props;
2323
2424
const currentPage = new URL(Astro.request.url).pathname;
25+
// Fallback pages can render English content while their navigation labels use the page locale.
26+
const textDirection = Astro.locals.t.dir();
2527
---
2628

27-
<section class:list={['cards-nav', classes, 'not-content']}>
29+
<section dir={textDirection} class:list={['cards-nav', classes, 'not-content']}>
2830
<slot />
2931
<Grid {size}>
3032
{

src/content/docs/en/reference/modules/astro-app.mdx

Lines changed: 135 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,13 @@ Returns an [`App` instance](#the-app-instance) that includes methods to work wit
4242

4343
```js
4444
import { createApp } from "astro/app/entrypoint";
45-
import http from "http";
4645

4746
const app = createApp();
4847

49-
addEventListener("fetch", event => {
50-
event.respondWith(
51-
app.render(event.request)
52-
);
48+
addEventListener("fetch", (event) => {
49+
if (event instanceof FetchEvent) {
50+
event.respondWith(app.render(event.request));
51+
}
5352
});
5453
```
5554

@@ -90,8 +89,15 @@ The `createApp()` function returns a class instance with the following methods.
9089

9190
Calls the Astro page that matches the [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request), renders it, and returns a promise to a [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) object. This also works for [API routes](/en/guides/endpoints/#server-endpoints-api-routes) that do not render pages.
9291

93-
```js
94-
const response = await app.render(request);
92+
```ts {6}
93+
import { createApp } from "astro/app/entrypoint";
94+
95+
const app = createApp();
96+
97+
export const handle = async (request: Request) => {
98+
const response = await app.render(request);
99+
return response;
100+
};
95101
```
96102

97103
##### `app.match()`
@@ -103,33 +109,47 @@ const response = await app.render(request);
103109

104110
Determines whether a request is matched by the Astro app's routing rules.
105111

106-
```js
107-
if(app.match(request)) {
108-
const response = await app.render(request);
109-
}
112+
```ts {6,11}
113+
import { createApp } from "astro/app/entrypoint";
114+
115+
const app = createApp();
116+
117+
export const handle = async (request: Request) => {
118+
if (app.match(request)) {
119+
const response = await app.render(request);
120+
return response;
121+
} else {
122+
return new Response("Not Found", { status: 404 });
123+
}
124+
};
110125
```
111126

112127
You can usually call `app.render(request)` without using `.match` because Astro handles 404s if you provide a `404.astro` file. Use `app.match(request)` if you want to handle 404s in a different way.
113128

114129
By default, prerendered routes aren't returned, even if they are matched. You can change this behavior by using `true` as the second argument.
115130

116-
##### `app.getAdapterLogger()`
131+
##### `app.adapterLogger`
117132

118133
<p>
119134

120-
**Type:** <code>() => <a href="/en/reference/integrations-reference/#astrointegrationlogger">AstroIntegrationLogger</a></code><br />
121-
<Since v="v3.0.0" />
135+
**Type:** [AstroIntegrationLogger](/en/reference/integrations-reference/#astrointegrationlogger)<br />
136+
<Since v="v6.2.0" />
122137
</p>
123138

124139
Returns an [instance of the Astro logger](/en/reference/integrations-reference/#astrointegrationlogger) available to the adapter's runtime environment.
125140

126-
```js "logger"
127-
const logger = app.getAdapterLogger();
128-
try {
129-
/* Some logic that can throw */
130-
} catch {
131-
logger.error("Your custom error message using Astro logger.");
132-
}
141+
```ts {9}
142+
import { createApp } from "astro/app/entrypoint";
143+
144+
const app = createApp();
145+
146+
export const handle = async () => {
147+
try {
148+
/* Some logic that can throw */
149+
} catch {
150+
app.adapterLogger.error("Your custom error message using Astro logger.");
151+
}
152+
};
133153
```
134154

135155
##### `app.getAllowedDomains()`
@@ -164,10 +184,18 @@ Returns a generator that yields individual cookie header values from a `Response
164184

165185
The following example appends a `Set-Cookie` header for each header obtained from a response:
166186

167-
```js
168-
for (const setCookieHeader of app.setCookieHeaders(response)) {
169-
response.headers.append('Set-Cookie', setCookieHeader);
170-
}
187+
```ts {7-9}
188+
import { createApp } from "astro/app/entrypoint";
189+
190+
const app = createApp();
191+
192+
export const handle = async (request: Request) => {
193+
const response = await app.render(request);
194+
for (const setCookieHeader of app.setCookieHeaders(response)) {
195+
response.headers.append("Set-Cookie", setCookieHeader);
196+
}
197+
return response;
198+
};
171199
```
172200

173201
## Imports from `astro/app/node`
@@ -195,7 +223,7 @@ Converts a NodeJS `IncomingMessage` into a standard `Request` object. An optiona
195223

196224
The following example creates a `Request` and passes it to [`app.render()`](#apprender):
197225

198-
```js {8}
226+
```js {2,8}
199227
import { createApp } from "astro/app/entrypoint";
200228
import { createRequest } from "astro/app/node";
201229
import { createServer } from "node:http";
@@ -205,7 +233,7 @@ const app = createApp();
205233
const server = createServer(async (req, res) => {
206234
const request = createRequest(req);
207235
const response = await app.render(request);
208-
})
236+
});
209237
```
210238

211239
### `writeResponse()`
@@ -220,7 +248,7 @@ Streams a web-standard `Response` into a NodeJS server response. This function t
220248

221249
The following example creates a `Request`, passes it to [`app.render()`](#apprender), and writes the response:
222250

223-
```js {10}
251+
```js {10} /(?<=\s)writeResponse(?=\s)/
224252
import { createApp } from "astro/app/entrypoint";
225253
import { createRequest, writeResponse } from "astro/app/node";
226254
import { createServer } from "node:http";
@@ -231,7 +259,7 @@ const server = createServer(async (req, res) => {
231259
const request = createRequest(req);
232260
const response = await app.render(request);
233261
await writeResponse(response, res);
234-
})
262+
});
235263
```
236264

237265
## `astro/app` types
@@ -265,8 +293,15 @@ Whether or not to automatically add all cookies written by [`Astro.cookie.set()`
265293

266294
When set to `true`, they will be added to the `Set-Cookie` header of the response as comma-separated key-value pairs. You can use the standard `response.headers.getSetCookie()` API to read them individually.
267295

268-
```js
269-
const response = await app.render(request, { addCookieHeader: true });
296+
```ts {6}
297+
import { createApp } from "astro/app/entrypoint";
298+
299+
const app = createApp();
300+
301+
export const handle = async (request: Request) => {
302+
const response = await app.render(request, { addCookieHeader: true });
303+
return response;
304+
};
270305
```
271306

272307
#### `RenderOptions.clientAddress`
@@ -281,9 +316,16 @@ The client IP address that will be made available as [`Astro.clientAddress`](/en
281316

282317
The example below reads the `x-forwarded-for` header and passes it as `clientAddress`. This value becomes available to the user as `Astro.clientAddress`.
283318

284-
```js "clientAddress"
285-
const clientAddress = request.headers.get("x-forwarded-for");
286-
const response = await app.render(request, { clientAddress });
319+
```ts "clientAddress"
320+
import { createApp } from "astro/app/entrypoint";
321+
322+
const app = createApp();
323+
324+
export const handle = async (request: Request) => {
325+
const clientAddress = request.headers.get("x-forwarded-for") ?? undefined;
326+
const response = await app.render(request, { clientAddress });
327+
return response;
328+
};
287329
```
288330

289331
#### `RenderOptions.locals`
@@ -297,16 +339,23 @@ The [`context.locals` object](/en/reference/api-reference/#locals) used to store
297339

298340
The example below reads a header named `x-private-header`, attempts to parse it as an object, and passes it to `locals`, which can then be passed to any [middleware function](/en/guides/middleware/).
299341

300-
```js "locals"
301-
const privateHeader = request.headers.get("x-private-header");
302-
let locals = {};
303-
try {
304-
if (privateHeader) {
305-
locals = JSON.parse(privateHeader);
342+
```ts "locals"
343+
import { createApp } from "astro/app/entrypoint";
344+
345+
const app = createApp();
346+
347+
export const handle = async (request: Request) => {
348+
const privateHeader = request.headers.get("x-private-header");
349+
let locals = {};
350+
try {
351+
if (privateHeader) {
352+
locals = JSON.parse(privateHeader);
353+
}
354+
} finally {
355+
const response = await app.render(request, { locals });
356+
return response;
306357
}
307-
} finally {
308-
const response = await app.render(request, { locals });
309-
}
358+
};
310359
```
311360

312361
#### `RenderOptions.prerenderedErrorPageFetch()`
@@ -325,23 +374,30 @@ This is used to override the default `fetch()` behavior, for example, when `fetc
325374
The following example reads `500.html` and `404.html` from disk instead of performing an HTTP call:
326375

327376
```ts "prerenderedErrorPageFetch"
328-
return app.render(request, {
329-
prerenderedErrorPageFetch: async (url: string): Promise<Response> => {
330-
if (url.includes("/500")) {
331-
const content = await fs.promises.readFile("500.html", "utf-8");
377+
import { createApp } from "astro/app/entrypoint";
378+
import fs from "node:fs";
379+
380+
const app = createApp();
381+
382+
export const handle = async (request: Request) => {
383+
return app.render(request, {
384+
prerenderedErrorPageFetch: async (url: string): Promise<Response> => {
385+
if (url.includes("/500")) {
386+
const content = await fs.promises.readFile("500.html", "utf-8");
387+
return new Response(content, {
388+
status: 500,
389+
headers: { "Content-Type": "text/html" },
390+
});
391+
}
392+
393+
const content = await fs.promises.readFile("404.html", "utf-8");
332394
return new Response(content, {
333-
status: 500,
395+
status: 404,
334396
headers: { "Content-Type": "text/html" },
335397
});
336-
}
337-
338-
const content = await fs.promises.readFile("404.html", "utf-8");
339-
return new Response(content, {
340-
status: 404,
341-
headers: { "Content-Type": "text/html" },
342-
});
343-
}
344-
});
398+
},
399+
});
400+
};
345401
```
346402

347403
If not provided, Astro will fallback to its default behavior for fetching error pages.
@@ -360,14 +416,18 @@ Adapters can pass this through to let runtime cache providers schedule work such
360416

361417
The following example forwards a runtime's `waitUntil()` implementation to [`app.render()`](#apprender) in an [adapter server entrypoint](/en/reference/adapter-reference/#building-a-server-entrypoint):
362418

363-
```js {8}
364-
import { createApp } from 'astro/app/entrypoint';
419+
```ts {12}
420+
import { createApp } from "astro/app/entrypoint";
421+
422+
// Context is provided by the runtime. This is a minimal example of what it can look like.
423+
type Context = {
424+
waitUntil(promise: Promise<any>): void;
425+
};
365426

366427
const app = createApp();
367428

368-
export async function handler(event, context) {
369-
// ...
370-
return app.render(event.request, {
429+
export async function handler(request: Request, context: Context) {
430+
return app.render(request, {
371431
waitUntil: context.waitUntil.bind(context),
372432
});
373433
}
@@ -383,12 +443,18 @@ export async function handler(event, context) {
383443

384444
Defines the information about a route. This is useful when you already know the route to render. Doing so will bypass the internal call to [`app.match()`](#appmatch) to determine the route to render.
385445

386-
```js "routeData"
387-
const routeData = app.match(request);
388-
if (routeData) {
389-
return app.render(request, { routeData });
390-
} else {
391-
/* adapter-specific 404 response */
392-
return new Response(..., { status: 404 });
446+
```ts "routeData"
447+
import { createApp } from "astro/app/entrypoint";
448+
449+
const app = createApp();
450+
451+
export async function handler(request: Request) {
452+
const routeData = app.match(request);
453+
if (routeData) {
454+
return app.render(request, { routeData });
455+
} else {
456+
/* adapter-specific 404 response */
457+
return new Response("Not Found", { status: 404 });
458+
}
393459
}
394460
```

0 commit comments

Comments
 (0)