@apocaliss92/nodelink-js 0.4.5 → 0.4.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.
@@ -12,7 +12,7 @@ import {
12
12
  sampleStreams,
13
13
  sanitizeFixtureData,
14
14
  testChannelStreams
15
- } from "./chunk-DEOMUWBN.js";
15
+ } from "./chunk-TR3V5FTO.js";
16
16
  export {
17
17
  captureModelFixtures,
18
18
  collectCgiDiagnostics,
@@ -28,4 +28,4 @@ export {
28
28
  sanitizeFixtureData,
29
29
  testChannelStreams
30
30
  };
31
- //# sourceMappingURL=DiagnosticsTools-55PR4WFD.js.map
31
+ //# sourceMappingURL=DiagnosticsTools-UMN4C7SY.js.map
@@ -144,7 +144,7 @@ import {
144
144
  talkTraceLog,
145
145
  traceLog,
146
146
  xmlEscape
147
- } from "./chunk-DEOMUWBN.js";
147
+ } from "./chunk-TR3V5FTO.js";
148
148
 
149
149
  // src/protocol/framing.ts
150
150
  function encodeHeader(h) {
@@ -654,6 +654,9 @@ var BcUdpStream = class extends EventEmitter {
654
654
  resendTimer;
655
655
  hbTimer;
656
656
  discoveryTid;
657
+ // Track discovery-phase timers so close() can cancel them even if
658
+ // discovery is still in progress (prevents ERR_SOCKET_DGRAM_NOT_RUNNING).
659
+ discoveryTimers = [];
657
660
  acceptSent = false;
658
661
  lastAcceptAtMs;
659
662
  ackScheduled = false;
@@ -702,9 +705,31 @@ var BcUdpStream = class extends EventEmitter {
702
705
  });
703
706
  sock.on("error", (e) => this.emit("error", e));
704
707
  sock.on("close", () => this.emit("close"));
705
- await new Promise(
706
- (resolve) => sock.bind(0, "0.0.0.0", () => resolve())
707
- );
708
+ const portRange = Array.from({ length: 500 }, (_, i) => 53500 + i);
709
+ for (let i = portRange.length - 1; i > 0; i--) {
710
+ const j = Math.floor(Math.random() * (i + 1));
711
+ [portRange[i], portRange[j]] = [portRange[j], portRange[i]];
712
+ }
713
+ let bound = false;
714
+ for (const port of portRange) {
715
+ try {
716
+ await new Promise((resolve, reject) => {
717
+ sock.once("error", reject);
718
+ sock.bind(port, "0.0.0.0", () => {
719
+ sock.removeListener("error", reject);
720
+ resolve();
721
+ });
722
+ });
723
+ bound = true;
724
+ break;
725
+ } catch {
726
+ }
727
+ }
728
+ if (!bound) {
729
+ await new Promise(
730
+ (resolve) => sock.bind(0, "0.0.0.0", () => resolve())
731
+ );
732
+ }
708
733
  if (this.opts.mode === "direct") {
709
734
  this.remote = { host: this.opts.host, port: this.opts.port };
710
735
  this.clientId = this.opts.clientId;
@@ -1124,7 +1149,24 @@ var BcUdpStream = class extends EventEmitter {
1124
1149
  BCUDP_DISCOVERY_PORT_LOCAL_ANY,
1125
1150
  BCUDP_DISCOVERY_PORT_LOCAL_UID
1126
1151
  ];
1127
- const broadcastHost = "255.255.255.255";
1152
+ const broadcastHosts = ["255.255.255.255"];
1153
+ const ifaces = networkInterfaces();
1154
+ for (const name of Object.keys(ifaces)) {
1155
+ const entries = ifaces[name];
1156
+ if (!entries) continue;
1157
+ for (const addr2 of entries) {
1158
+ if (addr2.family === "IPv4" && !addr2.internal && addr2.cidr) {
1159
+ const ipParts = addr2.address.split(".").map(Number);
1160
+ const maskParts = addr2.netmask.split(".").map(Number);
1161
+ if (ipParts.length === 4 && maskParts.length === 4) {
1162
+ const bcast = ipParts.map((octet, i) => octet | ~maskParts[i] & 255).join(".");
1163
+ if (!broadcastHosts.includes(bcast)) {
1164
+ broadcastHosts.push(bcast);
1165
+ }
1166
+ }
1167
+ }
1168
+ }
1169
+ }
1128
1170
  const directHost = (this.opts.directHost ?? "").trim();
1129
1171
  const localMode = opts?.localMode ?? "local-broadcast";
1130
1172
  const directFirstWindowMs = localMode === "local-direct" && directHost ? 3e3 : 0;
@@ -1151,6 +1193,7 @@ var BcUdpStream = class extends EventEmitter {
1151
1193
  )
1152
1194
  );
1153
1195
  }, discoveryTimeout);
1196
+ this.discoveryTimers.push(timeout);
1154
1197
  let retryTimer;
1155
1198
  let retryCount = 0;
1156
1199
  let discoveredSid;
@@ -1327,11 +1370,11 @@ var BcUdpStream = class extends EventEmitter {
1327
1370
  if (directHost) {
1328
1371
  if (directFirstWindowMs > 0 && elapsedMs < directFirstWindowMs)
1329
1372
  return [directHost];
1330
- return [directHost, broadcastHost];
1373
+ return [directHost, ...broadcastHosts];
1331
1374
  }
1332
- return [broadcastHost];
1375
+ return broadcastHosts;
1333
1376
  }
1334
- return [broadcastHost];
1377
+ return broadcastHosts;
1335
1378
  })();
