@nsnanocat/util 2.2.3 → 2.3.0
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 +77 -26
- package/index.js +1 -0
- package/lib/app.mjs +8 -4
- package/lib/done.mjs +5 -0
- package/lib/environment.mjs +6 -0
- package/lib/notification.mjs +5 -0
- package/package.json +1 -1
- package/polyfill/Console.mjs +4 -3
- package/polyfill/KV.mjs +240 -0
- package/polyfill/Storage.mjs +24 -4
- package/polyfill/fetch.mjs +15 -11
- package/polyfill/index.js +1 -0
- package/types/modules/core.d.ts +54 -0
- package/types/modules/environment.d.ts +4 -0
- package/types/modules/fetch.d.ts +29 -0
- package/types/modules/getStorage.d.ts +22 -0
- package/types/modules/kv.d.ts +35 -0
- package/types/modules/polyfills.d.ts +34 -0
- package/types/modules/storage.d.ts +10 -0
- package/types/nsnanocat-util.d.ts +7 -151
package/README.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# @nsnanocat/util
|
|
2
2
|
|
|
3
|
-
用于统一 Quantumult X / Loon / Shadowrocket / Node.js / Egern / Surge / Stash 脚本接口的通用工具库。
|
|
3
|
+
用于统一 Quantumult X / Loon / Shadowrocket / Worker / Node.js / Egern / Surge / Stash 脚本接口的通用工具库。
|
|
4
4
|
|
|
5
5
|
核心目标:
|
|
6
6
|
- 统一不同平台的 HTTP、通知、持久化、结束脚本等调用方式。
|
|
7
7
|
- 在一个脚本里尽量少写平台分支。
|
|
8
|
-
- 提供一组可直接复用的 polyfill(`fetch` / `Storage` / `Console` / `Lodash`)。
|
|
8
|
+
- 提供一组可直接复用的 polyfill(`fetch` / `Storage` / `KV` / `Console` / `Lodash`)。
|
|
9
9
|
|
|
10
10
|
## 目录
|
|
11
11
|
- [安装与导入](#安装与导入)
|
|
@@ -56,16 +56,17 @@ npm i @nsnanocat/util@latest
|
|
|
56
56
|
|
|
57
57
|
```js
|
|
58
58
|
import {
|
|
59
|
-
$app, // 当前平台名(如 "Surge" / "Loon" / "Quantumult X" / "Node.js")
|
|
59
|
+
$app, // 当前平台名(如 "Surge" / "Loon" / "Quantumult X" / "Worker" / "Node.js")
|
|
60
60
|
$argument, // 已标准化的模块参数对象(导入包时自动处理字符串 -> 对象)
|
|
61
61
|
done, // 统一结束脚本函数(内部自动适配各平台 $done 差异)
|
|
62
|
-
fetch, // 统一 HTTP 请求函数(内部自动适配 $httpClient / $task /
|
|
62
|
+
fetch, // 统一 HTTP 请求函数(内部自动适配 $httpClient / $task / fetch)
|
|
63
63
|
notification, // 统一通知函数(内部自动适配 $notify / $notification.post)
|
|
64
64
|
time, // 时间格式化工具
|
|
65
65
|
wait, // 延时等待工具(Promise)
|
|
66
66
|
Console, // 统一日志工具(支持 logLevel)
|
|
67
67
|
Lodash as _, // Lodash 建议按官方示例惯例使用 `_` 作为工具对象别名
|
|
68
|
-
|
|
68
|
+
KV, // Cloudflare Workers KV 异步适配器(显式传入 namespace binding)
|
|
69
|
+
Storage, // 统一持久化存储接口(适配 $prefs / $persistentStore / 内存 / 文件)
|
|
69
70
|
} from "@nsnanocat/util";
|
|
70
71
|
```
|
|
71
72
|
|
|
@@ -80,6 +81,7 @@ import {
|
|
|
80
81
|
- `lib/wait.mjs`
|
|
81
82
|
- `polyfill/Console.mjs`
|
|
82
83
|
- `polyfill/fetch.mjs`
|
|
84
|
+
- `polyfill/KV.mjs`
|
|
83
85
|
- `polyfill/Lodash.mjs`
|
|
84
86
|
- `polyfill/StatusTexts.mjs`
|
|
85
87
|
- `polyfill/Storage.mjs`
|
|
@@ -104,8 +106,9 @@ import {
|
|
|
104
106
|
| `lib/notification.mjs` | `lib/app.mjs`, `polyfill/Console.mjs` | `$app`, `Console.group`, `Console.log`, `Console.groupEnd`, `Console.error` | 将通知参数映射到各平台通知接口并统一日志输出 |
|
|
105
107
|
| `lib/runScript.mjs` | `polyfill/Console.mjs`, `polyfill/fetch.mjs`, `polyfill/Storage.mjs`, `polyfill/Lodash.mjs` | `Console.error`, `fetch`, `Storage.getItem`(`Lodash` 当前版本未实际调用) | 读取 BoxJS 配置并发起统一 HTTP 调用执行脚本 |
|
|
106
108
|
| `getStorage.mjs` | `lib/argument.mjs`, `polyfill/Console.mjs`, `polyfill/Lodash.mjs`, `polyfill/Storage.mjs` | `Console.debug`, `Console.logLevel`, `Lodash.merge`, `Storage.getItem` | 先标准化 `$argument`,再合并默认配置/持久化配置/运行参数 |
|
|
107
|
-
| `polyfill/Console.mjs` | `lib/app.mjs` | `$app` | 日志在 Node.js 与 iOS 脚本环境使用不同错误输出策略 |
|
|
109
|
+
| `polyfill/Console.mjs` | `lib/app.mjs` | `$app` | 日志在 Worker / Node.js 与 iOS 脚本环境使用不同错误输出策略 |
|
|
108
110
|
| `polyfill/fetch.mjs` | `lib/app.mjs`, `polyfill/Lodash.mjs`, `polyfill/StatusTexts.mjs`, `polyfill/Console.mjs` | `$app`, `Lodash.set`, `StatusTexts`(`Console` 当前版本未实际调用) | 按平台选请求引擎并做参数映射、响应结构统一 |
|
|
111
|
+
| `polyfill/KV.mjs` | `lib/app.mjs`, `polyfill/Lodash.mjs`, `polyfill/Storage.mjs` | `$app`, `Lodash.get`, `Lodash.set`, `Lodash.unset`, `Storage` | 为 Cloudflare Workers KV 提供异步适配,并在非 Worker 平台回退到 `Storage` |
|
|
109
112
|
| `polyfill/Storage.mjs` | `lib/app.mjs`, `polyfill/Lodash.mjs` | `$app`, `Lodash.get`, `Lodash.set`, `Lodash.unset` | 按平台选持久化后端并支持 `@key.path` 读写 |
|
|
110
113
|
| `polyfill/Lodash.mjs` | 无 | 无 | 提供路径/合并等基础能力,被多个模块复用 |
|
|
111
114
|
| `polyfill/StatusTexts.mjs` | 无 | 无 | 提供 HTTP 状态文案,供 `fetch/done` 使用 |
|
|
@@ -116,7 +119,7 @@ import {
|
|
|
116
119
|
### `lib/app.mjs` 与 `lib/environment.mjs`(平台识别与环境)
|
|
117
120
|
|
|
118
121
|
#### `$app`
|
|
119
|
-
- 类型:`"Quantumult X" | "Loon" | "Shadowrocket" | "Egern" | "Surge" | "Stash" | "Node.js" | undefined`
|
|
122
|
+
- 类型:`"Quantumult X" | "Loon" | "Shadowrocket" | "Egern" | "Surge" | "Stash" | "Worker" | "Node.js" | undefined`
|
|
120
123
|
- 角色:核心模块。库内所有存在平台行为差异的模块都会先读取 `$app` 再分流(如 `done`、`notification`、`fetch`、`Storage`、`Console`、`environment`)。
|
|
121
124
|
- 读取方式:
|
|
122
125
|
|
|
@@ -133,9 +136,10 @@ console.log(appName);
|
|
|
133
136
|
4. 存在 `Egern` -> `Egern`
|
|
134
137
|
5. 存在 `$environment` 且有 `surge-version` -> `Surge`
|
|
135
138
|
6. 存在 `$environment` 且有 `stash-version` -> `Stash`
|
|
136
|
-
7. 存在 `
|
|
137
|
-
8.
|
|
138
|
-
|
|
139
|
+
7. 存在 `Cloudflare` -> `Worker`
|
|
140
|
+
8. 存在 `process.versions.node` -> `Node.js`
|
|
141
|
+
9. 默认回落 -> `undefined`
|
|
142
|
+
- 实现细节:内部使用 `'key' in globalThis` 检测平台标记,避免 `Object.keys(globalThis)` 漏掉不可枚举全局变量;当前 Worker 识别以 `Cloudflare` 全局标记为准。
|
|
139
143
|
|
|
140
144
|
#### `$environment` / `environment()`
|
|
141
145
|
- 路径:`lib/environment.mjs`(未从包主入口导出)
|
|
@@ -157,6 +161,7 @@ console.log(environment()); // 当前环境对象
|
|
|
157
161
|
| Egern | 读取全局 `$environment`,再写入 `app` | `{ ..., app: "Egern" }` |
|
|
158
162
|
| Loon | 读取全局 `$loon` 字符串并拆分 | `{ device, ios, "loon-version", app: "Loon" }` |
|
|
159
163
|
| Quantumult X | 不读取额外环境字段,直接构造对象 | `{ app: "Quantumult X" }` |
|
|
164
|
+
| Worker | 直接构造对象 | `{ app: "Worker" }` |
|
|
160
165
|
| Node.js | 读取 `process.env` 并写入 `process.env.app` | `{ ..., app: "Node.js" }` |
|
|
161
166
|
| 其他 | 无 | `{}` |
|
|
162
167
|
|
|
@@ -194,7 +199,7 @@ console.log($argument); // { mode: "on", a: { b: "1" } }
|
|
|
194
199
|
|
|
195
200
|
#### `done(object = {})`
|
|
196
201
|
- 签名:`done(object?: object): void`
|
|
197
|
-
- 作用:统一不同平台的脚本结束接口(`$done` / Node 退出)。
|
|
202
|
+
- 作用:统一不同平台的脚本结束接口(`$done` / Worker 日志结束 / Node 退出)。
|
|
198
203
|
|
|
199
204
|
说明:下表描述的是各 App 原生接口差异与本库内部映射逻辑。调用方只需要按 `done` 的统一参数传值即可,不需要自己再写平台分支。
|
|
200
205
|
|
|
@@ -216,12 +221,14 @@ console.log($argument); // { mode: "on", a: { b: "1" } }
|
|
|
216
221
|
| Egern | 不转换 | 透传 | 透传 | `$done(object)` |
|
|
217
222
|
| Shadowrocket | 不转换 | 透传 | 透传 | `$done(object)` |
|
|
218
223
|
| Quantumult X | 写入 `opts.policy` | `number` 会转 `HTTP/1.1 200 OK` 字符串 | 仅保留 `status/url/headers/body/bodyBytes`;`ArrayBuffer/TypedArray` 转 `bodyBytes` | `$done(object)` |
|
|
224
|
+
| Worker | 不适用 | 不适用 | 不适用 | 仅记录结束日志 |
|
|
219
225
|
| Node.js | 不适用 | 不适用 | 不适用 | `process.exit(1)` |
|
|
220
226
|
|
|
221
227
|
不可用/差异点:
|
|
222
228
|
- `policy` 在 Egern / Shadowrocket 分支不做映射。
|
|
223
229
|
- Quantumult X 会丢弃未在白名单内的字段。
|
|
224
230
|
- Quantumult X 的 `status` 在部分场景要求完整状态行(如 `HTTP/1.1 200 OK`),本库会在传入数字状态码时自动拼接(依赖 `StatusTexts`)。
|
|
231
|
+
- Worker 不调用 `$done`,仅记录结束日志。
|
|
225
232
|
- Node.js 不调用 `$done`,而是直接退出进程,且退出码固定为 `1`。
|
|
226
233
|
- 未识别平台(`$app === undefined`)只记录结束日志,不会尝试调用 `$done` 或退出进程。
|
|
227
234
|
|
|
@@ -252,11 +259,13 @@ console.log($argument); // { mode: "on", a: { b: "1" } }
|
|
|
252
259
|
| Shadowrocket | `$notification.post` | `{ openUrl: content }` | 走 Surge 分支的 action/url/text/media 字段 |
|
|
253
260
|
| Loon | `$notification.post` | `{ openUrl: content }` | `openUrl`、`mediaUrl`(仅 http/https) |
|
|
254
261
|
| Quantumult X | `$notify` | `{ "open-url": content }` | `open-url`、`media-url`(仅 http/https)、`update-pasteboard` |
|
|
262
|
+
| Worker | 不发送通知(非 iOS App 环境) | 无 | 无 |
|
|
255
263
|
| Node.js | 不发送通知(非 iOS App 环境) | 无 | 无 |
|
|
256
264
|
|
|
257
265
|
不可用/差异点:
|
|
258
266
|
- `copy/update-pasteboard` 在 Loon 分支不会生效。
|
|
259
267
|
- Loon / Quantumult X 对 `media` 仅接受网络 URL;Base64 媒体不会自动映射。
|
|
268
|
+
- Worker 不是 iOS App 脚本环境,不支持 iOS 通知行为;当前分支仅日志输出。
|
|
260
269
|
- Node.js 不是 iOS App 脚本环境,不支持 iOS 通知行为;当前分支仅日志输出。
|
|
261
270
|
|
|
262
271
|
### `lib/time.mjs`
|
|
@@ -384,7 +393,7 @@ const store = getStorage("@my_box", ["YouTube", "Global"], database);
|
|
|
384
393
|
- `timeout`
|
|
385
394
|
- `policy`
|
|
386
395
|
- `redirection` / `auto-redirect`
|
|
387
|
-
- `auto-cookie
|
|
396
|
+
- `auto-cookie`(Worker / Node.js 共享分支识别;默认启用,传入 `false` / `0` / `-1` 可关闭)
|
|
388
397
|
|
|
389
398
|
说明:下表是各 App 原生 HTTP 接口的差异补充,以及本库 `fetch` 的内部映射方式。调用方使用统一入参即可。
|
|
390
399
|
|
|
@@ -398,6 +407,7 @@ const store = getStorage("@my_box", ["YouTube", "Global"], database);
|
|
|
398
407
|
| Egern | `$httpClient[method]` | 秒 | 无专门映射 | `auto-redirect` | 同上 |
|
|
399
408
|
| Shadowrocket | `$httpClient[method]` | 秒 | `headers.X-Surge-Proxy` | `auto-redirect` | 同上 |
|
|
400
409
|
| Quantumult X | `$task.fetch` | 毫秒(内部乘 1000) | `opts.policy` | `opts.redirection` | `body(ArrayBuffer/TypedArray)` 转 `bodyBytes`;响应按 `Content-Type` 恢复到 `body` |
|
|
410
|
+
| Worker | `globalThis.fetch`(不存在时回退 `node-fetch`);共享 `auto-cookie` 处理 | 毫秒(内部乘 1000) | 无 | `redirect: follow/manual` | 返回 `body`(UTF-8 string) + `bodyBytes`(ArrayBuffer) |
|
|
401
411
|
| Node.js | `globalThis.fetch`(不存在时回退 `node-fetch`);默认按需包裹 `fetch-cookie` | 毫秒(内部乘 1000) | 无 | `redirect: follow/manual` | 返回 `body`(UTF-8 string) + `bodyBytes`(ArrayBuffer) |
|
|
402
412
|
|
|
403
413
|
返回对象(统一后)常见字段:
|
|
@@ -410,9 +420,9 @@ const store = getStorage("@my_box", ["YouTube", "Global"], database);
|
|
|
410
420
|
- `bodyBytes`
|
|
411
421
|
|
|
412
422
|
不可用/差异点:
|
|
413
|
-
- `policy` 在 Surge / Egern / Node.js 分支没有额外适配逻辑。
|
|
423
|
+
- `policy` 在 Surge / Egern / Worker / Node.js 分支没有额外适配逻辑。
|
|
414
424
|
- `redirection` 在部分平台会映射为 `auto-redirect` 或 `opts.redirection`。
|
|
415
|
-
- Node.js
|
|
425
|
+
- Worker / Node.js 共享基于 `fetch` 的请求分支;若 `globalThis.fetch` 不存在则回退到 `node-fetch`,并在 `auto-cookie` 未关闭时按需包裹 `fetch-cookie`。
|
|
416
426
|
- 传入 `timeout` 时,`5` 和 `5000` 都会被接受;库会先将用户输入归一化,再按平台要求转换为秒或毫秒。
|
|
417
427
|
- 返回结构是统一兼容结构,不等同于浏览器 `Response` 对象。
|
|
418
428
|
|
|
@@ -435,21 +445,24 @@ const store = getStorage("@my_box", ["YouTube", "Global"], database);
|
|
|
435
445
|
#### `Storage.removeItem(keyName)`
|
|
436
446
|
- Quantumult X:可用(`$prefs.removeValueForKey`)。
|
|
437
447
|
- Surge:通过 `$persistentStore.write(null, keyName)` 删除。
|
|
448
|
+
- Worker:可用(仅删除内存缓存中的对应 key,不持久化)。
|
|
438
449
|
- Node.js:可用(删除 `box.dat` 中对应 key 并落盘)。
|
|
439
450
|
- Loon / Stash / Egern / Shadowrocket:返回 `false`。
|
|
440
451
|
|
|
441
452
|
#### `Storage.clear()`
|
|
442
453
|
- Quantumult X:可用(`$prefs.removeAllValues`)。
|
|
454
|
+
- Worker:可用(仅清空内存缓存,不持久化)。
|
|
443
455
|
- Node.js:可用(清空 `box.dat` 并落盘)。
|
|
444
456
|
- 其他平台:返回 `false`。
|
|
445
457
|
|
|
446
|
-
#### Node.js 特性
|
|
458
|
+
#### Worker / Node.js 特性
|
|
459
|
+
- Worker:使用进程内内存缓存,不写文件。
|
|
447
460
|
- 数据文件默认:`box.dat`。
|
|
448
461
|
- 读取路径优先级:当前目录 -> `process.cwd()`。
|
|
449
462
|
|
|
450
463
|
与 Web Storage 的行为差异:
|
|
451
464
|
- 支持 `@key.path` 深路径读写(Web Storage 原生不支持)。
|
|
452
|
-
- `removeItem/clear` 仅部分平台可用(目前为 Quantumult X、Node.js,以及 Surge 的 `removeItem`)。
|
|
465
|
+
- `removeItem/clear` 仅部分平台可用(目前为 Quantumult X、Worker、Node.js,以及 Surge 的 `removeItem`)。
|
|
453
466
|
- `getItem` 会尝试 `JSON.parse`,`setItem` 写入对象会 `JSON.stringify`。
|
|
454
467
|
|
|
455
468
|
平台后端映射:
|
|
@@ -458,8 +471,42 @@ const store = getStorage("@my_box", ["YouTube", "Global"], database);
|
|
|
458
471
|
| --- | --- |
|
|
459
472
|
| Surge / Loon / Stash / Egern / Shadowrocket | `$persistentStore.read/write` |
|
|
460
473
|
| Quantumult X | `$prefs.valueForKey/setValueForKey` |
|
|
474
|
+
| Worker | 进程内内存缓存 |
|
|
461
475
|
| Node.js | 本地 `box.dat` |
|
|
462
476
|
|
|
477
|
+
### `polyfill/KV.mjs`
|
|
478
|
+
|
|
479
|
+
`KV` 是面向 Cloudflare Workers KV 的异步适配器:
|
|
480
|
+
- 调用方显式传入 namespace binding:`new KV(env.NAMESPACE)`
|
|
481
|
+
- Worker 分支直接调用 `namespace.get/put/delete/list`
|
|
482
|
+
- `get()` 不传 `type`,默认按 Cloudflare 行为读取字符串
|
|
483
|
+
- 非 Worker 平台会回退到 `Storage.getItem/setItem/removeItem`
|
|
484
|
+
- `list()` 仅支持 Worker,返回 Cloudflare KV 原生列举结果
|
|
485
|
+
- `clear()` 始终返回 `false`
|
|
486
|
+
|
|
487
|
+
#### `new KV(namespace)`
|
|
488
|
+
- `namespace` 需提供 `get(key)` / `put(key, value)` / `delete(key)`。
|
|
489
|
+
|
|
490
|
+
#### `await kv.getItem(keyName, defaultValue = null)`
|
|
491
|
+
- 支持普通 key。
|
|
492
|
+
- 支持路径 key:`@root.path.to.key`。
|
|
493
|
+
- 读取后会尝试 `JSON.parse`。
|
|
494
|
+
|
|
495
|
+
#### `await kv.setItem(keyName, keyValue)`
|
|
496
|
+
- 支持普通 key 与路径 key。
|
|
497
|
+
- `keyValue` 为对象时自动 `JSON.stringify`。
|
|
498
|
+
|
|
499
|
+
#### `await kv.removeItem(keyName)`
|
|
500
|
+
- 支持普通 key 与路径 key。
|
|
501
|
+
|
|
502
|
+
#### `await kv.list(options = {})`
|
|
503
|
+
- 仅支持 Worker。
|
|
504
|
+
- 透传 `prefix` / `limit` / `cursor` 到 `namespace.list(options)`。
|
|
505
|
+
- 返回 Cloudflare KV 的原生结果:`keys` / `list_complete` / `cursor`。
|
|
506
|
+
|
|
507
|
+
#### `await kv.clear()`
|
|
508
|
+
- 始终返回 `false`。
|
|
509
|
+
|
|
463
510
|
### `polyfill/Console.mjs`
|
|
464
511
|
|
|
465
512
|
`Console` 是统一日志工具(静态类)。
|
|
@@ -507,7 +554,7 @@ console.log(Console.logLevel); // "WARN"
|
|
|
507
554
|
| `count(label)` | `label?: string` | `void` | 计数并输出 |
|
|
508
555
|
| `countReset(label)` | `label?: string` | `void` | 重置计数器 |
|
|
509
556
|
| `debug(...msg)` | `...msg: any[]` | `void` | 仅 `DEBUG/ALL` 级别输出 |
|
|
510
|
-
| `error(...msg)` | `...msg: any[]` | `void` | Node.js 优先输出 `stack` |
|
|
557
|
+
| `error(...msg)` | `...msg: any[]` | `void` | Worker / Node.js 优先输出 `stack` |
|
|
511
558
|
| `exception(...msg)` | `...msg: any[]` | `void` | `error` 别名 |
|
|
512
559
|
| `group(label)` | `label: string` | `void` | 压栈分组 |
|
|
513
560
|
| `groupEnd()` | 无 | `void` | 出栈分组 |
|
|
@@ -519,7 +566,7 @@ console.log(Console.logLevel); // "WARN"
|
|
|
519
566
|
| `warn(...msg)` | `...msg: any[]` | `void` | `WARN` 及以上 |
|
|
520
567
|
|
|
521
568
|
平台差异:
|
|
522
|
-
- Node.js 下 `error` 会优先打印 `Error.stack`。
|
|
569
|
+
- Worker / Node.js 下 `error` 会优先打印 `Error.stack`。
|
|
523
570
|
- 其他平台统一加前缀符号输出(`❌/⚠️/ℹ️/🅱️`)。
|
|
524
571
|
|
|
525
572
|
### `polyfill/Lodash.mjs`
|
|
@@ -623,18 +670,19 @@ console.log(value); // 1
|
|
|
623
670
|
|
|
624
671
|
说明:本节展示的是各平台原生脚本接口差异。实际在本库中,这些差异已由 `done`、`fetch`、`notification`、`Storage` 等模块做了统一适配。
|
|
625
672
|
|
|
626
|
-
| 能力 | Quantumult X | Loon | Surge | Stash | Egern | Shadowrocket | Node.js |
|
|
627
|
-
| --- | --- | --- | --- | --- | --- | --- | --- |
|
|
628
|
-
| HTTP 请求 | `$task.fetch` | `$httpClient` | `$httpClient` | `$httpClient` | `$httpClient` | `$httpClient` | `fetch` |
|
|
629
|
-
| 通知 | `$notify` | `$notification.post` | `$notification.post` | `$notification.post` | `$notification.post` | `$notification.post` | 无 |
|
|
630
|
-
| 持久化 | `$prefs` | `$persistentStore` | `$persistentStore` | `$persistentStore` | `$persistentStore` | `$persistentStore` | `box.dat` |
|
|
631
|
-
| 结束脚本 | `$done` | `$done` | `$done` | `$done` | `$done` | `$done` | `process.exit(1)` |
|
|
632
|
-
| `removeItem/clear` | 可用 | 不可用 | `removeItem` 可用 / `clear` 不可用 | 不可用 | 不可用 | 不可用 | 可用 |
|
|
633
|
-
| `policy` 注入(`fetch/done`) | `opts.policy` | `node` | `X-Surge-Policy`(done) | `X-Stash-Selected-Proxy` | 无专门映射 | `X-Surge-Proxy`(fetch) | 无 |
|
|
673
|
+
| 能力 | Quantumult X | Loon | Surge | Stash | Egern | Shadowrocket | Worker | Node.js |
|
|
674
|
+
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
|
675
|
+
| HTTP 请求 | `$task.fetch` | `$httpClient` | `$httpClient` | `$httpClient` | `$httpClient` | `$httpClient` | `fetch` | `fetch` |
|
|
676
|
+
| 通知 | `$notify` | `$notification.post` | `$notification.post` | `$notification.post` | `$notification.post` | `$notification.post` | 无 | 无 |
|
|
677
|
+
| 持久化 | `$prefs` | `$persistentStore` | `$persistentStore` | `$persistentStore` | `$persistentStore` | `$persistentStore` | 内存缓存 | `box.dat` |
|
|
678
|
+
| 结束脚本 | `$done` | `$done` | `$done` | `$done` | `$done` | `$done` | 仅日志 | `process.exit(1)` |
|
|
679
|
+
| `removeItem/clear` | 可用 | 不可用 | `removeItem` 可用 / `clear` 不可用 | 不可用 | 不可用 | 不可用 | 可用 | 可用 |
|
|
680
|
+
| `policy` 注入(`fetch/done`) | `opts.policy` | `node` | `X-Surge-Policy`(done) | `X-Stash-Selected-Proxy` | 无专门映射 | `X-Surge-Proxy`(fetch) | 无 | 无 |
|
|
634
681
|
|
|
635
682
|
## 已知限制与注意事项
|
|
636
683
|
|
|
637
684
|
- `lib/argument.mjs` 为 `$argument` 标准化模块,`import` 时会按规则重写全局 `$argument`。
|
|
685
|
+
- `lib/done.mjs` 在 Worker 仅记录结束日志。
|
|
638
686
|
- `lib/done.mjs` 在 Node.js 固定 `process.exit(1)`。
|
|
639
687
|
- `Storage.removeItem("@a.b")` 分支存在未声明变量写入风险;如要大量使用路径删除,建议先本地验证。
|
|
640
688
|
- `lib/runScript.mjs` 未从包主入口导出,需要按文件路径直接导入。
|
|
@@ -662,6 +710,9 @@ console.log(value); // 1
|
|
|
662
710
|
- [crossutility/Quantumult-X - sample-fetch-opts-policy.js](https://raw.githubusercontent.com/crossutility/Quantumult-X/master/sample-fetch-opts-policy.js)
|
|
663
711
|
- [crossutility/Quantumult-X - sample-rewrite-response-header.js](https://github.com/crossutility/Quantumult-X/raw/refs/heads/master/sample-rewrite-response-header.js)
|
|
664
712
|
|
|
713
|
+
### Worker
|
|
714
|
+
- 以 `Cloudflare` 全局标记识别 Worker 运行时。
|
|
715
|
+
|
|
665
716
|
### Node.js
|
|
666
717
|
- [Node.js Globals - fetch](https://nodejs.org/api/globals.html#fetch)
|
|
667
718
|
|
package/index.js
CHANGED
|
@@ -6,6 +6,7 @@ export * from "./lib/time.mjs";
|
|
|
6
6
|
export * from "./lib/wait.mjs";
|
|
7
7
|
export * from "./polyfill/Console.mjs";
|
|
8
8
|
export * from "./polyfill/fetch.mjs";
|
|
9
|
+
export * from "./polyfill/KV.mjs";
|
|
9
10
|
export * from "./polyfill/Lodash.mjs";
|
|
10
11
|
export * from "./polyfill/StatusTexts.mjs";
|
|
11
12
|
export * from "./polyfill/Storage.mjs";
|
package/lib/app.mjs
CHANGED
|
@@ -10,8 +10,9 @@
|
|
|
10
10
|
* 4) `Egern` -> Egern
|
|
11
11
|
* 5) `$environment["surge-version"]` -> Surge
|
|
12
12
|
* 6) `$environment["stash-version"]` -> Stash
|
|
13
|
-
* 7) `
|
|
14
|
-
* 8)
|
|
13
|
+
* 7) `Cloudflare` -> Worker
|
|
14
|
+
* 8) `process.versions.node` -> Node.js
|
|
15
|
+
* 9) 默认回落 -> undefined
|
|
15
16
|
* default fallback -> undefined
|
|
16
17
|
*
|
|
17
18
|
* 说明:
|
|
@@ -19,10 +20,10 @@
|
|
|
19
20
|
* - 使用 `'key' in globalThis`,避免 `Object.keys` 对不可枚举全局变量漏检。
|
|
20
21
|
* - Use `'key' in globalThis` to avoid missing non-enumerable globals with `Object.keys`.
|
|
21
22
|
*
|
|
22
|
-
* @type {("Quantumult X" | "Loon" | "Shadowrocket" | "Egern" | "Surge" | "Stash" | "Node.js" | undefined)}
|
|
23
|
+
* @type {("Quantumult X" | "Loon" | "Shadowrocket" | "Egern" | "Surge" | "Stash" | "Worker" | "Node.js" | undefined)}
|
|
23
24
|
*/
|
|
24
25
|
export const $app = (() => {
|
|
25
|
-
const has =
|
|
26
|
+
const has = key => key in globalThis;
|
|
26
27
|
switch (true) {
|
|
27
28
|
case has("$task"):
|
|
28
29
|
return "Quantumult X";
|
|
@@ -36,6 +37,9 @@ export const $app = (() => {
|
|
|
36
37
|
return "Surge";
|
|
37
38
|
case Boolean(globalThis.$environment?.["stash-version"]):
|
|
38
39
|
return "Stash";
|
|
40
|
+
case has("Cloudflare"):
|
|
41
|
+
//case has("ServiceWorkerGlobalScope") && has("self") && has("caches") && has("scheduler"):
|
|
42
|
+
return "Worker";
|
|
39
43
|
case Boolean(globalThis.process?.versions?.node):
|
|
40
44
|
return "Node.js";
|
|
41
45
|
default:
|
package/lib/done.mjs
CHANGED
|
@@ -24,6 +24,8 @@ import { StatusTexts } from "../polyfill/StatusTexts.mjs";
|
|
|
24
24
|
* Notes:
|
|
25
25
|
* - 这是调用入口,平台原生 `$done` 差异在内部处理
|
|
26
26
|
* - This is the call entry and native `$done` differences are handled internally
|
|
27
|
+
* - Worker 不调用 `$done` 或退出进程,仅记录日志
|
|
28
|
+
* - Worker neither calls `$done` nor exits the process; it only logs
|
|
27
29
|
* - Node.js 不调用 `$done`,而是直接退出进程
|
|
28
30
|
* - Node.js does not call `$done`; it exits the process directly
|
|
29
31
|
* - 未识别平台仅记录结束日志,不会强制退出
|
|
@@ -80,6 +82,9 @@ export function done(object = {}) {
|
|
|
80
82
|
Console.log("🚩 执行结束!");
|
|
81
83
|
$done(object);
|
|
82
84
|
break;
|
|
85
|
+
case "Worker":
|
|
86
|
+
Console.log("🚩 执行结束!");
|
|
87
|
+
break;
|
|
83
88
|
case "Node.js":
|
|
84
89
|
Console.log("🚩 执行结束!");
|
|
85
90
|
process.exit(1);
|
package/lib/environment.mjs
CHANGED
|
@@ -10,6 +10,8 @@ import { $app } from "./app.mjs";
|
|
|
10
10
|
* - Loon: parse `$loon` into device/version fields
|
|
11
11
|
* - Quantumult X: 仅返回 `{ app: "Quantumult X" }`
|
|
12
12
|
* - Quantumult X: returns `{ app: "Quantumult X" }` only
|
|
13
|
+
* - Worker: 返回 `{ app: "Worker" }`
|
|
14
|
+
* - Worker: returns `{ app: "Worker" }`
|
|
13
15
|
* - Node.js: 复用 `process.env` 并写入 `process.env.app`
|
|
14
16
|
* - Node.js: reuses `process.env` and writes `process.env.app`
|
|
15
17
|
*
|
|
@@ -47,6 +49,10 @@ export function environment() {
|
|
|
47
49
|
return {
|
|
48
50
|
app: "Quantumult X",
|
|
49
51
|
};
|
|
52
|
+
case "Worker":
|
|
53
|
+
return {
|
|
54
|
+
app: "Worker",
|
|
55
|
+
};
|
|
50
56
|
case "Node.js":
|
|
51
57
|
process.env.app = "Node.js";
|
|
52
58
|
return process.env;
|
package/lib/notification.mjs
CHANGED
|
@@ -29,6 +29,8 @@ import { Console } from "../polyfill/Console.mjs";
|
|
|
29
29
|
* Notes:
|
|
30
30
|
* - iOS App 平台调用 `$notification.post` 或 `$notify`
|
|
31
31
|
* - iOS app platforms call `$notification.post` or `$notify`
|
|
32
|
+
* - Worker 不支持 iOS 通知接口,仅输出日志
|
|
33
|
+
* - Worker does not support iOS notification APIs; it logs only
|
|
32
34
|
* - Node.js 不支持 iOS 通知接口,仅输出日志
|
|
33
35
|
* - Node.js does not support iOS notification APIs; it logs only
|
|
34
36
|
*
|
|
@@ -52,6 +54,7 @@ export function notification(title = `ℹ️ ${$app} 通知`, subtitle = "", bod
|
|
|
52
54
|
case "Quantumult X":
|
|
53
55
|
$notify(title, subtitle, body, mutableContent);
|
|
54
56
|
break;
|
|
57
|
+
case "Worker":
|
|
55
58
|
case "Node.js":
|
|
56
59
|
break;
|
|
57
60
|
}
|
|
@@ -90,6 +93,7 @@ const MutableContent = content => {
|
|
|
90
93
|
case "Quantumult X":
|
|
91
94
|
mutableContent["open-url"] = content;
|
|
92
95
|
break;
|
|
96
|
+
case "Worker":
|
|
93
97
|
case "Node.js":
|
|
94
98
|
break;
|
|
95
99
|
}
|
|
@@ -167,6 +171,7 @@ const MutableContent = content => {
|
|
|
167
171
|
if (copyUrl) mutableContent["update-pasteboard"] = copyUrl;
|
|
168
172
|
break;
|
|
169
173
|
}
|
|
174
|
+
case "Worker":
|
|
170
175
|
case "Node.js":
|
|
171
176
|
break;
|
|
172
177
|
}
|
package/package.json
CHANGED
package/polyfill/Console.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { $app } from "../lib/app.mjs";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
* Unified logger compatible with script platforms and Node.js.
|
|
4
|
+
* 统一日志工具,兼容各脚本平台、Worker 与 Node.js。
|
|
5
|
+
* Unified logger compatible with script platforms, Worker, and Node.js.
|
|
6
6
|
*
|
|
7
7
|
* logLevel 用法:
|
|
8
8
|
* logLevel usage:
|
|
@@ -99,8 +99,9 @@ export class Console {
|
|
|
99
99
|
default:
|
|
100
100
|
msg = msg.map(m => `❌ ${m}`);
|
|
101
101
|
break;
|
|
102
|
+
case "Worker":
|
|
102
103
|
case "Node.js":
|
|
103
|
-
msg = msg.map(m => `❌ ${m
|
|
104
|
+
msg = msg.map(m => `❌ ${m?.stack ?? m}`);
|
|
104
105
|
break;
|
|
105
106
|
}
|
|
106
107
|
Console.log(...msg);
|
package/polyfill/KV.mjs
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { $app } from "../lib/app.mjs";
|
|
2
|
+
import { Lodash as _ } from "./Lodash.mjs";
|
|
3
|
+
import { Storage } from "./Storage.mjs";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Cloudflare Workers KV 异步适配器。
|
|
7
|
+
* Async adapter for Cloudflare Workers KV.
|
|
8
|
+
*
|
|
9
|
+
* 设计目标:
|
|
10
|
+
* Design goal:
|
|
11
|
+
* - 提供与 `Storage` 接近的异步接口
|
|
12
|
+
* - Provide an async API close to `Storage`
|
|
13
|
+
* - 在 Worker 中使用显式传入的 KV namespace binding
|
|
14
|
+
* - Use an explicitly passed KV namespace binding in Workers
|
|
15
|
+
* - 在非 Worker 平台回退到 `Storage`
|
|
16
|
+
* - Fall back to `Storage` on non-Worker platforms
|
|
17
|
+
*
|
|
18
|
+
* 支持路径键:
|
|
19
|
+
* Supports path key:
|
|
20
|
+
* - `@root.path.to.value`
|
|
21
|
+
*
|
|
22
|
+
* @link https://developers.cloudflare.com/kv/get-started/#5-access-your-kv-namespace-from-your-worker
|
|
23
|
+
* @link https://developers.cloudflare.com/kv/api/read-key-value-pairs/
|
|
24
|
+
* @link https://developers.cloudflare.com/kv/api/write-key-value-pairs/
|
|
25
|
+
* @link https://developers.cloudflare.com/kv/api/delete-key-value-pairs/
|
|
26
|
+
* @link https://developers.cloudflare.com/kv/api/list-keys/
|
|
27
|
+
*/
|
|
28
|
+
export class KV {
|
|
29
|
+
/**
|
|
30
|
+
* `@key.path` 解析正则。
|
|
31
|
+
* Regex for `@key.path` parsing.
|
|
32
|
+
*
|
|
33
|
+
* @type {RegExp}
|
|
34
|
+
*/
|
|
35
|
+
static #nameRegex = /^@(?<key>[^.]+)(?:\.(?<path>.*))?$/;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Cloudflare KV namespace 绑定。
|
|
39
|
+
* Cloudflare KV namespace binding.
|
|
40
|
+
*
|
|
41
|
+
* @type {{ get(key: string): Promise<string|null>; put(key: string, value: string): Promise<void>; delete(key: string): Promise<void>; list?(options?: { prefix?: string; limit?: number; cursor?: string }): Promise<{ keys: { name: string; expiration?: number; metadata?: object }[]; list_complete: boolean; cursor: string }> } | undefined}
|
|
42
|
+
*/
|
|
43
|
+
namespace;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 创建 KV 适配器实例。
|
|
47
|
+
* Create a KV adapter instance.
|
|
48
|
+
*
|
|
49
|
+
* @param {{ get(key: string): Promise<string|null>; put(key: string, value: string): Promise<void>; delete(key: string): Promise<void>; list?(options?: { prefix?: string; limit?: number; cursor?: string }): Promise<{ keys: { name: string; expiration?: number; metadata?: object }[]; list_complete: boolean; cursor: string }> } | null | undefined} namespace KV namespace 绑定 / KV namespace binding.
|
|
50
|
+
*/
|
|
51
|
+
constructor(namespace) {
|
|
52
|
+
this.namespace = namespace ?? undefined;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 读取存储值。
|
|
57
|
+
* Read value from persistent storage.
|
|
58
|
+
*
|
|
59
|
+
* @param {string} keyName 键名或路径键 / Key or path key.
|
|
60
|
+
* @param {*} [defaultValue=null] 默认值 / Default value when key is missing.
|
|
61
|
+
* @returns {Promise<*>}
|
|
62
|
+
*/
|
|
63
|
+
async getItem(keyName, defaultValue = null) {
|
|
64
|
+
let keyValue = defaultValue;
|
|
65
|
+
switch (keyName.startsWith("@")) {
|
|
66
|
+
case true: {
|
|
67
|
+
const { key, path } = keyName.match(KV.#nameRegex)?.groups ?? {};
|
|
68
|
+
keyName = key;
|
|
69
|
+
let value = await this.getItem(keyName, {});
|
|
70
|
+
if (typeof value !== "object" || value === null) value = {};
|
|
71
|
+
keyValue = _.get(value, path);
|
|
72
|
+
keyValue = KV.#deserialize(keyValue);
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
default:
|
|
76
|
+
switch ($app) {
|
|
77
|
+
case "Worker":
|
|
78
|
+
keyValue = await this.#getNamespace().get(keyName);
|
|
79
|
+
break;
|
|
80
|
+
default:
|
|
81
|
+
keyValue = Storage.getItem(keyName, defaultValue);
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
keyValue = KV.#deserialize(keyValue);
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
return keyValue ?? defaultValue;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* 写入存储值。
|
|
92
|
+
* Write value into persistent storage.
|
|
93
|
+
*
|
|
94
|
+
* @param {string} keyName 键名或路径键 / Key or path key.
|
|
95
|
+
* @param {*} keyValue 写入值 / Value to store.
|
|
96
|
+
* @returns {Promise<boolean>}
|
|
97
|
+
*/
|
|
98
|
+
async setItem(keyName = new String(), keyValue = new String()) {
|
|
99
|
+
let result = false;
|
|
100
|
+
keyValue = KV.#serialize(keyValue);
|
|
101
|
+
switch (keyName.startsWith("@")) {
|
|
102
|
+
case true: {
|
|
103
|
+
const { key, path } = keyName.match(KV.#nameRegex)?.groups ?? {};
|
|
104
|
+
keyName = key;
|
|
105
|
+
let value = await this.getItem(keyName, {});
|
|
106
|
+
if (typeof value !== "object" || value === null) value = {};
|
|
107
|
+
_.set(value, path, keyValue);
|
|
108
|
+
result = await this.setItem(keyName, value);
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
default:
|
|
112
|
+
switch ($app) {
|
|
113
|
+
case "Worker":
|
|
114
|
+
await this.#getNamespace().put(keyName, keyValue);
|
|
115
|
+
result = true;
|
|
116
|
+
break;
|
|
117
|
+
default:
|
|
118
|
+
result = Storage.setItem(keyName, keyValue);
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* 删除存储值。
|
|
128
|
+
* Remove value from persistent storage.
|
|
129
|
+
*
|
|
130
|
+
* @param {string} keyName 键名或路径键 / Key or path key.
|
|
131
|
+
* @returns {Promise<boolean>}
|
|
132
|
+
*/
|
|
133
|
+
async removeItem(keyName) {
|
|
134
|
+
let result = false;
|
|
135
|
+
switch (keyName.startsWith("@")) {
|
|
136
|
+
case true: {
|
|
137
|
+
const { key, path } = keyName.match(KV.#nameRegex)?.groups ?? {};
|
|
138
|
+
keyName = key;
|
|
139
|
+
let value = await this.getItem(keyName);
|
|
140
|
+
if (typeof value !== "object" || value === null) value = {};
|
|
141
|
+
_.unset(value, path);
|
|
142
|
+
result = await this.setItem(keyName, value);
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
default:
|
|
146
|
+
switch ($app) {
|
|
147
|
+
case "Worker":
|
|
148
|
+
await this.#getNamespace().delete(keyName);
|
|
149
|
+
result = true;
|
|
150
|
+
break;
|
|
151
|
+
default:
|
|
152
|
+
result = Storage.removeItem(keyName);
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
return result;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* 清空存储。
|
|
162
|
+
* Clear storage.
|
|
163
|
+
*
|
|
164
|
+
* @returns {Promise<boolean>}
|
|
165
|
+
*/
|
|
166
|
+
async clear() {
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* 列出命名空间中的键。
|
|
172
|
+
* List keys in the namespace.
|
|
173
|
+
*
|
|
174
|
+
* @param {{ prefix?: string; limit?: number; cursor?: string }} [options={}] 列举选项 / List options.
|
|
175
|
+
* @returns {Promise<{ keys: { name: string; expiration?: number; metadata?: object }[]; list_complete: boolean; cursor: string }>}
|
|
176
|
+
*/
|
|
177
|
+
async list(options = {}) {
|
|
178
|
+
switch ($app) {
|
|
179
|
+
case "Worker": {
|
|
180
|
+
const namespace = this.#getNamespace();
|
|
181
|
+
if (typeof namespace.list !== "function") throw new TypeError("KV namespace binding with list() is required in Worker runtime.");
|
|
182
|
+
return await namespace.list(options);
|
|
183
|
+
}
|
|
184
|
+
default:
|
|
185
|
+
throw new TypeError("KV.list() is only supported in Worker runtime.");
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* 解析 Worker 所需的 namespace 绑定。
|
|
191
|
+
* Resolve the namespace binding required by Workers.
|
|
192
|
+
*
|
|
193
|
+
* @private
|
|
194
|
+
* @returns {{ get(key: string): Promise<string|null>; put(key: string, value: string): Promise<void>; delete(key: string): Promise<void>; list?(options?: { prefix?: string; limit?: number; cursor?: string }): Promise<{ keys: { name: string; expiration?: number; metadata?: object }[]; list_complete: boolean; cursor: string }> }}
|
|
195
|
+
*/
|
|
196
|
+
#getNamespace() {
|
|
197
|
+
if (
|
|
198
|
+
!this.namespace ||
|
|
199
|
+
typeof this.namespace.get !== "function" ||
|
|
200
|
+
typeof this.namespace.put !== "function" ||
|
|
201
|
+
typeof this.namespace.delete !== "function"
|
|
202
|
+
) {
|
|
203
|
+
throw new TypeError("KV namespace binding is required in Worker runtime.");
|
|
204
|
+
}
|
|
205
|
+
return this.namespace;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* 尝试将字符串反序列化为原始值。
|
|
210
|
+
* Try to deserialize a string into its original value.
|
|
211
|
+
*
|
|
212
|
+
* @private
|
|
213
|
+
* @param {*} value 原始值 / Raw value.
|
|
214
|
+
* @returns {*}
|
|
215
|
+
*/
|
|
216
|
+
static #deserialize(value) {
|
|
217
|
+
try {
|
|
218
|
+
return JSON.parse(value);
|
|
219
|
+
} catch (e) {
|
|
220
|
+
return value;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* 规范化待写入的值。
|
|
226
|
+
* Normalize a value before persisting it.
|
|
227
|
+
*
|
|
228
|
+
* @private
|
|
229
|
+
* @param {*} value 原始值 / Raw value.
|
|
230
|
+
* @returns {string}
|
|
231
|
+
*/
|
|
232
|
+
static #serialize(value) {
|
|
233
|
+
switch (typeof value) {
|
|
234
|
+
case "object":
|
|
235
|
+
return JSON.stringify(value);
|
|
236
|
+
default:
|
|
237
|
+
return String(value);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
package/polyfill/Storage.mjs
CHANGED
|
@@ -16,6 +16,8 @@ import { Lodash as _ } from "./Lodash.mjs";
|
|
|
16
16
|
* Supported backends:
|
|
17
17
|
* - Surge/Loon/Stash/Egern/Shadowrocket: `$persistentStore`
|
|
18
18
|
* - Quantumult X: `$prefs`
|
|
19
|
+
* - Worker: 内存缓存(非持久化)
|
|
20
|
+
* - Worker: in-memory cache (non-persistent)
|
|
19
21
|
* - Node.js: 本地 `box.dat`
|
|
20
22
|
* - Node.js: local `box.dat`
|
|
21
23
|
*
|
|
@@ -37,8 +39,8 @@ import { Lodash as _ } from "./Lodash.mjs";
|
|
|
37
39
|
*/
|
|
38
40
|
export class Storage {
|
|
39
41
|
/**
|
|
40
|
-
* Node.js 环境下的内存数据缓存。
|
|
41
|
-
* In-memory data cache for Node.js runtime.
|
|
42
|
+
* Worker / Node.js 环境下的内存数据缓存。
|
|
43
|
+
* In-memory data cache for Worker / Node.js runtime.
|
|
42
44
|
*
|
|
43
45
|
* @type {Record<string, any>|null}
|
|
44
46
|
*/
|
|
@@ -95,6 +97,10 @@ export class Storage {
|
|
|
95
97
|
case "Quantumult X":
|
|
96
98
|
keyValue = $prefs.valueForKey(keyName);
|
|
97
99
|
break;
|
|
100
|
+
case "Worker":
|
|
101
|
+
Storage.data = Storage.data ?? {};
|
|
102
|
+
keyValue = Storage.data[keyName];
|
|
103
|
+
break;
|
|
98
104
|
case "Node.js":
|
|
99
105
|
Storage.data = Storage.#loaddata(Storage.dataFile);
|
|
100
106
|
keyValue = Storage.data?.[keyName];
|
|
@@ -153,6 +159,11 @@ export class Storage {
|
|
|
153
159
|
case "Quantumult X":
|
|
154
160
|
result = $prefs.setValueForKey(keyValue, keyName);
|
|
155
161
|
break;
|
|
162
|
+
case "Worker":
|
|
163
|
+
Storage.data = Storage.data ?? {};
|
|
164
|
+
Storage.data[keyName] = keyValue;
|
|
165
|
+
result = true;
|
|
166
|
+
break;
|
|
156
167
|
case "Node.js":
|
|
157
168
|
Storage.data = Storage.#loaddata(Storage.dataFile);
|
|
158
169
|
Storage.data[keyName] = keyValue;
|
|
@@ -207,6 +218,11 @@ export class Storage {
|
|
|
207
218
|
case "Quantumult X":
|
|
208
219
|
result = $prefs.removeValueForKey(keyName);
|
|
209
220
|
break;
|
|
221
|
+
case "Worker":
|
|
222
|
+
Storage.data = Storage.data ?? {};
|
|
223
|
+
delete Storage.data[keyName];
|
|
224
|
+
result = true;
|
|
225
|
+
break;
|
|
210
226
|
case "Node.js":
|
|
211
227
|
// result = false;
|
|
212
228
|
Storage.data = Storage.#loaddata(Storage.dataFile);
|
|
@@ -224,8 +240,8 @@ export class Storage {
|
|
|
224
240
|
}
|
|
225
241
|
|
|
226
242
|
/**
|
|
227
|
-
*
|
|
228
|
-
* Clear storage
|
|
243
|
+
* 清空存储。
|
|
244
|
+
* Clear storage.
|
|
229
245
|
*
|
|
230
246
|
* @returns {boolean}
|
|
231
247
|
*/
|
|
@@ -242,6 +258,10 @@ export class Storage {
|
|
|
242
258
|
case "Quantumult X":
|
|
243
259
|
result = $prefs.removeAllValues();
|
|
244
260
|
break;
|
|
261
|
+
case "Worker":
|
|
262
|
+
Storage.data = {};
|
|
263
|
+
result = true;
|
|
264
|
+
break;
|
|
245
265
|
case "Node.js":
|
|
246
266
|
// result = false;
|
|
247
267
|
Storage.data = Storage.#loaddata(Storage.dataFile);
|
package/polyfill/fetch.mjs
CHANGED
|
@@ -17,7 +17,7 @@ import { StatusTexts } from "./StatusTexts.mjs";
|
|
|
17
17
|
* @property {string} [policy] 指定策略 / Preferred policy.
|
|
18
18
|
* @property {boolean} [redirection] 是否跟随重定向 / Whether to follow redirects.
|
|
19
19
|
* @property {boolean} ["auto-redirect"] 平台重定向字段 / Platform redirect flag.
|
|
20
|
-
* @property {boolean|number|string} ["auto-cookie"] Node.js Cookie 开关 / Node.js Cookie toggle.
|
|
20
|
+
* @property {boolean|number|string} ["auto-cookie"] Worker / Node.js Cookie 开关 / Worker / Node.js Cookie toggle.
|
|
21
21
|
* @property {Record<string, any>} [opts] 平台扩展字段 / Platform extension fields.
|
|
22
22
|
*/
|
|
23
23
|
|
|
@@ -43,13 +43,13 @@ import { StatusTexts } from "./StatusTexts.mjs";
|
|
|
43
43
|
* Design goal:
|
|
44
44
|
* - 仿照 Web API `fetch`(`Window.fetch`)接口设计
|
|
45
45
|
* - Modeled after Web API `fetch` (`Window.fetch`)
|
|
46
|
-
* - 统一 VPN App 与 Node.js 环境中的请求调用
|
|
47
|
-
* - Unify request calls across VPN apps and Node.js
|
|
46
|
+
* - 统一 VPN App、Worker 与 Node.js 环境中的请求调用
|
|
47
|
+
* - Unify request calls across VPN apps, Worker, and Node.js
|
|
48
48
|
*
|
|
49
49
|
* 功能:
|
|
50
50
|
* Features:
|
|
51
|
-
* - 统一 Quantumult X / Loon / Surge / Stash / Egern / Shadowrocket / Node.js 请求接口
|
|
52
|
-
* - Normalize request APIs across Quantumult X / Loon / Surge / Stash / Egern / Shadowrocket / Node.js
|
|
51
|
+
* - 统一 Quantumult X / Loon / Surge / Stash / Egern / Shadowrocket / Worker / Node.js 请求接口
|
|
52
|
+
* - Normalize request APIs across Quantumult X / Loon / Surge / Stash / Egern / Shadowrocket / Worker / Node.js
|
|
53
53
|
* - 统一返回体字段(`ok/status/statusText/body/bodyBytes`)
|
|
54
54
|
* - Normalize response fields (`ok/status/statusText/body/bodyBytes`)
|
|
55
55
|
*
|
|
@@ -57,8 +57,10 @@ import { StatusTexts } from "./StatusTexts.mjs";
|
|
|
57
57
|
* Known differences from Web `fetch`:
|
|
58
58
|
* - 支持 `policy`、`auto-redirect` 等平台扩展字段
|
|
59
59
|
* - Supports platform extension fields like `policy` and `auto-redirect`
|
|
60
|
-
* - Node.js
|
|
61
|
-
* - Node.js
|
|
60
|
+
* - Worker / Node.js 共享基于 `fetch` 的请求分支
|
|
61
|
+
* - Worker / Node.js share the `fetch`-based request branch
|
|
62
|
+
* - `auto-cookie` 在 Worker / Node.js 共享分支中识别
|
|
63
|
+
* - `auto-cookie` is recognized by the shared Worker / Node.js branch
|
|
62
64
|
* - 非浏览器平台通过 `$httpClient/$task` 实现,不是原生 Fetch 实现
|
|
63
65
|
* - Non-browser platforms use `$httpClient/$task` instead of native Fetch engine
|
|
64
66
|
* - 返回结构包含 `statusCode/bodyBytes` 等兼容字段
|
|
@@ -117,6 +119,7 @@ export async function fetch(resource, options = {}) {
|
|
|
117
119
|
switch ($app) {
|
|
118
120
|
case "Loon":
|
|
119
121
|
case "Quantumult X":
|
|
122
|
+
case "Worker":
|
|
120
123
|
case "Node.js":
|
|
121
124
|
// 这些平台要求毫秒,因此把秒重新换算为毫秒。
|
|
122
125
|
// These platforms expect milliseconds, so convert seconds back to milliseconds.
|
|
@@ -238,9 +241,10 @@ export async function fetch(resource, options = {}) {
|
|
|
238
241
|
}, resource.timeout);
|
|
239
242
|
}),
|
|
240
243
|
]);
|
|
244
|
+
case "Worker":
|
|
241
245
|
case "Node.js": {
|
|
242
|
-
// Node.js
|
|
243
|
-
//
|
|
246
|
+
// Worker 复用宿主 `fetch`;Node.js 优先复用原生 `fetch`,缺失时再回退到 `node-fetch`。
|
|
247
|
+
// Worker reuses host `fetch`; Node.js reuses native `fetch` first and falls back to `node-fetch`.
|
|
244
248
|
if (!globalThis.fetch) globalThis.fetch = require("node-fetch");
|
|
245
249
|
switch (resource["auto-cookie"]) {
|
|
246
250
|
case undefined:
|
|
@@ -261,8 +265,8 @@ export async function fetch(resource, options = {}) {
|
|
|
261
265
|
case -1:
|
|
262
266
|
break;
|
|
263
267
|
}
|
|
264
|
-
// 将通用字段映射到 Node.js Fetch 语义。
|
|
265
|
-
// Map shared fields to Node.js Fetch semantics.
|
|
268
|
+
// 将通用字段映射到 Worker / Node.js Fetch 语义。
|
|
269
|
+
// Map shared fields to Worker / Node.js Fetch semantics.
|
|
266
270
|
resource.redirect = resource.redirection ? "follow" : "manual";
|
|
267
271
|
const { url, ...options } = resource;
|
|
268
272
|
// 发起请求并归一化响应头、文本与二进制响应体。
|
package/polyfill/index.js
CHANGED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
declare module "@nsnanocat/util" {
|
|
2
|
+
export type AppName =
|
|
3
|
+
| "Quantumult X"
|
|
4
|
+
| "Loon"
|
|
5
|
+
| "Shadowrocket"
|
|
6
|
+
| "Egern"
|
|
7
|
+
| "Surge"
|
|
8
|
+
| "Stash"
|
|
9
|
+
| "Worker"
|
|
10
|
+
| "Node.js";
|
|
11
|
+
|
|
12
|
+
export const $app: AppName | undefined;
|
|
13
|
+
export const $argument: Record<string, unknown>;
|
|
14
|
+
export const argument: typeof $argument;
|
|
15
|
+
|
|
16
|
+
export interface DonePayload {
|
|
17
|
+
status?: number | string;
|
|
18
|
+
url?: string;
|
|
19
|
+
headers?: Record<string, unknown>;
|
|
20
|
+
body?: string | ArrayBuffer | ArrayBufferView;
|
|
21
|
+
bodyBytes?: ArrayBuffer;
|
|
22
|
+
policy?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function done(object?: DonePayload): void;
|
|
26
|
+
|
|
27
|
+
export interface NotificationContentObject {
|
|
28
|
+
open?: string;
|
|
29
|
+
"open-url"?: string;
|
|
30
|
+
url?: string;
|
|
31
|
+
openUrl?: string;
|
|
32
|
+
copy?: string;
|
|
33
|
+
"update-pasteboard"?: string;
|
|
34
|
+
updatePasteboard?: string;
|
|
35
|
+
media?: string;
|
|
36
|
+
"media-url"?: string;
|
|
37
|
+
mediaUrl?: string;
|
|
38
|
+
mime?: string;
|
|
39
|
+
"auto-dismiss"?: number;
|
|
40
|
+
sound?: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export type NotificationContent = NotificationContentObject | string | number | boolean;
|
|
44
|
+
|
|
45
|
+
export function notification(
|
|
46
|
+
title?: string,
|
|
47
|
+
subtitle?: string,
|
|
48
|
+
body?: string,
|
|
49
|
+
content?: NotificationContent,
|
|
50
|
+
): void;
|
|
51
|
+
|
|
52
|
+
export function time(format: string, ts?: number): string;
|
|
53
|
+
export function wait(delay?: number): Promise<void>;
|
|
54
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
declare module "@nsnanocat/util" {
|
|
2
|
+
export interface FetchRequest {
|
|
3
|
+
url: string;
|
|
4
|
+
method?: string;
|
|
5
|
+
headers?: Record<string, unknown>;
|
|
6
|
+
body?: string | ArrayBuffer | ArrayBufferView | object;
|
|
7
|
+
bodyBytes?: ArrayBuffer;
|
|
8
|
+
timeout?: number | string;
|
|
9
|
+
policy?: string;
|
|
10
|
+
redirection?: boolean;
|
|
11
|
+
"auto-redirect"?: boolean;
|
|
12
|
+
"auto-cookie"?: boolean | number | string;
|
|
13
|
+
opts?: Record<string, unknown>;
|
|
14
|
+
[key: string]: unknown;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface FetchResponse {
|
|
18
|
+
ok: boolean;
|
|
19
|
+
status: number;
|
|
20
|
+
statusCode?: number;
|
|
21
|
+
statusText?: string;
|
|
22
|
+
headers?: Record<string, unknown>;
|
|
23
|
+
body?: string | ArrayBuffer;
|
|
24
|
+
bodyBytes?: ArrayBuffer;
|
|
25
|
+
[key: string]: unknown;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function fetch(resource: FetchRequest | string, options?: Partial<FetchRequest>): Promise<FetchResponse>;
|
|
29
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
declare module "@nsnanocat/util/getStorage.mjs" {
|
|
2
|
+
export interface StorageProfile {
|
|
3
|
+
Settings: Record<string, unknown>;
|
|
4
|
+
Configs: Record<string, unknown>;
|
|
5
|
+
Caches: Record<string, unknown>;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function traverseObject(
|
|
9
|
+
o: Record<string, unknown>,
|
|
10
|
+
c: (key: string, value: unknown) => unknown,
|
|
11
|
+
): Record<string, unknown>;
|
|
12
|
+
|
|
13
|
+
export function string2number(string: string): string | number;
|
|
14
|
+
|
|
15
|
+
export function value2array(value: string | number | boolean | string[] | null | undefined): Array<string | number | boolean>;
|
|
16
|
+
|
|
17
|
+
export default function getStorage(
|
|
18
|
+
key: string,
|
|
19
|
+
names: string | string[] | Array<string | string[]>,
|
|
20
|
+
database: Record<string, unknown>,
|
|
21
|
+
): StorageProfile;
|
|
22
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
declare module "@nsnanocat/util" {
|
|
2
|
+
export interface KVNamespaceLike {
|
|
3
|
+
get(key: string): Promise<string | null>;
|
|
4
|
+
put(key: string, value: string): Promise<void>;
|
|
5
|
+
delete(key: string): Promise<void>;
|
|
6
|
+
list?(options?: KVListOptions): Promise<KVListResult>;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface KVListOptions {
|
|
10
|
+
prefix?: string;
|
|
11
|
+
limit?: number;
|
|
12
|
+
cursor?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface KVListKey {
|
|
16
|
+
name: string;
|
|
17
|
+
expiration?: number;
|
|
18
|
+
metadata?: Record<string, unknown>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface KVListResult {
|
|
22
|
+
keys: KVListKey[];
|
|
23
|
+
list_complete: boolean;
|
|
24
|
+
cursor: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export class KV {
|
|
28
|
+
constructor(namespace?: KVNamespaceLike | null);
|
|
29
|
+
getItem<T = unknown>(keyName: string, defaultValue?: T): Promise<T>;
|
|
30
|
+
setItem(keyName: string, keyValue: unknown): Promise<boolean>;
|
|
31
|
+
removeItem(keyName: string): Promise<boolean>;
|
|
32
|
+
clear(): Promise<boolean>;
|
|
33
|
+
list(options?: KVListOptions): Promise<KVListResult>;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
declare module "@nsnanocat/util" {
|
|
2
|
+
export class Console {
|
|
3
|
+
static clear(): void;
|
|
4
|
+
static count(label?: string): void;
|
|
5
|
+
static countReset(label?: string): void;
|
|
6
|
+
static debug(...msg: unknown[]): void;
|
|
7
|
+
static error(...msg: unknown[]): void;
|
|
8
|
+
static exception(...msg: unknown[]): void;
|
|
9
|
+
static group(label: string): number;
|
|
10
|
+
static groupEnd(): string | undefined;
|
|
11
|
+
static info(...msg: unknown[]): void;
|
|
12
|
+
static get logLevel(): "OFF" | "ERROR" | "WARN" | "INFO" | "DEBUG" | "ALL";
|
|
13
|
+
static set logLevel(level: number | string);
|
|
14
|
+
static log(...msg: unknown[]): void;
|
|
15
|
+
static time(label?: string): Map<string, number>;
|
|
16
|
+
static timeEnd(label?: string): boolean;
|
|
17
|
+
static timeLog(label?: string): void;
|
|
18
|
+
static warn(...msg: unknown[]): void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class Lodash {
|
|
22
|
+
static escape(string: string): string;
|
|
23
|
+
static get<T = unknown, D = undefined>(object?: Record<string, unknown>, path?: string | string[], defaultValue?: D): T | D;
|
|
24
|
+
static merge<T extends Record<string, unknown>>(object: T, ...sources: Array<Record<string, unknown> | null | undefined>): T;
|
|
25
|
+
static omit<T extends Record<string, unknown>>(object?: T, paths?: string | string[]): T;
|
|
26
|
+
static pick<T extends Record<string, unknown>, K extends keyof T>(object?: T, paths?: K | K[]): Pick<T, K>;
|
|
27
|
+
static set<T extends Record<string, unknown>>(object: T, path: string | string[], value: unknown): T;
|
|
28
|
+
static toPath(value: string): string[];
|
|
29
|
+
static unescape(string: string): string;
|
|
30
|
+
static unset(object?: Record<string, unknown>, path?: string | string[]): boolean;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const StatusTexts: Record<number, string>;
|
|
34
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
declare module "@nsnanocat/util" {
|
|
2
|
+
export class Storage {
|
|
3
|
+
static data: Record<string, unknown> | null;
|
|
4
|
+
static dataFile: string;
|
|
5
|
+
static getItem<T = unknown>(keyName: string, defaultValue?: T): T;
|
|
6
|
+
static setItem(keyName: string, keyValue: unknown): boolean;
|
|
7
|
+
static removeItem(keyName: string): boolean;
|
|
8
|
+
static clear(): boolean;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -1,151 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
| "Stash"
|
|
9
|
-
| "Node.js";
|
|
10
|
-
|
|
11
|
-
export const $app: AppName | undefined;
|
|
12
|
-
export const $argument: Record<string, unknown>;
|
|
13
|
-
export const argument: typeof $argument;
|
|
14
|
-
|
|
15
|
-
export interface DonePayload {
|
|
16
|
-
status?: number | string;
|
|
17
|
-
url?: string;
|
|
18
|
-
headers?: Record<string, unknown>;
|
|
19
|
-
body?: string | ArrayBuffer | ArrayBufferView;
|
|
20
|
-
bodyBytes?: ArrayBuffer;
|
|
21
|
-
policy?: string;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function done(object?: DonePayload): void;
|
|
25
|
-
|
|
26
|
-
export interface NotificationContentObject {
|
|
27
|
-
open?: string;
|
|
28
|
-
"open-url"?: string;
|
|
29
|
-
url?: string;
|
|
30
|
-
openUrl?: string;
|
|
31
|
-
copy?: string;
|
|
32
|
-
"update-pasteboard"?: string;
|
|
33
|
-
updatePasteboard?: string;
|
|
34
|
-
media?: string;
|
|
35
|
-
"media-url"?: string;
|
|
36
|
-
mediaUrl?: string;
|
|
37
|
-
mime?: string;
|
|
38
|
-
"auto-dismiss"?: number;
|
|
39
|
-
sound?: string;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export type NotificationContent = NotificationContentObject | string | number | boolean;
|
|
43
|
-
|
|
44
|
-
export function notification(
|
|
45
|
-
title?: string,
|
|
46
|
-
subtitle?: string,
|
|
47
|
-
body?: string,
|
|
48
|
-
content?: NotificationContent,
|
|
49
|
-
): void;
|
|
50
|
-
|
|
51
|
-
export function time(format: string, ts?: number): string;
|
|
52
|
-
export function wait(delay?: number): Promise<void>;
|
|
53
|
-
|
|
54
|
-
export interface FetchRequest {
|
|
55
|
-
url: string;
|
|
56
|
-
method?: string;
|
|
57
|
-
headers?: Record<string, unknown>;
|
|
58
|
-
body?: string | ArrayBuffer | ArrayBufferView | object;
|
|
59
|
-
bodyBytes?: ArrayBuffer;
|
|
60
|
-
timeout?: number | string;
|
|
61
|
-
policy?: string;
|
|
62
|
-
redirection?: boolean;
|
|
63
|
-
"auto-redirect"?: boolean;
|
|
64
|
-
"auto-cookie"?: boolean | number | string;
|
|
65
|
-
opts?: Record<string, unknown>;
|
|
66
|
-
[key: string]: unknown;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export interface FetchResponse {
|
|
70
|
-
ok: boolean;
|
|
71
|
-
status: number;
|
|
72
|
-
statusCode?: number;
|
|
73
|
-
statusText?: string;
|
|
74
|
-
headers?: Record<string, unknown>;
|
|
75
|
-
body?: string | ArrayBuffer;
|
|
76
|
-
bodyBytes?: ArrayBuffer;
|
|
77
|
-
[key: string]: unknown;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export function fetch(resource: FetchRequest | string, options?: Partial<FetchRequest>): Promise<FetchResponse>;
|
|
81
|
-
|
|
82
|
-
export class Console {
|
|
83
|
-
static clear(): void;
|
|
84
|
-
static count(label?: string): void;
|
|
85
|
-
static countReset(label?: string): void;
|
|
86
|
-
static debug(...msg: unknown[]): void;
|
|
87
|
-
static error(...msg: unknown[]): void;
|
|
88
|
-
static exception(...msg: unknown[]): void;
|
|
89
|
-
static group(label: string): number;
|
|
90
|
-
static groupEnd(): string | undefined;
|
|
91
|
-
static info(...msg: unknown[]): void;
|
|
92
|
-
static get logLevel(): "OFF" | "ERROR" | "WARN" | "INFO" | "DEBUG" | "ALL";
|
|
93
|
-
static set logLevel(level: number | string);
|
|
94
|
-
static log(...msg: unknown[]): void;
|
|
95
|
-
static time(label?: string): Map<string, number>;
|
|
96
|
-
static timeEnd(label?: string): boolean;
|
|
97
|
-
static timeLog(label?: string): void;
|
|
98
|
-
static warn(...msg: unknown[]): void;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export class Lodash {
|
|
102
|
-
static escape(string: string): string;
|
|
103
|
-
static get<T = unknown, D = undefined>(object?: Record<string, unknown>, path?: string | string[], defaultValue?: D): T | D;
|
|
104
|
-
static merge<T extends Record<string, unknown>>(object: T, ...sources: Array<Record<string, unknown> | null | undefined>): T;
|
|
105
|
-
static omit<T extends Record<string, unknown>>(object?: T, paths?: string | string[]): T;
|
|
106
|
-
static pick<T extends Record<string, unknown>, K extends keyof T>(object?: T, paths?: K | K[]): Pick<T, K>;
|
|
107
|
-
static set<T extends Record<string, unknown>>(object: T, path: string | string[], value: unknown): T;
|
|
108
|
-
static toPath(value: string): string[];
|
|
109
|
-
static unescape(string: string): string;
|
|
110
|
-
static unset(object?: Record<string, unknown>, path?: string | string[]): boolean;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
export const StatusTexts: Record<number, string>;
|
|
114
|
-
|
|
115
|
-
export class Storage {
|
|
116
|
-
static data: Record<string, unknown> | null;
|
|
117
|
-
static dataFile: string;
|
|
118
|
-
static getItem<T = unknown>(keyName: string, defaultValue?: T): T;
|
|
119
|
-
static setItem(keyName: string, keyValue: unknown): boolean;
|
|
120
|
-
static removeItem(keyName: string): boolean;
|
|
121
|
-
static clear(): boolean;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
declare module "@nsnanocat/util/getStorage.mjs" {
|
|
126
|
-
export interface StorageProfile {
|
|
127
|
-
Settings: Record<string, unknown>;
|
|
128
|
-
Configs: Record<string, unknown>;
|
|
129
|
-
Caches: Record<string, unknown>;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
export function traverseObject(
|
|
133
|
-
o: Record<string, unknown>,
|
|
134
|
-
c: (key: string, value: unknown) => unknown,
|
|
135
|
-
): Record<string, unknown>;
|
|
136
|
-
|
|
137
|
-
export function string2number(string: string): string | number;
|
|
138
|
-
|
|
139
|
-
export function value2array(value: string | number | boolean | string[] | null | undefined): Array<string | number | boolean>;
|
|
140
|
-
|
|
141
|
-
export default function getStorage(
|
|
142
|
-
key: string,
|
|
143
|
-
names: string | string[] | Array<string | string[]>,
|
|
144
|
-
database: Record<string, unknown>,
|
|
145
|
-
): StorageProfile;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
declare module "@nsnanocat/util/lib/environment.mjs" {
|
|
149
|
-
export const $environment: Record<string, unknown>;
|
|
150
|
-
export function environment(): Record<string, unknown>;
|
|
151
|
-
}
|
|
1
|
+
/// <reference path="./modules/core.d.ts" />
|
|
2
|
+
/// <reference path="./modules/fetch.d.ts" />
|
|
3
|
+
/// <reference path="./modules/polyfills.d.ts" />
|
|
4
|
+
/// <reference path="./modules/storage.d.ts" />
|
|
5
|
+
/// <reference path="./modules/kv.d.ts" />
|
|
6
|
+
/// <reference path="./modules/getStorage.d.ts" />
|
|
7
|
+
/// <reference path="./modules/environment.d.ts" />
|