Skip to content

Commit

Permalink
5.1.0 Minor Docs (#10447)
Browse files Browse the repository at this point in the history
Co-authored-by: Sarah Rainsberger <[email protected]>
Co-authored-by: Princesseuh <[email protected]>
Co-authored-by: ascorbic <[email protected]>
Co-authored-by: sarahrainsberger <[email protected]>
Co-authored-by: delucis <[email protected]>
Co-authored-by: Florian Lefebvre <[email protected]>
Co-authored-by: oliverlynch <[email protected]>
Co-authored-by: Matt Kane <[email protected]>
  • Loading branch information
8 people authored Dec 19, 2024
1 parent 763db6c commit 2dcdf53
Show file tree
Hide file tree
Showing 7 changed files with 351 additions and 1 deletion.
1 change: 1 addition & 0 deletions astro.sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ export const sidebar = [
'reference/experimental-flags/svg',
'reference/experimental-flags/client-prerender',
'reference/experimental-flags/content-intellisense',
'reference/experimental-flags/sessions',
],
}),
'reference/legacy-flags',
Expand Down
21 changes: 20 additions & 1 deletion src/content/docs/en/guides/images.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Store your images in the `public/` folder if you want to avoid any processing or
You can also choose to store your images remotely, in a [content management system (CMS)](/en/guides/cms/) or [digital asset management (DAM)](/en/guides/media/) platform.
Astro can fetch your data remotely using APIs or display images from their full URL path.

For extra protection when dealing with external sources, Astro's image components and helper function will only process (e.g. optimize, transform) images from [authorized image sources specified in your configuration](#authorizing-remote-images). Remote images from other sources will be displayed with no processing.
For extra protection when dealing with external sources, Astro's image components and helper function will only process (e.g. optimize, transform) images from [authorized image sources specified in your configuration](#authorizing-remote-images). Remote images from other sources will be displayed with no processing.

## Images in `.astro` files

