homebridge-http-advanced-platform 2.0.0-alpha.6

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 (56) hide show
  1. package/LICENSE +176 -0
  2. package/README.md +175 -0
  3. package/config.schema.json +449 -0
  4. package/dist/accessory.d.ts +27 -0
  5. package/dist/accessory.js +164 -0
  6. package/dist/accessory.js.map +1 -0
  7. package/dist/actions.d.ts +8 -0
  8. package/dist/actions.js +47 -0
  9. package/dist/actions.js.map +1 -0
  10. package/dist/compatibility.d.ts +3 -0
  11. package/dist/compatibility.js +26 -0
  12. package/dist/compatibility.js.map +1 -0
  13. package/dist/config.d.ts +2 -0
  14. package/dist/config.js +81 -0
  15. package/dist/config.js.map +1 -0
  16. package/dist/coordinator.d.ts +51 -0
  17. package/dist/coordinator.js +145 -0
  18. package/dist/coordinator.js.map +1 -0
  19. package/dist/index.d.ts +2 -0
  20. package/dist/index.js +8 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/mappers.d.ts +3 -0
  23. package/dist/mappers.js +116 -0
  24. package/dist/mappers.js.map +1 -0
  25. package/dist/metadata.d.ts +5 -0
  26. package/dist/metadata.js +8 -0
  27. package/dist/metadata.js.map +1 -0
  28. package/dist/platform.d.ts +18 -0
  29. package/dist/platform.js +129 -0
  30. package/dist/platform.js.map +1 -0
  31. package/dist/runtime.d.ts +54 -0
  32. package/dist/runtime.js +376 -0
  33. package/dist/runtime.js.map +1 -0
  34. package/dist/settings.d.ts +21 -0
  35. package/dist/settings.js +51 -0
  36. package/dist/settings.js.map +1 -0
  37. package/dist/transport.d.ts +25 -0
  38. package/dist/transport.js +139 -0
  39. package/dist/transport.js.map +1 -0
  40. package/dist/types.d.ts +106 -0
  41. package/dist/types.js +10 -0
  42. package/dist/types.js.map +1 -0
  43. package/dist/ui-config.d.ts +27 -0
  44. package/dist/ui-config.js +208 -0
  45. package/dist/ui-config.js.map +1 -0
  46. package/docs/alpha-release-notes.md +19 -0
  47. package/docs/legacy-reference.md +678 -0
  48. package/docs/migration.md +43 -0
  49. package/docs/modernization.md +211 -0
  50. package/docs/performance.md +37 -0
  51. package/docs/service-support.md +47 -0
  52. package/homebridge-ui/public/index.html +74 -0
  53. package/homebridge-ui/public/settings.js +132 -0
  54. package/homebridge-ui/server.js +17 -0
  55. package/package.json +83 -0
  56. package/sample-config.json +39 -0
