@twinsearth/dsh-2xray 0.3.5 → 0.3.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.6 — 2026-10-29
4
+
5
+ ### 规则数据
6
+
7
+ - 自动更新周期从 24h/12h 调整为 **72 小时**:新鲜度阈值与定时检查间隔一致。
8
+ - 启动前仍会补缺(缺失时先下载再启动);更新成功后重启 xray 加载新数据。
9
+ - 小于 100KB 的响应仍视为错误页,不覆盖现有文件。
10
+ - 设置页文案改为「每 72 小时更新规则数据」。
11
+
3
12
  ## 0.3.5 — 2026-10-29
4
13
 
5
14
  ### 规则数据
package/README.md CHANGED
@@ -336,7 +336,7 @@ v0.2.0 提供两个入口,互不替代:
336
336
 
337
337
  ## 规则数据自动更新
338
338
 
339
- 设置页默认勾选「每日更新规则数据」:Host 会下载 XTLS 的 `geoip-lite.dat` / `geosite.dat`,失败时回退 jsDelivr(Loyalsoldier);文件小于 100KB 视为错误页并拒绝替换。首次缺失时在启动前下载,之后每 12 小时检查一次,更新成功后重启 xray 热加载。
339
+ 设置页默认勾选「每 72 小时更新规则数据」:Host 会下载 XTLS 的 `geoip-lite.dat` / `geosite.dat`,失败时回退 jsDelivr(Loyalsoldier);文件小于 100KB 视为错误页并拒绝替换。首次缺失时在启动前下载,之后每 72 小时检查一次,更新成功后重启 xray 热加载。
340
340
 
341
341
  > Xray 26.9.30 接受顶层 `geodata` 配置块但实测不执行其 cron(85 秒内无下载),因此更新由插件完成,不依赖该字段。
342
342
 
@@ -345,6 +345,16 @@ v0.2.0 提供两个入口,互不替代:
345
345
  - 进程内(需 DSH 会话鉴权):`GET /api/xray/healthz` → `{ "ok": true, "version": "v0.3.3", ... }`
346
346
  - 发布物(公开、静态):Release 资产 `healthz.json`,`version` 与 tag 一致,可用于部署流水线的健康探针。
347
347
 
348
+ ## DSH 插件市场
349
+
350
+ 索引地址(format 1):
351
+
352
+ ```
353
+ https://raw.githubusercontent.com/TwinsEarth/DSH-2Xray/main/market/index.json
354
+ ```
355
+
356
+ 在 DSH 的「设置 → 插件市场 → 添加源」粘贴该地址,即可搜索并安装 DSH-2Xray。索引只声明 npm 包 `@twinsearth/dsh-2xray` 与其版本,安装仍走 npm registry。
357
+
348
358
  ## 更新
349
359
 
350
360
  设置页 2Xray 里有三个入口:
package/index.js CHANGED
@@ -308,7 +308,7 @@ export function apply(ctx, rawConfig) {
308
308
  })().catch((error) => logger.warn(`规则数据更新失败:${String(error)}`))
309
309
  }
310
310
  const first = setTimeout(refresh, 60_000)
311
- const daily = setInterval(refresh, 12 * 60 * 60 * 1000)
311
+ const daily = setInterval(refresh, 72 * 60 * 60 * 1000)
312
312
  first.unref?.()
313
313
  daily.unref?.()
314
314
  }
