@camstack/addon-provider-wyze 0.2.77 → 0.2.79

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/addon.js CHANGED
@@ -33629,6 +33629,53 @@ var BaseDeviceProvider = class extends BaseAddon {
33629
33629
  const ids = [...this._permanentRestoreFailures.keys()].join(", ");
33630
33630
  return `${this._permanentRestoreFailures.size} device(s) permanently failed restore (deviceIds: ${ids}) — restart the ${this.providerName} provider to retry`;
33631
33631
  }
33632
+ /**
33633
+ * A top-level persisted row with NO configuration is a leftover, not a
33634
+ * device — quarantine it instead of dialling it.
33635
+ *
33636
+ * Device 614 was deleted, resurrected as a config-less shell by a write
33637
+ * already in flight (D376), and then dialled at every single boot: eight
33638
+ * `Failed to restore device — bounded retry scheduled` lines in one day,
33639
+ * each one the same Zod refusal on `host` and `password`. The bound was
33640
+ * real, but it is a bound PER PROCESS, and the runner restarts — so nothing
33641
+ * about the row ever stopped costing attempts and log lines.
33642
+ *
33643
+ * No retry can add a configuration that is not there. The row is reported
33644
+ * once, with its `deviceId`, and set aside.
33645
+ *
33646
+ * Top-level only: an accessory child legitimately carries an empty blob (it
33647
+ * lives off its parent), and a hub-adopted child with an emptied blob is
33648
+ * repaired by `healSavedConfig` from its parent instead. Providers that
33649
+ * genuinely create configuration-free top-level devices turn this off.
33650
+ */
33651
+ quarantineConfiglessTopLevelRestores = true;
33652
+ isUnrestorableShell(saved) {
33653
+ if (!this.quarantineConfiglessTopLevelRestores) return false;
33654
+ if (saved.parentDeviceId !== null) return false;
33655
+ const config = saved.config;
33656
+ if (config === void 0) return false;
33657
+ return Object.keys(config).length === 0;
33658
+ }
33659
+ quarantineShell(saved) {
33660
+ this._permanentRestoreFailures.set(saved.id, {
33661
+ deviceId: saved.id,
33662
+ stableId: saved.stableId,
33663
+ type: saved.type,
33664
+ attempts: 0,
33665
+ lastError: "persisted row has no configuration",
33666
+ failedAt: Date.now()
33667
+ });
33668
+ this.ctx.logger.error("Persisted device row has NO configuration — quarantined: not restored, not retried. Remove it (deviceManager.removeDevice) or re-add the device.", {
33669
+ tags: {
33670
+ deviceId: saved.id,
33671
+ stableId: saved.stableId
33672
+ },
33673
+ meta: {
33674
+ type: saved.type,
33675
+ provider: this.providerName
33676
+ }
33677
+ });
33678
+ }
33632
33679
  cancelRestoreRetries() {
33633
33680
  this._restoreRetryScheduler?.cancel();
33634
33681
  this._restoreRetryScheduler = null;
@@ -33813,6 +33860,10 @@ var BaseDeviceProvider = class extends BaseAddon {
33813
33860
  });
33814
33861
  return;
33815
33862
  }
33863
+ if (this.isUnrestorableShell(saved)) {
33864
+ this.quarantineShell(saved);
33865
+ return;
33866
+ }
33816
33867
  try {
33817
33868
  await attemptRestore(saved);
33818
33869
  } catch (err) {
package/dist/addon.mjs CHANGED
@@ -33608,6 +33608,53 @@ var BaseDeviceProvider = class extends BaseAddon {
33608
33608
  const ids = [...this._permanentRestoreFailures.keys()].join(", ");
33609
33609
  return `${this._permanentRestoreFailures.size} device(s) permanently failed restore (deviceIds: ${ids}) — restart the ${this.providerName} provider to retry`;
33610
33610
  }
33611
+ /**
33612
+ * A top-level persisted row with NO configuration is a leftover, not a
33613
+ * device — quarantine it instead of dialling it.
33614
+ *
33615
+ * Device 614 was deleted, resurrected as a config-less shell by a write
33616
+ * already in flight (D376), and then dialled at every single boot: eight
33617
+ * `Failed to restore device — bounded retry scheduled` lines in one day,
33618
+ * each one the same Zod refusal on `host` and `password`. The bound was
33619
+ * real, but it is a bound PER PROCESS, and the runner restarts — so nothing
33620
+ * about the row ever stopped costing attempts and log lines.
33621
+ *
33622
+ * No retry can add a configuration that is not there. The row is reported
33623
+ * once, with its `deviceId`, and set aside.
33624
+ *
33625
+ * Top-level only: an accessory child legitimately carries an empty blob (it
33626
+ * lives off its parent), and a hub-adopted child with an emptied blob is
33627
+ * repaired by `healSavedConfig` from its parent instead. Providers that
33628
+ * genuinely create configuration-free top-level devices turn this off.
33629
+ */
33630
+ quarantineConfiglessTopLevelRestores = true;
33631
+ isUnrestorableShell(saved) {
33632
+ if (!this.quarantineConfiglessTopLevelRestores) return false;
33633
+ if (saved.parentDeviceId !== null) return false;
33634
+ const config = saved.config;
33635
+ if (config === void 0) return false;
33636
+ return Object.keys(config).length === 0;
33637
+ }
33638
+ quarantineShell(saved) {
33639
+ this._permanentRestoreFailures.set(saved.id, {
33640
+ deviceId: saved.id,
33641
+ stableId: saved.stableId,
33642
+ type: saved.type,
33643
+ attempts: 0,
33644
+ lastError: "persisted row has no configuration",
33645
+ failedAt: Date.now()
33646
+ });
33647
+ this.ctx.logger.error("Persisted device row has NO configuration — quarantined: not restored, not retried. Remove it (deviceManager.removeDevice) or re-add the device.", {
33648
+ tags: {
33649
+ deviceId: saved.id,
33650
+ stableId: saved.stableId
33651
+ },
33652
+ meta: {
33653
+ type: saved.type,
33654
+ provider: this.providerName
33655
+ }
33656
+ });
33657
+ }
33611
33658
  cancelRestoreRetries() {
33612
33659
  this._restoreRetryScheduler?.cancel();
33613
33660
  this._restoreRetryScheduler = null;
@@ -33792,6 +33839,10 @@ var BaseDeviceProvider = class extends BaseAddon {
33792
33839
  });
33793
33840
  return;
33794
33841
  }
33842
+ if (this.isUnrestorableShell(saved)) {
33843
+ this.quarantineShell(saved);
33844
+ return;
33845
+ }
33795
33846
  try {
33796
33847
  await attemptRestore(saved);
33797
33848
  } catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-wyze",
3
- "version": "0.2.77",
3
+ "version": "0.2.79",
4
4
  "description": "Wyze camera device-provider addon for CamStack — wraps the @apocaliss92/wyze-bridge-js P2P/DTLS client, feeding the stream-broker via the pull-rfc4571 lazy-publish path (a structural twin of addon-provider-reolink)",
5
5
  "keywords": [
6
6
  "camstack",