@apocaliss92/nodelink-js 0.4.19 → 0.4.21-beta.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.
@@ -11237,9 +11237,11 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
11237
11237
  if (!this.sessionGuardIntervalTimer) {
11238
11238
  client.once("push", () => {
11239
11239
  void this.logActiveSessionsOnStartup();
11240
- this.sessionGuardIntervalTimer = setInterval(() => {
11241
- void this.maybeRebootOnTooManySessions();
11242
- }, 6e4);
11240
+ if (this.sessionGuardEnabled) {
11241
+ this.sessionGuardIntervalTimer = setInterval(() => {
11242
+ void this.maybeRebootOnTooManySessions();
11243
+ }, 6e4);
11244
+ }
11243
11245
  });
11244
11246
  }
11245
11247
  }
@@ -11272,6 +11274,19 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
11272
11274
  _isMultiFocal;
11273
11275
  /** Maximum dedicated sessions allowed before triggering a reboot (default: 7). */
11274
11276
  maxDedicatedSessionsBeforeReboot;
11277
+ /**
11278
+ * Opt-in: when `false` (default), the lib never starts the 60s periodic
11279
+ * `getOnlineUserList` poll and never schedules an automatic reboot based
11280
+ * on the session count. The post-socket-create probe at line ~1859 is
11281
+ * also skipped. Consumers that want the legacy behaviour can pass
11282
+ * `enableSessionGuard: true` to the constructor.
11283
+ *
11284
+ * Rationale: on BCUDP (battery cameras) the periodic poll wakes the
11285
+ * camera every minute and triggers a perpetual sleeping↔awake cycle —
11286
+ * see issue #18. Even on AC cameras the auto-reboot side effect is
11287
+ * surprising; making it explicit avoids astonishment.
11288
+ */
11289
+ sessionGuardEnabled = false;
11275
11290
  sessionGuardRebootInFlight;
11276
11291
  sessionGuardLastRebootAtMs;
11277
11292
  /** Track last known session count and IDs for change detection. */
@@ -11316,6 +11331,25 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
11316
11331
  simpleEventResubscribeTimer;
11317
11332
  simpleEventResubscribeInFlight;
11318
11333
  simpleEventResubscribeIntervalMs = 5 * 6e4;
11334
+ /**
11335
+ * Default `true` for non-UDP transports (TCP / `auto`), `false` for UDP.
11336
+ *
11337
+ * On TCP the periodic 5-min `subscribeEvents` renewal is cheap belt-and-
11338
+ * braces for firmwares that silently drop the push subscription.
11339
+ *
11340
+ * On UDP (battery cameras) every renewal sends cmd_id 31 which wakes
11341
+ * the device, driving an exact-5-minute sleep/awake cycle visible
11342
+ * downstream in MQTT / Home Assistant (continuation of issue #18). The
11343
+ * reactive `simpleEventWatchdog` (10s tick, 5 min silence threshold)
11344
+ * already recovers silent-drop cases without periodic wakes, so the
11345
+ * renewal is disabled by default for UDP.
11346
+ *
11347
+ * `startSimpleEventResubscribeTimer` also re-checks the live transport
11348
+ * before arming the timer, so callers that pick `transport: "auto"` and
11349
+ * end up on UDP at runtime get the safer behaviour even if the flag
11350
+ * was left default-on.
11351
+ */
11352
+ eventResubscribeEnabled = true;
11319
11353
  // Event watchdog: auto-recovery when events stop flowing or subscription fails
11320
11354
  simpleEventWatchdogTimer;
11321
11355
  simpleEventLastReceivedAt = 0;
@@ -11963,7 +11997,9 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
11963
11997
  } catch {
11964
11998
  }
11965
11999
  }
11966
- void this.maybeRebootOnTooManySessions();
12000
+ if (this.sessionGuardEnabled) {
12001
+ void this.maybeRebootOnTooManySessions();
12002
+ }
11967
12003
  return newClient;
