@mzzsfy/dsh-usage-panel 0.4.3 → 0.4.4

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
@@ -123,10 +123,10 @@ custom 端点支持自定义请求方法(GET/POST/PUT/DELETE/PATCH)、请求头(
123
123
  - 早期版本允许无 `id` 的账号(落盘时按索引一次性补齐);当前前端保存时总携带 `id`,不再做旧数据特判
124
124
  - 账号卡片渲染未做 memo 化、趋势浮层常挂载:数据规模受账号上限(20)与悬浮窗口点数(24)双重钳制,无可感知卡顿,后置观察
125
125
 
126
- ## 开发安装(不经 npm 发布直接装仓库副本)
126
+ ## 开发安装(仓库工作副本直挂,不经 npm 发布)
127
127
 
128
128
  ```sh
129
- dsh plugin --profile web add file:./packages/dsh-usage-panel
129
+ node scripts/dev-link.mjs dsh-usage-panel # 仓库根执行:归一 profile 依赖行 + 挂 junction
130
130
  ```
131
131
 
132
- `file:` 安装指向仓库工作副本,改代码后重跑该命令即同步,无需发版。
132
+ 工作副本以 junction 挂进 profile,改代码保存即热重载(host 半区)或刷新页面生效(client 半区),无需发版;规约与全仓归一见仓库根 `node scripts/dev-link.mjs all`。
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mzzsfy/dsh-usage-panel",
3
3
  "description": "多平台 LLM 账号余额与额度面板:支持 DeepSeek/OpenRouter/Kimi/智谱/MiniMax/NewApi 及自定义端点,自动定期查询,趋势图与历史快照,用量/余额阈值与窗口重置多通道通知",
4
- "version": "0.4.3",
4
+ "version": "0.4.4",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
7
7
  "exports": {
@@ -0,0 +1,54 @@
1
+ // client.js 求值形态守卫:宿主以经典 script 整源求值,顶层词法声明落页面全局词法环境,
2
+ // 跨 bundle 同名即整脚本 SyntaxError 拒载。本包 client.js 以单条 __ModuleLoader__.load
3
+ // 语句承载全部代码(声明均在 factory 作用域内),本守卫锁定"顶层零词法声明"不变量,
4
+ // 防未来声明误置顶层。vm.runInContext 与浏览器经典 script 同语义(全局词法环境跨脚本共享)。
5
+ import { test } from 'node:test'
6
+ import assert from 'node:assert/strict'
7
+ import { readFileSync } from 'node:fs'
8
+ import { fileURLToPath } from 'node:url'
9
+ import { dirname, join } from 'node:path'
10
+ import vm from 'node:vm'
11
+
12
+ const CLIENT_SOURCE = readFileSync(join(dirname(fileURLToPath(import.meta.url)), '..', 'src', 'client.js'), 'utf8').trimEnd()
13
+ const DECLARATION_NAMES = [
14
+ ...new Set(
15
+ [...CLIENT_SOURCE.matchAll(/^(?:const|let|var|class|(?:async )?function\*?) ([A-Za-z_$][\w$]*)/gm)].map((match) => match[1])
16
+ ),
17
+ ]
18
+ const BUNDLE_ID = '@mzzsfy/dsh-usage-panel'
19
+
20
+ test('Given 同 context 已有外部 CSS 声明(宿主经典 script 全局词法环境), When 整源求值 client.js, Then 双源共存不拒载且外部声明原值不变', () => {
21
+ const ctx = vm.createContext({ window: { __ModuleLoader__: { load: () => {} } } })
22
+ vm.runInContext('const CSS = 1', ctx)
23
+ vm.runInContext(CLIENT_SOURCE, ctx)
24
+ assert.equal(vm.runInContext('CSS', ctx), 1)
25
+ })
26
+
27
+ test('Given client.js 已整源求值, When 同 context 再声明外部 CSS, Then 双源共存不拒载', () => {
28
+ const ctx = vm.createContext({ window: { __ModuleLoader__: { load: () => {} } } })
29
+ vm.runInContext(CLIENT_SOURCE, ctx)
30
+ vm.runInContext('const CSS = 1', ctx)
31
+ })
32
+
33
+ test('Given client.js 整源求值完成, When 逐名以 const 重声明探针行首声明名, Then 全局词法环境零泄漏', () => {
34
+ const ctx = vm.createContext({ window: { __ModuleLoader__: { load: () => {} } } })
35
+ vm.runInContext(CLIENT_SOURCE, ctx)
36
+ const leaked = DECLARATION_NAMES.filter((name) => {
37
+ try {
38
+ vm.runInContext(`const ${name} = null`, ctx)
39
+ return false
40
+ } catch {
41
+ return true
42
+ }
43
+ })
44
+ assert.deepEqual(leaked, [])
45
+ })
46
+
47
+ test('Given 宿主 loader 就绪, When 整源求值 client.js, Then 自注册照常发生且 id 不变', () => {
48
+ const registrations = []
49
+ const ctx = vm.createContext({ window: { __ModuleLoader__: { load: (registration) => registrations.push(registration) } } })
50
+ vm.runInContext(CLIENT_SOURCE, ctx)
51
+ assert.equal(registrations.length, 1)
52
+ assert.equal(registrations[0].id, BUNDLE_ID)
53
+ assert.equal(typeof registrations[0].factory, 'function')
54
+ })