homey-api 1.10.20 → 3.0.0-rc.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.
Files changed (55) hide show
  1. package/README.md +1 -1
  2. package/assets/types/homey-api.d.ts +54 -647
  3. package/assets/types/homey-api.private.d.ts +54 -707
  4. package/index.js +1 -1
  5. package/lib/APIErrorNotFound.js +20 -0
  6. package/lib/AthomCloudAPI/Homey.js +3 -1
  7. package/lib/EventEmitter.js +0 -6
  8. package/lib/HomeyAPI/HomeyAPI.js +53 -5
  9. package/lib/HomeyAPI/HomeyAPIErrorNotFound.js +21 -0
  10. package/lib/HomeyAPI/HomeyAPIV2/Manager.js +2 -575
  11. package/lib/HomeyAPI/HomeyAPIV2/ManagerDevices/Capability.js +20 -0
  12. package/lib/HomeyAPI/HomeyAPIV2/ManagerDevices/Device.js +18 -0
  13. package/lib/HomeyAPI/HomeyAPIV2/ManagerDevices.js +6 -3
  14. package/lib/HomeyAPI/HomeyAPIV2/ManagerDrivers/Driver.js +25 -0
  15. package/lib/HomeyAPI/HomeyAPIV2/ManagerDrivers/PairSession.js +20 -0
  16. package/lib/HomeyAPI/HomeyAPIV2/ManagerDrivers.js +46 -0
  17. package/lib/HomeyAPI/HomeyAPIV2/ManagerFlow/AdvancedFlow.js +30 -0
  18. package/lib/HomeyAPI/HomeyAPIV2/ManagerFlow/Flow.js +57 -0
  19. package/lib/HomeyAPI/HomeyAPIV2/ManagerFlow/FlowCardAction.js +25 -0
  20. package/lib/HomeyAPI/HomeyAPIV2/ManagerFlow/FlowCardCondition.js +25 -0
  21. package/lib/HomeyAPI/HomeyAPIV2/ManagerFlow/FlowCardTrigger.js +25 -0
  22. package/lib/HomeyAPI/HomeyAPIV2/ManagerFlow.js +127 -0
  23. package/lib/HomeyAPI/HomeyAPIV2/ManagerFlowToken/FlowToken.js +24 -0
  24. package/lib/HomeyAPI/HomeyAPIV2/ManagerFlowToken.js +29 -0
  25. package/lib/HomeyAPI/HomeyAPIV2/ManagerInsights/Log.js +22 -0
  26. package/lib/HomeyAPI/HomeyAPIV2/ManagerInsights.js +46 -0
  27. package/lib/HomeyAPI/HomeyAPIV2.js +12 -716
  28. package/lib/HomeyAPI/HomeyAPIV3/Item.js +186 -2
  29. package/lib/HomeyAPI/HomeyAPIV3/Manager.js +513 -3
  30. package/lib/HomeyAPI/{HomeyAPIV2 → HomeyAPIV3/ManagerApps}/App.js +1 -1
  31. package/lib/HomeyAPI/{HomeyAPIV2 → HomeyAPIV3}/ManagerApps.js +4 -3
  32. package/lib/HomeyAPI/HomeyAPIV3/ManagerDevices/Capability.js +9 -0
  33. package/lib/HomeyAPI/{HomeyAPIV2 → HomeyAPIV3/ManagerDevices}/Device.js +82 -7
  34. package/lib/HomeyAPI/{HomeyAPIV2 → HomeyAPIV3/ManagerDevices}/DeviceCapability.js +4 -4
  35. package/lib/HomeyAPI/HomeyAPIV3/ManagerDevices.js +17 -0
  36. package/lib/HomeyAPI/HomeyAPIV3/ManagerDrivers/Driver.js +9 -0
  37. package/lib/HomeyAPI/HomeyAPIV3/ManagerDrivers/PairSession.js +9 -0
  38. package/lib/HomeyAPI/HomeyAPIV3/ManagerDrivers.js +17 -0
  39. package/lib/HomeyAPI/HomeyAPIV3/ManagerFlow/AdvancedFlow.js +9 -0
  40. package/lib/HomeyAPI/HomeyAPIV3/ManagerFlow/Flow.js +17 -0
  41. package/lib/HomeyAPI/HomeyAPIV3/ManagerFlow/FlowCard.js +17 -0
  42. package/lib/HomeyAPI/HomeyAPIV3/ManagerFlow/FlowCardAction.js +9 -0
  43. package/lib/HomeyAPI/HomeyAPIV3/ManagerFlow/FlowCardCondition.js +9 -0
  44. package/lib/HomeyAPI/HomeyAPIV3/ManagerFlow/FlowCardTrigger.js +9 -0
  45. package/lib/HomeyAPI/HomeyAPIV3/ManagerFlow.js +12 -23
  46. package/lib/HomeyAPI/HomeyAPIV3/ManagerFlowToken/FlowToken.js +19 -0
  47. package/lib/HomeyAPI/HomeyAPIV3/ManagerFlowToken.js +15 -0
  48. package/lib/HomeyAPI/HomeyAPIV3/ManagerInsights/Log.js +23 -0
  49. package/lib/HomeyAPI/HomeyAPIV3/ManagerInsights.js +15 -0
  50. package/lib/HomeyAPI/HomeyAPIV3.js +728 -4
  51. package/lib/HomeyAPI/HomeyAPIV3Cloud.js +1 -1
  52. package/lib/HomeyAPI/HomeyAPIV3Local.js +1 -1
  53. package/package.json +1 -1
  54. package/lib/HomeyAPI/HomeyAPIApp.js +0 -127
  55. package/lib/HomeyAPI/HomeyAPIV2/Item.js +0 -177
