@linxin666/dsh-ssh 0.3.1 → 0.3.3

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/README.i18n.yaml CHANGED
@@ -2,5 +2,5 @@
2
2
  # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
3
  # after editing either side, bring the other along and re-record with:
4
4
  # node scripts/verify-docs.mjs --write <dir>
5
- README.md: 7ea38ed3468b6dcac409216661ed4d33a2c81007
6
- README.zh.md: 736f82081b9d64729e449da4d1e4316efa9b37e1
5
+ README.md: bf12f2cd3c82e9f12800c74f1d907f8cf08370f2
6
+ README.zh.md: c404cbbf891f1d004ff23dc52c95d1e67d665450
package/README.md CHANGED
@@ -32,15 +32,15 @@ Built on the capability list of [badseal/ssh-skill](https://github.com/badseal/s
32
32
 
33
33
  ## Install
34
34
 
35
- Install the family aggregate package `@linxin666/dsh-web-ui-all` (all plugins and skins in one) or this plugin alone:
35
+ Install the family aggregate package `@linxin666/dsh-web-all` (all plugins and skins in one) or this plugin alone:
36
36
 
37
37
  ```sh
38
38
  ### From npm (recommended)
39
39
  dsh plugin --profile web add @linxin666/dsh-ssh@latest
40
40
 
41
41
  ### From the repository (development)
42
- git clone https://github.com/zhu1090093659/dsh-web-ui.git
43
- cd dsh-web-ui
42
+ git clone https://github.com/zhu1090093659/dsh-web.git
43
+ cd dsh-web
44
44
  pnpm install && pnpm -r build
45
45
  dsh plugin --profile web add link:$(pwd)/packages/dsh-ssh
46
46
 
@@ -73,3 +73,7 @@ pnpm --filter @linxin666/dsh-ssh build # tsc types + tsdown dual-half artifact
73
73
  - Every hop of a ProxyJump jump host must be a host alias already configured in this plugin.
74
74
  - Resume (broken-transfer continuation) is not implemented yet.
75
75
  - The transfer of Agent tools is a host-machine local path (same semantics as ssh-skill).
76
+
77
+ ## Telemetry
78
+
79
+ The browser half sends one anonymous install heartbeat per UTC day to dsh-market.com: a random localStorage id plus this package's name, nothing else. The server stores only a salted hash of that id, never IP addresses, and exposes aggregate counts only. See [docs/telemetry.md](../../docs/telemetry.md) for the full contract.
package/README.zh.md CHANGED
@@ -32,15 +32,15 @@
32
32
 
33
33
  ## 安装
34
34
 
35
- 推荐直接安装全家桶聚合包 `@linxin666/dsh-web-ui-all`(一个包装齐全部功能插件与皮肤),或单独安装本插件:
35
+ 推荐直接安装全家桶聚合包 `@linxin666/dsh-web-all`(一个包装齐全部功能插件与皮肤),或单独安装本插件:
36
36
 
37
37
  ```sh
38
38
  ### 从 npm 安装(推荐)
39
39
  dsh plugin --profile web add @linxin666/dsh-ssh@latest
40
40
 
41
41
  ### 从仓库安装(开发调试)
42
- git clone https://github.com/zhu1090093659/dsh-web-ui.git
43
- cd dsh-web-ui
42
+ git clone https://github.com/zhu1090093659/dsh-web.git
43
+ cd dsh-web
44
44
  pnpm install && pnpm -r build
45
45
  dsh plugin --profile web add link:$(pwd)/packages/dsh-ssh
46
46
 
@@ -73,3 +73,7 @@ pnpm --filter @linxin666/dsh-ssh build # tsc 类型 + tsdown 双半区产物
73
73
  - 跳板机 ProxyJump 的每一跳必须是本插件已配置的主机别名。
74
74
  - 断点续传(resume)暂未实现。
75
75
  - Agent 工具的传输为宿主机器本地路径(与 ssh-skill 相同的语义)。
76
+
77
+ ## 数据遥测
78
+
79
+ 浏览器半区每个 UTC 日向 dsh-market.com 发送一次匿名安装心跳:仅含一个 localStorage 随机 ID 与本包名,无其他数据。服务端只存储该 ID 的加盐哈希,不存 IP,且只暴露聚合计数。完整契约见 [docs/telemetry.md](../../docs/telemetry.md)。
package/lib/client.js CHANGED
@@ -15975,6 +15975,76 @@ window.__ModuleLoader__.load({
15975
15975
  });
15976
15976
  }
