first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,126 @@
# SessionGraphNode
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
`SessionGraphNode` is the internal mutable graph node powering the
hierarchical session tree at the heart of `@suaveplan/game-server`. Every
node holds a stable id, a closed-vocabulary session type, a metadata bag,
the mutable bidirectional parent/children links that form the tree, and
the two timestamps that mark when the node was created and last touched.
The class is named `SessionGraphNode` deliberately — Wave A's public
`SessionNode` interface (in `core/types`) is a read-only structural view of
exactly this shape. exposes the read-only interface to consumers
and uses the mutable class internally, so callers cannot accidentally
mutate the tree by reaching into `node.children.push(...)` through the
public manager surface.
## Features
- Implements Wave A's `SessionNode` interface structurally (the class is
the canonical implementation; the interface is the read-only view).
- Injectable `Clock` — no `Date.now()` calls; the entire tree is
deterministic under `FakeClock`.
- Bidirectional parent/children link maintenance via `addChild` /
`removeChild` with idempotent attach/detach semantics.
- Tree-walking helpers: `getDepth`, `getDescendants` (DFS pre-order),
`getAncestors`, `getRoot`, `isAncestorOf`, `isDescendantOf`.
- `toJSON()` returning a `SerializedSessionNode` shape for `SessionStore`
persistence.
## Usage: Basic
```typescript
import { SessionGraphNode } from "../session-node/index.js";
const clock = () => 1700000000000;
const root = new SessionGraphNode(
"venue1",
"venue",
{ createdAt: 0, updatedAt: 0 },
clock
);
const table = new SessionGraphNode(
"table1",
"table",
{ createdAt: 0, updatedAt: 0 },
clock,
root
);
root.addChild(table);
console.log(table.getDepth()); // 1
console.log(table.getRoot().id); // "venue1"
```
## Usage: Advanced
```typescript
import { SessionGraphNode } from "../session-node/index.js";
// Persistence round-trip: serialise, then restore with original timestamps.
const node = new SessionGraphNode("s1", "game", meta, clock);
const json = node.toJSON();
const restored = new SessionGraphNode(
json.id,
json.type,
json.metadata,
clock,
null,
{ createdAt: json.createdAt, updatedAt: json.updatedAt }
);
// Removing a child clears the bidirectional link.
root.removeChild(table);
console.log(table.parent); // null
console.log(root.children.length); // 0
```
## API Reference
### Constructor
`new SessionGraphNode(id, type, metadata, clock, parent?, timestamps?)`
`timestamps` is optional — passed only when restoring from persistence to
preserve the original `createdAt` / `updatedAt` stamps.
### Methods
- `addChild(child)` — attach a child; idempotent (re-adding is a no-op).
- `removeChild(child)` — returns `true` if removed, `false` if not a
child.
- `updateMetadata(patch)` — shallow-merge patch; refreshes `updatedAt`.
- `getDepth()` — 0 for a root, otherwise the distance to the root.
- `getDescendants()` — depth-first pre-order array, excluding `this`.
- `getAncestors()` — parent-to-root array.
- `getRoot()` — the topmost ancestor (or `this`).
- `isAncestorOf(other)` / `isDescendantOf(other)` — strict ancestry tests.
- `toJSON()` — serialised plain object suitable for storage adapters.
### Read-only properties
`id`, `type`, `createdAt`, `updatedAt`.
### Mutable properties
`parent` (managed by `addChild`/`removeChild`), `children`, `metadata`.
## Implementation Notes
The bidirectional parent/children invariant is held by `addChild` and
`removeChild`. Direct mutation of `node.children` or `node.parent` is
discouraged — callers should always go through these methods so the
counterpart link stays in sync. The class is internal to the engine
package and is not part of the public re-export surface; consumers should
import `SessionNode` from `core/types` instead.
The constructor accepts an optional `timestamps` parameter solely for the
persistence round-trip path — without it, a freshly restored node would
have its `createdAt` set to the moment of restoration, losing the original
creation time. With it, `SessionStore.restore` produces nodes that are
byte-equivalent to the ones that were originally persisted.