@earendil-works/pi-client 0.84.4 → 0.85.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/state.js DELETED
@@ -1,145 +0,0 @@
1
- import { toError } from "./errors.js";
2
- export class ClientState {
3
- #sessionSnapshots = new Map();
4
- #attachedSessionIds = new Set();
5
- #snapshotListeners = new Set();
6
- #eventListeners = new Set();
7
- #sessionSnapshotListeners = new Map();
8
- #sessionEventListeners = new Map();
9
- #onListenerError;
10
- #snapshot;
11
- constructor(onListenerError) {
12
- this.#onListenerError = onListenerError;
13
- }
14
- get snapshot() {
15
- return this.#snapshot;
16
- }
17
- reset() {
18
- this.#snapshot = undefined;
19
- this.#sessionSnapshots.clear();
20
- this.#attachedSessionIds.clear();
21
- }
22
- clearAttachments() {
23
- this.#attachedSessionIds.clear();
24
- }
25
- dispose() {
26
- this.reset();
27
- this.#snapshotListeners.clear();
28
- this.#eventListeners.clear();
29
- this.#sessionSnapshotListeners.clear();
30
- this.#sessionEventListeners.clear();
31
- }
32
- getSessionSnapshot(sessionId) {
33
- return this.#sessionSnapshots.get(sessionId);
34
- }
35
- isSessionAttached(sessionId) {
36
- return this.#attachedSessionIds.has(sessionId);
37
- }
38
- forgetSessionSnapshot(sessionId) {
39
- const previous = this.#sessionSnapshots.get(sessionId);
40
- this.#sessionSnapshots.delete(sessionId);
41
- return previous;
42
- }
43
- restoreSessionSnapshot(snapshot) {
44
- if (!this.#sessionSnapshots.has(snapshot.id))
45
- this.#sessionSnapshots.set(snapshot.id, snapshot);
46
- }
47
- subscribe(listener) {
48
- this.#snapshotListeners.add(listener);
49
- return () => this.#snapshotListeners.delete(listener);
50
- }
51
- onEvent(listener) {
52
- this.#eventListeners.add(listener);
53
- return () => this.#eventListeners.delete(listener);
54
- }
55
- subscribeSession(sessionId, listener) {
56
- return addMappedListener(this.#sessionSnapshotListeners, sessionId, listener);
57
- }
58
- onSessionEvent(sessionId, listener) {
59
- return addMappedListener(this.#sessionEventListeners, sessionId, listener);
60
- }
61
- applyResult(result) {
62
- if (result.command === "list")
63
- return;
64
- if (result.command === "detach") {
65
- this.#attachedSessionIds.delete(result.sessionId);
66
- const snapshot = this.#sessionSnapshots.get(result.sessionId);
67
- if (snapshot)
68
- this.#applySessionSnapshot({ ...snapshot, attached: false }, true);
69
- return;
70
- }
71
- this.#applySessionSnapshot(result.session);
72
- }
73
- applyEvent(event) {
74
- if (event.type === "server_snapshot")
75
- this.applyServerSnapshot(event.snapshot);
76
- if (event.type === "session_snapshot")
77
- this.#applySessionSnapshot(event.snapshot);
78
- if (event.type === "session_removed") {
79
- this.#sessionSnapshots.delete(event.sessionId);
80
- this.#attachedSessionIds.delete(event.sessionId);
81
- }
82
- this.#notify(this.#eventListeners, event);
83
- const sessionId = getEventSessionId(event);
84
- if (sessionId)
85
- this.#notify(this.#sessionEventListeners.get(sessionId), event);
86
- }
87
- applyServerSnapshot(snapshot) {
88
- if (this.#snapshot && snapshot.revision < this.#snapshot.revision)
89
- return;
90
- this.#snapshot = snapshot;
91
- this.#notify(this.#snapshotListeners, snapshot);
92
- }
93
- #applySessionSnapshot(snapshot, force = false) {
94
- const current = this.#sessionSnapshots.get(snapshot.id);
95
- if (!force && current && snapshot.revision < current.revision)
96
- return;
97
- this.#sessionSnapshots.set(snapshot.id, snapshot);
98
- if (snapshot.attached)
99
- this.#attachedSessionIds.add(snapshot.id);
100
- else
101
- this.#attachedSessionIds.delete(snapshot.id);
102
- this.#notify(this.#sessionSnapshotListeners.get(snapshot.id), snapshot);
103
- }
104
- #notify(listeners, value) {
105
- for (const listener of listeners ?? []) {
106
- try {
107
- listener(value);
108
- }
109
- catch (error) {
110
- this.#reportListenerError(error);
111
- }
112
- }
113
- }
114
- #reportListenerError(error) {
115
- if (!this.#onListenerError)
116
- return;
117
- try {
118
- this.#onListenerError(toError(error));
119
- }
120
- catch {
121
- // Diagnostics cannot affect client state.
122
- }
123
- }
124
- }
125
- function addMappedListener(listenersById, id, listener) {
126
- let listeners = listenersById.get(id);
127
- if (!listeners) {
128
- listeners = new Set();
129
- listenersById.set(id, listeners);
130
- }
131
- listeners.add(listener);
132
- return () => {
133
- listeners.delete(listener);
134
- if (listeners.size === 0)
135
- listenersById.delete(id);
136
- };
137
- }
138
- function getEventSessionId(event) {
139
- if (event.type === "session_snapshot")
140
- return event.snapshot.id;
141
- if (event.type === "session_progress" || event.type === "session_removed")
142
- return event.sessionId;
143
- return undefined;
144
- }
145
- //# sourceMappingURL=state.js.map
package/dist/state.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"state.js","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"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","sourcesContent":["import type { CommandResult, ServerEvent, ServerSnapshot, SessionSnapshot } from \"@earendil-works/pi-protocol\";\nimport { toError } from \"./errors.ts\";\nimport type { ListenerErrorHandler, Unsubscribe } from \"./types.ts\";\n\nexport class ClientState {\n\treadonly #sessionSnapshots = new Map<string, SessionSnapshot>();\n\treadonly #attachedSessionIds = new Set<string>();\n\treadonly #snapshotListeners = new Set<(snapshot: ServerSnapshot) => void>();\n\treadonly #eventListeners = new Set<(event: ServerEvent) => void>();\n\treadonly #sessionSnapshotListeners = new Map<string, Set<(snapshot: SessionSnapshot) => void>>();\n\treadonly #sessionEventListeners = new Map<string, Set<(event: ServerEvent) => void>>();\n\treadonly #onListenerError: ListenerErrorHandler | undefined;\n\t#snapshot: ServerSnapshot | undefined;\n\n\tconstructor(onListenerError?: ListenerErrorHandler) {\n\t\tthis.#onListenerError = onListenerError;\n\t}\n\n\tget snapshot(): ServerSnapshot | undefined {\n\t\treturn this.#snapshot;\n\t}\n\n\treset(): void {\n\t\tthis.#snapshot = undefined;\n\t\tthis.#sessionSnapshots.clear();\n\t\tthis.#attachedSessionIds.clear();\n\t}\n\n\tclearAttachments(): void {\n\t\tthis.#attachedSessionIds.clear();\n\t}\n\n\tdispose(): void {\n\t\tthis.reset();\n\t\tthis.#snapshotListeners.clear();\n\t\tthis.#eventListeners.clear();\n\t\tthis.#sessionSnapshotListeners.clear();\n\t\tthis.#sessionEventListeners.clear();\n\t}\n\n\tgetSessionSnapshot(sessionId: string): SessionSnapshot | undefined {\n\t\treturn this.#sessionSnapshots.get(sessionId);\n\t}\n\n\tisSessionAttached(sessionId: string): boolean {\n\t\treturn this.#attachedSessionIds.has(sessionId);\n\t}\n\n\tforgetSessionSnapshot(sessionId: string): SessionSnapshot | undefined {\n\t\tconst previous = this.#sessionSnapshots.get(sessionId);\n\t\tthis.#sessionSnapshots.delete(sessionId);\n\t\treturn previous;\n\t}\n\n\trestoreSessionSnapshot(snapshot: SessionSnapshot): void {\n\t\tif (!this.#sessionSnapshots.has(snapshot.id)) this.#sessionSnapshots.set(snapshot.id, snapshot);\n\t}\n\n\tsubscribe(listener: (snapshot: ServerSnapshot) => void): Unsubscribe {\n\t\tthis.#snapshotListeners.add(listener);\n\t\treturn () => this.#snapshotListeners.delete(listener);\n\t}\n\n\tonEvent(listener: (event: ServerEvent) => void): Unsubscribe {\n\t\tthis.#eventListeners.add(listener);\n\t\treturn () => this.#eventListeners.delete(listener);\n\t}\n\n\tsubscribeSession(sessionId: string, listener: (snapshot: SessionSnapshot) => void): Unsubscribe {\n\t\treturn addMappedListener(this.#sessionSnapshotListeners, sessionId, listener);\n\t}\n\n\tonSessionEvent(sessionId: string, listener: (event: ServerEvent) => void): Unsubscribe {\n\t\treturn addMappedListener(this.#sessionEventListeners, sessionId, listener);\n\t}\n\n\tapplyResult(result: CommandResult): void {\n\t\tif (result.command === \"list\") return;\n\t\tif (result.command === \"detach\") {\n\t\t\tthis.#attachedSessionIds.delete(result.sessionId);\n\t\t\tconst snapshot = this.#sessionSnapshots.get(result.sessionId);\n\t\t\tif (snapshot) this.#applySessionSnapshot({ ...snapshot, attached: false }, true);\n\t\t\treturn;\n\t\t}\n\t\tthis.#applySessionSnapshot(result.session);\n\t}\n\n\tapplyEvent(event: ServerEvent): void {\n\t\tif (event.type === \"server_snapshot\") this.applyServerSnapshot(event.snapshot);\n\t\tif (event.type === \"session_snapshot\") this.#applySessionSnapshot(event.snapshot);\n\t\tif (event.type === \"session_removed\") {\n\t\t\tthis.#sessionSnapshots.delete(event.sessionId);\n\t\t\tthis.#attachedSessionIds.delete(event.sessionId);\n\t\t}\n\t\tthis.#notify(this.#eventListeners, event);\n\t\tconst sessionId = getEventSessionId(event);\n\t\tif (sessionId) this.#notify(this.#sessionEventListeners.get(sessionId), event);\n\t}\n\n\tapplyServerSnapshot(snapshot: ServerSnapshot): void {\n\t\tif (this.#snapshot && snapshot.revision < this.#snapshot.revision) return;\n\t\tthis.#snapshot = snapshot;\n\t\tthis.#notify(this.#snapshotListeners, snapshot);\n\t}\n\n\t#applySessionSnapshot(snapshot: SessionSnapshot, force = false): void {\n\t\tconst current = this.#sessionSnapshots.get(snapshot.id);\n\t\tif (!force && current && snapshot.revision < current.revision) return;\n\t\tthis.#sessionSnapshots.set(snapshot.id, snapshot);\n\t\tif (snapshot.attached) this.#attachedSessionIds.add(snapshot.id);\n\t\telse this.#attachedSessionIds.delete(snapshot.id);\n\t\tthis.#notify(this.#sessionSnapshotListeners.get(snapshot.id), snapshot);\n\t}\n\n\t#notify<T>(listeners: Iterable<(value: T) => void> | undefined, value: T): void {\n\t\tfor (const listener of listeners ?? []) {\n\t\t\ttry {\n\t\t\t\tlistener(value);\n\t\t\t} catch (error) {\n\t\t\t\tthis.#reportListenerError(error);\n\t\t\t}\n\t\t}\n\t}\n\n\t#reportListenerError(error: unknown): void {\n\t\tif (!this.#onListenerError) return;\n\t\ttry {\n\t\t\tthis.#onListenerError(toError(error));\n\t\t} catch {\n\t\t\t// Diagnostics cannot affect client state.\n\t\t}\n\t}\n}\n\nfunction addMappedListener<T>(\n\tlistenersById: Map<string, Set<(value: T) => void>>,\n\tid: string,\n\tlistener: (value: T) => void,\n): Unsubscribe {\n\tlet listeners = listenersById.get(id);\n\tif (!listeners) {\n\t\tlisteners = new Set();\n\t\tlistenersById.set(id, listeners);\n\t}\n\tlisteners.add(listener);\n\treturn () => {\n\t\tlisteners.delete(listener);\n\t\tif (listeners.size === 0) listenersById.delete(id);\n\t};\n}\n\nfunction getEventSessionId(event: ServerEvent): string | undefined {\n\tif (event.type === \"session_snapshot\") return event.snapshot.id;\n\tif (event.type === \"session_progress\" || event.type === \"session_removed\") return event.sessionId;\n\treturn undefined;\n}\n"]}