dsh-zen-remote 1.1.11 → 1.1.13
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/AGENTS.md +24 -0
- package/README.md +7 -3
- package/README.zh-CN.md +7 -3
- package/docs/interface.md +5 -2
- package/dsh-push.mjs +25 -1
- package/lan-gate.mjs +16 -1
- package/lib/client.js +684 -43
- package/lib/lan-gate-server.cjs +107 -4
- package/lib/types/client/MobileHome.d.ts +7 -2
- package/lib/types/client/MobileHome.d.ts.map +1 -1
- package/lib/types/client/MobileSessionInfo.d.ts +2 -2
- package/lib/types/client/MobileSessionInfo.d.ts.map +1 -1
- package/lib/types/client/compat/store.d.ts +62 -0
- package/lib/types/client/compat/store.d.ts.map +1 -0
- package/lib/types/client/compat/types.d.ts +84 -0
- package/lib/types/client/compat/types.d.ts.map +1 -0
- package/lib/types/client/debug.d.ts +1 -1
- package/lib/types/client/debug.d.ts.map +1 -1
- package/lib/types/client/effects/aionui-compat.d.ts +1 -1
- package/lib/types/client/effects/aionui-compat.d.ts.map +1 -1
- package/lib/types/client/effects/gestures.d.ts +1 -1
- package/lib/types/client/effects/gestures.d.ts.map +1 -1
- package/lib/types/client/effects/header-status.d.ts +1 -1
- package/lib/types/client/effects/header-status.d.ts.map +1 -1
- package/lib/types/client/effects/keyboard-avoid.d.ts +1 -1
- package/lib/types/client/effects/keyboard-avoid.d.ts.map +1 -1
- package/lib/types/client/effects/keyboard-guard.d.ts +1 -1
- package/lib/types/client/effects/keyboard-guard.d.ts.map +1 -1
- package/lib/types/client/effects/modal-back.d.ts +1 -1
- package/lib/types/client/effects/modal-back.d.ts.map +1 -1
- package/lib/types/client/effects/model-sheet-extras.d.ts +33 -0
- package/lib/types/client/effects/model-sheet-extras.d.ts.map +1 -0
- package/lib/types/client/effects/native-trigger-overlay.d.ts +1 -1
- package/lib/types/client/effects/native-trigger-overlay.d.ts.map +1 -1
- package/lib/types/client/effects/phone-chrome.d.ts +1 -1
- package/lib/types/client/effects/phone-chrome.d.ts.map +1 -1
- package/lib/types/client/effects/turn-fold.d.ts +1 -1
- package/lib/types/client/effects/turn-fold.d.ts.map +1 -1
- package/lib/types/client/effects/welcome-notice.d.ts +1 -1
- package/lib/types/client/effects/welcome-notice.d.ts.map +1 -1
- package/lib/types/client/effects/workbench-ref-close.d.ts +1 -1
- package/lib/types/client/effects/workbench-ref-close.d.ts.map +1 -1
- package/lib/types/client/index.d.ts +1 -1
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/nav-store.d.ts +2 -2
- package/lib/types/client/nav-store.d.ts.map +1 -1
- package/lib/types/client/session-dot.d.ts +11 -3
- package/lib/types/client/session-dot.d.ts.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/client/styles/info.css.d.ts +1 -1
- package/lib/types/client/styles/info.css.d.ts.map +1 -1
- package/package.json +49 -26
- package/pwa/app.css +47 -7
- package/scripts/check-client-externals.mjs +48 -0
- package/scripts/check-compat-store.mjs +113 -0
- package/scripts/check-host-shadow.mjs +145 -0
- package/scripts/check-info-sheet-stacking.mjs +55 -0
- package/src/client/MobileAttachButton.tsx +1 -1
- package/src/client/MobileHome.tsx +33 -7
- package/src/client/MobileSessionInfo.tsx +6 -4
- package/src/client/chips-store.ts +1 -1
- package/src/client/compat/store.ts +205 -0
- package/src/client/compat/types.ts +115 -0
- package/src/client/debug.ts +1 -1
- package/src/client/effects/aionui-compat.ts +1 -1
- package/src/client/effects/gestures.ts +1 -1
- package/src/client/effects/header-status.ts +22 -3
- package/src/client/effects/keyboard-avoid.ts +1 -1
- package/src/client/effects/keyboard-guard.ts +1 -1
- package/src/client/effects/modal-back.ts +1 -1
- package/src/client/effects/model-sheet-extras.ts +159 -0
- package/src/client/effects/native-trigger-overlay.ts +1 -1
- package/src/client/effects/phone-chrome.ts +1 -1
- package/src/client/effects/turn-fold.ts +1 -1
- package/src/client/effects/welcome-notice.ts +1 -1
- package/src/client/effects/workbench-ref-close.ts +1 -1
- package/src/client/index.tsx +70 -6
- package/src/client/nav-store.ts +2 -2
- package/src/client/session-dot.ts +13 -4
- package/src/client/styles/compat.css.ts +43 -11
- package/src/client/styles/composer.css.ts +184 -9
- package/src/client/styles/info.css.ts +21 -0
package/lib/lan-gate-server.cjs
CHANGED
|
@@ -51,6 +51,16 @@ const LISTEN_HOST = cfg('LAN_GATE_HOST', 'host', '127.0.0.1')
|
|
|
51
51
|
const RATE_LIMIT_PER_MIN = Number(cfg('LAN_GATE_RATE_LIMIT', 'rateLimit', 120))
|
|
52
52
|
const TARGET_HOST = '127.0.0.1'
|
|
53
53
|
const TARGET_PORT = Number(cfg('LAN_GATE_TARGET_PORT', 'targetPort', 3080))
|
|
54
|
+
// 0.1.2 browser auth: the host half hands us a one-use token URL via env.
|
|
55
|
+
// ABSENT env = 0.1.1 mode — every auth-exchange branch below short-circuits
|
|
56
|
+
// and proxying behaves exactly as before. Only the token value is kept (and
|
|
57
|
+
// never written to any response, log, or state file).
|
|
58
|
+
var UPSTREAM_TOKEN = null
|
|
59
|
+
;(function () {
|
|
60
|
+
var url = process.env.LAN_GATE_UPSTREAM_TOKEN_URL
|
|
61
|
+
if (!url) return
|
|
62
|
+
try { UPSTREAM_TOKEN = new URL(url).searchParams.get('token') || null } catch (e) { UPSTREAM_TOKEN = null }
|
|
63
|
+
})()
|
|
54
64
|
const TRUSTED_PROXIES = String(cfg('LAN_GATE_TRUSTED_PROXIES', 'trustedProxies', '')).split(',').map(function (s) { return s.trim() }).filter(Boolean)
|
|
55
65
|
// UI language for the pages this file serves. "auto" (default) follows the
|
|
56
66
|
// requesting browser's Accept-Language, which is the only language signal a
|
|
@@ -248,7 +258,12 @@ const COPY = {
|
|
|
248
258
|
kindDesktop: '电脑',
|
|
249
259
|
chipTitle: '设备配对管理',
|
|
250
260
|
chipText: '配对管理',
|
|
251
|
-
turnEnd: 'DSH 任务完成'
|
|
261
|
+
turnEnd: 'DSH 任务完成',
|
|
262
|
+
tapH1: '需要再点一次',
|
|
263
|
+
tapBody: '从外部应用打开的链接还没登录这个浏览器。点下面的站内链接一次即可进入。',
|
|
264
|
+
tapOpen: '打开 DSH 界面',
|
|
265
|
+
upstreamToken: 'DSH 上游鉴权:token(自动交换)',
|
|
266
|
+
upstreamNone: 'DSH 上游鉴权:无(0.1.1 直连模式)'
|
|
252
267
|
},
|
|
253
268
|
en: {
|
|
254
269
|
pairH1: 'Device Pairing',
|
|
@@ -287,7 +302,12 @@ const COPY = {
|
|
|
287
302
|
kindDesktop: 'Desktop',
|
|
288
303
|
chipTitle: 'Device Pairing Admin',
|
|
289
304
|
chipText: 'Pairing Admin',
|
|
290
|
-
turnEnd: 'DSH task finished'
|
|
305
|
+
turnEnd: 'DSH task finished',
|
|
306
|
+
tapH1: 'Tap once to continue',
|
|
307
|
+
tapBody: 'A link opened from another app has not logged this browser in yet. Tap the in-page link below once to enter.',
|
|
308
|
+
tapOpen: 'Open DSH',
|
|
309
|
+
upstreamToken: 'Upstream auth: token (auto exchange)',
|
|
310
|
+
upstreamNone: 'Upstream auth: none (0.1.1 direct mode)'
|
|
291
311
|
}
|
|
292
312
|
}
|
|
293
313
|
function copyOf(lang) { return COPY[lang] || COPY.zh }
|
|
@@ -313,15 +333,25 @@ function rateLimitPage(lang) {
|
|
|
313
333
|
return gatePage(lang, C.rateH1 + ' · DSH', '<div class="logo">DSH</div><h1>' + C.rateH1 + '</h1><p class="bad">' + C.rateBody.replace('{n}', RATE_LIMIT_PER_MIN) + '</p>')
|
|
314
334
|
}
|
|
315
335
|
|
|
336
|
+
// Strict-cookie guard: a cross-app top-level navigation never carries the
|
|
337
|
+
// SameSite=Strict cookie, so after one exchange round-trip the retry marker
|
|
338
|
+
// still 401s. Looping again would be an infinite redirect — instead serve a
|
|
339
|
+
// same-site page whose link, once tapped, IS same-site navigation and sends
|
|
340
|
+
// the cookie. href = the ORIGINAL path with the retry marker stripped.
|
|
341
|
+
function tapThroughPage(lang, target) {
|
|
342
|
+
var C = copyOf(lang)
|
|
343
|
+
return gatePage(lang, C.tapH1 + ' · DSH', '<div class="logo">DSH</div><h1>' + C.tapH1 + '</h1><p class="sub">' + C.tapBody + '</p><a class="btn" href="' + target + '">' + C.tapOpen + '</a>')
|
|
344
|
+
}
|
|
345
|
+
|
|
316
346
|
function adminPage(lang) {
|
|
317
347
|
var C = copyOf(lang)
|
|
318
|
-
return '<!doctype html><html lang="' + (lang === 'zh' ? 'zh-CN' : 'en') + '"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="theme-color" content="#0f1115"><title>' + C.adminTitle + '</title><style>*{box-sizing:border-box}html,body{margin:0;padding:0}body{min-height:100dvh;font-family:system-ui,-apple-system,"Segoe UI","PingFang SC","Microsoft YaHei",sans-serif;background:radial-gradient(1100px 700px at 50% -10%,#1b2233 0%,#0f1115 55%);color:#e6e8ec;padding:20px 16px 30px}.card{width:100%;max-width:560px;margin:0 auto;padding:28px 24px 24px;border:1px solid #2a2f3a;border-radius:20px;background:#161a22;box-shadow:0 20px 60px rgba(0,0,0,.45)}.head{display:flex;align-items:center;gap:12px;margin-bottom:18px}.logo{width:44px;height:44px;flex:none;border-radius:13px;background:linear-gradient(135deg,#4c8dff,#7a5cff);display:flex;align-items:center;justify-content:center;font-size:19px;font-weight:700;color:#fff}h1{font-size:19px;margin:0}.sub{font-size:13px;color:#9aa3b2;margin:2px 0 0}.badge{display:inline-flex;align-items:center;gap:6px;font-size:12px;border-radius:999px;padding:3px 10px;border:1px solid #2a2f3a;color:#9aa3b2;margin:0 0 14px}.badge b{width:8px;height:8px;border-radius:50%;background:#34d399;box-shadow:0 0 8px #34d399}.label{font-size:13px;font-weight:600;margin:18px 0 8px}.code{font-family:ui-monospace,Consolas,monospace;font-size:26px;letter-spacing:6px;color:#9cc0ff;background:#0b0e14;border:1px solid #232a37;border-radius:10px;padding:12px 16px;text-align:center;margin:6px 0}.item{padding:10px 0;border-bottom:1px solid #232a37}.item:last-child{border-bottom:none}.name{font-size:14px;font-weight:600}.muted{font-size:12px;color:#9aa3b2;margin:3px 0;word-break:break-all}.row{display:flex;align-items:center;gap:8px;margin-top:8px;flex-wrap:wrap}.btn{font-size:13px;border:1px solid #2f3748;background:transparent;color:#e6e8ec;border-radius:9px;padding:7px 14px;cursor:pointer}.btn:active{background:#222838}.btn-primary{border-color:#4c8dff;color:#9cc0ff;background:rgba(76,141,255,.08)}.btn-danger{border-color:#f0716f;color:#f0716f}.kind{font-size:12px;border:1px solid #2f3748;background:transparent;color:#9aa3b2;border-radius:999px;padding:5px 12px;cursor:pointer}.kind.on{border-color:#4c8dff;color:#9cc0ff;background:rgba(76,141,255,.08)}.empty{font-size:13px;color:#9aa3b2;text-align:center;padding:12px 0}.note{font-size:12px;color:#6b7280;line-height:1.7;margin:16px 0 0}.err{color:#f0716f;font-size:13px}</style></head><body><div class="card"><div class="head"><div class="logo">DSH</div><div><h1>' + C.adminH1 + '</h1><p class="sub">' + C.adminSub + '</p></div></div><span class="badge"><b></b>' + C.running + ' · 127.0.0.1:' + PROXY_PORT + ' → DSH ' + TARGET_PORT + '</span>' +
|
|
348
|
+
return '<!doctype html><html lang="' + (lang === 'zh' ? 'zh-CN' : 'en') + '"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="theme-color" content="#0f1115"><title>' + C.adminTitle + '</title><style>*{box-sizing:border-box}html,body{margin:0;padding:0}body{min-height:100dvh;font-family:system-ui,-apple-system,"Segoe UI","PingFang SC","Microsoft YaHei",sans-serif;background:radial-gradient(1100px 700px at 50% -10%,#1b2233 0%,#0f1115 55%);color:#e6e8ec;padding:20px 16px 30px}.card{width:100%;max-width:560px;margin:0 auto;padding:28px 24px 24px;border:1px solid #2a2f3a;border-radius:20px;background:#161a22;box-shadow:0 20px 60px rgba(0,0,0,.45)}.head{display:flex;align-items:center;gap:12px;margin-bottom:18px}.logo{width:44px;height:44px;flex:none;border-radius:13px;background:linear-gradient(135deg,#4c8dff,#7a5cff);display:flex;align-items:center;justify-content:center;font-size:19px;font-weight:700;color:#fff}h1{font-size:19px;margin:0}.sub{font-size:13px;color:#9aa3b2;margin:2px 0 0}.badge{display:inline-flex;align-items:center;gap:6px;font-size:12px;border-radius:999px;padding:3px 10px;border:1px solid #2a2f3a;color:#9aa3b2;margin:0 0 14px}.badge b{width:8px;height:8px;border-radius:50%;background:#34d399;box-shadow:0 0 8px #34d399}.label{font-size:13px;font-weight:600;margin:18px 0 8px}.code{font-family:ui-monospace,Consolas,monospace;font-size:26px;letter-spacing:6px;color:#9cc0ff;background:#0b0e14;border:1px solid #232a37;border-radius:10px;padding:12px 16px;text-align:center;margin:6px 0}.item{padding:10px 0;border-bottom:1px solid #232a37}.item:last-child{border-bottom:none}.name{font-size:14px;font-weight:600}.muted{font-size:12px;color:#9aa3b2;margin:3px 0;word-break:break-all}.row{display:flex;align-items:center;gap:8px;margin-top:8px;flex-wrap:wrap}.btn{font-size:13px;border:1px solid #2f3748;background:transparent;color:#e6e8ec;border-radius:9px;padding:7px 14px;cursor:pointer}.btn:active{background:#222838}.btn-primary{border-color:#4c8dff;color:#9cc0ff;background:rgba(76,141,255,.08)}.btn-danger{border-color:#f0716f;color:#f0716f}.kind{font-size:12px;border:1px solid #2f3748;background:transparent;color:#9aa3b2;border-radius:999px;padding:5px 12px;cursor:pointer}.kind.on{border-color:#4c8dff;color:#9cc0ff;background:rgba(76,141,255,.08)}.empty{font-size:13px;color:#9aa3b2;text-align:center;padding:12px 0}.note{font-size:12px;color:#6b7280;line-height:1.7;margin:16px 0 0}.err{color:#f0716f;font-size:13px}</style></head><body><div class="card"><div class="head"><div class="logo">DSH</div><div><h1>' + C.adminH1 + '</h1><p class="sub">' + C.adminSub + '</p></div></div><span class="badge"><b></b>' + C.running + ' · 127.0.0.1:' + PROXY_PORT + ' → DSH ' + TARGET_PORT + '</span><div class="muted" id="authline"></div>' +
|
|
319
349
|
'<div class="label">' + C.codeLabel + '</div><div id="pair" class="empty">' + C.codeEmpty + '</div><div class="row"><button class="btn btn-primary" data-act="new-code">' + C.codeNew + '</button></div><p class="note">' + C.codeNote + '</p>' +
|
|
320
350
|
'<div class="label">' + C.devLabel + '</div><div id="devices" class="empty">' + C.loading + '</div>' +
|
|
321
351
|
'<div class="row" style="margin-top:14px"><button class="btn btn-danger" data-act="revoke-all">' + C.revokeAll + '</button></div>' +
|
|
322
352
|
'<p class="note">' + C.devNote + '</p><div id="err"></div></div><script>' + copyScript(lang) +
|
|
323
353
|
'var KIND={auto:C.kindAuto,phone:C.kindPhone,desktop:C.kindDesktop};function post(body){return fetch("/lan-gate/action",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(body)}).then(function(){refresh()}).catch(function(){})}function esc(s){return String(s==null?"":s).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function fmt(ms){return ms?new Date(ms).toLocaleString():""}' +
|
|
324
|
-
'function render(s){var pairEl=document.getElementById("pair");if(s.pairing&&s.pairing.code){pairEl.innerHTML="<div class=\\"code\\">"+esc(s.pairing.code)+"</div><div class=\\"muted\\">"+C.validUntil+fmt(s.pairing.expiresAt)+"</div>";pairEl.className=""}else{pairEl.textContent=C.codeGone;pairEl.className="empty"}' +
|
|
354
|
+
'function render(s){var al=document.getElementById("authline");if(al)al.textContent=s.upstreamAuth==="token"?C.upstreamToken:C.upstreamNone;var pairEl=document.getElementById("pair");if(s.pairing&&s.pairing.code){pairEl.innerHTML="<div class=\\"code\\">"+esc(s.pairing.code)+"</div><div class=\\"muted\\">"+C.validUntil+fmt(s.pairing.expiresAt)+"</div>";pairEl.className=""}else{pairEl.textContent=C.codeGone;pairEl.className="empty"}' +
|
|
325
355
|
'var ds=s.devices||[],h="";if(!ds.length)h="<div class=\\"empty\\">"+C.noDevices+"</div>";for(var i=0;i<ds.length;i++){var d=ds[i];var kb="";var ks=["auto","phone","desktop"];for(var j=0;j<ks.length;j++){var k=ks[j];kb+="<button class=\\"kind"+(d.kind===k?" on":"")+"\\" data-act=\\"set-kind\\" data-id=\\""+esc(d.id)+"\\" data-kind=\\""+k+"\\">"+KIND[k]+"</button>"}h+="<div class=\\"item\\"><div class=\\"name\\">"+esc(d.name)+(d.hasPush?" · 🔔":"")+"</div><div class=\\"muted\\">"+esc(d.ua||"")+"</div><div class=\\"muted\\">"+C.paired+fmt(d.createdAt)+" · "+C.lastSeen+fmt(d.lastSeen)+"</div><div class=\\"row\\">"+kb+"<button class=\\"btn btn-danger\\" data-act=\\"revoke\\" data-id=\\""+esc(d.id)+"\\">"+C.revoke+"</button></div></div>"}document.getElementById("devices").innerHTML=h}' +
|
|
326
356
|
'function refresh(){fetch("/lan-gate/status").then(function(r){return r.json()}).then(render).catch(function(){var e=document.getElementById("err");if(e)e.innerHTML="<div class=\\"err\\">"+C.statusErr+"</div>"})}' +
|
|
327
357
|
'document.addEventListener("click",function(ev){var el=ev.target;if(!el||!el.getAttribute)return;var act=el.getAttribute("data-act");if(!act)return;if(act==="new-code"){post({action:"new-code"});return}if(act==="set-kind"){post({action:"set-kind",id:el.getAttribute("data-id"),kind:el.getAttribute("data-kind")});return}if(act==="revoke"){post({action:"revoke",id:el.getAttribute("data-id")});return}if(act==="revoke-all"){post({action:"revoke-all"});return}});refresh();setInterval(refresh,3000);' +
|
|
@@ -338,6 +368,8 @@ function statusHandler(req, res) {
|
|
|
338
368
|
devices.sort(function (a, b) { return (b.lastSeen || 0) - (a.lastSeen || 0) })
|
|
339
369
|
json(req, res, 200, {
|
|
340
370
|
state: 'running', port: PROXY_PORT, target: TARGET_HOST + ':' + TARGET_PORT, pwa: true,
|
|
371
|
+
// 0.1.2 浏览器鉴权模式:token 存在 = 自动交换;缺失 = 0.1.1 直连。只报有无。
|
|
372
|
+
upstreamAuth: UPSTREAM_TOKEN === null ? 'none' : 'token',
|
|
341
373
|
pairing: (pairing && pairing.expiresAt > Date.now()) ? pairing : null,
|
|
342
374
|
devices: devices, pushSubscriptions: Object.keys(state.pushSubscriptions).length
|
|
343
375
|
})
|
|
@@ -601,9 +633,80 @@ function cleanHeaders(req, clientIp) {
|
|
|
601
633
|
return out
|
|
602
634
|
}
|
|
603
635
|
|
|
636
|
+
// --- 0.1.2 browser-auth exchange --------------------------------------------
|
|
637
|
+
// DSH 0.1.2 requires a signed cookie even for the homepage. The gateway
|
|
638
|
+
// "plays courier": when the upstream 401s an HTML navigation, it does one
|
|
639
|
+
// `GET /?token=…` on the client's behalf (Host still rewritten to loopback,
|
|
640
|
+
// so the authority the cookie binds to is the same one DSH validates) and
|
|
641
|
+
// hands the resulting set-cookie straight back with a 303 to the client's
|
|
642
|
+
// original path + a retry marker. The marker breaks the SameSite=Strict
|
|
643
|
+
// dead-loop: a marked request that STILL 401s (cross-app navigation) gets the
|
|
644
|
+
// tap-through page instead of another redirect.
|
|
645
|
+
var AUTH_RETRY_MARKER = 'dsh-auth-retry=1'
|
|
646
|
+
function hasAuthRetry(url) {
|
|
647
|
+
var q = String(url || '').indexOf('?')
|
|
648
|
+
if (q < 0) return false
|
|
649
|
+
return String(url).slice(q + 1).split('&').indexOf(AUTH_RETRY_MARKER) >= 0
|
|
650
|
+
}
|
|
651
|
+
function addAuthRetry(url) {
|
|
652
|
+
return String(url || '/') + (String(url || '').indexOf('?') >= 0 ? '&' : '?') + AUTH_RETRY_MARKER
|
|
653
|
+
}
|
|
654
|
+
function stripAuthRetry(url) {
|
|
655
|
+
var u = String(url || '/')
|
|
656
|
+
var q = u.indexOf('?')
|
|
657
|
+
if (q < 0) return u
|
|
658
|
+
var rest = u.slice(q + 1).split('&').filter(function (p) { return p !== AUTH_RETRY_MARKER })
|
|
659
|
+
return rest.length ? u.slice(0, q) + '?' + rest.join('&') : u.slice(0, q)
|
|
660
|
+
}
|
|
661
|
+
function isHtmlNavigation(req) {
|
|
662
|
+
return req.method === 'GET'
|
|
663
|
+
&& String(req.headers.accept || '').indexOf('text/html') >= 0
|
|
664
|
+
&& String(req.url || '').split('?')[0].indexOf('/api/') !== 0
|
|
665
|
+
}
|
|
666
|
+
function serveTapThrough(req, res, rejectedUpRes) {
|
|
667
|
+
try { if (rejectedUpRes) rejectedUpRes.resume() } catch (e) {}
|
|
668
|
+
sendHtml(req, res, 200, tapThroughPage(langOf(req), stripAuthRetry(req.url || '/')))
|
|
669
|
+
}
|
|
670
|
+
function attemptAuthExchange(req, res, client, rejectedUpRes) {
|
|
671
|
+
// Free the rejected 401 socket before making the follow-up request.
|
|
672
|
+
try { rejectedUpRes.resume() } catch (e) {}
|
|
673
|
+
var exchangeHeaders = cleanHeaders({ headers: { accept: 'text/html' } }, client.ip)
|
|
674
|
+
var exchange = http.request({
|
|
675
|
+
host: TARGET_HOST, port: TARGET_PORT, method: 'GET',
|
|
676
|
+
path: '/?token=' + encodeURIComponent(UPSTREAM_TOKEN),
|
|
677
|
+
headers: exchangeHeaders
|
|
678
|
+
}, function (xRes) {
|
|
679
|
+
var xc = xRes.statusCode || 0
|
|
680
|
+
var cookies = xRes.headers['set-cookie']
|
|
681
|
+
if (xc >= 300 && xc < 400 && cookies && cookies.length) {
|
|
682
|
+
// The token worked: pass the upstream cookie through verbatim and send
|
|
683
|
+
// the client back to its original path, marked once.
|
|
684
|
+
var out = { location: addAuthRetry(req.url), 'set-cookie': cookies }
|
|
685
|
+
try { res.writeHead(303, out) } catch (e2) {}
|
|
686
|
+
res.end()
|
|
687
|
+
return
|
|
688
|
+
}
|
|
689
|
+
// Token exchange failed too: guard page, never another redirect.
|
|
690
|
+
serveTapThrough(req, res)
|
|
691
|
+
})
|
|
692
|
+
exchange.on('error', function () {
|
|
693
|
+
try { if (!res.headersSent) res.writeHead(502, { 'Content-Type': 'text/plain; charset=utf-8' }); res.end('Bad Gateway') } catch (e) {}
|
|
694
|
+
})
|
|
695
|
+
exchange.end()
|
|
696
|
+
}
|
|
697
|
+
|
|
604
698
|
function forwardRequest(req, res, client, device, isLocal) {
|
|
605
699
|
var headers = cleanHeaders(req, client.ip)
|
|
606
700
|
var upstream = http.request({ host: TARGET_HOST, port: TARGET_PORT, method: req.method, path: req.url, headers: headers }, function (upRes) {
|
|
701
|
+
// 0.1.2 browser auth: an HTML navigation that upstream 401s is either
|
|
702
|
+
// exchanged for a cookie (first try) or, when the retry marker says we
|
|
703
|
+
// already tried, answered with the tap-through page — never a 401 body
|
|
704
|
+
// handed to a phone that cannot act on it, and never a second redirect.
|
|
705
|
+
if (UPSTREAM_TOKEN !== null && upRes.statusCode === 401 && isHtmlNavigation(req)) {
|
|
706
|
+
if (hasAuthRetry(req.url)) { serveTapThrough(req, res, upRes); return }
|
|
707
|
+
attemptAuthExchange(req, res, client, upRes)
|
|
708
|
+
return
|
|
709
|
+
}
|
|
607
710
|
var outHeaders = {}; for (var k in upRes.headers) outHeaders[k] = upRes.headers[k]
|
|
608
711
|
// upRes is already de-chunked by the http client; forwarding hop-by-hop
|
|
609
712
|
// framing headers would produce an invalid (or double-framed) response.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { PropsLocale, PropsRuntime, PropsStore } from '@deepseek-ai/dsh-client-ui-slots';
|
|
2
|
-
import type { SessionId, WorkspaceId } from '
|
|
2
|
+
import type { SessionId, UsePendingInteractions, WorkspaceId } from './compat/types.ts';
|
|
3
3
|
import { NS } from './locales.ts';
|
|
4
4
|
import type { createNavStore } from './nav-store.ts';
|
|
5
5
|
/** Full props for the phone home screen (shell.overlay entry). */
|
|
@@ -12,6 +12,11 @@ export type MobileHomeProps = PropsRuntime<'shell.overlay'> & PropsStore<ReturnT
|
|
|
12
12
|
downloadSessionLog: (id: SessionId) => void;
|
|
13
13
|
/** Bound ctx.workspaces.archiveSession(id) — the row swipe action. */
|
|
14
14
|
archiveSession: (id: SessionId) => Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* 0.1.2 的待处理交互选择器标准 prop;0.1.1 没有这个 prop,运行时读到
|
|
17
|
+
* undefined(见组件里 EMPTY_PENDING_HOOK 兜底)。
|
|
18
|
+
*/
|
|
19
|
+
useSessionPendingInteraction?: UsePendingInteractions;
|
|
15
20
|
};
|
|
16
21
|
/**
|
|
17
22
|
* Phone home screen: the full-screen session list that owns the first level
|
|
@@ -22,5 +27,5 @@ export type MobileHomeProps = PropsRuntime<'shell.overlay'> & PropsStore<ReturnT
|
|
|
22
27
|
* all navigation from the injected official actions; nothing here reads the
|
|
23
28
|
* official DOM.
|
|
24
29
|
*/
|
|
25
|
-
export declare function MobileHome({ useSessions, useWorkspaces, useStore, actions, openSession, startSession, downloadSessionLog, archiveSession, t, }: MobileHomeProps): import("react").JSX.Element | null;
|
|
30
|
+
export declare function MobileHome({ useSessions, useWorkspaces, useSessionPendingInteraction, useStore, actions, openSession, startSession, downloadSessionLog, archiveSession, t, }: MobileHomeProps): import("react").JSX.Element | null;
|
|
26
31
|
//# sourceMappingURL=MobileHome.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MobileHome.d.ts","sourceRoot":"","sources":["../../../src/client/MobileHome.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAA;
|
|
1
|
+
{"version":3,"file":"MobileHome.d.ts","sourceRoot":"","sources":["../../../src/client/MobileHome.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAA;AAU7F,OAAO,KAAK,EAAoB,SAAS,EAAE,sBAAsB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACzG,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAA;AAMjC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAMpD,kEAAkE;AAClE,MAAM,MAAM,eAAe,GACvB,YAAY,CAAC,eAAe,CAAC,GAC7B,UAAU,CAAC,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC,GAC7C,WAAW,CAAC,OAAO,EAAE,CAAC,GACtB;IACA,mCAAmC;IACnC,WAAW,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,IAAI,CAAA;IACpC,uDAAuD;IACvD,YAAY,EAAE,CAAC,WAAW,CAAC,EAAE,WAAW,KAAK,IAAI,CAAA;IACjD,2EAA2E;IAC3E,kBAAkB,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,IAAI,CAAA;IAC3C,sEAAsE;IACtE,cAAc,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAChD;;;OAGG;IACH,4BAA4B,CAAC,EAAE,sBAAsB,CAAA;CACtD,CAAA;AAgNH;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,EACzB,WAAW,EACX,aAAa,EACb,4BAA4B,EAC5B,QAAQ,EACR,OAAO,EACP,WAAW,EACX,YAAY,EACZ,kBAAkB,EAClB,cAAc,EACd,CAAC,GACF,EAAE,eAAe,sCAqRjB"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
|
|
2
|
-
import type {
|
|
2
|
+
import type { RenameResult, SessionId } from './compat/types.ts';
|
|
3
3
|
import { NS } from './locales.ts';
|
|
4
4
|
/** Full props for the session-info sheet (header.utilities, second entry). */
|
|
5
5
|
export type MobileSessionInfoProps = PropsRuntime<'conversation.session.header.utilities'> & PropsLocale<typeof NS> & {
|
|
@@ -8,7 +8,7 @@ export type MobileSessionInfoProps = PropsRuntime<'conversation.session.header.u
|
|
|
8
8
|
/** Bound ctx.sessions.open(id) — lands on the freshly forked session. */
|
|
9
9
|
openSession: (id: SessionId) => void;
|
|
10
10
|
/** Bound ctx.sessions.binding(id)?.session.rename(title); undefined when the binding is gone. */
|
|
11
|
-
renameSession: (sessionId: SessionId, title: string) =>
|
|
11
|
+
renameSession: (sessionId: SessionId, title: string) => RenameResult | undefined;
|
|
12
12
|
/** Bound ctx.workspaces.archiveSession(sessionId). */
|
|
13
13
|
archiveSession: (sessionId: SessionId) => Promise<void>;
|
|
14
14
|
/** Bound ctx.sessionLogDownload.download(sessionId) — owns its own progress/result modal. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MobileSessionInfo.d.ts","sourceRoot":"","sources":["../../../src/client/MobileSessionInfo.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;
|
|
1
|
+
{"version":3,"file":"MobileSessionInfo.d.ts","sourceRoot":"","sources":["../../../src/client/MobileSessionInfo.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AAUjF,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAChE,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAA;AAiBjC,8EAA8E;AAC9E,MAAM,MAAM,sBAAsB,GAC9B,YAAY,CAAC,uCAAuC,CAAC,GACrD,WAAW,CAAC,OAAO,EAAE,CAAC,GACtB;IACA,4CAA4C;IAC5C,WAAW,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,OAAO,CAAC,SAAS,CAAC,CAAA;IACzD,yEAAyE;IACzE,WAAW,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,IAAI,CAAA;IACpC,iGAAiG;IACjG,aAAa,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,KAAK,YAAY,GAAG,SAAS,CAAA;IAChF,sDAAsD;IACtD,cAAc,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACvD,6FAA6F;IAC7F,kBAAkB,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAC5D,CAAA;AA0CH;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,SAAS,EACT,WAAW,EACX,aAAa,EACb,WAAW,EACX,WAAW,EACX,aAAa,EACb,cAAc,EACd,kBAAkB,EAClB,CAAC,GACF,EAAE,sBAAsB,sCAuNxB"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { ActionsDecl, StoreHandle, StoreSpec } from '@deepseek-ai/dsh-client-ui-slots';
|
|
2
|
+
/** Writable snapshot source: read + subscribe + mutate/wholesale-set. */
|
|
3
|
+
export interface SnapshotStore<T> {
|
|
4
|
+
/** Read the current state. Same reference every time until an update. */
|
|
5
|
+
getSnapshot(): T;
|
|
6
|
+
/**
|
|
7
|
+
* Subscribe to state changes.
|
|
8
|
+
* @param fn - invalidation callback.
|
|
9
|
+
* @returns unsubscribe function.
|
|
10
|
+
*/
|
|
11
|
+
subscribe(fn: () => void): () => void;
|
|
12
|
+
/**
|
|
13
|
+
* Mutate the state through a draft.
|
|
14
|
+
* @param mutator - draft mutator.
|
|
15
|
+
*/
|
|
16
|
+
update(mutator: (draft: T) => void): void;
|
|
17
|
+
/** Replace the state wholesale. @param next - next state. */
|
|
18
|
+
set(next: T): void;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Create a snapshot store with optional whole-value localStorage persistence.
|
|
22
|
+
* The 0.1.1 `opts.flush: 'raf' | 'sync'` mode is deliberately not
|
|
23
|
+
* implemented: this plugin never used it (chips-store.ts persists
|
|
24
|
+
* synchronously and React reads via useSyncExternalStore).
|
|
25
|
+
* @param init - initial state.
|
|
26
|
+
* @param opts - optional persistence key.
|
|
27
|
+
* @returns the store.
|
|
28
|
+
*/
|
|
29
|
+
export declare function createSnapshotStore<T>(init: T, opts?: {
|
|
30
|
+
persist?: {
|
|
31
|
+
name: string;
|
|
32
|
+
};
|
|
33
|
+
}): SnapshotStore<T>;
|
|
34
|
+
/**
|
|
35
|
+
* Declare a store: an init lambda (fresh state per instance), an optional
|
|
36
|
+
* persistence key, and the full write set as pure draft mutators. Returns
|
|
37
|
+
* the registration currency of the slot system's store seat.
|
|
38
|
+
*
|
|
39
|
+
* The `A & ActionsDecl<T>` actions position is load-bearing: T resolves from
|
|
40
|
+
* `init` in the first inference round, and the intersection then
|
|
41
|
+
* contextually types each mutator's draft parameter, so call sites write
|
|
42
|
+
* `(draft, view: MobileView) => { … }` without annotating the draft. Keep
|
|
43
|
+
* the intersection — dropping it makes nav-store.ts fail to typecheck.
|
|
44
|
+
*
|
|
45
|
+
* Persist-key rules mirror the official defineStore: `decl.persist` alone at
|
|
46
|
+
* root scope, suffixed with `.{scopeKey}` per session scope, none when
|
|
47
|
+
* `decl.persist` is absent.
|
|
48
|
+
* @param decl - init/persist/actions declaration.
|
|
49
|
+
* @returns the store handle.
|
|
50
|
+
*/
|
|
51
|
+
export declare function defineStore<T, A extends ActionsDecl<T>>(decl: StoreSpec<T, A> & {
|
|
52
|
+
actions: A & ActionsDecl<T>;
|
|
53
|
+
}): StoreHandle<T, A>;
|
|
54
|
+
/**
|
|
55
|
+
* Last path segment of a workspace directory, for showing "which workspace
|
|
56
|
+
* is this session in" on the mobile info card. 0.1.1's one-line
|
|
57
|
+
* implementation, kept verbatim.
|
|
58
|
+
* @param cwd - a workspace path (posix or windows separators).
|
|
59
|
+
* @returns the trailing name, or '' when no non-empty segment exists.
|
|
60
|
+
*/
|
|
61
|
+
export declare function workspaceTitleOf(cwd: string): string;
|
|
62
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../../src/client/compat/store.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EACV,WAAW,EAEX,WAAW,EAEX,SAAS,EACV,MAAM,kCAAkC,CAAA;AAEzC,yEAAyE;AACzE,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,yEAAyE;IACzE,WAAW,IAAI,CAAC,CAAA;IAChB;;;;OAIG;IACH,SAAS,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAA;IACrC;;;OAGG;IACH,MAAM,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAAG,IAAI,CAAA;IACzC,6DAA6D;IAC7D,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,CAAA;CACnB;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EACnC,IAAI,EAAE,CAAC,EACP,IAAI,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GACpC,aAAa,CAAC,CAAC,CAAC,CA4DlB;AAcD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,CAAC,SAAS,WAAW,CAAC,CAAC,CAAC,EACrD,IAAI,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG;IAAE,OAAO,EAAE,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAAA;CAAE,GACtD,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,CA2CnB;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEpD"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { SessionId } from '@deepseek-ai/dsh-session/types';
|
|
3
|
+
import type { WorkspaceId } from '@deepseek-ai/dsh-workspace/types';
|
|
4
|
+
/**
|
|
5
|
+
* Browser-half cordis context. 0.1.1's `dsh-client-runtime` exported
|
|
6
|
+
* `ClientContext` as the bare `Context` type (lib/types/client/index.d.ts:55);
|
|
7
|
+
* 0.1.2 has no such alias. Re-declared here under the same name so the
|
|
8
|
+
* dozen files that used it only change their import path, not the
|
|
9
|
+
* identifier.
|
|
10
|
+
*/
|
|
11
|
+
export type ClientContext = Context;
|
|
12
|
+
/** Session id. Both versions ship it in `@deepseek-ai/dsh-session/types`; re-exported to collect import points. */
|
|
13
|
+
export type { SessionId };
|
|
14
|
+
/** Workspace id. 0.1.2 lives in `@deepseek-ai/dsh-workspace/types`. */
|
|
15
|
+
export type { WorkspaceId };
|
|
16
|
+
/**
|
|
17
|
+
* Structural mirror of the session-row fields this plugin reads, valid
|
|
18
|
+
* against both versions' `SessionSummary`. Deliberately NOT imported from
|
|
19
|
+
* either version (see the file header): `projectionValues` stays `unknown`
|
|
20
|
+
* rather than copying the host's
|
|
21
|
+
* `Readonly<Partial<SessionProjectionMap>>` — that type differs between
|
|
22
|
+
* versions and fights assignments under `exactOptionalPropertyTypes`. The
|
|
23
|
+
* single read site (MobileHome.tsx:311) already casts.
|
|
24
|
+
*
|
|
25
|
+
* `agentPreset` and `pendingInteraction` are intentionally absent: their
|
|
26
|
+
* real readers (MobileHome.tsx, MobileSessionInfo.tsx) receive rows typed by
|
|
27
|
+
* the host's devDeps (0.1.2), not by this mirror, so fields here would not
|
|
28
|
+
* help them — use {@link agentPresetOf} / {@link hasPendingInteraction}
|
|
29
|
+
* instead.
|
|
30
|
+
*/
|
|
31
|
+
export interface MobileSessionRow {
|
|
32
|
+
id: SessionId;
|
|
33
|
+
title?: string;
|
|
34
|
+
displayTitle: string;
|
|
35
|
+
cwd?: string;
|
|
36
|
+
parentId?: SessionId;
|
|
37
|
+
origin?: 'subagent';
|
|
38
|
+
running: boolean;
|
|
39
|
+
completed?: boolean;
|
|
40
|
+
blank: boolean;
|
|
41
|
+
updatedAt: number;
|
|
42
|
+
/** 宿主投影值;本插件只读 sessionStats.turns,读的地方自己 cast。 */
|
|
43
|
+
projectionValues?: unknown;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* 0.1.1's session row carries `agentPreset`; 0.1.2 dropped it. Reading it
|
|
47
|
+
* must not depend on which version's types are in scope in the current
|
|
48
|
+
* file, so narrow through unknown.
|
|
49
|
+
* @param row - a session row of either version.
|
|
50
|
+
* @returns the agent preset name, or undefined when absent.
|
|
51
|
+
*/
|
|
52
|
+
export declare function agentPresetOf(row: unknown): string | undefined;
|
|
53
|
+
/**
|
|
54
|
+
* 0.1.1's session row carries `pendingInteraction` (the pending-interaction
|
|
55
|
+
* state behind the sidebar's yellow dot); 0.1.2 serves it from the
|
|
56
|
+
* uiSession service instead. This answers only "does this row carry a
|
|
57
|
+
* pending interaction".
|
|
58
|
+
* @param row - a session row of either version.
|
|
59
|
+
* @returns true when the row has a pending interaction.
|
|
60
|
+
*/
|
|
61
|
+
export declare function hasPendingInteraction(row: unknown): boolean;
|
|
62
|
+
/**
|
|
63
|
+
* `ctx.sessions.binding(id)?.session.rename(title)` 的返回值。
|
|
64
|
+
* 两版的包裹类型不同(0.1.1 是 RpcResult、0.1.2 是 RemoteResult),但判别式
|
|
65
|
+
* 联合的形状一致:成功分支带 ok:true(还有个我们不读的 value),失败分支带
|
|
66
|
+
* ok:false + error。这里只镜像本插件真正读到的两个字段(ok、error.message),
|
|
67
|
+
* 两版的真类型都能结构赋值进来。
|
|
68
|
+
*/
|
|
69
|
+
export type RenameResult = Promise<{
|
|
70
|
+
readonly ok: true;
|
|
71
|
+
} | {
|
|
72
|
+
readonly ok: false;
|
|
73
|
+
readonly error: {
|
|
74
|
+
readonly message: string;
|
|
75
|
+
};
|
|
76
|
+
}>;
|
|
77
|
+
/**
|
|
78
|
+
* 待处理交互的选择器 hook(0.1.2 的标准 prop `useSessionPendingInteraction`);
|
|
79
|
+
* 0.1.1 没有这个 prop,运行时读到 undefined。本地镜像只描述本插件读到的形状
|
|
80
|
+
* (按会话 id 的只读 Map + 选择器调用),不从
|
|
81
|
+
* `@deepseek-ai/dsh-client-ui-session/client` 拿类型——那个包 0.1.1 装不到。
|
|
82
|
+
*/
|
|
83
|
+
export type UsePendingInteractions = <S>(sel: (m: ReadonlyMap<SessionId, unknown>) => S, eq?: (a: S, b: S) => boolean) => S;
|
|
84
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/client/compat/types.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAMlD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAA;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAA;AAEnE;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,GAAG,OAAO,CAAA;AAEnC,mHAAmH;AACnH,YAAY,EAAE,SAAS,EAAE,CAAA;AAEzB,uEAAuE;AACvE,YAAY,EAAE,WAAW,EAAE,CAAA;AAE3B;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,SAAS,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,YAAY,EAAE,MAAM,CAAA;IACpB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,SAAS,CAAA;IACpB,MAAM,CAAC,EAAE,UAAU,CAAA;IACnB,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,KAAK,EAAE,OAAO,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,kDAAkD;IAClD,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAC3B;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAG9D;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAG3D;AAED;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,GAAG,OAAO,CAC9B;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAA;CAAE,GACrB;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CACvE,CAAA;AAED;;;;;GAKG;AACH,MAAM,MAAM,sBAAsB,GAChC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,WAAW,CAAC,SAAS,EAAE,OAAO,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,OAAO,KAAK,CAAC,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"debug.d.ts","sourceRoot":"","sources":["../../../src/client/debug.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"debug.d.ts","sourceRoot":"","sources":["../../../src/client/debug.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACtD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAqP1D"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ClientContext } from '
|
|
1
|
+
import type { ClientContext } from '../compat/types.ts';
|
|
2
2
|
/** dsh-web-ui 兼容:explorer / preview 列的显隐标记与升起动画(同域同机制,合并一处)。 */
|
|
3
3
|
export declare function installAionuiCompat(ctx: ClientContext): void;
|
|
4
4
|
//# sourceMappingURL=aionui-compat.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aionui-compat.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/aionui-compat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"aionui-compat.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/aionui-compat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAEvD,gEAAgE;AAChE,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAmL5D"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ClientContext } from '
|
|
1
|
+
import type { ClientContext } from '../compat/types.ts';
|
|
2
2
|
/** S6: the two-gesture set — left-edge swipe-back and sheet drag-to-close.
|
|
3
3
|
* Both install/uninstall their own document listeners on the phone
|
|
4
4
|
* breakpoint's matchMedia change, so at >= 768px this is a true no-op (no
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gestures.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/gestures.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"gestures.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/gestures.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAiQvD;;;2EAG2E;AAC3E,wBAAgB,eAAe,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAGxD"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ClientContext } from '
|
|
1
|
+
import type { ClientContext } from '../compat/types.ts';
|
|
2
2
|
/**
|
|
3
3
|
* Session header running-status dot (S2). No official element exists to
|
|
4
4
|
* reposition (ConversationSessionHeader renders only the crumb title, the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"header-status.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/header-status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"header-status.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/header-status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAGvD;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAiC/D"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ClientContext } from '
|
|
1
|
+
import type { ClientContext } from '../compat/types.ts';
|
|
2
2
|
import { type KeyboardTuning } from '../client-config.ts';
|
|
3
3
|
/** The safety pad this platform gets: the configured clearance, or nothing
|
|
4
4
|
* off Android. UA sniffing is the right tool here — the target is a platform
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keyboard-avoid.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/keyboard-avoid.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"keyboard-avoid.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/keyboard-avoid.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AACvD,OAAO,EAAmC,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAoC1F;;;uEAGuE;AACvE,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,GAAE,MAAsB,GAAG,MAAM,CAElF;AAyBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,GAAE,cAAkC,GAAG,MAAM,CAErG;AAED,iDAAiD;AACjD,MAAM,WAAW,eAAe;IAC9B,mDAAmD;IACnD,WAAW,EAAE,MAAM,CAAA;IACnB,6BAA6B;IAC7B,QAAQ,EAAE,MAAM,CAAA;IAChB,gCAAgC;IAChC,SAAS,EAAE,MAAM,CAAA;IACjB,4BAA4B;IAC5B,KAAK,EAAE,MAAM,CAAA;CACd;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,CAI7D;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,cAAc,EAAE,OAAO,EACvB,GAAG,EAAE,MAAM,GACV,MAAM,CAUR;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CA2L7D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keyboard-guard.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/keyboard-guard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"keyboard-guard.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/keyboard-guard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAWvD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAqF7D"}
|
|
@@ -17,6 +17,6 @@
|
|
|
17
17
|
* Phone only. On desktop the back gesture is not a thing and the official
|
|
18
18
|
* dialogs keep their own behaviour untouched (the repo's desktop no-op rule).
|
|
19
19
|
*/
|
|
20
|
-
import type { ClientContext } from '
|
|
20
|
+
import type { ClientContext } from '../compat/types.ts';
|
|
21
21
|
export declare function installModalBack(ctx: ClientContext): void;
|
|
22
22
|
//# sourceMappingURL=modal-back.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modal-back.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/modal-back.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"modal-back.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/modal-back.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAyBvD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAoDzD"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ClientContext } from '../compat/types.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Phone: park the composer row's third-party controls inside the model sheet.
|
|
4
|
+
*
|
|
5
|
+
* With the speed chip and the vision toggle both present on a GPT model the
|
|
6
|
+
* row runs out of width. Both are model-scoped settings, so the model sheet —
|
|
7
|
+
* which already holds 模型 and 推理等级 — is where they belong (user request,
|
|
8
|
+
* 2026-09-06).
|
|
9
|
+
*
|
|
10
|
+
* Why move the real controls instead of drawing our own rows that drive them:
|
|
11
|
+
* the same reason native-trigger-overlay.ts moves the real trigger. A stand-in
|
|
12
|
+
* has to script the original, which is a road this plugin does not go down —
|
|
13
|
+
* beyond the trusted-input wall that effect documents, our own rows would have
|
|
14
|
+
* to mirror every piece of state (speed tier, disabled, aria-pressed, whether
|
|
15
|
+
* a vision twin exists for the current model) and would rot on the next
|
|
16
|
+
* upstream restyle. Moving the node keeps one source of truth: their React
|
|
17
|
+
* roots go on owning and updating these elements, we only change where they
|
|
18
|
+
* hang.
|
|
19
|
+
*
|
|
20
|
+
* Measured 2026-09-06 (DSH 0.1.2, 390px) before writing this — the two things
|
|
21
|
+
* that would have killed the approach both hold: a relocated control survives
|
|
22
|
+
* host re-renders (typing into the composer re-renders the row and does not
|
|
23
|
+
* yank it back) and stays hit-testable at its new position.
|
|
24
|
+
*
|
|
25
|
+
* Restoring on close is not cosmetic. The sheet unmounts when it closes and
|
|
26
|
+
* anything still inside goes with it, so the controls would vanish from the
|
|
27
|
+
* page while their React roots kept updating detached nodes. The observer
|
|
28
|
+
* therefore watches the menu leaving too, and the parked node is held as a
|
|
29
|
+
* reference rather than looked up — once the menu is detached a document
|
|
30
|
+
* query can no longer find it.
|
|
31
|
+
*/
|
|
32
|
+
export declare function installModelSheetExtras(ctx: ClientContext): void;
|
|
33
|
+
//# sourceMappingURL=model-sheet-extras.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-sheet-extras.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/model-sheet-extras.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AA8DvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAkEhE"}
|
|
@@ -20,6 +20,6 @@
|
|
|
20
20
|
* trigger on top keeps the behaviour. Pills are `pointer-events: none` so a
|
|
21
21
|
* tap can only ever reach the real thing — no double handling.
|
|
22
22
|
*/
|
|
23
|
-
import type { ClientContext } from '
|
|
23
|
+
import type { ClientContext } from '../compat/types.ts';
|
|
24
24
|
export declare function installNativeTriggerOverlay(ctx: ClientContext): void;
|
|
25
25
|
//# sourceMappingURL=native-trigger-overlay.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native-trigger-overlay.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/native-trigger-overlay.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"native-trigger-overlay.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/native-trigger-overlay.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAuCvD,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAuCpE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"phone-chrome.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/phone-chrome.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"phone-chrome.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/phone-chrome.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAEvD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAkC3D;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,4BAA4B,CAAC,KAAK,EAAE;IAClD,UAAU,EAAE,OAAO,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;CACf,GAAG,OAAO,CAIV;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CA6E5D;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAyCzD"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ClientContext } from '
|
|
1
|
+
import type { ClientContext } from '../compat/types.ts';
|
|
2
2
|
/** Whole-row node kinds that are turn *process*, not conversation content.
|
|
3
3
|
* Keys are ChatNodeSeat's own `data-chat-flow-kind` dispatch values
|
|
4
4
|
* (registerChatNodeRenderers, lib/client.js:9322): tool calls, injected
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"turn-fold.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/turn-fold.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"turn-fold.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/turn-fold.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAkDvD;;;;;;;sDAOsD;AACtD,eAAO,MAAM,aAAa,8CAA+C,CAAA;AAMzE;sEACsE;AACtE,eAAO,MAAM,KAAK,6BAA2B,CAAA;AAS7C,4DAA4D;AAC5D,eAAO,MAAM,IAAI,wBAAwB,CAAA;AA4FzC;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAyNxD"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ClientContext } from '
|
|
1
|
+
import type { ClientContext } from '../compat/types.ts';
|
|
2
2
|
/**
|
|
3
3
|
* "内测声明" first-run notice, opt-out half (ALL widths — same user-directed
|
|
4
4
|
* exception as the _previewBadge rule in styles/base.css.ts).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"welcome-notice.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/welcome-notice.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"welcome-notice.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/welcome-notice.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAUvD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAsCnE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workbench-ref-close.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/workbench-ref-close.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"workbench-ref-close.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/workbench-ref-close.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAuBvD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAmBjE"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ClientContext } from '
|
|
1
|
+
import type { ClientContext } from './compat/types.ts';
|
|
2
2
|
import type { MobileNavKey } from './locales.ts';
|
|
3
3
|
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
4
4
|
interface LocaleNamespaceMap {
|