npm package: @glorhythm/session-request
Description: Glorhythm library for request with session and cookie
Author: glorhythm
Latest version: 1.0.0-beta

# @glorhythm/session-request

A thin wrapper around `@glorhythm/request` that **automatically wires cookies and sessions** using:

- `@glorhythm/request` – typed HTTP request wrapper for `IncomingMessage`
- `@glorhythm/session` – Redis-backed, encrypted session manager
- `@glorhythm/session/Cookie` – cookie helper used by the session layer

This package exposes a `Request` class that extends the base request with:

- `cookie` – an instance of `Cookie`
- `session` – an instance of `Session`

So anywhere you used `@glorhythm/request`, you can drop in `@glorhythm/session-request` and get session + cookie handling out of the box.

---

## Installation

```bash
npm install @glorhythm/session-request @glorhythm/request @glorhythm/session
```

---

## Overview

Source (simplified):

```ts
import BaseRequest from "@glorhythm/request";
import { IncomingMessage } from "node:http";
import Cookie, { setCookie } from "@glorhythm/session/Cookie";
import Session from "@glorhythm/session";

class Request extends BaseRequest {
  cookie: Cookie;
  session: Session;

  constructor(raw: IncomingMessage, setCookie: setCookie) {
    super(raw);
    this.cookie = new Cookie(this.header("cookie"), setCookie);
    this.session = new Session(this.cookie);
  }
}

export default Request;
```

Key points:

- It **inherits all functionality** from `@glorhythm/request`:
  - `method()`, `url()`, `ip()`
  - `header()`
  - `query` and `body` maps
  - `parseBody()` for JSON
- It additionally:
  - Creates a `Cookie` instance using the incoming `cookie` header and a `setCookie` function.
  - Creates a `Session` instance backed by Redis and encrypted IDs, using `Cookie` for storage.

---

## Basic Usage

You need to provide a `setCookie` function compatible with `@glorhythm/session/Cookie`.  
Typically, this will be a small adapter around your HTTP server / framework response.

### Example with Node `http`

```ts
import http from "http";
import Request from "@glorhythm/session-request";
import type { setCookie as SetCookieFn } from "@glorhythm/session/Cookie";

const server = http.createServer(async (rawReq, rawRes) => {
  const setCookie: SetCookieFn = (cookieHeaderValue: string) => {
    // Append Set-Cookie headers safely
    const existing = rawRes.getHeader("set-cookie");
    if (Array.isArray(existing)) {
      rawRes.setHeader("set-cookie", [...existing, cookieHeaderValue]);
    } else if (typeof existing === "string") {
      rawRes.setHeader("set-cookie", [existing, cookieHeaderValue]);
    } else {
      rawRes.setHeader("set-cookie", [cookieHeaderValue]);
    }
  };

  const req = new Request(rawReq, setCookie);

  // Use all base Request features
  await req.parseBody();
  const method = req.method();
  const ip = req.ip();

  // Access cookies & session
  const cookie = req.cookie;
  const session = req.session;

  // Example: read some auth info from session Redis payload
  // (you would typically extend Session with helper methods to read/write JSON)
  // const user = await session.getUser(); // hypothetical helper

  rawRes.statusCode = 200;
  rawRes.setHeader("content-type", "application/json");
  rawRes.end(
    JSON.stringify({
      method,
      ip,
      hasSession: !!session,
    })
  );
});

server.listen(3000, () => {
  console.log("Listening on http://localhost:3000");
});
```

---

## Request API

The `Request` class from this package **extends** the `@glorhythm/request` `Request` class:

```ts
import Request from "@glorhythm/session-request";

req.method(); // from @glorhythm/request
req.url(); // from @glorhythm/request
req.ip(); // from @glorhythm/request
await req.parseBody(); // from @glorhythm/request

req.cookie; // added by @glorhythm/session-request
req.session; // added by @glorhythm/session-request
```

### Added Properties

#### `cookie: Cookie`

An instance of `@glorhythm/session/Cookie`, created with:

- The raw `"cookie"` header from the request.
- The provided `setCookie` function to emit `Set-Cookie` headers.

You can use it directly if you want to read/write specific cookies.

#### `session: Session`

An instance of `@glorhythm/session`, which:

- Uses `Cookie` to store a sharded, encrypted session ID.
- Uses Redis (via `@glorhythm/redis`) to store encrypted session payloads.
- Is configured through `@glorhythm/config-loader` under the `"session"` key.

> For more details, see the README of `@glorhythm/session`.

---

## Framework Integration Notes

- This package is **framework-agnostic**. You just need:
  - A Node `IncomingMessage`
  - A way to set `Set-Cookie` headers on responses
- For frameworks like Express, Fastify, or uWebSockets.js, you typically:
  - Wrap the framework's request object to pass `req` (or its underlying `IncomingMessage`) to `new Request(...)`.
  - Wrap the framework's response object to implement `setCookie`.

Example (Express-style pseudo-code):

```ts
app.use(async (req, res, next) => {
  const setCookie: SetCookieFn = (cookieHeaderValue) => {
    res.append("Set-Cookie", cookieHeaderValue);
  };

  const request = new Request(req, setCookie);

  // Attach to res.locals or req for downstream handlers
  (req as any).grRequest = request;

  next();
});
```

---

## TypeScript

The package ships with type definitions:

- `main`: `dist/index.js`
- `types`: `dist/index.d.ts`
- `exports` configured for ESM/CJS.

Type-safe usage:

```ts
import Request from "@glorhythm/session-request";
import type { IncomingMessage } from "node:http";
import type { setCookie as SetCookieFn } from "@glorhythm/session/Cookie";

function buildRequest(raw: IncomingMessage, setCookie: SetCookieFn) {
  const req = new Request(raw, setCookie);
  return req;
}
```

---

## License

MIT © Glorhythm