@sockethub/client 5.0.0-alpha.12 → 5.0.0-alpha.13
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/README.md +42 -20
- package/dist/sockethub-client.browser.js +279 -908
- package/dist/sockethub-client.d.ts +280 -0
- package/dist/sockethub-client.js +273 -895
- package/dist/sockethub-client.min.js +21 -36
- package/package.json +6 -7
- package/src/sockethub-client.test.ts +0 -797
- package/src/sockethub-client.ts +0 -1095
|
@@ -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 {};
|