@rljson/server 0.0.9 → 0.0.10
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.public.md +57 -0
- package/dist/README.public.md +57 -0
- package/dist/client.d.ts +27 -0
- package/dist/server.js +73 -0
- package/package.json +1 -1
package/README.public.md
CHANGED
|
@@ -164,6 +164,9 @@ This is implemented with `IoMulti` and `BsMulti` internally, but the public API
|
|
|
164
164
|
- `connector` – Connector wired to the route and socket (available when route was provided)
|
|
165
165
|
- `route` – the Route passed to the constructor
|
|
166
166
|
- `logger` – the `ServerLogger` instance (defaults to `noopLogger`)
|
|
167
|
+
- `isConnected` – whether the socket is currently connected (tracks `disconnect`/`connect` events)
|
|
168
|
+
- `onDisconnect(callback)` – registers a callback that fires when the socket disconnects (receives the reason string)
|
|
169
|
+
- `onReconnect(callback)` – registers a callback that fires when the socket reconnects after a previous disconnect
|
|
167
170
|
|
|
168
171
|
### Server API
|
|
169
172
|
|
|
@@ -216,6 +219,60 @@ The same pattern is used for Bs (blob storage).
|
|
|
216
219
|
- Peer initialization is guarded by a configurable timeout (`peerInitTimeoutMs`, default 30 s) on both server and client. On the server it prevents `addSocket()` from hanging on unresponsive clients; on the client it prevents `init()` from hanging when the server is unreachable.
|
|
217
220
|
- Logging is opt-in via `{ logger }` options. Use `ConsoleLogger` for development, `BufferedLogger` for testing, `FilteredLogger` for production. Default is `NoopLogger` (zero overhead).
|
|
218
221
|
|
|
222
|
+
## Reconnect handling
|
|
223
|
+
|
|
224
|
+
The `Client` class tracks socket connection state and provides hooks for upper layers to react to disconnects and reconnections.
|
|
225
|
+
|
|
226
|
+
### How it works
|
|
227
|
+
|
|
228
|
+
Socket.IO auto-reconnects at the transport level by default. When the connection drops and is restored:
|
|
229
|
+
|
|
230
|
+
1. The client-side Socket.IO socket emits `'disconnect'` then (later) `'connect'`.
|
|
231
|
+
2. The `Client` class listens for these events and updates `isConnected`.
|
|
232
|
+
3. Registered `onDisconnect` / `onReconnect` callbacks fire.
|
|
233
|
+
4. The server auto-detects the dropped socket (`removeSocket`) and re-registers the reconnected socket via a new `'connection'` event.
|
|
234
|
+
5. The server sends a bootstrap ref to the reconnected client, triggering a re-sync via the Connector's bootstrap handler.
|
|
235
|
+
|
|
236
|
+
### Usage
|
|
237
|
+
|
|
238
|
+
```ts
|
|
239
|
+
import { Client } from '@rljson/server';
|
|
240
|
+
|
|
241
|
+
const client = new Client(socket, io, bs, route, {
|
|
242
|
+
logger: new ConsoleLogger(),
|
|
243
|
+
});
|
|
244
|
+
await client.init();
|
|
245
|
+
|
|
246
|
+
// Track connection state
|
|
247
|
+
console.log(client.isConnected); // true
|
|
248
|
+
|
|
249
|
+
// React to disconnects
|
|
250
|
+
client.onDisconnect((reason) => {
|
|
251
|
+
console.warn(`Disconnected: ${reason}`);
|
|
252
|
+
// Pause user-facing sync indicators, queue local changes, etc.
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
// React to reconnections
|
|
256
|
+
client.onReconnect(() => {
|
|
257
|
+
console.info('Reconnected to server');
|
|
258
|
+
// Resume sync, trigger re-fetch, update UI, etc.
|
|
259
|
+
});
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### What survives a reconnect
|
|
263
|
+
|
|
264
|
+
| Layer | Survives? | Details |
|
|
265
|
+
| ----------------- | --------- | ----------------------------------------------------------------- |
|
|
266
|
+
| Socket.IO | ✅ | Auto-reconnects, reuses the same client-side socket object |
|
|
267
|
+
| SocketIoBridge | ✅ | Wraps the same socket — event listeners are preserved |
|
|
268
|
+
| IoPeer / BsPeer | ✅ | Listeners remain on the client socket; server re-creates its side |
|
|
269
|
+
| Connector | ✅ | Listeners remain; server bootstrap re-syncs state |
|
|
270
|
+
| IoMulti / BsMulti | ✅ | Multi layers are unaffected; local Io/Bs always available |
|
|
271
|
+
|
|
272
|
+
### Cleanup
|
|
273
|
+
|
|
274
|
+
All connection handlers are cleaned up automatically on `tearDown()`. After tearDown, no callbacks will fire.
|
|
275
|
+
|
|
219
276
|
## Logging
|
|
220
277
|
|
|
221
278
|
Both `Server` and `Client` support structured logging via an injectable `ServerLogger` interface. Logging is opt-in — by default a zero-overhead `NoopLogger` is used.
|
package/dist/README.public.md
CHANGED
|
@@ -164,6 +164,9 @@ This is implemented with `IoMulti` and `BsMulti` internally, but the public API
|
|
|
164
164
|
- `connector` – Connector wired to the route and socket (available when route was provided)
|
|
165
165
|
- `route` – the Route passed to the constructor
|
|
166
166
|
- `logger` – the `ServerLogger` instance (defaults to `noopLogger`)
|
|
167
|
+
- `isConnected` – whether the socket is currently connected (tracks `disconnect`/`connect` events)
|
|
168
|
+
- `onDisconnect(callback)` – registers a callback that fires when the socket disconnects (receives the reason string)
|
|
169
|
+
- `onReconnect(callback)` – registers a callback that fires when the socket reconnects after a previous disconnect
|
|
167
170
|
|
|
168
171
|
### Server API
|
|
169
172
|
|
|
@@ -216,6 +219,60 @@ The same pattern is used for Bs (blob storage).
|
|
|
216
219
|
- Peer initialization is guarded by a configurable timeout (`peerInitTimeoutMs`, default 30 s) on both server and client. On the server it prevents `addSocket()` from hanging on unresponsive clients; on the client it prevents `init()` from hanging when the server is unreachable.
|
|
217
220
|
- Logging is opt-in via `{ logger }` options. Use `ConsoleLogger` for development, `BufferedLogger` for testing, `FilteredLogger` for production. Default is `NoopLogger` (zero overhead).
|
|
218
221
|
|
|
222
|
+
## Reconnect handling
|
|
223
|
+
|
|
224
|
+
The `Client` class tracks socket connection state and provides hooks for upper layers to react to disconnects and reconnections.
|
|
225
|
+
|
|
226
|
+
### How it works
|
|
227
|
+
|
|
228
|
+
Socket.IO auto-reconnects at the transport level by default. When the connection drops and is restored:
|
|
229
|
+
|
|
230
|
+
1. The client-side Socket.IO socket emits `'disconnect'` then (later) `'connect'`.
|
|
231
|
+
2. The `Client` class listens for these events and updates `isConnected`.
|
|
232
|
+
3. Registered `onDisconnect` / `onReconnect` callbacks fire.
|
|
233
|
+
4. The server auto-detects the dropped socket (`removeSocket`) and re-registers the reconnected socket via a new `'connection'` event.
|
|
234
|
+
5. The server sends a bootstrap ref to the reconnected client, triggering a re-sync via the Connector's bootstrap handler.
|
|
235
|
+
|
|
236
|
+
### Usage
|
|
237
|
+
|
|
238
|
+
```ts
|
|
239
|
+
import { Client } from '@rljson/server';
|
|
240
|
+
|
|
241
|
+
const client = new Client(socket, io, bs, route, {
|
|
242
|
+
logger: new ConsoleLogger(),
|
|
243
|
+
});
|
|
244
|
+
await client.init();
|
|
245
|
+
|
|
246
|
+
// Track connection state
|
|
247
|
+
console.log(client.isConnected); // true
|
|
248
|
+
|
|
249
|
+
// React to disconnects
|
|
250
|
+
client.onDisconnect((reason) => {
|
|
251
|
+
console.warn(`Disconnected: ${reason}`);
|
|
252
|
+
// Pause user-facing sync indicators, queue local changes, etc.
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
// React to reconnections
|
|
256
|
+
client.onReconnect(() => {
|
|
257
|
+
console.info('Reconnected to server');
|
|
258
|
+
// Resume sync, trigger re-fetch, update UI, etc.
|
|
259
|
+
});
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### What survives a reconnect
|
|
263
|
+
|
|
264
|
+
| Layer | Survives? | Details |
|
|
265
|
+
| ----------------- | --------- | ----------------------------------------------------------------- |
|
|
266
|
+
| Socket.IO | ✅ | Auto-reconnects, reuses the same client-side socket object |
|
|
267
|
+
| SocketIoBridge | ✅ | Wraps the same socket — event listeners are preserved |
|
|
268
|
+
| IoPeer / BsPeer | ✅ | Listeners remain on the client socket; server re-creates its side |
|
|
269
|
+
| Connector | ✅ | Listeners remain; server bootstrap re-syncs state |
|
|
270
|
+
| IoMulti / BsMulti | ✅ | Multi layers are unaffected; local Io/Bs always available |
|
|
271
|
+
|
|
272
|
+
### Cleanup
|
|
273
|
+
|
|
274
|
+
All connection handlers are cleaned up automatically on `tearDown()`. After tearDown, no callbacks will fire.
|
|
275
|
+
|
|
219
276
|
## Logging
|
|
220
277
|
|
|
221
278
|
Both `Server` and `Client` support structured logging via an injectable `ServerLogger` interface. Logging is opt-in — by default a zero-overhead `NoopLogger` is used.
|
package/dist/client.d.ts
CHANGED
|
@@ -45,6 +45,10 @@ export declare class Client extends BaseNode {
|
|
|
45
45
|
private _syncConfig?;
|
|
46
46
|
private _clientIdentity?;
|
|
47
47
|
private _peerInitTimeoutMs;
|
|
48
|
+
private _isConnected;
|
|
49
|
+
private _disconnectCallbacks;
|
|
50
|
+
private _reconnectCallbacks;
|
|
51
|
+
private _connectionCleanup?;
|
|
48
52
|
/**
|
|
49
53
|
* Creates a Client instance
|
|
50
54
|
* @param _socketToServer - Socket or namespace bundle to connect to server
|
|
@@ -91,11 +95,34 @@ export declare class Client extends BaseNode {
|
|
|
91
95
|
* Returns the logger instance.
|
|
92
96
|
*/
|
|
93
97
|
get logger(): ServerLogger;
|
|
98
|
+
/**
|
|
99
|
+
* Whether the client is currently connected to the server.
|
|
100
|
+
* Tracks socket-level connection state via `disconnect` and `connect` events.
|
|
101
|
+
*/
|
|
102
|
+
get isConnected(): boolean;
|
|
103
|
+
/**
|
|
104
|
+
* Registers a callback that fires when the socket disconnects.
|
|
105
|
+
* The callback receives the disconnect reason string.
|
|
106
|
+
* @param callback - Invoked with the disconnect reason
|
|
107
|
+
*/
|
|
108
|
+
onDisconnect(callback: (reason: string) => void): void;
|
|
109
|
+
/**
|
|
110
|
+
* Registers a callback that fires when the socket reconnects
|
|
111
|
+
* after a previous disconnect.
|
|
112
|
+
* @param callback - Invoked on reconnection
|
|
113
|
+
*/
|
|
114
|
+
onReconnect(callback: () => void): void;
|
|
94
115
|
/**
|
|
95
116
|
* Creates Db and Connector from the route and IoMulti.
|
|
96
117
|
* Called during init() when a route was provided.
|
|
97
118
|
*/
|
|
98
119
|
private _setupDbAndConnector;
|
|
120
|
+
/**
|
|
121
|
+
* Registers socket-level disconnect/connect listeners.
|
|
122
|
+
* Logs state transitions and invokes registered callbacks.
|
|
123
|
+
* The `connect` callback only fires on RE-connections (not the initial connect).
|
|
124
|
+
*/
|
|
125
|
+
private _registerConnectionHandlers;
|
|
99
126
|
/**
|
|
100
127
|
* Builds the Io multi with local and peer layers.
|
|
101
128
|
*/
|
package/dist/server.js
CHANGED
|
@@ -1159,6 +1159,11 @@ class Client extends BaseNode {
|
|
|
1159
1159
|
_syncConfig;
|
|
1160
1160
|
_clientIdentity;
|
|
1161
1161
|
_peerInitTimeoutMs;
|
|
1162
|
+
// Connection state
|
|
1163
|
+
_isConnected = true;
|
|
1164
|
+
_disconnectCallbacks = [];
|
|
1165
|
+
_reconnectCallbacks = [];
|
|
1166
|
+
_connectionCleanup;
|
|
1162
1167
|
/**
|
|
1163
1168
|
* Initializes Io and Bs multis and their peer bridges.
|
|
1164
1169
|
* @returns The initialized Io implementation.
|
|
@@ -1171,6 +1176,7 @@ class Client extends BaseNode {
|
|
|
1171
1176
|
if (this._route) {
|
|
1172
1177
|
this._setupDbAndConnector();
|
|
1173
1178
|
}
|
|
1179
|
+
this._registerConnectionHandlers();
|
|
1174
1180
|
await this.ready();
|
|
1175
1181
|
this._logger.info("Client", "Client initialized successfully", {
|
|
1176
1182
|
hasRoute: !!this._route,
|
|
@@ -1196,6 +1202,12 @@ class Client extends BaseNode {
|
|
|
1196
1202
|
*/
|
|
1197
1203
|
async tearDown() {
|
|
1198
1204
|
this._logger.info("Client", "Tearing down client");
|
|
1205
|
+
if (this._connectionCleanup) {
|
|
1206
|
+
this._connectionCleanup();
|
|
1207
|
+
this._connectionCleanup = void 0;
|
|
1208
|
+
}
|
|
1209
|
+
this._disconnectCallbacks = [];
|
|
1210
|
+
this._reconnectCallbacks = [];
|
|
1199
1211
|
if (this._ioMulti && this._ioMulti.isOpen) {
|
|
1200
1212
|
this._ioMulti.close();
|
|
1201
1213
|
}
|
|
@@ -1244,6 +1256,29 @@ class Client extends BaseNode {
|
|
|
1244
1256
|
get logger() {
|
|
1245
1257
|
return this._logger;
|
|
1246
1258
|
}
|
|
1259
|
+
/**
|
|
1260
|
+
* Whether the client is currently connected to the server.
|
|
1261
|
+
* Tracks socket-level connection state via `disconnect` and `connect` events.
|
|
1262
|
+
*/
|
|
1263
|
+
get isConnected() {
|
|
1264
|
+
return this._isConnected;
|
|
1265
|
+
}
|
|
1266
|
+
/**
|
|
1267
|
+
* Registers a callback that fires when the socket disconnects.
|
|
1268
|
+
* The callback receives the disconnect reason string.
|
|
1269
|
+
* @param callback - Invoked with the disconnect reason
|
|
1270
|
+
*/
|
|
1271
|
+
onDisconnect(callback) {
|
|
1272
|
+
this._disconnectCallbacks.push(callback);
|
|
1273
|
+
}
|
|
1274
|
+
/**
|
|
1275
|
+
* Registers a callback that fires when the socket reconnects
|
|
1276
|
+
* after a previous disconnect.
|
|
1277
|
+
* @param callback - Invoked on reconnection
|
|
1278
|
+
*/
|
|
1279
|
+
onReconnect(callback) {
|
|
1280
|
+
this._reconnectCallbacks.push(callback);
|
|
1281
|
+
}
|
|
1247
1282
|
/**
|
|
1248
1283
|
* Creates Db and Connector from the route and IoMulti.
|
|
1249
1284
|
* Called during init() when a route was provided.
|
|
@@ -1263,6 +1298,44 @@ class Client extends BaseNode {
|
|
|
1263
1298
|
);
|
|
1264
1299
|
this._logger.info("Client", "Db and Connector created");
|
|
1265
1300
|
}
|
|
1301
|
+
/**
|
|
1302
|
+
* Registers socket-level disconnect/connect listeners.
|
|
1303
|
+
* Logs state transitions and invokes registered callbacks.
|
|
1304
|
+
* The `connect` callback only fires on RE-connections (not the initial connect).
|
|
1305
|
+
*/
|
|
1306
|
+
_registerConnectionHandlers() {
|
|
1307
|
+
const sockets = normalizeSocketBundle(this._socketToServer);
|
|
1308
|
+
const socket = sockets.ioUp;
|
|
1309
|
+
const disconnectHandler = (...args) => {
|
|
1310
|
+
const reason = typeof args[0] === "string" ? args[0] : "unknown";
|
|
1311
|
+
this._isConnected = false;
|
|
1312
|
+
this._logger.warn("Client", "Disconnected from server", { reason });
|
|
1313
|
+
for (const cb of this._disconnectCallbacks) {
|
|
1314
|
+
try {
|
|
1315
|
+
cb(reason);
|
|
1316
|
+
} catch {
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
};
|
|
1320
|
+
const reconnectHandler = () => {
|
|
1321
|
+
if (!this._isConnected) {
|
|
1322
|
+
this._isConnected = true;
|
|
1323
|
+
this._logger.info("Client", "Reconnected to server");
|
|
1324
|
+
for (const cb of this._reconnectCallbacks) {
|
|
1325
|
+
try {
|
|
1326
|
+
cb();
|
|
1327
|
+
} catch {
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
};
|
|
1332
|
+
socket.on("disconnect", disconnectHandler);
|
|
1333
|
+
socket.on("connect", reconnectHandler);
|
|
1334
|
+
this._connectionCleanup = () => {
|
|
1335
|
+
socket.off("disconnect", disconnectHandler);
|
|
1336
|
+
socket.off("connect", reconnectHandler);
|
|
1337
|
+
};
|
|
1338
|
+
}
|
|
1266
1339
|
/**
|
|
1267
1340
|
* Builds the Io multi with local and peer layers.
|
|
1268
1341
|
*/
|