# tools/core/registries/board.registry.ts

> 51 lines of code and 12 definitions.

Tree: Coordination tree
Language: typescript
Layer: infrastructure
Canonical: https://banes-lab.com/anatomy/coordination#file-coordination-tools-core-registries-board-registry-ts
Source text: https://banes-lab.com/assets/sources/source.39211f56c45d1940071401e83a7326a2c6b2710040c4479264fdabc9447a5cab.generated.txt

## Definitions

- `writeWaiters` (lexical_declaration, line 44, exported)
- `currentWaiters` (lexical_declaration, line 36, exported)
- `releaseWaiter` (lexical_declaration, line 49, exported)
- `releaseAgent` (lexical_declaration, line 56, exported)
- `readWaiters` (lexical_declaration, line 27)
- `waitersPath` (lexical_declaration, line 32, exported)
- `WAITERS` (lexical_declaration, line 7)
- `Waiter` (interface_declaration, line 9, exported)
- `isWaiter` (lexical_declaration, line 15)
- `expiresAt` (lexical_declaration, line 19)
- `parsed` (lexical_declaration, line 28)
- `path` (lexical_declaration, line 37, exported)

## Used by

- [tools/core/coordinators/board.coordinator.ts](https://banes-lab.com/source/coordination/tools/core/coordinators/board.coordinator.ts.md)
- [tools/core/entrypoints/board.entrypoint.ts](https://banes-lab.com/source/coordination/tools/core/entrypoints/board.entrypoint.ts.md)

## Source

```typescript
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { fieldOf, tryParse } from "../readers/json.reader.ts";
import { GENERATED_DIR } from "../constants/path.constants.ts";

import { resolve } from "node:path";

const WAITERS = `${GENERATED_DIR}/board.waiters.generated.json`;

export interface Waiter {
    readonly id: string;
    readonly agent: string;
    readonly expiresAt: number;
}

const isWaiter = function isWaiter(value: unknown): value is Waiter {
    if (typeof value !== "object" || value === null) {
        return false;
    }
    const expiresAt = fieldOf(value, "expiresAt");
    return (
        typeof fieldOf(value, "id") === "string" &&
        typeof fieldOf(value, "agent") === "string" &&
        typeof expiresAt === "number"
    );
};

const readWaiters = function readWaiters(source: string): Waiter[] {
    const parsed = tryParse(source)?.value;
    return Array.isArray(parsed) ? parsed.filter(isWaiter) : [];
};

export const waitersPath = function waitersPath(root: string): string {
    return resolve(root, WAITERS);
};

export const currentWaiters = function currentWaiters(root: string, now: number): Waiter[] {
    const path = waitersPath(root);
    if (!existsSync(path)) {
        return [];
    }
    return readWaiters(readFileSync(path, "utf8")).filter((waiter) => waiter.expiresAt > now);
};

export const writeWaiters = function writeWaiters(root: string, waiters: readonly Waiter[]): void {
    mkdirSync(resolve(root, GENERATED_DIR), { recursive: true });
    writeFileSync(waitersPath(root), `${JSON.stringify(waiters, null, 4)}\n`, "utf8");
};

export const releaseWaiter = function releaseWaiter(root: string, id: string, now: number): void {
    writeWaiters(
        root,
        currentWaiters(root, now).filter((waiter) => waiter.id !== id),
    );
};

export const releaseAgent = function releaseAgent(root: string, agent: string, now: number): void {
    writeWaiters(
        root,
        currentWaiters(root, now).filter((waiter) => waiter.agent !== agent),
    );
};
```