11968
12004
  } catch (loginError) {
11969
12005
  const prevCooldown = this.socketPoolCooldowns.get(this.host);
@@ -12273,6 +12309,13 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
12273
12309
  logger: this.logger,
12274
12310
  debugConfig: generalClient.getDebugConfig?.()
12275
12311
  });
12312
+ this.sessionGuardEnabled = opts.enableSessionGuard === true;
12313
+ const explicitResubscribe = opts.enableEventResubscribe;
12314
+ if (typeof explicitResubscribe === "boolean") {
12315
+ this.eventResubscribeEnabled = explicitResubscribe;
12316
+ } else {
12317
+ this.eventResubscribeEnabled = opts.transport !== "udp";
12318
+ }
12276
12319
  const maxSessions = opts.maxDedicatedSessionsBeforeReboot;
12277
12320
  if (typeof maxSessions === "number" && Number.isFinite(maxSessions) && maxSessions > 0) {
12278
12321
  this.maxDedicatedSessionsBeforeReboot = Math.floor(maxSessions);
@@ -12446,6 +12489,7 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
12446
12489
  */
12447
12490
  async maybeRebootOnTooManySessions() {
12448
12491
  if (!this.client.isSocketConnected?.()) return;
12492
+ if (this.client.getTransport?.() === "udp") return;
12449
12493
  const threshold = this.maxDedicatedSessionsBeforeReboot ?? 10;
12450
12494
  if (this.sessionGuardRebootInFlight) return;
12451
12495
  const cooldownMs = 10 * 6e4;
@@ -12991,6 +13035,8 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
12991
13035
  startSimpleEventResubscribeTimer() {
12992
13036
  if (this.simpleEventResubscribeTimer) return;
12993
13037
  if (this.simpleEventListeners.size === 0) return;
13038
+ if (!this.eventResubscribeEnabled) return;
13039
+ if (this.client.getTransport?.() === "udp") return;
12994
13040
  this.simpleEventResubscribeTimer = setInterval(() => {
12995
13041
  void this.renewSimpleEventSubscription();
12996
13042
  }, this.simpleEventResubscribeIntervalMs);
@@ -18790,7 +18836,17 @@ ${xml}`
18790
18836
  const isSingleMotionModel = normalizedModel ? checkModelMatch(DUAL_LENS_SINGLE_MOTION_MODELS, normalizedModel) : false;
18791
18837
  const channelNumValue = typeof channelNum === "string" ? Number.parseInt(channelNum, 10) : channelNum;
18792
18838
  const hasDualLensChannelCount = channelNumValue === 2 && Number.isFinite(channelNumValue);
18793
- const isDualLens = isDualMotionModel || isSingleMotionModel || hasDualLensChannelCount;
18839
+ const supportItemForChannel = (() => {
18840
+ if (!supportInfo) return void 0;
18841
+ const items = supportInfo.items;
18842
+ if (!Array.isArray(items)) return void 0;
18843
+ return items.find(
18844
+ (it) => typeof it === "object" && it !== null && "ledCtrl" in it
18845
+ );
18846
+ })();
18847
+ const binoCfgRaw = supportItemForChannel ? supportItemForChannel.binoCfg : void 0;
18848
+ const hasBinoCfgFlag = typeof binoCfgRaw === "number" ? binoCfgRaw > 0 : typeof binoCfgRaw === "string" ? Number(binoCfgRaw) > 0 : false;
18849
+ const isDualLens = hasBinoCfgFlag || isDualMotionModel || isSingleMotionModel || hasDualLensChannelCount;
18794
18850
  if (!isDualLens) {
18795
18851
  return {
18796
18852
  isDualLens: false,
@@ -23950,4 +24006,4 @@ export {
23950
24006
  isTcpFailureThatShouldFallbackToUdp,
23951
24007
  autoDetectDeviceType
23952
24008
  };
23953
- //# sourceMappingURL=chunk-5M7BGMLV.js.map
24009
+ //# sourceMappingURL=chunk-EZ7WNPLB.js.map