homebridge-myleviton 3.0.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.
Files changed (72) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +112 -0
  3. package/config.schema.json +136 -0
  4. package/dist/api/cache.d.ts +108 -0
  5. package/dist/api/cache.d.ts.map +1 -0
  6. package/dist/api/cache.js +206 -0
  7. package/dist/api/cache.js.map +1 -0
  8. package/dist/api/circuit-breaker.d.ts +118 -0
  9. package/dist/api/circuit-breaker.d.ts.map +1 -0
  10. package/dist/api/circuit-breaker.js +223 -0
  11. package/dist/api/circuit-breaker.js.map +1 -0
  12. package/dist/api/client.d.ts +116 -0
  13. package/dist/api/client.d.ts.map +1 -0
  14. package/dist/api/client.js +358 -0
  15. package/dist/api/client.js.map +1 -0
  16. package/dist/api/index.d.ts +23 -0
  17. package/dist/api/index.d.ts.map +1 -0
  18. package/dist/api/index.js +47 -0
  19. package/dist/api/index.js.map +1 -0
  20. package/dist/api/persistence.d.ts +107 -0
  21. package/dist/api/persistence.d.ts.map +1 -0
  22. package/dist/api/persistence.js +285 -0
  23. package/dist/api/persistence.js.map +1 -0
  24. package/dist/api/rate-limiter.d.ts +102 -0
  25. package/dist/api/rate-limiter.d.ts.map +1 -0
  26. package/dist/api/rate-limiter.js +173 -0
  27. package/dist/api/rate-limiter.js.map +1 -0
  28. package/dist/api/request-queue.d.ts +104 -0
  29. package/dist/api/request-queue.d.ts.map +1 -0
  30. package/dist/api/request-queue.js +223 -0
  31. package/dist/api/request-queue.js.map +1 -0
  32. package/dist/api/websocket.d.ts +116 -0
  33. package/dist/api/websocket.d.ts.map +1 -0
  34. package/dist/api/websocket.js +319 -0
  35. package/dist/api/websocket.js.map +1 -0
  36. package/dist/errors/index.d.ts +182 -0
  37. package/dist/errors/index.d.ts.map +1 -0
  38. package/dist/errors/index.js +273 -0
  39. package/dist/errors/index.js.map +1 -0
  40. package/dist/index.d.ts +16 -0
  41. package/dist/index.d.ts.map +1 -0
  42. package/dist/index.js +42 -0
  43. package/dist/index.js.map +1 -0
  44. package/dist/platform.d.ts +139 -0
  45. package/dist/platform.d.ts.map +1 -0
  46. package/dist/platform.js +664 -0
  47. package/dist/platform.js.map +1 -0
  48. package/dist/types/index.d.ts +225 -0
  49. package/dist/types/index.d.ts.map +1 -0
  50. package/dist/types/index.js +34 -0
  51. package/dist/types/index.js.map +1 -0
  52. package/dist/utils/index.d.ts +15 -0
  53. package/dist/utils/index.d.ts.map +1 -0
  54. package/dist/utils/index.js +52 -0
  55. package/dist/utils/index.js.map +1 -0
  56. package/dist/utils/logger.d.ts +103 -0
  57. package/dist/utils/logger.d.ts.map +1 -0
  58. package/dist/utils/logger.js +184 -0
  59. package/dist/utils/logger.js.map +1 -0
  60. package/dist/utils/retry.d.ts +56 -0
  61. package/dist/utils/retry.d.ts.map +1 -0
  62. package/dist/utils/retry.js +141 -0
  63. package/dist/utils/retry.js.map +1 -0
  64. package/dist/utils/sanitizers.d.ts +37 -0
  65. package/dist/utils/sanitizers.d.ts.map +1 -0
  66. package/dist/utils/sanitizers.js +128 -0
  67. package/dist/utils/sanitizers.js.map +1 -0
  68. package/dist/utils/validators.d.ts +51 -0
  69. package/dist/utils/validators.d.ts.map +1 -0
  70. package/dist/utils/validators.js +243 -0
  71. package/dist/utils/validators.js.map +1 -0
  72. package/package.json +69 -0
