@sockethub/client 5.0.0-alpha.12 → 5.0.0-alpha.14

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.
@@ -0,0 +1,280 @@
1
+ import type { ActivityStream } from "@sockethub/schemas";
2
+ import EventEmitter from "eventemitter3";
3
+ import type { Socket } from "socket.io-client";
4
+ export interface EventMapping {
5
+ credentials: Map<string, ActivityStream>;
6
+ connect: Map<string, ActivityStream>;
7
+ join: Map<string, ActivityStream>;
8
+ }
9
+ type InitState = "idle" | "initializing" | "ready" | "init_error" | "closed";
10
+ type ReadyReason = "initial-connect" | "reconnect" | "schemas-update";
11
+ type InitErrorPhase = "schemas-request" | "schemas-apply" | "timeout";
12
+ export interface SockethubClientOptions {
13
+ initTimeoutMs?: number;
14
+ maxQueuedOutbound?: number;
15
+ maxQueuedAgeMs?: number;
16
+ }
17
+ interface CustomEmitter extends EventEmitter {
18
+ _emit(s: string, o: unknown, c?: unknown): void;
19
+ connect(): void;
20
+ disconnect(): void;
21
+ connected: boolean;
22
+ id: string;
23
+ }
24
+ interface PlatformRegistrySchemas {
25
+ credentials?: object;
26
+ messages?: object;
27
+ }
28
+ /**
29
+ * Server-declared platform metadata used by the client for context generation
30
+ * and runtime validation.
31
+ */
32
+ export interface PlatformRegistryEntry {
33
+ id: string;
34
+ version: string;
35
+ contextUrl: string;
36
+ contextVersion: string;
37
+ schemaVersion: string;
38
+ types: Array<string>;
39
+ schemas: PlatformRegistrySchemas;
40
+ }
41
+ export interface PlatformRegistryPayload {
42
+ version?: string;
43
+ fingerprint?: string;
44
+ unchanged?: boolean;
45
+ contexts?: {
46
+ as?: string;
47
+ sockethub?: string;
48
+ };
49
+ platforms?: Array<PlatformRegistryEntry>;
50
+ }
51
+ export interface ClientReadyInfo {
52
+ state: "ready";
53
+ reason: ReadyReason;
54
+ sockethubVersion: string;
55
+ contexts: {
56
+ as: string;
57
+ sockethub: string;
58
+ };
59
+ platforms: Array<{
60
+ id: string;
61
+ version: string;
62
+ contextUrl: string;
63
+ contextVersion: string;
64
+ schemaVersion: string;
65
+ types: Array<string>;
66
+ }>;
67
+ }
68
+ export interface ClientInitError {
69
+ error: string;
70
+ phase: InitErrorPhase;
71
+ retrying: boolean;
72
+ }
73
+ /**
74
+ * SockethubClient - Client library for Sockethub protocol gateway
75
+ *
76
+ * A JavaScript client for connecting to Sockethub servers. Provides a high-level
77
+ * API for sending and receiving ActivityStreams messages over Socket.IO, with
78
+ * automatic state management and reconnection handling.
79
+ *
80
+ * Sockethub acts as a protocol gateway, translating ActivityStreams messages into
81
+ * various protocols (XMPP, IRC, RSS, etc.). This client handles the communication
82
+ * with the Sockethub server, including credential management, connection state,
83
+ * and automatic reconnection.
84
+ *
85
+ * ## Automatic Reconnection & State Replay
86
+ *
87
+ * This client automatically handles transient network disconnections by storing
88
+ * connection state in memory and replaying it when the socket reconnects.
89
+ *
90
+ * ### Security Model
91
+ *
92
+ * **Storage Location:**
93
+ * - All credentials and state are stored ONLY in JavaScript memory (heap)
94
+ * - Nothing is persisted to localStorage, sessionStorage, cookies, or disk
95
+ * - Memory is cleared when the browser tab closes or page refreshes
96
+ *
97
+ * **Replay Triggers:**
98
+ * - Automatic replay occurs on Socket.IO reconnection events
99
+ * - Typically triggered by brief network interruptions (WiFi switching, mobile network blips)
100
+ * - Does NOT occur on page refresh (new SockethubClient instance = empty state)
101
+ *
102
+ * **Server Restart Behavior:**
103
+ * - If server restarts, client socket will reconnect and replay credentials
104
+ * - Server must handle replayed credentials appropriately (validate, reject stale sessions, etc.)
105
+ * - Applications should implement proper session validation server-side
106
+ *
107
+ * **Lifetime:**
108
+ * - Credentials exist only during the browser tab's lifetime
109
+ * - Cleared on page reload, tab close, or manual disconnect
110
+ * - Not accessible across tabs or after browser restart
111
+ *
112
+ * **What Gets Replayed:**
113
+ * - Credentials (username/password/tokens sent via credentials event)
114
+ * - Activity Objects (actor definitions)
115
+ * - Connect commands (platform connections)
116
+ * - Join commands (room/channel joins)
117
+ *
118
+ * @example
119
+ * ```typescript
120
+ * // Create client
121
+ * const socket = io('http://localhost:10550');
122
+ * const client = new SockethubClient(socket);
123
+ *
124
+ * // Wait for schema registry before sending messages
125
+ * await client.ready();
126
+ *
127
+ * // Build canonical @context for a platform
128
+ * const ctx = client.contextFor('irc');
129
+ *
130
+ * // Send credentials - these will be replayed on reconnection
131
+ * client.socket.emit('credentials', {
132
+ * '@context': ctx,
133
+ * type: 'credentials',
134
+ * actor: { id: 'user@example.com', type: 'person' },
135
+ * object: { type: 'credentials', username: 'user', password: 'pass' }
136
+ * });
137
+ * ```
138
+ */
139
+ export default class SockethubClient {
140
+ /**
141
+ * In-memory storage for client state that should be replayed on reconnection.
142
+ *
143
+ * Security: Stored ONLY in JavaScript heap memory. Never persisted to disk,
144
+ * localStorage, or any permanent storage. Cleared on page reload.
145
+ */
146
+ private events;
147
+ private _socket;
148
+ socket: CustomEmitter;
149
+ debug: boolean;
150
+ private readonly options;
151
+ private platformRegistry;
152
+ private asContextUrl?;
153
+ private sockethubContextUrl?;
154
+ private sockethubVersion?;
155
+ private initState;
156
+ private hasReadyOnce;
157
+ private initCycle?;
158
+ private initTokenCounter;
159
+ private initTimeoutTimer?;
160
+ private waitingWarningTimer?;
161
+ private waitingWarningIntervalMs;
162
+ private readyWaiters;
163
+ private outboundQueue;
164
+ private outboundSequence;
165
+ private registryFingerprint?;
166
+ private latestReadyInfo?;
167
+ constructor(socket: Socket, options?: SockethubClientOptions);
168
+ /**
169
+ * Clear stored credentials to prevent automatic replay on reconnection.
170
+ *
171
+ * This method removes all stored credentials from memory. Useful for
172
+ * security-sensitive applications that want to prevent automatic credential
173
+ * replay when the socket reconnects.
174
+ *
175
+ * @example
176
+ * ```typescript
177
+ * // Clear credentials on disconnect
178
+ * sc.socket.on('disconnect', () => {
179
+ * sc.clearCredentials();
180
+ * });
181
+ * ```
182
+ */
183
+ clearCredentials(): void;
184
+ /**
185
+ * Return the platform registry discovered from the server.
186
+ */
187
+ getRegisteredPlatforms(): Array<PlatformRegistryEntry>;
188
+ /**
189
+ * Indicates whether server-provided schema/context registry data is loaded.
190
+ */
191
+ isSchemasReady(): boolean;
192
+ /**
193
+ * Indicates whether the client has completed schema initialization.
194
+ */
195
+ isReady(): boolean;
196
+ /**
197
+ * Returns the current client initialization state.
198
+ */
199
+ getInitState(): InitState;
200
+ /**
201
+ * Return the canonical base contexts learned from the server registry.
202
+ */
203
+ getRegisteredBaseContexts(): {
204
+ as: string;
205
+ sockethub: string;
206
+ };
207
+ getPlatformSchema(platform: string, schemaType?: "messages" | "credentials"): object | undefined;
208
+ /**
209
+ * Wait for schema registry data from the server and return the normalized payload.
210
+ * @deprecated Use ready(timeoutMs?) instead.
211
+ */
212
+ waitForSchemas(timeoutMs?: number): Promise<PlatformRegistryPayload>;
213
+ /**
214
+ * Wait until the client reaches a ready state.
215
+ */
216
+ ready(timeoutMs?: number): Promise<ClientReadyInfo>;
217
+ /**
218
+ * Validate an activity stream against currently registered platform schemas.
219
+ * Returns an empty string when valid.
220
+ */
221
+ validateActivity(activity: ActivityStream): string;
222
+ /**
223
+ * Build canonical Sockethub contexts for a platform using server-provided schema metadata.
224
+ */
225
+ contextFor(platform: string): ActivityStream["@context"];
226
+ private createPublicEmitter;
227
+ /**
228
+ * Ask server for the latest platform/context registry via ack callback.
229
+ * This keeps client context composition aligned with server schema state.
230
+ */
231
+ private requestSchemaRegistry;
232
+ /**
233
+ * Apply server-provided registry metadata to local runtime state.
234
+ * Also registers platform contexts/schemas with @sockethub/schemas validators
235
+ * so local validation uses the same canonical sources as the server.
236
+ */
237
+ private applyPlatformRegistry;
238
+ private eventCredentials;
239
+ private eventMessage;
240
+ private static getKey;
241
+ private buildPlatformRegistryPayload;
242
+ private buildReadyInfo;
243
+ private resolveReadyWaiters;
244
+ private rejectReadyWaiters;
245
+ private emitInitError;
246
+ private emitClientError;
247
+ private clearInitTimers;
248
+ private startWaitingWarnings;
249
+ private startInitialization;
250
+ private markReady;
251
+ private handleSchemasPayload;
252
+ private handlePublicEmit;
253
+ private enqueueOutbound;
254
+ private flushOutboundQueue;
255
+ private sendOutbound;
256
+ private log;
257
+ private registerSocketIOHandlers;
258
+ /**
259
+ * Type guard to check if an object is an ActivityStream with a valid actor.id.
260
+ */
261
+ private hasActorId;
262
+ /**
263
+ * Replays previously sent events to the server after reconnection.
264
+ *
265
+ * This method is called automatically when the Socket.IO connection is
266
+ * re-established after a transient network interruption. It resends
267
+ * credentials and connection state so the user doesn't need to manually
268
+ * re-authenticate or rejoin channels.
269
+ *
270
+ * Security considerations:
271
+ * - Only replays events stored in memory during this session
272
+ * - Does not replay after page refresh (memory cleared)
273
+ * - Server should validate replayed credentials (may be stale/revoked)
274
+ *
275
+ * @param name - Event name to emit ("credentials", "message")
276
+ * @param asMap - Map of events to replay
277
+ */
278
+ private replay;
279
+ }
280
+ export {};