1336
1379
  for (const host of Array.from(new Set(hosts))) {
1337
1380
  for (const port of ports) {
@@ -1339,8 +1382,7 @@ var BcUdpStream = class extends EventEmitter {
1339
1382
  sock.send(packet, port, host);
1340
1383
  retryCount++;
1341
1384
  this.emit("debug", "discovery_send", { retryCount, host, port });
1342
- } catch (e) {
1343
- this.emit("error", e instanceof Error ? e : new Error(String(e)));
1385
+ } catch {
1344
1386
  }
1345
1387
  }
1346
1388
  }
@@ -1349,6 +1391,7 @@ var BcUdpStream = class extends EventEmitter {
1349
1391
  retryTimer = setIntervalNode(() => {
1350
1392
  sendDiscovery();
1351
1393
  }, retryInterval);
1394
+ this.discoveryTimers.push(retryTimer);
1352
1395
  });
1353
1396
  this.clientId = reply.cid;
1354
1397
  this.cameraId = reply.did;
@@ -1665,6 +1708,10 @@ var BcUdpStream = class extends EventEmitter {
1665
1708
  this.ackTimer = void 0;
1666
1709
  this.resendTimer = void 0;
1667
1710
  this.hbTimer = void 0;
1711
+ for (const t of this.discoveryTimers) {
1712
+ clearInterval(t);
1713
+ }
1714
+ this.discoveryTimers = [];
1668
1715
  const s = this.sock;
1669
1716
  this.sock = void 0;
1670
1717
  if (!s) return;
@@ -10726,6 +10773,20 @@ var ReolinkBaichuanApi = class _ReolinkBaichuanApi {
10726
10773
  const prefix = basename.substring(0, 10).toUpperCase();
10727
10774
  return prefix.includes("S") ? "subStream" : "mainStream";
10728
10775
  }
10776
+ /**
10777
+ * Stream profiles that the device explicitly rejected (response_code 400).
10778
+ * Keyed by `"ch:profile"` (e.g. `"0:ext"`). Once a profile is in this set
10779
+ * it is excluded from `buildVideoStreamOptions()` results and no further
10780
+ * start attempts are made until the API instance is recreated.
10781
+ */
10782
+ _rejectedStreamProfiles = /* @__PURE__ */ new Set();
10783
+ /**
10784
+ * Check whether a stream profile was rejected by the device at runtime
10785
+ * (e.g. ext returned response_code 400).
10786
+ */
10787
+ isStreamProfileRejected(channel, profile) {
10788
+ return this._rejectedStreamProfiles.has(`${channel}:${profile}`);
10789
+ }
10729
10790
  /**
10730
10791
  * Cache for buildVideoStreamOptions.
10731
10792
  *
@@ -15850,6 +15911,16 @@ ${stderr}`)
15850
15911
  }
15851
15912
  if (!frame) frame = await targetClient.sendFrame(baseParams);
15852
15913
  if (frame.header.responseCode !== 200) {
15914
+ if (frame.header.responseCode === 400) {
15915
+ const rejKey = `${ch}:${profile}`;
15916
+ if (!this._rejectedStreamProfiles.has(rejKey)) {
15917
+ this._rejectedStreamProfiles.add(rejKey);
15918
+ this.videoStreamOptionsCache.clear();
15919
+ this.logger?.warn?.(
15920
+ `[ReolinkBaichuanApi] Stream profile rejected by device: channel=${ch} profile=${profile} (response_code 400). This profile will be excluded from available streams. The camera may not support this stream profile with the current firmware.`
15921
+ );
15922
+ }
15923
+ }
15853
15924
  throw new Error(
15854
15925
  `Video stream request rejected (response_code ${frame.header.responseCode}). Expected response_code 200, camera returned ${frame.header.responseCode}`
15855
15926
  );
@@ -17871,6 +17942,8 @@ ${xml}`
17871
17942
  for (const metadata of params.metadatas) {
17872
17943
  const profile = metadata.profile;
17873
17944
  if (isMultiFocal && profile === "ext") continue;
17945
+ if (this._rejectedStreamProfiles.has(`${params.channel}:${profile}`))
17946
+ continue;
17874
17947
  if (params.includeRtsp && profile !== "ext") {
17875
17948
  const streamName = profile === "main" ? "main" : "sub";
17876
17949
  pushRtsp({
@@ -18032,7 +18105,7 @@ ${xml}`
18032
18105
  * @returns Test results for all stream types and profiles
18033
18106
  */
18034
18107
  async testChannelStreams(channel, logger) {
18035
- const { testChannelStreams } = await import("./DiagnosticsTools-55PR4WFD.js");
18108
+ const { testChannelStreams } = await import("./DiagnosticsTools-UMN4C7SY.js");
18036
18109
  return await testChannelStreams({
18037
18110
  api: this,
18038
18111
  channel: this.normalizeChannel(channel),
@@ -18048,7 +18121,7 @@ ${xml}`
18048
18121
  * @returns Complete diagnostics for all channels and streams
18049
18122
  */
18050
18123
  async collectMultifocalDiagnostics(logger) {
18051
- const { collectMultifocalDiagnostics } = await import("./DiagnosticsTools-55PR4WFD.js");
18124
+ const { collectMultifocalDiagnostics } = await import("./DiagnosticsTools-UMN4C7SY.js");
18052
18125
  return await collectMultifocalDiagnostics({
18053
18126
  api: this,
18054
18127
  logger
@@ -21730,4 +21803,4 @@ export {
21730
21803
  isTcpFailureThatShouldFallbackToUdp,
21731
21804
  autoDetectDeviceType
21732
21805
  };
21733
- //# sourceMappingURL=chunk-WDFKIHM5.js.map
21806
+ //# sourceMappingURL=chunk-F2Y5U3YP.js.map