@@ -0,0 +1,223 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2026 tbaur
4
+ *
5
+ * Licensed under the Apache License, Version 2.0
6
+ * See LICENSE file for full license text
7
+ *
8
+ * @fileoverview Request queue with priority and deduplication
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.RequestDeduplicator = exports.RequestQueue = exports.DEFAULT_REQUEST_QUEUE_CONFIG = void 0;
12
+ /**
13
+ * Default request queue configuration
14
+ */
15
+ exports.DEFAULT_REQUEST_QUEUE_CONFIG = {
16
+ maxConcurrent: 5,
17
+ maxQueueSize: 100,
18
+ requestTimeout: 30000,
19
+ };
20
+ /**
21
+ * Request queue with priority ordering and deduplication
22
+ */
23
+ class RequestQueue {
24
+ maxConcurrent;
25
+ maxQueueSize;
26
+ requestTimeout;
27
+ queue = [];
28
+ inFlight = new Map();
29
+ processing = false;
30
+ constructor(config = {}) {
31
+ const merged = { ...exports.DEFAULT_REQUEST_QUEUE_CONFIG, ...config };
32
+ this.maxConcurrent = merged.maxConcurrent;
33
+ this.maxQueueSize = merged.maxQueueSize;
34
+ this.requestTimeout = merged.requestTimeout;
35
+ }
36
+ /**
37
+ * Get queue length
38
+ */
39
+ get length() {
40
+ return this.queue.length;
41
+ }
42
+ /**
43
+ * Get number of in-flight requests
44
+ */
45
+ get inFlightCount() {
46
+ return this.inFlight.size;
47
+ }
48
+ /**
49
+ * Check if queue is full
50
+ */
51
+ get isFull() {
52
+ return this.queue.length >= this.maxQueueSize;
53
+ }
54
+ /**
55
+ * Add a request to the queue
56
+ */
57
+ add(execute, options = {}) {
58
+ const { priority = 'normal', dedupeKey } = options;
59
+ // Check for duplicate in-flight request
60
+ if (dedupeKey && this.inFlight.has(dedupeKey)) {
61
+ return this.inFlight.get(dedupeKey);
62
+ }
63
+ // Check queue size limit
64
+ if (this.isFull) {
65
+ return Promise.reject(new Error('Request queue is full'));
66
+ }
67
+ return new Promise((resolve, reject) => {
68
+ const request = {
69
+ id: dedupeKey || `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
70
+ priority,
71
+ execute,
72
+ timestamp: Date.now(),
73
+ resolve: resolve,
74
+ reject,
75
+ };
76
+ this.enqueue(request);
77
+ this.processQueue();
78
+ });
79
+ }
80
+ /**
81
+ * Insert request into queue by priority
82
+ */
83
+ enqueue(request) {
84
+ // Priority order: high > normal > low
85
+ // Within same priority, FIFO ordering
86
+ const priorityOrder = { high: 0, normal: 1, low: 2 };
87
+ const requestPriority = priorityOrder[request.priority];
88
+ const insertIndex = this.queue.findIndex(r => priorityOrder[r.priority] > requestPriority);
89
+ if (insertIndex === -1) {
90
+ this.queue.push(request);
91
+ }
92
+ else {
93
+ this.queue.splice(insertIndex, 0, request);
94
+ }
95
+ }
96
+ /**
97
+ * Process queued requests
98
+ */
99
+ async processQueue() {
100
+ if (this.processing) {
101
+ return;
102
+ }
103
+ this.processing = true;
104
+ try {
105
+ while (this.queue.length > 0 && this.inFlight.size < this.maxConcurrent) {
106
+ const request = this.queue.shift();
107
+ if (!request) {
108
+ break;
109
+ }
110
+ const promise = this.executeRequest(request);
111
+ this.inFlight.set(request.id, promise);
112
+ // Don't await - let it run concurrently
113
+ promise.finally(() => {
114
+ this.inFlight.delete(request.id);
115
+ // Continue processing after completion
116
+ setImmediate(() => this.processQueue());
117
+ });
118
+ }
119
+ }
120
+ finally {
121
+ this.processing = false;
122
+ }
123
+ }
124
+ /**
125
+ * Execute a single request with timeout
126
+ */
127
+ async executeRequest(request) {
128
+ let timeoutId;
129
+ const timeoutPromise = new Promise((_, reject) => {
130
+ timeoutId = setTimeout(() => {
131
+ reject(new Error(`Request timed out after ${this.requestTimeout}ms`));
132
+ }, this.requestTimeout);
133
+ });
134
+ try {
135
+ const result = await Promise.race([request.execute(), timeoutPromise]);
136
+ request.resolve(result);
137
+ }
138
+ catch (error) {
139
+ request.reject(error);
140
+ }
141
+ finally {
142
+ // Always clear the timeout to prevent memory leaks and open handles
143
+ if (timeoutId) {
144
+ clearTimeout(timeoutId);
145
+ }
146
+ }
147
+ }
148
+ /**
149
+ * Clear the queue
150
+ */
151
+ clear() {
152
+ // Reject all pending requests
153
+ for (const request of this.queue) {
154
+ request.reject(new Error('Request queue cleared'));
155
+ }
156
+ this.queue = [];
157
+ }
158
+ /**
159
+ * Get queue statistics
160
+ */
161
+ getStats() {
162
+ return {
163
+ queueLength: this.length,
164
+ inFlight: this.inFlightCount,
165
+ maxConcurrent: this.maxConcurrent,
166
+ maxQueueSize: this.maxQueueSize,
167
+ };
168
+ }
169
+ /**
170
+ * Wait for all in-flight requests to complete
171
+ */
172
+ async drain() {
173
+ await Promise.all(this.inFlight.values());
174
+ }
175
+ }
176
+ exports.RequestQueue = RequestQueue;
177
+ /**
178
+ * In-flight request deduplication map
179
+ */
180
+ class RequestDeduplicator {
181
+ inFlight = new Map();
182
+ maxSize;
183
+ constructor(maxSize = 100) {
184
+ this.maxSize = maxSize;
185
+ }
186
+ /**
187
+ * Execute a request with deduplication
188
+ */
189
+ async execute(key, fn) {
190
+ // Check for existing in-flight request
191
+ const existing = this.inFlight.get(key);
192
+ if (existing) {
193
+ return existing;
194
+ }
195
+ // Prevent unbounded growth
196
+ if (this.inFlight.size >= this.maxSize) {
197
+ const firstKey = this.inFlight.keys().next().value;
198
+ if (firstKey) {
199
+ this.inFlight.delete(firstKey);
200
+ }
201
+ }
202
+ // Create and track new request
203
+ const promise = fn().finally(() => {
204
+ this.inFlight.delete(key);
205
+ });
206
+ this.inFlight.set(key, promise);
207
+ return promise;
208
+ }
209
+ /**
210
+ * Get number of in-flight requests
211
+ */
212
+ get size() {
213
+ return this.inFlight.size;
214
+ }
215
+ /**
216
+ * Clear all tracked requests
217
+ */
218
+ clear() {
219
+ this.inFlight.clear();
220
+ }
221
+ }
222
+ exports.RequestDeduplicator = RequestDeduplicator;
223
+ //# sourceMappingURL=request-queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-queue.js","sourceRoot":"","sources":["../../src/api/request-queue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Copyright (c) 2026 tbaur
3
+ *
4
+ * Licensed under the Apache License, Version 2.0
5
+ * See LICENSE file for full license text
6
+ *
7
+ * @fileoverview WebSocket client for real-time device updates
8
+ */
9
+ import type { WebSocketPayload, DeviceInfo, Logger } from '../types';
10
+ /**
11
+ * WebSocket configuration
12
+ */
13
+ export interface WebSocketConfig {
14
+ /** Socket URL */
15
+ socketUrl: string;
16
+ /** Connection timeout in ms */
17
+ connectionTimeout: number;
18
+ /** Maximum reconnection attempts */
19
+ maxReconnectAttempts: number;
20
+ /** Initial reconnection delay in ms */
21
+ initialReconnectDelay: number;
22
+ /** Maximum reconnection delay in ms */
23
+ maxReconnectDelay: number;
24
+ }
25
+ /**
26
+ * Default WebSocket configuration
27
+ */
28
+ export declare const DEFAULT_WEBSOCKET_CONFIG: WebSocketConfig;
29
+ /**
30
+ * Logger interface for WebSocket
31
+ */
32
+ interface WebSocketLogger {
33
+ debug: (message: string) => void;
34
+ info: (message: string) => void;
35
+ warn: (message: string) => void;
36
+ error: (message: string) => void;
37
+ }
38
+ /**
39
+ * WebSocket connection for real-time updates
40
+ */
41
+ export declare class LevitonWebSocket {
42
+ private readonly config;
43
+ private readonly logger;
44
+ private ws;
45
+ private token;
46
+ private devices;
47
+ private callback;
48
+ private reconnectAttempt;
49
+ private timers;
50
+ private isConnecting;
51
+ private isClosed;
52
+ constructor(token: string, devices: DeviceInfo[], callback: (payload: WebSocketPayload) => void, logger: WebSocketLogger | Logger, config?: Partial<WebSocketConfig>);
53
+ /**
54
+ * Normalize logger to standard interface
55
+ */
56
+ private normalizeLogger;
57
+ /**
58
+ * Update token (after refresh)
59
+ */
60
+ updateToken(token: string): void;
61
+ /**
62
+ * Connect to WebSocket
63
+ */
64
+ connect(): void;
65
+ /**
66
+ * Setup WebSocket event handlers
67
+ */
68
+ private setupEventHandlers;
69
+ /**
70
+ * Handle incoming message
71
+ */
72
+ private handleMessage;
73
+ /**
74
+ * Subscribe to device updates
75
+ */
76
+ private subscribeToDevices;
77
+ /**
78
+ * Handle notification message
79
+ */
80
+ private handleNotification;
81
+ /**
82
+ * Schedule reconnection
83
+ */
84
+ private scheduleReconnect;
85
+ /**
86
+ * Remove a timer from tracking
87
+ */
88
+ private removeTimer;
89
+ /**
90
+ * Clear all timers
91
+ */
92
+ private clearTimers;
93
+ /**
94
+ * Close the WebSocket connection
95
+ */
96
+ close(): void;
97
+ /**
98
+ * Check if connected
99
+ */
100
+ get isConnected(): boolean;
101
+ /**
102
+ * Get connection status
103
+ */
104
+ getStatus(): {
105
+ isConnected: boolean;
106
+ isConnecting: boolean;
107
+ isClosed: boolean;
108
+ reconnectAttempt: number;
109
+ };
110
+ }
111
+ /**
112
+ * Create and connect a WebSocket
113
+ */
114
+ export declare function createWebSocket(token: string, devices: DeviceInfo[], callback: (payload: WebSocketPayload) => void, logger: WebSocketLogger | Logger, config?: Partial<WebSocketConfig>): LevitonWebSocket;
115
+ export {};
116
+ //# sourceMappingURL=websocket.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websocket.d.ts","sourceRoot":"","sources":["../../src/api/websocket.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAEpE;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,iBAAiB;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,+BAA+B;IAC/B,iBAAiB,EAAE,MAAM,CAAA;IACzB,oCAAoC;IACpC,oBAAoB,EAAE,MAAM,CAAA;IAC5B,uCAAuC;IACvC,qBAAqB,EAAE,MAAM,CAAA;IAC7B,uCAAuC;IACvC,iBAAiB,EAAE,MAAM,CAAA;CAC1B;AAED;;GAEG;AACH,eAAO,MAAM,wBAAwB,EAAE,eAMtC,CAAA;AAgBD;;GAEG;AACH,UAAU,eAAe;IACvB,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IAChC,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/B,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/B,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CACjC;AAED;;GAEG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;IACxC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;IAExC,OAAO,CAAC,EAAE,CAAyC;IACnD,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,QAAQ,CAAqC;IAErD,OAAO,CAAC,gBAAgB,CAAI;IAC5B,OAAO,CAAC,MAAM,CAAsC;IACpD,OAAO,CAAC,YAAY,CAAQ;IAC5B,OAAO,CAAC,QAAQ,CAAQ;gBAGtB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,UAAU,EAAE,EACrB,QAAQ,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,IAAI,EAC7C,MAAM,EAAE,eAAe,GAAG,MAAM,EAChC,MAAM,GAAE,OAAO,CAAC,eAAe,CAAM;IASvC;;OAEG;IACH,OAAO,CAAC,eAAe;IAcvB;;OAEG;IACH,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIhC;;OAEG;IACH,OAAO,IAAI,IAAI;IAqBf;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAoE1B;;OAEG;IACH,OAAO,CAAC,aAAa;IAkCrB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAc1B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IA2B1B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAuBzB;;OAEG;IACH,OAAO,CAAC,WAAW;IAOnB;;OAEG;IACH,OAAO,CAAC,WAAW;IAOnB;;OAEG;IACH,KAAK,IAAI,IAAI;IAcb;;OAEG;IACH,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED;;OAEG;IACH,SAAS,IAAI;QACX,WAAW,EAAE,OAAO,CAAA;QACpB,YAAY,EAAE,OAAO,CAAA;QACrB,QAAQ,EAAE,OAAO,CAAA;QACjB,gBAAgB,EAAE,MAAM,CAAA;KACzB;CAQF;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,UAAU,EAAE,EACrB,QAAQ,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,IAAI,EAC7C,MAAM,EAAE,eAAe,GAAG,MAAM,EAChC,MAAM,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,GAChC,gBAAgB,CAIlB"}
@@ -0,0 +1,319 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2026 tbaur
4
+ *
5
+ * Licensed under the Apache License, Version 2.0
6
+ * See LICENSE file for full license text
7
+ *
8
+ * @fileoverview WebSocket client for real-time device updates
9
+ */
10
+ var __importDefault = (this && this.__importDefault) || function (mod) {
11
+ return (mod && mod.__esModule) ? mod : { "default": mod };
12
+ };
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.LevitonWebSocket = exports.DEFAULT_WEBSOCKET_CONFIG = void 0;
15
+ exports.createWebSocket = createWebSocket;
16
+ const sockjs_client_1 = __importDefault(require("sockjs-client"));
17
+ const sanitizers_1 = require("../utils/sanitizers");
18
+ /**
19
+ * Default WebSocket configuration
20
+ */
21
+ exports.DEFAULT_WEBSOCKET_CONFIG = {
22
+ socketUrl: 'https://my.leviton.com/socket',
23
+ connectionTimeout: 10000,
24
+ maxReconnectAttempts: 10,
25
+ initialReconnectDelay: 1000,
26
+ maxReconnectDelay: 60000,
27
+ };
28
+ /**
29
+ * WebSocket message types
30
+ */
31
+ var MessageType;
32
+ (function (MessageType) {
33
+ MessageType["CHALLENGE"] = "challenge";
34
+ MessageType["STATUS"] = "status";
35
+ MessageType["NOTIFICATION"] = "notification";
36
+ })(MessageType || (MessageType = {}));
37
+ /**
38
+ * WebSocket status values
39
+ */
40
+ const STATUS_READY = 'ready';
41
+ /**
42
+ * WebSocket connection for real-time updates
43
+ */
44
+ class LevitonWebSocket {
45
+ config;
46
+ logger;
47
+ ws = null;
48
+ token;
49
+ devices;
50
+ callback;
51
+ reconnectAttempt = 0;
52
+ timers = [];
53
+ isConnecting = false;
54
+ isClosed = false;
55
+ constructor(token, devices, callback, logger, config = {}) {
56
+ this.config = { ...exports.DEFAULT_WEBSOCKET_CONFIG, ...config };
57
+ this.logger = this.normalizeLogger(logger);
58
+ this.token = token;
59
+ this.devices = devices;
60
+ this.callback = callback;
61
+ }
62
+ /**
63
+ * Normalize logger to standard interface
64
+ */
65
+ normalizeLogger(logger) {
66
+ if ('debug' in logger && 'info' in logger && 'warn' in logger && 'error' in logger) {
67
+ return logger;
68
+ }
69
+ // Wrap basic logger
70
+ const baseLogger = logger;
71
+ return {
72
+ debug: (msg) => { baseLogger.info?.(`[debug] ${msg}`) ?? console.log(msg); },
73
+ info: (msg) => { baseLogger.info?.(msg) ?? console.log(msg); },
74
+ warn: (msg) => { baseLogger.warn?.(msg) ?? console.warn(msg); },
75
+ error: (msg) => { baseLogger.error?.(msg) ?? console.error(msg); },
76
+ };
77
+ }
78
+ /**
79
+ * Update token (after refresh)
80
+ */
81
+ updateToken(token) {
82
+ this.token = token;
83
+ }
84
+ /**
85
+ * Connect to WebSocket
86
+ */
87
+ connect() {
88
+ if (this.isConnecting || this.isClosed) {
89
+ return;
90
+ }
91
+ this.isConnecting = true;
92
+ this.logger.debug('Connecting to WebSocket...');
93
+ try {
94
+ this.ws = new sockjs_client_1.default(this.config.socketUrl, undefined, {
95
+ transports: ['websocket', 'xhr-streaming', 'xhr-polling'],
96
+ });
97
+ this.setupEventHandlers();
98
+ }
99
+ catch (error) {
100
+ this.isConnecting = false;
101
+ this.logger.error(`Failed to create WebSocket: ${error.message}`);
102
+ this.scheduleReconnect();
103
+ }
104
+ }
105
+ /**
106
+ * Setup WebSocket event handlers
107
+ */
108
+ setupEventHandlers() {
109
+ if (!this.ws) {
110
+ return;
111
+ }
112
+ let isOpen = false;
113
+ // Connection timeout
114
+ const connectionTimeout = setTimeout(() => {
115
+ if (!isOpen && this.ws) {
116
+ this.logger.error('WebSocket connection timeout');
117
+ try {
118
+ this.ws.close();
119
+ }
120
+ catch {
121
+ // Ignore
122
+ }
123
+ }
124
+ }, this.config.connectionTimeout);
125
+ this.timers.push(connectionTimeout);
126
+ this.ws.onopen = () => {
127
+ clearTimeout(connectionTimeout);
128
+ this.removeTimer(connectionTimeout);
129
+ isOpen = true;
130
+ this.isConnecting = false;
131
+ this.reconnectAttempt = 0;
132
+ this.logger.debug(`WebSocket connected (token: ${(0, sanitizers_1.maskToken)(this.token)})`);
133
+ };
134
+ this.ws.onclose = (event) => {
135
+ this.clearTimers();
136
+ isOpen = false;
137
+ this.isConnecting = false;
138
+ const code = event?.code;
139
+ const wasClean = event?.wasClean;
140
+ // Normal close
141
+ if (wasClean && code === 1000) {
142
+ this.logger.debug('WebSocket closed normally');
143
+ return;
144
+ }
145
+ // Auth failure - don't reconnect
146
+ if (code === 401) {
147
+ this.logger.info('WebSocket auth failed (expected - device control still works)');
148
+ return;
149
+ }
150
+ // Closed externally
151
+ if (this.isClosed) {
152
+ this.logger.debug('WebSocket closed by user');
153
+ return;
154
+ }
155
+ this.logger.debug(`WebSocket closed: code=${code} wasClean=${wasClean}`);
156
+ this.scheduleReconnect();
157
+ };
158
+ this.ws.onerror = (error) => {
159
+ clearTimeout(connectionTimeout);
160
+ this.removeTimer(connectionTimeout);
161
+ this.logger.error(`WebSocket error: ${error.message || 'Unknown error'}`);
162
+ };
163
+ this.ws.onmessage = (message) => {
164
+ this.handleMessage(message);
165
+ };
166
+ }
167
+ /**
168
+ * Handle incoming message
169
+ */
170
+ handleMessage(message) {
171
+ let data;
172
+ try {
173
+ data = JSON.parse(message.data);
174
+ }
175
+ catch {
176
+ this.logger.error(`Failed to parse WebSocket message: ${message.data}`);
177
+ return;
178
+ }
179
+ if (!data || typeof data !== 'object') {
180
+ return;
181
+ }
182
+ // Handle challenge
183
+ if (data.type === MessageType.CHALLENGE) {
184
+ this.logger.debug(`Received challenge, responding with token: ${(0, sanitizers_1.maskToken)(this.token)}`);
185
+ this.ws?.send(JSON.stringify([{ token: this.token }]));
186
+ return;
187
+ }
188
+ // Handle ready status
189
+ if (data.type === MessageType.STATUS && data.status === STATUS_READY) {
190
+ this.logger.debug('WebSocket ready, subscribing to devices');
191
+ this.subscribeToDevices();
192
+ return;
193
+ }
194
+ // Handle notifications
195
+ if (data.type === MessageType.NOTIFICATION) {
196
+ this.handleNotification(data);
197
+ }
198
+ }
199
+ /**
200
+ * Subscribe to device updates
201
+ */
202
+ subscribeToDevices() {
203
+ for (const device of this.devices) {
204
+ if (device?.id) {
205
+ this.ws?.send(JSON.stringify([{
206
+ type: 'subscribe',
207
+ subscription: {
208
+ modelName: 'IotSwitch',
209
+ modelId: device.id,
210
+ },
211
+ }]));
212
+ }
213
+ }
214
+ }
215
+ /**
216
+ * Handle notification message
217
+ */
218
+ handleNotification(data) {
219
+ const notification = data.notification;
220
+ if (!notification?.data || !notification.modelId) {
221
+ return;
222
+ }
223
+ const notificationData = notification.data;
224
+ if (!notificationData.power) {
225
+ return;
226
+ }
227
+ const payload = {
228
+ id: notification.modelId,
229
+ power: notificationData.power,
230
+ };
231
+ if (notificationData.brightness !== undefined) {
232
+ payload.brightness = notificationData.brightness;
233
+ }
234
+ if (notificationData.occupancy !== undefined) {
235
+ payload.occupancy = notificationData.occupancy;
236
+ }
237
+ this.callback(payload);
238
+ }
239
+ /**
240
+ * Schedule reconnection
241
+ */
242
+ scheduleReconnect() {
243
+ if (this.isClosed) {
244
+ return;
245
+ }
246
+ if (this.reconnectAttempt >= this.config.maxReconnectAttempts) {
247
+ this.logger.warn(`WebSocket reconnection failed after ${this.config.maxReconnectAttempts} attempts`);
248
+ return;
249
+ }
250
+ const delay = Math.min(this.config.initialReconnectDelay * Math.pow(2, this.reconnectAttempt), this.config.maxReconnectDelay);
251
+ this.logger.info(`WebSocket reconnecting in ${Math.round(delay / 1000)}s (${this.reconnectAttempt + 1}/${this.config.maxReconnectAttempts})`);
252
+ const timer = setTimeout(() => {
253
+ this.reconnectAttempt++;
254
+ this.connect();
255
+ }, delay);
256
+ this.timers.push(timer);
257
+ }
258
+ /**
259
+ * Remove a timer from tracking
260
+ */
261
+ removeTimer(timer) {
262
+ const index = this.timers.indexOf(timer);
263
+ if (index !== -1) {
264
+ this.timers.splice(index, 1);
265
+ }
266
+ }
267
+ /**
268
+ * Clear all timers
269
+ */
270
+ clearTimers() {
271
+ for (const timer of this.timers) {
272
+ clearTimeout(timer);
273
+ }
274
+ this.timers = [];
275
+ }
276
+ /**
277
+ * Close the WebSocket connection
278
+ */
279
+ close() {
280
+ this.isClosed = true;
281
+ this.clearTimers();
282
+ if (this.ws) {
283
+ try {
284
+ this.ws.close();
285
+ }
286
+ catch {
287
+ // Ignore
288
+ }
289
+ this.ws = null;
290
+ }
291
+ }
292
+ /**
293
+ * Check if connected
294
+ */
295
+ get isConnected() {
296
+ return this.ws?.readyState === sockjs_client_1.default.OPEN;
297
+ }
298
+ /**
299
+ * Get connection status
300
+ */
301
+ getStatus() {
302
+ return {
303
+ isConnected: this.isConnected,
304
+ isConnecting: this.isConnecting,
305
+ isClosed: this.isClosed,
306
+ reconnectAttempt: this.reconnectAttempt,
307
+ };
308
+ }
309
+ }
310
+ exports.LevitonWebSocket = LevitonWebSocket;
311
+ /**
312
+ * Create and connect a WebSocket
313
+ */
314
+ function createWebSocket(token, devices, callback, logger, config) {
315
+ const ws = new LevitonWebSocket(token, devices, callback, logger, config);
316
+ ws.connect();
317
+ return ws;
318
+ }
319
+ //# sourceMappingURL=websocket.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websocket.js","sourceRoot":"","sources":["../../src/api/websocket.ts"],"names":[],"mappings":"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"}