An open API service indexing awesome lists of open source software.

https://github.com/maxiviper117/example-asynclocalstorage-sveltekit


https://github.com/maxiviper117/example-asynclocalstorage-sveltekit

asynclocalstorage example sveltekit

Last synced: 21 days ago
JSON representation

Awesome Lists containing this project

README

          

# example-AsyncLocalStorage-sveltekit

This project demonstrates how to use Node.js' AsyncLocalStorage within a SvelteKit application to manage per-request data without the need for passing data manually through each load function.

## Overview

In this example, the AsyncLocalStorage is initialized in the server hooks and is used to store the authenticated user and other request-specific data.

## How AsyncLocalStorage Works

AsyncLocalStorage provides a way to store data throughout the lifetime of an asynchronous operation. It allows you to create a storage context that is unique to each asynchronous execution chain. This is particularly useful in web applications where you need to maintain request-specific data across various asynchronous operations without explicitly passing it around.

### Key Concepts

1. **Context Creation**: A new context is created at the beginning of each request using `asyncLocalStorage.run()`. This context is a Map object that can store key-value pairs.

2. **Setting Data**: Data can be stored in the context using the `setRequestData` function. This function retrieves the current context and sets the specified key-value pair.

3. **Getting Data**: Data can be retrieved from the context using the `getRequestData` function. This function retrieves the current context and gets the value associated with the specified key.

## Advantages Over event.locals and Load Function Waterfalls

1. **Simplified Data Propagation**: With AsyncLocalStorage, data such as the authenticated user is set once during the request lifecycle and then accessed anywhere within that lifecycle, eliminating the need to manually pass values through `event.locals` in each load function.

2. **Avoiding Load Function Waterfalls**: Instead of using `await parent()` in nested load functions, which can lead to complex chaining of asynchronous calls, AsyncLocalStorage allows direct access to the context data, thereby reducing boilerplate code.

3. **Centralized Context Management**: Managing request-specific data with AsyncLocalStorage centralizes the data access layer. This not only simplifies the code by avoiding repetitive data passing but also minimizes potential errors in distributed data flow.

## Code Snippets

### 1. Initialization in hooks

The following snippet shows how the context is created and used in the `handle` hook to store the authenticated user:

```typescript
// src/hooks.server.ts
import { getUserFromToken } from '$lib/server/auth';
import { runWithContext, setRequestData } from '$lib/server/requestContext';

export const handle = async ({ event, resolve }) => {
return runWithContext(async () => {
const token = event.cookies.get('auth_token');

if (token) {
const user = await getUserFromToken(token);
setRequestData('user', user);
} else {
console.warn('No valid auth token found');
setRequestData('user', null);
}

return await resolve(event);
});
};
```

### 2. Context Management with AsyncLocalStorage

This snippet from `src/lib/server/requestContext.ts` demonstrates how AsyncLocalStorage is used to maintain a per-request store:

```typescript
// src/lib/server/requestContext.ts
import { AsyncLocalStorage } from 'node:async_hooks';

const asyncLocalStorage = new AsyncLocalStorage>();

export function runWithContext(fn: () => T) {
return asyncLocalStorage.run(new Map(), fn);
}

export function setRequestData(key: string, value: T) {
const store = asyncLocalStorage.getStore();
if (store) {
store.set(key, value);
} else {
console.error('AsyncLocalStorage store is not available');
}
}

export function getRequestData(key: string): T | undefined {
const store = asyncLocalStorage.getStore();
return store ? store.get(key) : undefined;
}
```

### 3. Accessing the Stored Data

The user information stored in AsyncLocalStorage can be accessed from other modules, such as in the authentication helper:

```typescript
// src/lib/server/authUser.ts
import { getRequestData } from '$lib/server/requestContext';
import type { AuthUser } from '$lib/types/authUser';

export function getAuthenticatedUser() {
return getRequestData('user');
}
```

> [!WARNING]
> Node.js' AsyncLocalStorage is only available on the server. It cannot be used in client-side code.

## Getting Started

1. Install dependencies with your package manager (e.g., `pnpm install`).
2. Run the development server with `pnpm dev`.
3. Explore the code in the `src/hooks.server.ts` and `src/lib/server/` directories to see how AsyncLocalStorage is integrated.