@@ -0,0 +1,129 @@
1
+ import { DeviceAdapter, serviceConstructor } from './accessory.js';
2
+ import { validateDevice } from './config.js';
3
+ import { sharedRuntime } from './runtime.js';
4
+ import { validateSettings } from './settings.js';
5
+ import { pluginName, platformName, platformUUIDNamespace } from './metadata.js';
6
+ export { pluginName, platformName } from './metadata.js';
7
+ export class HTTPPlatform {
8
+ log;
9
+ config;
10
+ api;
11
+ cached = new Map();
12
+ constructor(log, config, api) {
13
+ this.log = log;
14
+ this.config = config;
15
+ this.api = api;
16
+ api.on('didFinishLaunching', () => this.discover());
17
+ }
18
+ configureAccessory(accessory) { this.cached.set(accessory.UUID, accessory); }
19
+ unavailable() {
20
+ const fail = () => { throw new this.api.hap.HapStatusError(-70402 /* this.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE */); };
21
+ for (const accessory of this.cached.values()) {
22
+ for (const service of accessory.services) {
23
+ if (service.UUID === this.api.hap.Service.AccessoryInformation.UUID)
24
+ continue;
25
+ for (const characteristic of service.characteristics) {
26
+ if (characteristic.UUID === this.api.hap.Characteristic.Name.UUID)
27
+ continue;
28
+ if (characteristic.props.perms.includes("pr" /* this.api.hap.Perms.PAIRED_READ */))
29
+ characteristic.onGet(fail);
30
+ if (characteristic.props.perms.includes("pw" /* this.api.hap.Perms.PAIRED_WRITE */))
31
+ characteristic.onSet(fail);
32
+ }
33
+ }
34
+ }
35
+ }
36
+ discover() {
37
+ // disabling a platform retains its configuration and cached HomeKit identities
38
+ if (this.config.enabled === false) {
39
+ this.unavailable();
40
+ return;
41
+ }
42
+ if (this.config.enabled !== undefined && typeof this.config.enabled !== 'boolean') {
43
+ this.unavailable();
44
+ this.log.error('HTTP Advanced platform enabled must be true or false; cached accessories retained');
45
+ return;
46
+ }
47
+ // validate the whole inventory before reconciling so malformed configuration cannot remove devices
48
+ const devices = this.config.devices;
49
+ if (!Array.isArray(devices)) {
50
+ this.unavailable();
51
+ this.log.error('HTTP Advanced platform requires a devices array');
52
+ return;
53
+ }
54
+ const desired = new Map();
55
+ try {
56
+ for (const device of devices) {
57
+ validateDevice(device);
58
+ serviceConstructor(this.api, device.service);
59
+ const id = device.id ?? device.name;
60
+ if (typeof id !== 'string' || !id.trim())
61
+ throw new Error();
62
+ const UUID = this.api.hap.uuid.generate(`${platformUUIDNamespace}:${this.config.name ?? platformName}:${id}`);
63
+ if (desired.has(UUID))
64
+ throw new Error();
65
+ desired.set(UUID, device);
66
+ }
67
+ }
68
+ catch (error) {
69
+ this.unavailable();
70
+ const unsupported = error instanceof Error && error.message.startsWith('HTTP Advanced unsupported HomeKit service:');
71
+ this.log.error(unsupported ? `${error.message}; cached accessories retained` : 'HTTP Advanced platform inventory invalid or contains duplicate IDs; cached accessories retained');
72
+ return;
73
+ }
74
+ const runtime = sharedRuntime(this.api, this.log);
75
+ try {
76
+ if (this.config.coordinator !== undefined)
77
+ validateSettings({ coordinator: this.config.coordinator });
78
+ runtime.coordinator.configure(this.config.coordinator ?? {});
79
+ }
80
+ catch {
81
+ this.unavailable();
82
+ this.log.error('HTTP Advanced invalid coordinator limits; cached accessories retained');
83
+ return;
84
+ }
85
+ let failed = false;
86
+ for (const [UUID, device] of desired) {
87
+ try {
88
+ const cached = this.cached.get(UUID);
89
+ const accessory = cached ?? new this.api.platformAccessory(device.name, UUID);
90
+ const Constructor = serviceConstructor(this.api, device.service);
91
+ const existing = accessory.services.find(service => service.UUID === Constructor.UUID);
92
+ const adapter = new DeviceAdapter(this.api, runtime, device, `platform:${UUID}`, existing);
93
+ if (!existing)
94
+ accessory.addService(adapter.service);
95
+ // remove obsolete primary services only after the new definition was successfully attached
96
+ for (const service of accessory.services.slice()) {
97
+ if (service.UUID !== this.api.hap.Service.AccessoryInformation.UUID && service !== adapter.service)
98
+ accessory.removeService(service);
99
+ }
100
+ accessory.displayName = device.name;
101
+ accessory.getService(this.api.hap.Service.AccessoryInformation)
102
+ .setCharacteristic(this.api.hap.Characteristic.Name, device.name)
103
+ .setCharacteristic(this.api.hap.Characteristic.Manufacturer, device.manufacturer ?? 'Custom Manufacturer')
104
+ .setCharacteristic(this.api.hap.Characteristic.Model, device.model ?? 'HTTP Accessory Model')
105
+ .setCharacteristic(this.api.hap.Characteristic.SerialNumber, device.id ?? 'HTTP Accessory Serial Number');
106
+ // context stores no configuration, URLs, bodies, usernames or passwords
107
+ accessory.context = { schemaVersion: 1 };
108
+ if (cached)
109
+ this.api.updatePlatformAccessories([accessory]);
110
+ else
111
+ this.api.registerPlatformAccessories(pluginName, platformName, [accessory]);
112
+ this.cached.set(UUID, accessory);
113
+ }
114
+ catch {
115
+ failed = true;
116
+ this.log.error('HTTP Advanced device initialization failed; cached accessories retained');
117
+ }
118
+ }
119
+ if (!failed) {
120
+ const removed = [...this.cached.values()].filter(a => !desired.has(a.UUID));
121
+ if (removed.length)
122
+ this.api.unregisterPlatformAccessories(pluginName, platformName, removed);
123
+ for (const accessory of removed)
124
+ this.cached.delete(accessory.UUID);
125
+ }
126
+ runtime.start();
127
+ }
128
+ }
129
+ //# sourceMappingURL=platform.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ import type { API, CharacteristicValue, Logging } from 'homebridge';
2
+ import { Coordinator } from './coordinator.js';
3
+ import { Transport } from './transport.js';
4
+ import { Actions } from './actions.js';
5
+ import { type GlobalSettings } from './settings.js';
6
+ import { type CacheEntry, type CoordinatorConfig, type DeviceConfig, type PendingWrite, type State } from './types.js';
7
+ export declare const fingerprint: (value: unknown) => string;
8
+ export declare class Runtime {
9
+ readonly log: Logging;
10
+ readonly settings: GlobalSettings;
11
+ readonly coordinator: Coordinator;
12
+ readonly transport: Transport;
13
+ readonly actions: Actions;
14
+ readonly entries: Map<string, CacheEntry>;
15
+ readonly setters: Map<string, NodeJS.Timeout>;
16
+ private readonly persisted;
17
+ private readonly owners;
18
+ private readonly recovering;
19
+ private timer?;
20
+ private persistenceTimer?;
21
+ private stopped;
22
+ private started;
23
+ private savePath?;
24
+ private dirty;
25
+ readonly stats: {
26
+ changes: number;
27
+ mapperFailures: number;
28
+ restored: number;
29
+ reads: number;
30
+ failedRefreshes: number;
31
+ };
32
+ constructor(log: Logging, options?: CoordinatorConfig, persistPath?: string, settings?: GlobalSettings);
33
+ register(owner: string, actionName: string, config: DeviceConfig, state: State, convert: CacheEntry['convert'], update: CacheEntry['update']): CacheEntry;
34
+ start(): void;
35
+ interval(entry: CacheEntry, now?: number): number;
36
+ read(entry: CacheEntry): CharacteristicValue;
37
+ tick(now?: number): void;
38
+ refresh(entry: CacheEntry): Promise<void>;
39
+ private ownerFor;
40
+ private originFor;
41
+ private pauseOrigin;
42
+ private reportRecovery;
43
+ private finishRecovery;
44
+ beginWrite(entry: CacheEntry, value: CharacteristicValue): PendingWrite;
45
+ private expireWrite;
46
+ publish(entry: CacheEntry): void;
47
+ set(config: DeviceConfig, state: State, actionName: string, value: CharacteristicValue, entry?: CacheEntry, intent?: PendingWrite): Promise<void>;
48
+ debounce(key: string, delay: number, work: () => Promise<void>, onFailure?: () => void): void;
49
+ snapshot(): object;
50
+ private debugSnapshot;
51
+ persist(): void;
52
+ shutdown(): void;
53
+ }
54
+ export declare function sharedRuntime(api: API, log: Logging): Runtime;
@@ -0,0 +1,376 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { Coordinator } from './coordinator.js';
5
+ import { Transport } from './transport.js';
6
+ import { Actions } from './actions.js';
7
+ import { readGlobalSettings } from './settings.js';
8
+ import { pluginVersion } from './metadata.js';
9
+ import { ActionError } from './types.js';
10
+ const temporaryFailure = (category) => category !== undefined && ['network', 'timeout', 'inconclusive', 'unavailable'].includes(category);
11
+ export const fingerprint = (value) => createHash('sha256').update(JSON.stringify(value)).digest('hex');
12
+ export class Runtime {
13
+ log;
14
+ settings;
15
+ coordinator;
16
+ transport;
17
+ actions;
18
+ entries = new Map();
19
+ setters = new Map();
20
+ persisted = {};
21
+ owners = new Set();
22
+ recovering = new Map();
23
+ timer;
24
+ persistenceTimer;
25
+ stopped = false;
26
+ started = false;
27
+ savePath;
28
+ dirty = false;
29
+ stats = { changes: 0, mapperFailures: 0, restored: 0, reads: 0, failedRefreshes: 0 };
30
+ constructor(log, options = {}, persistPath, settings = {}) {
31
+ this.log = log;
32
+ this.settings = settings;
33
+ this.coordinator = new Coordinator({ ...settings.coordinator, ...options });
34
+ this.transport = new Transport(this.coordinator, settings);
35
+ this.actions = new Actions(this.transport);
36
+ if (persistPath) {
37
+ this.savePath = join(persistPath, 'http-advanced-state-v1');
38
+ }
39
+ }
40
+ register(owner, actionName, config, state, convert, update) {
41
+ const key = fingerprint([owner, config, actionName]);
42
+ if (this.entries.has(key))
43
+ throw new ActionError('config');
44
+ this.owners.add(owner);
45
+ const now = Date.now();
46
+ const entry = { key, actionName, config, state, known: false, lastSuccess: 0, lastAttempt: 0, lastChange: 0, lastDemand: now, inFlight: false, failures: 0, nextEligible: now + Math.random() * 1000, generation: 0, convert, update };
47
+ if (this.savePath) {
48
+ try {
49
+ const saved = JSON.parse(readFileSync(join(this.savePath, key + '.json'), 'utf8'));
50
+ if (saved && typeof saved === 'object')
51
+ this.persisted[key] = saved;
52
+ }
53
+ catch { /* missing or corrupt optional state cannot block startup */ }
54
+ }
55
+ const saved = this.persisted[key];
56
+ if (saved && Number.isFinite(saved.lastSuccess) && saved.lastSuccess > 0 && saved.lastSuccess <= now) {
57
+ try {
58
+ entry.value = convert(saved.value);
59
+ entry.known = true;
60
+ entry.lastSuccess = saved.lastSuccess;
61
+ entry.lastChange = saved.lastChange;
62
+ entry.stateValue = ['string', 'boolean', 'number'].includes(typeof saved.stateValue) ? saved.stateValue : entry.value;
63
+ state[actionName] = entry.stateValue;
64
+ update(entry.value);
65
+ this.stats.restored++;
66
+ }
67
+ catch { /* invalid values are ignored; the getter reports not-ready until refreshed */ }
68
+ }
69
+ this.entries.set(key, entry);
70
+ return entry;
71
+ }
72
+ start() {
73
+ if (this.started || this.stopped)
74
+ return;
75
+ this.started = true;
76
+ this.log.info(`HTTP Advanced ${pluginVersion}: ${this.owners.size} devices, ${this.entries.size} cached getters, ${this.stats.restored} restored; concurrency ${this.coordinator.limits.concurrency}/${this.coordinator.limits.perOrigin}`);
77
+ this.timer = setInterval(() => this.tick(), 100);
78
+ this.timer.unref();
79
+ this.persistenceTimer = setInterval(() => { this.persist(); this.debugSnapshot(); }, 30000);
80
+ this.persistenceTimer.unref();
81
+ this.tick();
82
+ }
83
+ interval(entry, now = Date.now()) {
84
+ if (entry.config.forceRefreshDelay)
85
+ return entry.config.forceRefreshDelay * 1000;
86
+ const options = { ...this.settings.refresh, ...entry.config.refresh };
87
+ return now - entry.lastDemand > (options.idleAfter ?? 60) * 1000
88
+ ? (options.idleInterval ?? 60) * 1000 : (options.activeInterval ?? 5) * 1000;
89
+ }
90
+ read(entry) {
91
+ this.stats.reads++;
92
+ entry.lastDemand = Date.now();
93
+ this.expireWrite(entry, entry.lastDemand);
94
+ if (entry.pendingWrite)
95
+ return entry.pendingWrite.value;
96
+ // demand only marks work eligible; the scheduler starts it on a separate turn
97
+ if (!entry.config.forceRefreshDelay && entry.failures === 0 && entry.lastDemand - entry.lastSuccess >= this.interval(entry)) {
98
+ entry.nextEligible = Math.min(entry.nextEligible, entry.lastDemand);
99
+ }
100
+ if (!entry.known || entry.value === undefined)
101
+ throw new ActionError('inconclusive');
102
+ return entry.value;
103
+ }
104
+ tick(now = Date.now()) {
105
+ if (this.stopped)
106
+ return;
107
+ this.reportRecovery(now);
108
+ // expiry must still reach HomeKit when the endpoint or request queue is blocked
109
+ for (const entry of this.entries.values())
110
+ this.expireWrite(entry, now);
111
+ for (const entry of [...this.entries.values()].sort((a, b) => a.nextEligible - b.nextEligible)) {
112
+ if (!this.coordinator.available)
113
+ break;
114
+ if (entry.pendingWrite && entry.pendingWrite.expires === undefined)
115
+ continue;
116
+ const origin = this.originFor(entry);
117
+ if (origin && !this.coordinator.backgroundReady(origin, now))
118
+ continue;
119
+ if (!entry.inFlight && entry.nextEligible <= now)
120
+ void this.refresh(entry);
121
+ }
122
+ }
123
+ async refresh(entry) {
124
+ if (this.stopped || entry.inFlight)
125
+ return;
126
+ entry.inFlight = true;
127
+ entry.lastAttempt = Date.now();
128
+ const generation = entry.generation;
129
+ try {
130
+ let fallbackError;
131
+ let fallbackRetryAfter;
132
+ const raw = await this.actions.get(entry.config.urls[entry.actionName], entry.config, this.ownerFor(entry), entry.state, new Set(), (category, retryAfter) => { fallbackError = category; fallbackRetryAfter = retryAfter; });
133
+ if (this.stopped || generation !== entry.generation || (entry.pendingWrite && entry.pendingWrite.expires === undefined))
134
+ return;
135
+ // an unusable response (including a gateway timeout page) is not a broken mapper
136
+ if (raw === 'inconclusive')
137
+ throw new ActionError('inconclusive');
138
+ let value;
139
+ try {
140
+ value = entry.convert(raw);
141
+ }
142
+ catch (error) {
143
+ // valid mapping code can still receive a temporary non-value from an older server
144
+ if (error instanceof ActionError && error.category === 'mapper')
145
+ throw new ActionError('inconclusive');
146
+ throw error;
147
+ }
148
+ // an error fallback is not confirmation of a command, even if its value matches
149
+ if (entry.pendingWrite && fallbackError)
150
+ throw new ActionError(fallbackError, fallbackRetryAfter);
151
+ if (entry.pendingWrite && (value === entry.pendingWrite.value || Date.now() >= entry.pendingWrite.expires))
152
+ delete entry.pendingWrite;
153
+ const changed = !entry.known || value !== entry.value;
154
+ entry.value = value;
155
+ entry.known = true;
156
+ if (!fallbackError)
157
+ entry.lastSuccess = Date.now();
158
+ // legacy on-demand state holds mapper output; polling converts only numeric HAP formats
159
+ entry.stateValue = entry.config.forceRefreshDelay && typeof value === 'number' ? value : raw;
160
+ entry.state[entry.actionName] = entry.stateValue;
161
+ if (changed) {
162
+ entry.lastChange = Date.now();
163
+ this.stats.changes++;
164
+ }
165
+ // also clear a prior HAP error without calling any setter
166
+ entry.update(entry.pendingWrite?.value ?? value);
167
+ this.dirty = true;
168
+ if (fallbackError)
169
+ throw new ActionError(fallbackError, fallbackRetryAfter);
170
+ this.persisted[entry.key] = { value, stateValue: entry.stateValue, lastSuccess: entry.lastSuccess, lastChange: entry.lastChange };
171
+ this.finishRecovery(entry);
172
+ entry.failures = 0;
173
+ entry.lastError = undefined;
174
+ entry.nextEligible = Date.now() + this.interval(entry) * (1 + Math.random() * 0.1);
175
+ if (entry.pendingWrite)
176
+ entry.nextEligible = Math.min(entry.nextEligible, Date.now() + 1000, entry.pendingWrite.expires);
177
+ }
178
+ catch (error) {
179
+ if (this.stopped || generation !== entry.generation)
180
+ return;
181
+ if (error instanceof ActionError && error.category === 'deferred') {
182
+ entry.nextEligible = Date.now() + Math.max(100, error.retryAfter ?? 0);
183
+ return;
184
+ }
185
+ this.expireWrite(entry, Date.now());
186
+ entry.failures++;
187
+ this.stats.failedRefreshes++;
188
+ entry.lastError = error instanceof ActionError ? error.category : 'mapper';
189
+ if (entry.lastError === 'mapper')
190
+ this.stats.mapperFailures++;
191
+ entry.nextEligible = Date.now() + Math.min(300000, Math.max(this.interval(entry), 1000) * 2 ** Math.min(entry.failures - 1, 8)) * (1 + Math.random() * 0.1);
192
+ if (temporaryFailure(entry.lastError)) {
193
+ this.pauseOrigin(entry, error instanceof ActionError ? error.retryAfter : undefined);
194
+ }
195
+ else if (entry.failures === 1) {
196
+ this.log.warn(`HTTP Advanced action ${entry.key.slice(0, 12)} ${entry.actionName}: ${entry.lastError}; keeping cached state where available; retrying in background`);
197
+ }
198
+ }
199
+ finally {
200
+ entry.inFlight = false;
201
+ // a SET that raced an old GET must be verified again after that GET leaves
202
+ if (generation !== entry.generation && !this.stopped)
203
+ entry.nextEligible = Date.now();
204
+ }
205
+ }
206
+ ownerFor(entry) { return fingerprint(entry.config); }
207
+ originFor(entry) {
208
+ try {
209
+ return new URL(entry.config.urls[entry.actionName].url).origin;
210
+ }
211
+ catch {
212
+ return undefined;
213
+ }
214
+ }
215
+ pauseOrigin(entry, retryAfter = 0) {
216
+ const origin = this.originFor(entry);
217
+ if (!origin)
218
+ return;
219
+ const now = Date.now();
220
+ const recovery = this.recovering.get(origin) ?? { since: now, nextProbe: 0, attempts: 0, lastWarning: 0, category: entry.lastError };
221
+ // failures from requests already in flight belong to the same attempt
222
+ if (now >= recovery.nextProbe) {
223
+ recovery.attempts++;
224
+ recovery.nextProbe = now + Math.min((this.settings.recovery?.maxRetryInterval ?? 30) * 1000, (this.settings.recovery?.retryInterval ?? 5) * 1000 * 2 ** Math.min(recovery.attempts - 1, 20));
225
+ }
226
+ recovery.nextProbe = Math.max(recovery.nextProbe, now + retryAfter);
227
+ recovery.category = entry.lastError;
228
+ this.recovering.set(origin, recovery);
229
+ this.coordinator.pauseOrigin(origin, recovery.nextProbe);
230
+ entry.nextEligible = recovery.nextProbe;
231
+ this.reportRecovery(now);
232
+ }
233
+ reportRecovery(now) {
234
+ for (const [origin, recovery] of this.recovering) {
235
+ if (now - recovery.since < (this.settings.recovery?.quietPeriod ?? 90) * 1000 || (recovery.lastWarning && now - recovery.lastWarning < (this.settings.recovery?.reminderInterval ?? 300) * 1000))
236
+ continue;
237
+ recovery.lastWarning = now;
238
+ this.log.warn(`HTTP Advanced endpoint ${fingerprint(origin).slice(0, 12)}: waiting for usable responses for ${Math.round((now - recovery.since) / 1000)}s (${recovery.category}); keeping cached state where available; retrying one background request at a time`);
239
+ }
240
+ }
241
+ finishRecovery(entry) {
242
+ const origin = this.originFor(entry);
243
+ if (!origin)
244
+ return;
245
+ const recovery = this.recovering.get(origin);
246
+ if (!recovery)
247
+ return;
248
+ this.recovering.delete(origin);
249
+ this.coordinator.resumeOrigin(origin);
250
+ const message = `HTTP Advanced endpoint ${fingerprint(origin).slice(0, 12)}: responses recovered after ${Math.round((Date.now() - recovery.since) / 1000)}s; refreshing cached state`;
251
+ if (recovery.lastWarning)
252
+ this.log.info(message);
253
+ else
254
+ this.log.debug(message);
255
+ // a successful probe releases siblings from outage backoff, retaining normal queue limits
256
+ for (const sibling of this.entries.values()) {
257
+ if (temporaryFailure(sibling.lastError) && this.originFor(sibling) === origin) {
258
+ sibling.failures = 0;
259
+ sibling.lastError = undefined;
260
+ sibling.nextEligible = Date.now() + Math.random() * 1000;
261
+ }
262
+ }
263
+ }
264
+ beginWrite(entry, value) {
265
+ const intent = { value: entry.convert(value) };
266
+ entry.generation++;
267
+ entry.pendingWrite = intent;
268
+ entry.lastDemand = Date.now();
269
+ return intent;
270
+ }
271
+ expireWrite(entry, now) {
272
+ if (entry.pendingWrite?.expires === undefined || now < entry.pendingWrite.expires)
273
+ return;
274
+ delete entry.pendingWrite;
275
+ this.publish(entry);
276
+ }
277
+ publish(entry) {
278
+ if (this.stopped)
279
+ return;
280
+ if (entry.pendingWrite?.expires !== undefined && Date.now() >= entry.pendingWrite.expires)
281
+ delete entry.pendingWrite;
282
+ entry.update(entry.pendingWrite?.value ?? (entry.known ? entry.value : undefined) ?? new ActionError('inconclusive'));
283
+ }
284
+ async set(config, state, actionName, value, entry, intent) {
285
+ if (this.stopped)
286
+ throw new ActionError('aborted');
287
+ const action = config.urls?.[actionName];
288
+ if (!action)
289
+ return;
290
+ intent ??= entry ? this.beginWrite(entry, value) : undefined;
291
+ try {
292
+ await this.actions.set(action, config, fingerprint(config), state, value);
293
+ if (entry && entry.pendingWrite === intent)
294
+ intent.expires = Date.now() + (config.writeConfirmationTimeout ?? this.settings.writeConfirmationTimeout ?? 10000);
295
+ }
296
+ catch (error) {
297
+ if (entry && entry.pendingWrite === intent) {
298
+ delete entry.pendingWrite;
299
+ this.publish(entry);
300
+ }
301
+ throw error;
302
+ }
303
+ finally {
304
+ if (entry) {
305
+ // also invalidate reads started while the write was in progress
306
+ entry.generation++;
307
+ entry.nextEligible = Date.now();
308
+ }
309
+ }
310
+ }
311
+ debounce(key, delay, work, onFailure) {
312
+ clearTimeout(this.setters.get(key));
313
+ const timer = setTimeout(() => {
314
+ this.setters.delete(key);
315
+ void work().catch(() => { this.log.warn('HTTP Advanced delayed SET failed'); onFailure?.(); });
316
+ }, delay);
317
+ this.setters.set(key, timer);
318
+ }
319
+ snapshot() {
320
+ const now = Date.now();
321
+ return { ...this.stats, queue: this.coordinator.queue.length, inFlight: this.coordinator.active.size, limits: this.coordinator.limits,
322
+ requests: { ...this.coordinator.stats, durations: [...this.coordinator.stats.durations] }, transport: { ...this.transport.stats },
323
+ cache: [...this.entries.values()].map(e => ({ id: e.key.slice(0, 12), known: e.known, age: e.known ? now - e.lastSuccess : null, failures: e.failures, lastError: e.lastError, nextRefresh: Math.max(0, e.nextEligible - now), inFlight: e.inFlight })),
324
+ recovering: [...this.recovering].map(([origin, recovery]) => ({ id: fingerprint(origin).slice(0, 12), age: now - recovery.since, nextProbe: Math.max(0, recovery.nextProbe - now), attempts: recovery.attempts, category: recovery.category })),
325
+ origins: [...this.coordinator.originStats].map(([origin, stats]) => ({ id: fingerprint(origin).slice(0, 12), ...stats, inFlight: this.coordinator.origins.get(origin) ?? 0 })) };
326
+ }
327
+ debugSnapshot() {
328
+ if ([...this.entries.values()].some(e => e.config.debug))
329
+ this.log.info(`HTTP Advanced diagnostics ${JSON.stringify(this.snapshot())}`);
330
+ }
331
+ persist() {
332
+ if (!this.savePath || !this.dirty)
333
+ return;
334
+ try {
335
+ mkdirSync(this.savePath, { recursive: true });
336
+ // separate hashed entries prevent one child bridge overwriting another's cache
337
+ for (const e of this.entries.values())
338
+ if (this.persisted[e.key]) {
339
+ const path = join(this.savePath, e.key + '.json');
340
+ const temporary = path + `.${process.pid}.tmp`;
341
+ writeFileSync(temporary, JSON.stringify(this.persisted[e.key]), { mode: 0o600 });
342
+ renameSync(temporary, path);
343
+ }
344
+ this.dirty = false;
345
+ }
346
+ catch {
347
+ this.log.warn('HTTP Advanced could not persist state cache');
348
+ }
349
+ }
350
+ shutdown() {
351
+ this.stopped = true;
352
+ clearInterval(this.timer);
353
+ clearInterval(this.persistenceTimer);
354
+ for (const timer of this.setters.values())
355
+ clearTimeout(timer);
356
+ this.setters.clear();
357
+ this.transport.shutdown();
358
+ this.persist();
359
+ }
360
+ }
361
+ const runtimes = new WeakMap();
362
+ export function sharedRuntime(api, log) {
363
+ let runtime = runtimes.get(api);
364
+ if (!runtime) {
365
+ // Homebridge's Logging methods use their receiver's public prefix and log method
366
+ // copy them onto a separate callable so accessory-specific logging stays untouched
367
+ const sharedLog = Object.assign((message, ...parameters) => sharedLog.info(message, ...parameters), log, { prefix: 'HTTP Advanced' });
368
+ runtime = new Runtime(sharedLog, {}, api.user.persistPath(), readGlobalSettings(api, sharedLog));
369
+ runtimes.set(api, runtime);
370
+ const instance = runtime;
371
+ api.on('didFinishLaunching', () => { setImmediate(() => instance.start()); });
372
+ api.on('shutdown', () => instance.shutdown());
373
+ }
374
+ return runtime;
375
+ }
376
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { API, Logging } from 'homebridge';
2
+ import { ActionError, type CoordinatorConfig, type RefreshConfig } from './types.js';
3
+ export interface GlobalSettings {
4
+ requestTimeout?: number;
5
+ uriCallsDelay?: number;
6
+ setterDelay?: number;
7
+ writeConfirmationTimeout?: number;
8
+ refresh?: RefreshConfig;
9
+ coordinator?: CoordinatorConfig;
10
+ recovery?: {
11
+ retryInterval?: number;
12
+ maxRetryInterval?: number;
13
+ quietPeriod?: number;
14
+ reminderInterval?: number;
15
+ };
16
+ }
17
+ export declare class SettingsValidationError extends ActionError {
18
+ constructor(field: string, requirement: string);
19
+ }
20
+ export declare function validateSettings(value: unknown): asserts value is GlobalSettings;
21
+ export declare function readGlobalSettings(api: API, log: Logging): GlobalSettings;