@decentnetwork/lan 0.1.157 → 0.1.158

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.
Binary file
Binary file
Binary file
Binary file
@@ -42,6 +42,14 @@ export const BUILTIN_REGION_DOMAINS = {
42
42
  // subdomains that resolve to a non-China edge, so pin them statically.
43
43
  ".v.myalicdn.com", ".myalicdn.com",
44
44
  ".kcdnvip.com", ".ks-cdn.com", ".ksyuncdn.com",
45
+ // CCTV live also rotates onto Baidu (bdydns) and Wangsu/网宿 (wscdns)
46
+ // edges — observed segment hosts ldcctvwbcdbd.a.bdydns.com and
47
+ // ldcctvwbcdcnc.v.wscdns.com. These aren't .cn, so pin the provider
48
+ // suffixes so they deterministically ride a China exit instead of
49
+ // depending on geo-classify timing (which flaps to direct → geo-block
50
+ // when a China exit is momentarily busy). Tencent live is .myqcloud.com
51
+ // below.
52
+ ".bdydns.com", ".wscdns.com",
45
53
  ".bilibili.com", ".biliapi.net", ".bilivideo.com", ".bilivideo.cn", ".hdslb.com",
46
54
  ".youku.com", ".iqiyi.com", ".iq.com", ".mgtv.com", ".hitv.com",
47
55
  ".miguvideo.com", ".cmvideo.cn", ".migu.cn",
@@ -254,7 +262,14 @@ export function startMultiExitRouter(opts) {
254
262
  const geoCn = new GeoCnClassifier();
255
263
  async function resolveRegion(host) {
256
264
  let region = routeFor(host); // static domains + persistent learned routes
257
- if (region === "direct" && !isLocalDest(host) && fallbackRegion && regionHasExits(fallbackRegion)) {
265
+ // Consult the geo classifier even when the fallback region currently has
266
+ // NO healthy exits. A China-allocated host (e.g. a CCTV live CDN edge)
267
+ // must be pinned to the China region and 503 (retriable) when the region
268
+ // is momentarily down — NOT leaked to `direct`, where the CDN geo-blocks
269
+ // our non-China egress outright ("您所在的地区,暂不支持播放该视频") and the
270
+ // directConnect failover can even unlearn the route, turning a transient
271
+ // exit blip into a persistent geo-block until re-learned.
272
+ if (region === "direct" && !isLocalDest(host) && fallbackRegion) {
258
273
  // peek() is sync for IP literals / cached verdicts; classify() resolves.
259
274
  const cn = geoCn.peek(host);
260
275
  if (cn === true || (cn === null && await geoCn.classify(host))) {
@@ -265,8 +280,13 @@ export function startMultiExitRouter(opts) {
265
280
  region = fallbackRegion;
266
281
  }
267
282
  }
268
- if (region !== "direct" && !regionHasExits(region))
283
+ // Downgrade a region-with-no-exits to direct ONLY for hosts we don't know
284
+ // to be China. A known-China host to direct is a guaranteed geo-block, so
285
+ // keep it in-region (the caller 503s, the player retries, and a recovered
286
+ // China exit serves the retry).
287
+ if (region !== "direct" && !regionHasExits(region) && geoCn.peek(host) !== true) {
269
288
  region = "direct";
289
+ }
270
290
  return region;
271
291
  }
272
292
  const seenGeo = new Set();
@@ -599,7 +619,12 @@ export function startMultiExitRouter(opts) {
599
619
  let i = 0;
600
620
  const tryNext = () => {
601
621
  if (i >= order.length) {
602
- learner.unlearn(h);
622
+ // Only unlearn if we DON'T know this is a China host. Unlearning a
623
+ // China-geo host back to `direct` is the geo-block trap: direct is
624
+ // guaranteed to fail for it, so keep the learned China route and let
625
+ // the player retry when a China exit recovers.
626
+ if (geoCn.peek(h) !== true)
627
+ learner.unlearn(h);
603
628
  client.end("HTTP/1.1 502 All routes failed\r\n\r\n");
604
629
  return;
605
630
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decentnetwork/lan",
3
- "version": "0.1.157",
3
+ "version": "0.1.158",
4
4
  "description": "Private virtual LAN for self-hosted services and AI agents, built on Elastos Carrier. NAT-traversal, name service, ACL, all over a peer-to-peer mesh — no public IP required.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -79,7 +79,7 @@
79
79
  },
80
80
  "dependencies": {
81
81
  "@decentnetwork/dora": "^0.1.13",
82
- "@decentnetwork/peer": "^0.1.82",
82
+ "@decentnetwork/peer": "^0.1.83",
83
83
  "ink": "^5.2.1",
84
84
  "js-yaml": "^4.1.0",
85
85
  "node-forge": "^1.4.0",