@@ -1,8 +1,192 @@
1
1
  'use strict';
2
2
 
3
- const HomeyAPIV2Item = require('../HomeyAPIV2/Item');
3
+ const EventEmitter = require('../../EventEmitter');
4
4
 
5
- class Item extends HomeyAPIV2Item {
5
+ class Item extends EventEmitter {
6
+
7
+ static ID = null; // Set by Manager.js
8
+
9
+ constructor({
10
+ id,
11
+ homey,
12
+ manager,
13
+ properties,
14
+ }) {
15
+ super();
16
+
17
+ // Set ID
18
+ Object.defineProperty(this, 'id', {
19
+ value: id,
20
+ enumerable: true,
21
+ writable: false,
22
+ });
23
+
24
+ // Set Homey
25
+ Object.defineProperty(this, 'homey', {
26
+ value: homey,
27
+ enumerable: false,
28
+ writable: false,
29
+ });
30
+
31
+ // Set Manager
32
+ Object.defineProperty(this, 'manager', {
33
+ value: manager,
34
+ enumerable: false,
35
+ writable: false,
36
+ });
37
+
38
+ // Set Connected
39
+ Object.defineProperty(this, '__connected', {
40
+ value: false,
41
+ enumerable: false,
42
+ writable: true,
43
+ });
44
+
45
+ // Set Properties
46
+ for (const [key, value] of Object.entries(properties)) {
47
+ if (key === 'id') continue;
48
+
49
+ Object.defineProperty(this, key, {
50
+ value,
51
+ enumerable: true,
52
+ writable: true,
53
+ });
54
+ }
55
+ }
56
+
57
+ get uri() {
58
+ return `homey:${this.constructor.ID}:${this.id}`;
59
+ }
60
+
61
+ __debug(...props) {
62
+ this.manager.__debug(`[${this.constructor.name}:${this.id}]`, ...props);
63
+ }
64
+
65
+ __update(properties) {
66
+ for (const [key, value] of Object.entries(properties)) {
67
+ if (key === 'id') continue;
68
+
69
+ this[key] = value;
70
+ }
71
+
72
+ this.emit('update', properties);
73
+ }
74
+
75
+ __delete() {
76
+ this.destroy();
77
+ this.emit('delete');
78
+ }
79
+
80
+ async connect() {
81
+ this.__debug('connect');
82
+
83
+ // If disconnecting, await that first
84
+ try {
85
+ // Ensure all microtasks are done first. E.g. if disconnect is called in the same tick as
86
+ // connect. This way the disconnect is always started first so we can await the disconnect
87
+ // promise before we try to connect again.
88
+ await Promise.resolve();
89
+ await this.__disconnectPromise;
90
+ } catch (err) { }
91
+
92
+ this.__connectPromise = Promise.resolve().then(async () => {
93
+ if (!this.io) {
94
+ this.io = this.homey.subscribe(this.uri, {
95
+ onConnect: () => {
96
+ this.__debug('onConnect');
97
+ this.__connected = true;
98
+
99
+ this.onConnect();
100
+ },
101
+ onDisconnect: () => {
102
+ this.__debug('onDisconnect');
103
+ this.__connected = false;
104
+
105
+ this.onDisconnect();
106
+ },
107
+ onReconnect: () => {
108
+ this.__debug('onDisconnect');
109
+
110
+ this.onReconnect();
111
+ },
112
+ onEvent: (event, data) => {
113
+ this.__debug('onEvent', event, data);
114
+
115
+ this.emit(event, data);
116
+ },
117
+ });
118
+ }
119
+
120
+ await this.io;
121
+ });
122
+
123
+ // Delete the connecting Promise
124
+ this.__connectPromise
125
+ .catch(() => { })
126
+ .finally(() => {
127
+ delete this.__connectPromise;
128
+ });
129
+
130
+ await this.__connectPromise;
131
+ }
132
+
133
+ async disconnect() {
134
+ this.__debug('disconnect');
135
+
136
+ // If connecting, await that first
137
+ try {
138
+ await this.__connectPromise;
139
+ } catch (err) { }
140
+
141
+ this.__disconnectPromise = Promise.resolve().then(async () => {
142
+ this.__connected = false;
143
+
144
+ if (this.io) {
145
+ this.io
146
+ .then(io => io.unsubscribe())
147
+ .catch(err => this.__debug('Error Disconnecting:', err));
148
+ }
149
+ });
150
+
151
+ // Delete the disconnecting Promise
152
+ this.__disconnectPromise
153
+ .catch(() => { })
154
+ .finally(() => {
155
+ delete this.__disconnectPromise;
156
+ // Delete this.io so connect can start new connections.
157
+ delete this.io;
158
+ });
159
+
160
+ await this.__disconnectPromise;
161
+ }
162
+
163
+ onConnect() {
164
+ // Overload Me
165
+ }
166
+
167
+ onReconnect() {
168
+ // Overload Me
169
+ }
170
+
171
+ onDisconnect() {
172
+ // Overload Me
173
+ }
174
+
175
+ destroy() {
176
+ // Remove all event listeners
177
+ this.removeAllListeners();
178
+
179
+ // Disconnect from Socket.io
180
+ this.disconnect().catch(() => { });
181
+ }
182
+
183
+ static transformGet(item) {
184
+ return item;
185
+ }
186
+
187
+ static transformSet(item) {
188
+ return item;
189
+ }
6
190
 
7
191
  }
8
192
 
@@ -1,14 +1,524 @@
1
+ /* eslint-disable no-multi-assign */
2
+
1
3
  'use strict';
2
4
 
3
- const HomeyAPIV2Manager = require('../HomeyAPIV2/Manager');
5
+ const EventEmitter = require('../../EventEmitter');
6
+ const Util = require('../../Util');
7
+ const HomeyAPIError = require('../HomeyAPIError');
8
+
9
+ // eslint-disable-next-line no-unused-vars
10
+ const Item = require('./Item');
4
11
 
5
12
  /**
6
13
  * @class
7
- * @extends HomeyAPIV2.Manager
8
14
  * @hideconstructor
9
15
  * @memberof HomeyAPIV3
10
16
  */
11
- class Manager extends HomeyAPIV2Manager {
17
+ class Manager extends EventEmitter {
18
+
19
+ static ID = null; // Set by HomeyAPIV3.js
20
+ static CRUD = {};
21
+
22
+ constructor({
23
+ homey,
24
+ items,
25
+ operations,
26
+ }) {
27
+ super();
28
+
29
+ // Set Homey
30
+ Object.defineProperty(this, 'homey', {
31
+ value: homey,
32
+ enumerable: false,
33
+ writable: false,
34
+ });
35
+
36
+ // Set Items
37
+ Object.defineProperty(this, 'items', {
38
+ value: Object.entries(items).reduce((obj, [itemName, item]) => {
39
+ const ItemClass = this.constructor.CRUD[itemName]
40
+ ? this.constructor.CRUD[itemName]
41
+ // eslint-disable-next-line no-eval
42
+ : eval(`(class ${itemName} extends Item {})`);
43
+ ItemClass.ID = item.id;
44
+ obj[item.id] = ItemClass;
45
+
46
+ return obj;
47
+ }, {}),
48
+ enumerable: false,
49
+ writable: false,
50
+ });
51
+
52
+ // Set Connected
53
+ Object.defineProperty(this, '__connected', {
54
+ value: false,
55
+ enumerable: false,
56
+ writable: true,
57
+ });
58
+
59
+ // Set Cache
60
+ Object.defineProperty(this, '__cache', {
61
+ value: Object.values(items).reduce((obj, item) => ({
62
+ ...obj,
63
+ [item.id]: {},
64
+ }), {}),
65
+ enumerable: false,
66
+ writable: false,
67
+ });
68
+
69
+ Object.defineProperty(this, '__cacheAllComplete', {
70
+ value: Object.values(items).reduce((obj, item) => ({
71
+ ...obj,
72
+ [item.id]: false,
73
+ }), {}),
74
+ enumerable: false,
75
+ writable: false,
76
+ });
77
+
78
+ // Create methods
79
+ for (const [operationId, operation] of Object.entries(operations)) {
80
+ Object.defineProperty(this,
81
+ // Name method __super__foo if there's an override method
82
+ this[operationId]
83
+ ? `__super__${operationId}`
84
+ : operationId,
85
+ {
86
+ value: async ({
87
+ $validate = true,
88
+ $cache = true,
89
+ $timeout = operation.timeout ?? 5000,
90
+ $socket = operation.socket ?? true,
91
+ $body = {},
92
+ $query = {},
93
+ $headers = {},
94
+ ...args
95
+ } = {}) => {
96
+ let { path } = operation;
97
+ let body = { ...$body };
98
+ const query = { ...$query };
99
+ const headers = { ...$headers };
100
+
101
+ // Verify & Transform parameters
102
+ if (operation.parameters) {
103
+ // Parse Parameters
104
+ for (const [parameterId, parameter] of Object.entries(operation.parameters)) {
105
+ const value = args[parameterId];
106
+
107
+ // Validate the parameter
108
+ if ($validate) {
109
+ if (parameter.required === true && typeof value === 'undefined') {
110
+ throw new Error(`Missing Parameter: ${parameterId}`);
111
+ }
112
+
113
+ if (typeof value !== 'undefined') {
114
+ if (parameter.type === 'string' && typeof value !== 'string') {
115
+ throw new Error(`Invalid Parameter Type: ${parameterId}. Got: ${typeof value}. Expected: string`);
116
+ }
117
+
118
+ if (parameter.type === 'number' && typeof value !== 'number') {
119
+ throw new Error(`Invalid Parameter Type: ${parameterId}. Got: ${typeof value}. Expected: number`);
120
+ }
121
+
122
+ if (parameter.type === 'boolean' && typeof value !== 'boolean') {
123
+ throw new Error(`Invalid Parameter Type: ${parameterId}. Got: ${typeof value}. Expected: boolean`);
124
+ }
125
+
126
+ if (parameter.type === 'object' && typeof value !== 'object') {
127
+ throw new Error(`Invalid Parameter Type: ${parameterId}. Got: ${typeof value}. Expected: object`);
128
+ }
129
+
130
+ if (parameter.type === 'array' && !Array.isArray(value)) {
131
+ throw new Error(`Invalid Parameter Type: ${parameterId}. Got: ${typeof value}. Expected: array`);
132
+ }
133
+
134
+ if (Array.isArray(parameter.type)) {
135
+ // TODO
136
+ }
137
+ }
138
+ }
139
+
140
+ // Set the parameter
141
+ if (typeof value !== 'undefined') {
142
+ switch (parameter.in) {
143
+ case 'path': {
144
+ if (typeof value !== 'string') {
145
+ throw new Error(`Invalid Parameter Type: ${parameterId}. Got: ${typeof value}. Expected: string`);
146
+ }
147
+
148
+ path = path.replace(`:${parameterId}`, value);
149
+ break;
150
+ }
151
+ case 'body': {
152
+ if (parameter.root) {
153
+ body = value;
154
+ } else {
155
+ body[parameterId] = value;
156
+ }
157
+ break;
158
+ }
159
+ case 'query': {
160
+ if (typeof value !== 'string') {
161
+ throw new Error(`Invalid Parameter Type: ${parameterId}. Got: ${typeof value}. Expected: string`);
162
+ }
163
+
164
+ query[parameterId] = value;
165
+ break;
166
+ }
167
+ default: {
168
+ throw new Error(`Invalid 'in': ${parameter.in}`);
169
+ }
170
+ }
171
+ }
172
+ }
173
+ }
174
+
175
+ // Append query to path
176
+ if (Object.keys(query).length > 0) {
177
+ const queryString = Object.entries(query).map(([key, value]) => {
178
+ return `${key}=${encodeURIComponent(value)}`;
179
+ }).join('&');
180
+ path = `${path}?${queryString}`;
181
+ }
182
+
183
+ let result;
184
+ const benchmark = Util.benchmark();
185
+
186
+ // If connected to Socket.io,
187
+ // try to get the CRUD Item from Cache.
188
+ if (this.isConnected() && operation.crud && $cache === true) {
189
+ const itemId = items[operation.crud.item].id;
190
+
191
+ switch (operation.crud.type) {
192
+ case 'getOne': {
193
+ if (this.__cache[itemId][args.id]) {
194
+ return this.__cache[itemId][args.id];
195
+ }
196
+
197
+ break;
198
+ }
199
+ case 'getAll': {
200
+ if (this.__cache[itemId]
201
+ && this.__cacheAllComplete[itemId]) {
202
+ return this.__cache[itemId];
203
+ }
204
+ break;
205
+ }
206
+ default:
207
+ break;
208
+ }
209
+ }
210
+
211
+ // If Homey is connected to Socket.io,
212
+ // send the API request to socket.io.
213
+ // This is about ~2x faster than HTTP
214
+ if (this.homey.isConnected() && $socket === true) {
215
+ result = await Util.timeout(new Promise((resolve, reject) => {
216
+ this.homey.__ioNamespace.emit('api', {
217
+ args,
218
+ operation: operationId,
219
+ uri: this.uri,
220
+ }, (err, result) => {
221
+ // String Error
222
+ if (typeof err === 'string') {
223
+ err = new HomeyAPIError({
224
+ error: err,
225
+ }, 500);
226
+ return reject(err);
227
+ }
228
+
229
+ // Object Error
230
+ if (typeof err === 'object' && err !== null) {
231
+ err = new HomeyAPIError({
232
+ stack: err.stack,
233
+ error: err.error,
234
+ error_description: err.error_description,
235
+ }, err.statusCode || 500);
236
+ return reject(err);
237
+ }
238
+
239
+ return resolve(result);
240
+ });
241
+ }), $timeout);
242
+ } else {
243
+ // Get from HTTP
244
+ result = await this.homey.call({
245
+ $timeout,
246
+ headers,
247
+ body,
248
+ path: `/api/manager/${this.constructor.ID}${path}`,
249
+ method: operation.method,
250
+ });
251
+ }
252
+
253
+ // Transform and cache output if this is a CRUD call
254
+ if (operation.crud) {
255
+ const itemId = items[operation.crud.item].id;
256
+ const Item = this.items[itemId];
257
+
258
+ switch (operation.crud.type) {
259
+ case 'getOne': {
260
+ let item = { ...result };
261
+ item = Item.transformGet(item);
262
+ item = new Item({
263
+ id: item.id,
264
+ homey: this.homey,
265
+ manager: this,
266
+ properties: { ...item },
267
+ });
268
+
269
+ if (this.isConnected()) {
270
+ this.__cache[itemId][item.id] = item;
271
+ }
272
+
273
+ return item;
274
+ }
275
+ case 'getAll': {
276
+ const items = {};
277
+
278
+ // Add all to cache
279
+ for (let item of Object.values(result)) {
280
+ item = Item.transformGet(item);
281
+ if (this.__cache[itemId][item.id]) {
282
+ items[item.id] = this.__cache[itemId][item.id];
283
+ items[item.id].__update(item);
284
+ } else {
285
+ items[item.id] = new Item({
286
+ id: item.id,
287
+ homey: this.homey,
288
+ manager: this,
289
+ properties: { ...item },
290
+ });
291
+
292
+ if (this.isConnected()) {
293
+ this.__cache[itemId][item.id] = items[item.id];
294
+ }
295
+ }
296
+ }
297
+
298
+ // Find and delete deleted items from cache
299
+ if (this.__cache[itemId]) {
300
+ for (const cachedItem of Object.values(this.__cache[itemId])) {
301
+ if (!items[cachedItem.id]) {
302
+ delete this.__cache[itemId][cachedItem.id];
303
+ }
304
+ }
305
+ }
306
+
307
+ // Mark cache as complete
308
+ if (this.isConnected()) {
309
+ this.__cacheAllComplete[itemId] = true;
310
+ }
311
+
312
+ return items;
313
+ }
314
+ case 'createOne':
315
+ case 'updateOne': {
316
+ let item = { ...result };
317
+ item = Item.transformGet(item);
318
+
319
+ if (this.__cache[itemId][item.id]) {
320
+ item = this.__cache[itemId][item.id];
321
+ item.__update(item);
322
+ } else {
323
+ item = Item.transformGet(item);
324
+ item = new Item({
325
+ id: item.id,
326
+ homey: this.homey,
327
+ manager: this,
328
+ properties: { ...item },
329
+ });
330
+
331
+ if (this.isConnected()) {
332
+ this.__cache[itemId][item.id] = item;
333
+ }
334
+ }
335
+
336
+ return item;
337
+ }
338
+ case 'deleteOne': {
339
+ if (this.__cache[itemId][args.id]) {
340
+ this.__cache[itemId][args.id].destroy();
341
+ delete this.__cache[itemId][args.id];
342
+ }
343
+
344
+ return undefined;
345
+ }
346
+ default:
347
+ break;
348
+ }
349
+ }
350
+
351
+ this.__debug(`${operationId} took ${benchmark()}ms`);
352
+ return result;
353
+ },
354
+ });
355
+ }
356
+ }
357
+
358
+ get uri() {
359
+ return `homey:manager:${this.constructor.ID}`;
360
+ }
361
+
362
+ __debug(...props) {
363
+ this.homey.__debug(`[${this.constructor.name}]`, ...props);
364
+ }
365
+
366
+ /**
367
+ * If this manager's namespace is connected to Socket.io.
368
+ * @returns {Boolean}
369
+ */
370
+ isConnected() {
371
+ return this.__connected === true;
372
+ }
373
+
374
+ /**
375
+ * Connect to the realtime namespace.
376
+ * @returns {Promise<void>}
377
+ */
378
+ async connect() {
379
+ this.__debug('connect');
380
+
381
+ // If disconnecting, await that first
382
+ try {
383
+ await this.__disconnectPromise;
384
+ } catch (err) { }
385
+
386
+ this.__connectPromise = Promise.resolve().then(async () => {
387
+ if (!this.io) {
388
+ this.io = this.homey.subscribe(this.uri, {
389
+ onConnect: () => {
390
+ this.__debug('onConnect');
391
+ this.__connected = true;
392
+ },
393
+ onDisconnect: reason => {
394
+ this.__debug(`onDisconnect Reason:${reason}`);
395
+ this.__connected = false;
396
+
397
+ // Clear CRUD Item cache
398
+ for (const itemId of Object.keys(this.__cache)) {
399
+ this.__cache[itemId] = {};
400
+ this.__cacheAllComplete[itemId] = false;
401
+ }
402
+ },
403
+ onEvent: (event, data) => {
404
+ this.__debug('onEvent', event);
405
+
406
+ // Transform & add to cache if this is a CRUD event
407
+ if (event.endsWith('.create')
408
+ || event.endsWith('.update')
409
+ || event.endsWith('.delete')) {
410
+ const [itemId, operation] = event.split('.');
411
+ const Item = this.items[itemId];
412
+
413
+ switch (operation) {
414
+ case 'create': {
415
+ data = Item.transformGet(data);
416
+
417
+ const item = new Item({
418
+ id: data.id,
419
+ homey: this.homey,
420
+ manager: this,
421
+ properties: { ...data },
422
+ });
423
+ this.__cache[itemId][data.id] = item;
424
+
425
+ break;
426
+ }
427
+ case 'update': {
428
+ data = Item.transformGet(data);
429
+
430
+ if (this.__cache[itemId][data.id]) {
431
+ const item = this.__cache[itemId][data.id];
432
+ item.__update(data);
433
+ }
434
+
435
+ break;
436
+ }
437
+ case 'delete': {
438
+ data = Item.transformGet(data);
439
+
440
+ if (this.__cache[itemId][data.id]) {
441
+ const item = this.__cache[itemId][data.id];
442
+ item.__delete();
443
+ delete this.__cache[itemId][item.id];
444
+ }
445
+
446
+ break;
447
+ }
448
+ default:
449
+ break;
450
+ }
451
+ }
452
+
453
+ // Fire event listeners
454
+ this.emit(event, data);
455
+ },
456
+ });
457
+ }
458
+
459
+ await this.io;
460
+ });
461
+
462
+ // Delete the connecting Promise
463
+ this.__connectPromise
464
+ .catch(() => { })
465
+ .finally(() => {
466
+ delete this.__connectPromise;
467
+ });
468
+
469
+ await this.__connectPromise;
470
+ }
471
+
472
+ /**
473
+ * Disconnect from the realtime namespace.
474
+ * @returns {Promise<void>}
475
+ */
476
+ async disconnect() {
477
+ this.__debug('disconnect');
478
+
479
+ // If connecting, await that first
480
+ try {
481
+ await this.__connectPromise;
482
+ } catch (err) { }
483
+
484
+ this.__disconnectPromise = Promise.resolve().then(async () => {
485
+ this.__connected = false;
486
+
487
+ if (this.io) {
488
+ await this.io
489
+ .then(io => io.unsubscribe())
490
+ .catch(err => this.__debug('Error Disconnecting:', err));
491
+
492
+ delete this.io;
493
+ }
494
+ });
495
+
496
+ // Delete the disconnecting Promise
497
+ this.__disconnectPromise
498
+ .catch(() => { })
499
+ .finally(() => {
500
+ delete this.__disconnectPromise;
501
+ });
502
+
503
+ await this.__disconnectPromise;
504
+ }
505
+
506
+ destroy() {
507
+ // Clear cache
508
+ for (const id of Object.keys(this.__cache)) {
509
+ this.__cache[id] = {};
510
+ }
511
+
512
+ for (const id of Object.keys(this.__cacheAllComplete)) {
513
+ this.__cacheAllComplete[id] = false;
514
+ }
515
+
516
+ // Remove all event listeners
517
+ this.removeAllListeners();
518
+
519
+ // Disconnect from Socket.io
520
+ this.disconnect().catch(() => { });
521
+ }
12
522
 
13
523
  }
14
524