Initial Commit
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
# `gate` + `audit`
|
||||
|
||||
## Purpose
|
||||
|
||||
Central rate-limit / authorization / audit pipeline. The gateway calls `gate(...)` once before every mutating action (room create, broadcast, channel subscribe, channel publish, presence update, unicast). Splitting this out of the main daemon file keeps `gateway.ts` under the 300-line cap and makes the gate behaviour unit-testable without booting a server.
|
||||
|
||||
## Features
|
||||
|
||||
- Strict ordering: rate-limit first, authorization second. DoS traffic never exercises the (potentially expensive) authorization callback.
|
||||
- Typed denials: `RATE_LIMITED` and `AUTH_REJECTED` codes surface the exact failure reason to the caller.
|
||||
- Every decision records an OTel `recordAction(action, outcome)` counter increment AND a structured audit-log entry through the injected `AuditLogger`.
|
||||
- `audit(...)` swallows any thrown logger error so observability bugs cannot crash the daemon.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { gate } from "@suaveplan/websocket-gateway";
|
||||
|
||||
await gate(
|
||||
{ rateLimitGate, authorizationCheck, auditLogger, clock: Date.now },
|
||||
ctx,
|
||||
"room.broadcast"
|
||||
);
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { audit, gate } from "@suaveplan/websocket-gateway";
|
||||
|
||||
try {
|
||||
await gate(deps, ctx, "channel.publish");
|
||||
// … perform the publish
|
||||
} catch (err) {
|
||||
if (err instanceof WsGatewayError && err.code === WS_GATEWAY_CODES.RATE_LIMITED) {
|
||||
// The audit logger has already received a "denied" record; the
|
||||
// caller may emit an additional client-side denial event.
|
||||
audit(deps.auditLogger, "channel.publish", ctx, "denied", "client-handled", Date.now());
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `gate(deps, ctx, action): Promise<void>` — runs rate-limit + authz. Throws `WsGatewayError` on denial.
|
||||
- `audit(logger, action, ctx, outcome, reason, at): void` — pushes one record through the audit logger; swallows errors.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The function is intentionally a free function (not a class method) so the daemon can pass it any composition of callbacks — a future tier might want to gate-only without auditing, or audit-only without gating. Decoupling the four hooks from each other matches the proposal's "Hooks for unmigrated deps" stance: each callback is replaceable independently when the matching `@suaveplan/*` package lands.
|
||||
Reference in New Issue
Block a user