@deepseek-ai/dsh-client-test-runtime 0.2.1-rc.4 → 0.2.2-alpha.2
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 +6 -6
- package/README.md +4 -4
- package/README.zh.md +4 -4
- package/lib/index.js +61 -21
- package/lib/types/access.d.ts +37 -13
- package/lib/types/assembly/bundle-roster.d.ts +4 -1
- package/lib/types/assembly/test-client.d.ts +2 -0
- package/lib/types/index.d.ts +4 -2
- package/lib/types/sessions.d.ts +3 -3
- package/package.json +53 -53
package/README.i18n.yaml
CHANGED
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
en: 12afbb217bc06678
|
|
19
19
|
zh: c07f001ed8bb3300
|
|
20
20
|
/deepseek-ai-dsh-client-test-runtime/use-this-package/setting-up-a-feature-spec:
|
|
21
|
-
en:
|
|
22
|
-
zh:
|
|
21
|
+
en: 2cc497326fc544d9
|
|
22
|
+
zh: db7f73ab937d7c05
|
|
23
23
|
/deepseek-ai-dsh-client-test-runtime/use-this-package/local-dom-snapshots:
|
|
24
24
|
en: 1abbbed6cc4cf57b
|
|
25
25
|
zh: ab3975178b589653
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
en: 1442fc215c8128e8
|
|
31
31
|
zh: 8439861b08e46ea2
|
|
32
32
|
/deepseek-ai-dsh-client-test-runtime/use-this-package/roster-and-startup-behavior:
|
|
33
|
-
en:
|
|
34
|
-
zh:
|
|
33
|
+
en: 707b824ae6391cc0
|
|
34
|
+
zh: bb7621826e6b07db
|
|
35
35
|
/deepseek-ai-dsh-client-test-runtime/use-this-package/when-to-use-it:
|
|
36
36
|
en: eb2f9bc90acb7a62
|
|
37
37
|
zh: cb59a2134bc83106
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
en: 3264640018c1a0e8
|
|
46
46
|
zh: d777e0b8ad8b602f
|
|
47
47
|
/deepseek-ai-dsh-client-test-runtime/understand-the-implementation/source-map:
|
|
48
|
-
en:
|
|
49
|
-
zh:
|
|
48
|
+
en: f9d1e576b34bd2d6
|
|
49
|
+
zh: 73bd7c2d57852a9f
|
|
50
50
|
/deepseek-ai-dsh-client-test-runtime/understand-the-implementation/lifecycle:
|
|
51
51
|
en: b42779f364504719
|
|
52
52
|
zh: a10bad7ea1161388
|
package/README.md
CHANGED
|
@@ -42,9 +42,9 @@ expect(view.container).toMatchSnapshot()
|
|
|
42
42
|
await runtime.dispose()
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
-
`mount` prechecks required services and fails loud when one is missing — `provide(name, value)` supplies an extra service first. The runtime provides a `fileUpload` stub
|
|
45
|
+
`mount` prechecks required services and fails loud when one is missing — `provide(name, value)` supplies an extra service first. The runtime provides a `fileUpload` stub whose `upload` and `uploadImage` reject every call until a suite replaces them. `storeOf(key, scopeKey)` returns the live store instance the renderer hands a slot's component for identity and action-driven-write assertions.
|
|
46
46
|
|
|
47
|
-
The runtime installs `allowAllAccessPlugin` before ui-session: its `remoteAccess` service answers true for every resource, so every access Hook allows every action. Hand-built component props spread `...allowAllAccess` to receive the same Hooks; a spec of a refused path overrides one Hook
|
|
47
|
+
The runtime installs `allowAllAccessPlugin` before ui-session: its `remoteAccess` service, a `StaticRemoteAccess`, answers true for every resource, so every access Hook allows every action and every `whenAccess` callback runs at once. `TestClientOptions.access` fixes the answer per action instead, through `staticAccessPlugin(allows)`. Hand-built component props spread `...allowAllAccess` to receive the same Hooks; a spec of a refused path overrides one Hook or provides `new StaticRemoteAccess(ctx, allows)`.
|
|
48
48
|
|
|
49
49
|
The optional render options select a keyed entry with `entryKey` or a list item with `only`; `view.update(owner)` retains that selection. `runtime.panelInfo` supplies the default `usePanelInfo` source with no global panel selected. Release it with `releasePanelInfoSource()` before mounting the production Layout owner. `dispose()` releases both default Workspace and panel-info root sources; early release is idempotent and does not remove replacement owners.
|
|
50
50
|
|
|
@@ -93,7 +93,7 @@ The [generic Remote proxy](../remote-mock/README.md#remote-proxy) supports every
|
|
|
93
93
|
|
|
94
94
|
### Roster and startup behavior
|
|
95
95
|
|
|
96
|
-
`webApp` is the `web` profile's browser roster, read when the assembly entry is first imported from its bundles (`dsh-base`, then `dsh-web-app`) as the launcher composes them, except that a patch matching nothing throws here where the launcher warns: each bundle's `dsh.bundle.patch` list is parsed with the include plugin's YAML dialect and composed by its `applyEntryPatches`, and every enabled row whose package declares `dsh.client.platform === 'web'` becomes a row carrying that declaration's `inject` and `immediately`; `bundleRoster(bundles, anchor, disabledContext)` accepts an explicit Loader evaluation scope for conditional `disabled` flags; without one, browser expressions are rejected. `webApp` supplies the Web profile name, not business Host services. Nothing is copied from the bundles, so a bundle change is visible at the next test run. `webApp.closure(names)` keeps the named rows plus everything they inject, transitively (the rows a spec needs to boot those plugins as the bundle composes them), `webApp.pick(names)` and `webApp.without(names)` cut it down by hand, all three throw on unknown names, and `ClientRoster.of(rows)` builds one inline. `remoteDefaultResponses` holds default responses for exactly the Remote endpoints the roster calls while booting with no sessions, no workspaces, and default settings; a spec layers its own `RemoteTable` on top with `mock.load(table)`, and any call without a rule fails the test at `dispose()` through `mock.assertNoUnmatched()`. `mount` requires a roster that provides `uiRenderer`; `start` fails loud otherwise instead of returning an empty container. `client.connection` is the roster's Connection service (no `Context` augmentation declares it), and `connectTimeoutMs` bounds the readiness wait, whose failure message lists the mock log. `reload(name)` rebuilds one Loader entry through the shared Client Modules helper (registry-first teardown, then `entry.refresh()`); each client retains its own module system and instance-bound Connection replacement, so starts and reloads can overlap without changing a page global. `unload(name)` removes an entry and waits for plugin cleanup; `flush()` settles React inside `act`. jsdom implements neither `EventSource` (client-hmr opens one at apply) nor `ResizeObserver` nor the `document.fonts` event target (layout components observe size and font loading at mount), so `start` reference-counts inert stubs for whichever global is absent and `dispose` removes exactly those — a jsdom gap, not a client identity channel. The `@deepseek-ai/dsh-api-remotes` row is dropped from every roster: its generated Remote clients exist only in built `lib/`, and `remote.<ns>` is what the tier replaces anyway. The `@deepseek-ai/dsh-api-remote-access` row, which mounts its own generated contribution, is dropped too, and `start` installs `allowAllAccessPlugin` in its place; a plan `provide` entry for either row is refused. `start` instead provides one contract-free proxy per `remote.<ns>` service the roster injects (plus the namespaces the mock has rules for at that point; a namespace first registered later has no proxy); `ctx.remote.<ns>.<method>(...args)` becomes a call on the endpoint `<ns>/<method>` carrying the positional args, a stream when the mock registered a `stream()` script and a unary call otherwise, with the generated client's outcome folding (`gateway/internal` for carrier throws, `gateway/cancelled` on abort). An endpoint without a rule is still dispatched, so the mock logs it and `dispose()` fails the test.
|
|
96
|
+
`webApp` is the `web` profile's browser roster, read when the assembly entry is first imported from its bundles (`dsh-base`, then `dsh-web-app`) as the launcher composes them, except that a patch matching nothing throws here where the launcher warns: each bundle's `dsh.bundle.patch` list is parsed with the include plugin's YAML dialect and composed by its `applyEntryPatches`, and every enabled row whose package declares `dsh.client.platform === 'web'` becomes a row carrying that declaration's `inject` and `immediately`; `bundleRoster(bundles, anchor, disabledContext)` accepts an explicit Loader evaluation scope for conditional `disabled` flags; without one, browser expressions are rejected. Both bundle and browser-entry lookup prefer an anchor manifest with the requested package name over dependency directories, including self-referencing bundles. `webApp` supplies the Web profile name, not business Host services. Nothing is copied from the bundles, so a bundle change is visible at the next test run. `webApp.closure(names)` keeps the named rows plus everything they inject, transitively (the rows a spec needs to boot those plugins as the bundle composes them), `webApp.pick(names)` and `webApp.without(names)` cut it down by hand, all three throw on unknown names, and `ClientRoster.of(rows)` builds one inline. `remoteDefaultResponses` holds default responses for exactly the Remote endpoints the roster calls while booting with no sessions, no workspaces, and default settings; a spec layers its own `RemoteTable` on top with `mock.load(table)`, and any call without a rule fails the test at `dispose()` through `mock.assertNoUnmatched()`. `mount` requires a roster that provides `uiRenderer`; `start` fails loud otherwise instead of returning an empty container. `client.connection` is the roster's Connection service (no `Context` augmentation declares it), and `connectTimeoutMs` bounds the readiness wait, whose failure message lists the mock log. `reload(name)` rebuilds one Loader entry through the shared Client Modules helper (registry-first teardown, then `entry.refresh()`); each client retains its own module system and instance-bound Connection replacement, so starts and reloads can overlap without changing a page global. `unload(name)` removes an entry and waits for plugin cleanup; `flush()` settles React inside `act`. jsdom implements neither `EventSource` (client-hmr opens one at apply) nor `ResizeObserver` nor the `document.fonts` event target (layout components observe size and font loading at mount), so `start` reference-counts inert stubs for whichever global is absent and `dispose` removes exactly those — a jsdom gap, not a client identity channel. The `@deepseek-ai/dsh-api-remotes` row is dropped from every roster: its generated Remote clients exist only in built `lib/`, and `remote.<ns>` is what the tier replaces anyway. The `@deepseek-ai/dsh-api-remote-access` row, which mounts its own generated contribution, is dropped too, and `start` installs `allowAllAccessPlugin`, or `staticAccessPlugin(options.access)`, in its place; a plan `provide` entry for either row is refused. `start` instead provides one contract-free proxy per `remote.<ns>` service the roster injects (plus the namespaces the mock has rules for at that point; a namespace first registered later has no proxy); `ctx.remote.<ns>.<method>(...args)` becomes a call on the endpoint `<ns>/<method>` carrying the positional args, a stream when the mock registered a `stream()` script and a unary call otherwise, with the generated client's outcome folding (`gateway/internal` for carrier throws, `gateway/cancelled` on abort). An endpoint without a rule is still dispatched, so the mock logs it and `dispose()` fails the test.
|
|
97
97
|
|
|
98
98
|
### When to use it
|
|
99
99
|
|
|
@@ -127,7 +127,7 @@ The bench copies no production logic: it mounts the production `SlotRegistry`, p
|
|
|
127
127
|
| [`src/sessions.ts`](src/sessions.ts) + [`src/workspaces.ts`](src/workspaces.ts) | `ISessions`/`IWorkspaces` test doubles and `FixtureSession` behavior stubs |
|
|
128
128
|
| [`src/fixtures.ts`](src/fixtures.ts) | Plain fixture builders: conversation snapshots, workspace list state |
|
|
129
129
|
| [`src/snapshot.ts`](src/snapshot.ts) | DOM snapshot serializer (class-hash folding, `<svg>` fingerprint) |
|
|
130
|
-
| [`src/access.ts`](src/access.ts) | `allowAllAccess` props and `allowAllAccessPlugin`, the
|
|
130
|
+
| [`src/access.ts`](src/access.ts) | `allowAllAccess` props, `StaticRemoteAccess`, `staticAccessPlugin`, and `allowAllAccessPlugin`, the fixed-answer stand-ins for the remote-access Client row |
|
|
131
131
|
| [`src/remote.ts`](src/remote.ts) | `TestRemote` double for host RPC, `RemoteError` value re-export |
|
|
132
132
|
| [`src/translate.ts`](src/translate.ts) + [`src/locale-env.ts`](src/locale-env.ts) | Translation and pinned-browser-language test helpers |
|
|
133
133
|
| [`src/config-form.ts`](src/config-form.ts) | `stubConfigForm` with test-driven publications and write spies |
|
package/README.zh.md
CHANGED
|
@@ -42,9 +42,9 @@ expect(view.container).toMatchSnapshot()
|
|
|
42
42
|
await runtime.dispose()
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
-
`mount` 会预检必需服务,缺失时自明报错——先用 `provide(name, value)` 提供额外服务。运行时提供的 `fileUpload`
|
|
45
|
+
`mount` 会预检必需服务,缺失时自明报错——先用 `provide(name, value)` 提供额外服务。运行时提供的 `fileUpload` 替身,其 `upload` 与 `uploadImage` 会拒绝每次调用,直到测试套件替换它们。`storeOf(key, scopeKey)` 返回渲染器交给 slot 组件的实时存储实例,用于身份与动作驱动写入断言。
|
|
46
46
|
|
|
47
|
-
运行时在 ui-session 之前安装 `allowAllAccessPlugin`:它的 `remoteAccess`
|
|
47
|
+
运行时在 ui-session 之前安装 `allowAllAccessPlugin`:它的 `remoteAccess` 服务是一个 `StaticRemoteAccess`,对每个资源都回答 true,因此每个访问 Hook 都允许每个 action,每个 `whenAccess` 回调都立即执行。`TestClientOptions.access` 改为按 action 固定答案,经由 `staticAccessPlugin(allows)`。手工构造的组件 props 展开 `...allowAllAccess` 以获得同样的 Hook;测试被拒绝路径的 spec 覆盖其中一个 Hook,或提供 `new StaticRemoteAccess(ctx, allows)`。
|
|
48
48
|
|
|
49
49
|
可选渲染参数通过 `entryKey` 选择 keyed 条目,或通过 `only` 选择 list 条目;`view.update(owner)` 保留该选择。`runtime.panelInfo` 提供默认的 `usePanelInfo` 数据源,初始不选中全局面板。挂载生产 Layout 所有者之前,先调用 `releasePanelInfoSource()` 释放该数据源。`dispose()` 同时释放默认的工作区与面板信息根数据源;提前释放是幂等的,不会移除替代它们的所有者。
|
|
50
50
|
|
|
@@ -93,7 +93,7 @@ test('registers into the sidebar', async ({ remote, start }) => {
|
|
|
93
93
|
|
|
94
94
|
### Roster 与启动行为
|
|
95
95
|
|
|
96
|
-
`webApp` 是 `web` profile 的浏览器 roster,首次 import 装配入口时从它的 bundle(先 `dsh-base`、再 `dsh-web-app`)按启动器的方式现读,只是匹配不到任何行的补丁在这里抛错、启动器只警告:每个 bundle 的 `dsh.bundle.patch` 列表用 include 插件的 YAML 方言解析、用它的 `applyEntryPatches` 合成,每个未禁用且其包声明 `dsh.client.platform === 'web'` 的行成为一行,带上该声明的 `inject` 与 `immediately`;`bundleRoster(bundles, anchor, disabledContext)` 接受显式 Loader 求值作用域来处理条件 `disabled`
|
|
96
|
+
`webApp` 是 `web` profile 的浏览器 roster,首次 import 装配入口时从它的 bundle(先 `dsh-base`、再 `dsh-web-app`)按启动器的方式现读,只是匹配不到任何行的补丁在这里抛错、启动器只警告:每个 bundle 的 `dsh.bundle.patch` 列表用 include 插件的 YAML 方言解析、用它的 `applyEntryPatches` 合成,每个未禁用且其包声明 `dsh.client.platform === 'web'` 的行成为一行,带上该声明的 `inject` 与 `immediately`;`bundleRoster(bundles, anchor, disabledContext)` 接受显式 Loader 求值作用域来处理条件 `disabled` 标记;未提供作用域时拒绝浏览器表达式。查找 bundle 和浏览器入口时,优先使用包名匹配的 anchor 清单,再搜索依赖目录;这也适用于注册自身浏览器入口的 bundle。`webApp` 仅提供 Web profile 名称,不提供业务 Host 服务。没有任何东西从 bundle 拷贝出来,bundle 一改下次跑测试就能看见。`webApp.closure(names)` 保留点名的行及其传递注入的全部行(即按 bundle 组合方式起这些插件所需的行),`webApp.pick(names)` 与 `webApp.without(names)` 手工裁剪,三者都对未知名字抛错,`ClientRoster.of(rows)` 内联构造一份。`remoteDefaultResponses` 是 roster 在没有 session、没有 workspace、默认设置下启动时恰好会打的那些 Remote 端点的默认响应;测试用 `mock.load(table)` 在其上叠加自己的 `RemoteTable`,任何没有规则的调用都会在 `dispose()` 时经 `mock.assertNoUnmatched()` 让测试失败。`mount` 要求 roster 提供 `uiRenderer`;否则 `start` 响亮失败而不是返回一个空容器。`client.connection` 是 roster 的 Connection 服务(没有任何 `Context` 增强声明它),`connectTimeoutMs` 限定等就绪的时长,超时消息列出 mock log。`reload(name)` 通过共享的 Client Modules 辅助函数重建一个 Loader entry(先拆 registry,再 `entry.refresh()`);每个客户端都保留自己的模块系统和绑定实例的 Connection 替换,因此启动与重载可以重叠而无需改写页面全局变量。`unload(name)` 移除 entry 并等待插件清理完成,`flush()` 在 `act` 内让 React 落定。jsdom 既没有 `EventSource`(client-hmr 在 apply 时打开一个)也没有 `ResizeObserver` 和 `document.fonts` 事件目标(布局组件挂载时观察尺寸与字体加载),所以 `start` 对缺失的全局惰性桩做引用计数,`dispose` 只移除它装的那些——这是 jsdom 的缺口,不是客户端身份通道。每个 roster 里的 `@deepseek-ai/dsh-api-remotes` 行都会被去掉:它生成的 Remote 客户端只存在于构建后的 `lib/`,而 `remote.<ns>` 正是本档要替掉的东西。自行挂载其生成 contribution 的 `@deepseek-ai/dsh-api-remote-access` 行同样会被去掉,`start` 改为安装 `allowAllAccessPlugin` 或 `staticAccessPlugin(options.access)`;计划中为这两行之一提供的 `provide` 项会被拒绝。`start` 改为给 roster 注入的每个 `remote.<ns>` 服务(加上此刻 mock 登记过规则的命名空间;之后才首次登记的命名空间没有代理)提供一个无契约代理;`ctx.remote.<ns>.<method>(...args)` 变成对端点 `<ns>/<method>` 的调用,携带位置参数,mock 登记了 `stream()` 脚本的走流、否则走一元,并沿用生成客户端的结果折叠(载体抛错折成 `gateway/internal`,中止折成 `gateway/cancelled`)。没有规则的端点照样发出,所以 mock 会记下它、`dispose()` 让测试失败。
|
|
97
97
|
|
|
98
98
|
### 何时使用
|
|
99
99
|
|
|
@@ -127,7 +127,7 @@ test('registers into the sidebar', async ({ remote, start }) => {
|
|
|
127
127
|
| [`src/sessions.ts`](src/sessions.ts) + [`src/workspaces.ts`](src/workspaces.ts) | `ISessions`/`IWorkspaces` 测试替身与 `FixtureSession` 行为桩 |
|
|
128
128
|
| [`src/fixtures.ts`](src/fixtures.ts) | 普通 fixture 构造器:会话快照、workspace 列表状态 |
|
|
129
129
|
| [`src/snapshot.ts`](src/snapshot.ts) | DOM 快照序列化器(类名哈希折叠、`<svg>` 指纹) |
|
|
130
|
-
| [`src/access.ts`](src/access.ts) | `allowAllAccess` props 与 `allowAllAccessPlugin`:remote-access Client
|
|
130
|
+
| [`src/access.ts`](src/access.ts) | `allowAllAccess` props、`StaticRemoteAccess`、`staticAccessPlugin` 与 `allowAllAccessPlugin`:remote-access Client 行的固定答案替身 |
|
|
131
131
|
| [`src/remote.ts`](src/remote.ts) | 用于 host RPC 的 `TestRemote` 替身、`RemoteError` 值转出 |
|
|
132
132
|
| [`src/translate.ts`](src/translate.ts) + [`src/locale-env.ts`](src/locale-env.ts) | 翻译与固定浏览器语言测试辅助 |
|
|
133
133
|
| [`src/config-form.ts`](src/config-form.ts) | 带测试驱动发布与写入 spy 的 `stubConfigForm` |
|
package/lib/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Context, Inject } from "@deepseek-ai/cordis";
|
|
1
|
+
import { Context, Inject, Service } from "@deepseek-ai/cordis";
|
|
2
2
|
import { Fragment, createElement, useSyncExternalStore } from "react";
|
|
3
3
|
import { act, render, within } from "@testing-library/react";
|
|
4
4
|
import { SlotRegistry } from "@deepseek-ai/dsh-client-ui-renderer/client";
|
|
@@ -328,10 +328,10 @@ var FixtureSession = class {
|
|
|
328
328
|
submissionSeq = 0;
|
|
329
329
|
/**
|
|
330
330
|
* Fail-loud stub; supply `readAttachment` on the fixture's session face to exercise it.
|
|
331
|
-
* @param
|
|
331
|
+
* @param _attachment - complete durable image reference.
|
|
332
332
|
* @returns never — always throws.
|
|
333
333
|
*/
|
|
334
|
-
readAttachment(
|
|
334
|
+
readAttachment(_attachment) {
|
|
335
335
|
throw new Error(`test session "${this.sessionId}": readAttachment is not stubbed — supply it on the fixture's session face`);
|
|
336
336
|
}
|
|
337
337
|
/**
|
|
@@ -1177,14 +1177,15 @@ var TestWorkspaces = class {
|
|
|
1177
1177
|
//#endregion
|
|
1178
1178
|
//#region lib/types/access.js
|
|
1179
1179
|
/**
|
|
1180
|
-
*
|
|
1180
|
+
* Static access for client specs. Production pages receive the
|
|
1181
1181
|
* `remoteAccess` Client service and the global-resource `useRemoteAccess` Hook
|
|
1182
1182
|
* from the remote-access Client plugin, and the Session and Workspace access
|
|
1183
1183
|
* Hooks (Session-scope `useAccess`, `useSessionAccess`, `useWorkspaceAccess`)
|
|
1184
1184
|
* from ui-session and ui-workspace over that service. The test runtimes
|
|
1185
1185
|
* install an allow-all service and `useRemoteAccess` Hook instead, and
|
|
1186
1186
|
* hand-built component props spread {@link allowAllAccess}; a spec of a
|
|
1187
|
-
* refused path overrides one Hook
|
|
1187
|
+
* refused path overrides one Hook or provides a {@link StaticRemoteAccess}
|
|
1188
|
+
* that refuses the action.
|
|
1188
1189
|
* @module @deepseek-ai/dsh-client-test-runtime/src/access
|
|
1189
1190
|
*/
|
|
1190
1191
|
/** Access Hooks that allow every action on every resource, for hand-built component props. */
|
|
@@ -1198,24 +1199,60 @@ const ALLOWED = {
|
|
|
1198
1199
|
getSnapshot: () => true,
|
|
1199
1200
|
subscribe: () => () => {}
|
|
1200
1201
|
};
|
|
1201
|
-
const
|
|
1202
|
-
|
|
1203
|
-
|
|
1202
|
+
const REFUSED = {
|
|
1203
|
+
getSnapshot: () => false,
|
|
1204
|
+
subscribe: () => () => {}
|
|
1205
|
+
};
|
|
1204
1206
|
/**
|
|
1205
|
-
*
|
|
1206
|
-
*
|
|
1207
|
-
*
|
|
1208
|
-
*
|
|
1207
|
+
* A `remoteAccess` Client service whose answers never change: `allows`
|
|
1208
|
+
* decides each action on every resource once. `whenAccess` installs an
|
|
1209
|
+
* allowed action's effects in the caller's fiber at once and never installs a
|
|
1210
|
+
* refused action's effects.
|
|
1209
1211
|
*/
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1212
|
+
var StaticRemoteAccess = class extends Service {
|
|
1213
|
+
allows;
|
|
1214
|
+
/**
|
|
1215
|
+
* @param ctx - Context the service is provided on.
|
|
1216
|
+
* @param allows - the fixed answer for each action; allows everything when omitted.
|
|
1217
|
+
*/
|
|
1218
|
+
constructor(ctx, allows = () => true) {
|
|
1219
|
+
super(ctx, "remoteAccess");
|
|
1220
|
+
this.allows = allows;
|
|
1221
|
+
}
|
|
1222
|
+
source(_kind, _id, action) {
|
|
1223
|
+
return this.allows(action) ? ALLOWED : REFUSED;
|
|
1224
|
+
}
|
|
1225
|
+
whenAccess(action, callback) {
|
|
1226
|
+
if (!this.allows(action)) return () => {};
|
|
1227
|
+
const dispose = this.ctx.effect(callback, `remoteAccess.whenAccess(${JSON.stringify(action)})`);
|
|
1228
|
+
return () => {
|
|
1229
|
+
dispose();
|
|
1230
|
+
};
|
|
1231
|
+
}
|
|
1232
|
+
whenResourceAccess(_kind, _id, action, callback) {
|
|
1233
|
+
return this.whenAccess(action, callback);
|
|
1217
1234
|
}
|
|
1218
1235
|
};
|
|
1236
|
+
/**
|
|
1237
|
+
* Plugin standing in for the remote-access Client row with fixed answers: it
|
|
1238
|
+
* provides a {@link StaticRemoteAccess}, so ui-session and ui-workspace
|
|
1239
|
+
* publish their resource Hooks over it, and the matching `useRemoteAccess`
|
|
1240
|
+
* Hook on the global resource.
|
|
1241
|
+
* @param allows - the fixed answer for each action on every resource.
|
|
1242
|
+
* @returns the plugin.
|
|
1243
|
+
*/
|
|
1244
|
+
function staticAccessPlugin(allows) {
|
|
1245
|
+
return {
|
|
1246
|
+
name: "client-test-runtime:static-access",
|
|
1247
|
+
inject: ["slots"],
|
|
1248
|
+
apply(ctx) {
|
|
1249
|
+
new StaticRemoteAccess(ctx, allows);
|
|
1250
|
+
ctx.slots.provideRoot({ keyedHooks: { remoteAccess: (action) => allows(action) ? ALLOWED : REFUSED } });
|
|
1251
|
+
}
|
|
1252
|
+
};
|
|
1253
|
+
}
|
|
1254
|
+
/** {@link staticAccessPlugin} allowing every action on every resource. */
|
|
1255
|
+
const allowAllAccessPlugin = staticAccessPlugin(() => true);
|
|
1219
1256
|
//#endregion
|
|
1220
1257
|
//#region lib/types/config-form.js
|
|
1221
1258
|
/** Test doubles for settings transport. */
|
|
@@ -1481,7 +1518,10 @@ var SlotTestRuntime = class SlotTestRuntime {
|
|
|
1481
1518
|
this.sessions = new TestSessions(this.stabilizer, ctx);
|
|
1482
1519
|
this.remote = new TestRemote(ctx);
|
|
1483
1520
|
this.workspaces = new TestWorkspaces(this.stabilizer);
|
|
1484
|
-
this.fileUpload = {
|
|
1521
|
+
this.fileUpload = {
|
|
1522
|
+
upload: () => Promise.reject(/* @__PURE__ */ new Error("client test runtime: file upload is not stubbed")),
|
|
1523
|
+
uploadImage: () => Promise.reject(/* @__PURE__ */ new Error("client test runtime: image upload is not stubbed"))
|
|
1524
|
+
};
|
|
1485
1525
|
ctx.provide("sessions", this.sessions);
|
|
1486
1526
|
ctx.provide("workspaces", this.workspaces);
|
|
1487
1527
|
ctx.provide("fileUpload", this.fileUpload);
|
|
@@ -1674,4 +1714,4 @@ var SlotTestRuntime = class SlotTestRuntime {
|
|
|
1674
1714
|
}
|
|
1675
1715
|
};
|
|
1676
1716
|
//#endregion
|
|
1677
|
-
export { FixtureSession, RemoteError, SlotTestRuntime, TestRemote, TestRoot, TestSessions, TestWorkspaces, allowAllAccess, allowAllAccessPlugin, bindSnapshotSelector, chatSnapshot, conversationSnapshot, createSlotRenderer, domSnapshotSerializer, makeTranslate, registerDomSnapshotSerializer, sessionSnapshot, stubConfigForm, usePinnedBrowserLanguages, workspaceSnapshot };
|
|
1717
|
+
export { FixtureSession, RemoteError, SlotTestRuntime, StaticRemoteAccess, TestRemote, TestRoot, TestSessions, TestWorkspaces, allowAllAccess, allowAllAccessPlugin, bindSnapshotSelector, chatSnapshot, conversationSnapshot, createSlotRenderer, domSnapshotSerializer, makeTranslate, registerDomSnapshotSerializer, sessionSnapshot, staticAccessPlugin, stubConfigForm, usePinnedBrowserLanguages, workspaceSnapshot };
|
package/lib/types/access.d.ts
CHANGED
|
@@ -1,30 +1,54 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Static access for client specs. Production pages receive the
|
|
3
3
|
* `remoteAccess` Client service and the global-resource `useRemoteAccess` Hook
|
|
4
4
|
* from the remote-access Client plugin, and the Session and Workspace access
|
|
5
5
|
* Hooks (Session-scope `useAccess`, `useSessionAccess`, `useWorkspaceAccess`)
|
|
6
6
|
* from ui-session and ui-workspace over that service. The test runtimes
|
|
7
7
|
* install an allow-all service and `useRemoteAccess` Hook instead, and
|
|
8
8
|
* hand-built component props spread {@link allowAllAccess}; a spec of a
|
|
9
|
-
* refused path overrides one Hook
|
|
9
|
+
* refused path overrides one Hook or provides a {@link StaticRemoteAccess}
|
|
10
|
+
* that refuses the action.
|
|
10
11
|
* @module @deepseek-ai/dsh-client-test-runtime/src/access
|
|
11
12
|
*/
|
|
12
|
-
import type
|
|
13
|
-
import type {
|
|
13
|
+
import { Service, type Context } from '@deepseek-ai/cordis';
|
|
14
|
+
import type { AccessEffect, ClientRemoteAccess, RemoteEndpoint, TypertResourceKind } from '@deepseek-ai/dsh-api-remote-access/client';
|
|
15
|
+
import type { GlobalStandardProps, HostObservable, SessionStandardProps } from '@deepseek-ai/dsh-client-ui-slots';
|
|
14
16
|
/** The access Hooks every Slot component receives. */
|
|
15
17
|
export type AccessStandardProps = Pick<GlobalStandardProps, 'useRemoteAccess' | 'useSessionAccess' | 'useWorkspaceAccess'> & Pick<SessionStandardProps, 'useAccess'>;
|
|
16
18
|
/** Access Hooks that allow every action on every resource, for hand-built component props. */
|
|
17
19
|
export declare const allowAllAccess: AccessStandardProps;
|
|
18
20
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
21
|
+
* A `remoteAccess` Client service whose answers never change: `allows`
|
|
22
|
+
* decides each action on every resource once. `whenAccess` installs an
|
|
23
|
+
* allowed action's effects in the caller's fiber at once and never installs a
|
|
24
|
+
* refused action's effects.
|
|
23
25
|
*/
|
|
24
|
-
export declare
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
export declare class StaticRemoteAccess extends Service implements ClientRemoteAccess {
|
|
27
|
+
private readonly allows;
|
|
28
|
+
/**
|
|
29
|
+
* @param ctx - Context the service is provided on.
|
|
30
|
+
* @param allows - the fixed answer for each action; allows everything when omitted.
|
|
31
|
+
*/
|
|
32
|
+
constructor(ctx: Context, allows?: (action: string) => boolean);
|
|
33
|
+
source(_kind: TypertResourceKind, _id: string, action: string): HostObservable<boolean>;
|
|
34
|
+
whenAccess(action: RemoteEndpoint, callback: () => AccessEffect): () => void;
|
|
35
|
+
whenResourceAccess(_kind: TypertResourceKind, _id: string, action: RemoteEndpoint, callback: () => AccessEffect): () => void;
|
|
36
|
+
}
|
|
37
|
+
/** The plugin shape {@link staticAccessPlugin} returns. */
|
|
38
|
+
export interface StaticAccessPlugin {
|
|
39
|
+
readonly name: string;
|
|
40
|
+
readonly inject: readonly string[];
|
|
28
41
|
apply(ctx: Context): void;
|
|
29
|
-
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Plugin standing in for the remote-access Client row with fixed answers: it
|
|
45
|
+
* provides a {@link StaticRemoteAccess}, so ui-session and ui-workspace
|
|
46
|
+
* publish their resource Hooks over it, and the matching `useRemoteAccess`
|
|
47
|
+
* Hook on the global resource.
|
|
48
|
+
* @param allows - the fixed answer for each action on every resource.
|
|
49
|
+
* @returns the plugin.
|
|
50
|
+
*/
|
|
51
|
+
export declare function staticAccessPlugin(allows: (action: string) => boolean): StaticAccessPlugin;
|
|
52
|
+
/** {@link staticAccessPlugin} allowing every action on every resource. */
|
|
53
|
+
export declare const allowAllAccessPlugin: StaticAccessPlugin;
|
|
30
54
|
//# sourceMappingURL=access.d.ts.map
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { ClientRoster } from './roster.ts';
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* The `web` profile's bundle layers, in the order `dsh --profile web` applies them
|
|
4
|
+
* (`PROFILE_TEMPLATES.web` in `@deepseek-ai/dsh-official-bundles`).
|
|
5
|
+
*/
|
|
3
6
|
export declare const WEB_PROFILE_BUNDLES: readonly string[];
|
|
4
7
|
/**
|
|
5
8
|
* Compose the browser roster of `bundles`, applied in order.
|
|
@@ -19,6 +19,8 @@ export interface TestClientOptions {
|
|
|
19
19
|
readonly awaitConnected?: boolean;
|
|
20
20
|
/** Readiness budget in milliseconds before `start` rejects with the mock log summary. Default 5000. */
|
|
21
21
|
readonly connectTimeoutMs?: number;
|
|
22
|
+
/** The fixed access answer for each action on every resource. Default: every action is allowed. */
|
|
23
|
+
readonly access?: (action: string) => boolean;
|
|
22
24
|
}
|
|
23
25
|
/** A booted client under test. */
|
|
24
26
|
export declare class TestClient {
|
package/lib/types/index.d.ts
CHANGED
|
@@ -34,8 +34,8 @@ export { RemoteError, TestRemote } from './remote.ts';
|
|
|
34
34
|
export { chatSnapshot, conversationSnapshot, sessionSnapshot, workspaceSnapshot, } from './fixtures.ts';
|
|
35
35
|
export type { FixtureSnapshot, SessionBehaviorOverrides, SessionFixture, SessionFixtureSnapshot, Stabilizer, } from './fixtures.ts';
|
|
36
36
|
export { makeTranslate } from './translate.ts';
|
|
37
|
-
export { allowAllAccess, allowAllAccessPlugin } from './access.ts';
|
|
38
|
-
export type { AccessStandardProps } from './access.ts';
|
|
37
|
+
export { allowAllAccess, allowAllAccessPlugin, StaticRemoteAccess, staticAccessPlugin } from './access.ts';
|
|
38
|
+
export type { AccessStandardProps, StaticAccessPlugin } from './access.ts';
|
|
39
39
|
export { usePinnedBrowserLanguages } from './locale-env.ts';
|
|
40
40
|
/**
|
|
41
41
|
* Bind an observable source to the production renderer's selector hook.
|
|
@@ -90,6 +90,8 @@ export interface FeatureHandle {
|
|
|
90
90
|
export interface TestFileUpload {
|
|
91
91
|
/** Test-supplied upload behavior; the default rejects every call. */
|
|
92
92
|
upload: (sessionId: SessionId, ...args: unknown[]) => Promise<unknown>;
|
|
93
|
+
/** Test-supplied image upload behavior; the default rejects every call. */
|
|
94
|
+
uploadImage: (sessionId: SessionId, ...args: unknown[]) => Promise<unknown>;
|
|
93
95
|
}
|
|
94
96
|
/**
|
|
95
97
|
* The test-owned 'root' occupant: declares the child slots a suite needs
|
package/lib/types/sessions.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Test-owned Session Controller faces over declarative fixtures. */
|
|
2
2
|
import type { Context } from '@deepseek-ai/cordis';
|
|
3
|
-
import type {
|
|
3
|
+
import type { ImageAttachmentRef } from '@deepseek-ai/dsh-attachment';
|
|
4
4
|
import { MutableSessionEventSource } from '@deepseek-ai/dsh-api-session-controller/client';
|
|
5
5
|
import type { AgentContext, ISessions, ProjectionsFace, SessionBinding, SessionFace, SessionListState, SessionEventLikeEntry, SessionLiveEventEntry, SessionSearchResultItem, SessionReference, SessionRetainInfo, SessionRetainOptions, SessionSnapshot, SessionSummary, SessionTarget, SubmissionHandle } from '@deepseek-ai/dsh-api-session-controller/client';
|
|
6
6
|
import type { SubagentAddress } from '@deepseek-ai/dsh-subagent/client';
|
|
@@ -61,10 +61,10 @@ export declare class FixtureSession implements SessionFace {
|
|
|
61
61
|
private submissionSeq;
|
|
62
62
|
/**
|
|
63
63
|
* Fail-loud stub; supply `readAttachment` on the fixture's session face to exercise it.
|
|
64
|
-
* @param
|
|
64
|
+
* @param _attachment - complete durable image reference.
|
|
65
65
|
* @returns never — always throws.
|
|
66
66
|
*/
|
|
67
|
-
readAttachment(
|
|
67
|
+
readAttachment(_attachment: ImageAttachmentRef): never;
|
|
68
68
|
/**
|
|
69
69
|
* Fail-loud stub; supply `updateQueue` on the fixture's session face to exercise it.
|
|
70
70
|
* @returns never — always throws.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepseek-ai/dsh-client-test-runtime",
|
|
3
3
|
"description": "Browser test runtimes: a jsdom slot bench with test-owned Session and Workspace doubles, and a whole-client tier that boots the web roster through the production bootClient over an endpoint-named Remote mock",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.2-alpha.2",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -29,62 +29,62 @@
|
|
|
29
29
|
"vitest": "^4.1.11"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
|
-
"@deepseek-ai/cordis": "~4.0.
|
|
33
|
-
"@deepseek-ai/cordis-plugin-include": "~1.0.
|
|
34
|
-
"@deepseek-ai/cordis-plugin-loader": "~1.0.
|
|
35
|
-
"@deepseek-ai/dsh-api-gateway": "0.2.
|
|
36
|
-
"@deepseek-ai/dsh-api-session-controller": "0.2.
|
|
37
|
-
"@deepseek-ai/dsh-api-workspace-controller": "0.2.
|
|
38
|
-
"@deepseek-ai/dsh-attachment": "0.2.
|
|
39
|
-
"@deepseek-ai/dsh-client-connection": "0.2.
|
|
40
|
-
"@deepseek-ai/dsh-client-hmr": "0.2.
|
|
41
|
-
"@deepseek-ai/dsh-client-modules": "0.2.
|
|
42
|
-
"@deepseek-ai/dsh-client-store": "0.2.
|
|
43
|
-
"@deepseek-ai/dsh-client-ui-chat": "0.2.
|
|
44
|
-
"@deepseek-ai/dsh-client-ui-conversation": "0.2.
|
|
45
|
-
"@deepseek-ai/dsh-client-ui-renderer": "0.2.
|
|
46
|
-
"@deepseek-ai/dsh-client-ui-session": "0.2.
|
|
47
|
-
"@deepseek-ai/dsh-client-ui-settings": "0.2.
|
|
48
|
-
"@deepseek-ai/dsh-client-ui-slots": "0.2.
|
|
49
|
-
"@deepseek-ai/dsh-client-web": "0.2.
|
|
50
|
-
"@deepseek-ai/dsh-remote-mock": "0.2.
|
|
51
|
-
"@deepseek-ai/dsh-session": "0.2.
|
|
52
|
-
"@deepseek-ai/dsh-subagent": "0.2.
|
|
53
|
-
"@deepseek-ai/dsh-typert-protocol": "0.2.
|
|
32
|
+
"@deepseek-ai/cordis": "~4.0.6-alpha.1",
|
|
33
|
+
"@deepseek-ai/cordis-plugin-include": "~1.0.11-alpha.1",
|
|
34
|
+
"@deepseek-ai/cordis-plugin-loader": "~1.0.7-alpha.1",
|
|
35
|
+
"@deepseek-ai/dsh-api-gateway": "0.2.2-alpha.2",
|
|
36
|
+
"@deepseek-ai/dsh-api-session-controller": "0.2.2-alpha.2",
|
|
37
|
+
"@deepseek-ai/dsh-api-workspace-controller": "0.2.2-alpha.2",
|
|
38
|
+
"@deepseek-ai/dsh-attachment": "0.2.2-alpha.2",
|
|
39
|
+
"@deepseek-ai/dsh-client-connection": "0.2.2-alpha.2",
|
|
40
|
+
"@deepseek-ai/dsh-client-hmr": "0.2.2-alpha.2",
|
|
41
|
+
"@deepseek-ai/dsh-client-modules": "0.2.2-alpha.2",
|
|
42
|
+
"@deepseek-ai/dsh-client-store": "0.2.2-alpha.2",
|
|
43
|
+
"@deepseek-ai/dsh-client-ui-chat": "0.2.2-alpha.2",
|
|
44
|
+
"@deepseek-ai/dsh-client-ui-conversation": "0.2.2-alpha.2",
|
|
45
|
+
"@deepseek-ai/dsh-client-ui-renderer": "0.2.2-alpha.2",
|
|
46
|
+
"@deepseek-ai/dsh-client-ui-session": "0.2.2-alpha.2",
|
|
47
|
+
"@deepseek-ai/dsh-client-ui-settings": "0.2.2-alpha.2",
|
|
48
|
+
"@deepseek-ai/dsh-client-ui-slots": "0.2.2-alpha.2",
|
|
49
|
+
"@deepseek-ai/dsh-client-web": "0.2.2-alpha.2",
|
|
50
|
+
"@deepseek-ai/dsh-remote-mock": "0.2.2-alpha.2",
|
|
51
|
+
"@deepseek-ai/dsh-session": "0.2.2-alpha.2",
|
|
52
|
+
"@deepseek-ai/dsh-subagent": "0.2.2-alpha.2",
|
|
53
|
+
"@deepseek-ai/dsh-typert-protocol": "0.2.2-alpha.2",
|
|
54
54
|
"react": "^18.2.0",
|
|
55
55
|
"react-dom": "^18.2.0"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
|
-
"@deepseek-ai/cordis": "~4.0.
|
|
59
|
-
"@deepseek-ai/cordis-plugin-include": "~1.0.
|
|
60
|
-
"@deepseek-ai/cordis-plugin-loader": "~1.0.
|
|
61
|
-
"@deepseek-ai/dsh-api-gateway": "0.2.
|
|
62
|
-
"@deepseek-ai/dsh-api-remote-access": "0.2.
|
|
63
|
-
"@deepseek-ai/dsh-api-remotes": "0.2.
|
|
64
|
-
"@deepseek-ai/dsh-api-session-controller": "0.2.
|
|
65
|
-
"@deepseek-ai/dsh-api-workspace-controller": "0.2.
|
|
66
|
-
"@deepseek-ai/dsh-attachment": "0.2.
|
|
67
|
-
"@deepseek-ai/dsh-base": "0.2.
|
|
68
|
-
"@deepseek-ai/dsh-client-connection": "0.2.
|
|
69
|
-
"@deepseek-ai/dsh-client-hmr": "0.2.
|
|
70
|
-
"@deepseek-ai/dsh-client-locale": "0.2.
|
|
71
|
-
"@deepseek-ai/dsh-client-modules": "0.2.
|
|
72
|
-
"@deepseek-ai/dsh-client-store": "0.2.
|
|
73
|
-
"@deepseek-ai/dsh-client-ui-chat": "0.2.
|
|
74
|
-
"@deepseek-ai/dsh-client-ui-conversation": "0.2.
|
|
75
|
-
"@deepseek-ai/dsh-client-ui-layout": "0.2.
|
|
76
|
-
"@deepseek-ai/dsh-client-ui-renderer": "0.2.
|
|
77
|
-
"@deepseek-ai/dsh-client-ui-session": "0.2.
|
|
78
|
-
"@deepseek-ai/dsh-client-ui-settings": "0.2.
|
|
79
|
-
"@deepseek-ai/dsh-client-ui-slots": "0.2.
|
|
80
|
-
"@deepseek-ai/dsh-client-ui-workspace": "0.2.
|
|
81
|
-
"@deepseek-ai/dsh-client-web": "0.2.
|
|
82
|
-
"@deepseek-ai/dsh-remote-mock": "0.2.
|
|
83
|
-
"@deepseek-ai/dsh-session": "0.2.
|
|
84
|
-
"@deepseek-ai/dsh-settings": "0.2.
|
|
85
|
-
"@deepseek-ai/dsh-subagent": "0.2.
|
|
86
|
-
"@deepseek-ai/dsh-typert-protocol": "0.2.
|
|
87
|
-
"@deepseek-ai/dsh-web-app": "0.2.
|
|
58
|
+
"@deepseek-ai/cordis": "~4.0.6-alpha.1",
|
|
59
|
+
"@deepseek-ai/cordis-plugin-include": "~1.0.11-alpha.1",
|
|
60
|
+
"@deepseek-ai/cordis-plugin-loader": "~1.0.7-alpha.1",
|
|
61
|
+
"@deepseek-ai/dsh-api-gateway": "0.2.2-alpha.2",
|
|
62
|
+
"@deepseek-ai/dsh-api-remote-access": "0.2.2-alpha.2",
|
|
63
|
+
"@deepseek-ai/dsh-api-remotes": "0.2.2-alpha.2",
|
|
64
|
+
"@deepseek-ai/dsh-api-session-controller": "0.2.2-alpha.2",
|
|
65
|
+
"@deepseek-ai/dsh-api-workspace-controller": "0.2.2-alpha.2",
|
|
66
|
+
"@deepseek-ai/dsh-attachment": "0.2.2-alpha.2",
|
|
67
|
+
"@deepseek-ai/dsh-base": "0.2.2-alpha.2",
|
|
68
|
+
"@deepseek-ai/dsh-client-connection": "0.2.2-alpha.2",
|
|
69
|
+
"@deepseek-ai/dsh-client-hmr": "0.2.2-alpha.2",
|
|
70
|
+
"@deepseek-ai/dsh-client-locale": "0.2.2-alpha.2",
|
|
71
|
+
"@deepseek-ai/dsh-client-modules": "0.2.2-alpha.2",
|
|
72
|
+
"@deepseek-ai/dsh-client-store": "0.2.2-alpha.2",
|
|
73
|
+
"@deepseek-ai/dsh-client-ui-chat": "0.2.2-alpha.2",
|
|
74
|
+
"@deepseek-ai/dsh-client-ui-conversation": "0.2.2-alpha.2",
|
|
75
|
+
"@deepseek-ai/dsh-client-ui-layout": "0.2.2-alpha.2",
|
|
76
|
+
"@deepseek-ai/dsh-client-ui-renderer": "0.2.2-alpha.2",
|
|
77
|
+
"@deepseek-ai/dsh-client-ui-session": "0.2.2-alpha.2",
|
|
78
|
+
"@deepseek-ai/dsh-client-ui-settings": "0.2.2-alpha.2",
|
|
79
|
+
"@deepseek-ai/dsh-client-ui-slots": "0.2.2-alpha.2",
|
|
80
|
+
"@deepseek-ai/dsh-client-ui-workspace": "0.2.2-alpha.2",
|
|
81
|
+
"@deepseek-ai/dsh-client-web": "0.2.2-alpha.2",
|
|
82
|
+
"@deepseek-ai/dsh-remote-mock": "0.2.2-alpha.2",
|
|
83
|
+
"@deepseek-ai/dsh-session": "0.2.2-alpha.2",
|
|
84
|
+
"@deepseek-ai/dsh-settings": "0.2.2-alpha.2",
|
|
85
|
+
"@deepseek-ai/dsh-subagent": "0.2.2-alpha.2",
|
|
86
|
+
"@deepseek-ai/dsh-typert-protocol": "0.2.2-alpha.2",
|
|
87
|
+
"@deepseek-ai/dsh-web-app": "0.2.2-alpha.2",
|
|
88
88
|
"@types/js-yaml": "^4.0.9",
|
|
89
89
|
"react": "^18.2.0",
|
|
90
90
|
"react-dom": "^18.2.0"
|