@nolag/iot 1.0.0 → 1.1.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/react-native.d.ts +13 -0
- package/dist/react-native.js +1151 -0
- package/dist/react-native.js.map +1 -0
- package/package.json +10 -4
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @nolag/iot
|
|
3
|
+
* React Native entry point.
|
|
4
|
+
*
|
|
5
|
+
* Identical to the browser entry: this SDK is transport-agnostic and attaches
|
|
6
|
+
* to an injected NoLag client, so it has no platform-specific code of its own.
|
|
7
|
+
* The entry exists purely so Metro has a `react-native` condition to resolve.
|
|
8
|
+
* Metro matches "react-native" then "import"/"require" and does not understand
|
|
9
|
+
* the "browser" condition, so without this it resolves the Node build of this
|
|
10
|
+
* package and, through it, the Node build of @nolag/js-sdk (which imports
|
|
11
|
+
* `ws` and fails to bundle).
|
|
12
|
+
*/
|
|
13
|
+
export * from "./browser";
|
|
@@ -0,0 +1,1151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tiny typed event emitter — framework-agnostic base for NoLag SDKs.
|
|
3
|
+
*
|
|
4
|
+
* EventMap is a record of event name → tuple of handler arguments.
|
|
5
|
+
*/
|
|
6
|
+
class EventEmitter {
|
|
7
|
+
constructor() {
|
|
8
|
+
this._handlers = new Map();
|
|
9
|
+
}
|
|
10
|
+
on(event, handler) {
|
|
11
|
+
if (!this._handlers.has(event)) {
|
|
12
|
+
this._handlers.set(event, new Set());
|
|
13
|
+
}
|
|
14
|
+
this._handlers.get(event).add(handler);
|
|
15
|
+
return this;
|
|
16
|
+
}
|
|
17
|
+
off(event, handler) {
|
|
18
|
+
if (handler) {
|
|
19
|
+
this._handlers.get(event)?.delete(handler);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
this._handlers.delete(event);
|
|
23
|
+
}
|
|
24
|
+
return this;
|
|
25
|
+
}
|
|
26
|
+
removeAllListeners() {
|
|
27
|
+
this._handlers.clear();
|
|
28
|
+
return this;
|
|
29
|
+
}
|
|
30
|
+
emit(event, ...args) {
|
|
31
|
+
const handlers = this._handlers.get(event);
|
|
32
|
+
if (!handlers)
|
|
33
|
+
return;
|
|
34
|
+
for (const handler of handlers) {
|
|
35
|
+
try {
|
|
36
|
+
handler(...args);
|
|
37
|
+
}
|
|
38
|
+
catch (e) {
|
|
39
|
+
console.error(`Error in ${String(event)} handler:`, e);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
listenerCount(event) {
|
|
44
|
+
return this._handlers.get(event)?.size ?? 0;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Maps actorTokenId ↔ Device, filtering self.
|
|
50
|
+
*/
|
|
51
|
+
class PresenceManager {
|
|
52
|
+
constructor(localActorId) {
|
|
53
|
+
this._devices = new Map();
|
|
54
|
+
this._actorToDeviceId = new Map();
|
|
55
|
+
this._localActorId = localActorId;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Add or update a device from presence data.
|
|
59
|
+
* Returns the Device if it's a remote device, null if it's self.
|
|
60
|
+
*/
|
|
61
|
+
addFromPresence(actorTokenId, presence, joinedAt) {
|
|
62
|
+
const isLocal = actorTokenId === this._localActorId;
|
|
63
|
+
// Skip self
|
|
64
|
+
if (isLocal)
|
|
65
|
+
return null;
|
|
66
|
+
const existing = this._actorToDeviceId.get(actorTokenId);
|
|
67
|
+
const deviceId = presence.deviceId || existing || actorTokenId;
|
|
68
|
+
const device = {
|
|
69
|
+
deviceId,
|
|
70
|
+
actorTokenId,
|
|
71
|
+
deviceName: presence.deviceName,
|
|
72
|
+
role: presence.role,
|
|
73
|
+
metadata: presence.metadata,
|
|
74
|
+
joinedAt: joinedAt ?? Date.now(),
|
|
75
|
+
isLocal: false,
|
|
76
|
+
};
|
|
77
|
+
this._devices.set(deviceId, device);
|
|
78
|
+
this._actorToDeviceId.set(actorTokenId, deviceId);
|
|
79
|
+
return device;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Remove a device by actorTokenId.
|
|
83
|
+
* Returns the removed device, or null if not found / is self.
|
|
84
|
+
*/
|
|
85
|
+
removeByActorId(actorTokenId) {
|
|
86
|
+
if (actorTokenId === this._localActorId)
|
|
87
|
+
return null;
|
|
88
|
+
const deviceId = this._actorToDeviceId.get(actorTokenId);
|
|
89
|
+
if (!deviceId)
|
|
90
|
+
return null;
|
|
91
|
+
const device = this._devices.get(deviceId) ?? null;
|
|
92
|
+
this._devices.delete(deviceId);
|
|
93
|
+
this._actorToDeviceId.delete(actorTokenId);
|
|
94
|
+
return device;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Get a device by deviceId.
|
|
98
|
+
*/
|
|
99
|
+
getDevice(deviceId) {
|
|
100
|
+
return this._devices.get(deviceId);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Get a device by actorTokenId.
|
|
104
|
+
*/
|
|
105
|
+
getDeviceByActorId(actorTokenId) {
|
|
106
|
+
const deviceId = this._actorToDeviceId.get(actorTokenId);
|
|
107
|
+
return deviceId ? this._devices.get(deviceId) : undefined;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Get all remote devices.
|
|
111
|
+
*/
|
|
112
|
+
getAll() {
|
|
113
|
+
return Array.from(this._devices.values());
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Get the devices Map (readonly view).
|
|
117
|
+
*/
|
|
118
|
+
get devices() {
|
|
119
|
+
return this._devices;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Clear all tracked devices.
|
|
123
|
+
*/
|
|
124
|
+
clear() {
|
|
125
|
+
this._devices.clear();
|
|
126
|
+
this._actorToDeviceId.clear();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Per-device, per-sensor time-series buffer.
|
|
132
|
+
*
|
|
133
|
+
* Readings are stored under a composite key `${deviceId}:${sensorId}` and
|
|
134
|
+
* bounded to `maxPoints` entries per key (oldest entries are dropped first).
|
|
135
|
+
*/
|
|
136
|
+
class TelemetryStore {
|
|
137
|
+
constructor(maxPoints) {
|
|
138
|
+
this._store = new Map();
|
|
139
|
+
this._ids = new Set();
|
|
140
|
+
this._maxPoints = maxPoints;
|
|
141
|
+
}
|
|
142
|
+
// ============ Public API ============
|
|
143
|
+
/**
|
|
144
|
+
* Add a telemetry reading to the store.
|
|
145
|
+
* Returns false if the reading id is a duplicate (idempotent).
|
|
146
|
+
*/
|
|
147
|
+
add(reading) {
|
|
148
|
+
if (this._ids.has(reading.id))
|
|
149
|
+
return false;
|
|
150
|
+
const key = this._key(reading.deviceId, reading.sensorId);
|
|
151
|
+
if (!this._store.has(key)) {
|
|
152
|
+
this._store.set(key, []);
|
|
153
|
+
}
|
|
154
|
+
const bucket = this._store.get(key);
|
|
155
|
+
bucket.push(reading);
|
|
156
|
+
// Enforce per-key cap
|
|
157
|
+
if (bucket.length > this._maxPoints) {
|
|
158
|
+
bucket.splice(0, bucket.length - this._maxPoints);
|
|
159
|
+
}
|
|
160
|
+
this._ids.add(reading.id);
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Retrieve readings, optionally filtered by deviceId and/or sensorId.
|
|
165
|
+
*
|
|
166
|
+
* - No args → all readings across all devices and sensors
|
|
167
|
+
* - deviceId only → all readings for that device across all sensors
|
|
168
|
+
* - deviceId + sensorId → readings for that exact device/sensor pair
|
|
169
|
+
*/
|
|
170
|
+
getAll(deviceId, sensorId) {
|
|
171
|
+
if (deviceId !== undefined && sensorId !== undefined) {
|
|
172
|
+
return [...(this._store.get(this._key(deviceId, sensorId)) ?? [])];
|
|
173
|
+
}
|
|
174
|
+
const results = [];
|
|
175
|
+
for (const [key, bucket] of this._store.entries()) {
|
|
176
|
+
if (deviceId !== undefined && !key.startsWith(`${deviceId}:`))
|
|
177
|
+
continue;
|
|
178
|
+
results.push(...bucket);
|
|
179
|
+
}
|
|
180
|
+
return results;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Get the most recent reading for a specific device/sensor pair.
|
|
184
|
+
*/
|
|
185
|
+
getLatest(deviceId, sensorId) {
|
|
186
|
+
const bucket = this._store.get(this._key(deviceId, sensorId));
|
|
187
|
+
if (!bucket || bucket.length === 0)
|
|
188
|
+
return undefined;
|
|
189
|
+
return bucket[bucket.length - 1];
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Check whether a reading id already exists in the store.
|
|
193
|
+
*/
|
|
194
|
+
has(id) {
|
|
195
|
+
return this._ids.has(id);
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Total number of readings across all device/sensor buckets.
|
|
199
|
+
*/
|
|
200
|
+
get size() {
|
|
201
|
+
let total = 0;
|
|
202
|
+
for (const bucket of this._store.values()) {
|
|
203
|
+
total += bucket.length;
|
|
204
|
+
}
|
|
205
|
+
return total;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Clear all stored readings and ids.
|
|
209
|
+
*/
|
|
210
|
+
clear() {
|
|
211
|
+
this._store.clear();
|
|
212
|
+
this._ids.clear();
|
|
213
|
+
}
|
|
214
|
+
// ============ Private ============
|
|
215
|
+
_key(deviceId, sensorId) {
|
|
216
|
+
return `${deviceId}:${sensorId}`;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function generateId() {
|
|
221
|
+
if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
|
|
222
|
+
return crypto.randomUUID();
|
|
223
|
+
}
|
|
224
|
+
return 'xxxx-xxxx-xxxx-xxxx'.replace(/x/g, () => Math.floor(Math.random() * 16).toString(16));
|
|
225
|
+
}
|
|
226
|
+
function createLogger(prefix, enabled) {
|
|
227
|
+
if (!enabled) {
|
|
228
|
+
return (..._args) => { };
|
|
229
|
+
}
|
|
230
|
+
return (...args) => {
|
|
231
|
+
console.log(`[${prefix}]`, ...args);
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
// ============ Wrapper registry ============
|
|
235
|
+
// One wrapper instance per (client, appName): two wrappers sharing an app on
|
|
236
|
+
// one connection would collide on topics, presence and the online lobby.
|
|
237
|
+
// Warn (not throw): HMR and tests legitimately construct before disposing.
|
|
238
|
+
const wrapperRegistry = new WeakMap();
|
|
239
|
+
/** Register a wrapper against a client + appName; warns on collision. */
|
|
240
|
+
function registerWrapper(client, appName, wrapperName) {
|
|
241
|
+
let apps = wrapperRegistry.get(client);
|
|
242
|
+
if (!apps) {
|
|
243
|
+
apps = new Map();
|
|
244
|
+
wrapperRegistry.set(client, apps);
|
|
245
|
+
}
|
|
246
|
+
const existing = apps.get(appName);
|
|
247
|
+
if (existing) {
|
|
248
|
+
console.warn(`[${wrapperName}] Another wrapper (${existing}) is already attached to this client for app "${appName}". ` +
|
|
249
|
+
`Use one wrapper per (client, app) — detach the other instance first.`);
|
|
250
|
+
}
|
|
251
|
+
apps.set(appName, wrapperName);
|
|
252
|
+
}
|
|
253
|
+
/** Release a wrapper's (client, appName) registration on detach. */
|
|
254
|
+
function releaseWrapper(client, appName) {
|
|
255
|
+
wrapperRegistry.get(client)?.delete(appName);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Command dispatch with ack tracking and per-command timeout.
|
|
260
|
+
*
|
|
261
|
+
* Controllers call `send()` to dispatch a command and await the result.
|
|
262
|
+
* Devices call `ack()` to acknowledge receipt and report completion/failure.
|
|
263
|
+
*/
|
|
264
|
+
class CommandManager {
|
|
265
|
+
constructor(defaultTimeout) {
|
|
266
|
+
this._pending = new Map();
|
|
267
|
+
this._commands = new Map();
|
|
268
|
+
this._defaultTimeout = defaultTimeout;
|
|
269
|
+
}
|
|
270
|
+
// ============ Public API ============
|
|
271
|
+
/**
|
|
272
|
+
* Dispatch a command to a target device.
|
|
273
|
+
*
|
|
274
|
+
* Returns a Promise that resolves once the device acks with 'acked' or
|
|
275
|
+
* 'completed', or rejects on 'failed' status or timeout.
|
|
276
|
+
*/
|
|
277
|
+
send(targetDeviceId, command, params, sentBy, timeout) {
|
|
278
|
+
const id = generateId();
|
|
279
|
+
const now = Date.now();
|
|
280
|
+
const cmd = {
|
|
281
|
+
id,
|
|
282
|
+
targetDeviceId,
|
|
283
|
+
command,
|
|
284
|
+
params,
|
|
285
|
+
status: 'pending',
|
|
286
|
+
sentBy,
|
|
287
|
+
sentAt: now,
|
|
288
|
+
};
|
|
289
|
+
this._commands.set(id, cmd);
|
|
290
|
+
const promise = new Promise((resolve, reject) => {
|
|
291
|
+
const ms = timeout ?? this._defaultTimeout;
|
|
292
|
+
const timer = setTimeout(() => {
|
|
293
|
+
const entry = this._pending.get(id);
|
|
294
|
+
if (!entry)
|
|
295
|
+
return;
|
|
296
|
+
entry.command.status = 'timeout';
|
|
297
|
+
this._commands.set(id, entry.command);
|
|
298
|
+
this._pending.delete(id);
|
|
299
|
+
reject(new Error(`Command "${command}" (${id}) timed out after ${ms}ms`));
|
|
300
|
+
}, ms);
|
|
301
|
+
this._pending.set(id, { command: cmd, resolve, reject, timer });
|
|
302
|
+
});
|
|
303
|
+
// Prevent unhandled rejection warnings when dispose() rejects orphaned commands.
|
|
304
|
+
// Callers who await/catch send() still see the rejection normally.
|
|
305
|
+
promise.catch(() => { });
|
|
306
|
+
return promise;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Acknowledge a command from the device side.
|
|
310
|
+
*
|
|
311
|
+
* `status` must be one of 'acked', 'completed', or 'failed'.
|
|
312
|
+
* Returns the updated DeviceCommand, or null if the command is unknown or
|
|
313
|
+
* already settled.
|
|
314
|
+
*/
|
|
315
|
+
ack(commandId, status, result) {
|
|
316
|
+
const entry = this._pending.get(commandId);
|
|
317
|
+
if (!entry)
|
|
318
|
+
return null;
|
|
319
|
+
clearTimeout(entry.timer);
|
|
320
|
+
this._pending.delete(commandId);
|
|
321
|
+
const now = Date.now();
|
|
322
|
+
const cmd = entry.command;
|
|
323
|
+
cmd.status = status;
|
|
324
|
+
if (status === 'acked') {
|
|
325
|
+
cmd.ackedAt = now;
|
|
326
|
+
}
|
|
327
|
+
else if (status === 'completed') {
|
|
328
|
+
cmd.ackedAt = cmd.ackedAt ?? now;
|
|
329
|
+
cmd.completedAt = now;
|
|
330
|
+
cmd.result = result;
|
|
331
|
+
}
|
|
332
|
+
else if (status === 'failed') {
|
|
333
|
+
cmd.ackedAt = cmd.ackedAt ?? now;
|
|
334
|
+
cmd.error = typeof result === 'string' ? result : 'Command failed';
|
|
335
|
+
}
|
|
336
|
+
this._commands.set(commandId, cmd);
|
|
337
|
+
if (status === 'acked' || status === 'completed') {
|
|
338
|
+
entry.resolve(cmd);
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
entry.reject(new Error(cmd.error ?? 'Command failed'));
|
|
342
|
+
}
|
|
343
|
+
return cmd;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Get a command by id (includes settled commands).
|
|
347
|
+
*/
|
|
348
|
+
get(commandId) {
|
|
349
|
+
return this._commands.get(commandId);
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Get all commands currently in 'pending' status.
|
|
353
|
+
*/
|
|
354
|
+
getPending() {
|
|
355
|
+
return Array.from(this._pending.values()).map((e) => e.command);
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Clear all pending timers and reject all outstanding promises.
|
|
359
|
+
* Call this when the group or client is torn down.
|
|
360
|
+
*/
|
|
361
|
+
dispose() {
|
|
362
|
+
for (const [id, entry] of this._pending.entries()) {
|
|
363
|
+
clearTimeout(entry.timer);
|
|
364
|
+
entry.command.status = 'timeout';
|
|
365
|
+
this._commands.set(id, entry.command);
|
|
366
|
+
entry.reject(new Error(`Command "${entry.command.command}" (${id}) was disposed`));
|
|
367
|
+
}
|
|
368
|
+
this._pending.clear();
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/** Default app name for NoLag IoT SDK */
|
|
373
|
+
const DEFAULT_APP_NAME = 'iot';
|
|
374
|
+
/** Maximum telemetry readings to retain per device/sensor key */
|
|
375
|
+
const DEFAULT_MAX_TELEMETRY_POINTS = 1000;
|
|
376
|
+
/** Default command acknowledgement timeout in milliseconds */
|
|
377
|
+
const DEFAULT_COMMAND_TIMEOUT = 30000;
|
|
378
|
+
/** Topic name for telemetry readings */
|
|
379
|
+
const TOPIC_TELEMETRY = 'telemetry';
|
|
380
|
+
/** Topic name for dispatched commands */
|
|
381
|
+
const TOPIC_COMMANDS = 'commands';
|
|
382
|
+
/** Topic name for command acknowledgements */
|
|
383
|
+
const TOPIC_CMD_ACK = '_cmd_ack';
|
|
384
|
+
/** Lobby ID for global online presence */
|
|
385
|
+
const LOBBY_ID = 'online';
|
|
386
|
+
/** Delay before the post-setup lobby presence refetch (catches simultaneous joiners) */
|
|
387
|
+
const LOBBY_REFRESH_DELAY_MS = 2000;
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* DeviceGroup — a single IoT group for telemetry streaming and command dispatch.
|
|
391
|
+
*
|
|
392
|
+
* Created via `NoLagIoT.joinGroup(name)`. Do not instantiate directly.
|
|
393
|
+
*/
|
|
394
|
+
class DeviceGroup extends EventEmitter {
|
|
395
|
+
/** @internal */
|
|
396
|
+
constructor(name, roomContext, localDevice, options, log, isConnected) {
|
|
397
|
+
super();
|
|
398
|
+
this._receivedCommands = new Map();
|
|
399
|
+
// Stored topic handler refs — cleanup removes exactly these, never all
|
|
400
|
+
// handlers for a topic (the client may be shared with other consumers).
|
|
401
|
+
this._onTelemetryRef = null;
|
|
402
|
+
this._onCommandsRef = null;
|
|
403
|
+
this._onCmdAckRef = null;
|
|
404
|
+
this.name = name;
|
|
405
|
+
this._roomContext = roomContext;
|
|
406
|
+
this._localDevice = localDevice;
|
|
407
|
+
this._options = options;
|
|
408
|
+
this._log = log;
|
|
409
|
+
this._isConnected = isConnected;
|
|
410
|
+
this._presenceManager = new PresenceManager(localDevice.actorTokenId);
|
|
411
|
+
this._telemetryStore = new TelemetryStore(options.maxTelemetryPoints);
|
|
412
|
+
this._commandManager = new CommandManager(options.commandTimeout);
|
|
413
|
+
}
|
|
414
|
+
// ============ Public Properties ============
|
|
415
|
+
/** All remote devices currently in this group */
|
|
416
|
+
get devices() {
|
|
417
|
+
return this._presenceManager.devices;
|
|
418
|
+
}
|
|
419
|
+
// ============ Telemetry ============
|
|
420
|
+
/**
|
|
421
|
+
* Publish a telemetry reading from this device.
|
|
422
|
+
*/
|
|
423
|
+
sendTelemetry(sensorId, value, opts = {}) {
|
|
424
|
+
const reading = {
|
|
425
|
+
id: generateId(),
|
|
426
|
+
deviceId: this._localDevice.deviceId,
|
|
427
|
+
sensorId,
|
|
428
|
+
value,
|
|
429
|
+
unit: opts.unit,
|
|
430
|
+
tags: opts.tags,
|
|
431
|
+
timestamp: Date.now(),
|
|
432
|
+
isReplay: false,
|
|
433
|
+
};
|
|
434
|
+
this._log('Sending telemetry:', sensorId, '=', value);
|
|
435
|
+
this._roomContext.emit(TOPIC_TELEMETRY, reading, { echo: false });
|
|
436
|
+
// Store locally so the sender also has it in the buffer
|
|
437
|
+
this._telemetryStore.add(reading);
|
|
438
|
+
return reading;
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Retrieve buffered telemetry readings, optionally filtered by device/sensor.
|
|
442
|
+
*/
|
|
443
|
+
getTelemetry(deviceId, sensorId) {
|
|
444
|
+
return this._telemetryStore.getAll(deviceId, sensorId);
|
|
445
|
+
}
|
|
446
|
+
// ============ Commands ============
|
|
447
|
+
/**
|
|
448
|
+
* Dispatch a command to a target device.
|
|
449
|
+
* Resolves when the device acks the command, rejects on failure or timeout.
|
|
450
|
+
*/
|
|
451
|
+
sendCommand(targetDeviceId, command, params) {
|
|
452
|
+
this._log('Sending command:', command, '→', targetDeviceId);
|
|
453
|
+
const promise = this._commandManager.send(targetDeviceId, command, params, this._localDevice.deviceId, this._options.commandTimeout);
|
|
454
|
+
// We need the command id to publish it — grab it from pending after send
|
|
455
|
+
const pending = this._commandManager.getPending();
|
|
456
|
+
const cmd = pending[pending.length - 1];
|
|
457
|
+
if (cmd) {
|
|
458
|
+
this._roomContext.emit(TOPIC_COMMANDS, cmd, { echo: false, filter: targetDeviceId });
|
|
459
|
+
}
|
|
460
|
+
return promise;
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Acknowledge a command on the device side.
|
|
464
|
+
* Typically called by the device after receiving a command event.
|
|
465
|
+
*/
|
|
466
|
+
ackCommand(commandId, status, result) {
|
|
467
|
+
this._log('Acking command:', commandId, status);
|
|
468
|
+
const ack = {
|
|
469
|
+
commandId,
|
|
470
|
+
status,
|
|
471
|
+
result,
|
|
472
|
+
ackedBy: this._localDevice.deviceId,
|
|
473
|
+
ackedAt: Date.now(),
|
|
474
|
+
};
|
|
475
|
+
// Route ack back to the controller that sent the command
|
|
476
|
+
const cmd = this._receivedCommands.get(commandId) || this._commandManager.get(commandId);
|
|
477
|
+
const ackFilter = cmd?.sentBy;
|
|
478
|
+
this._receivedCommands.delete(commandId);
|
|
479
|
+
this._roomContext.emit(TOPIC_CMD_ACK, ack, { echo: false, ...(ackFilter ? { filter: ackFilter } : {}) });
|
|
480
|
+
// Also settle locally if this device is the one that sent the command
|
|
481
|
+
this._commandManager.ack(commandId, status, result);
|
|
482
|
+
}
|
|
483
|
+
// ============ Devices ============
|
|
484
|
+
/**
|
|
485
|
+
* Get all remote devices in this group.
|
|
486
|
+
*/
|
|
487
|
+
getDevices() {
|
|
488
|
+
return this._presenceManager.getAll();
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Get a specific device by deviceId.
|
|
492
|
+
*/
|
|
493
|
+
getDevice(deviceId) {
|
|
494
|
+
return this._presenceManager.getDevice(deviceId);
|
|
495
|
+
}
|
|
496
|
+
// ============ Internal (called by NoLagIoT) ============
|
|
497
|
+
/** @internal Subscribe to all group topics and attach listeners */
|
|
498
|
+
_subscribe() {
|
|
499
|
+
this._log('Group subscribe:', this.name);
|
|
500
|
+
this._roomContext.subscribe(TOPIC_TELEMETRY);
|
|
501
|
+
// Commands: devices subscribe with their deviceId as filter so they only
|
|
502
|
+
// receive commands targeted at them. Controllers subscribe as wildcard
|
|
503
|
+
// to observe all commands.
|
|
504
|
+
if (this._options.role === 'device') {
|
|
505
|
+
this._roomContext.subscribe(TOPIC_COMMANDS, { filters: [this._localDevice.deviceId] });
|
|
506
|
+
}
|
|
507
|
+
else {
|
|
508
|
+
this._roomContext.subscribe(TOPIC_COMMANDS);
|
|
509
|
+
}
|
|
510
|
+
// Acks: controllers subscribe with their deviceId as filter so they only
|
|
511
|
+
// receive acks for commands they sent. Devices subscribe as wildcard.
|
|
512
|
+
if (this._options.role === 'controller') {
|
|
513
|
+
this._roomContext.subscribe(TOPIC_CMD_ACK, { filters: [this._localDevice.deviceId] });
|
|
514
|
+
}
|
|
515
|
+
else {
|
|
516
|
+
this._roomContext.subscribe(TOPIC_CMD_ACK);
|
|
517
|
+
}
|
|
518
|
+
// Listeners: refs stored for handler-specific removal (the client may be
|
|
519
|
+
// shared with other consumers on the same topic).
|
|
520
|
+
this._onTelemetryRef = (data) => {
|
|
521
|
+
this._handleIncomingTelemetry(data);
|
|
522
|
+
};
|
|
523
|
+
this._roomContext.on(TOPIC_TELEMETRY, this._onTelemetryRef);
|
|
524
|
+
this._onCommandsRef = (data) => {
|
|
525
|
+
this._handleIncomingCommand(data);
|
|
526
|
+
};
|
|
527
|
+
this._roomContext.on(TOPIC_COMMANDS, this._onCommandsRef);
|
|
528
|
+
this._onCmdAckRef = (data) => {
|
|
529
|
+
this._handleIncomingCmdAck(data);
|
|
530
|
+
};
|
|
531
|
+
this._roomContext.on(TOPIC_CMD_ACK, this._onCmdAckRef);
|
|
532
|
+
}
|
|
533
|
+
/** @internal Set presence and fetch existing group members */
|
|
534
|
+
_activate() {
|
|
535
|
+
this._log('Group activate:', this.name);
|
|
536
|
+
this._setPresence();
|
|
537
|
+
this._roomContext.fetchPresence().then((actors) => {
|
|
538
|
+
this._log('Group presence fetched:', this.name, actors.length, 'actors');
|
|
539
|
+
for (const actor of actors) {
|
|
540
|
+
if (actor.presence) {
|
|
541
|
+
const device = this._presenceManager.addFromPresence(actor.actorTokenId, actor.presence, actor.joinedAt);
|
|
542
|
+
if (device) {
|
|
543
|
+
this.emit('deviceJoined', device);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}).catch((err) => {
|
|
548
|
+
this._log('Failed to fetch group presence:', err);
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
/** @internal Re-set presence after reconnect */
|
|
552
|
+
_updateLocalPresence() {
|
|
553
|
+
this._setPresence();
|
|
554
|
+
}
|
|
555
|
+
/** @internal Handle a presence:join event */
|
|
556
|
+
_handlePresenceJoin(actorTokenId, presenceData) {
|
|
557
|
+
const device = this._presenceManager.addFromPresence(actorTokenId, presenceData);
|
|
558
|
+
if (device) {
|
|
559
|
+
this._log('Device joined group:', this.name, device.deviceId);
|
|
560
|
+
this.emit('deviceJoined', device);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
/** @internal Handle a presence:leave event */
|
|
564
|
+
_handlePresenceLeave(actorTokenId) {
|
|
565
|
+
const device = this._presenceManager.removeByActorId(actorTokenId);
|
|
566
|
+
if (device) {
|
|
567
|
+
this._log('Device left group:', this.name, device.deviceId);
|
|
568
|
+
this.emit('deviceLeft', device);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
/** @internal Handle a presence:update event */
|
|
572
|
+
_handlePresenceUpdate(actorTokenId, presenceData) {
|
|
573
|
+
this._presenceManager.addFromPresence(actorTokenId, presenceData);
|
|
574
|
+
}
|
|
575
|
+
/** @internal Unsubscribe and clean up */
|
|
576
|
+
_cleanup() {
|
|
577
|
+
this._log('Group cleanup:', this.name);
|
|
578
|
+
// Server unsubscribes need a live socket; skip when disconnected
|
|
579
|
+
// (best-effort — the core would no-op with an error callback anyway).
|
|
580
|
+
if (this._isConnected()) {
|
|
581
|
+
this._roomContext.unsubscribe(TOPIC_TELEMETRY);
|
|
582
|
+
this._roomContext.unsubscribe(TOPIC_COMMANDS);
|
|
583
|
+
this._roomContext.unsubscribe(TOPIC_CMD_ACK);
|
|
584
|
+
}
|
|
585
|
+
// Handler-specific removal only: the client may be shared, and a bare
|
|
586
|
+
// off(topic) would strip other consumers' handlers too.
|
|
587
|
+
if (this._onTelemetryRef)
|
|
588
|
+
this._roomContext.off(TOPIC_TELEMETRY, this._onTelemetryRef);
|
|
589
|
+
if (this._onCommandsRef)
|
|
590
|
+
this._roomContext.off(TOPIC_COMMANDS, this._onCommandsRef);
|
|
591
|
+
if (this._onCmdAckRef)
|
|
592
|
+
this._roomContext.off(TOPIC_CMD_ACK, this._onCmdAckRef);
|
|
593
|
+
this._onTelemetryRef = null;
|
|
594
|
+
this._onCommandsRef = null;
|
|
595
|
+
this._onCmdAckRef = null;
|
|
596
|
+
// Clears all pending command-timeout timers and rejects orphaned commands.
|
|
597
|
+
this._commandManager.dispose();
|
|
598
|
+
this._receivedCommands.clear();
|
|
599
|
+
this._presenceManager.clear();
|
|
600
|
+
this.removeAllListeners();
|
|
601
|
+
}
|
|
602
|
+
// ============ Private ============
|
|
603
|
+
_handleIncomingTelemetry(data) {
|
|
604
|
+
const reading = data;
|
|
605
|
+
this._log('Received telemetry:', reading.sensorId, '=', reading.value, 'from', reading.deviceId);
|
|
606
|
+
const isNew = this._telemetryStore.add(reading);
|
|
607
|
+
if (!isNew)
|
|
608
|
+
return; // duplicate — skip
|
|
609
|
+
this.emit('telemetry', reading);
|
|
610
|
+
}
|
|
611
|
+
_handleIncomingCommand(data) {
|
|
612
|
+
const cmd = data;
|
|
613
|
+
// Controllers observe all commands but don't process them as targets
|
|
614
|
+
if (this._options.role === 'controller')
|
|
615
|
+
return;
|
|
616
|
+
this._log('Received command:', cmd.command, 'from', cmd.sentBy);
|
|
617
|
+
this._receivedCommands.set(cmd.id, cmd);
|
|
618
|
+
this.emit('command', cmd);
|
|
619
|
+
}
|
|
620
|
+
_handleIncomingCmdAck(data) {
|
|
621
|
+
const ack = data;
|
|
622
|
+
this._log('Received command ack:', ack.commandId, ack.status);
|
|
623
|
+
const cmd = this._commandManager.ack(ack.commandId, ack.status, ack.result);
|
|
624
|
+
if (cmd) {
|
|
625
|
+
this.emit('commandAck', cmd);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
_setPresence() {
|
|
629
|
+
const presenceData = {
|
|
630
|
+
deviceId: this._localDevice.deviceId,
|
|
631
|
+
deviceName: this._localDevice.deviceName,
|
|
632
|
+
role: this._localDevice.role,
|
|
633
|
+
metadata: this._localDevice.metadata,
|
|
634
|
+
// Scope tag: on a shared client, other apps' wrappers filter our
|
|
635
|
+
// presence out by this (and we filter theirs).
|
|
636
|
+
__scope: this._options.appName,
|
|
637
|
+
};
|
|
638
|
+
this._roomContext.setPresence(presenceData);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* NoLagIoT — high-level IoT telemetry and command dispatch SDK built on @nolag/js-sdk.
|
|
644
|
+
*
|
|
645
|
+
* Provides device presence, real-time telemetry streaming, and command dispatch
|
|
646
|
+
* with ack tracking — all framework-agnostic via events.
|
|
647
|
+
*
|
|
648
|
+
* The wrapper NEVER manages the connection. The app owns one core NoLag
|
|
649
|
+
* client (shared by any number of wrappers on distinct apps) and the
|
|
650
|
+
* wrapper attaches to it at construction and releases it via `detach()`.
|
|
651
|
+
*
|
|
652
|
+
* @example
|
|
653
|
+
* ```typescript
|
|
654
|
+
* import { NoLag } from '@nolag/js-sdk';
|
|
655
|
+
* import { NoLagIoT } from '@nolag/iot';
|
|
656
|
+
*
|
|
657
|
+
* const client = NoLag(async () => (await (await fetch('/api/nolag-token')).json()).token);
|
|
658
|
+
* const iot = new NoLagIoT({ client, deviceId: 'sensor-01', role: 'device' });
|
|
659
|
+
*
|
|
660
|
+
* iot.on('connected', () => console.log('Connected!'));
|
|
661
|
+
*
|
|
662
|
+
* await client.connect(); // the app owns the connection
|
|
663
|
+
* await iot.ready(); // wrapper setup done (identity, lobby, groups)
|
|
664
|
+
*
|
|
665
|
+
* const group = iot.joinGroup('factory-floor');
|
|
666
|
+
* group.on('command', (cmd) => {
|
|
667
|
+
* group.ackCommand(cmd.id, 'completed', { ok: true });
|
|
668
|
+
* });
|
|
669
|
+
* group.sendTelemetry('temperature', 22.5, { unit: '°C' });
|
|
670
|
+
*
|
|
671
|
+
* iot.detach(); // wrapper releases its handlers and topics
|
|
672
|
+
* client.disconnect(); // the app closes the socket
|
|
673
|
+
* ```
|
|
674
|
+
*/
|
|
675
|
+
class NoLagIoT extends EventEmitter {
|
|
676
|
+
constructor(options) {
|
|
677
|
+
super();
|
|
678
|
+
this._localDevice = null;
|
|
679
|
+
this._groups = new Map();
|
|
680
|
+
this._lobby = null;
|
|
681
|
+
this._onlineDevices = new Map();
|
|
682
|
+
this._actorToDeviceId = new Map();
|
|
683
|
+
// Lifecycle: one setup run per connection epoch; detach is terminal.
|
|
684
|
+
this._epoch = 0;
|
|
685
|
+
this._detached = false;
|
|
686
|
+
this._isReady = false;
|
|
687
|
+
this._lobbyRefreshTimer = null;
|
|
688
|
+
// Stored client handler refs. INVARIANT: every client.on() below has a
|
|
689
|
+
// matching client.off() in detach() — never bare off(event), never inline
|
|
690
|
+
// closures on the client.
|
|
691
|
+
this._onConnectRef = () => this._onConnect();
|
|
692
|
+
this._onDisconnectRef = (reason) => {
|
|
693
|
+
this._log('Disconnected:', reason);
|
|
694
|
+
this.emit('disconnected', reason);
|
|
695
|
+
};
|
|
696
|
+
this._onReconnectRef = () => {
|
|
697
|
+
this._log('Reconnecting...');
|
|
698
|
+
this.emit('reconnecting');
|
|
699
|
+
};
|
|
700
|
+
this._onErrorRef = (error) => {
|
|
701
|
+
this._log('Error:', error);
|
|
702
|
+
this.emit('error', error);
|
|
703
|
+
};
|
|
704
|
+
this._onPresenceJoinRef = (data) => this._handleRoomPresenceJoin(data);
|
|
705
|
+
this._onPresenceLeaveRef = (data) => this._handleRoomPresenceLeave(data);
|
|
706
|
+
this._onPresenceUpdateRef = (data) => this._handleRoomPresenceUpdate(data);
|
|
707
|
+
this._onLobbyJoinRef = (data) => this._handleLobbyJoin(data);
|
|
708
|
+
this._onLobbyLeaveRef = (data) => this._handleLobbyLeave(data);
|
|
709
|
+
this._onLobbyUpdateRef = (data) => this._handleLobbyUpdate(data);
|
|
710
|
+
if (!options?.client) {
|
|
711
|
+
throw new TypeError('NoLagIoT requires an injected NoLag client: new NoLagIoT({ client, deviceId, ... })');
|
|
712
|
+
}
|
|
713
|
+
this._client = options.client;
|
|
714
|
+
this._deviceId = options.deviceId ?? generateId();
|
|
715
|
+
this._options = {
|
|
716
|
+
deviceId: this._deviceId,
|
|
717
|
+
deviceName: options.deviceName,
|
|
718
|
+
role: options.role ?? 'device',
|
|
719
|
+
metadata: options.metadata,
|
|
720
|
+
appName: options.appName ?? DEFAULT_APP_NAME,
|
|
721
|
+
maxTelemetryPoints: options.maxTelemetryPoints ?? DEFAULT_MAX_TELEMETRY_POINTS,
|
|
722
|
+
commandTimeout: options.commandTimeout ?? DEFAULT_COMMAND_TIMEOUT,
|
|
723
|
+
debug: options.debug ?? false,
|
|
724
|
+
groups: options.groups ?? [],
|
|
725
|
+
};
|
|
726
|
+
this._log = createLogger('NoLagIoT', this._options.debug);
|
|
727
|
+
this._readyPromise = new Promise((resolve, reject) => {
|
|
728
|
+
this._readyResolve = resolve;
|
|
729
|
+
this._readyReject = reject;
|
|
730
|
+
});
|
|
731
|
+
// ready() rejection is only meaningful to callers that await it
|
|
732
|
+
this._readyPromise.catch(() => { });
|
|
733
|
+
registerWrapper(this._client, this._options.appName, 'NoLagIoT');
|
|
734
|
+
// Construction = attach: wire everything now, with stored refs.
|
|
735
|
+
this._client.on('connect', this._onConnectRef);
|
|
736
|
+
this._client.on('disconnect', this._onDisconnectRef);
|
|
737
|
+
this._client.on('reconnect', this._onReconnectRef);
|
|
738
|
+
this._client.on('error', this._onErrorRef);
|
|
739
|
+
this._client.on('presence:join', this._onPresenceJoinRef);
|
|
740
|
+
this._client.on('presence:leave', this._onPresenceLeaveRef);
|
|
741
|
+
this._client.on('presence:update', this._onPresenceUpdateRef);
|
|
742
|
+
this._client.on('lobbyPresence:join', this._onLobbyJoinRef);
|
|
743
|
+
this._client.on('lobbyPresence:leave', this._onLobbyLeaveRef);
|
|
744
|
+
this._client.on('lobbyPresence:update', this._onLobbyUpdateRef);
|
|
745
|
+
// Attach-to-connected: if the client is already authenticated, run setup.
|
|
746
|
+
// The microtask lets the caller wire wrapper event handlers synchronously
|
|
747
|
+
// first; a racing real 'connect' event wins via the epoch guard.
|
|
748
|
+
queueMicrotask(() => {
|
|
749
|
+
if (this._epoch === 0 && !this._detached && this._client.connected) {
|
|
750
|
+
this._onConnect();
|
|
751
|
+
}
|
|
752
|
+
});
|
|
753
|
+
}
|
|
754
|
+
// ============ Public Properties ============
|
|
755
|
+
/** Whether the underlying connection is established (connected ≠ ready) */
|
|
756
|
+
get connected() {
|
|
757
|
+
return !this._detached && this._client.connected;
|
|
758
|
+
}
|
|
759
|
+
/** The injected core client (owned by the app, not the wrapper) */
|
|
760
|
+
get client() {
|
|
761
|
+
return this._client;
|
|
762
|
+
}
|
|
763
|
+
/** The local device info (available after ready) */
|
|
764
|
+
get localDevice() {
|
|
765
|
+
return this._localDevice;
|
|
766
|
+
}
|
|
767
|
+
/** All currently joined groups */
|
|
768
|
+
get groups() {
|
|
769
|
+
return this._groups;
|
|
770
|
+
}
|
|
771
|
+
// ============ Lifecycle ============
|
|
772
|
+
/**
|
|
773
|
+
* Resolves once the wrapper's first setup completed (identity, lobby and
|
|
774
|
+
* configured groups ready — equivalently, once 'connected' has fired).
|
|
775
|
+
* Rejects only if detach() is called before that. Client auth failures
|
|
776
|
+
* surface via the app's own `await client.connect()`, not here.
|
|
777
|
+
*/
|
|
778
|
+
ready() {
|
|
779
|
+
return this._readyPromise;
|
|
780
|
+
}
|
|
781
|
+
/**
|
|
782
|
+
* Detach from the client: remove every handler this wrapper added,
|
|
783
|
+
* unsubscribe its topics and lobby (when connected), clear state. Also
|
|
784
|
+
* clears any pending command-timeout timers on every group. Terminal and
|
|
785
|
+
* idempotent; never touches the socket. To use IoT again, construct a new
|
|
786
|
+
* instance.
|
|
787
|
+
*/
|
|
788
|
+
detach() {
|
|
789
|
+
if (this._detached)
|
|
790
|
+
return;
|
|
791
|
+
this._log('Detaching...');
|
|
792
|
+
this._detached = true;
|
|
793
|
+
this._epoch++; // aborts any in-flight setup at its next checkpoint
|
|
794
|
+
if (this._lobbyRefreshTimer) {
|
|
795
|
+
clearTimeout(this._lobbyRefreshTimer);
|
|
796
|
+
this._lobbyRefreshTimer = null;
|
|
797
|
+
}
|
|
798
|
+
// Remove all client handlers by stored ref
|
|
799
|
+
this._client.off('connect', this._onConnectRef);
|
|
800
|
+
this._client.off('disconnect', this._onDisconnectRef);
|
|
801
|
+
this._client.off('reconnect', this._onReconnectRef);
|
|
802
|
+
this._client.off('error', this._onErrorRef);
|
|
803
|
+
this._client.off('presence:join', this._onPresenceJoinRef);
|
|
804
|
+
this._client.off('presence:leave', this._onPresenceLeaveRef);
|
|
805
|
+
this._client.off('presence:update', this._onPresenceUpdateRef);
|
|
806
|
+
this._client.off('lobbyPresence:join', this._onLobbyJoinRef);
|
|
807
|
+
this._client.off('lobbyPresence:leave', this._onLobbyLeaveRef);
|
|
808
|
+
this._client.off('lobbyPresence:update', this._onLobbyUpdateRef);
|
|
809
|
+
// Groups: handler-specific off + connected-gated server unsubscribe.
|
|
810
|
+
// _cleanup() also disposes each group's command-timeout timers.
|
|
811
|
+
for (const name of [...this._groups.keys()]) {
|
|
812
|
+
this._groups.get(name)._cleanup();
|
|
813
|
+
this._groups.delete(name);
|
|
814
|
+
}
|
|
815
|
+
// Lobby: server unsubscribe is best-effort and needs a live socket
|
|
816
|
+
if (this._lobby && this._client.connected) {
|
|
817
|
+
try {
|
|
818
|
+
this._lobby.unsubscribe();
|
|
819
|
+
}
|
|
820
|
+
catch {
|
|
821
|
+
/* best-effort */
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
this._lobby = null;
|
|
825
|
+
this._onlineDevices.clear();
|
|
826
|
+
this._actorToDeviceId.clear();
|
|
827
|
+
this._localDevice = null;
|
|
828
|
+
releaseWrapper(this._client, this._options.appName);
|
|
829
|
+
if (!this._isReady) {
|
|
830
|
+
this._readyReject(new Error('NoLagIoT detached before ready'));
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
// ============ Private: Epoch Setup ============
|
|
834
|
+
_onConnect() {
|
|
835
|
+
this._epoch++;
|
|
836
|
+
void this._runSetup(this._epoch);
|
|
837
|
+
}
|
|
838
|
+
/**
|
|
839
|
+
* One setup pass per connection epoch. Serves both initial setup (epoch 1)
|
|
840
|
+
* and reconnect restore (epoch > 1). Aborts silently whenever a newer
|
|
841
|
+
* epoch started or the wrapper detached — checked after every await.
|
|
842
|
+
*/
|
|
843
|
+
async _runSetup(epoch) {
|
|
844
|
+
const stale = () => epoch !== this._epoch || this._detached;
|
|
845
|
+
this._log(this._isReady ? 'Restoring after reconnect...' : 'Setting up...');
|
|
846
|
+
// Identity (client.actorId is guaranteed post-auth)
|
|
847
|
+
if (!this._localDevice) {
|
|
848
|
+
this._localDevice = {
|
|
849
|
+
deviceId: this._deviceId,
|
|
850
|
+
actorTokenId: this._client.actorId,
|
|
851
|
+
deviceName: this._options.deviceName,
|
|
852
|
+
role: this._options.role,
|
|
853
|
+
metadata: this._options.metadata,
|
|
854
|
+
joinedAt: Date.now(),
|
|
855
|
+
isLocal: true,
|
|
856
|
+
};
|
|
857
|
+
this._log('Local device:', this._localDevice.deviceId, '→', this._localDevice.actorTokenId);
|
|
858
|
+
}
|
|
859
|
+
else {
|
|
860
|
+
this._localDevice.actorTokenId = this._client.actorId;
|
|
861
|
+
}
|
|
862
|
+
// Lobby: subscribe every epoch (idempotent server-side) and diff-hydrate
|
|
863
|
+
// from the returned snapshot — one path for setup and restore.
|
|
864
|
+
if (!this._lobby) {
|
|
865
|
+
this._lobby = this._client.setApp(this._options.appName).setLobby(LOBBY_ID);
|
|
866
|
+
}
|
|
867
|
+
try {
|
|
868
|
+
const state = await this._lobby.subscribe();
|
|
869
|
+
if (stale())
|
|
870
|
+
return;
|
|
871
|
+
this._diffHydrateOnlineDevices(state);
|
|
872
|
+
this._log('Lobby subscribed, online devices:', this._onlineDevices.size);
|
|
873
|
+
}
|
|
874
|
+
catch (err) {
|
|
875
|
+
if (stale())
|
|
876
|
+
return;
|
|
877
|
+
this._log('Lobby subscription failed:', err);
|
|
878
|
+
}
|
|
879
|
+
if (!this._isReady) {
|
|
880
|
+
// First successful setup: pre-join configured groups.
|
|
881
|
+
for (const groupName of this._options.groups) {
|
|
882
|
+
const group = this._subscribeGroup(groupName);
|
|
883
|
+
group._activate();
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
else {
|
|
887
|
+
// Server auto-restored topic subscriptions; only room-scoped presence
|
|
888
|
+
// needs re-applying (the core does not restore it) — persistent-presence
|
|
889
|
+
// semantics across reconnects.
|
|
890
|
+
for (const group of this._groups.values()) {
|
|
891
|
+
group._updateLocalPresence();
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
if (stale())
|
|
895
|
+
return;
|
|
896
|
+
// Ready keys on the first setup that COMPLETES, not on epoch 1: an
|
|
897
|
+
// epoch aborted by a racing reconnect must not strand ready().
|
|
898
|
+
if (!this._isReady) {
|
|
899
|
+
this._isReady = true;
|
|
900
|
+
this._readyResolve();
|
|
901
|
+
this.emit('connected');
|
|
902
|
+
}
|
|
903
|
+
else {
|
|
904
|
+
this.emit('reconnected');
|
|
905
|
+
}
|
|
906
|
+
// Deferred lobby refetch: catches devices who joined during the setup
|
|
907
|
+
// window (e.g. simultaneous multi-tab connects).
|
|
908
|
+
this._scheduleLobbyRefresh(epoch);
|
|
909
|
+
}
|
|
910
|
+
_scheduleLobbyRefresh(epoch) {
|
|
911
|
+
if (this._lobbyRefreshTimer)
|
|
912
|
+
clearTimeout(this._lobbyRefreshTimer);
|
|
913
|
+
this._lobbyRefreshTimer = setTimeout(() => {
|
|
914
|
+
this._lobbyRefreshTimer = null;
|
|
915
|
+
if (epoch !== this._epoch || this._detached || !this._client.connected || !this._lobby) {
|
|
916
|
+
return;
|
|
917
|
+
}
|
|
918
|
+
this._lobby
|
|
919
|
+
.fetchPresence()
|
|
920
|
+
.then((state) => {
|
|
921
|
+
if (epoch !== this._epoch || this._detached)
|
|
922
|
+
return;
|
|
923
|
+
this._diffHydrateOnlineDevices(state);
|
|
924
|
+
})
|
|
925
|
+
.catch(() => {
|
|
926
|
+
/* best-effort */
|
|
927
|
+
});
|
|
928
|
+
}, LOBBY_REFRESH_DELAY_MS);
|
|
929
|
+
}
|
|
930
|
+
// ============ Group Management ============
|
|
931
|
+
/**
|
|
932
|
+
* Join a device group. Creates, subscribes, and activates it.
|
|
933
|
+
* Returns an existing group if already joined.
|
|
934
|
+
*/
|
|
935
|
+
joinGroup(name) {
|
|
936
|
+
this._assertUsable();
|
|
937
|
+
let group = this._groups.get(name);
|
|
938
|
+
if (!group) {
|
|
939
|
+
group = this._subscribeGroup(name);
|
|
940
|
+
group._activate();
|
|
941
|
+
}
|
|
942
|
+
return group;
|
|
943
|
+
}
|
|
944
|
+
/**
|
|
945
|
+
* Leave a device group. Fully unsubscribes and removes it.
|
|
946
|
+
*/
|
|
947
|
+
leaveGroup(name) {
|
|
948
|
+
const group = this._groups.get(name);
|
|
949
|
+
if (!group)
|
|
950
|
+
return;
|
|
951
|
+
this._log('Leaving group:', name);
|
|
952
|
+
group._cleanup();
|
|
953
|
+
this._groups.delete(name);
|
|
954
|
+
}
|
|
955
|
+
/**
|
|
956
|
+
* Get all joined groups.
|
|
957
|
+
*/
|
|
958
|
+
getGroups() {
|
|
959
|
+
return Array.from(this._groups.values());
|
|
960
|
+
}
|
|
961
|
+
// ============ Global Presence ============
|
|
962
|
+
/**
|
|
963
|
+
* Get all devices currently online across all groups.
|
|
964
|
+
*/
|
|
965
|
+
getOnlineDevices() {
|
|
966
|
+
return Array.from(this._onlineDevices.values());
|
|
967
|
+
}
|
|
968
|
+
// ============ Private: Guards ============
|
|
969
|
+
_assertUsable() {
|
|
970
|
+
if (this._detached) {
|
|
971
|
+
throw new Error('NoLagIoT has been detached — construct a new instance');
|
|
972
|
+
}
|
|
973
|
+
if (!this._isReady || !this._localDevice) {
|
|
974
|
+
throw new Error('NoLagIoT not ready — await ready() or the "connected" event');
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
// ============ Private: Group Setup ============
|
|
978
|
+
_subscribeGroup(name) {
|
|
979
|
+
this._log('Subscribing group:', name);
|
|
980
|
+
const roomContext = this._client.setApp(this._options.appName).setRoom(name);
|
|
981
|
+
const group = new DeviceGroup(name, roomContext, this._localDevice, this._options, createLogger(`DeviceGroup:${name}`, this._options.debug), () => this._client.connected);
|
|
982
|
+
this._groups.set(name, group);
|
|
983
|
+
group._subscribe();
|
|
984
|
+
return group;
|
|
985
|
+
}
|
|
986
|
+
// ============ Private: Scope Filtering ============
|
|
987
|
+
/**
|
|
988
|
+
* On a shared client, presence events from other apps' wrappers arrive on
|
|
989
|
+
* the same connection-level events. Wrappers stamp their presence with a
|
|
990
|
+
* `__scope` (their appName); a mismatched tag means another app's data.
|
|
991
|
+
* Untagged presence is accepted (older peers in this same app).
|
|
992
|
+
*/
|
|
993
|
+
_foreignScope(data) {
|
|
994
|
+
const scope = data?.__scope;
|
|
995
|
+
return typeof scope === 'string' && scope !== this._options.appName;
|
|
996
|
+
}
|
|
997
|
+
// ============ Private: Room Presence ============
|
|
998
|
+
_handleRoomPresenceJoin(data) {
|
|
999
|
+
if (data.actorTokenId === this._localDevice?.actorTokenId)
|
|
1000
|
+
return;
|
|
1001
|
+
const presenceData = data.presence;
|
|
1002
|
+
if (!presenceData?.deviceId || this._foreignScope(presenceData))
|
|
1003
|
+
return;
|
|
1004
|
+
const device = this._presenceToDevice(data.actorTokenId, presenceData);
|
|
1005
|
+
this._actorToDeviceId.set(data.actorTokenId, device.deviceId);
|
|
1006
|
+
if (!this._onlineDevices.has(device.deviceId)) {
|
|
1007
|
+
this._onlineDevices.set(device.deviceId, device);
|
|
1008
|
+
this.emit('deviceOnline', device);
|
|
1009
|
+
}
|
|
1010
|
+
// Route to all groups
|
|
1011
|
+
for (const group of this._groups.values()) {
|
|
1012
|
+
group._handlePresenceJoin(data.actorTokenId, presenceData);
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
_handleRoomPresenceLeave(data) {
|
|
1016
|
+
if (data.actorTokenId === this._localDevice?.actorTokenId)
|
|
1017
|
+
return;
|
|
1018
|
+
// Route to all groups
|
|
1019
|
+
for (const group of this._groups.values()) {
|
|
1020
|
+
group._handlePresenceLeave(data.actorTokenId);
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
_handleRoomPresenceUpdate(data) {
|
|
1024
|
+
if (data.actorTokenId === this._localDevice?.actorTokenId)
|
|
1025
|
+
return;
|
|
1026
|
+
const presenceData = data.presence;
|
|
1027
|
+
if (!presenceData?.deviceId || this._foreignScope(presenceData))
|
|
1028
|
+
return;
|
|
1029
|
+
if (this._onlineDevices.has(presenceData.deviceId)) {
|
|
1030
|
+
const device = this._presenceToDevice(data.actorTokenId, presenceData);
|
|
1031
|
+
this._onlineDevices.set(device.deviceId, device);
|
|
1032
|
+
}
|
|
1033
|
+
// Route to all groups
|
|
1034
|
+
for (const group of this._groups.values()) {
|
|
1035
|
+
group._handlePresenceUpdate(data.actorTokenId, presenceData);
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
// ============ Private: Lobby ============
|
|
1039
|
+
_handleLobbyJoin(event) {
|
|
1040
|
+
const { actorId, data } = event;
|
|
1041
|
+
if (actorId === this._localDevice?.actorTokenId)
|
|
1042
|
+
return;
|
|
1043
|
+
const presenceData = data;
|
|
1044
|
+
if (!presenceData?.deviceId || this._foreignScope(presenceData))
|
|
1045
|
+
return;
|
|
1046
|
+
const device = this._presenceToDevice(actorId, presenceData);
|
|
1047
|
+
this._actorToDeviceId.set(actorId, device.deviceId);
|
|
1048
|
+
if (!this._onlineDevices.has(device.deviceId)) {
|
|
1049
|
+
this._onlineDevices.set(device.deviceId, device);
|
|
1050
|
+
this.emit('deviceOnline', device);
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
_handleLobbyLeave(event) {
|
|
1054
|
+
const { actorId, data } = event;
|
|
1055
|
+
if (actorId === this._localDevice?.actorTokenId)
|
|
1056
|
+
return;
|
|
1057
|
+
const presenceData = data;
|
|
1058
|
+
if (this._foreignScope(presenceData))
|
|
1059
|
+
return;
|
|
1060
|
+
const deviceId = presenceData?.deviceId
|
|
1061
|
+
|| this._actorToDeviceId.get(actorId)
|
|
1062
|
+
|| this._findDeviceIdByActorId(actorId);
|
|
1063
|
+
if (deviceId) {
|
|
1064
|
+
const device = this._onlineDevices.get(deviceId);
|
|
1065
|
+
if (device) {
|
|
1066
|
+
this._onlineDevices.delete(deviceId);
|
|
1067
|
+
this._actorToDeviceId.delete(actorId);
|
|
1068
|
+
this.emit('deviceOffline', device);
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
_handleLobbyUpdate(event) {
|
|
1073
|
+
const { actorId, data } = event;
|
|
1074
|
+
if (actorId === this._localDevice?.actorTokenId)
|
|
1075
|
+
return;
|
|
1076
|
+
const presenceData = data;
|
|
1077
|
+
if (!presenceData?.deviceId || this._foreignScope(presenceData))
|
|
1078
|
+
return;
|
|
1079
|
+
const device = this._presenceToDevice(actorId, presenceData);
|
|
1080
|
+
this._onlineDevices.set(device.deviceId, device);
|
|
1081
|
+
}
|
|
1082
|
+
/**
|
|
1083
|
+
* Reconcile the online-device map against a fresh lobby snapshot, emitting
|
|
1084
|
+
* only the deltas (deviceOffline for vanished, deviceOnline for new). One
|
|
1085
|
+
* path for initial hydration, reconnect restore, and the deferred refetch.
|
|
1086
|
+
*/
|
|
1087
|
+
_diffHydrateOnlineDevices(state) {
|
|
1088
|
+
// Build the fresh device set from the snapshot
|
|
1089
|
+
const fresh = new Map();
|
|
1090
|
+
const freshActors = new Map();
|
|
1091
|
+
for (const roomId of Object.keys(state)) {
|
|
1092
|
+
const roomPresence = state[roomId];
|
|
1093
|
+
for (const actorId of Object.keys(roomPresence)) {
|
|
1094
|
+
if (actorId === this._localDevice?.actorTokenId)
|
|
1095
|
+
continue;
|
|
1096
|
+
const raw = roomPresence[actorId];
|
|
1097
|
+
// Server returns full actor records with presence nested under .presence
|
|
1098
|
+
const presenceData = (raw?.presence ?? raw);
|
|
1099
|
+
if (presenceData?.deviceId && !this._foreignScope(presenceData)) {
|
|
1100
|
+
if (!fresh.has(presenceData.deviceId)) {
|
|
1101
|
+
fresh.set(presenceData.deviceId, this._presenceToDevice(actorId, presenceData));
|
|
1102
|
+
}
|
|
1103
|
+
freshActors.set(actorId, presenceData.deviceId);
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
// Vanished devices
|
|
1108
|
+
for (const [deviceId, device] of [...this._onlineDevices]) {
|
|
1109
|
+
if (!fresh.has(deviceId)) {
|
|
1110
|
+
this._onlineDevices.delete(deviceId);
|
|
1111
|
+
for (const [actorId, mappedDeviceId] of [...this._actorToDeviceId]) {
|
|
1112
|
+
if (mappedDeviceId === deviceId)
|
|
1113
|
+
this._actorToDeviceId.delete(actorId);
|
|
1114
|
+
}
|
|
1115
|
+
this.emit('deviceOffline', device);
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
// New devices
|
|
1119
|
+
for (const [deviceId, device] of fresh) {
|
|
1120
|
+
if (!this._onlineDevices.has(deviceId)) {
|
|
1121
|
+
this._onlineDevices.set(deviceId, device);
|
|
1122
|
+
this.emit('deviceOnline', device);
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
for (const [actorId, deviceId] of freshActors) {
|
|
1126
|
+
this._actorToDeviceId.set(actorId, deviceId);
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
// ============ Private: Helpers ============
|
|
1130
|
+
_presenceToDevice(actorTokenId, data) {
|
|
1131
|
+
return {
|
|
1132
|
+
deviceId: data.deviceId,
|
|
1133
|
+
actorTokenId,
|
|
1134
|
+
deviceName: data.deviceName,
|
|
1135
|
+
role: data.role,
|
|
1136
|
+
metadata: data.metadata,
|
|
1137
|
+
joinedAt: Date.now(),
|
|
1138
|
+
isLocal: false,
|
|
1139
|
+
};
|
|
1140
|
+
}
|
|
1141
|
+
_findDeviceIdByActorId(actorTokenId) {
|
|
1142
|
+
for (const device of this._onlineDevices.values()) {
|
|
1143
|
+
if (device.actorTokenId === actorTokenId)
|
|
1144
|
+
return device.deviceId;
|
|
1145
|
+
}
|
|
1146
|
+
return undefined;
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
export { CommandManager, DeviceGroup, EventEmitter, NoLagIoT, PresenceManager, TelemetryStore };
|
|
1151
|
+
//# sourceMappingURL=react-native.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react-native.js","sources":["../src/EventEmitter.ts","../src/PresenceManager.ts","../src/TelemetryStore.ts","../src/utils.ts","../src/CommandManager.ts","../src/constants.ts","../src/DeviceGroup.ts","../src/NoLagIoT.ts"],"sourcesContent":[null,null,null,null,null,null,null,null],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nolag/iot",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=18.0.0"
|
|
@@ -9,9 +9,14 @@
|
|
|
9
9
|
"main": "./dist/index.cjs",
|
|
10
10
|
"module": "./dist/index.mjs",
|
|
11
11
|
"browser": "./dist/browser.js",
|
|
12
|
+
"react-native": "./dist/react-native.js",
|
|
12
13
|
"types": "./dist/index.d.ts",
|
|
13
14
|
"exports": {
|
|
14
15
|
".": {
|
|
16
|
+
"react-native": {
|
|
17
|
+
"types": "./dist/react-native.d.ts",
|
|
18
|
+
"default": "./dist/react-native.js"
|
|
19
|
+
},
|
|
15
20
|
"browser": {
|
|
16
21
|
"types": "./dist/browser.d.ts",
|
|
17
22
|
"default": "./dist/browser.js"
|
|
@@ -25,7 +30,8 @@
|
|
|
25
30
|
"default": "./dist/index.cjs"
|
|
26
31
|
},
|
|
27
32
|
"default": "./dist/index.mjs"
|
|
28
|
-
}
|
|
33
|
+
},
|
|
34
|
+
"./package.json": "./package.json"
|
|
29
35
|
},
|
|
30
36
|
"files": [
|
|
31
37
|
"dist"
|
|
@@ -46,10 +52,10 @@
|
|
|
46
52
|
"license": "MIT",
|
|
47
53
|
"homepage": "https://nolag.app",
|
|
48
54
|
"devDependencies": {
|
|
49
|
-
"@nolag/js-sdk": "^1.
|
|
55
|
+
"@nolag/js-sdk": "^1.12.0"
|
|
50
56
|
},
|
|
51
57
|
"peerDependencies": {
|
|
52
|
-
"@nolag/js-sdk": "^1.
|
|
58
|
+
"@nolag/js-sdk": "^1.12.0"
|
|
53
59
|
},
|
|
54
60
|
"publishConfig": {
|
|
55
61
|
"access": "public"
|