npm package: @revas-hq/kit-context
Description: The `@revas-hq/kit-context` package provides an immutable, chained context implementation inspired by Go's `context.Context`. It allows passing request-scoped values down a call stack or component hierarchy without explicit prop drilling.
Latest version: 0.0.16

# Revas Kit: Context (`@revas-hq/kit-context`)

The `@revas-hq/kit-context` package provides an immutable, chained context implementation inspired by Go's `context.Context`. It allows passing request-scoped values down a call stack or component hierarchy without explicit prop drilling.

This pattern is central to other Revas Kit packages for sharing data like authentication tokens, trace IDs, or request-specific configurations between middleware, endpoints, and transport handlers.

## Installation

Install the package using npm or yarn:

```sh
npm install @revas-hq/kit-context
# or
yarn add @revas-hq/kit-context
```

## Features

- **Immutable:** Adding values creates a new context instance without modifying the parent (uses structural sharing).
- **Chained:** Contexts form a chain; value lookups delegate to the parent if a key isn't found locally.
- **String Keys:** Values are associated with simple string keys.
- **Explicit Value Retrieval:** Use `getValue<T>(key)` to retrieve values.

## Usage

### Creating an Empty Context

Typically, an empty root context is created at the beginning of a request lifecycle (e.g., within kit-http-react-router).

```ts
import { createContext, Context } from "@revas-hq/kit-context";

// Create an empty root context
const rootContext: Context = createContext();
```

### Adding Values (Immutable)

Use the `withValue` function to create a new context instance with an added key-value pair. The original context remains unchanged. Values cannot be `undefined`.

```ts
import { withValue } from "@revas-hq/kit-context";

// Add a userId to the context
const contextWithUser: Context = withValue(rootContext, "userId", "user-123");

// Add request trace ID to the context *derived from contextWithUser*
const contextWithTrace: Context = withValue(contextWithUser, "traceId", "trace-abc");

// rootContext is still empty
// contextWithUser only contains userId
// contextWithTrace contains traceId and delegates to contextWithUser for userId
```

### Retrieving Values

Use the `getValue` method to look up a value by its key. The lookup checks the current context node and then traverses up the parent chain until the key is found or the root is reached.

> **Important:** You must provide the expected type via the generic argument (`<T>`). The context itself cannot guarantee the type associated with a string key at compile time.

```ts
// Assuming contextWithTrace from the previous example

// Retrieve traceId (found in the current context node)
const traceId = contextWithTrace.getValue<string>("traceId");
console.log(traceId); // Output: trace-abc

// Retrieve userId (found in the parent context node)
const userId = contextWithTrace.getValue<string>("userId");
console.log(userId); // Output: user-123

// Retrieve a non-existent key
const nonExistent = contextWithTrace.getValue<number>("timeout");
console.log(nonExistent); // Output: undefined

// --- Type Safety Warning ---
// Requesting the wrong type can lead to runtime issues if not handled carefully.
const userIdAsNumber = contextWithTrace.getValue<number>("userId");
// userIdAsNumber is "user-123" at runtime, but typed as number | undefined.
// Operations assuming it's a number will fail!
// console.log(userIdAsNumber * 2); // Runtime Error!
```

**Best Practice:** Use constants or Symbols for context keys to avoid typos and manage keys centrally. Ensure consumers request values with the correct expected type.

### Checking for Keys

While `getValue` returning `undefined` indicates a key wasn't found, there isn't a dedicated `has(key)` method in this specific implementation. You can check the result of `getValue`:

```ts
if (contextWithTrace.getValue<string>("userId") !== undefined) {
    console.log("User ID exists in the context chain.");
}
```

### Type Safety Considerations

This context implementation relies on string keys for value retrieval. TypeScript cannot statically verify that the type `T` you provide to `getValue<T>(key)` matches the type of the value originally stored with that key. It is the developer's responsibility to ensure consistency between setting and getting values and their types. Mismatches can lead to runtime errors. Consider using well-defined constants or symbols for keys to mitigate typos.

## License

This project is licensed under the MIT License. See the LICENSE file for details.