dsh-zen-remote 2.0.1 → 2.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/docs/remote-access.md +6 -0
- package/lan-gate.mjs +15 -1
- package/lib/client.js +16 -9
- package/lib/intercept.js +14 -5
- package/lib/intercept.js.map +1 -1
- package/lib/relay-client.js +21 -2
- package/lib/relay-client.js.map +1 -1
- package/lib/relay-server.js +32 -7
- package/lib/relay-server.js.map +1 -1
- package/lib/types/client/styles/compat.css.d.ts +1 -1
- package/lib/types/client/styles/compat.css.d.ts.map +1 -1
- package/lib/types/client/styles/composer.css.d.ts +1 -1
- package/lib/types/client/styles/composer.css.d.ts.map +1 -1
- package/lib/types/intercept.d.ts.map +1 -1
- package/lib/types/relay-client.d.ts +5 -1
- package/lib/types/relay-client.d.ts.map +1 -1
- package/lib/types/relay-server.d.ts.map +1 -1
- package/package.json +48 -49
- package/src/client/styles/compat.css.ts +14 -8
- package/src/client/styles/composer.css.ts +2 -1
- package/src/intercept.ts +14 -4
- package/src/relay-client.ts +19 -2
- package/src/relay-server.ts +31 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relay-server.d.ts","sourceRoot":"","sources":["../../src/relay-server.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"relay-server.d.ts","sourceRoot":"","sources":["../../src/relay-server.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-zen-remote",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.3",
|
|
4
4
|
"description": "一个插件、两种角色:主服务端把 DeepSeek Harness 变成手机能安全访问的 PWA(移动端界面、配对码网关、Web Push),并把选定会话共享给已配对的桌面端;子客户端在另一台 DSH 桌面端的侧边栏里远程使用这些会话。One DSH plugin, two roles: the host turns DeepSeek Harness into a phone-reachable PWA (mobile UI, pairing-code gateway behind your own reverse proxy, Web Push) and shares chosen sessions to paired desktops; the client uses those sessions remotely from another DSH desktop app's sidebar.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -82,18 +82,18 @@
|
|
|
82
82
|
},
|
|
83
83
|
"peerDependencies": {
|
|
84
84
|
"@deepseek-ai/cordis": "*",
|
|
85
|
-
"@deepseek-ai/dsh-client-locale": "^0.1.7-rc.2 || ^0.2.0-rc.1",
|
|
86
|
-
"@deepseek-ai/dsh-client-ui-conversation": "^0.1.7-rc.2 || ^0.2.0-rc.1",
|
|
87
|
-
"@deepseek-ai/dsh-client-ui-layout": "^0.1.7-rc.2 || ^0.2.0-rc.1",
|
|
88
|
-
"@deepseek-ai/dsh-client-ui-primitives": "^0.1.7-rc.2 || ^0.2.0-rc.1",
|
|
89
|
-
"@deepseek-ai/dsh-client-ui-sidebar": "^0.1.7-rc.2 || ^0.2.0-rc.1",
|
|
90
|
-
"@deepseek-ai/dsh-client-ui-slots": "^0.1.7-rc.2 || ^0.2.0-rc.1",
|
|
91
|
-
"@deepseek-ai/dsh-host-webserver": "^0.1.7-rc.2 || ^0.2.0-rc.1",
|
|
92
|
-
"@deepseek-ai/dsh-session": "^0.1.7-rc.2 || ^0.2.0-rc.1",
|
|
93
|
-
"@deepseek-ai/dsh-session-log-export": "^0.1.7-rc.2 || ^0.2.0-rc.1",
|
|
94
|
-
"@deepseek-ai/dsh-session-query": "^0.1.7-rc.2 || ^0.2.0-rc.1",
|
|
95
|
-
"@deepseek-ai/dsh-tools": "^0.1.7-rc.2 || ^0.2.0-rc.1",
|
|
96
|
-
"@deepseek-ai/dsh-workspace": "^0.1.7-rc.2 || ^0.2.0-rc.1",
|
|
85
|
+
"@deepseek-ai/dsh-client-locale": "^0.1.7-rc.2 || ^0.2.0-rc.1 || ^0.2.1-alpha.1",
|
|
86
|
+
"@deepseek-ai/dsh-client-ui-conversation": "^0.1.7-rc.2 || ^0.2.0-rc.1 || ^0.2.1-alpha.1",
|
|
87
|
+
"@deepseek-ai/dsh-client-ui-layout": "^0.1.7-rc.2 || ^0.2.0-rc.1 || ^0.2.1-alpha.1",
|
|
88
|
+
"@deepseek-ai/dsh-client-ui-primitives": "^0.1.7-rc.2 || ^0.2.0-rc.1 || ^0.2.1-alpha.1",
|
|
89
|
+
"@deepseek-ai/dsh-client-ui-sidebar": "^0.1.7-rc.2 || ^0.2.0-rc.1 || ^0.2.1-alpha.1",
|
|
90
|
+
"@deepseek-ai/dsh-client-ui-slots": "^0.1.7-rc.2 || ^0.2.0-rc.1 || ^0.2.1-alpha.1",
|
|
91
|
+
"@deepseek-ai/dsh-host-webserver": "^0.1.7-rc.2 || ^0.2.0-rc.1 || ^0.2.1-alpha.1",
|
|
92
|
+
"@deepseek-ai/dsh-session": "^0.1.7-rc.2 || ^0.2.0-rc.1 || ^0.2.1-alpha.1",
|
|
93
|
+
"@deepseek-ai/dsh-session-log-export": "^0.1.7-rc.2 || ^0.2.0-rc.1 || ^0.2.1-alpha.1",
|
|
94
|
+
"@deepseek-ai/dsh-session-query": "^0.1.7-rc.2 || ^0.2.0-rc.1 || ^0.2.1-alpha.1",
|
|
95
|
+
"@deepseek-ai/dsh-tools": "^0.1.7-rc.2 || ^0.2.0-rc.1 || ^0.2.1-alpha.1",
|
|
96
|
+
"@deepseek-ai/dsh-workspace": "^0.1.7-rc.2 || ^0.2.0-rc.1 || ^0.2.1-alpha.1",
|
|
97
97
|
"@deepseek-ai/schemastery": "*",
|
|
98
98
|
"react": "^18.2.0"
|
|
99
99
|
},
|
|
@@ -115,43 +115,42 @@
|
|
|
115
115
|
}
|
|
116
116
|
},
|
|
117
117
|
"devDependencies": {
|
|
118
|
-
"@deepseek-ai/cordis": "4.0.
|
|
118
|
+
"@deepseek-ai/cordis": "4.0.5-alpha.1",
|
|
119
119
|
"@deepseek-ai/cosmokit": "1.8.5",
|
|
120
|
-
"@deepseek-ai/dsh-agent": "0.1
|
|
121
|
-
"@deepseek-ai/dsh-api-remotes": "0.1
|
|
122
|
-
"@deepseek-ai/dsh-api-session-controller": "0.1
|
|
123
|
-
"@deepseek-ai/dsh-api-workspace-controller": "0.1
|
|
124
|
-
"@deepseek-ai/dsh-brand": "0.1
|
|
125
|
-
"@deepseek-ai/dsh-client-connection": "0.1
|
|
126
|
-
"@deepseek-ai/dsh-client-locale": "0.1
|
|
127
|
-
"@deepseek-ai/dsh-client-store": "0.1
|
|
128
|
-
"@deepseek-ai/dsh-client-ui-conversation": "0.1
|
|
129
|
-
"@deepseek-ai/dsh-client-ui-layout": "0.1
|
|
130
|
-
"@deepseek-ai/dsh-client-ui-primitives": "0.1
|
|
131
|
-
"@deepseek-ai/dsh-client-ui-renderer": "0.1
|
|
132
|
-
"@deepseek-ai/dsh-client-ui-session": "0.1
|
|
133
|
-
"@deepseek-ai/dsh-client-ui-sidebar": "0.1
|
|
134
|
-
"@deepseek-ai/dsh-client-ui-slots": "0.1
|
|
135
|
-
"@deepseek-ai/dsh-host-webserver": "0.1
|
|
136
|
-
"@deepseek-ai/dsh-
|
|
137
|
-
"@deepseek-ai/dsh-
|
|
138
|
-
"@deepseek-ai/dsh-
|
|
139
|
-
"@deepseek-ai/dsh-sandbox": "0.1
|
|
140
|
-
"@deepseek-ai/dsh-
|
|
141
|
-
"@deepseek-ai/dsh-
|
|
142
|
-
"@deepseek-ai/dsh-session": "0.1
|
|
143
|
-
"@deepseek-ai/dsh-session-
|
|
144
|
-
"@deepseek-ai/dsh-session-
|
|
145
|
-
"@deepseek-ai/dsh-session-
|
|
146
|
-
"@deepseek-ai/dsh-
|
|
147
|
-
"@deepseek-ai/dsh-
|
|
148
|
-
"@deepseek-ai/dsh-
|
|
149
|
-
"@deepseek-ai/dsh-
|
|
150
|
-
"@deepseek-ai/dsh-
|
|
151
|
-
"@deepseek-ai/dsh-
|
|
152
|
-
"@deepseek-ai/dsh-util-
|
|
153
|
-
"@deepseek-ai/dsh-
|
|
154
|
-
"@deepseek-ai/dsh-workspace": "0.1.7-rc.2",
|
|
120
|
+
"@deepseek-ai/dsh-agent": "0.2.1-alpha.2",
|
|
121
|
+
"@deepseek-ai/dsh-api-remotes": "0.2.1-alpha.2",
|
|
122
|
+
"@deepseek-ai/dsh-api-session-controller": "0.2.1-alpha.2",
|
|
123
|
+
"@deepseek-ai/dsh-api-workspace-controller": "0.2.1-alpha.2",
|
|
124
|
+
"@deepseek-ai/dsh-brand": "0.2.1-alpha.2",
|
|
125
|
+
"@deepseek-ai/dsh-client-connection": "0.2.1-alpha.2",
|
|
126
|
+
"@deepseek-ai/dsh-client-locale": "0.2.1-alpha.2",
|
|
127
|
+
"@deepseek-ai/dsh-client-store": "0.2.1-alpha.2",
|
|
128
|
+
"@deepseek-ai/dsh-client-ui-conversation": "0.2.1-alpha.2",
|
|
129
|
+
"@deepseek-ai/dsh-client-ui-layout": "0.2.1-alpha.2",
|
|
130
|
+
"@deepseek-ai/dsh-client-ui-primitives": "0.2.1-alpha.2",
|
|
131
|
+
"@deepseek-ai/dsh-client-ui-renderer": "0.2.1-alpha.2",
|
|
132
|
+
"@deepseek-ai/dsh-client-ui-session": "0.2.1-alpha.2",
|
|
133
|
+
"@deepseek-ai/dsh-client-ui-sidebar": "0.2.1-alpha.2",
|
|
134
|
+
"@deepseek-ai/dsh-client-ui-slots": "0.2.1-alpha.2",
|
|
135
|
+
"@deepseek-ai/dsh-host-webserver": "0.2.1-alpha.2",
|
|
136
|
+
"@deepseek-ai/dsh-llm": "0.2.1-alpha.2",
|
|
137
|
+
"@deepseek-ai/dsh-ptc-runtime": "0.2.1-alpha.2",
|
|
138
|
+
"@deepseek-ai/dsh-sandbox": "0.2.1-alpha.2",
|
|
139
|
+
"@deepseek-ai/dsh-sandbox-policy": "0.2.1-alpha.2",
|
|
140
|
+
"@deepseek-ai/dsh-scope": "0.2.1-alpha.2",
|
|
141
|
+
"@deepseek-ai/dsh-session": "0.2.1-alpha.2",
|
|
142
|
+
"@deepseek-ai/dsh-session-log-export": "0.2.1-alpha.2",
|
|
143
|
+
"@deepseek-ai/dsh-session-projection": "0.2.1-alpha.2",
|
|
144
|
+
"@deepseek-ai/dsh-session-query": "0.2.1-alpha.2",
|
|
145
|
+
"@deepseek-ai/dsh-session-stats": "0.2.1-alpha.2",
|
|
146
|
+
"@deepseek-ai/dsh-subagent": "0.2.1-alpha.2",
|
|
147
|
+
"@deepseek-ai/dsh-timeout": "0.2.1-alpha.2",
|
|
148
|
+
"@deepseek-ai/dsh-token-meter": "0.2.1-alpha.2",
|
|
149
|
+
"@deepseek-ai/dsh-tools": "0.2.1-alpha.2",
|
|
150
|
+
"@deepseek-ai/dsh-typert-protocol": "0.2.1-alpha.2",
|
|
151
|
+
"@deepseek-ai/dsh-util-crypto": "0.2.1-alpha.2",
|
|
152
|
+
"@deepseek-ai/dsh-util-values": "0.2.1-alpha.2",
|
|
153
|
+
"@deepseek-ai/dsh-workspace": "0.2.1-alpha.2",
|
|
155
154
|
"@deepseek-ai/schemastery": "3.18.4",
|
|
156
155
|
"@types/node": "^26.2.0",
|
|
157
156
|
"@types/react": "~18.3.1",
|
|
@@ -440,14 +440,20 @@ export const COMPAT_CSS = ` /* ---------- dsh-web-ui family compatibility -----
|
|
|
440
440
|
cache) is long. It is the single entry the official StatsLine puts in
|
|
441
441
|
conversation.composer.dock, so the structural anchor below reaches it
|
|
442
442
|
without any DOM marking (S3 deleted the text-matching effect that used
|
|
443
|
-
to set
|
|
443
|
+
to set the dock-entry marker). Layout: ONE fixed-height (28px) flex
|
|
444
444
|
strip that scrolls horizontally — the full metrics stream stays
|
|
445
445
|
reachable by swiping, the row never grows vertically, no ellipsis or
|
|
446
446
|
fade, 12px gaps between metric groups, a 2px scrollbar as the swipe
|
|
447
447
|
affordance. The phone breakpoint hides the strip outright instead
|
|
448
448
|
(styles/composer.css.ts — its data moves into the session info card). */
|
|
449
449
|
|
|
450
|
-
|
|
450
|
+
/* Marker set is deliberately dual: 0.2.0-rc.2 renders the strip root with
|
|
451
|
+
data-composer-stats (plural, dsh-client-ui-chat rc.2 lib), 0.2.1-alpha.2
|
|
452
|
+
dropped the strip wrapper and registers activity/usage as separate dock
|
|
453
|
+
entries whose pill spans carry data-composer-stat (singular). Keeping
|
|
454
|
+
both lets this plugin style the strip on a host that has NOT upgraded to
|
|
455
|
+
alpha.2 — verified against both npm tarballs 2026-10-09. */
|
|
456
|
+
[data-slot="conversation.composer.dock"] > :is([data-composer-stat], [data-composer-stats]) {
|
|
451
457
|
display: flex !important;
|
|
452
458
|
flex-flow: row nowrap !important;
|
|
453
459
|
align-items: center !important;
|
|
@@ -469,17 +475,17 @@ export const COMPAT_CSS = ` /* ---------- dsh-web-ui family compatibility -----
|
|
|
469
475
|
line-height: 20px !important;
|
|
470
476
|
font-size: 12px !important;
|
|
471
477
|
}
|
|
472
|
-
[data-slot="conversation.composer.dock"] > [
|
|
478
|
+
[data-slot="conversation.composer.dock"] > :is([data-composer-stat], [data-composer-stats])::-webkit-scrollbar {
|
|
473
479
|
height: 2px !important;
|
|
474
480
|
}
|
|
475
|
-
[data-slot="conversation.composer.dock"] > [
|
|
481
|
+
[data-slot="conversation.composer.dock"] > :is([data-composer-stat], [data-composer-stats])::-webkit-scrollbar-thumb {
|
|
476
482
|
background: var(--dsw-alias-label-tertiary, rgba(0, 0, 0, .3)) !important;
|
|
477
483
|
border-radius: 2px !important;
|
|
478
484
|
}
|
|
479
|
-
[data-slot="conversation.composer.dock"] > [
|
|
485
|
+
[data-slot="conversation.composer.dock"] > :is([data-composer-stat], [data-composer-stats])::-webkit-scrollbar-track {
|
|
480
486
|
background: transparent !important;
|
|
481
487
|
}
|
|
482
|
-
[data-slot="conversation.composer.dock"] > [
|
|
488
|
+
[data-slot="conversation.composer.dock"] > :is([data-composer-stat], [data-composer-stats]) > * {
|
|
483
489
|
display: flex !important;
|
|
484
490
|
flex: 0 0 auto !important;
|
|
485
491
|
flex-flow: row nowrap !important;
|
|
@@ -491,10 +497,10 @@ export const COMPAT_CSS = ` /* ---------- dsh-web-ui family compatibility -----
|
|
|
491
497
|
margin-right: 12px !important;
|
|
492
498
|
padding: 0 !important;
|
|
493
499
|
}
|
|
494
|
-
[data-slot="conversation.composer.dock"] > [
|
|
500
|
+
[data-slot="conversation.composer.dock"] > :is([data-composer-stat], [data-composer-stats]) > *:last-child {
|
|
495
501
|
margin-right: 0 !important;
|
|
496
502
|
}
|
|
497
|
-
[data-slot="conversation.composer.dock"] > [
|
|
503
|
+
[data-slot="conversation.composer.dock"] > :is([data-composer-stat], [data-composer-stats]) * {
|
|
498
504
|
white-space: nowrap !important;
|
|
499
505
|
}
|
|
500
506
|
|
|
@@ -803,7 +803,8 @@ export const COMPOSER_CSS = `/* ---------- phone composer (< 768px) ---------- *
|
|
|
803
803
|
/* --- 8. the official stats strip leaves the composer ---
|
|
804
804
|
Its data moves into the session info card (S4). The row is the composer
|
|
805
805
|
dock's own \`_root\` entry; the slot itself stays live for later entries. */
|
|
806
|
-
[data-slot="conversation.composer.dock"] > [class$="_root"]
|
|
806
|
+
[data-slot="conversation.composer.dock"] > [class$="_root"],
|
|
807
|
+
[data-slot="conversation.composer.dock"] > [data-composer-stat] {
|
|
807
808
|
display: none !important;
|
|
808
809
|
}
|
|
809
810
|
|
package/src/intercept.ts
CHANGED
|
@@ -1100,9 +1100,16 @@ export function rewriteResult(endpoint: string, value: unknown, serverId: string
|
|
|
1100
1100
|
// mergeSessionList rewrite instead, merge-streams.ts.)
|
|
1101
1101
|
if (!isPlainObject(value) || !isPlainObject(value.values)) return value
|
|
1102
1102
|
const values: Record<string, unknown> = { ...value.values }
|
|
1103
|
-
|
|
1103
|
+
// alpha.2 clients validate list/control projections with kind:'cached'|'sequenced'.
|
|
1104
|
+
// Older hosts (rc.2) omit it on the session/projections control-key result — synthesize.
|
|
1105
|
+
const withKind = typeof value.kind === 'string'
|
|
1106
|
+
? value
|
|
1107
|
+
: (typeof value.asOfSeq === 'number' ? { ...value, kind: 'sequenced' as const } : value)
|
|
1108
|
+
if (!Object.hasOwn(values, 'modelSelection')) {
|
|
1109
|
+
return withKind === value ? value : { ...withKind, values }
|
|
1110
|
+
}
|
|
1104
1111
|
values.modelSelection = virtualizeModelSelectionValue(values.modelSelection, serverId)
|
|
1105
|
-
return { ...
|
|
1112
|
+
return { ...withKind, values }
|
|
1106
1113
|
}
|
|
1107
1114
|
if (endpoint === 'session/selectModel') {
|
|
1108
1115
|
// T52: the result echoes the selection it accepted (`{selected:
|
|
@@ -2637,7 +2644,10 @@ export function installIntercept(options: InstallInterceptOptions): InterceptHan
|
|
|
2637
2644
|
return { ok: true, value: undefined }
|
|
2638
2645
|
}
|
|
2639
2646
|
recordFailure(endpoint, code)
|
|
2640
|
-
|
|
2647
|
+
// The host's sanitized `details` rides along when present — its
|
|
2648
|
+
// `reason` codes (MODEL_DOES_NOT_SUPPORT_IMAGES, …) are what the UI
|
|
2649
|
+
// maps onto a user-facing line; without them it prints `undefined`.
|
|
2650
|
+
return { ok: false, error: { code, message: messageOf(error), details: error instanceof RelayError && isPlainObject(error.details) ? error.details : {} } }
|
|
2641
2651
|
}
|
|
2642
2652
|
})()
|
|
2643
2653
|
}
|
|
@@ -2696,7 +2706,7 @@ export function installIntercept(options: InstallInterceptOptions): InterceptHan
|
|
|
2696
2706
|
// A call on a closed session reads like the banner, not like the
|
|
2697
2707
|
// relay's bare code (T73).
|
|
2698
2708
|
const message = code === 'not-shared' ? CLOSED_MESSAGE : messageOf(error)
|
|
2699
|
-
return { ok: false, error: { code, message, details: {} } }
|
|
2709
|
+
return { ok: false, error: { code, message, details: error instanceof RelayError && isPlainObject(error.details) ? error.details : {} } }
|
|
2700
2710
|
}
|
|
2701
2711
|
}
|
|
2702
2712
|
|
package/src/relay-client.ts
CHANGED
|
@@ -197,16 +197,33 @@ export class RelayError extends Error {
|
|
|
197
197
|
code: string
|
|
198
198
|
status?: number
|
|
199
199
|
reason?: string
|
|
200
|
+
/** The host error's sanitized `details` (invoke path): the UI maps
|
|
201
|
+
* `details.reason` codes like `MODEL_DOES_NOT_SUPPORT_IMAGES` onto a
|
|
202
|
+
* user-facing line — absent details stay undefined. */
|
|
203
|
+
details?: Record<string, unknown>
|
|
200
204
|
|
|
201
|
-
constructor(code: string, message?: string, httpStatus?: number, reason?: string) {
|
|
205
|
+
constructor(code: string, message?: string, httpStatus?: number, reason?: string, details?: Record<string, unknown>) {
|
|
202
206
|
super(message === undefined ? code : message)
|
|
203
207
|
this.name = 'RelayError'
|
|
204
208
|
this.code = code
|
|
205
209
|
if (httpStatus !== undefined) this.status = httpStatus
|
|
206
210
|
if (reason !== undefined) this.reason = reason
|
|
211
|
+
if (details !== undefined) this.details = details
|
|
207
212
|
}
|
|
208
213
|
}
|
|
209
214
|
|
|
215
|
+
/** The error body's structured `details`, when it is a record of scalars —
|
|
216
|
+
* the shape the server's own sanitizer emits. */
|
|
217
|
+
function detailsOf(error: Record<string, unknown>): Record<string, unknown> | undefined {
|
|
218
|
+
const raw = error.details
|
|
219
|
+
if (!isRecord(raw)) return undefined
|
|
220
|
+
const out: Record<string, unknown> = {}
|
|
221
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
222
|
+
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean' || value === null) out[key] = value
|
|
223
|
+
}
|
|
224
|
+
return Object.keys(out).length > 0 ? out : undefined
|
|
225
|
+
}
|
|
226
|
+
|
|
210
227
|
export interface CreateRelayClientOptions {
|
|
211
228
|
/** The normalized server address (no trailing slash), read live per
|
|
212
229
|
* request; `undefined` counts as unpaired. */
|
|
@@ -948,7 +965,7 @@ export function createRelayClient(options: CreateRelayClientOptions): RelayClien
|
|
|
948
965
|
// 200 {ok:false} envelopes, 400/404/429 answers and anything else
|
|
949
966
|
// unheard-of: the body's error code is the answer, the state is not
|
|
950
967
|
// touched.
|
|
951
|
-
if (code !== undefined) return new RelayError(code, message, status)
|
|
968
|
+
if (code !== undefined) return new RelayError(code, message, status, undefined, detailsOf(error))
|
|
952
969
|
// The bad-gateway band carries no relay body of its own — it is what a
|
|
953
970
|
// reverse proxy answers when the gateway behind it is down (nginx: an
|
|
954
971
|
// HTML 502). That IS the offline case, and the e2e contract expects it.
|
package/src/relay-server.ts
CHANGED
|
@@ -611,6 +611,16 @@ function drainUpload(req: IncomingMessage, fromBytes: number, deadlineMs: number
|
|
|
611
611
|
})
|
|
612
612
|
}
|
|
613
613
|
|
|
614
|
+
|
|
615
|
+
/** The 200 error envelope for a failed gateway call, `details` included when
|
|
616
|
+
* the host error carried a sanitized one (see errorOf). */
|
|
617
|
+
function errorEnvelopeOf(error: unknown): { ok: false; error: Record<string, unknown> } {
|
|
618
|
+
const { code, message, details } = errorOf(error)
|
|
619
|
+
const inner: Record<string, unknown> = message === undefined ? { code } : { code, message }
|
|
620
|
+
if (details !== undefined) inner.details = details
|
|
621
|
+
return { ok: false, error: inner }
|
|
622
|
+
}
|
|
623
|
+
|
|
614
624
|
/**
|
|
615
625
|
* What may travel to the client about a failed gateway call. DSH's own errors
|
|
616
626
|
* always carry a `namespace/name`-shaped string `code` — those pass through
|
|
@@ -618,7 +628,7 @@ function drainUpload(req: IncomingMessage, fromBytes: number, deadlineMs: number
|
|
|
618
628
|
* error whose `code` (`ENOENT`, …) and message (`… '/Users/x/…'`) quote the
|
|
619
629
|
* server's filesystem — reports `internal` and NO message at all (T22a-fix).
|
|
620
630
|
*/
|
|
621
|
-
function errorOf(error: unknown): { code: string; message?: string } {
|
|
631
|
+
function errorOf(error: unknown): { code: string; message?: string; details?: Record<string, unknown> } {
|
|
622
632
|
const code =
|
|
623
633
|
error !== null && typeof error === 'object' && typeof (error as { code?: unknown }).code === 'string'
|
|
624
634
|
? (error as { code: string }).code
|
|
@@ -629,7 +639,23 @@ function errorOf(error: unknown): { code: string; message?: string } {
|
|
|
629
639
|
// error would, so only the code travels.
|
|
630
640
|
if (code.endsWith('/internal')) return { code }
|
|
631
641
|
const text = error instanceof Error ? error.message : String(error)
|
|
632
|
-
|
|
642
|
+
// The structured `details` beside code/message (2026-10-10): the host
|
|
643
|
+
// rejects an image-bearing prompt with `session/attachment-invalid` whose
|
|
644
|
+
// `details.reason` (`MODEL_DOES_NOT_SUPPORT_IMAGES`, …) is what the client
|
|
645
|
+
// UI maps onto a user-facing line — dropped here, the UI prints
|
|
646
|
+
// `undefined`. Scalars and clipped strings only, bounded key count;
|
|
647
|
+
// nested objects/arrays stay out so server internals cannot ride this.
|
|
648
|
+
const raw = (error as { details?: unknown }).details
|
|
649
|
+
const details: Record<string, unknown> = {}
|
|
650
|
+
if (isPlainObject(raw)) {
|
|
651
|
+
for (const [key, value] of Object.entries(raw).slice(0, 16)) {
|
|
652
|
+
if (typeof value === 'string') details[key] = value.slice(0, MAX_MESSAGE_CHARS)
|
|
653
|
+
else if (typeof value === 'number' || typeof value === 'boolean' || value === null) details[key] = value
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
const out: { code: string; message?: string; details?: Record<string, unknown> } = { code, message: text.slice(0, MAX_MESSAGE_CHARS) }
|
|
657
|
+
if (Object.keys(details).length > 0) out.details = details
|
|
658
|
+
return out
|
|
633
659
|
}
|
|
634
660
|
|
|
635
661
|
/**
|
|
@@ -1117,8 +1143,7 @@ export function createRelayHandler(options: RelayHandlerOptions): RelayHandler {
|
|
|
1117
1143
|
)) as unknown
|
|
1118
1144
|
responseJson(res, 200, isPlainObject(envelope) ? envelope : { ok: false, error: { code: 'internal' } })
|
|
1119
1145
|
} catch (error) {
|
|
1120
|
-
|
|
1121
|
-
responseJson(res, 200, message === undefined ? { ok: false, error: { code } } : { ok: false, error: { code, message } })
|
|
1146
|
+
responseJson(res, 200, errorEnvelopeOf(error))
|
|
1122
1147
|
} finally {
|
|
1123
1148
|
res.off('close', onClientGone)
|
|
1124
1149
|
}
|
|
@@ -1266,8 +1291,7 @@ export function createRelayHandler(options: RelayHandlerOptions): RelayHandler {
|
|
|
1266
1291
|
// The gateway's own failures (unknown namespace, absent service) are
|
|
1267
1292
|
// business answers, not transport errors: they ride a 200 envelope
|
|
1268
1293
|
// like every other result, with the gateway's string code preserved.
|
|
1269
|
-
|
|
1270
|
-
responseJson(res, 200, message === undefined ? { ok: false, error: { code } } : { ok: false, error: { code, message } })
|
|
1294
|
+
responseJson(res, 200, errorEnvelopeOf(error))
|
|
1271
1295
|
} finally {
|
|
1272
1296
|
res.off('close', onClientGone)
|
|
1273
1297
|
// The invoke is over — answered, refused mid-flight, or its client
|
|
@@ -1927,8 +1951,7 @@ export function createRelayHandler(options: RelayHandlerOptions): RelayHandler {
|
|
|
1927
1951
|
// DOCUMENTED normal end, swallowed whole.
|
|
1928
1952
|
closeWith(null)
|
|
1929
1953
|
} else {
|
|
1930
|
-
|
|
1931
|
-
closeWith(message === undefined ? { type: 'error', error: { code } } : { type: 'error', error: { code, message } })
|
|
1954
|
+
closeWith({ type: 'error', error: errorEnvelopeOf(error).error })
|
|
1932
1955
|
}
|
|
1933
1956
|
} finally {
|
|
1934
1957
|
openStreamKills.delete(killThisStream)
|