@apocaliss92/nodelink-js 0.6.0 → 0.6.1

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.
@@ -3,7 +3,7 @@ import {
3
3
  BaichuanRtspServer,
4
4
  ReolinkBaichuanApi,
5
5
  autoDetectDeviceType
6
- } from "../chunk-7HSTETZR.js";
6
+ } from "../chunk-EAHRVNEX.js";
7
7
  import "../chunk-XDVBNZGR.js";
8
8
  import {
9
9
  __require
package/dist/index.cjs CHANGED
@@ -9047,12 +9047,28 @@ async function getServerBinding(uid, options = {}) {
9047
9047
  const fetchImpl = options.fetchImpl ?? globalThis.fetch;
9048
9048
  const logger = options.logger;
9049
9049
  if (typeof fetchImpl !== "function") {
9050
- logger?.debug?.(
9050
+ logger?.log?.(
9051
9051
  `[server-binding] global fetch unavailable; skipping cloud lookup`
9052
9052
  );
9053
9053
  cache.set(uid, { kind: "err", expires: now + NEGATIVE_TTL_MS });
9054
9054
  return void 0;
9055
9055
  }
9056
+ try {
9057
+ const apiHostname = new URL(baseUrl).hostname;
9058
+ const dns2 = await import("dns/promises");
9059
+ const answers = await dns2.lookup(apiHostname, { family: 4, all: true });
9060
+ const sinkholed = answers.find(
9061
+ (a) => a.address?.startsWith("127.") || a.address === "0.0.0.0" || a.address?.startsWith("10.") || a.address?.startsWith("192.168.") || /^172\.(1[6-9]|2[0-9]|3[0-1])\./.test(a.address ?? "")
9062
+ );
9063
+ if (sinkholed) {
9064
+ logger?.log?.(
9065
+ `[server-binding] ${uid}: DNS for ${apiHostname} resolves to ${sinkholed.address} (sinkhole / /etc/hosts override). Cloud directory unreachable \u2014 falling back to the 22-hostname P2P sweep. Whitelist ${apiHostname} to enable.`
9066
+ );
9067
+ cache.set(uid, { kind: "err", expires: now + NEGATIVE_TTL_MS });
9068
+ return void 0;
9069
+ }
9070
+ } catch {
9071
+ }
9056
9072
  const url = `${baseUrl}/devices/${encodeURIComponent(uid)}/server-binding?language=${encodeURIComponent(language)}`;
9057
9073
  const controller = new AbortController();
9058
9074
  const timer = setTimeout(() => controller.abort(), timeoutMs);
@@ -9063,8 +9079,8 @@ async function getServerBinding(uid, options = {}) {
9063
9079
  headers: { Accept: "application/json" }
9064
9080
  });
9065
9081
  if (!res.ok) {
9066
- logger?.debug?.(
9067
- `[server-binding] ${uid}: HTTP ${res.status} ${res.statusText}`
9082
+ logger?.log?.(
9083
+ `[server-binding] ${uid}: HTTP ${res.status} ${res.statusText} from ${url}`
9068
9084
  );
9069
9085
  cache.set(uid, { kind: "err", expires: now + NEGATIVE_TTL_MS });
9070
9086
  return void 0;
@@ -9072,8 +9088,15 @@ async function getServerBinding(uid, options = {}) {
9072
9088
  const json = await res.json();
9073
9089
  const parsed = parseServerBindingResponse(json);
9074
9090
  if (!parsed) {
9075
- logger?.debug?.(
9076
- `[server-binding] ${uid}: response shape did not match expectations`
9091
+ logger?.log?.(
9092
+ `[server-binding] ${uid}: response shape did not match expectations (Reolink schema change?)`
9093
+ );
9094
+ cache.set(uid, { kind: "err", expires: now + NEGATIVE_TTL_MS });
9095
+ return void 0;
9096
+ }
9097
+ if (parsed.availableZones.length === 0) {
9098
+ logger?.log?.(
9099
+ `[server-binding] ${uid}: cloud returned 0 zones \u2014 UID not registered with Reolink cloud (or wrong region)`
9077
9100
  );
9078
9101
  cache.set(uid, { kind: "err", expires: now + NEGATIVE_TTL_MS });
9079
9102
  return void 0;
@@ -9092,9 +9115,23 @@ async function getServerBinding(uid, options = {}) {
9092
9115
  );
9093
9116
  return parsed;
9094
9117
  } catch (e) {
9095
- logger?.debug?.(
9096
- `[server-binding] ${uid}: ${e?.message ?? String(e)}`
9097
- );
9118
+ const msg = e?.message ?? String(e);
9119
+ const errName = e?.name;
9120
+ if (errName === "AbortError" || msg.includes("aborted")) {
9121
+ logger?.log?.(
9122
+ `[server-binding] ${uid}: timed out after ${timeoutMs}ms (cloud unreachable)`
9123
+ );
9124
+ } else if (msg.includes("ENOTFOUND") || msg.includes("EAI_AGAIN")) {
9125
+ logger?.log?.(
9126
+ `[server-binding] ${uid}: DNS failed (${msg}) \u2014 apis.reolink.com may be blocked at resolver`
9127
+ );
9128
+ } else if (msg.includes("ECONNREFUSED") || msg.includes("EHOSTUNREACH") || msg.includes("ENETUNREACH")) {
9129
+ logger?.log?.(
9130
+ `[server-binding] ${uid}: network unreachable (${msg}) \u2014 cloud port blocked`
9131
+ );
9132
+ } else {
9133
+ logger?.log?.(`[server-binding] ${uid}: fetch failed \u2014 ${msg}`);
9134
+ }
9098
9135
  cache.set(uid, { kind: "err", expires: now + NEGATIVE_TTL_MS });
9099
9136
  return void 0;
9100
9137
  } finally {
@@ -9530,12 +9567,19 @@ var BcUdpStream = class extends import_node_events.EventEmitter {
9530
9567
  const tid = (Math.floor(Math.random() * 2147483647) | 0) >>> 0;
9531
9568
  const xml = buildC2mQ({ uid });
9532
9569
  const pkt = encodeDiscoveryPacket(tid, xml);
9570
+ const counters = { sentBytes: 0, rxBytes: 0 };
9533
9571
  return await new Promise((resolve, reject) => {
9534
9572
  const deadline = setTimeout(() => {
9535
9573
  cleanup();
9536
- reject(new Error(`P2P UID lookup timeout (${dest.host}:${dest.port})`));
9574
+ const err = new Error(
9575
+ `P2P UID lookup timeout (${dest.host}:${dest.port}) \u2014 sent=${counters.sentBytes}B rx=${counters.rxBytes}B`
9576
+ );
9577
+ err.sentBytes = counters.sentBytes;
9578
+ err.rxBytes = counters.rxBytes;
9579
+ reject(err);
9537
9580
  }, timeoutMs);
9538
9581
  const onMsg = (msg) => {
9582
+ counters.rxBytes += msg.length;
9539
9583
  try {
9540
9584
  const p = decodeBcUdpPacket(msg);
9541
9585
  if (p.kind !== "discovery") return;
@@ -9543,13 +9587,19 @@ var BcUdpStream = class extends import_node_events.EventEmitter {
9543
9587
  const qr = parseM2cQr(p.xml);
9544
9588
  if (!qr?.reg || !qr?.relay) return;
9545
9589
  cleanup();
9546
- resolve({ reg: qr.reg, relay: qr.relay });
9590
+ resolve({
9591
+ reg: qr.reg,
9592
+ relay: qr.relay,
9593
+ sentBytes: counters.sentBytes,
9594
+ rxBytes: counters.rxBytes
9595
+ });
9547
9596
  } catch {
9548
9597
  }
9549
9598
  };
9550
9599
  const send = () => {
9551
9600
  try {
9552
9601
  sock.send(pkt, dest.port, dest.host);
9602
+ counters.sentBytes += pkt.length;
9553
9603
  } catch {
9554
9604
  }
9555
9605
  };