dsh-pet-live2d 3.1.0 → 3.1.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # 更新日志
2
2
 
3
+ ## 3.1.1(2026-09-30)
4
+
5
+ ### 修:在某些桌面外壳里"宠物整个不出现"(`localStorage` 一访问就抛)
6
+
7
+ 有人反馈在 DeepSeek Harness 的**官方桌面端**里用不了(issue #1)。查下来最要命的一处是:
8
+ 客户端里有 20 多处**直接读写 `window.localStorage`**,而在**自定义协议 / opaque origin**
9
+ 的外壳里,**光是访问 `localStorage` 就会抛 `SecurityError`**(有些壳还会因为隐私设置直接
10
+ 禁用 storage)。它抛在组件的第一帧里 ⇒ **宠物和设置页一起白掉**,现象看起来就像"这个插件
11
+ 不支持我的桌面端"。
12
+
13
+ 现在所有读写都走一层带兜底的封装:
14
+
15
+ - 先试着取一次原生引用(**连这一步都在 `try` 里** —— `typeof window.localStorage` 本身也会抛);
16
+ - 拿不到、或读写中途抛(配额/隐私模式),就退回**内存实现**:本次会话内位置 / 大小 / 装扮
17
+ 照常工作,只是关掉窗口不留存。
18
+
19
+ 顺带确认了一条:前端**只走相对路径**(`/api/live2d-pet/*`),插件加载走官方机制
20
+ (`dsh.bundle` / `dsh.client` / `slots`)—— 所以换成 `http://127.0.0.1:<端口>` 之外的外壳
21
+ 地址也不该受影响。
22
+
23
+ ### 改:macOS(arm64)平台子包进入主包声明
24
+
25
+ `dsh-pet-live2d-desktop-darwin-arm64` 已在上一版发上 npm,这一版把主包的
26
+ `optionalDependencies` 补上它 —— mac 用户装插件时会自动带上桌面端(在这之前只能从
27
+ Release 下 zip)。
28
+
3
29
  ## 3.1.0(2026-09-29)
4
30
 
5
31
  这一轮的主线是**桌面端**:托盘的"没有她"查到底了 —— 根因是本项目自己给产物贴错了
package/lib/client.js CHANGED
@@ -31,6 +31,57 @@ window.__ModuleLoader__.load({ id: "dsh-pet-live2d", factory: (require) => {
31
31
 
32
32
  const API = "/api/live2d-pet";
33
33
  const STORAGE_KEY = "dsh-live2d-pet.state.v1";
34
+
35
+ // ---- 存储:`localStorage` 要裹起来用 ----
36
+ //
37
+ // 为什么不能直接 `window.localStorage.getItem(...)`:**有些桌面外壳里访问它就抛异常**
38
+ // (自定义协议 / opaque origin 下是 `SecurityError: The operation is insecure`,
39
+ // 有的壳还会因为隐私设置直接禁用 storage)。一抛就是**在组件第一帧里**,整个宠物
40
+ // 连带设置页一起白掉 —— 而这种外壳(官方 desktop / 各家 Tauri、Electron 打包版)
41
+ // 恰恰是本插件最常见的运行环境之一。
42
+ //
43
+ // 拿不到就退回内存实现:这一次会话内照样能存(位置、大小、装扮),只是关掉窗口不保留。
44
+ // 注意**不能**用 `typeof window.localStorage` 判断 —— 那个 getter 本身就会抛,
45
+ // 所以连"取一次引用"都要裹在 try 里。
46
+ const nativeStorage = (() => {
47
+ try {
48
+ return window.localStorage;
49
+ } catch {
50
+ return null;
51
+ }
52
+ })();
53
+ const memoryStorage = new Map();
54
+ const storage = {
55
+ getItem(key) {
56
+ if (nativeStorage !== null) {
57
+ try {
58
+ return nativeStorage.getItem(key);
59
+ } catch {
60
+ /* 读也抛(配额/隐私模式)⇒ 退回内存那份 */
61
+ }
62
+ }
63
+ return memoryStorage.has(key) ? memoryStorage.get(key) : null;
64
+ },
65
+ setItem(key, value) {
66
+ memoryStorage.set(key, String(value));
67
+ if (nativeStorage === null) return;
68
+ try {
69
+ nativeStorage.setItem(key, value);
70
+ } catch {
71
+ /* 写不进去也别抛:内存那份已经存了 */
72
+ }
73
+ },
74
+ removeItem(key) {
75
+ memoryStorage.delete(key);
76
+ if (nativeStorage === null) return;
77
+ try {
78
+ nativeStorage.removeItem(key);
79
+ } catch {
80
+ /* 同上 */
81
+ }
82
+ },
83
+ };
84
+
34
85
  const ROOT_ATTR = "data-dsh-live2d-pet-root";
35
86
  const PET_ATTR = "data-dsh-live2d-pet";
36
87
  const LEGACY_ATTR = "data-dsh-live2d-pet-container";
@@ -3010,7 +3061,7 @@ window.__ModuleLoader__.load({ id: "dsh-pet-live2d", factory: (require) => {
3010
3061
 
3011
3062
  function loadStored() {
3012
3063
  try {
3013
- const raw = window.localStorage.getItem(STORAGE_KEY);
3064
+ const raw = storage.getItem(STORAGE_KEY);
3014
3065
  if (raw === null) return {};
3015
3066
  const parsed = JSON.parse(raw);
3016
3067
  return typeof parsed === "object" && parsed !== null ? parsed : {};
@@ -3021,7 +3072,7 @@ window.__ModuleLoader__.load({ id: "dsh-pet-live2d", factory: (require) => {
3021
3072
 
3022
3073
  function saveStored(patch) {
3023
3074
  try {
3024
- window.localStorage.setItem(STORAGE_KEY, JSON.stringify(Object.assign(loadStored(), patch)));
3075
+ storage.setItem(STORAGE_KEY, JSON.stringify(Object.assign(loadStored(), patch)));
3025
3076
  } catch {
3026
3077
  /* storage is best-effort */
3027
3078
  }
@@ -3637,7 +3688,7 @@ window.__ModuleLoader__.load({ id: "dsh-pet-live2d", factory: (require) => {
3637
3688
 
3638
3689
  const readLocal = (key) => {
3639
3690
  try {
3640
- const raw = window.localStorage.getItem(key);
3691
+ const raw = storage.getItem(key);
3641
3692
  return raw === null ? null : JSON.parse(raw);
3642
3693
  } catch {
3643
3694
  return null;
@@ -3645,8 +3696,8 @@ window.__ModuleLoader__.load({ id: "dsh-pet-live2d", factory: (require) => {
3645
3696
  };
3646
3697
  const writeLocal = (key, value) => {
3647
3698
  try {
3648
- if (value === null || value === undefined) window.localStorage.removeItem(key);
3649
- else window.localStorage.setItem(key, JSON.stringify(value));
3699
+ if (value === null || value === undefined) storage.removeItem(key);
3700
+ else storage.setItem(key, JSON.stringify(value));
3650
3701
  } catch {
3651
3702
  /* 无痕模式之类:这次生效,下次不记得 */
3652
3703
  }
@@ -3912,7 +3963,7 @@ window.__ModuleLoader__.load({ id: "dsh-pet-live2d", factory: (require) => {
3912
3963
  FLAGS[key] = value === true;
3913
3964
  if (key === "outfitArchive" && FLAGS[key] === false) {
3914
3965
  try {
3915
- window.localStorage.removeItem(OUTFIT_KEY);
3966
+ storage.removeItem(OUTFIT_KEY);
3916
3967
  } catch {
3917
3968
  /* 无痕模式:本来也没存下 */
3918
3969
  }
@@ -3952,7 +4003,7 @@ window.__ModuleLoader__.load({ id: "dsh-pet-live2d", factory: (require) => {
3952
4003
  let saved = given === undefined ? null : given;
3953
4004
  if (saved === undefined || saved === null) {
3954
4005
  try {
3955
- saved = JSON.parse(window.localStorage.getItem(OVERRIDE_KEY) ?? "null");
4006
+ saved = JSON.parse(storage.getItem(OVERRIDE_KEY) ?? "null");
3956
4007
  } catch {
3957
4008
  saved = null;
3958
4009
  }
@@ -4304,7 +4355,7 @@ window.__ModuleLoader__.load({ id: "dsh-pet-live2d", factory: (require) => {
4304
4355
  let saved = given === undefined ? null : given;
4305
4356
  if (saved === undefined || saved === null) {
4306
4357
  try {
4307
- saved = JSON.parse(window.localStorage.getItem(TUNING_KEY) ?? "null");
4358
+ saved = JSON.parse(storage.getItem(TUNING_KEY) ?? "null");
4308
4359
  } catch {
4309
4360
  saved = null;
4310
4361
  }
@@ -5985,7 +6036,7 @@ window.__ModuleLoader__.load({ id: "dsh-pet-live2d", factory: (require) => {
5985
6036
  const readOutfit = () => {
5986
6037
  if (!FLAGS.outfitArchive) return null;
5987
6038
  try {
5988
- const parsed = JSON.parse(window.localStorage.getItem(OUTFIT_KEY) ?? "null");
6039
+ const parsed = JSON.parse(storage.getItem(OUTFIT_KEY) ?? "null");
5989
6040
  return parsed !== null && typeof parsed === "object" ? parsed : null;
5990
6041
  } catch {
5991
6042
  return null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-pet-live2d",
3
- "version": "3.1.0",
3
+ "version": "3.1.1",
4
4
  "description": "Live2D 桌宠插件:为 DSH Web GUI 挂一只可拖动、会跟随鼠标、能换动作与表情的 Live2D 宠物。",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -49,7 +49,8 @@
49
49
  }
50
50
  },
51
51
  "optionalDependencies": {
52
- "dsh-pet-live2d-desktop-win32-x64": "3.1.0"
52
+ "dsh-pet-live2d-desktop-darwin-arm64": "3.1.1",
53
+ "dsh-pet-live2d-desktop-win32-x64": "3.1.1"
53
54
  },
54
55
  "devDependencies": {
55
56
  "esbuild": "^0.25.10",