15977
15977
  //#endregion
15978
+ //#region src/client/telemetry.ts
15979
+ const VISITOR_KEY = "dsh-web-ui-telemetry-visitor";
15980
+ const DAY_KEY_PREFIX = "dsh-web-ui-telemetry-day:";
15981
+ const ENDPOINT = "https://dsh-market.com/api/telemetry/event";
15982
+ /** The building package's version, when the bundle carries it. */
15983
+ function bakedVersion() {
15984
+ try {
15985
+ return "0.3.3";
15986
+ } catch {
15987
+ return;
15988
+ }
15989
+ }
15990
+ /** Read or lazily create the anonymous visitor id; null when storage is unavailable. */
15991
+ function visitorId() {
15992
+ try {
15993
+ const existing = localStorage.getItem(VISITOR_KEY);
15994
+ if (existing && /^[A-Za-z0-9_-]{16,64}$/.test(existing)) return existing;
15995
+ const fresh = crypto.randomUUID().replaceAll("-", "");
15996
+ localStorage.setItem(VISITOR_KEY, fresh);
15997
+ return fresh;
15998
+ } catch {
15999
+ return null;
16000
+ }
16001
+ }
16002
+ /** Drop stale per-day dedup keys so localStorage does not grow forever. */
16003
+ function pruneDayKeys(today) {
16004
+ try {
16005
+ for (let index = localStorage.length - 1; index >= 0; index -= 1) {
16006
+ const key = localStorage.key(index);
16007
+ if (key !== null && key.startsWith(DAY_KEY_PREFIX) && key !== DAY_KEY_PREFIX + today) localStorage.removeItem(key);
16008
+ }
16009
+ } catch {}
16010
+ }
16011
+ /**
16012
+ * Fire the daily heartbeat for the given items at most once per UTC day per
16013
+ * browser. Never throws and never blocks the caller. Items without an explicit
16014
+ * version inherit the bundle's baked build version.
16015
+ */
16016
+ function reportDailyHeartbeat(items) {
16017
+ try {
16018
+ if (items.length === 0) return;
16019
+ const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
16020
+ if (navigator.webdriver) return;
16021
+ if (localStorage.getItem(DAY_KEY_PREFIX + today) !== null) return;
16022
+ const visitor = visitorId();
16023
+ if (visitor === null) return;
16024
+ pruneDayKeys(today);
16025
+ const payloadItems = items.map((item) => {
16026
+ const out = { name: item.name };
16027
+ const version = item.version ?? bakedVersion();
16028
+ if (version !== void 0) out.version = version;
16029
+ if (item.channel !== void 0) out.channel = item.channel;
16030
+ return out;
16031
+ });
16032
+ const body = JSON.stringify({
16033
+ kind: "heartbeat",
16034
+ visitor,
16035
+ items: payloadItems
16036
+ });
16037
+ fetch(ENDPOINT, {
16038
+ method: "POST",
16039
+ headers: { "content-type": "application/json" },
16040
+ body,
16041
+ keepalive: true
16042
+ }).then((response) => {
16043
+ if (response.ok) localStorage.setItem(DAY_KEY_PREFIX + today, "1");
16044
+ }).catch(() => {});
16045
+ } catch {}
16046
+ }
16047
+ //#endregion
15978
16048
  //#region src/client/index.ts
15979
16049
  /** Locale namespace this plugin owns. */
15980
16050
  const NS = "dsh-ssh";
@@ -15991,6 +16061,7 @@ window.__ModuleLoader__.load({
15991
16061
  * @param ctx - client root context (locale service).
15992
16062
  */
15993
16063
  function apply(ctx) {
16064
+ reportDailyHeartbeat([{ name: "@linxin666/dsh-ssh" }]);
15994
16065
  ctx.effect(() => {
15995
16066
  try {
15996
16067
  return ctx.locale.register(NS, {