first commit
This commit is contained in:
@@ -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.
|
||||
Reference in New Issue
Block a user