Expand Down Expand Up @@ -475,6 +475,25 @@ export default defineConfig({
});
```

## Asset Caching

Astro stores processed image assets in a cache directory during site builds for both local and [remote images from authorized sources](/en/guides/images/#authorizing-remote-images). By preserving the cache directory between builds, processed assets are reused, improving build time and bandwidth usage.

The default cache directory is `./node_modules/.astro`, however this can be changed using the [`cacheDir`](/en/reference/configuration-reference/#cachedir) configuration setting.

### Remote Images

Remote images in the asset cache are managed based on [HTTP Caching](https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching), and respect the [Cache-Control header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control) returned by the remote server.
Images are cached if the Cache-Control header allows, and will be used until they are no longer [fresh](https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching#fresh_and_stale_based_on_age).

#### Revalidation

<p><Since v="5.1.0" /></p>

[Revalidation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching#validation) reduces bandwidth usage and build time by checking with the remote server whether an expired cached image is still up-to-date. If the server indicates that the image is still fresh, the cached version is reused, otherwise the image is redownloaded.

Revalidation requires that the remote server send [Last-Modified](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Last-Modified) and/or [Etag (entity tag)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag) headers with its responses. This feature is available for remote servers that support the [If-Modified-Since](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Modified-Since) and [If-None-Match](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-None-Match) headers.

## Community Integrations

There are several third-party [community image integrations](https://astro.build/integrations?search=images) for optimizing and working with images in your Astro project.
2 changes: 2 additions & 0 deletions src/content/docs/en/reference/error-reference.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ The following reference is a complete list of the errors you may encounter while
- [**LocalsNotAnObject**](/en/reference/errors/locals-not-an-object/)<br/>Value assigned to `locals` is not accepted.
- [**LocalsReassigned**](/en/reference/errors/locals-reassigned/)<br/>`locals` must not be reassigned.
- [**AstroResponseHeadersReassigned**](/en/reference/errors/astro-response-headers-reassigned/)<br/>`Astro.response.headers` must not be reassigned.
- [**SessionStorageInitError**](/en/reference/errors/session-storage-init-error/)<br/>Session storage could not be initialized.
- [**SessionStorageSaveError**](/en/reference/errors/session-storage-save-error/)<br/>Session data could not be saved.
- [**MiddlewareCantBeLoaded**](/en/reference/errors/middleware-cant-be-loaded/)<br/>Can't load the middleware.
- [**LocalImageUsedWrongly**](/en/reference/errors/local-image-used-wrongly/)<br/>Local images must be imported.
- [**AstroGlobUsedOutside**](/en/reference/errors/astro-glob-used-outside/)<br/>Astro.glob() used outside of an Astro file.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
# NOTE: This file is auto-generated from 'scripts/error-docgen.mjs'
# Do not make edits to it directly, they will be overwritten.
# Instead, change this file: https://github.com/withastro/astro/blob/main/packages/astro/src/core/errors/errors-data.ts
# Translators, please remove this note and the <DontEditWarning/> component.

title: Session storage could not be initialized.
i18nReady: true
githubURL: https://github.com/withastro/astro/blob/main/packages/astro/src/core/errors/errors-data.ts
---
import DontEditWarning from '~/components/DontEditWarning.astro'

<DontEditWarning />


> **SessionStorageInitError**: Error when initializing session storageDRIVER ? ` WITH DRIVER ${DRIVER` : ''}. ERROR ?? ''
## What went wrong?
Thrown when the session storage could not be initialized.

**See Also:**
- [experimental.session](/en/reference/experimental-flags/sessions/)


Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
# NOTE: This file is auto-generated from 'scripts/error-docgen.mjs'
# Do not make edits to it directly, they will be overwritten.
# Instead, change this file: https://github.com/withastro/astro/blob/main/packages/astro/src/core/errors/errors-data.ts
# Translators, please remove this note and the <DontEditWarning/> component.

title: Session data could not be saved.
i18nReady: true
githubURL: https://github.com/withastro/astro/blob/main/packages/astro/src/core/errors/errors-data.ts
---
import DontEditWarning from '~/components/DontEditWarning.astro'

<DontEditWarning />


> **SessionStorageSaveError**: Error when saving session dataDRIVER ? ` WITH DRIVER ${DRIVER` : ''}. ERROR ?? ''
## What went wrong?
Thrown when the session data could not be saved.

**See Also:**
- [experimental.session](/en/reference/experimental-flags/sessions/)


237 changes: 237 additions & 0 deletions src/content/docs/en/reference/experimental-flags/sessions.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
---
title: Experimental sessions
sidebar:
label: Sessions
i18nReady: true
---

import Since from '~/components/Since.astro';
import ReadMore from '~/components/ReadMore.astro';

<p>

**Type:** `SessionConfig`<br />
**Default:** `undefined`<br />

<Since v="5.1.0" />
</p>

Sessions are used to store user state between requests for [on-demand rendered pages](/en/guides/on-demand-rendering/).

This experimental feature allows you to store and access items such as login status, shopping cart contents, or other user-specific data:

```astro title="src/components/CartButton.astro" {3}
---
export const prerender = false; // Not needed in 'server' mode
const cart = await Astro.session.get('cart');
---
<a href="/checkout">🛒 {cart?.length ?? 0} items</a>
```

Sessions rely on a [configurable session `driver`](#enabling-experimental-sessions) to store data on the `session` object. A [session cookie](#cookies) stores an identifying session ID.

The [`session` object](#sessions-api) allow you to interact with the stored user state (e.g. add items to a shopping cart) and the session ID (e.g. delete the session ID cookie when logging out).

## Enabling experimental sessions

In this early release of `experimental.sessions`, Astro's official server adapters have not yet been updated to provide a default session driver based on the platform's default storage feature. Until these are built in, you will have to specify a `driver` yourself in the `experimental.sessions` configuration object in addition to [adding an adapter](/en/guides/on-demand-rendering/#add-an-adapter).

The following sections show the recommended drivers for each adapter. (These will be automatically configured for you in the stable release of this feature.) Alternatively, you can specify [any supported driver from unstorage](https://unstorage.unjs.io/drivers/).

### Configuring sessions with the Node adapter

The Node adapter is compatible with the the [filesystem driver](https://unstorage.unjs.io/drivers/fs). Note that this cannot be used in serverless environments as they have no shared filesystem.

```js title="astro.config.mjs" ins={6}
{
adapter: node({ mode: 'standalone' }),
experimental: {
session: {
// Required: the name of the unstorage driver
driver: "fs",
},
},
}
```

### Configuring a session driver for other adapters

Choose the [unstorage `driver` name](https://unstorage.unjs.io/drivers/) that corresponds to the storage feature provided by your hosting platform, such as the [Netlify Blobs driver (`netlify-blobs`)](https://unstorage.unjs.io/drivers/netlify), the [Cloudflare KV driver (`cloudflare-kv-binding`)](https://unstorage.unjs.io/drivers/cloudflare) or the [Deno KV driver (`deno-kv`)](https://unstorage.unjs.io/drivers/deno). You can also use a cross-platform driver such as [Upstash](https://unstorage.unjs.io/drivers/upstash) or [Redis](https://unstorage.unjs.io/drivers/redis).

:::note
Some drivers may need extra packages to be installed. For example, the `netlify-blobs` driver requires the `@netlify/blobs` package, and Upstash requires the `@upstash/redis` package. Some drivers may also require environment variables or credentials to be set.

<ReadMore>See [the unstorage driver docs](https://unstorage.unjs.io/drivers) for more information.</ReadMore>
:::

### Driver options

You can also pass any available options to the unstorage driver in a separate `session.options` object. The following example configures the [Netlify Blobs](https://unstorage.unjs.io/drivers/netlify) driver while also providing a `name` and specifying a `consistency` mode:

```js title="astro.config.mjs" ins={7-11}
{
experimental: {
adapter: netlify(),
session: {
// The name of the unstorage driver is camelCase
driver: "netlify-blobs",
options: {
name: 'astro-sessions',
// Sessions need strong consistency
consistency: 'strong',
}
},
},
}
```

## Using sessions

Once you have configured a driver, you can use the `session` object to interact with the session. This object is accessible as `Astro.session` in your Astro components and pages and on the `context` object in API endpoints, middleware and actions. The API is the same in all cases.

In most cases you will only need to use [`Astro.session.get()`](#sessionget) and [`Astro.session.set()`](#sessionset). For other available methods, see the [API section](#sessions-api).

### Astro components and pages

In `.astro` components and pages, you can access the session object via the global `Astro` object. For example, to display the number of items in a shopping cart:

```astro title="src/components/CartButton.astro" "Astro.session"
---
export const prerender = false; // Not needed in 'server' mode
const cart = await Astro.session.get('cart');
---
<a href="/checkout">🛒 {cart?.length ?? 0} items</a>
```

### API endpoints

In API endpoints, the session object is available on the `context` object. For example, to add an item to a shopping cart:

```ts title="src/pages/api/addToCart.ts" "context.session"
import type { APIContext } from "astro";

export async function POST(req: Request, context: APIContext) {
const cart = await context.session.get("cart");
cart.push(req.body.item);
await context.session.set("cart", cart);
return Response.json(cart);
}
```

### Actions

In actions, the session object is available on the `context` object. For example, to add an item to a shopping cart:

```ts title="src/actions/addToCart.ts" "context.session"
import { defineAction } from "astro:actions";
import { z } from "astro:schema";

export const server = {
addToCart: defineAction({
input: z.object({ productId: z.string() }),
handler: async (input, context) => {
const cart = await context.session.get("cart");
cart.push(input.productId);
await context.session.set("cart", cart);
return cart;
},
}),
};
```

### Middleware

:::note
Sessions are not currently supported in edge middleware.
:::

In middleware, the session object is available on the `context` object. For example, to set the last visit time in the session:

```ts title="src/middleware.ts" "context.session"
import { defineMiddleware } from 'astro:middleware';

export const onRequest = defineMiddleware(async (context, next) => {
context.session.set('lastVisit', new Date());
return next();
});
```

## Cookies

Sessions are generated when first accessed, and a session ID cookie is set in the response. No actual user data is stored in the cookie – just an ID that is used to identify a user's session. The session can be regenerated at any time with [`Astro.session.regenerate()`](#sessionregenerate), and destroyed with [`Astro.session.destroy()`](#sessiondestroy).

### `session.cookie`

<p>

**Type:** `string` | `object`<br />
**Default:** `undefined`<br />

</p>

An optional property to set cookie options. The `cookie.name` property can be automatically set by providing a string. To configure additional options, provide an object.

```js title="astro.config.mjs" {5} ins={7-10}
{
experimental: {
session: {
// If set to a string, this will be used as the cookie name
// cookie: "my-session-id",
// If set to an object, this will allow advanced options to be set
cookie: {
name: "my-session-id"
sameSite: "Strict",
},
}
}
}
```

## Sessions API

The session object is available in all Astro contexts, including components, actions, and API endpoints. In components, it is accessed via the global `Astro` object, and in actions and API endpoints it is available on the `context` object. The API is the same in all cases.

Values are serialized and deserialized using [devalue](https://github.com/Rich-Harris/devalue), which is the same library used by content layer and actions. This means that supported types are the same, and include strings, numbers, `Date`, `Map`, `Set`, `URL`, arrays and plain objects.


### `session.get()`

<p>

**Type**: `(key: string) => Promise<any>`
</p>

Returns the value of the given key in the session. If the key does not exist, it returns `undefined`.

### `session.set()`

<p>

**Type**: `(key: string, value: any, options?: { ttl: number }) => void`
</p>

Sets the value of the given key in the session. The value can be any serializable type.

### `session.regenerate()`

<p>

**Type**: `() => void`
</p>

Regenerates the session ID. Best practice is to call this when a user logs in or escalates their privileges, to prevent session fixation attacks.

### `session.destroy()`

<p>

**Type**: `() => void`
</p>

Destroys the session, deleting the cookie and the object from the backend. This should be called when a user logs out or their session is otherwise invalidated.

## Further reading

For full details and to give feedback on this experimental API, see [the Sessions RFC](https://github.com/withastro/roadmap/blob/sessions/proposals/0054-sessions.md).
43 changes: 43 additions & 0 deletions src/content/docs/en/reference/modules/astro-actions.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -301,3 +301,46 @@ export const onRequest = defineMiddleware(async (context, next) => {
</p>

`deserializeActionResult()` will reverse the effect of `serializeActionResult()` and return an action result to its original state. This is useful to access the `data` and `error` objects on a serialized action result.

### `getActionPath()`

<p>

**Type:** `(action: ActionClient<any, any, any>) => string`
<Since v="5.1.0" />
</p>

The `getActionPath()` utility accepts an action and returns a URL path so you can execute an action call as a `fetch()` operation directly. This allows you to provide details such as custom headers when you call your action. Then, you can [handle the custom-formatted returned data](/en/guides/actions/#handling-returned-data) as needed, just as if you had called an action directly.

This example shows how to call a defined `like` action passing the `Authorization` header and the [`keepalive`](https://developer.mozilla.org/en-US/docs/Web/API/Request/keepalive) option:

```astro title="src/components/my-component.astro" {8,11}
<script>
import { actions, getActionPath } from 'astro:actions'
await fetch(getActionPath(actions.like), {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer YOUR_TOKEN'
},
body: JSON.stringify({ id: 'YOUR_ID' }),
keepalive: true
})
</script>
```

This example shows how to call the same `like` action using the [`sendBeacon`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon) API:

```astro title="src/components/my-component.astro" {5} "sendBeacon"
<script>
import { actions, getActionPath } from 'astro:actions'
navigator.sendBeacon(
getActionPath(actions.like),
new Blob([JSON.stringify({ id: 'YOUR_ID' })], {
type: 'application/json'
})
)
</script>
```

0 comments on commit 2dcdf53

Please sign in to comment.