meross-iot 0.2.0 → 0.3.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/CHANGELOG.md +31 -1
- package/README.md +53 -5
- package/index.d.ts +122 -47
- package/index.js +5 -5
- package/lib/controller/device.js +3 -3
- package/lib/controller/features/light-feature.js +1 -1
- package/lib/controller/subdevice.js +4 -4
- package/lib/manager.js +72 -90
- package/lib/subscription.js +4 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,7 +5,37 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
-
## [
|
|
8
|
+
## [0.3.0] - 2026-01-15
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
- **BREAKING**: Renamed core classes to follow Manager-prefix naming pattern
|
|
12
|
+
- `MerossManager` → `ManagerMeross` (all imports/exports)
|
|
13
|
+
- `SubscriptionManager` → `ManagerSubscription` (all imports/exports)
|
|
14
|
+
- **BREAKING**: Replaced method-based access with property-based access patterns
|
|
15
|
+
- Removed `getSubscriptionManager()` method - use `meross.subscription` property instead
|
|
16
|
+
- Removed wrapper methods - use `meross.devices.*` instead:
|
|
17
|
+
- `getDevice(uuid)` → `meross.devices.get(uuid)`
|
|
18
|
+
- `findDevices(filters)` → `meross.devices.find(filters)`
|
|
19
|
+
- `getAllDevices()` → `meross.devices.list()`
|
|
20
|
+
- **BREAKING**: Unified device lookup API in DeviceRegistry
|
|
21
|
+
- Removed `lookupByUuid()` and `lookupByInternalId()` from public API
|
|
22
|
+
- Added unified `get(identifier)` method that handles both base devices and subdevices:
|
|
23
|
+
- Base devices: `meross.devices.get('device-uuid')`
|
|
24
|
+
- Subdevices: `meross.devices.get({ hubUuid: 'hub-uuid', id: 'subdevice-id' })`
|
|
25
|
+
- **BREAKING**: Renamed DeviceRegistry methods for cleaner API
|
|
26
|
+
- `getAllDevices()` → `list()` (returns all devices)
|
|
27
|
+
- `findDevices(filters)` → `find(filters)` (search/filter devices)
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
- Property access to subscription manager: `meross.subscription` returns `ManagerSubscription` instance
|
|
31
|
+
- Property access to device registry: `meross.devices` returns `DeviceRegistry` instance with full API access
|
|
32
|
+
- Unified `get()` method in DeviceRegistry supporting both base devices and subdevices
|
|
33
|
+
- Constructor option `subscription` for configuring subscription manager during initialization
|
|
34
|
+
|
|
35
|
+
## [0.2.1] - 2026-01-14
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
- Fixed syntax error in `example/device-control.js` - missing closing brace for `deviceInitialized` event handler
|
|
9
39
|
|
|
10
40
|
## [0.2.0] - 2026-01-14
|
|
11
41
|
|
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@ The library can control devices locally via HTTP or via cloud MQTT server.
|
|
|
26
26
|
npm install meross-iot@alpha
|
|
27
27
|
|
|
28
28
|
# Or install specific version
|
|
29
|
-
npm install meross-iot@0.
|
|
29
|
+
npm install meross-iot@0.3.0
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
## Usage & Documentation
|
|
@@ -36,7 +36,7 @@ Refer to the [example/README.md](example/README.md) for detailed usage instructi
|
|
|
36
36
|
If you are really impatient to use this library, refer to the following snippet of code that looks for a device and turns it on/off.
|
|
37
37
|
|
|
38
38
|
```javascript
|
|
39
|
-
const {
|
|
39
|
+
const { ManagerMeross, MerossHttpClient } = require('meross-iot');
|
|
40
40
|
|
|
41
41
|
(async () => {
|
|
42
42
|
// Create HTTP client using factory method
|
|
@@ -46,7 +46,7 @@ const { MerossManager, MerossHttpClient } = require('meross-iot');
|
|
|
46
46
|
});
|
|
47
47
|
|
|
48
48
|
// Create manager with HTTP client
|
|
49
|
-
const meross = new
|
|
49
|
+
const meross = new ManagerMeross({
|
|
50
50
|
httpClient: httpClient
|
|
51
51
|
});
|
|
52
52
|
|
|
@@ -59,7 +59,7 @@ const { MerossManager, MerossHttpClient } = require('meross-iot');
|
|
|
59
59
|
await meross.connect();
|
|
60
60
|
|
|
61
61
|
// Find a device and control it
|
|
62
|
-
const devices = meross.
|
|
62
|
+
const devices = meross.devices.list();
|
|
63
63
|
if (devices.length > 0) {
|
|
64
64
|
const device = devices[0];
|
|
65
65
|
|
|
@@ -75,7 +75,7 @@ The `example/` directory contains focused examples for different use cases:
|
|
|
75
75
|
- **`basic-usage.js`** - Simple connection and device discovery
|
|
76
76
|
- **`device-control.js`** - Controlling switches, lights, and monitoring devices
|
|
77
77
|
- **`event-handling.js`** - Handling events from devices and the manager
|
|
78
|
-
- **`subscription-manager.js`** - Automatic polling and unified update streams with
|
|
78
|
+
- **`subscription-manager.js`** - Automatic polling and unified update streams with ManagerSubscription
|
|
79
79
|
- **`token-reuse.js`** - Saving and reusing authentication tokens
|
|
80
80
|
- **`statistics.js`** - Enabling and viewing API call statistics
|
|
81
81
|
- **`error-handling.js`** - Comprehensive error handling and MFA
|
|
@@ -120,6 +120,54 @@ Please create an issue on GitHub and include:
|
|
|
120
120
|
|
|
121
121
|
## Changelog
|
|
122
122
|
|
|
123
|
+
### [0.3.0] - 2026-01-15
|
|
124
|
+
|
|
125
|
+
#### Changed
|
|
126
|
+
- **BREAKING**: Renamed core classes to follow Manager-prefix naming pattern
|
|
127
|
+
- `MerossManager` → `ManagerMeross` (all imports/exports)
|
|
128
|
+
- `SubscriptionManager` → `ManagerSubscription` (all imports/exports)
|
|
129
|
+
- **BREAKING**: Replaced method-based access with property-based access patterns
|
|
130
|
+
- Removed `getSubscriptionManager()` method - use `meross.subscription` property instead
|
|
131
|
+
- Removed wrapper methods - use `meross.devices.*` instead:
|
|
132
|
+
- `getDevice(uuid)` → `meross.devices.get(uuid)`
|
|
133
|
+
- `findDevices(filters)` → `meross.devices.find(filters)`
|
|
134
|
+
- `getAllDevices()` → `meross.devices.list()`
|
|
135
|
+
- **BREAKING**: Unified device lookup API in DeviceRegistry
|
|
136
|
+
- Removed `lookupByUuid()` and `lookupByInternalId()` from public API
|
|
137
|
+
- Added unified `get(identifier)` method that handles both base devices and subdevices:
|
|
138
|
+
- Base devices: `meross.devices.get('device-uuid')`
|
|
139
|
+
- Subdevices: `meross.devices.get({ hubUuid: 'hub-uuid', id: 'subdevice-id' })`
|
|
140
|
+
- **BREAKING**: Renamed DeviceRegistry methods for cleaner API
|
|
141
|
+
- `getAllDevices()` → `list()` (returns all devices)
|
|
142
|
+
- `findDevices(filters)` → `find(filters)` (search/filter devices)
|
|
143
|
+
|
|
144
|
+
#### Added
|
|
145
|
+
- Property access to subscription manager: `meross.subscription` returns `ManagerSubscription` instance
|
|
146
|
+
- Property access to device registry: `meross.devices` returns `DeviceRegistry` instance with full API access
|
|
147
|
+
- Unified `get()` method in DeviceRegistry supporting both base devices and subdevices
|
|
148
|
+
- Constructor option `subscription` for configuring subscription manager during initialization
|
|
149
|
+
|
|
150
|
+
### [0.2.1] - 2026-01-14
|
|
151
|
+
|
|
152
|
+
#### Fixed
|
|
153
|
+
- Fixed syntax error in `device-control.js` example - missing closing brace for `deviceInitialized` event handler
|
|
154
|
+
|
|
155
|
+
### [0.2.0] - 2026-01-14
|
|
156
|
+
|
|
157
|
+
#### Changed
|
|
158
|
+
- **BREAKING**: `SubscriptionManager` now uses EventEmitter pattern instead of callbacks
|
|
159
|
+
- `subscribe(device, config, onUpdate)` → `subscribe(device, config)` (no callback, no return value)
|
|
160
|
+
- `unsubscribe(deviceUuid, subscriptionId)` → `unsubscribe(deviceUuid)` (no subscription ID needed)
|
|
161
|
+
- `subscribeToDeviceList(onUpdate)` → `subscribeToDeviceList()` (no callback, no return value)
|
|
162
|
+
- `unsubscribeFromDeviceList(subscriptionId)` → `unsubscribeFromDeviceList()` (no subscription ID needed)
|
|
163
|
+
- Listen for updates using: `on('deviceUpdate:${deviceUuid}', handler)` and `on('deviceListUpdate', handler)`
|
|
164
|
+
- Use standard EventEmitter methods: `on()`, `once()`, `off()`, `removeAllListeners()`
|
|
165
|
+
- Configuration is now per-device subscription (merged aggressively) rather than per-listener
|
|
166
|
+
|
|
167
|
+
#### Added
|
|
168
|
+
- `subscription-manager.js` example demonstrating EventEmitter-based SubscriptionManager usage
|
|
169
|
+
- Enhanced documentation for SubscriptionManager with JSDoc comments explaining implementation rationale
|
|
170
|
+
|
|
123
171
|
### [0.1.0] - 2026-01-10
|
|
124
172
|
|
|
125
173
|
#### Added
|
package/index.d.ts
CHANGED
|
@@ -436,7 +436,7 @@ declare module 'meross-iot' {
|
|
|
436
436
|
}
|
|
437
437
|
|
|
438
438
|
/**
|
|
439
|
-
* Configuration options for
|
|
439
|
+
* Configuration options for ManagerMeross cloud manager.
|
|
440
440
|
*
|
|
441
441
|
* @example
|
|
442
442
|
* ```typescript
|
|
@@ -445,7 +445,7 @@ declare module 'meross-iot' {
|
|
|
445
445
|
* password: 'password'
|
|
446
446
|
* });
|
|
447
447
|
*
|
|
448
|
-
* const manager = new
|
|
448
|
+
* const manager = new ManagerMeross({
|
|
449
449
|
* httpClient,
|
|
450
450
|
* transportMode: TransportMode.LAN_HTTP_FIRST,
|
|
451
451
|
* logger: console.log
|
|
@@ -476,7 +476,9 @@ declare module 'meross-iot' {
|
|
|
476
476
|
/** Delay in milliseconds between batches (default: 200) */
|
|
477
477
|
requestBatchDelay?: number,
|
|
478
478
|
/** Enable/disable request throttling (default: true) */
|
|
479
|
-
enableRequestThrottling?: boolean
|
|
479
|
+
enableRequestThrottling?: boolean,
|
|
480
|
+
/** Subscription manager options for automatic polling and data provisioning */
|
|
481
|
+
subscription?: ManagerSubscriptionOptions
|
|
480
482
|
}
|
|
481
483
|
|
|
482
484
|
export interface LightData {
|
|
@@ -1115,18 +1117,18 @@ declare module 'meross-iot' {
|
|
|
1115
1117
|
/**
|
|
1116
1118
|
* Filter options for finding devices.
|
|
1117
1119
|
*
|
|
1118
|
-
* Used with
|
|
1120
|
+
* Used with DeviceRegistry.find() to filter the device list.
|
|
1119
1121
|
*
|
|
1120
1122
|
* @example
|
|
1121
1123
|
* ```typescript
|
|
1122
1124
|
* // Find online devices
|
|
1123
|
-
* const onlineDevices = manager.
|
|
1125
|
+
* const onlineDevices = manager.devices.find({ online_status: 1 });
|
|
1124
1126
|
*
|
|
1125
1127
|
* // Find specific device types
|
|
1126
|
-
* const plugs = manager.
|
|
1128
|
+
* const plugs = manager.devices.find({ device_type: 'mss310' });
|
|
1127
1129
|
*
|
|
1128
1130
|
* // Find by custom filter function
|
|
1129
|
-
* const customDevices = manager.
|
|
1131
|
+
* const customDevices = manager.devices.find({
|
|
1130
1132
|
* device_class: (device) => device.deviceType.startsWith('mss')
|
|
1131
1133
|
* });
|
|
1132
1134
|
* ```
|
|
@@ -1146,6 +1148,102 @@ declare module 'meross-iot' {
|
|
|
1146
1148
|
device_class?: string | ((device: MerossDevice) => boolean) | Array<string | ((device: MerossDevice) => boolean)>;
|
|
1147
1149
|
}
|
|
1148
1150
|
|
|
1151
|
+
/**
|
|
1152
|
+
* Registry for managing Meross devices and subdevices.
|
|
1153
|
+
*
|
|
1154
|
+
* Maintains indexes for efficient device lookups across base devices and subdevices.
|
|
1155
|
+
* Base devices can be looked up by UUID, while internal IDs enable unified lookup
|
|
1156
|
+
* for both base devices and subdevices.
|
|
1157
|
+
*
|
|
1158
|
+
* Internal IDs unify device identification:
|
|
1159
|
+
* - Base devices: `#BASE:{uuid}`
|
|
1160
|
+
* - Subdevices: `#SUB:{hubUuid}:{subdeviceId}`
|
|
1161
|
+
*
|
|
1162
|
+
* @example
|
|
1163
|
+
* ```typescript
|
|
1164
|
+
* // Look up device by UUID
|
|
1165
|
+
* const device = manager.devices.get('device-uuid');
|
|
1166
|
+
*
|
|
1167
|
+
* // Look up subdevice by hub UUID and subdevice ID
|
|
1168
|
+
* const subdevice = manager.devices.get({ hubUuid: 'hub-uuid', id: 'subdevice-id' });
|
|
1169
|
+
*
|
|
1170
|
+
* // Find devices matching filters
|
|
1171
|
+
* const lights = manager.devices.find({ device_class: 'light' });
|
|
1172
|
+
*
|
|
1173
|
+
* // Get all devices
|
|
1174
|
+
* const allDevices = manager.devices.list();
|
|
1175
|
+
* ```
|
|
1176
|
+
*/
|
|
1177
|
+
export class DeviceRegistry {
|
|
1178
|
+
/**
|
|
1179
|
+
* Generates an internal ID for a device or subdevice.
|
|
1180
|
+
*
|
|
1181
|
+
* @param uuid - Device UUID (for base devices) or hub UUID (for subdevices)
|
|
1182
|
+
* @param isSubdevice - Whether this is a subdevice
|
|
1183
|
+
* @param hubUuid - Hub UUID (required if isSubdevice is true)
|
|
1184
|
+
* @param subdeviceId - Subdevice ID (required if isSubdevice is true)
|
|
1185
|
+
* @returns Internal ID string
|
|
1186
|
+
*/
|
|
1187
|
+
static generateInternalId(uuid: string, isSubdevice?: boolean, hubUuid?: string | null, subdeviceId?: string | null): string
|
|
1188
|
+
|
|
1189
|
+
/**
|
|
1190
|
+
* Registers a device in the registry.
|
|
1191
|
+
*
|
|
1192
|
+
* @param device - Device instance to register
|
|
1193
|
+
*/
|
|
1194
|
+
registerDevice(device: MerossDevice | MerossHubDevice | MerossSubDevice): void
|
|
1195
|
+
|
|
1196
|
+
/**
|
|
1197
|
+
* Removes a device from the registry.
|
|
1198
|
+
*
|
|
1199
|
+
* @param device - Device instance to remove
|
|
1200
|
+
*/
|
|
1201
|
+
removeDevice(device: MerossDevice | MerossHubDevice | MerossSubDevice): void
|
|
1202
|
+
|
|
1203
|
+
/**
|
|
1204
|
+
* Unified method to get a device by identifier.
|
|
1205
|
+
*
|
|
1206
|
+
* Supports both base devices (by UUID string) and subdevices (by object with hubUuid and id).
|
|
1207
|
+
* Internally converts the identifier to an internal ID format and performs the lookup.
|
|
1208
|
+
*
|
|
1209
|
+
* @param identifier - Device identifier
|
|
1210
|
+
* @returns Device instance, or null if not found
|
|
1211
|
+
* @example
|
|
1212
|
+
* // Get base device by UUID
|
|
1213
|
+
* const device = registry.get('device-uuid');
|
|
1214
|
+
*
|
|
1215
|
+
* @example
|
|
1216
|
+
* // Get subdevice by hub UUID and subdevice ID
|
|
1217
|
+
* const subdevice = registry.get({ hubUuid: 'hub-uuid', id: 'subdevice-id' });
|
|
1218
|
+
*/
|
|
1219
|
+
get(identifier: string | { hubUuid: string; id: string }): MerossDevice | MerossHubDevice | MerossSubDevice | null
|
|
1220
|
+
|
|
1221
|
+
/**
|
|
1222
|
+
* Gets all registered devices.
|
|
1223
|
+
*
|
|
1224
|
+
* @returns Array of all registered devices
|
|
1225
|
+
*/
|
|
1226
|
+
list(): Array<MerossDevice | MerossHubDevice | MerossSubDevice>
|
|
1227
|
+
|
|
1228
|
+
/**
|
|
1229
|
+
* Finds devices matching the specified filters.
|
|
1230
|
+
*
|
|
1231
|
+
* @param filters - Optional filter criteria
|
|
1232
|
+
* @returns Array of matching devices
|
|
1233
|
+
*/
|
|
1234
|
+
find(filters?: FindDevicesFilters): Array<MerossDevice | MerossHubDevice | MerossSubDevice>
|
|
1235
|
+
|
|
1236
|
+
/**
|
|
1237
|
+
* Clears all devices from the registry.
|
|
1238
|
+
*/
|
|
1239
|
+
clear(): void
|
|
1240
|
+
|
|
1241
|
+
/**
|
|
1242
|
+
* Gets the total number of devices registered (including subdevices).
|
|
1243
|
+
*/
|
|
1244
|
+
readonly size: number
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1149
1247
|
// Statistics types
|
|
1150
1248
|
export class HttpRequestSample {
|
|
1151
1249
|
readonly url: string;
|
|
@@ -1335,9 +1433,9 @@ declare module 'meross-iot' {
|
|
|
1335
1433
|
isStatsEnabled(): boolean;
|
|
1336
1434
|
}
|
|
1337
1435
|
|
|
1338
|
-
export function createDebugUtils(manager:
|
|
1436
|
+
export function createDebugUtils(manager: ManagerMeross): DebugUtils;
|
|
1339
1437
|
|
|
1340
|
-
export interface
|
|
1438
|
+
export interface ManagerSubscriptionOptions {
|
|
1341
1439
|
/** Logger function for debug output */
|
|
1342
1440
|
logger?: Logger;
|
|
1343
1441
|
deviceStateInterval?: number;
|
|
@@ -1372,9 +1470,9 @@ declare module 'meross-iot' {
|
|
|
1372
1470
|
timestamp: number
|
|
1373
1471
|
}
|
|
1374
1472
|
|
|
1375
|
-
export class
|
|
1376
|
-
constructor(manager:
|
|
1377
|
-
subscribe(device: MerossDevice, config?:
|
|
1473
|
+
export class ManagerSubscription extends EventEmitter {
|
|
1474
|
+
constructor(manager: ManagerMeross, options?: ManagerSubscriptionOptions);
|
|
1475
|
+
subscribe(device: MerossDevice, config?: ManagerSubscriptionOptions): void;
|
|
1378
1476
|
unsubscribe(deviceUuid: string): void;
|
|
1379
1477
|
subscribeToDeviceList(): void;
|
|
1380
1478
|
unsubscribeFromDeviceList(): void;
|
|
@@ -1399,19 +1497,19 @@ declare module 'meross-iot' {
|
|
|
1399
1497
|
* password: 'password'
|
|
1400
1498
|
* });
|
|
1401
1499
|
*
|
|
1402
|
-
* const manager = new
|
|
1500
|
+
* const manager = new ManagerMeross({ httpClient });
|
|
1403
1501
|
* await manager.connect();
|
|
1404
1502
|
*
|
|
1405
1503
|
* manager.on('deviceInitialized', (deviceId, deviceDef, device) => {
|
|
1406
1504
|
* console.log(`Device ${deviceId} initialized`);
|
|
1407
1505
|
* });
|
|
1408
1506
|
*
|
|
1409
|
-
* const devices = manager.
|
|
1507
|
+
* const devices = manager.devices.list();
|
|
1410
1508
|
* ```
|
|
1411
1509
|
*/
|
|
1412
|
-
export class
|
|
1510
|
+
export class ManagerMeross extends EventEmitter {
|
|
1413
1511
|
/**
|
|
1414
|
-
* Creates a new
|
|
1512
|
+
* Creates a new ManagerMeross instance.
|
|
1415
1513
|
*
|
|
1416
1514
|
* @param options - Configuration options
|
|
1417
1515
|
*/
|
|
@@ -1466,35 +1564,6 @@ declare module 'meross-iot' {
|
|
|
1466
1564
|
*/
|
|
1467
1565
|
disconnectAll(force: boolean): void
|
|
1468
1566
|
|
|
1469
|
-
/**
|
|
1470
|
-
* Gets a device by UUID.
|
|
1471
|
-
*
|
|
1472
|
-
* @param uuid - Device UUID
|
|
1473
|
-
* @returns Device instance or null if not found
|
|
1474
|
-
*/
|
|
1475
|
-
getDevice(uuid: string): MerossDevice | null
|
|
1476
|
-
|
|
1477
|
-
/**
|
|
1478
|
-
* Finds devices matching the specified filters.
|
|
1479
|
-
*
|
|
1480
|
-
* @param filters - Optional filter criteria
|
|
1481
|
-
* @returns Array of matching device instances
|
|
1482
|
-
*
|
|
1483
|
-
* @example
|
|
1484
|
-
* ```typescript
|
|
1485
|
-
* const onlineDevices = manager.findDevices({ online_status: 1 });
|
|
1486
|
-
* const plugs = manager.findDevices({ device_type: 'mss310' });
|
|
1487
|
-
* ```
|
|
1488
|
-
*/
|
|
1489
|
-
findDevices(filters?: FindDevicesFilters): MerossDevice[]
|
|
1490
|
-
|
|
1491
|
-
/**
|
|
1492
|
-
* Gets all initialized devices.
|
|
1493
|
-
*
|
|
1494
|
-
* @returns Array of all device instances
|
|
1495
|
-
*/
|
|
1496
|
-
getAllDevices(): MerossDevice[]
|
|
1497
|
-
|
|
1498
1567
|
/**
|
|
1499
1568
|
* Gets the current token data.
|
|
1500
1569
|
*
|
|
@@ -1504,6 +1573,12 @@ declare module 'meross-iot' {
|
|
|
1504
1573
|
|
|
1505
1574
|
/** HTTP client instance */
|
|
1506
1575
|
readonly httpClient: MerossHttpClient
|
|
1576
|
+
|
|
1577
|
+
/** Subscription manager instance for automatic polling and data provisioning */
|
|
1578
|
+
readonly subscription: ManagerSubscription
|
|
1579
|
+
|
|
1580
|
+
/** Device registry instance for device lookups and queries */
|
|
1581
|
+
readonly devices: DeviceRegistry
|
|
1507
1582
|
}
|
|
1508
1583
|
|
|
1509
1584
|
|
|
@@ -1684,7 +1759,7 @@ declare module 'meross-iot' {
|
|
|
1684
1759
|
*
|
|
1685
1760
|
* @example
|
|
1686
1761
|
* ```typescript
|
|
1687
|
-
* const device = manager.
|
|
1762
|
+
* const device = manager.devices.get('device-uuid');
|
|
1688
1763
|
*
|
|
1689
1764
|
* device.on('connected', () => {
|
|
1690
1765
|
* console.log('Device connected');
|
|
@@ -2359,5 +2434,5 @@ declare module 'meross-iot' {
|
|
|
2359
2434
|
mqttDomain?: string
|
|
2360
2435
|
}): MerossError
|
|
2361
2436
|
|
|
2362
|
-
export default
|
|
2437
|
+
export default ManagerMeross
|
|
2363
2438
|
}
|
package/index.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
// Main entry point - re-export everything from new modular structure
|
|
4
|
-
const
|
|
4
|
+
const ManagerMeross = require('./lib/manager');
|
|
5
5
|
const enums = require('./lib/model/enums');
|
|
6
6
|
const errors = require('./lib/model/exception');
|
|
7
7
|
const states = require('./lib/model/states');
|
|
8
8
|
const push = require('./lib/model/push');
|
|
9
9
|
|
|
10
10
|
// Export main class
|
|
11
|
-
module.exports =
|
|
11
|
+
module.exports = ManagerMeross;
|
|
12
12
|
|
|
13
13
|
// Export error classes
|
|
14
14
|
const httpExceptions = require('./lib/model/http/exception');
|
|
@@ -126,6 +126,6 @@ module.exports.HubSmokeDetector = subdevice.HubSmokeDetector;
|
|
|
126
126
|
const MerossHttpClient = require('./lib/http-api');
|
|
127
127
|
module.exports.MerossHttpClient = MerossHttpClient;
|
|
128
128
|
|
|
129
|
-
// Export
|
|
130
|
-
const
|
|
131
|
-
module.exports.
|
|
129
|
+
// Export ManagerSubscription class
|
|
130
|
+
const ManagerSubscription = require('./lib/subscription');
|
|
131
|
+
module.exports.ManagerSubscription = ManagerSubscription;
|
package/lib/controller/device.js
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
const EventEmitter = require('events');
|
|
4
4
|
const { OnlineStatus } = require('../model/enums');
|
|
5
5
|
const { parsePushNotification } = require('../model/push');
|
|
6
|
-
// DeviceRegistry is nested in
|
|
7
|
-
const {
|
|
6
|
+
// DeviceRegistry is nested in ManagerMeross but exported separately to avoid circular dependencies
|
|
7
|
+
const { ManagerMeross } = require('../manager');
|
|
8
8
|
const ChannelInfo = require('../model/channel-info');
|
|
9
9
|
const HttpDeviceInfo = require('../model/http/device');
|
|
10
10
|
const {
|
|
@@ -299,7 +299,7 @@ class MerossDevice extends EventEmitter {
|
|
|
299
299
|
throw new UnknownDeviceTypeError('Cannot generate internal ID: device missing UUID');
|
|
300
300
|
}
|
|
301
301
|
|
|
302
|
-
this._internalId =
|
|
302
|
+
this._internalId = ManagerMeross.DeviceRegistry.generateInternalId(this.uuid);
|
|
303
303
|
return this._internalId;
|
|
304
304
|
}
|
|
305
305
|
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
const { MerossDevice } = require('./device');
|
|
4
4
|
const { OnlineStatus, SmokeAlarmStatus } = require('../model/enums');
|
|
5
|
-
// DeviceRegistry is nested in
|
|
6
|
-
const {
|
|
5
|
+
// DeviceRegistry is nested in ManagerMeross but exported separately to avoid circular dependencies
|
|
6
|
+
const { ManagerMeross } = require('../manager');
|
|
7
7
|
const { UnknownDeviceTypeError, CommandError } = require('../model/exception');
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -42,7 +42,7 @@ class MerossSubDevice extends MerossDevice {
|
|
|
42
42
|
*/
|
|
43
43
|
constructor(hubDeviceUuid, subdeviceId, manager, kwargs = {}) {
|
|
44
44
|
// eslint-disable-next-line camelcase
|
|
45
|
-
const hubs = manager.
|
|
45
|
+
const hubs = manager.devices.find({ device_uuids: [hubDeviceUuid] });
|
|
46
46
|
if (!hubs || hubs.length < 1) {
|
|
47
47
|
throw new UnknownDeviceTypeError(`Specified hub device ${hubDeviceUuid} is not present`);
|
|
48
48
|
}
|
|
@@ -137,7 +137,7 @@ class MerossSubDevice extends MerossDevice {
|
|
|
137
137
|
throw new UnknownDeviceTypeError('Cannot generate internal ID: hub missing UUID');
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
-
this._internalId =
|
|
140
|
+
this._internalId = ManagerMeross.DeviceRegistry.generateInternalId(hubUuid, true, hubUuid, this._subdeviceId);
|
|
141
141
|
return this._internalId;
|
|
142
142
|
}
|
|
143
143
|
|
package/lib/manager.js
CHANGED
|
@@ -34,9 +34,9 @@ const { HttpApiError } = require('./model/http/exception');
|
|
|
34
34
|
* @class
|
|
35
35
|
* @extends EventEmitter
|
|
36
36
|
*/
|
|
37
|
-
class
|
|
37
|
+
class ManagerMeross extends EventEmitter {
|
|
38
38
|
/**
|
|
39
|
-
* Creates a new
|
|
39
|
+
* Creates a new ManagerMeross instance
|
|
40
40
|
*
|
|
41
41
|
* @param {Object} options - Configuration options
|
|
42
42
|
* @param {MerossHttpClient} options.httpClient - HTTP client instance (required)
|
|
@@ -94,7 +94,7 @@ class MerossManager extends EventEmitter {
|
|
|
94
94
|
|
|
95
95
|
this.mqttConnections = {};
|
|
96
96
|
this._mqttConnectionPromises = new Map();
|
|
97
|
-
this._deviceRegistry = new
|
|
97
|
+
this._deviceRegistry = new ManagerMeross.DeviceRegistry();
|
|
98
98
|
this._appId = null;
|
|
99
99
|
this.clientResponseTopic = null;
|
|
100
100
|
this._pendingMessagesFutures = new Map();
|
|
@@ -104,6 +104,9 @@ class MerossManager extends EventEmitter {
|
|
|
104
104
|
|
|
105
105
|
this.httpClient = options.httpClient;
|
|
106
106
|
|
|
107
|
+
// Store subscription options from constructor for lazy initialization
|
|
108
|
+
this._subscriptionOptions = options.subscription || {};
|
|
109
|
+
|
|
107
110
|
// Reuse authentication from HTTP client if already authenticated to avoid
|
|
108
111
|
// redundant authentication and share credentials between HTTP and MQTT connections
|
|
109
112
|
if (this.httpClient.token) {
|
|
@@ -490,51 +493,6 @@ class MerossManager extends EventEmitter {
|
|
|
490
493
|
return response;
|
|
491
494
|
}
|
|
492
495
|
|
|
493
|
-
/**
|
|
494
|
-
* Gets a device by UUID
|
|
495
|
-
*
|
|
496
|
-
* @param {string} uuid - Device UUID
|
|
497
|
-
* @returns {MerossDevice|MerossHubDevice|undefined} Device instance or undefined if not found
|
|
498
|
-
*/
|
|
499
|
-
getDevice(uuid) {
|
|
500
|
-
return this._deviceRegistry.lookupByUuid(uuid);
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
/**
|
|
504
|
-
* Finds devices matching the specified filters
|
|
505
|
-
*
|
|
506
|
-
* @param {Object} [filters={}] - Filter criteria
|
|
507
|
-
* @param {string[]} [filters.device_uuids] - Array of device UUIDs to match (snake_case to match API)
|
|
508
|
-
* @param {string[]} [filters.internal_ids] - Array of internal IDs to match
|
|
509
|
-
* @param {string} [filters.device_type] - Device type to match (e.g., 'mss310')
|
|
510
|
-
* @param {string} [filters.device_name] - Device name to match
|
|
511
|
-
* @param {number} [filters.online_status] - Online status to match (from OnlineStatus enum)
|
|
512
|
-
* @param {string|Function|Array} [filters.device_class] - Device class filter (string, function, or array)
|
|
513
|
-
* @returns {Array<MerossDevice|MerossHubDevice>} Array of matching devices
|
|
514
|
-
*/
|
|
515
|
-
findDevices(filters = {}) {
|
|
516
|
-
return this._deviceRegistry.findDevices(filters);
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
/**
|
|
520
|
-
* Gets all registered devices
|
|
521
|
-
*
|
|
522
|
-
* @returns {Array<MerossDevice|MerossHubDevice>} Array of all devices
|
|
523
|
-
*/
|
|
524
|
-
getAllDevices() {
|
|
525
|
-
return this._deviceRegistry.getAllDevices();
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
/**
|
|
529
|
-
* Gets a device by UUID (internal helper method)
|
|
530
|
-
*
|
|
531
|
-
* @param {string} uuid - Device UUID
|
|
532
|
-
* @returns {MerossDevice|MerossHubDevice|undefined} Device instance or undefined if not found
|
|
533
|
-
* @private
|
|
534
|
-
*/
|
|
535
|
-
_getDeviceByUuid(uuid) {
|
|
536
|
-
return this._deviceRegistry.lookupByUuid(uuid);
|
|
537
|
-
}
|
|
538
496
|
|
|
539
497
|
/**
|
|
540
498
|
* Disconnects all devices and closes all MQTT connections
|
|
@@ -547,7 +505,7 @@ class MerossManager extends EventEmitter {
|
|
|
547
505
|
*/
|
|
548
506
|
disconnectAll(force) {
|
|
549
507
|
// Retrieve devices before clearing registry to allow queue cleanup
|
|
550
|
-
const devices = this._deviceRegistry.
|
|
508
|
+
const devices = this._deviceRegistry.list();
|
|
551
509
|
this._deviceRegistry.clear();
|
|
552
510
|
|
|
553
511
|
if (this._requestQueue) {
|
|
@@ -650,7 +608,7 @@ class MerossManager extends EventEmitter {
|
|
|
650
608
|
}
|
|
651
609
|
|
|
652
610
|
this.mqttConnections[domain].deviceList.forEach(devId => {
|
|
653
|
-
const device = this.
|
|
611
|
+
const device = this._deviceRegistry._devicesByUuid.get(devId) || null;
|
|
654
612
|
if (device) {
|
|
655
613
|
device.emit('connected');
|
|
656
614
|
}
|
|
@@ -660,7 +618,7 @@ class MerossManager extends EventEmitter {
|
|
|
660
618
|
client.on('error', (error) => {
|
|
661
619
|
// MQTT client handles reconnection automatically via reconnectPeriod option
|
|
662
620
|
this.mqttConnections[domain].deviceList.forEach(devId => {
|
|
663
|
-
const device = this.
|
|
621
|
+
const device = this._deviceRegistry._devicesByUuid.get(devId) || null;
|
|
664
622
|
if (device) {
|
|
665
623
|
device.emit('error', error ? error.toString() : null);
|
|
666
624
|
}
|
|
@@ -669,7 +627,7 @@ class MerossManager extends EventEmitter {
|
|
|
669
627
|
|
|
670
628
|
client.on('close', (error) => {
|
|
671
629
|
this.mqttConnections[domain].deviceList.forEach(devId => {
|
|
672
|
-
const device = this.
|
|
630
|
+
const device = this._deviceRegistry._devicesByUuid.get(devId) || null;
|
|
673
631
|
if (device) {
|
|
674
632
|
device.emit('close', error ? error.toString() : null);
|
|
675
633
|
}
|
|
@@ -678,7 +636,7 @@ class MerossManager extends EventEmitter {
|
|
|
678
636
|
|
|
679
637
|
client.on('reconnect', () => {
|
|
680
638
|
this.mqttConnections[domain].deviceList.forEach(devId => {
|
|
681
|
-
const device = this.
|
|
639
|
+
const device = this._deviceRegistry._devicesByUuid.get(devId) || null;
|
|
682
640
|
if (device) {
|
|
683
641
|
device.emit('reconnect');
|
|
684
642
|
}
|
|
@@ -734,7 +692,7 @@ class MerossManager extends EventEmitter {
|
|
|
734
692
|
|
|
735
693
|
if (!message.header.from) {return;}
|
|
736
694
|
const deviceUuid = deviceUuidFromPushNotification(message.header.from);
|
|
737
|
-
const device = this.
|
|
695
|
+
const device = this._deviceRegistry._devicesByUuid.get(deviceUuid) || null;
|
|
738
696
|
if (device) {
|
|
739
697
|
device.handleMessage(message);
|
|
740
698
|
}
|
|
@@ -831,7 +789,7 @@ class MerossManager extends EventEmitter {
|
|
|
831
789
|
const topic = buildDeviceRequestTopic(device.uuid);
|
|
832
790
|
this.mqttConnections[domain].client.publish(topic, JSON.stringify(data), undefined, err => {
|
|
833
791
|
if (err) {
|
|
834
|
-
const deviceObj = this.
|
|
792
|
+
const deviceObj = this._deviceRegistry._devicesByUuid.get(device.uuid) || null;
|
|
835
793
|
if (deviceObj) {
|
|
836
794
|
deviceObj.emit('error', err);
|
|
837
795
|
}
|
|
@@ -1230,25 +1188,40 @@ class MerossManager extends EventEmitter {
|
|
|
1230
1188
|
}
|
|
1231
1189
|
|
|
1232
1190
|
/**
|
|
1233
|
-
* Gets or creates the
|
|
1191
|
+
* Gets or creates the ManagerSubscription instance
|
|
1234
1192
|
*
|
|
1235
1193
|
* Provides automatic polling and data provisioning for devices.
|
|
1236
1194
|
* Uses lazy initialization to create the manager only when needed.
|
|
1195
|
+
* Merges constructor subscription options with any additional options.
|
|
1237
1196
|
*
|
|
1238
|
-
* @
|
|
1239
|
-
* @returns {SubscriptionManager} SubscriptionManager instance
|
|
1197
|
+
* @returns {ManagerSubscription} ManagerSubscription instance
|
|
1240
1198
|
*/
|
|
1241
|
-
|
|
1199
|
+
get subscription() {
|
|
1242
1200
|
if (!this._subscriptionManager) {
|
|
1243
|
-
const
|
|
1244
|
-
this._subscriptionManager = new
|
|
1201
|
+
const ManagerSubscription = require('./subscription');
|
|
1202
|
+
this._subscriptionManager = new ManagerSubscription(this, {
|
|
1245
1203
|
logger: this.options?.logger,
|
|
1246
|
-
...
|
|
1204
|
+
...this._subscriptionOptions
|
|
1247
1205
|
});
|
|
1248
1206
|
}
|
|
1249
1207
|
return this._subscriptionManager;
|
|
1250
1208
|
}
|
|
1251
1209
|
|
|
1210
|
+
/**
|
|
1211
|
+
* Gets the DeviceRegistry instance for device management
|
|
1212
|
+
*
|
|
1213
|
+
* Provides direct access to DeviceRegistry methods for device lookups and queries.
|
|
1214
|
+
* Use this property to access device registry functionality:
|
|
1215
|
+
* - `meross.devices.get(identifier)` - Get a device by UUID or subdevice identifier
|
|
1216
|
+
* - `meross.devices.find(filters)` - Find devices matching filters
|
|
1217
|
+
* - `meross.devices.list()` - Get all registered devices
|
|
1218
|
+
*
|
|
1219
|
+
* @returns {DeviceRegistry} DeviceRegistry instance
|
|
1220
|
+
*/
|
|
1221
|
+
get devices() {
|
|
1222
|
+
return this._deviceRegistry;
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1252
1225
|
}
|
|
1253
1226
|
|
|
1254
1227
|
/**
|
|
@@ -1342,29 +1315,38 @@ class DeviceRegistry {
|
|
|
1342
1315
|
}
|
|
1343
1316
|
|
|
1344
1317
|
/**
|
|
1345
|
-
*
|
|
1318
|
+
* Unified method to get a device by identifier.
|
|
1346
1319
|
*
|
|
1347
|
-
*
|
|
1348
|
-
*
|
|
1320
|
+
* Supports both base devices (by UUID string) and subdevices (by object with hubUuid and id).
|
|
1321
|
+
* Internally converts the identifier to an internal ID format and performs the lookup.
|
|
1349
1322
|
*
|
|
1350
|
-
* @param {string}
|
|
1323
|
+
* @param {string|Object} identifier - Device identifier
|
|
1324
|
+
* @param {string} identifier - For base devices: device UUID string (e.g., 'device-uuid')
|
|
1325
|
+
* @param {Object} identifier - For subdevices: object with hubUuid and id properties
|
|
1326
|
+
* @param {string} identifier.hubUuid - Hub UUID that the subdevice belongs to
|
|
1327
|
+
* @param {string} identifier.id - Subdevice ID
|
|
1351
1328
|
* @returns {MerossDevice|MerossHubDevice|MerossSubDevice|null} Device instance, or null if not found
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
}
|
|
1356
|
-
|
|
1357
|
-
/**
|
|
1358
|
-
* Looks up a base device by its UUID.
|
|
1359
|
-
*
|
|
1360
|
-
* Provides O(1) lookup for base devices using the UUID index. Subdevices do not have
|
|
1361
|
-
* unique UUIDs and must be looked up by internal ID instead.
|
|
1329
|
+
* @example
|
|
1330
|
+
* // Get base device by UUID
|
|
1331
|
+
* const device = registry.get('device-uuid');
|
|
1362
1332
|
*
|
|
1363
|
-
* @
|
|
1364
|
-
*
|
|
1333
|
+
* @example
|
|
1334
|
+
* // Get subdevice by hub UUID and subdevice ID
|
|
1335
|
+
* const subdevice = registry.get({ hubUuid: 'hub-uuid', id: 'subdevice-id' });
|
|
1365
1336
|
*/
|
|
1366
|
-
|
|
1367
|
-
|
|
1337
|
+
get(identifier) {
|
|
1338
|
+
if (typeof identifier === 'string') {
|
|
1339
|
+
// Base device lookup by UUID
|
|
1340
|
+
return this._devicesByUuid.get(identifier) || null;
|
|
1341
|
+
} else if (identifier && typeof identifier === 'object') {
|
|
1342
|
+
// Subdevice lookup by hubUuid and id
|
|
1343
|
+
const { hubUuid, id } = identifier;
|
|
1344
|
+
if (hubUuid && id) {
|
|
1345
|
+
const internalId = ManagerMeross.DeviceRegistry.generateInternalId(hubUuid, true, hubUuid, id);
|
|
1346
|
+
return this._devicesByInternalId.get(internalId) || null;
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
return null;
|
|
1368
1350
|
}
|
|
1369
1351
|
|
|
1370
1352
|
/**
|
|
@@ -1375,7 +1357,7 @@ class DeviceRegistry {
|
|
|
1375
1357
|
*
|
|
1376
1358
|
* @returns {Array<MerossDevice|MerossHubDevice|MerossSubDevice>} Array of all registered devices
|
|
1377
1359
|
*/
|
|
1378
|
-
|
|
1360
|
+
list() {
|
|
1379
1361
|
return Array.from(this._devicesByInternalId.values());
|
|
1380
1362
|
}
|
|
1381
1363
|
|
|
@@ -1398,8 +1380,8 @@ class DeviceRegistry {
|
|
|
1398
1380
|
* - Function: custom filter function that receives device and returns boolean
|
|
1399
1381
|
* @returns {Array<MerossDevice|MerossHubDevice|MerossSubDevice>} Array of matching devices
|
|
1400
1382
|
*/
|
|
1401
|
-
|
|
1402
|
-
let devices = this.
|
|
1383
|
+
find(filters = {}) {
|
|
1384
|
+
let devices = this.list();
|
|
1403
1385
|
|
|
1404
1386
|
if (filters.device_uuids && Array.isArray(filters.device_uuids) && filters.device_uuids.length > 0) {
|
|
1405
1387
|
const uuidSet = new Set(filters.device_uuids);
|
|
@@ -1513,7 +1495,7 @@ class DeviceRegistry {
|
|
|
1513
1495
|
throw new UnknownDeviceTypeError('Cannot generate internal ID for subdevice: missing hub UUID or subdevice ID');
|
|
1514
1496
|
}
|
|
1515
1497
|
|
|
1516
|
-
const internalId =
|
|
1498
|
+
const internalId = ManagerMeross.DeviceRegistry.generateInternalId(hubUuid, true, hubUuid, subdeviceId);
|
|
1517
1499
|
device._internalId = internalId;
|
|
1518
1500
|
return internalId;
|
|
1519
1501
|
}
|
|
@@ -1523,7 +1505,7 @@ class DeviceRegistry {
|
|
|
1523
1505
|
throw new UnknownDeviceTypeError('Cannot generate internal ID: device missing UUID');
|
|
1524
1506
|
}
|
|
1525
1507
|
|
|
1526
|
-
const internalId =
|
|
1508
|
+
const internalId = ManagerMeross.DeviceRegistry.generateInternalId(uuid);
|
|
1527
1509
|
device._internalId = internalId;
|
|
1528
1510
|
return internalId;
|
|
1529
1511
|
}
|
|
@@ -1551,7 +1533,7 @@ class DeviceRegistry {
|
|
|
1551
1533
|
* @returns {void}
|
|
1552
1534
|
*/
|
|
1553
1535
|
clear() {
|
|
1554
|
-
const devices = this.
|
|
1536
|
+
const devices = this.list();
|
|
1555
1537
|
devices.forEach(device => {
|
|
1556
1538
|
if (device.disconnect) {
|
|
1557
1539
|
device.disconnect();
|
|
@@ -1571,11 +1553,11 @@ class DeviceRegistry {
|
|
|
1571
1553
|
}
|
|
1572
1554
|
}
|
|
1573
1555
|
|
|
1574
|
-
// Attach DeviceRegistry as nested class to
|
|
1575
|
-
|
|
1556
|
+
// Attach DeviceRegistry as nested class to ManagerMeross
|
|
1557
|
+
ManagerMeross.DeviceRegistry = DeviceRegistry;
|
|
1576
1558
|
|
|
1577
1559
|
/**
|
|
1578
|
-
* Events emitted by
|
|
1560
|
+
* Events emitted by ManagerMeross instance
|
|
1579
1561
|
*
|
|
1580
1562
|
* @typedef {Object} MerossCloudEvents
|
|
1581
1563
|
* @property {Function} deviceInitialized - Emitted when a device is initialized
|
|
@@ -1604,6 +1586,6 @@ MerossManager.DeviceRegistry = DeviceRegistry;
|
|
|
1604
1586
|
* @param {Object} message - Raw message object
|
|
1605
1587
|
*/
|
|
1606
1588
|
|
|
1607
|
-
module.exports =
|
|
1589
|
+
module.exports = ManagerMeross;
|
|
1608
1590
|
module.exports.DeviceRegistry = DeviceRegistry;
|
|
1609
1591
|
|
package/lib/subscription.js
CHANGED
|
@@ -12,9 +12,9 @@ const EventEmitter = require('events');
|
|
|
12
12
|
* @class
|
|
13
13
|
* @extends EventEmitter
|
|
14
14
|
*/
|
|
15
|
-
class
|
|
15
|
+
class ManagerSubscription extends EventEmitter {
|
|
16
16
|
/**
|
|
17
|
-
* Creates a new
|
|
17
|
+
* Creates a new ManagerSubscription instance.
|
|
18
18
|
*
|
|
19
19
|
* @param {Object} manager - MerossManager instance that provides device access
|
|
20
20
|
* @param {Object} [options={}] - Configuration options
|
|
@@ -184,7 +184,7 @@ class SubscriptionManager extends EventEmitter {
|
|
|
184
184
|
* Initialize subscription state and register device event handlers.
|
|
185
185
|
*
|
|
186
186
|
* Sets up event listeners on the device to capture push notifications and state
|
|
187
|
-
* changes, which are then distributed to
|
|
187
|
+
* changes, which are then distributed to ManagerSubscription listeners via events.
|
|
188
188
|
*
|
|
189
189
|
* @private
|
|
190
190
|
* @param {MerossDevice} device - Device to create subscription for
|
|
@@ -612,5 +612,5 @@ class SubscriptionManager extends EventEmitter {
|
|
|
612
612
|
|
|
613
613
|
}
|
|
614
614
|
|
|
615
|
-
module.exports =
|
|
615
|
+
module.exports = ManagerSubscription;
|
|
616
616
|
|