first commit
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
# `last-event-id`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
The `last-event-id` module parses and validates the `Last-Event-Id`
|
||||
header browsers send automatically on `EventSource` reconnects. The
|
||||
engine consults the parsed value against the replay buffer; an empty
|
||||
or missing value means "start at live delivery", a well-formed value
|
||||
means "replay events with id > supplied first", a malformed value
|
||||
means "reject the handshake with `SSE_BUN.LAST_EVENT_ID_INVALID`".
|
||||
|
||||
## Features
|
||||
|
||||
- Returns `null` on missing/empty header (engine starts at live).
|
||||
- Validates decimal-string format `/^\d+$/` so non-numeric ids cannot
|
||||
poison the replay-buffer lookup.
|
||||
- Throws `SseBunError(LAST_EVENT_ID_INVALID)` on bad input — never
|
||||
silently fails.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { parseLastEventId } from "@suaveplan/api-sse-bun";
|
||||
|
||||
const id = parseLastEventId(request.headers.get("last-event-id"));
|
||||
if (id !== null) {
|
||||
// ...consult replay buffer...
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import {
|
||||
parseLastEventId,
|
||||
SSE_BUN_CODES,
|
||||
SseBunError,
|
||||
} from "@suaveplan/api-sse-bun";
|
||||
|
||||
try {
|
||||
const id = parseLastEventId(request.headers.get("last-event-id"));
|
||||
return id;
|
||||
} catch (err) {
|
||||
if (
|
||||
err instanceof SseBunError &&
|
||||
err.code === SSE_BUN_CODES.LAST_EVENT_ID_INVALID
|
||||
) {
|
||||
return new Response("bad Last-Event-Id", { status: 400 });
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `function parseLastEventId(raw: string | null): string | null` — `null`
|
||||
in → `null` out; numeric string in → trimmed numeric string out;
|
||||
anything else → throws `SseBunError(LAST_EVENT_ID_INVALID)`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The decimal-only format is a deliberate choice: it sorts numerically
|
||||
when the engine reasons about "events with id > n" and it forbids the
|
||||
WHATWG-allowed embedded newlines that would otherwise need their own
|
||||
trimming pass. If the contract grows to admit ULIDs or UUIDs the
|
||||
validator becomes a discriminated union; the engine never builds the
|
||||
event id itself (it relies on the replay buffer's `since` to do the
|
||||
comparison), so callers downstream do not need to be updated when the
|
||||
format widens.
|
||||
Reference in New Issue
Block a user