package/lib/client.js CHANGED
@@ -553,7 +553,7 @@ window.__ModuleLoader__.load({
553
553
  h('label', { style: { fontSize: 12.5, display: 'flex', alignItems: 'center', gap: 6 } },
554
554
  h('input', { type: 'checkbox', checked: autoUpdate, onChange: (event) => setAutoUpdate(event.target.checked) }), '自动更新'),
555
555
  h('label', { style: { fontSize: 12.5, display: 'flex', alignItems: 'center', gap: 6 } },
556
- h('input', { type: 'checkbox', checked: autoGeodata, onChange: (event) => setAutoGeodata(event.target.checked) }), '每日更新规则数据')),
556
+ h('input', { type: 'checkbox', checked: autoGeodata, onChange: (event) => setAutoGeodata(event.target.checked) }), '每 72 小时更新规则数据')),
557
557
  h('div', { style: { ...C.muted, fontSize: 12, marginTop: 6 } },
558
558
  updateInfo
559
559
  ? `当前 ${updateInfo.current} · 最新 ${updateInfo.latest ?? '未知'}${updateInfo.available ? '(可更新)' : '(已是最新)'}` +
package/lib/geodata.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { mkdirSync, renameSync, rmSync, statSync, writeFileSync } from 'node:fs'
2
2
  import { join } from 'node:path'
3
3
 
4
- const DAY_MS = 24 * 60 * 60 * 1000
4
+ const REFRESH_MS = 72 * 60 * 60 * 1000
5
5
  const MIN_BYTES = 100_000
6
6
 
7
7
  export const GEODATA_FILES = [
@@ -39,7 +39,7 @@ export function geodataStatus(dataDir) {
39
39
  return {
40
40
  files,
41
41
  missing,
42
- stale: missing.length > 0 || Date.now() - oldest > DAY_MS,
42
+ stale: missing.length > 0 || Date.now() - oldest > REFRESH_MS,
43
43
  updatedAt: files.length > 0 ? Math.min(...files.map((entry) => entry.mtimeMs)) : null,
44
44
  }
45
45
  }
package/lib/schema.js CHANGED
@@ -116,7 +116,7 @@ export const Config = Schema.object({
116
116
  geodata: Schema.object({
117
117
  autoUpdate: Schema.boolean()
118
118
  .default(true)
119
- .description('每日自动下载 geoip.dat/geosite.dat(XTLS 主源,jsDelivr 回退),更新后重启 xray。')
119
+ .description('每 72 小时自动下载 geoip.dat/geosite.dat(XTLS 主源,jsDelivr 回退),更新后重启 xray。')
120
120
  .volatile(),
121
121
  }),
122
122
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@twinsearth/dsh-2xray",
3
- "version": "0.3.5",
3
+ "version": "0.3.6",
4
4
  "private": false,
5
5
  "description": "DSH-2Xray: supervises xray-core and routes DSH process-wide HTTP(S) traffic through its local inbound, with optional multi-node gRPC control plane",
6
6
  "type": "module",
@@ -1,7 +1,7 @@
1
1
  import test from 'node:test'
2
2
  import assert from 'node:assert/strict'
3
3
  import http from 'node:http'
4
- import { existsSync, mkdtempSync, readFileSync, rmSync, statSync } from 'node:fs'
4
+ import { existsSync, mkdtempSync, readFileSync, rmSync, statSync, utimesSync, writeFileSync } from 'node:fs'
5
5
  import { tmpdir } from 'node:os'
6
6
  import { join } from 'node:path'
7
7
  import { geodataStatus, updateGeodata } from '../lib/geodata.js'
@@ -76,3 +76,17 @@ test('fresh files are skipped unless forced', async () => {
76
76
  rmSync(dir, { recursive: true, force: true })
77
77
  }
78
78
  })
79
+
80
+ test('the freshness window is 72 hours', () => {
81
+ const dir = mkdtempSync(join(tmpdir(), 'dsh-geodata-'))
82
+ try {
83
+ for (const file of ['geoip.dat', 'geosite.dat']) writeFileSync(join(dir, file), Buffer.alloc(200_000, 0x1f))
84
+ const now = Math.floor(Date.now() / 1000)
85
+ for (const file of ['geoip.dat', 'geosite.dat']) utimesSync(join(dir, file), now - 48 * 3600, now - 48 * 3600)
86
+ assert.equal(geodataStatus(dir).stale, false, '48h old must still be fresh')
87
+ for (const file of ['geoip.dat', 'geosite.dat']) utimesSync(join(dir, file), now - 73 * 3600, now - 73 * 3600)
88
+ assert.equal(geodataStatus(dir).stale, true, '73h old must be stale')
89
+ } finally {
90
+ rmSync(dir, { recursive: true, force: true })
91
+ }
92
+ })