# tools/core/resolvers/snapshot.resolver.ts

> 47 lines of code and 10 definitions.

Tree: Coordination tree
Language: typescript
Layer: infrastructure
Canonical: https://banes-lab.com/anatomy/coordination#file-coordination-tools-core-resolvers-snapshot-resolver-ts
Source text: https://banes-lab.com/assets/sources/source.3d3cad9ad4633f381265e447f0f5b50eb35a57301bfaec8582d409fe0399da7c.generated.txt

## Definitions

- `unreadEcho` (lexical_declaration, line 50, exported)
- `unreadSince` (lexical_declaration, line 11, exported)
- `UnreadInterval` (interface_declaration, line 4, exported)
- `held` (lexical_declaration, line 20, exported)
- `keys` (lexical_declaration, line 21, exported)
- `agents` (lexical_declaration, line 22, exported)
- `earliest` (lexical_declaration, line 23, exported)
- `latest` (lexical_declaration, line 24, exported)
- `SECOND` (lexical_declaration, line 48)
- `span` (lexical_declaration, line 55, exported)

## Uses

- [tools/core/resolvers/sweep.resolver.ts](https://banes-lab.com/source/coordination/tools/core/resolvers/sweep.resolver.ts.md)
- [tools/core/strings/snapshot.strings.ts](https://banes-lab.com/source/coordination/tools/core/strings/snapshot.strings.ts.md)

## Used by

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

## Source

```typescript
import { itemSpans } from "./sweep.resolver.ts";
import { unreadItems } from "../strings/snapshot.strings.ts";

export interface UnreadInterval {
    readonly keys: readonly string[];
    readonly agents: readonly string[];
    readonly earliest: number;
    readonly latest: number;
}

export const unreadSince = function unreadSince(
    current: string,
    snapshot: string | null,
    agent: string,
): UnreadInterval | null {
    if (snapshot === null) {
        return null;
    }

    const held = new Set(itemSpans(snapshot).map((span) => span.key));
    const keys: string[] = [];
    const agents = new Set<string>();
    let earliest = 0;
    let latest = 0;

    for (const span of itemSpans(current)) {
        if (span.agent === agent || held.has(span.key)) {
            continue;
        }

        keys.push(span.key);
        agents.add(span.agent);
        if (span.at > 0 && (earliest === 0 || span.at < earliest)) {
            earliest = span.at;
        }
        if (span.at > latest) {
            latest = span.at;
        }
    }

    if (keys.length === 0) {
        return null;
    }

    return { agents: [...agents].sort(), earliest, keys, latest };
};

const SECOND = 1000;

export const unreadEcho = function unreadEcho(interval: UnreadInterval | null, target: string): string {
    if (interval === null) {
        return "";
    }

    const span = interval.latest > interval.earliest ? Math.round((interval.latest - interval.earliest) / SECOND) : 0;

    return unreadItems(interval.agents, target, span, interval.keys);
};
```
