@nsnanocat/util 2.1.1 → 2.1.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.md CHANGED
@@ -64,7 +64,7 @@ import {
64
64
  time, // 时间格式化工具
65
65
  wait, // 延时等待工具(Promise)
66
66
  Console, // 统一日志工具(支持 logLevel)
67
- Lodash, // 内置的 Lodash 部分方法实现
67
+ Lodash as _, // Lodash 建议按官方示例惯例使用 `_` 作为工具对象别名
68
68
  Storage, // 统一持久化存储接口(适配 $prefs / $persistentStore / 文件)
69
69
  } from "@nsnanocat/util";
70
70
  ```
@@ -177,7 +177,7 @@ console.log(environment()); // 当前环境对象
177
177
  - 使用点路径展开对象(`a.b=1 -> { a: { b: "1" } }`)。
178
178
  - 当全局 `$argument` 为 `object` 时:
179
179
  - 将 key 当路径写回新对象(`{"a.b":"1"}` -> `{a:{b:"1"}}`)。
180
- - 当 `$argument` 为 `undefined`:不处理。
180
+ - 当 `$argument` 为 `null` 或 `undefined`:会归一化为 `{}`。
181
181
  - 若 `$argument.LogLevel` 存在:同步到 `Console.logLevel`。
182
182
 
183
183
  #### 用法
@@ -315,13 +315,15 @@ await runScript("$done({})", { timeout: 20 });
315
315
  - `database: object`(默认数据库)
316
316
  - 返回:`{ Settings, Configs, Caches }`
317
317
 
318
- 合并顺序:
319
- 1. `database.Default` -> 初始 `Store`
320
- 2. 持久化中的 BoxJS 值(`Storage.getItem(key)`)
321
- 3. `names` 合并 `database[name]` + `BoxJs[name]`
322
- 4. 最后合并 `$argument`
318
+ 合并顺序由 `$argument.Storage` 控制(持久化读取统一使用 `PersistentStore = Storage.getItem(key, {})`):
319
+ 1. 默认(`undefined`):`database[name]` -> `$argument` -> `PersistentStore[name]`
320
+ 2. `$argument`:`database[name]` -> `PersistentStore[name]` -> `$argument`
321
+ 3. `PersistentStore` / `BoxJs`:`database[name]` -> `PersistentStore[name]`
322
+ 4. `database`:仅 `database[name]`
323
323
 
324
- 自动类型转换(`Store.Settings`):
324
+ 注意:`Configs` 与 `Caches` 始终按每个 `name` 合并(与 `$argument.Storage` 无关)。
325
+
326
+ 自动类型转换(`Root.Settings`):
325
327
  - 字符串 `"true"/"false"` -> `boolean`
326
328
  - 纯数字字符串 -> `number`
327
329
  - 含逗号字符串 -> `array`,并尝试逐项转数字
@@ -408,7 +410,8 @@ const store = getStorage("@my_box", ["YouTube", "Global"], database);
408
410
 
409
411
  #### `Storage.removeItem(keyName)`
410
412
  - Quantumult X:可用(`$prefs.removeValueForKey`)。
411
- - Surge / Loon / Stash / Egern / Shadowrocket / Node.js:返回 `false`。
413
+ - Surge:通过 `$persistentStore.write(null, keyName)` 删除。
414
+ - Loon / Stash / Egern / Shadowrocket / Node.js:返回 `false`。
412
415
 
413
416
  #### `Storage.clear()`
414
417
  - Quantumult X:可用(`$prefs.removeAllValues`)。
@@ -420,7 +423,7 @@ const store = getStorage("@my_box", ["YouTube", "Global"], database);
420
423
 
421
424
  与 Web Storage 的行为差异:
422
425
  - 支持 `@key.path` 深路径读写(Web Storage 原生不支持)。
423
- - `removeItem/clear` 仅部分平台可用(目前主要是 Quantumult X)。
426
+ - `removeItem/clear` 仅部分平台可用(目前为 Quantumult X,以及 Surge 的 `removeItem`)。
424
427
  - `getItem` 会尝试 `JSON.parse`,`setItem` 写入对象会 `JSON.stringify`。
425
428
 
426
429
  平台后端映射:
@@ -499,6 +502,28 @@ console.log(Console.logLevel); // "WARN"
499
502
  - https://www.lodashjs.com
500
503
  - https://lodash.com
501
504
 
505
+ 导入约定(建议):
506
+ - 这是 lodash 官方示例中常见的惯例写法:使用 `_` 作为工具对象别名。
507
+
508
+ ```js
509
+ import { Lodash as _ } from "@nsnanocat/util";
510
+
511
+ const data = {};
512
+ _.set(data, "a.b", 1);
513
+ console.log(data); // { a: { b: 1 } }
514
+
515
+ const value = _.get(data, "a.b", 0);
516
+ console.log(value); // 1
517
+ ```
518
+
519
+ 示例对应的 lodash 官方文档页面:
520
+ - `set(object, path, value)`
521
+ - 官方文档:https://lodash.com/docs/#set
522
+ - 中文文档:https://www.lodashjs.com/docs/lodash.set
523
+ - `get(object, path, defaultValue)`
524
+ - 官方文档:https://lodash.com/docs/#get
525
+ - 中文文档:https://www.lodashjs.com/docs/lodash.get
526
+
502
527
  当前实现包含:
503
528
  - `escape(string)`
504
529
  - `unescape(string)`
@@ -510,6 +535,35 @@ console.log(Console.logLevel); // "WARN"
510
535
  - `omit(object, paths)`
511
536
  - `merge(object, ...sources)`
512
537
 
538
+ 对应 lodash 官方文档页面:
539
+ - `escape(string)`
540
+ - 官方文档:https://lodash.com/docs/#escape
541
+ - 中文文档:https://www.lodashjs.com/docs/lodash.escape
542
+ - `unescape(string)`
543
+ - 官方文档:https://lodash.com/docs/#unescape
544
+ - 中文文档:https://www.lodashjs.com/docs/lodash.unescape
545
+ - `toPath(value)`
546
+ - 官方文档:https://lodash.com/docs/#toPath
547
+ - 中文文档:https://www.lodashjs.com/docs/lodash.toPath
548
+ - `get(object, path, defaultValue)`
549
+ - 官方文档:https://lodash.com/docs/#get
550
+ - 中文文档:https://www.lodashjs.com/docs/lodash.get
551
+ - `set(object, path, value)`
552
+ - 官方文档:https://lodash.com/docs/#set
553
+ - 中文文档:https://www.lodashjs.com/docs/lodash.set
554
+ - `unset(object, path)`
555
+ - 官方文档:https://lodash.com/docs/#unset
556
+ - 中文文档:https://www.lodashjs.com/docs/lodash.unset
557
+ - `pick(object, paths)`
558
+ - 官方文档:https://lodash.com/docs/#pick
559
+ - 中文文档:https://www.lodashjs.com/docs/lodash.pick
560
+ - `omit(object, paths)`
561
+ - 官方文档:https://lodash.com/docs/#omit
562
+ - 中文文档:https://www.lodashjs.com/docs/lodash.omit
563
+ - `merge(object, ...sources)`
564
+ - 官方文档:https://lodash.com/docs/#merge
565
+ - 中文文档:https://www.lodashjs.com/docs/lodash.merge
566
+
513
567
  参数与返回值:
514
568
 
515
569
  | 方法 | 参数 | 返回值 | 说明 |
@@ -549,7 +603,7 @@ console.log(Console.logLevel); // "WARN"
549
603
  | 通知 | `$notify` | `$notification.post` | `$notification.post` | `$notification.post` | `$notification.post` | `$notification.post` | 无 |
550
604
  | 持久化 | `$prefs` | `$persistentStore` | `$persistentStore` | `$persistentStore` | `$persistentStore` | `$persistentStore` | `box.dat` |
551
605
  | 结束脚本 | `$done` | `$done` | `$done` | `$done` | `$done` | `$done` | `process.exit(1)` |
552
- | `removeItem/clear` | 可用 | 不可用 | 不可用 | 不可用 | 不可用 | 不可用 | 不可用 |
606
+ | `removeItem/clear` | 可用 | 不可用 | `removeItem` 可用 / `clear` 不可用 | 不可用 | 不可用 | 不可用 | 不可用 |
553
607
  | `policy` 注入(`fetch/done`) | `opts.policy` | `node` | `X-Surge-Policy`(done) | `X-Stash-Selected-Proxy` | 无专门映射 | `X-Surge-Proxy`(fetch) | 无 |
554
608
 
555
609
  ## 已知限制与注意事项
package/getStorage.mjs CHANGED
@@ -17,13 +17,17 @@ import { Storage } from "./polyfill/Storage.mjs";
17
17
  * 读取并合并默认配置、持久化配置与 `$argument`。
18
18
  * Read and merge default config, persisted config and `$argument`.
19
19
  *
20
- * 合并顺序:
21
- * Merge order:
22
- * 1) `database.Default`
23
- * 2) BoxJS persisted value
24
- * 3) `database[name]` + `BoxJs[name]`
25
- * 4) `$argument`
20
+ * 注意:`Configs` 与 `Caches` 始终按每个 profile(`names`)合并;`Settings` 的合并顺序由 `$argument.Storage` 控制。
21
+ * Note: `Configs` and `Caches` are always merged per-profile (`names`); the merge order for `Settings` is controlled by `$argument.Storage`.
26
22
  *
23
+ * 合并来源与顺序由 `$argument.Storage` 控制:
24
+ * Merge source order is controlled by `$argument.Storage`:
25
+ * - `undefined`(默认): `database[name]` -> `$argument` -> `PersistentStore[name]`
26
+ * - `$argument`: `database[name]` -> `PersistentStore[name]` -> `$argument`
27
+ * - `PersistentStore` / `BoxJs`: `database[name]` -> `PersistentStore[name]`
28
+ * - `database`: 仅 `database[name]`
29
+ *
30
+ * @since 2.1.2
27
31
  * @link https://github.com/NanoCat-Me/utils/blob/main/getStorage.mjs
28
32
  * @author VirgilClyne
29
33
  * @param {string} key 持久化主键 / Persistent store key.
@@ -36,36 +40,63 @@ export function getStorage(key, names, database) {
36
40
  Console.debug("☑️ getStorage");
37
41
  names = [names].flat(Number.POSITIVE_INFINITY);
38
42
  /***************** Default *****************/
39
- const Store = { Settings: database?.Default?.Settings || {}, Configs: database?.Default?.Configs || {}, Caches: {} };
40
- Console.debug("Default", `Store.Settings类型: ${typeof Store.Settings}`, `Store.Settings: ${JSON.stringify(Store.Settings)}`);
41
- /***************** BoxJs *****************/
43
+ const Root = { Settings: database?.Default?.Settings || {}, Configs: database?.Default?.Configs || {}, Caches: {} };
44
+ Console.debug("Default", `Root.Settings类型: ${typeof Root.Settings}`, `Root.Settings: ${JSON.stringify(Root.Settings)}`);
45
+ /***************** PersistentStore *****************/
42
46
  // 包装为局部变量,用完释放内存
43
- // BoxJs的清空操作返回假值空字符串, 逻辑或操作符会在左侧操作数为假值时返回右侧操作数。
44
- const BoxJs = Storage.getItem(key);
45
- if (BoxJs) {
46
- Console.debug("☑️ BoxJs", `BoxJs类型: ${typeof BoxJs}`, `BoxJs内容: ${JSON.stringify(BoxJs || {})}`);
47
+ // BoxJs 的清空操作返回假值空字符串, 逻辑或操作符会在左侧操作数为假值时返回右侧操作数。
48
+ const PersistentStore = Storage.getItem(key, {});
49
+ if (PersistentStore) {
50
+ Console.debug("☑️ PersistentStore", `PersistentStore类型: ${typeof PersistentStore}`, `PersistentStore内容: ${JSON.stringify(PersistentStore || {})}`);
47
51
  names.forEach(name => {
48
- if (typeof BoxJs?.[name]?.Settings === "string") {
49
- BoxJs[name].Settings = JSON.parse(BoxJs[name].Settings || "{}");
52
+ if (typeof PersistentStore?.[name]?.Settings === "string") {
53
+ PersistentStore[name].Settings = JSON.parse(PersistentStore[name].Settings || "{}");
50
54
  }
51
- if (typeof BoxJs?.[name]?.Caches === "string") {
52
- BoxJs[name].Caches = JSON.parse(BoxJs[name].Caches || "{}");
55
+ if (typeof PersistentStore?.[name]?.Caches === "string") {
56
+ PersistentStore[name].Caches = JSON.parse(PersistentStore[name].Caches || "{}");
53
57
  }
54
58
  });
55
- if (BoxJs.LogLevel) Console.logLevel = BoxJs.LogLevel;
56
- Console.debug("✅ BoxJs", `Store.Settings类型: ${typeof Store.Settings}`, `Store.Settings: ${JSON.stringify(Store.Settings)}`);
59
+ if (PersistentStore.LogLevel) Console.logLevel = PersistentStore.LogLevel;
60
+ Console.debug("✅ PersistentStore", `Root.Settings类型: ${typeof Root.Settings}`, `Root.Settings: ${JSON.stringify(Root.Settings)}`);
57
61
  }
58
62
  /***************** Merge *****************/
59
63
  names.forEach(name => {
60
- _.merge(Store.Settings, database?.[name]?.Settings, BoxJs?.[name]?.Settings);
61
- _.merge(Store.Configs, database?.[name]?.Configs);
62
- _.merge(Store.Caches, BoxJs?.[name]?.Caches);
64
+ _.merge(Root.Configs, database?.[name]?.Configs);
65
+ _.merge(Root.Caches, PersistentStore?.[name]?.Caches);
63
66
  });
64
- _.merge(Store.Settings, $argument);
65
- if (Store.Settings.LogLevel) Console.logLevel = Store.Settings.LogLevel;
66
- Console.debug("✅ Merge", `Store.Settings类型: ${typeof Store.Settings}`, `Store.Settings: ${JSON.stringify(Store.Settings)}`);
67
+ switch ($argument.Storage) {
68
+ case "$argument":
69
+ names.forEach(name => {
70
+ _.merge(Root.Settings, database?.[name]?.Settings, PersistentStore?.[name]?.Settings);
71
+ });
72
+ _.merge(Root.Settings, $argument);
73
+ break;
74
+ case "BoxJs":
75
+ case "PersistentStore":
76
+ names.forEach(name => {
77
+ _.merge(Root.Settings, database?.[name]?.Settings, PersistentStore?.[name]?.Settings);
78
+ });
79
+ break;
80
+ case "database":
81
+ names.forEach(name => {
82
+ _.merge(Root.Settings, database?.[name]?.Settings);
83
+ });
84
+ break;
85
+ default:
86
+ case undefined:
87
+ names.forEach(name => {
88
+ _.merge(Root.Settings, database?.[name]?.Settings);
89
+ });
90
+ _.merge(Root.Settings, $argument);
91
+ names.forEach(name => {
92
+ _.merge(Root.Settings, PersistentStore?.[name]?.Settings);
93
+ });
94
+ break;
95
+ }
96
+ if (Root.Settings.LogLevel) Console.logLevel = Root.Settings.LogLevel;
97
+ Console.debug("✅ Merge", `Root.Settings类型: ${typeof Root.Settings}`, `Root.Settings: ${JSON.stringify(Root.Settings)}`);
67
98
  /***************** traverseObject *****************/
68
- traverseObject(Store.Settings, (key, value) => {
99
+ traverseObject(Root.Settings, (key, value) => {
69
100
  Console.debug("☑️ traverseObject", `${key}: ${typeof value}`, `${key}: ${JSON.stringify(value)}`);
70
101
  if (value === "true" || value === "false")
71
102
  value = JSON.parse(value); // 字符串转Boolean
@@ -76,9 +107,9 @@ export function getStorage(key, names, database) {
76
107
  }
77
108
  return value;
78
109
  });
79
- Console.debug("✅ traverseObject", `Store.Settings类型: ${typeof Store.Settings}`, `Store.Settings: ${JSON.stringify(Store.Settings)}`);
110
+ Console.debug("✅ traverseObject", `Root.Settings类型: ${typeof Root.Settings}`, `Root.Settings: ${JSON.stringify(Root.Settings)}`);
80
111
  Console.debug("✅ getStorage");
81
- return Store;
112
+ return Root;
82
113
  }
83
114
 
84
115
  /**
package/lib/argument.mjs CHANGED
@@ -18,25 +18,37 @@ import { Lodash as _ } from "../polyfill/Lodash.mjs";
18
18
  * Execution timing:
19
19
  * - 该模块为即时执行模块,`import` 时立即处理全局 `$argument`
20
20
  * - This module executes immediately and mutates global `$argument` on import
21
+ *
22
+ * 归一化规则补充:
23
+ * Normalization details:
24
+ * - 使用 `globalThis.$argument` 读写,避免运行环境下未声明变量引用问题
25
+ * - Read/write via `globalThis.$argument` to avoid undeclared variable access
26
+ * - 当 `$argument` 为 `null` 或 `undefined` 时,会重置为 `{}`
27
+ * - When `$argument` is `null` or `undefined`, it is normalized to `{}`
21
28
  */
22
29
  (() => {
23
30
  Console.debug("☑️ $argument");
24
- switch (typeof $argument) {
31
+ switch (typeof globalThis.$argument) {
25
32
  case "string": {
26
- const argument = Object.fromEntries($argument.split("&").map(item => item.split("=", 2).map(i => i.replace(/\"/g, ""))));
27
- $argument = {};
28
- Object.keys(argument).forEach(key => _.set($argument, key, argument[key]));
33
+ const argument = Object.fromEntries(globalThis.$argument.split("&").map(item => item.split("=", 2).map(i => i.replace(/\"/g, ""))));
34
+ globalThis.$argument = {};
35
+ Object.keys(argument).forEach(key => _.set(globalThis.$argument, key, argument[key]));
29
36
  break;
30
37
  }
31
38
  case "object": {
39
+ if (globalThis.$argument === null) {
40
+ globalThis.$argument = {};
41
+ break;
42
+ }
32
43
  const argument = {};
33
- Object.keys($argument).forEach(key => _.set(argument, key, $argument[key]));
34
- $argument = argument;
44
+ Object.keys(globalThis.$argument).forEach(key => _.set(argument, key, globalThis.$argument[key]));
45
+ globalThis.$argument = argument;
35
46
  break;
36
47
  }
37
48
  case "undefined":
49
+ globalThis.$argument = {};
38
50
  break;
39
51
  }
40
- if ($argument.LogLevel) Console.logLevel = $argument.LogLevel;
41
- Console.debug("✅ $argument", `$argument: ${JSON.stringify($argument)}`);
52
+ if (globalThis.$argument.LogLevel) Console.logLevel = globalThis.$argument.LogLevel;
53
+ Console.debug("✅ $argument", `$argument: ${JSON.stringify(globalThis.$argument)}`);
42
54
  })();
package/package.json CHANGED
@@ -39,5 +39,5 @@
39
39
  "registry": "https://registry.npmjs.org/",
40
40
  "access": "public"
41
41
  },
42
- "version": "2.1.1"
42
+ "version": "2.1.3"
43
43
  }
@@ -9,6 +9,8 @@
9
9
  * - This is a simplified subset, not a full Lodash implementation
10
10
  * - 各方法语义可参考 Lodash 官方文档
11
11
  * - Method semantics can be referenced from official Lodash docs
12
+ * - 导入时建议使用 `Lodash as _`,遵循 lodash 官方示例惯例
13
+ * - Use `Lodash as _` when importing, following official lodash example convention
12
14
  *
13
15
  * 参考:
14
16
  * Reference:
@@ -22,6 +24,8 @@ export class Lodash {
22
24
  *
23
25
  * @param {string} string 输入文本 / Input text.
24
26
  * @returns {string}
27
+ * @see {@link https://lodash.com/docs/#escape lodash.escape}
28
+ * @see {@link https://www.lodashjs.com/docs/lodash.escape lodash.escape (中文)}
25
29
  */
26
30
  static escape(string) {
27
31
  const map = {
@@ -42,6 +46,8 @@ export class Lodash {
42
46
  * @param {string|string[]} [path=""] 路径 / Path.
43
47
  * @param {*} [defaultValue=undefined] 默认值 / Default value.
44
48
  * @returns {*}
49
+ * @see {@link https://lodash.com/docs/#get lodash.get}
50
+ * @see {@link https://www.lodashjs.com/docs/lodash.get lodash.get (中文)}
45
51
  */
46
52
  static get(object = {}, path = "", defaultValue = undefined) {
47
53
  // translate array case to dot case, then split with .
@@ -80,6 +86,8 @@ export class Lodash {
80
86
  * @param {...object} sources - Source objects.
81
87
  * @returns {object} 返回合并后的目标对象
82
88
  * @returns {object} Merged target object.
89
+ * @see {@link https://lodash.com/docs/#merge lodash.merge}
90
+ * @see {@link https://www.lodashjs.com/docs/lodash.merge lodash.merge (中文)}
83
91
  * @example
84
92
  * const target = { a: { b: 1 }, c: 2 };
85
93
  * const source = { a: { d: 3 }, e: 4 };
@@ -141,6 +149,8 @@ export class Lodash {
141
149
  * @param {*} value - Value to check.
142
150
  * @returns {boolean} 如果是普通对象返回 true
143
151
  * @returns {boolean} Returns true when value is a plain object.
152
+ * @see {@link https://lodash.com/docs/#isPlainObject lodash.isPlainObject}
153
+ * @see {@link https://www.lodashjs.com/docs/lodash.isPlainObject lodash.isPlainObject (中文)}
144
154
  */
145
155
  static #isPlainObject(value) {
146
156
  if (value === null || typeof value !== "object") return false;
@@ -155,6 +165,8 @@ export class Lodash {
155
165
  * @param {object} [object={}] 目标对象 / Target object.
156
166
  * @param {string|string[]} [paths=[]] 要删除的路径 / Paths to remove.
157
167
  * @returns {object}
168
+ * @see {@link https://lodash.com/docs/#omit lodash.omit}
169
+ * @see {@link https://www.lodashjs.com/docs/lodash.omit lodash.omit (中文)}
158
170
  */
159
171
  static omit(object = {}, paths = []) {
160
172
  if (!Array.isArray(paths)) paths = [paths.toString()];
@@ -169,6 +181,8 @@ export class Lodash {
169
181
  * @param {object} [object={}] 目标对象 / Target object.
170
182
  * @param {string|string[]} [paths=[]] 需要保留的键 / Keys to keep.
171
183
  * @returns {object}
184
+ * @see {@link https://lodash.com/docs/#pick lodash.pick}
185
+ * @see {@link https://www.lodashjs.com/docs/lodash.pick lodash.pick (中文)}
172
186
  */
173
187
  static pick(object = {}, paths = []) {
174
188
  if (!Array.isArray(paths)) paths = [paths.toString()];
@@ -184,6 +198,8 @@ export class Lodash {
184
198
  * @param {string|string[]} path 路径 / Path.
185
199
  * @param {*} value 写入值 / Value.
186
200
  * @returns {object}
201
+ * @see {@link https://lodash.com/docs/#set lodash.set}
202
+ * @see {@link https://www.lodashjs.com/docs/lodash.set lodash.set (中文)}
187
203
  */
188
204
  static set(object, path, value) {
189
205
  if (!Array.isArray(path)) path = Lodash.toPath(path);
@@ -197,6 +213,8 @@ export class Lodash {
197
213
  *
198
214
  * @param {string} value 路径字符串 / Path string.
199
215
  * @returns {string[]}
216
+ * @see {@link https://lodash.com/docs/#toPath lodash.toPath}
217
+ * @see {@link https://www.lodashjs.com/docs/lodash.toPath lodash.toPath (中文)}
200
218
  */
201
219
  static toPath(value) {
202
220
  return value
@@ -211,6 +229,8 @@ export class Lodash {
211
229
  *
212
230
  * @param {string} string 输入文本 / Input text.
213
231
  * @returns {string}
232
+ * @see {@link https://lodash.com/docs/#unescape lodash.unescape}
233
+ * @see {@link https://www.lodashjs.com/docs/lodash.unescape lodash.unescape (中文)}
214
234
  */
215
235
  static unescape(string) {
216
236
  const map = {
@@ -230,6 +250,8 @@ export class Lodash {
230
250
  * @param {object} [object={}] 目标对象 / Target object.
231
251
  * @param {string|string[]} [path=""] 路径 / Path.
232
252
  * @returns {boolean}
253
+ * @see {@link https://lodash.com/docs/#unset lodash.unset}
254
+ * @see {@link https://www.lodashjs.com/docs/lodash.unset lodash.unset (中文)}
233
255
  */
234
256
  static unset(object = {}, path = "") {
235
257
  if (!Array.isArray(path)) path = Lodash.toPath(path);
@@ -172,6 +172,12 @@ export class Storage {
172
172
  * 删除存储值。
173
173
  * Remove value from persistent storage.
174
174
  *
175
+ * 平台说明:
176
+ * Platform notes:
177
+ * - Quantumult X: `$prefs.removeValueForKey`
178
+ * - Surge: 通过 `$persistentStore.write(null, keyName)` 删除
179
+ * - 其余平台当前返回 `false`
180
+ *
175
181
  * @param {string} keyName 键名或路径键 / Key or path key.
176
182
  * @returns {boolean}
177
183
  */
@@ -190,6 +196,8 @@ export class Storage {
190
196
  default:
191
197
  switch ($app) {
192
198
  case "Surge":
199
+ result = $persistentStore.write(null, keyName);
200
+ break;
193
201
  case "Loon":
194
202
  case "Stash":
195
203
  case "Egern":