dsh-remote-bridge 2.6.0 → 2.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +52 -11
- package/README.md +47 -10
- package/docs/api/asyncapi.yaml +1 -1
- package/docs/api/openapi.yaml +51 -4
- package/kotlin-sdk/src/main/kotlin/ai/deepseek/dsh/workspace/DshWorkspaceClient.kt +6 -0
- package/lib/client.cjs +103 -30
- package/lib/index.d.ts +123 -3
- package/lib/index.js +584 -39
- package/package.json +1 -1
package/lib/index.d.ts
CHANGED
|
@@ -26,6 +26,24 @@ interface DeviceView {
|
|
|
26
26
|
createdAt: number;
|
|
27
27
|
lastSeenAt?: number;
|
|
28
28
|
revokedAt?: number;
|
|
29
|
+
/**
|
|
30
|
+
* 设备自称/被推断出的平台与型号(`android` / `harmonyos` / …)。
|
|
31
|
+
*
|
|
32
|
+
* **可选**:老设备从未上报过就是 `undefined`,客户端必须能接受缺省。
|
|
33
|
+
* 这两个字段只用于界面显示与排查,**不参与任何授权判断** —— 它们是客户端
|
|
34
|
+
* 自称的,不是可信身份。
|
|
35
|
+
*/
|
|
36
|
+
platform?: string;
|
|
37
|
+
model?: string;
|
|
38
|
+
/**
|
|
39
|
+
* `name` 是怎么来的,决定后续能不能自动改名。
|
|
40
|
+
*
|
|
41
|
+
* - `default`:配对时的占位名(`'Android 设备'` 之类)。设备第一次带身份
|
|
42
|
+
* 连上来时**允许**被自动改成「平台 · 型号」。
|
|
43
|
+
* - `detected`:由探测到的身份自动生成。后续身份变了仍可再自动更新。
|
|
44
|
+
* - `declared`:用户手工改的。**永不再自动覆盖** —— 用户起的名比机器猜的准。
|
|
45
|
+
*/
|
|
46
|
+
nameSource?: 'default' | 'detected' | 'declared';
|
|
29
47
|
}
|
|
30
48
|
interface FileEntryView {
|
|
31
49
|
name: string;
|
|
@@ -179,6 +197,7 @@ declare class WorkspaceDatabase {
|
|
|
179
197
|
*/
|
|
180
198
|
exchangePairing(code: string, deviceName: string, options?: {
|
|
181
199
|
requestId?: string;
|
|
200
|
+
nameSource?: 'default' | 'declared';
|
|
182
201
|
}): {
|
|
183
202
|
token: string;
|
|
184
203
|
device: DeviceView;
|
|
@@ -186,6 +205,47 @@ declare class WorkspaceDatabase {
|
|
|
186
205
|
authenticate(token: string): AuthenticatedDevice | undefined;
|
|
187
206
|
getActiveDevice(id: string): AuthenticatedDevice | undefined;
|
|
188
207
|
private hydrateDevice;
|
|
208
|
+
/**
|
|
209
|
+
* 记录一次探测到的设备身份,必要时顺手把占位名改成「平台 · 型号」。
|
|
210
|
+
*
|
|
211
|
+
* 时序说明:配对时桥只知道「有个设备要连」,真正的平台与型号要等设备
|
|
212
|
+
* **第一次发请求**才拿得到。所以这个方法由认证路径调用(见 `auth.ts`
|
|
213
|
+
* 的 `principal`),而不是配对路径。
|
|
214
|
+
*
|
|
215
|
+
* ## 什么时候改名
|
|
216
|
+
*
|
|
217
|
+
* 只有 `name_source` 是 `default`(配对时的占位名)或 `detected`(上次自动
|
|
218
|
+
* 生成的)才改名。`declared`(用户手工改的)**永不动** —— 用户起的名比机器
|
|
219
|
+
* 猜的准,而且他能改一次就能改第二次,但机器每次连接都覆盖就再也留不住了。
|
|
220
|
+
*
|
|
221
|
+
* 老库的 `name_source` 是 NULL:那些行里的名字多半是硬编码的「Android 设备」,
|
|
222
|
+
* 但**也可能是用户手工改过的**(此前没有任何改名通道,所以实际上只有占位名;
|
|
223
|
+
* 不过万一有人直接改过库,我们不能替他决定)。保守起见把 NULL 当作
|
|
224
|
+
* `declared` 处理 —— 名字不动,只补 platform/model 两列。
|
|
225
|
+
*
|
|
226
|
+
* ## 为什么不做成「每次请求都写库」
|
|
227
|
+
*
|
|
228
|
+
* 调用方只在**探测结果与库里不同**时才调这里(见 `auth.ts`),所以正常情况
|
|
229
|
+
* 下一台设备一生只写一次。这不是性能考虑,而是避免把一次读请求变成写请求:
|
|
230
|
+
* 写请求会碰 WAL、会影响 `devicesRevisionCounter`,进而触发全体客户端重拉设备表。
|
|
231
|
+
*
|
|
232
|
+
* @returns 是否真的改了库(调用方据此决定要不要递增设备版本号)。
|
|
233
|
+
*/
|
|
234
|
+
recordDeviceIdentity(id: string, identity: {
|
|
235
|
+
platform?: string;
|
|
236
|
+
model?: string;
|
|
237
|
+
suggestedName?: string;
|
|
238
|
+
}): boolean;
|
|
239
|
+
/**
|
|
240
|
+
* 用户手工改名。
|
|
241
|
+
*
|
|
242
|
+
* 一旦走这条路,`name_source` 就变成 `declared`,此后任何自动探测都**不再**
|
|
243
|
+
* 覆盖它。这是「用户意图优先于机器推断」的唯一实现点,所以单独一个方法而不是
|
|
244
|
+
* 塞进 `updateDevice`:权限变更与改名是两件不同的事,审计动作也不该混。
|
|
245
|
+
*/
|
|
246
|
+
renameDevice(id: string, name: string, options?: {
|
|
247
|
+
requestId?: string;
|
|
248
|
+
}): DeviceView;
|
|
189
249
|
listDevices(): DeviceView[];
|
|
190
250
|
isDeviceActive(id: string): boolean;
|
|
191
251
|
/**
|
|
@@ -333,6 +393,9 @@ declare class WorkspaceDatabase {
|
|
|
333
393
|
private dropRootsUniqueConstraint;
|
|
334
394
|
/** `roots` 表是否已有指定列。 */
|
|
335
395
|
private hasRootColumn;
|
|
396
|
+
/** `devices` 表是否已有指定列。 */
|
|
397
|
+
private hasDeviceColumn;
|
|
398
|
+
private hasColumn;
|
|
336
399
|
}
|
|
337
400
|
//#endregion
|
|
338
401
|
//#region src/host/settings-namespace.d.ts
|
|
@@ -553,9 +616,13 @@ declare class DshSettingsAdapter {
|
|
|
553
616
|
/**
|
|
554
617
|
* @param options.writeNamespaces 额外允许手机端写入的设置命名空间(精确 ns 或
|
|
555
618
|
* `前缀*`),与内置策略(`ui-*` / 以 `locale` 结尾)叠加;默认为空。
|
|
619
|
+
* @param options.allowPrivateProviderHosts 允许供应商 `baseURL` 指向的私网 / 回环
|
|
620
|
+
* host 白名单(默认空 = 一律拒绝)。要连本地 LLM 的部署方显式填,理由见
|
|
621
|
+
* `provider-url-policy.ts` 文件头。
|
|
556
622
|
*/
|
|
557
623
|
constructor(api: SettingsApiProxy, options?: {
|
|
558
624
|
writeNamespaces?: readonly string[];
|
|
625
|
+
allowPrivateProviderHosts?: readonly string[];
|
|
559
626
|
});
|
|
560
627
|
/**
|
|
561
628
|
* 列出全部设置命名空间(通用设置面的读侧)。
|
|
@@ -572,6 +639,8 @@ declare class DshSettingsAdapter {
|
|
|
572
639
|
*/
|
|
573
640
|
mutateNamespace(ns: string, ops: unknown, expectedRevision?: number): Promise<SettingsNamespaceEntry>;
|
|
574
641
|
private get writeNamespaces();
|
|
642
|
+
/** 交给地址策略的选项;集中一处,三个入口不会各配各的。 */
|
|
643
|
+
private get baseURLOptions();
|
|
575
644
|
/** 内核 settings 服务缺失时给 503(而不是把 `TypeError` 漏成 500)。 */
|
|
576
645
|
private settingsService;
|
|
577
646
|
listProviders(): Promise<{
|
|
@@ -587,14 +656,38 @@ declare class DshSettingsAdapter {
|
|
|
587
656
|
message: string;
|
|
588
657
|
}[];
|
|
589
658
|
}>;
|
|
590
|
-
|
|
591
|
-
|
|
659
|
+
/**
|
|
660
|
+
* 更新供应商配置。
|
|
661
|
+
*
|
|
662
|
+
* 返回 `baseURLHost`(仅当本次 patch 动了 `baseURL` 时存在)供路由层写审计:
|
|
663
|
+
* 攻击者可以用 discover 把凭据发到任意地址,事后必须能从审计里看出「打了哪」。
|
|
664
|
+
* 只记 host 不记完整 URL —— path/query 可能带凭据,审计表不该成为新的泄露点。
|
|
665
|
+
*/
|
|
666
|
+
updateProvider(providerId: string, patch: ProviderPatch): Promise<{
|
|
667
|
+
baseURLHost?: string;
|
|
668
|
+
}>;
|
|
669
|
+
createProvider(input: CustomProviderCreate): Promise<{
|
|
670
|
+
baseURLHost: string;
|
|
671
|
+
}>;
|
|
592
672
|
removeProvider(providerId: string, expectedRevision?: number): Promise<void>;
|
|
673
|
+
/**
|
|
674
|
+
* 发现供应商可用模型。
|
|
675
|
+
*
|
|
676
|
+
* `draft.baseURL` 是**临时覆盖**(不写配置),但内核会带着该供应商已配置的真实
|
|
677
|
+
* 凭据去请求它 —— 这正是 SEC-H11 的窃取路径:攻击者把自己的服务器填进来即可收到
|
|
678
|
+
* `Authorization: Bearer <真实 key>`。因此临时覆盖与持久化写入过同一道地址策略。
|
|
679
|
+
*
|
|
680
|
+
* 返回 `baseURLHost` 供路由层审计;不传 `baseURL` 时(用配置里的地址)同样返回,
|
|
681
|
+
* 这样「打了哪个地址」在任何情况下都能追溯。
|
|
682
|
+
*/
|
|
593
683
|
discover(providerId: string, draft: {
|
|
594
684
|
baseURL?: string;
|
|
595
685
|
api?: string;
|
|
596
686
|
apiKey?: string;
|
|
597
|
-
}): Promise<
|
|
687
|
+
}): Promise<{
|
|
688
|
+
models: ProviderModelView[];
|
|
689
|
+
baseURLHost?: string;
|
|
690
|
+
}>;
|
|
598
691
|
/**
|
|
599
692
|
* 取一个 provider 的上下文(目录条目 + 设置命名空间 + 当前 profile)。
|
|
600
693
|
*
|
|
@@ -622,6 +715,13 @@ declare class DshSettingsAdapter {
|
|
|
622
715
|
*/
|
|
623
716
|
private invalidateProviderContext;
|
|
624
717
|
private loadProviderContext;
|
|
718
|
+
/**
|
|
719
|
+
* 该供应商当前是否已经存了凭据。
|
|
720
|
+
*
|
|
721
|
+
* 单独一次 `credentials.describe` 只在「要换 baseURL host」时才调 —— 那是罕见路径,
|
|
722
|
+
* 而正常保存(改 models / 显示名 / 协议)不该为此多付一次内核往返。
|
|
723
|
+
*/
|
|
724
|
+
private providerHoldsCredential;
|
|
625
725
|
}
|
|
626
726
|
//#endregion
|
|
627
727
|
//#region src/host/dsh-0.2-bridge.d.ts
|
|
@@ -1927,6 +2027,14 @@ declare class AuthService {
|
|
|
1927
2027
|
principal(req: IncomingMessage, options?: {
|
|
1928
2028
|
allowAdmin?: boolean;
|
|
1929
2029
|
}): Principal;
|
|
2030
|
+
/**
|
|
2031
|
+
* 把本次请求探测到的身份记进库,并(在允许时)更新设备显示名。
|
|
2032
|
+
*
|
|
2033
|
+
* 吞掉一切异常的理由见调用点注释:设备名是显示信息,不该成为连接的前置条件。
|
|
2034
|
+
*
|
|
2035
|
+
* @returns 改名成功时的新名字;没改名(或探测不到)时 `undefined`。
|
|
2036
|
+
*/
|
|
2037
|
+
private recordIdentity;
|
|
1930
2038
|
/**
|
|
1931
2039
|
* `/manage/**` 的守门人。
|
|
1932
2040
|
*
|
|
@@ -2696,6 +2804,18 @@ interface Config {
|
|
|
2696
2804
|
* 遥控器交出去(理由见 docs/project/SECURITY.md)。
|
|
2697
2805
|
*/
|
|
2698
2806
|
settingsWriteNamespaces?: readonly string[];
|
|
2807
|
+
/**
|
|
2808
|
+
* 允许供应商 `baseURL` 指向的私网 / 回环 host 白名单(默认空 = 一律拒绝)。
|
|
2809
|
+
*
|
|
2810
|
+
* 默认拒绝的理由:手机端改 `baseURL` 就等于把模型请求(含 `Authorization:
|
|
2811
|
+
* Bearer <真实 key>`)引到任意地址,这是 SEC-H11 的窃取路径。默认拒绝把
|
|
2812
|
+
* 「谁能连内网」变成部署方的显式决定。
|
|
2813
|
+
*
|
|
2814
|
+
* 要连本地 LLM(ollama / LM Studio 之类)时填这里,推荐带端口:
|
|
2815
|
+
* `["127.0.0.1:11434", "localhost:1234"]`。带端口的条目只放行该端口,裸
|
|
2816
|
+
* host 条目放行该主机的任意端口(面更大)。规则见 `src/host/provider-url-policy.ts`。
|
|
2817
|
+
*/
|
|
2818
|
+
allowPrivateProviderHosts?: readonly string[];
|
|
2699
2819
|
}
|
|
2700
2820
|
interface HostContext extends Dsh02HostServices {
|
|
2701
2821
|
webServer: Parameters<typeof attachEmbeddedRoutes>[0];
|