dsh-mobile 0.8.1 → 0.8.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/CHANGELOG.md +33 -0
- package/CONTRIBUTORS.md +30 -2
- package/README.en.md +7 -5
- package/README.md +7 -5
- package/SECURITY.md +1 -1
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/apps/mobile/README.md +8 -4
- package/apps/mobile/README.zh-CN.md +8 -4
- package/apps/mobile/release.json +3 -3
- package/docs/ATTACH_EXISTING_FRPS.en.md +2 -0
- package/docs/ATTACH_EXISTING_FRPS.md +2 -0
- package/docs/CLIENT_MODULES.en.md +6 -2
- package/docs/CLIENT_MODULES.md +6 -2
- package/docs/CONNECTION_DIAGNOSTICS.en.md +56 -0
- package/docs/CONNECTION_DIAGNOSTICS.md +56 -0
- package/docs/IROH.en.md +7 -1
- package/docs/IROH.md +7 -1
- package/docs/MOBILE_PLUGIN_ADAPTATION.en.md +1 -1
- package/docs/MOBILE_PLUGIN_ADAPTATION.md +1 -1
- package/docs/README.md +1 -0
- package/docs/SKIN_COMPATIBILITY.en.md +1 -1
- package/docs/SKIN_COMPATIBILITY.md +1 -1
- package/docs/SLOW_CONNECTIONS.en.md +6 -2
- package/docs/SLOW_CONNECTIONS.md +6 -2
- package/lib/cli.js +6 -12
- package/lib/cli.js.map +1 -1
- package/lib/client.js +772 -248
- package/lib/client.js.map +1 -1
- package/lib/extension-worker-runtime.mjs +4 -8
- package/lib/extension-worker-runtime.mjs.map +1 -1
- package/lib/index.d.mts +19 -89
- package/lib/index.mjs +397 -273
- package/lib/index.mjs.map +1 -1
- package/lib/mobile-compat.js +2 -2
- package/lib/mobile-compat.js.map +1 -1
- package/lib/mobile-layout.js +116 -33
- package/lib/mobile-layout.js.map +1 -1
- package/package.json +9 -7
- package/packages/question-fixes/lib/client.js +1 -2
- package/packages/question-fixes/lib/index.mjs +1 -2
- package/packages/question-fixes/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -5,7 +5,7 @@ window.__ModuleLoader__.load({
|
|
|
5
5
|
var exports = module.exports;
|
|
6
6
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
7
|
let react = require("react");
|
|
8
|
-
|
|
8
|
+
// src/client-messages.ts
|
|
9
9
|
const frpFormMessages = {
|
|
10
10
|
en: {
|
|
11
11
|
frpServerAddressInvalid: "Enter the frps IP address or full hostname only, without https://, a port, or a path.",
|
|
@@ -1160,6 +1160,7 @@ window.__ModuleLoader__.load({
|
|
|
1160
1160
|
enlargeQr: "Enlarge the QR code",
|
|
1161
1161
|
closeEnlargedQr: "Close the enlarged QR code",
|
|
1162
1162
|
irohPairingReady: "iroh pairing code {code} is live for five minutes. Scan it from the iroh pairing screen; opening another code replaces this one.",
|
|
1163
|
+
irohPairingCopyOnly: "The QR image could not be generated. Copy the pairing link and paste it into the App’s iroh pairing screen.",
|
|
1163
1164
|
irohDescription: "Peer-to-peer encrypted link with relay fallback. No domain, port or account needed; requires the full Android App.",
|
|
1164
1165
|
prepareIroh: "Prepare iroh",
|
|
1165
1166
|
irohInstallNote: "The Install button downloads the pinned sidecar release (dsh-mobile-iroh 0.1.0-alpha.1, about 15 MB on Windows x64, 24 MB on Linux x64) into the plugin private directory and verifies its SHA-256. An installed companion with a verified copy is reused instead, with no download.",
|
|
@@ -1194,6 +1195,7 @@ window.__ModuleLoader__.load({
|
|
|
1194
1195
|
enlargeQr: "Ingrandisci il codice QR",
|
|
1195
1196
|
closeEnlargedQr: "Chiudi il codice QR ingrandito",
|
|
1196
1197
|
irohPairingReady: "Il codice iroh {code} è attivo per cinque minuti. Scansionalo dalla schermata di abbinamento iroh; aprirne un altro sostituisce questo.",
|
|
1198
|
+
irohPairingCopyOnly: "Impossibile generare il codice QR. Copia il link di abbinamento e incollalo nella schermata di abbinamento iroh dell’app.",
|
|
1197
1199
|
irohDescription: "Collegamento cifrato peer-to-peer con ripiego su relay. Nessun dominio, porta o account richiesto; richiede l’App Android completa.",
|
|
1198
1200
|
prepareIroh: "Prepara iroh",
|
|
1199
1201
|
irohInstallNote: "Il pulsante Installa scarica la release pinnata del sidecar (dsh-mobile-iroh 0.1.0-alpha.1, circa 15 MB su Windows x64, 24 MB su Linux x64) nella directory privata del plugin e ne verifica lo SHA-256. Un complemento installato con una copia verificata viene invece riutilizzato senza scaricare nulla.",
|
|
@@ -1228,6 +1230,7 @@ window.__ModuleLoader__.load({
|
|
|
1228
1230
|
enlargeQr: "放大二维码",
|
|
1229
1231
|
closeEnlargedQr: "关闭放大的二维码",
|
|
1230
1232
|
irohPairingReady: "iroh 配对码 {code} 已生效,有效期 5 分钟。请在 App 的 iroh 配对页扫码;再生成一个会替换当前这个。",
|
|
1233
|
+
irohPairingCopyOnly: "未能生成二维码。可复制配对链接,粘贴到 App 的 iroh 配对页。",
|
|
1231
1234
|
irohDescription: "点对点加密直连,跨网自动经中继。无需域名、端口或账号;需完整版 App。",
|
|
1232
1235
|
prepareIroh: "准备 iroh",
|
|
1233
1236
|
irohInstallNote: "点击安装会下载固定的 sidecar 发行版(dsh-mobile-iroh 0.1.0-alpha.1,Windows x64 约 15 MB,Linux x64 约 24 MB)到插件私有目录并校验 SHA-256;已安装的配套插件如有校验通过的副本会直接复用,不再下载。",
|
|
@@ -1866,6 +1869,93 @@ window.__ModuleLoader__.load({
|
|
|
1866
1869
|
cloudflaredTunnelSettingsInvalid: "隧道设置未通过校验。",
|
|
1867
1870
|
cloudflaredTunnelConfigMissing: "使用命名隧道需要同时填写令牌、公网域名和端口。"
|
|
1868
1871
|
});
|
|
1872
|
+
/** Measurement boundaries shared by diagnostic cards and copied reports. */
|
|
1873
|
+
const DIAGNOSTIC_SCOPE_MESSAGES = {
|
|
1874
|
+
en: {
|
|
1875
|
+
scripts: "Page scripts",
|
|
1876
|
+
configuration: "Configuration",
|
|
1877
|
+
computer: "Computer-side check",
|
|
1878
|
+
phone: "Phone not tested",
|
|
1879
|
+
versions: "Version information",
|
|
1880
|
+
provider: "Local channel state",
|
|
1881
|
+
dns: "System DNS",
|
|
1882
|
+
coverage: "Computer-side checks only. Phone reachability, authenticated pages, resources and WebSockets have not been verified."
|
|
1883
|
+
},
|
|
1884
|
+
it: {
|
|
1885
|
+
scripts: "Script pagina",
|
|
1886
|
+
configuration: "Configurazione",
|
|
1887
|
+
computer: "Controllo dal computer",
|
|
1888
|
+
phone: "Telefono non verificato",
|
|
1889
|
+
versions: "Informazioni versioni",
|
|
1890
|
+
provider: "Stato del canale locale",
|
|
1891
|
+
dns: "DNS di sistema",
|
|
1892
|
+
coverage: "Solo controlli dal computer. Raggiungibilità dal telefono, pagine autenticate, risorse e WebSocket non verificati."
|
|
1893
|
+
},
|
|
1894
|
+
zh: {
|
|
1895
|
+
scripts: "页面脚本",
|
|
1896
|
+
configuration: "配置信息",
|
|
1897
|
+
computer: "电脑侧检查",
|
|
1898
|
+
phone: "手机尚未验证",
|
|
1899
|
+
versions: "版本信息",
|
|
1900
|
+
provider: "本机通道状态",
|
|
1901
|
+
dns: "系统 DNS",
|
|
1902
|
+
coverage: "仅为电脑侧检查。手机可达性、认证页面、资源加载和 WebSocket 尚未验证。"
|
|
1903
|
+
}
|
|
1904
|
+
};
|
|
1905
|
+
/** Fixed DNS/egress observations never imply acceptance from another network. */
|
|
1906
|
+
const DIAGNOSTIC_NETWORK_MESSAGES = {
|
|
1907
|
+
en: {
|
|
1908
|
+
"remote-service-ready": ["{provider} reports its local component ready; public and phone paths are not verified.", ""],
|
|
1909
|
+
"plugin-inspection-unavailable": ["Active page scripts could not be inspected; absence of a competing remote channel is unverified.", "Other network checks are independent. Keep the reproduction environment and inspect the relevant plugins."],
|
|
1910
|
+
"firewall-inactive": ["LAN is off, so LAN firewall rules were not probed. This does not assess the remote entry.", "Enable LAN first if you need a local connection."],
|
|
1911
|
+
"remote-tailnet-shadowed": ["System DNS returned tailnet addresses and this Funnel-only listener does not accept that private path. This failed check does not establish a public Funnel outage.", "Compare from outside the tailnet. If you voluntarily change device DNS for a test, consider other private services and restore it afterward."],
|
|
1912
|
+
"dns-public": ["System DNS returned ordinary public-address results. This does not establish endpoint reachability.", ""],
|
|
1913
|
+
"dns-tailnet": ["System DNS returned tailnet addresses, not Fake-IP. This is a private path, not an independent public-path test.", ""],
|
|
1914
|
+
"dns-fake-ip": ["System DNS returned Fake-IP-range addresses; proxy routing may affect the measurement.", "Check the DNS/routing policy without disabling certificate verification."],
|
|
1915
|
+
"dns-private": ["System DNS returned private/local addresses. This does not test the public ingress.", ""],
|
|
1916
|
+
"dns-mixed": ["System DNS returned mixed address categories; do not attribute the failure to a single private address.", "Compare the actual routes and address families."],
|
|
1917
|
+
"dns-unknown": ["System DNS context was unavailable or exceeded its wait budget; no public DNS service was queried.", ""],
|
|
1918
|
+
"remote-dns-failed": ["The computer-side endpoint probe failed during name resolution.", "Check system DNS; compare from the phone network before judging the public service."],
|
|
1919
|
+
"remote-connect-failed": ["The computer-side endpoint probe could not establish or retain its connection.", "Check the current route and ingress, then compare from another network."],
|
|
1920
|
+
"remote-tls-failed": ["The computer-side TLS identity check failed.", "Check the certificate, hostname and proxy route. Do not disable certificate verification."],
|
|
1921
|
+
"remote-probe-timeout": ["The computer-side endpoint probe exceeded its wait budget.", "A timeout does not locate the failed hop. Compare from another network."],
|
|
1922
|
+
"remote-http-failed": ["The computer reached an HTTP endpoint but did not receive a successful health status.", "Check the ingress route and provider access policy; no credentials were sent by this probe."]
|
|
1923
|
+
},
|
|
1924
|
+
it: {
|
|
1925
|
+
"remote-service-ready": ["{provider} segnala il componente locale pronto; i percorsi pubblico e del telefono non sono verificati.", ""],
|
|
1926
|
+
"plugin-inspection-unavailable": ["Script attivi non verificati; non è confermata l’assenza di un altro canale remoto.", "Gli altri controlli sono indipendenti. Mantieni il caso riproducibile e controlla i plugin coinvolti."],
|
|
1927
|
+
"firewall-inactive": ["LAN disattivata: regole firewall locali non verificate. Il canale remoto non viene valutato da questo controllo.", "Abilita LAN prima di verificare una connessione locale."],
|
|
1928
|
+
"remote-tailnet-shadowed": ["Il DNS restituisce indirizzi tailnet e questo listener solo Funnel non accetta il percorso privato. Il controllo fallito non prova un guasto pubblico.", "Confronta da una rete esterna alla tailnet. Se modifichi volontariamente il DNS del dispositivo, valuta gli altri servizi privati e ripristinalo dopo il test."],
|
|
1929
|
+
"dns-public": ["Il DNS di sistema restituisce indirizzi pubblici ordinari; non prova la raggiungibilità.", ""],
|
|
1930
|
+
"dns-tailnet": ["Il DNS restituisce indirizzi tailnet, non Fake-IP. È un percorso privato, non un test pubblico indipendente.", ""],
|
|
1931
|
+
"dns-fake-ip": ["Il DNS restituisce indirizzi Fake-IP; il routing del proxy può influire sulla misura.", "Controlla DNS e routing senza disabilitare la verifica dei certificati."],
|
|
1932
|
+
"dns-private": ["Il DNS restituisce indirizzi privati/locali; non verifica l’ingresso pubblico.", ""],
|
|
1933
|
+
"dns-mixed": ["Il DNS restituisce categorie miste; non attribuire il problema a un solo indirizzo privato.", "Confronta percorsi e famiglie IP effettivi."],
|
|
1934
|
+
"dns-unknown": ["Il contesto DNS non è disponibile o ha superato il tempo previsto; nessun DNS pubblico è stato interrogato.", ""],
|
|
1935
|
+
"remote-dns-failed": ["La risoluzione del nome è fallita nel controllo dal computer.", "Controlla il DNS di sistema e confronta dalla rete del telefono."],
|
|
1936
|
+
"remote-connect-failed": ["Il controllo dal computer non ha stabilito o mantenuto la connessione.", "Controlla percorso e ingresso, poi confronta da un’altra rete."],
|
|
1937
|
+
"remote-tls-failed": ["La verifica TLS dal computer è fallita.", "Controlla certificato, nome host e proxy. Non disabilitare la verifica TLS."],
|
|
1938
|
+
"remote-probe-timeout": ["Il controllo dal computer ha superato il tempo previsto.", "Il timeout non identifica il punto guasto; confronta da un’altra rete."],
|
|
1939
|
+
"remote-http-failed": ["Il computer ha raggiunto HTTP ma senza uno stato di salute riuscito.", "Controlla percorso e criteri di accesso. Il test non invia credenziali."]
|
|
1940
|
+
},
|
|
1941
|
+
zh: {
|
|
1942
|
+
"remote-service-ready": ["{provider} 报告本机组件已就绪;公网与手机路径尚未验证。", ""],
|
|
1943
|
+
"plugin-inspection-unavailable": ["本次未能检查活动页面脚本,不能据此认定不存在其他远程通道。", "其余网络项目独立检查;保留复现环境并核对相关插件。"],
|
|
1944
|
+
"firewall-inactive": ["局域网未启用,本次没有探测局域网防火墙规则,不用于判断远程入口。", "需要局域网连接时,先启用再检查。"],
|
|
1945
|
+
"remote-tailnet-shadowed": ["系统 DNS 返回 tailnet 地址,而当前 Funnel-only 监听不接受此私网路径。本次失败不能证明公网 Funnel 故障。", "用 tailnet 外的网络对照。若自愿临时调整设备 DNS,注意其他私网服务的影响,并在测试后恢复。"],
|
|
1946
|
+
"dns-public": ["系统 DNS 返回普通公网地址类别;这本身不证明端点可达。", ""],
|
|
1947
|
+
"dns-tailnet": ["系统 DNS 返回 tailnet 地址,不是 Fake-IP。这是私网路径,不是独立的公网验证。", ""],
|
|
1948
|
+
"dns-fake-ip": ["系统 DNS 返回 Fake-IP 网段;代理路由可能影响本次测量。", "核对 DNS 和路由策略,不要关闭证书验证。"],
|
|
1949
|
+
"dns-private": ["系统 DNS 返回私网或本机地址,不是在验证公网入口。", ""],
|
|
1950
|
+
"dns-mixed": ["系统 DNS 返回混合地址类别,不能只凭其中一个私网地址归因。", "对照实际路由与 IPv4/IPv6 路径。"],
|
|
1951
|
+
"dns-unknown": ["系统 DNS 信息不可用或等待超时;没有查询公共 DNS 服务。", ""],
|
|
1952
|
+
"remote-dns-failed": ["电脑出口探测在名称解析阶段失败。", "检查系统 DNS,并用手机当前网络对照后再判断公网状态。"],
|
|
1953
|
+
"remote-connect-failed": ["电脑出口探测无法建立或保持连接。", "核对当前路由和入口,再用其他网络对照。"],
|
|
1954
|
+
"remote-tls-failed": ["电脑出口探测的 TLS 身份验证失败。", "检查证书、主机名和代理路由,不要关闭证书验证。"],
|
|
1955
|
+
"remote-probe-timeout": ["电脑出口探测超过了等待预算。", "超时不能定位具体故障节点,请用其他网络对照。"],
|
|
1956
|
+
"remote-http-failed": ["电脑已到达 HTTP 入口,但未得到成功的健康状态。", "检查入口路由与服务商访问策略;本次探测不发送配对凭据。"]
|
|
1957
|
+
}
|
|
1958
|
+
};
|
|
1869
1959
|
const DIAGNOSTIC_REASON_MESSAGES = {
|
|
1870
1960
|
en: {
|
|
1871
1961
|
"lan-setup-required": ["Local network setup has not been completed.", "Return to Local network and choose a network to finish setup."],
|
|
@@ -1873,24 +1963,24 @@ window.__ModuleLoader__.load({
|
|
|
1873
1963
|
"network-unavailable": ["The saved local network adapter is unavailable.", "Run dsh-mobile setup again."],
|
|
1874
1964
|
"network-interface": ["Using network interface {interfaceName}.", ""],
|
|
1875
1965
|
"network-fixed": ["A fixed local network configuration is in use.", ""],
|
|
1876
|
-
"lan-ready": ["The
|
|
1966
|
+
"lan-ready": ["The computer gateway is listening at {endpointSuffix}; phone reachability is unverified.", ""],
|
|
1877
1967
|
"lan-off": ["Local network access is currently off.", "Enable local network access when the phone must connect directly."],
|
|
1878
|
-
"firewall-ready": ["
|
|
1968
|
+
"firewall-ready": ["Enabled local TCP/discovery rules were found; this does not prove the phone route is permitted.", ""],
|
|
1879
1969
|
"firewall-missing": ["The complete local network firewall rules were not found.", "Run dsh-mobile setup as administrator and check the firewall rules."],
|
|
1880
1970
|
"firewall-unknown": ["The system did not allow the plugin to read firewall status.", "If the phone cannot find this computer, run setup as administrator."],
|
|
1881
1971
|
"remote-off": ["Remote access through {provider} is currently off.", ""],
|
|
1882
1972
|
"remote-origin-ready": ["The private HTTP backend is listening; public HTTPS is not verified.", "Verify your reverse proxy, public certificate, external Host including port, and WebSocket access from your phone. Keep the HTTP backend private."],
|
|
1883
|
-
"remote-ready": ["{provider} endpoint {endpointSuffix}
|
|
1973
|
+
"remote-ready": ["Computer-side HTTP reached {provider} endpoint {endpointSuffix} in about {latencyMs} ms; phone and independent public-path reachability are unverified.", ""],
|
|
1884
1974
|
"remote-ready-via-proxy": ["The computer reached {provider} endpoint {endpointSuffix} through its configured proxy in about {latencyMs} ms; phone reachability is not verified.", "Test the connection from the phone’s network."],
|
|
1885
1975
|
"remote-rate-limited": ["{provider} endpoint {endpointSuffix} is reachable, but this check observed rate limiting.", "Try again later; older sessions load on demand to reduce traffic."],
|
|
1886
1976
|
"remote-rate-limited-via-proxy": ["The computer reached {provider} endpoint {endpointSuffix} through its proxy, but the service rate-limited this check; phone reachability is not verified.", "Try again later and test from the phone’s network."],
|
|
1887
|
-
"remote-fake-ip": ["
|
|
1888
|
-
"remote-unreachable": ["{provider}
|
|
1977
|
+
"remote-fake-ip": ["System DNS returned Fake-IP-range addresses and the computer-side probe failed; this does not prove a public outage.", "Check DNS/proxy routing and compare another network without disabling certificate checks."],
|
|
1978
|
+
"remote-unreachable": ["The computer-side probe of {provider} endpoint {endpointSuffix} failed; this does not establish failure from other networks.", "Compare DNS, routing, TLS and ingress from the phone network before reconnecting."],
|
|
1889
1979
|
"remote-needs-login": ["Tailscale is waiting for login to finish.", "Return to Remote access and continue login."],
|
|
1890
1980
|
"remote-connecting": ["The {provider} remote channel is still connecting.", "Wait briefly, then check again."],
|
|
1891
1981
|
"remote-controller-error": ["The {provider} controller reported {controllerCode}.", "Return to Remote access and reconnect."],
|
|
1892
1982
|
"competing-remote-channel": ["Another remote plugin is injecting its own request channel; the phone may show that plugin’s pairing screen.", "Turn off dsh-remote-web-ui remote access on the computer, refresh, and pair using the current DSH Mobile QR code. Do not mix pairing codes."],
|
|
1893
|
-
"phone-network-unknown": ["The
|
|
1983
|
+
"phone-network-unknown": ["The phone network, paired page, resources and WebSocket have not been tested by this computer.", "Test from the current phone network; record the failing stage without sharing pairing secrets."]
|
|
1894
1984
|
},
|
|
1895
1985
|
it: {
|
|
1896
1986
|
"lan-setup-required": ["La configurazione della rete locale non è completa.", "Torna a Rete locale e scegli una rete per completare la configurazione."],
|
|
@@ -1898,24 +1988,24 @@ window.__ModuleLoader__.load({
|
|
|
1898
1988
|
"network-unavailable": ["La scheda di rete locale salvata non è disponibile.", "Esegui di nuovo dsh-mobile setup."],
|
|
1899
1989
|
"network-interface": ["È in uso l’interfaccia di rete {interfaceName}.", ""],
|
|
1900
1990
|
"network-fixed": ["È in uso una configurazione di rete locale fissa.", ""],
|
|
1901
|
-
"lan-ready": ["Il gateway
|
|
1991
|
+
"lan-ready": ["Il gateway del computer è in ascolto su {endpointSuffix}; il telefono non è verificato.", ""],
|
|
1902
1992
|
"lan-off": ["L’accesso dalla rete locale è disattivato.", "Attiva l’accesso locale quando il telefono deve collegarsi direttamente."],
|
|
1903
|
-
"firewall-ready": ["
|
|
1993
|
+
"firewall-ready": ["Trovate regole TCP/discovery abilitate; il percorso dal telefono non è verificato.", ""],
|
|
1904
1994
|
"firewall-missing": ["Le regole firewall complete per la rete locale non sono state trovate.", "Esegui dsh-mobile setup come amministratore e controlla le regole firewall."],
|
|
1905
1995
|
"firewall-unknown": ["Il sistema non ha consentito al plugin di leggere lo stato del firewall.", "Se il telefono non trova il computer, esegui setup come amministratore."],
|
|
1906
1996
|
"remote-off": ["L’accesso remoto tramite {provider} è disattivato.", ""],
|
|
1907
1997
|
"remote-origin-ready": ["Il backend HTTP privato è in ascolto; HTTPS pubblico non è verificato.", "Verifica dal telefono reverse proxy, certificato pubblico, Host esterno inclusa la porta e accesso WebSocket. Mantieni privato il backend HTTP."],
|
|
1908
|
-
"remote-ready": ["
|
|
1998
|
+
"remote-ready": ["HTTP dal computer ha raggiunto {provider} su {endpointSuffix} in circa {latencyMs} ms; telefono e percorso pubblico indipendente non verificati.", ""],
|
|
1909
1999
|
"remote-ready-via-proxy": ["Il computer ha raggiunto l’endpoint {provider} {endpointSuffix} tramite il proxy configurato in circa {latencyMs} ms; la raggiungibilità dal telefono non è verificata.", "Prova la connessione dalla rete del telefono."],
|
|
1910
2000
|
"remote-rate-limited": ["L’endpoint {provider} {endpointSuffix} è raggiungibile, ma il controllo ha rilevato una limitazione temporanea.", "Riprova più tardi; le sessioni precedenti vengono caricate su richiesta per ridurre il traffico."],
|
|
1911
2001
|
"remote-rate-limited-via-proxy": ["Il computer ha raggiunto l’endpoint {provider} {endpointSuffix} tramite proxy, ma il servizio ha limitato questo controllo; la raggiungibilità dal telefono non è verificata.", "Riprova più tardi e verifica dalla rete del telefono."],
|
|
1912
|
-
"remote-fake-ip": ["
|
|
1913
|
-
"remote-unreachable": ["
|
|
2002
|
+
"remote-fake-ip": ["Il DNS restituisce indirizzi Fake-IP e il controllo dal computer è fallito; non prova un guasto pubblico.", "Controlla DNS e routing e confronta una rete alternativa senza disabilitare TLS."],
|
|
2003
|
+
"remote-unreachable": ["Il controllo dal computer di {provider} su {endpointSuffix} è fallito; altre reti non sono verificate.", "Confronta DNS, routing, TLS e ingresso dalla rete del telefono."],
|
|
1914
2004
|
"remote-needs-login": ["Tailscale attende il completamento dell’accesso.", "Torna ad Accesso remoto e continua l’accesso."],
|
|
1915
2005
|
"remote-connecting": ["Il canale remoto {provider} è ancora in connessione.", "Attendi qualche istante e ripeti il controllo."],
|
|
1916
2006
|
"remote-controller-error": ["Il controller {provider} ha segnalato {controllerCode}.", "Torna ad Accesso remoto e riconnettiti."],
|
|
1917
2007
|
"competing-remote-channel": ["Un altro plugin remoto sta inserendo il proprio canale di richieste; sul telefono potrebbe apparire la sua schermata di abbinamento.", "Disattiva l’accesso remoto di dsh-remote-web-ui sul computer, aggiorna la pagina e usa il codice QR corrente di DSH Mobile. Non mescolare i codici."],
|
|
1918
|
-
"phone-network-unknown": ["
|
|
2008
|
+
"phone-network-unknown": ["Rete del telefono, pagina abbinata, risorse e WebSocket non sono stati verificati dal computer.", "Verifica dalla rete del telefono e indica la fase del problema senza condividere credenziali."]
|
|
1919
2009
|
},
|
|
1920
2010
|
zh: {
|
|
1921
2011
|
"lan-setup-required": ["尚未完成局域网初始化。", "返回局域网页选择网卡并完成配置。"],
|
|
@@ -1923,24 +2013,24 @@ window.__ModuleLoader__.load({
|
|
|
1923
2013
|
"network-unavailable": ["已保存的局域网网卡当前不可用。", "重新运行 dsh-mobile setup。"],
|
|
1924
2014
|
"network-interface": ["正在使用网卡 {interfaceName}。", ""],
|
|
1925
2015
|
"network-fixed": ["当前使用固定局域网配置。", ""],
|
|
1926
|
-
"lan-ready": ["
|
|
2016
|
+
"lan-ready": ["电脑网关已监听 {endpointSuffix};手机能否到达尚未验证。", ""],
|
|
1927
2017
|
"lan-off": ["局域网访问当前未开启。", "手机需要直连时开启局域网访问。"],
|
|
1928
|
-
"firewall-ready": ["
|
|
2018
|
+
"firewall-ready": ["已发现启用的局域网 TCP 与发现规则;这不证明手机路由或全部防火墙策略已放行。", ""],
|
|
1929
2019
|
"firewall-missing": ["未找到完整的局域网防火墙规则。", "以管理员身份运行 dsh-mobile setup 并检查防火墙规则。"],
|
|
1930
2020
|
"firewall-unknown": ["系统未允许插件读取防火墙状态。", "若手机找不到电脑,请以管理员身份运行 setup。"],
|
|
1931
2021
|
"remote-off": ["{provider} 远程访问当前未启用。", ""],
|
|
1932
2022
|
"remote-origin-ready": ["私有 HTTP 后端已监听;尚未验证公网 HTTPS。", "请用手机核对反向代理、公网证书、含端口的外部 Host 及 WebSocket 访问。HTTP 后端必须留在私网。"],
|
|
1933
|
-
"remote-ready": ["{provider}
|
|
2023
|
+
"remote-ready": ["电脑当前出口可访问 {provider} 入口 {endpointSuffix},约 {latencyMs} ms;公网及手机路径未独立验证。", ""],
|
|
1934
2024
|
"remote-ready-via-proxy": ["电脑经已配置代理访问 {provider} 端点 {endpointSuffix},约 {latencyMs} ms;尚未验证手机网络是否可达。", "请用手机当前网络实际连接测试。"],
|
|
1935
2025
|
"remote-rate-limited": ["{provider} 端点 {endpointSuffix} 可达,但本次检查观察到服务限流。", "稍后重试;旧会话会按需加载以减少流量。"],
|
|
1936
2026
|
"remote-rate-limited-via-proxy": ["电脑经代理访问 {provider} 端点 {endpointSuffix} 时遇到限流;尚未验证手机网络是否可达。", "稍后重试,并用手机当前网络实际连接测试。"],
|
|
1937
|
-
"remote-fake-ip": ["
|
|
1938
|
-
"remote-unreachable": ["{provider}
|
|
2027
|
+
"remote-fake-ip": ["系统 DNS 返回 Fake-IP 网段,电脑出口探测未成功;这不是公网故障的证明。", "核对 DNS 与代理路由,用其他网络对照,不要关闭证书验证。"],
|
|
2028
|
+
"remote-unreachable": ["电脑当前出口无法完成 {provider} 入口 {endpointSuffix} 的探测;这不证明其他网络也失败。", "先对照手机网络及 DNS、路由、证书和入口,再决定是否重连。"],
|
|
1939
2029
|
"remote-needs-login": ["Tailscale 正在等待完成登录。", "返回远程访问并继续登录。"],
|
|
1940
2030
|
"remote-connecting": ["{provider} 远程通道仍在连接。", "等待片刻后重新检查。"],
|
|
1941
2031
|
"remote-controller-error": ["{provider} 控制器报告 {controllerCode}。", "返回远程访问并重新连接。"],
|
|
1942
2032
|
"competing-remote-channel": ["检测到另一个远程插件注入自己的请求通道;手机可能显示它的配对页面。", "在电脑端关闭 dsh-remote-web-ui 的远程访问并刷新,再用 DSH Mobile 当前二维码配对;不要混用配对码。"],
|
|
1943
|
-
"phone-network-unknown": ["
|
|
2033
|
+
"phone-network-unknown": ["电脑没有验证手机网络、配对后的页面、资源和 WebSocket。", "请用手机当前网络实际连接,记录失败阶段,不要提供配对密钥。"]
|
|
1944
2034
|
}
|
|
1945
2035
|
};
|
|
1946
2036
|
Object.assign(MOBILE_CONTROL_MESSAGES.en, {
|
|
@@ -1955,6 +2045,13 @@ window.__ModuleLoader__.load({
|
|
|
1955
2045
|
frpVhostHttpPortHint: "The loopback plaintext vhost port of your own frps (upstream default 7080).",
|
|
1956
2046
|
frpPublicPort: "Public entry port",
|
|
1957
2047
|
frpPublicPortHint: "Raw TCP proxy port used as the public HTTPS entry (default 33080, never 3080/3443/3444).",
|
|
2048
|
+
frpUser: "frpc user (optional)",
|
|
2049
|
+
frpUserPlaceholder: "myfrpuser",
|
|
2050
|
+
funnelListenerReady: "Funnel is listening. Verify public access from a network outside this tailnet.",
|
|
2051
|
+
macosFolderHelpTitle: "Before leaving this Mac",
|
|
2052
|
+
macosFolderHelpNote: "Open the workspace folder you plan to use in DSH on this Mac and respond to any macOS prompt. In System Settings → Privacy & Security → Files and Folders, allow only the locations you need. If opening a folder remotely times out, check this Mac for a pending prompt before changing the pairing.",
|
|
2053
|
+
frpUserHint: "Optional user field of shared frps services: the proxy registers as user.proxyName. Leave blank to omit it.",
|
|
2054
|
+
frpUserInvalid: "The user must be 1–128 letters, digits, dots, underscores, or hyphens.",
|
|
1958
2055
|
frpAttachPlan: "Copy attach runbook",
|
|
1959
2056
|
frpAttachPlanCopied: "Attach runbook copied: local frpc.toml plus the VPS checklist.",
|
|
1960
2057
|
frpAttachPlanFailed: "Could not build the attach runbook: {error}",
|
|
@@ -2008,6 +2105,13 @@ window.__ModuleLoader__.load({
|
|
|
2008
2105
|
frpVhostHttpPortHint: "Porta vhost in chiaro su loopback del tuo frps (predefinita 7080).",
|
|
2009
2106
|
frpPublicPort: "Porta pubblica di ingresso",
|
|
2010
2107
|
frpPublicPortHint: "Porta del proxy TCP grezzo usata come ingresso HTTPS pubblico (predefinita 33080, mai 3080/3443/3444).",
|
|
2108
|
+
frpUser: "Utente frpc (facoltativo)",
|
|
2109
|
+
frpUserPlaceholder: "myfrpuser",
|
|
2110
|
+
funnelListenerReady: "Funnel è in ascolto. Verifica l’accesso pubblico da una rete esterna alla tailnet.",
|
|
2111
|
+
macosFolderHelpTitle: "Prima di lasciare il Mac",
|
|
2112
|
+
macosFolderHelpNote: "Apri in DSH su questo Mac la cartella di lavoro che userai e rispondi alle eventuali richieste di macOS. In Impostazioni di Sistema → Privacy e sicurezza → File e cartelle, autorizza solo le posizioni necessarie. Se una cartella non si apre da remoto per un timeout, controlla se sul Mac c’è una richiesta in attesa prima di modificare l’abbinamento.",
|
|
2113
|
+
frpUserHint: "Campo utente facoltativo dei servizi frps condivisi: il proxy si registra come user.nomeproxy. Lascia vuoto per ometterlo.",
|
|
2114
|
+
frpUserInvalid: "L’utente deve essere di 1–128 lettere, cifre, punti, trattini bassi o trattini.",
|
|
2011
2115
|
frpAttachPlan: "Copia il runbook attach",
|
|
2012
2116
|
frpAttachPlanCopied: "Runbook attach copiato: frpc.toml locale più la checklist VPS.",
|
|
2013
2117
|
frpAttachPlanFailed: "Impossibile creare il runbook attach: {error}",
|
|
@@ -2061,6 +2165,13 @@ window.__ModuleLoader__.load({
|
|
|
2061
2165
|
frpVhostHttpPortHint: "你自己 frps 的回环明文 vhost 端口(上游默认 7080)。",
|
|
2062
2166
|
frpPublicPort: "公网入口端口",
|
|
2063
2167
|
frpPublicPortHint: "作为公网 HTTPS 入口的 TCP 透传端口(默认 33080,不得为 3080/3443/3444)。",
|
|
2168
|
+
frpUser: "用户名(可选)",
|
|
2169
|
+
frpUserPlaceholder: "myfrpuser",
|
|
2170
|
+
funnelListenerReady: "Funnel 已启动监听。请在此 tailnet 之外的网络验证公网访问。",
|
|
2171
|
+
macosFolderHelpTitle: "离开这台 Mac 前",
|
|
2172
|
+
macosFolderHelpNote: "先在这台 Mac 的 DSH 中打开远程会用到的工作区目录,处理可能出现的系统提示。在「系统设置 → 隐私与安全性 → 文件与文件夹」只授权需要的位置。手机打开文件夹超时时,先检查 Mac 上是否有待确认提示,不要急着重新配对。",
|
|
2173
|
+
frpUserHint: "共享 frp 服务的可选 user 字段:代理会以「用户名.代理名」注册。留空则不发送。",
|
|
2174
|
+
frpUserInvalid: "用户名只能包含 1–128 个字母、数字、点、下划线或连字符。",
|
|
2064
2175
|
frpAttachPlan: "复制接入清单",
|
|
2065
2176
|
frpAttachPlanCopied: "接入清单已复制:本机 frpc.toml 与 VPS 侧待办。",
|
|
2066
2177
|
frpAttachPlanFailed: "生成接入清单失败:{error}",
|
|
@@ -2228,8 +2339,7 @@ window.__ModuleLoader__.load({
|
|
|
2228
2339
|
if (publicIpv4Address(publicHost)) lines.push(manualIpCertificateGuide(publicHost), "");
|
|
2229
2340
|
return lines.join("\n");
|
|
2230
2341
|
}
|
|
2231
|
-
|
|
2232
|
-
//#region src/ip.ts
|
|
2342
|
+
// src/ip.ts
|
|
2233
2343
|
/**
|
|
2234
2344
|
* Browser-safe IP literal classification.
|
|
2235
2345
|
*
|
|
@@ -2310,8 +2420,7 @@ window.__ModuleLoader__.load({
|
|
|
2310
2420
|
if (leftGroups < 0 || rightGroups < 0) return 0;
|
|
2311
2421
|
return leftGroups + rightGroups >= 8 ? 0 : 6;
|
|
2312
2422
|
}
|
|
2313
|
-
|
|
2314
|
-
//#region src/network.ts
|
|
2423
|
+
// src/network.ts
|
|
2315
2424
|
/**
|
|
2316
2425
|
* IPv4 ranges that are never a public VPS endpoint (IANA special-purpose,
|
|
2317
2426
|
* private, shared, loopback, link-local, documentation, benchmark, multicast,
|
|
@@ -2381,7 +2490,8 @@ window.__ModuleLoader__.load({
|
|
|
2381
2490
|
"mode",
|
|
2382
2491
|
"entryTls",
|
|
2383
2492
|
"vhostHttpPort",
|
|
2384
|
-
"publicPort"
|
|
2493
|
+
"publicPort",
|
|
2494
|
+
"user"
|
|
2385
2495
|
]);
|
|
2386
2496
|
function hostname(value) {
|
|
2387
2497
|
if (value.length > 253 || !value.includes(".")) return false;
|
|
@@ -2404,6 +2514,11 @@ window.__ModuleLoader__.load({
|
|
|
2404
2514
|
if (typeof value !== "string" || value.length < 16 || value.length > 512 || /[\s\u0000-\u001f\u007f]/u.test(value)) throw new Error("frp_token_invalid");
|
|
2405
2515
|
return value;
|
|
2406
2516
|
}
|
|
2517
|
+
/** Validate the optional frpc `user` field; it must stay one safe TOML token. */
|
|
2518
|
+
function validateFrpUser(value) {
|
|
2519
|
+
if (typeof value !== "string" || value.length < 1 || value.length > 128 || !/^[A-Za-z0-9._-]+$/u.test(value)) throw new Error("frp_user_invalid");
|
|
2520
|
+
return value;
|
|
2521
|
+
}
|
|
2407
2522
|
/** Validate the public HTTPS origin used by Caddy and Android pairing. */
|
|
2408
2523
|
function validateFrpPublicOrigin(value) {
|
|
2409
2524
|
if (typeof value !== "string" || value.length > 512) throw new Error("frp_public_origin_invalid");
|
|
@@ -2481,6 +2596,7 @@ window.__ModuleLoader__.load({
|
|
|
2481
2596
|
const entryTls = record.entryTls === void 0 ? void 0 : validateFrpEntryTls(record.entryTls);
|
|
2482
2597
|
const vhostHttpPort = record.vhostHttpPort === void 0 ? void 0 : validateFrpVhostHttpPort(record.vhostHttpPort);
|
|
2483
2598
|
const publicPort = record.publicPort === void 0 ? void 0 : validateFrpPublicPort(record.publicPort);
|
|
2599
|
+
const user = record.user === void 0 || record.user === "" ? void 0 : validateFrpUser(record.user);
|
|
2484
2600
|
const resolvedMode = mode ?? "deploy";
|
|
2485
2601
|
const resolvedEntryTls = entryTls ?? "public-ip-cert";
|
|
2486
2602
|
if (resolvedEntryTls === "self-signed" && resolvedMode !== "attach") throw new Error("frp_entry_tls_invalid");
|
|
@@ -2496,7 +2612,8 @@ window.__ModuleLoader__.load({
|
|
|
2496
2612
|
...mode === void 0 ? {} : { mode },
|
|
2497
2613
|
...entryTls === void 0 ? {} : { entryTls },
|
|
2498
2614
|
...vhostHttpPort === void 0 ? {} : { vhostHttpPort },
|
|
2499
|
-
...publicPort === void 0 ? {} : { publicPort }
|
|
2615
|
+
...publicPort === void 0 ? {} : { publicPort },
|
|
2616
|
+
...user === void 0 ? {} : { user }
|
|
2500
2617
|
});
|
|
2501
2618
|
}
|
|
2502
2619
|
function tomlString(value) {
|
|
@@ -2542,6 +2659,7 @@ window.__ModuleLoader__.load({
|
|
|
2542
2659
|
`serverPort = ${String(settings.serverPort)}`,
|
|
2543
2660
|
"auth.method = \"token\"",
|
|
2544
2661
|
`auth.token = ${tomlString(settings.token)}`,
|
|
2662
|
+
...settings.user === void 0 ? [] : [`user = ${tomlString(settings.user)}`],
|
|
2545
2663
|
"transport.tls.enable = true",
|
|
2546
2664
|
"",
|
|
2547
2665
|
"[[proxies]]",
|
|
@@ -2569,8 +2687,7 @@ window.__ModuleLoader__.load({
|
|
|
2569
2687
|
""
|
|
2570
2688
|
].join("\n");
|
|
2571
2689
|
}
|
|
2572
|
-
|
|
2573
|
-
//#region src/frp-attach.ts
|
|
2690
|
+
// src/frp-attach.ts
|
|
2574
2691
|
/** Default proof path used to confirm the public entry answered from this computer. */
|
|
2575
2692
|
const FRP_ATTACH_DISCOVERY_PATH = "/mobile-access/discovery";
|
|
2576
2693
|
/** Declaration printed above the VPS half of an attach template. */
|
|
@@ -2767,8 +2884,7 @@ window.__ModuleLoader__.load({
|
|
|
2767
2884
|
function createFrpAttachTemplate(settings, options = {}) {
|
|
2768
2885
|
return createFrpAttachTemplateParts(settings, options).text;
|
|
2769
2886
|
}
|
|
2770
|
-
|
|
2771
|
-
//#region src/frp-form-validation.ts
|
|
2887
|
+
// src/frp-form-validation.ts
|
|
2772
2888
|
/** Field ownership for errors returned by the Host parser. */
|
|
2773
2889
|
const FRP_FORM_ERRORS = {
|
|
2774
2890
|
frp_server_address_invalid: {
|
|
@@ -2791,6 +2907,11 @@ window.__ModuleLoader__.load({
|
|
|
2791
2907
|
code: "frp_public_origin_invalid",
|
|
2792
2908
|
messageKey: "frpPublicOriginInvalid"
|
|
2793
2909
|
},
|
|
2910
|
+
frp_user_invalid: {
|
|
2911
|
+
field: "user",
|
|
2912
|
+
code: "frp_user_invalid",
|
|
2913
|
+
messageKey: "frpUserInvalid"
|
|
2914
|
+
},
|
|
2794
2915
|
frp_attach_mode_requires_vhost_port: {
|
|
2795
2916
|
field: "vhostHttpPort",
|
|
2796
2917
|
code: "frp_attach_mode_requires_vhost_port",
|
|
@@ -2824,6 +2945,7 @@ window.__ModuleLoader__.load({
|
|
|
2824
2945
|
check("serverAddress", "frpServerAddressInvalid", () => validateFrpServerAddress(form.serverAddress));
|
|
2825
2946
|
check("serverPort", "frpServerPortInvalid", () => validateFrpServerPort(form.serverPort));
|
|
2826
2947
|
if (form.token !== "" || !allowSavedToken) check("token", "frpTokenInvalid", () => validateFrpToken(form.token));
|
|
2948
|
+
if (form.user !== void 0 && form.user !== "") check("user", "frpUserInvalid", () => validateFrpUser(form.user));
|
|
2827
2949
|
check("publicOrigin", "frpPublicOriginInvalid", () => validateFrpPublicOrigin(form.publicOrigin));
|
|
2828
2950
|
check("mode", "frpModeInvalid", () => validateFrpMode(form.mode));
|
|
2829
2951
|
check("entryTls", "frpEntryTlsInvalid", () => validateFrpEntryTls(form.entryTls));
|
|
@@ -2846,46 +2968,173 @@ window.__ModuleLoader__.load({
|
|
|
2846
2968
|
}
|
|
2847
2969
|
return issues;
|
|
2848
2970
|
}
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2971
|
+
// node_modules/@noble/hashes/_u64.js
|
|
2972
|
+
const fromNumH = (n) => n / 2 ** 32 | 0;
|
|
2973
|
+
const fromNumL = (n) => n >>> 0;
|
|
2974
|
+
function setU64FromNum(view, byteOffset, n, isLE) {
|
|
2975
|
+
const h = fromNumH(n);
|
|
2976
|
+
const l = fromNumL(n);
|
|
2977
|
+
view.setUint32(byteOffset, isLE ? l : h, isLE);
|
|
2978
|
+
view.setUint32(byteOffset + 4, isLE ? h : l, isLE);
|
|
2979
|
+
}
|
|
2980
|
+
// node_modules/@noble/hashes/utils.js
|
|
2981
|
+
/**
|
|
2982
|
+
* Checks if something is Uint8Array. Be careful: nodejs Buffer will return true.
|
|
2983
|
+
* @param a - value to test
|
|
2984
|
+
* @returns `true` when the value is a Uint8Array-compatible view.
|
|
2985
|
+
* @example
|
|
2986
|
+
* Check whether a value is a Uint8Array-compatible view.
|
|
2987
|
+
* ```ts
|
|
2988
|
+
* isBytes(new Uint8Array([1, 2, 3]));
|
|
2989
|
+
* ```
|
|
2990
|
+
*/
|
|
2853
2991
|
function isBytes(a) {
|
|
2854
|
-
return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
|
|
2992
|
+
return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array" && "BYTES_PER_ELEMENT" in a && a.BYTES_PER_ELEMENT === 1;
|
|
2993
|
+
}
|
|
2994
|
+
const atitle = (title) => title ? `"${title}" ` : "";
|
|
2995
|
+
/**
|
|
2996
|
+
* Asserts something is a non-negative integer.
|
|
2997
|
+
* @param n - number to validate
|
|
2998
|
+
* @param title - label included in thrown errors
|
|
2999
|
+
* @returns The validated number.
|
|
3000
|
+
* @throws On wrong argument types. {@link TypeError}
|
|
3001
|
+
* @throws On wrong argument ranges or values. {@link RangeError}
|
|
3002
|
+
* @example
|
|
3003
|
+
* Validate a non-negative integer option.
|
|
3004
|
+
* ```ts
|
|
3005
|
+
* anumber(32, 'length');
|
|
3006
|
+
* ```
|
|
3007
|
+
*/
|
|
3008
|
+
function anumber(n, title = "") {
|
|
3009
|
+
if (typeof n !== "number") throw new TypeError(atitle(title) + "expected number, got " + typeof n);
|
|
3010
|
+
if (!Number.isSafeInteger(n) || n < 0) throw new RangeError(atitle(title) + "expected integer >= 0, got " + n);
|
|
3011
|
+
return n;
|
|
2855
3012
|
}
|
|
2856
|
-
/**
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
3013
|
+
/**
|
|
3014
|
+
* Asserts something is Uint8Array.
|
|
3015
|
+
* @param value - value to validate
|
|
3016
|
+
* @param length - optional exact length constraint
|
|
3017
|
+
* @param title - label included in thrown errors
|
|
3018
|
+
* @returns The validated byte array.
|
|
3019
|
+
* @throws On wrong argument types. {@link TypeError}
|
|
3020
|
+
* @throws On wrong argument ranges or values. {@link RangeError}
|
|
3021
|
+
* @example
|
|
3022
|
+
* Validate that a value is a byte array.
|
|
3023
|
+
* ```ts
|
|
3024
|
+
* abytes(new Uint8Array([1, 2, 3]));
|
|
3025
|
+
* ```
|
|
3026
|
+
*/
|
|
3027
|
+
function abytes(value, length, title = "") {
|
|
3028
|
+
if (isBytes(value) && (length === void 0 || value.length === length)) return value;
|
|
3029
|
+
if (length !== void 0) anumber(length, "length");
|
|
3030
|
+
const bytes = isBytes(value);
|
|
3031
|
+
const ofLen = length !== void 0 ? ` of length ${length}` : "";
|
|
3032
|
+
const got = bytes ? `length=${value.length}` : `type=${typeof value}`;
|
|
3033
|
+
const message = atitle(title) + "expected Uint8Array" + ofLen + ", got " + got;
|
|
3034
|
+
if (!bytes) throw new TypeError(message);
|
|
3035
|
+
throw new RangeError(message);
|
|
2860
3036
|
}
|
|
2861
|
-
|
|
3037
|
+
const aobject = (value, label) => {
|
|
3038
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) throw new TypeError((label === "object" ? "" : `"${label}" `) + "expected object, got type=" + typeof value);
|
|
3039
|
+
};
|
|
3040
|
+
const aopts = (value, label) => {
|
|
3041
|
+
aobject(value, label);
|
|
3042
|
+
const proto = Object.getPrototypeOf(value);
|
|
3043
|
+
if (proto !== Object.prototype && proto !== null) throw new TypeError(`"${label}" expected plain object`);
|
|
3044
|
+
if (Object.hasOwn(value, "__proto__")) throw new TypeError(`"${label}.__proto__" is not allowed`);
|
|
3045
|
+
};
|
|
3046
|
+
/**
|
|
3047
|
+
* Asserts a hash instance has not been destroyed or finished.
|
|
3048
|
+
* @param instance - hash instance to validate
|
|
3049
|
+
* @param checkFinished - whether to reject finalized instances
|
|
3050
|
+
* @throws If the hash instance has already been destroyed or finalized. {@link Error}
|
|
3051
|
+
* @example
|
|
3052
|
+
* Validate that a hash instance is still usable.
|
|
3053
|
+
* ```ts
|
|
3054
|
+
* import { aexists } from '@noble/hashes/utils.js';
|
|
3055
|
+
* import { sha256 } from '@noble/hashes/sha2.js';
|
|
3056
|
+
* const hash = sha256.create();
|
|
3057
|
+
* aexists(hash);
|
|
3058
|
+
* ```
|
|
3059
|
+
*/
|
|
2862
3060
|
function aexists(instance, checkFinished = true) {
|
|
2863
|
-
if (instance.destroyed) throw new Error("
|
|
2864
|
-
if (checkFinished && instance.finished) throw new Error("
|
|
3061
|
+
if (instance.destroyed) throw new Error("hash was destroyed");
|
|
3062
|
+
if (checkFinished && instance.finished) throw new Error("digest() was already called");
|
|
2865
3063
|
}
|
|
2866
|
-
/**
|
|
3064
|
+
/**
|
|
3065
|
+
* Asserts output is a sufficiently-sized byte array.
|
|
3066
|
+
* @param out - destination buffer
|
|
3067
|
+
* @param instance - hash instance providing output length
|
|
3068
|
+
* Oversized buffers are allowed; downstream code only promises to fill the first `outputLen` bytes.
|
|
3069
|
+
* @throws On wrong argument types. {@link TypeError}
|
|
3070
|
+
* @throws On wrong argument ranges or values. {@link RangeError}
|
|
3071
|
+
* @example
|
|
3072
|
+
* Validate a caller-provided digest buffer.
|
|
3073
|
+
* ```ts
|
|
3074
|
+
* import { aoutput } from '@noble/hashes/utils.js';
|
|
3075
|
+
* import { sha256 } from '@noble/hashes/sha2.js';
|
|
3076
|
+
* const hash = sha256.create();
|
|
3077
|
+
* aoutput(new Uint8Array(hash.outputLen), hash);
|
|
3078
|
+
* ```
|
|
3079
|
+
*/
|
|
2867
3080
|
function aoutput(out, instance) {
|
|
2868
|
-
abytes(out);
|
|
3081
|
+
abytes(out, void 0, "output");
|
|
2869
3082
|
const min = instance.outputLen;
|
|
2870
|
-
if (out.length
|
|
3083
|
+
if (!(out.length >= min)) throw new RangeError("\"output\" expected length >= " + min);
|
|
2871
3084
|
}
|
|
2872
|
-
/**
|
|
3085
|
+
/**
|
|
3086
|
+
* Zeroizes typed arrays in place. Warning: JS provides no guarantees.
|
|
3087
|
+
* @param arrays - arrays to overwrite with zeros
|
|
3088
|
+
* @example
|
|
3089
|
+
* Zeroize sensitive buffers in place.
|
|
3090
|
+
* ```ts
|
|
3091
|
+
* clean(new Uint8Array([1, 2, 3]));
|
|
3092
|
+
* ```
|
|
3093
|
+
*/
|
|
2873
3094
|
function clean(...arrays) {
|
|
2874
3095
|
for (let i = 0; i < arrays.length; i++) arrays[i].fill(0);
|
|
2875
3096
|
}
|
|
2876
|
-
/**
|
|
3097
|
+
/**
|
|
3098
|
+
* Creates a DataView for byte-level manipulation.
|
|
3099
|
+
* @param arr - source typed array
|
|
3100
|
+
* @returns DataView over the same buffer region.
|
|
3101
|
+
* @example
|
|
3102
|
+
* Create a DataView over an existing buffer.
|
|
3103
|
+
* ```ts
|
|
3104
|
+
* createView(new Uint8Array(4));
|
|
3105
|
+
* ```
|
|
3106
|
+
*/
|
|
2877
3107
|
function createView(arr) {
|
|
2878
3108
|
return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
|
|
2879
3109
|
}
|
|
2880
|
-
/**
|
|
3110
|
+
/**
|
|
3111
|
+
* Rotate-right operation for uint32 values.
|
|
3112
|
+
* @param word - source word
|
|
3113
|
+
* @param shift - shift amount in bits
|
|
3114
|
+
* @returns Rotated word.
|
|
3115
|
+
* @example
|
|
3116
|
+
* Rotate a 32-bit word to the right.
|
|
3117
|
+
* ```ts
|
|
3118
|
+
* rotr(0x12345678, 8);
|
|
3119
|
+
* ```
|
|
3120
|
+
*/
|
|
2881
3121
|
function rotr(word, shift) {
|
|
2882
3122
|
return word << 32 - shift | word >>> shift;
|
|
2883
3123
|
}
|
|
2884
3124
|
const hasHexBuiltin = /* @__PURE__ */ (() => typeof Uint8Array.from([]).toHex === "function" && typeof Uint8Array.fromHex === "function")();
|
|
2885
3125
|
const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
|
|
2886
3126
|
/**
|
|
2887
|
-
* Convert byte array to hex string.
|
|
2888
|
-
*
|
|
3127
|
+
* Convert byte array to hex string.
|
|
3128
|
+
* Uses the built-in function when available and assumes it matches the tested
|
|
3129
|
+
* fallback semantics.
|
|
3130
|
+
* @param bytes - bytes to encode
|
|
3131
|
+
* @returns Lowercase hexadecimal string.
|
|
3132
|
+
* @throws On wrong argument types. {@link TypeError}
|
|
3133
|
+
* @example
|
|
3134
|
+
* Convert bytes to lowercase hexadecimal.
|
|
3135
|
+
* ```ts
|
|
3136
|
+
* bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])); // 'cafe0123'
|
|
3137
|
+
* ```
|
|
2889
3138
|
*/
|
|
2890
3139
|
function bytesToHex(bytes) {
|
|
2891
3140
|
abytes(bytes);
|
|
@@ -2896,70 +3145,169 @@ window.__ModuleLoader__.load({
|
|
|
2896
3145
|
}
|
|
2897
3146
|
/**
|
|
2898
3147
|
* Converts string to bytes using UTF8 encoding.
|
|
2899
|
-
*
|
|
3148
|
+
* Built-in doesn't validate input to be string: we do the check.
|
|
3149
|
+
* Non-ASCII details are delegated to the platform `TextEncoder`.
|
|
3150
|
+
* @param str - string to encode
|
|
3151
|
+
* @returns UTF-8 encoded bytes.
|
|
3152
|
+
* @throws On wrong argument types. {@link TypeError}
|
|
3153
|
+
* @example
|
|
3154
|
+
* Encode a string as UTF-8 bytes.
|
|
3155
|
+
* ```ts
|
|
3156
|
+
* utf8ToBytes('abc'); // Uint8Array.from([97, 98, 99])
|
|
3157
|
+
* ```
|
|
2900
3158
|
*/
|
|
2901
3159
|
function utf8ToBytes(str) {
|
|
2902
|
-
if (typeof str !== "string") throw new
|
|
2903
|
-
|
|
3160
|
+
if (typeof str !== "string") throw new TypeError("string expected");
|
|
3161
|
+
const encoded = new TextEncoder().encode(str);
|
|
3162
|
+
try {
|
|
3163
|
+
return new Uint8Array(encoded);
|
|
3164
|
+
} finally {
|
|
3165
|
+
clean(encoded);
|
|
3166
|
+
}
|
|
2904
3167
|
}
|
|
2905
3168
|
/**
|
|
2906
|
-
*
|
|
2907
|
-
*
|
|
2908
|
-
*
|
|
3169
|
+
* Merges default options and passed options.
|
|
3170
|
+
* @param defaults - base option object
|
|
3171
|
+
* @param opts - user overrides
|
|
3172
|
+
* @param title - label included in thrown override errors
|
|
3173
|
+
* @returns Fresh merged option object with a null prototype.
|
|
3174
|
+
* @throws On wrong argument types. {@link TypeError}
|
|
3175
|
+
* @example
|
|
3176
|
+
* Merge user overrides onto default options.
|
|
3177
|
+
* ```ts
|
|
3178
|
+
* checkOpts({ dkLen: 32 }, { asyncTick: 10 });
|
|
3179
|
+
* ```
|
|
2909
3180
|
*/
|
|
2910
|
-
function
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
return
|
|
2914
|
-
}
|
|
2915
|
-
/**
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
3181
|
+
function checkOpts(defaults, opts, title = "opts") {
|
|
3182
|
+
aopts(defaults, "defaults");
|
|
3183
|
+
if (opts !== void 0) aopts(opts, title);
|
|
3184
|
+
return Object.assign(Object.create(null), defaults, opts);
|
|
3185
|
+
}
|
|
3186
|
+
/**
|
|
3187
|
+
* Creates a callable hash function from a stateful class constructor.
|
|
3188
|
+
* @param hashCons - hash constructor or factory
|
|
3189
|
+
* @param info - optional metadata such as DER OID
|
|
3190
|
+
* @returns Frozen callable hash wrapper with `.create()`.
|
|
3191
|
+
* Wrapper construction eagerly calls `hashCons(undefined)` once to read
|
|
3192
|
+
* `outputLen` / `blockLen`, so constructor side effects happen at module
|
|
3193
|
+
* init time.
|
|
3194
|
+
* @throws On wrong argument types. {@link TypeError}
|
|
3195
|
+
* @example
|
|
3196
|
+
* Wrap a stateful hash constructor into a callable helper.
|
|
3197
|
+
* ```ts
|
|
3198
|
+
* import { createHasher } from '@noble/hashes/utils.js';
|
|
3199
|
+
* import { sha256 } from '@noble/hashes/sha2.js';
|
|
3200
|
+
* const wrapped = createHasher(sha256.create, { oid: sha256.oid });
|
|
3201
|
+
* wrapped(new Uint8Array([1]));
|
|
3202
|
+
* ```
|
|
3203
|
+
*/
|
|
3204
|
+
function createHasher(hashCons, info = {}) {
|
|
3205
|
+
if (typeof hashCons !== "function") throw new TypeError("\"hashCons\" expected function, got type=" + typeof hashCons);
|
|
3206
|
+
info = checkOpts({}, info, "info");
|
|
3207
|
+
const hashC = (msg, opts) => hashCons(opts).update(msg).digest();
|
|
3208
|
+
const tmp = hashCons(void 0);
|
|
2921
3209
|
hashC.outputLen = tmp.outputLen;
|
|
2922
3210
|
hashC.blockLen = tmp.blockLen;
|
|
2923
|
-
hashC.
|
|
2924
|
-
|
|
3211
|
+
hashC.canXOF = tmp.canXOF;
|
|
3212
|
+
hashC.create = (opts) => hashCons(opts);
|
|
3213
|
+
Object.assign(hashC, info);
|
|
3214
|
+
return Object.freeze(hashC);
|
|
2925
3215
|
}
|
|
2926
|
-
|
|
2927
|
-
|
|
3216
|
+
/**
|
|
3217
|
+
* Creates OID metadata for NIST hashes with prefix `06 09 60 86 48 01 65 03 04 02`.
|
|
3218
|
+
* @param suffix - final OID byte for the selected hash.
|
|
3219
|
+
* The helper accepts any byte even though only the documented NIST hash
|
|
3220
|
+
* suffixes are meaningful downstream.
|
|
3221
|
+
* @returns Object containing the DER-encoded OID.
|
|
3222
|
+
* @example
|
|
3223
|
+
* Build OID metadata for a NIST hash.
|
|
3224
|
+
* ```ts
|
|
3225
|
+
* oidNist(0x01);
|
|
3226
|
+
* ```
|
|
3227
|
+
*/
|
|
3228
|
+
const oidNist = (suffix) => ({ oid: Uint8Array.from([
|
|
3229
|
+
6,
|
|
3230
|
+
9,
|
|
3231
|
+
96,
|
|
3232
|
+
134,
|
|
3233
|
+
72,
|
|
3234
|
+
1,
|
|
3235
|
+
101,
|
|
3236
|
+
3,
|
|
3237
|
+
4,
|
|
3238
|
+
2,
|
|
3239
|
+
suffix
|
|
3240
|
+
]) });
|
|
3241
|
+
// node_modules/@noble/hashes/_md.js
|
|
2928
3242
|
/**
|
|
2929
3243
|
* Internal Merkle-Damgard hash utils.
|
|
2930
3244
|
* @module
|
|
2931
3245
|
*/
|
|
2932
|
-
/**
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
3246
|
+
/**
|
|
3247
|
+
* Shared 32-bit conditional boolean primitive reused by SHA-256, SHA-1, and MD5 `F`.
|
|
3248
|
+
* Returns bits from `b` when `a` is set, otherwise from `c`.
|
|
3249
|
+
* The XOR form is equivalent to MD5's `F(X,Y,Z) = XY v not(X)Z` because the masked terms never
|
|
3250
|
+
* set the same bit.
|
|
3251
|
+
* @param a - selector word
|
|
3252
|
+
* @param b - word chosen when selector bit is set
|
|
3253
|
+
* @param c - word chosen when selector bit is clear
|
|
3254
|
+
* @returns Mixed 32-bit word.
|
|
3255
|
+
* @example
|
|
3256
|
+
* Combine three words with the shared 32-bit choice primitive.
|
|
3257
|
+
* ```ts
|
|
3258
|
+
* Chi(0xffffffff, 0x12345678, 0x87654321);
|
|
3259
|
+
* ```
|
|
3260
|
+
*/
|
|
2945
3261
|
function Chi(a, b, c) {
|
|
2946
3262
|
return a & b ^ ~a & c;
|
|
2947
3263
|
}
|
|
2948
|
-
/**
|
|
3264
|
+
/**
|
|
3265
|
+
* Shared 32-bit majority primitive reused by SHA-256 and SHA-1.
|
|
3266
|
+
* Returns bits shared by at least two inputs.
|
|
3267
|
+
* @param a - first input word
|
|
3268
|
+
* @param b - second input word
|
|
3269
|
+
* @param c - third input word
|
|
3270
|
+
* @returns Mixed 32-bit word.
|
|
3271
|
+
* @example
|
|
3272
|
+
* Combine three words with the shared 32-bit majority primitive.
|
|
3273
|
+
* ```ts
|
|
3274
|
+
* Maj(0xffffffff, 0x12345678, 0x87654321);
|
|
3275
|
+
* ```
|
|
3276
|
+
*/
|
|
2949
3277
|
function Maj(a, b, c) {
|
|
2950
3278
|
return a & b ^ a & c ^ b & c;
|
|
2951
3279
|
}
|
|
2952
3280
|
/**
|
|
2953
3281
|
* Merkle-Damgard hash construction base class.
|
|
2954
3282
|
* Could be used to create MD5, RIPEMD, SHA1, SHA2.
|
|
3283
|
+
* Accepts only byte-aligned `Uint8Array` input, even when the underlying spec describes bit
|
|
3284
|
+
* strings with partial-byte tails.
|
|
3285
|
+
* @param blockLen - internal block size in bytes
|
|
3286
|
+
* @param outputLen - digest size in bytes
|
|
3287
|
+
* @param padOffset - trailing length field size in bytes
|
|
3288
|
+
* @param isLE - whether length and state words are encoded in little-endian
|
|
3289
|
+
* @example
|
|
3290
|
+
* Use a concrete subclass to get the shared Merkle-Damgard update/digest flow.
|
|
3291
|
+
* ```ts
|
|
3292
|
+
* import { _SHA1 } from '@noble/hashes/legacy.js';
|
|
3293
|
+
* const hash = new _SHA1();
|
|
3294
|
+
* hash.update(new Uint8Array([97, 98, 99]));
|
|
3295
|
+
* hash.digest();
|
|
3296
|
+
* ```
|
|
2955
3297
|
*/
|
|
2956
|
-
var HashMD = class
|
|
3298
|
+
var HashMD = class {
|
|
3299
|
+
blockLen;
|
|
3300
|
+
outputLen;
|
|
3301
|
+
canXOF = false;
|
|
3302
|
+
padOffset;
|
|
3303
|
+
isLE;
|
|
3304
|
+
buffer;
|
|
3305
|
+
view;
|
|
3306
|
+
finished = false;
|
|
3307
|
+
length = 0;
|
|
3308
|
+
pos = 0;
|
|
3309
|
+
destroyed = false;
|
|
2957
3310
|
constructor(blockLen, outputLen, padOffset, isLE) {
|
|
2958
|
-
super();
|
|
2959
|
-
this.finished = false;
|
|
2960
|
-
this.length = 0;
|
|
2961
|
-
this.pos = 0;
|
|
2962
|
-
this.destroyed = false;
|
|
2963
3311
|
this.blockLen = blockLen;
|
|
2964
3312
|
this.outputLen = outputLen;
|
|
2965
3313
|
this.padOffset = padOffset;
|
|
@@ -2969,27 +3317,29 @@ window.__ModuleLoader__.load({
|
|
|
2969
3317
|
}
|
|
2970
3318
|
update(data) {
|
|
2971
3319
|
aexists(this);
|
|
2972
|
-
data = toBytes(data);
|
|
2973
3320
|
abytes(data);
|
|
2974
3321
|
const { view, buffer, blockLen } = this;
|
|
2975
3322
|
const len = data.length;
|
|
3323
|
+
let processed = false;
|
|
2976
3324
|
for (let pos = 0; pos < len;) {
|
|
2977
3325
|
const take = Math.min(blockLen - this.pos, len - pos);
|
|
2978
3326
|
if (take === blockLen) {
|
|
2979
3327
|
const dataView = createView(data);
|
|
2980
3328
|
for (; blockLen <= len - pos; pos += blockLen) this.process(dataView, pos);
|
|
3329
|
+
processed = true;
|
|
2981
3330
|
continue;
|
|
2982
3331
|
}
|
|
2983
|
-
buffer.set(data.subarray(pos, pos + take), this.pos);
|
|
3332
|
+
buffer.set(pos === 0 && take === len ? data : data.subarray(pos, pos + take), this.pos);
|
|
2984
3333
|
this.pos += take;
|
|
2985
3334
|
pos += take;
|
|
2986
3335
|
if (this.pos === blockLen) {
|
|
2987
3336
|
this.process(view, 0);
|
|
2988
3337
|
this.pos = 0;
|
|
3338
|
+
processed = true;
|
|
2989
3339
|
}
|
|
2990
3340
|
}
|
|
2991
3341
|
this.length += data.length;
|
|
2992
|
-
this.roundClean();
|
|
3342
|
+
if (processed) this.roundClean();
|
|
2993
3343
|
return this;
|
|
2994
3344
|
}
|
|
2995
3345
|
digestInto(out) {
|
|
@@ -2999,20 +3349,19 @@ window.__ModuleLoader__.load({
|
|
|
2999
3349
|
const { buffer, view, blockLen, isLE } = this;
|
|
3000
3350
|
let { pos } = this;
|
|
3001
3351
|
buffer[pos++] = 128;
|
|
3002
|
-
|
|
3352
|
+
buffer.fill(0, pos);
|
|
3003
3353
|
if (this.padOffset > blockLen - pos) {
|
|
3004
3354
|
this.process(view, 0);
|
|
3005
|
-
|
|
3355
|
+
buffer.fill(0);
|
|
3006
3356
|
}
|
|
3007
|
-
|
|
3008
|
-
setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE);
|
|
3357
|
+
setU64FromNum(view, blockLen - 8, this.length * 8, isLE);
|
|
3009
3358
|
this.process(view, 0);
|
|
3010
|
-
|
|
3359
|
+
this.roundClean();
|
|
3360
|
+
const oview = out === buffer ? view : createView(out);
|
|
3011
3361
|
const len = this.outputLen;
|
|
3012
|
-
if (len % 4) throw new Error("_sha2: outputLen should be aligned to 32bit");
|
|
3013
3362
|
const outLen = len / 4;
|
|
3014
3363
|
const state = this.get();
|
|
3015
|
-
if (outLen > state.length) throw new Error("
|
|
3364
|
+
if (len % 4 || outLen > state.length) throw new Error("invalid outputLen");
|
|
3016
3365
|
for (let i = 0; i < outLen; i++) oview.setUint32(4 * i, state[i], isLE);
|
|
3017
3366
|
}
|
|
3018
3367
|
digest() {
|
|
@@ -3022,15 +3371,13 @@ window.__ModuleLoader__.load({
|
|
|
3022
3371
|
this.destroy();
|
|
3023
3372
|
return res;
|
|
3024
3373
|
}
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
to.set(...this.get());
|
|
3028
|
-
const { blockLen, buffer, length, finished, destroyed, pos } = this;
|
|
3374
|
+
_cloneIntoMeta(to) {
|
|
3375
|
+
const { buffer, length, finished, destroyed, pos } = this;
|
|
3029
3376
|
to.destroyed = destroyed;
|
|
3030
3377
|
to.finished = finished;
|
|
3031
3378
|
to.length = length;
|
|
3032
3379
|
to.pos = pos;
|
|
3033
|
-
if (
|
|
3380
|
+
if (pos) to.buffer.set(buffer);
|
|
3034
3381
|
return to;
|
|
3035
3382
|
}
|
|
3036
3383
|
clone() {
|
|
@@ -3041,7 +3388,9 @@ window.__ModuleLoader__.load({
|
|
|
3041
3388
|
* Initial SHA-2 state: fractional parts of square roots of first 16 primes 2..53.
|
|
3042
3389
|
* Check out `test/misc/sha2-gen-iv.js` for recomputation guide.
|
|
3043
3390
|
*/
|
|
3044
|
-
/** Initial SHA256 state.
|
|
3391
|
+
/** Initial SHA256 state from RFC 6234 §6.1: the first 32 bits of the fractional parts of the
|
|
3392
|
+
* square roots of the first eight prime numbers. Exported as a shared table; callers must treat
|
|
3393
|
+
* it as read-only because constructors copy words from it by index. */
|
|
3045
3394
|
const SHA256_IV = /* @__PURE__ */ Uint32Array.from([
|
|
3046
3395
|
1779033703,
|
|
3047
3396
|
3144134277,
|
|
@@ -3052,18 +3401,17 @@ window.__ModuleLoader__.load({
|
|
|
3052
3401
|
528734635,
|
|
3053
3402
|
1541459225
|
|
3054
3403
|
]);
|
|
3055
|
-
|
|
3056
|
-
//#region node_modules/@noble/hashes/esm/sha2.js
|
|
3404
|
+
// node_modules/@noble/hashes/sha2.js
|
|
3057
3405
|
/**
|
|
3058
3406
|
* SHA2 hash function. A.k.a. sha256, sha384, sha512, sha512_224, sha512_256.
|
|
3059
3407
|
* SHA256 is the fastest hash implementable in JS, even faster than Blake3.
|
|
3060
|
-
* Check out
|
|
3061
|
-
*
|
|
3408
|
+
* Check out {@link https://www.rfc-editor.org/rfc/rfc4634 | RFC 4634} and
|
|
3409
|
+
* {@link https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf | FIPS 180-4}.
|
|
3062
3410
|
* @module
|
|
3063
3411
|
*/
|
|
3064
3412
|
/**
|
|
3065
|
-
*
|
|
3066
|
-
*
|
|
3413
|
+
* SHA-224 / SHA-256 round constants from RFC 6234 §5.1: the first 32 bits
|
|
3414
|
+
* of the cube roots of the first 64 primes (2..311).
|
|
3067
3415
|
*/
|
|
3068
3416
|
const SHA256_K = /* @__PURE__ */ Uint32Array.from([
|
|
3069
3417
|
1116352408,
|
|
@@ -3131,19 +3479,28 @@ window.__ModuleLoader__.load({
|
|
|
3131
3479
|
3204031479,
|
|
3132
3480
|
3329325298
|
|
3133
3481
|
]);
|
|
3134
|
-
/** Reusable
|
|
3482
|
+
/** Reusable SHA-224 / SHA-256 message schedule buffer `W_t` from RFC 6234 §6.2 step 1. */
|
|
3135
3483
|
const SHA256_W = /* @__PURE__ */ new Uint32Array(64);
|
|
3136
|
-
|
|
3137
|
-
|
|
3484
|
+
/** Internal SHA-224 / SHA-256 compression engine from RFC 6234 §6.2. */
|
|
3485
|
+
var SHA2_32B = class extends HashMD {
|
|
3486
|
+
A = 0;
|
|
3487
|
+
B = 0;
|
|
3488
|
+
C = 0;
|
|
3489
|
+
D = 0;
|
|
3490
|
+
E = 0;
|
|
3491
|
+
F = 0;
|
|
3492
|
+
G = 0;
|
|
3493
|
+
H = 0;
|
|
3494
|
+
constructor(outputLen, IV) {
|
|
3138
3495
|
super(64, outputLen, 8, false);
|
|
3139
|
-
this.A =
|
|
3140
|
-
this.B =
|
|
3141
|
-
this.C =
|
|
3142
|
-
this.D =
|
|
3143
|
-
this.E =
|
|
3144
|
-
this.F =
|
|
3145
|
-
this.G =
|
|
3146
|
-
this.H =
|
|
3496
|
+
this.A = IV[0] | 0;
|
|
3497
|
+
this.B = IV[1] | 0;
|
|
3498
|
+
this.C = IV[2] | 0;
|
|
3499
|
+
this.D = IV[3] | 0;
|
|
3500
|
+
this.E = IV[4] | 0;
|
|
3501
|
+
this.F = IV[5] | 0;
|
|
3502
|
+
this.G = IV[6] | 0;
|
|
3503
|
+
this.H = IV[7] | 0;
|
|
3147
3504
|
}
|
|
3148
3505
|
get() {
|
|
3149
3506
|
const { A, B, C, D, E, F, G, H } = this;
|
|
@@ -3168,6 +3525,10 @@ window.__ModuleLoader__.load({
|
|
|
3168
3525
|
this.G = G | 0;
|
|
3169
3526
|
this.H = H | 0;
|
|
3170
3527
|
}
|
|
3528
|
+
_cloneInto(to) {
|
|
3529
|
+
(to ||= new this.constructor()).set(...this.get());
|
|
3530
|
+
return this._cloneIntoMeta(to);
|
|
3531
|
+
}
|
|
3171
3532
|
process(view, offset) {
|
|
3172
3533
|
for (let i = 0; i < 16; i++, offset += 4) SHA256_W[i] = view.getUint32(offset, false);
|
|
3173
3534
|
for (let i = 16; i < 64; i++) {
|
|
@@ -3205,24 +3566,34 @@ window.__ModuleLoader__.load({
|
|
|
3205
3566
|
clean(SHA256_W);
|
|
3206
3567
|
}
|
|
3207
3568
|
destroy() {
|
|
3569
|
+
this.destroyed = true;
|
|
3208
3570
|
this.set(0, 0, 0, 0, 0, 0, 0, 0);
|
|
3209
3571
|
clean(this.buffer);
|
|
3210
3572
|
}
|
|
3211
3573
|
};
|
|
3212
|
-
|
|
3213
|
-
|
|
3574
|
+
/** Internal SHA-256 hash class grounded in RFC 6234 §6.2. */
|
|
3575
|
+
var _SHA256 = class extends SHA2_32B {
|
|
3576
|
+
constructor() {
|
|
3577
|
+
super(32, SHA256_IV);
|
|
3578
|
+
}
|
|
3579
|
+
};
|
|
3214
3580
|
/**
|
|
3215
|
-
* SHA2-256
|
|
3216
|
-
*
|
|
3217
|
-
* To break sha256 using birthday attack, attackers need to try 2^128 hashes.
|
|
3218
|
-
* BTC network is doing 2^70 hashes/sec (2^95 hashes/year) as per 2025.
|
|
3581
|
+
* SHA2-256 hash function from RFC 4634. In JS it's the fastest: even faster than Blake3. Some info:
|
|
3219
3582
|
*
|
|
3220
|
-
*
|
|
3221
|
-
*
|
|
3222
|
-
*
|
|
3583
|
+
* - Trying 2^128 hashes would get 50% chance of collision, using birthday attack.
|
|
3584
|
+
* - BTC network is doing 2^70 hashes/sec (2^95 hashes/year) as per 2025.
|
|
3585
|
+
* - Each sha256 hash is executing 2^18 bit operations.
|
|
3586
|
+
* - Good 2024 ASICs can do 200Th/sec with 3500 watts of power, corresponding to 2^36 hashes/joule.
|
|
3587
|
+
* @param msg - message bytes to hash
|
|
3588
|
+
* @param opts - Reserved hash options.
|
|
3589
|
+
* @returns Digest bytes.
|
|
3590
|
+
* @example
|
|
3591
|
+
* Hash a message with SHA2-256.
|
|
3592
|
+
* ```ts
|
|
3593
|
+
* sha256(new Uint8Array([97, 98, 99]));
|
|
3594
|
+
* ```
|
|
3223
3595
|
*/
|
|
3224
|
-
|
|
3225
|
-
const sha256 = /* @__PURE__ */ createHasher(() => new SHA256());
|
|
3596
|
+
const sha256 = /* @__PURE__ */ createHasher(() => new _SHA256(), /* @__PURE__ */ oidNist(1));
|
|
3226
3597
|
Object.freeze({
|
|
3227
3598
|
title: 80,
|
|
3228
3599
|
body: 200,
|
|
@@ -3231,7 +3602,7 @@ window.__ModuleLoader__.load({
|
|
|
3231
3602
|
const MAX_SEEN_QUESTION_KEYS = 20;
|
|
3232
3603
|
/** A bounded native identifier derived from the complete, case-sensitive wire ID. */
|
|
3233
3604
|
function notificationIdentity(value) {
|
|
3234
|
-
return bytesToHex(sha256(JSON.stringify(value)).subarray(0, 16));
|
|
3605
|
+
return bytesToHex(sha256(utf8ToBytes(JSON.stringify(value))).subarray(0, 16));
|
|
3235
3606
|
}
|
|
3236
3607
|
/** Stable per-turn tag so concurrent sessions keep separate notifications. */
|
|
3237
3608
|
function taskCompletionTag(sessionId, turn) {
|
|
@@ -3521,8 +3892,7 @@ window.__ModuleLoader__.load({
|
|
|
3521
3892
|
if (anchorTimer !== 0) window.clearTimeout(anchorTimer);
|
|
3522
3893
|
};
|
|
3523
3894
|
}
|
|
3524
|
-
|
|
3525
|
-
//#region src/mobile-composer-toolbar.ts
|
|
3895
|
+
// src/mobile-composer-toolbar.ts
|
|
3526
3896
|
/**
|
|
3527
3897
|
* Compact the stock InputBar without changing its React ownership, handlers,
|
|
3528
3898
|
* activity tree or the two groups observed by DSH's model-width controller.
|
|
@@ -3557,8 +3927,7 @@ window.__ModuleLoader__.load({
|
|
|
3557
3927
|
[data-dsh-mobile-composer-model-label] { flex:1 1 auto !important; max-width:none !important; min-width:0 !important; overflow:hidden !important; text-overflow:ellipsis !important; white-space:nowrap !important; }
|
|
3558
3928
|
}
|
|
3559
3929
|
`;
|
|
3560
|
-
|
|
3561
|
-
//#region src/browser-file-picker.ts
|
|
3930
|
+
// src/browser-file-picker.ts
|
|
3562
3931
|
/** Browser chooser lifetime shared by camera controls and the extension SDK. */
|
|
3563
3932
|
const BROWSER_FILE_PICKER_DEADLINE_MS = 3e5;
|
|
3564
3933
|
const browserEnvironment = {
|
|
@@ -3678,8 +4047,21 @@ window.__ModuleLoader__.load({
|
|
|
3678
4047
|
}
|
|
3679
4048
|
});
|
|
3680
4049
|
}
|
|
3681
|
-
|
|
3682
|
-
|
|
4050
|
+
// src/mobile-layout-attributes.ts
|
|
4051
|
+
/**
|
|
4052
|
+
* Root marker the dedicated layout publishes for its wide/narrow band.
|
|
4053
|
+
*
|
|
4054
|
+
* The band depends on the device screen size, which a media query cannot read,
|
|
4055
|
+
* so the layout decides it in JS and writes this attribute on `.dshm-shell`:
|
|
4056
|
+
* `"1"` docks the sidebar, anything else — `"0"`, or no marker — is the overlay
|
|
4057
|
+
* drawer. The stylesheet and the sidebar scroll adapter both follow the marker,
|
|
4058
|
+
* so the band has exactly one owner.
|
|
4059
|
+
*
|
|
4060
|
+
* This module stays free of imports: the dedicated layout bundle and the native
|
|
4061
|
+
* client bundle both use it, and neither should pull the other in.
|
|
4062
|
+
*/
|
|
4063
|
+
const WIDE_LAYOUT_ATTRIBUTE = "data-dshm-wide";
|
|
4064
|
+
// src/mobile-sidebar-scroll.ts
|
|
3683
4065
|
function sidebarRestoreTop(snapshot, anchorTop) {
|
|
3684
4066
|
return Math.max(0, anchorTop === void 0 || snapshot.offset === void 0 ? snapshot.top : anchorTop - snapshot.offset);
|
|
3685
4067
|
}
|
|
@@ -3709,7 +4091,16 @@ window.__ModuleLoader__.load({
|
|
|
3709
4091
|
function installMobileSidebarScrollMemory() {
|
|
3710
4092
|
const memories = /* @__PURE__ */ new Map();
|
|
3711
4093
|
const stockViewport = window.matchMedia("(max-width:720px)");
|
|
3712
|
-
|
|
4094
|
+
/**
|
|
4095
|
+
* Whether the dedicated layout currently renders the sidebar as an overlay
|
|
4096
|
+
* drawer. That is the layout's own decision on the shell — a landscape phone
|
|
4097
|
+
* is an overlay there although its viewport is wide — so a width query would
|
|
4098
|
+
* disable this memory exactly where the drawer is hardest to reach.
|
|
4099
|
+
*/
|
|
4100
|
+
const drawerBand = () => {
|
|
4101
|
+
const shell = document.querySelector(".dshm-shell");
|
|
4102
|
+
return shell === null || shell.getAttribute("data-dshm-wide") !== "1";
|
|
4103
|
+
};
|
|
3713
4104
|
let root;
|
|
3714
4105
|
let open = false;
|
|
3715
4106
|
let ports = /* @__PURE__ */ new Map();
|
|
@@ -3760,7 +4151,7 @@ window.__ModuleLoader__.load({
|
|
|
3760
4151
|
const sync = () => {
|
|
3761
4152
|
if (disposed) return;
|
|
3762
4153
|
const next = document.querySelector("[data-dsh-mobile-sidebar-root]") ?? void 0;
|
|
3763
|
-
const mobile = next?.closest("[data-pane=\"sidebar\"]") != null ?
|
|
4154
|
+
const mobile = next?.closest("[data-pane=\"sidebar\"]") != null ? drawerBand() : stockViewport.matches;
|
|
3764
4155
|
if (next !== root) {
|
|
3765
4156
|
cancel();
|
|
3766
4157
|
ports.clear();
|
|
@@ -3805,7 +4196,6 @@ window.__ModuleLoader__.load({
|
|
|
3805
4196
|
remember();
|
|
3806
4197
|
};
|
|
3807
4198
|
stockViewport.addEventListener("change", sync);
|
|
3808
|
-
dedicatedViewport.addEventListener("change", sync);
|
|
3809
4199
|
document.addEventListener("scroll", onScroll, true);
|
|
3810
4200
|
for (const type of [
|
|
3811
4201
|
"pointerdown",
|
|
@@ -3820,7 +4210,6 @@ window.__ModuleLoader__.load({
|
|
|
3820
4210
|
disposed = true;
|
|
3821
4211
|
cancel();
|
|
3822
4212
|
stockViewport.removeEventListener("change", sync);
|
|
3823
|
-
dedicatedViewport.removeEventListener("change", sync);
|
|
3824
4213
|
document.removeEventListener("scroll", onScroll, true);
|
|
3825
4214
|
for (const type of [
|
|
3826
4215
|
"pointerdown",
|
|
@@ -3835,8 +4224,7 @@ window.__ModuleLoader__.load({
|
|
|
3835
4224
|
}
|
|
3836
4225
|
};
|
|
3837
4226
|
}
|
|
3838
|
-
|
|
3839
|
-
//#region src/native-mobile.ts
|
|
4227
|
+
// src/native-mobile.ts
|
|
3840
4228
|
/**
|
|
3841
4229
|
* Viewport below which the injected chrome becomes an overlay drawer: the
|
|
3842
4230
|
* sidebar slides in as a sheet, the right panel as a drawer, and the scrim dims
|
|
@@ -4176,6 +4564,14 @@ window.__ModuleLoader__.load({
|
|
|
4176
4564
|
});
|
|
4177
4565
|
}
|
|
4178
4566
|
/**
|
|
4567
|
+
* Detect upstream ownership before applying legacy frame geometry.
|
|
4568
|
+
* @param frame - the stock frame's element lookup, if mounted.
|
|
4569
|
+
* @returns whether it provides the responsive sidebar opener.
|
|
4570
|
+
*/
|
|
4571
|
+
function stockOwnsMobileDrawer(frame) {
|
|
4572
|
+
return frame?.querySelector("[data-sidebar-opener]") != null;
|
|
4573
|
+
}
|
|
4574
|
+
/**
|
|
4179
4575
|
* Mirror the classes of the stock Add-menu item on an injected attachment action.
|
|
4180
4576
|
*
|
|
4181
4577
|
* An empty class name is not nullish: trusting it would strip the plugin's own
|
|
@@ -5464,11 +5860,27 @@ window.__ModuleLoader__.load({
|
|
|
5464
5860
|
const nextFrame = resolveNativeMobileFrame(document, dedicatedCenter);
|
|
5465
5861
|
if (frame !== nextFrame) frame?.removeAttribute("data-dsh-mobile-frame");
|
|
5466
5862
|
frame = nextFrame;
|
|
5467
|
-
|
|
5468
|
-
|
|
5863
|
+
const nativeDrawer = stockOwnsMobileDrawer(frame);
|
|
5864
|
+
if (frame !== void 0) {
|
|
5865
|
+
if (nativeDrawer) frame.removeAttribute("data-dsh-mobile-frame");
|
|
5866
|
+
else frame.dataset.dshMobileFrame = "true";
|
|
5867
|
+
}
|
|
5868
|
+
if (nativeDrawer) {
|
|
5869
|
+
sidebar?.removeAttribute("data-dsh-mobile-sidebar");
|
|
5870
|
+
sidebarRoot?.removeAttribute("data-dsh-mobile-sidebar-root");
|
|
5871
|
+
toggle?.removeAttribute("data-dsh-mobile-toggle");
|
|
5872
|
+
for (const node of frame.querySelectorAll("[data-dsh-mobile-details],[data-dsh-mobile-handle]")) {
|
|
5873
|
+
node.removeAttribute("data-dsh-mobile-details");
|
|
5874
|
+
node.removeAttribute("data-dsh-mobile-handle");
|
|
5875
|
+
}
|
|
5876
|
+
sidebarRoot = void 0;
|
|
5877
|
+
toggle = void 0;
|
|
5878
|
+
backdrop.hidden = true;
|
|
5879
|
+
}
|
|
5880
|
+
sidebar = nativeDrawer ? void 0 : frame === void 0 ? document.querySelector(".dshm-drawer") ?? void 0 : firstByClassSuffix(frame, "_sidebarCol");
|
|
5469
5881
|
const center = frame === void 0 ? dedicatedCenter : firstByClassSuffix(frame, "_centerCol");
|
|
5470
|
-
const details = frame === void 0 ? void 0 : firstByClassSuffix(frame, "_detailsCol");
|
|
5471
|
-
const handle = frame === void 0 ? void 0 : firstByClassSuffix(frame, "_handle");
|
|
5882
|
+
const details = frame === void 0 || nativeDrawer ? void 0 : firstByClassSuffix(frame, "_detailsCol");
|
|
5883
|
+
const handle = frame === void 0 || nativeDrawer ? void 0 : firstByClassSuffix(frame, "_handle");
|
|
5472
5884
|
markNativeMobileSettings(document);
|
|
5473
5885
|
if (center === void 0) {
|
|
5474
5886
|
syncPanHeader(void 0);
|
|
@@ -5482,12 +5894,15 @@ window.__ModuleLoader__.load({
|
|
|
5482
5894
|
return;
|
|
5483
5895
|
}
|
|
5484
5896
|
if (center !== void 0) {
|
|
5485
|
-
center.
|
|
5897
|
+
if (nativeDrawer) center.removeAttribute("data-dsh-mobile-center");
|
|
5898
|
+
else center.dataset.dshMobileCenter = "true";
|
|
5486
5899
|
const header = center.querySelector("header") ?? void 0;
|
|
5487
|
-
header?.
|
|
5488
|
-
|
|
5900
|
+
if (nativeDrawer) header?.removeAttribute("data-dsh-mobile-header");
|
|
5901
|
+
else header?.setAttribute("data-dsh-mobile-header", "true");
|
|
5902
|
+
syncPanHeader(nativeDrawer ? void 0 : header);
|
|
5489
5903
|
viewArea = firstByClassSuffix(center, "_viewArea");
|
|
5490
|
-
if (
|
|
5904
|
+
if (nativeDrawer) viewArea?.removeAttribute("data-dsh-mobile-view");
|
|
5905
|
+
else if (viewArea !== void 0) viewArea.dataset.dshMobileView = "true";
|
|
5491
5906
|
const conversation = center.querySelector("[data-conversation-scroll]");
|
|
5492
5907
|
const composerCard = center.querySelector("[data-composer-card]");
|
|
5493
5908
|
bindHistoryScroller(conversation ?? void 0, composerCard ?? null);
|
|
@@ -5594,7 +6009,8 @@ window.__ModuleLoader__.load({
|
|
|
5594
6009
|
"readonly",
|
|
5595
6010
|
"aria-busy",
|
|
5596
6011
|
"aria-selected",
|
|
5597
|
-
"data-dsh-mobile-session"
|
|
6012
|
+
"data-dsh-mobile-session",
|
|
6013
|
+
WIDE_LAYOUT_ATTRIBUTE
|
|
5598
6014
|
]
|
|
5599
6015
|
});
|
|
5600
6016
|
overlayQuery.addEventListener("change", schedule);
|
|
@@ -5696,8 +6112,7 @@ window.__ModuleLoader__.load({
|
|
|
5696
6112
|
delete document.documentElement.dataset.dshMobileInput;
|
|
5697
6113
|
};
|
|
5698
6114
|
}
|
|
5699
|
-
|
|
5700
|
-
//#region src/voice-session.ts
|
|
6115
|
+
// src/voice-session.ts
|
|
5701
6116
|
/** Screen wake-lock ownership and mobile composer focus during DSH dictation. */
|
|
5702
6117
|
/** Voice phases during which the user is dictating. */
|
|
5703
6118
|
const DICTATING_PHASES = [
|
|
@@ -6154,8 +6569,7 @@ window.__ModuleLoader__.load({
|
|
|
6154
6569
|
}
|
|
6155
6570
|
};
|
|
6156
6571
|
}
|
|
6157
|
-
|
|
6158
|
-
//#region src/mobile-font-capabilities.ts
|
|
6572
|
+
// src/mobile-font-capabilities.ts
|
|
6159
6573
|
const NO_ADVANCED_MOBILE_TYPOGRAPHY = Object.freeze({
|
|
6160
6574
|
codeSize: false,
|
|
6161
6575
|
textFamily: false,
|
|
@@ -6211,8 +6625,7 @@ window.__ModuleLoader__.load({
|
|
|
6211
6625
|
code.remove();
|
|
6212
6626
|
}
|
|
6213
6627
|
}
|
|
6214
|
-
|
|
6215
|
-
//#region src/mobile-font.ts
|
|
6628
|
+
// src/mobile-font.ts
|
|
6216
6629
|
/** Device-local typography for authenticated mobile pages, without Host settings writes. */
|
|
6217
6630
|
const MOBILE_FONT_STORAGE_KEY = "dsh-mobile.content-font-size.v1";
|
|
6218
6631
|
const MOBILE_TYPOGRAPHY_STORAGE_KEY = "dsh-mobile.typography.v1";
|
|
@@ -6638,8 +7051,7 @@ window.__ModuleLoader__.load({
|
|
|
6638
7051
|
}
|
|
6639
7052
|
}, copy.reset)));
|
|
6640
7053
|
}
|
|
6641
|
-
|
|
6642
|
-
//#region src/mobile-display-scale.ts
|
|
7054
|
+
// src/mobile-display-scale.ts
|
|
6643
7055
|
/** Native App page scaling in DSH General settings, independent from local typography. */
|
|
6644
7056
|
/** Validate the native reply before displaying or reusing its values in a request. */
|
|
6645
7057
|
function parseMobileDisplayScale(value) {
|
|
@@ -6856,8 +7268,7 @@ window.__ModuleLoader__.load({
|
|
|
6856
7268
|
}
|
|
6857
7269
|
}, copy.reset)));
|
|
6858
7270
|
}
|
|
6859
|
-
|
|
6860
|
-
//#region src/mobile-native-settings-action.ts
|
|
7271
|
+
// src/mobile-native-settings-action.ts
|
|
6861
7272
|
/** Own capability discovery and explicit calls; native actions retain the App's own timeout. */
|
|
6862
7273
|
var MobileNativeSettingsActionController = class {
|
|
6863
7274
|
action;
|
|
@@ -6966,8 +7377,7 @@ window.__ModuleLoader__.load({
|
|
|
6966
7377
|
for (const listener of this.listeners) listener();
|
|
6967
7378
|
}
|
|
6968
7379
|
};
|
|
6969
|
-
|
|
6970
|
-
//#region src/local-admin-host.ts
|
|
7380
|
+
// src/local-admin-host.ts
|
|
6971
7381
|
/** Browser-safe desktop-admin Host checks. Do not import Node APIs here. */
|
|
6972
7382
|
const DESKTOP_ADMIN_HEADER = "x-dsh-mobile-desktop-admin";
|
|
6973
7383
|
const DESKTOP_ADMIN_MARKER = "dsh-app://app";
|
|
@@ -7031,8 +7441,7 @@ window.__ModuleLoader__.load({
|
|
|
7031
7441
|
const query = search.startsWith("?") ? search.slice(1) : search;
|
|
7032
7442
|
return (protocol === "dsh-app:" ? hostname === "app" : (protocol === "" || protocol === "http:" || protocol === "https:") && isLocalAdminHostname(hostname)) && frontend !== "dedicated" && !new URLSearchParams(query).has("dsh-mobile-preview");
|
|
7033
7443
|
}
|
|
7034
|
-
|
|
7035
|
-
//#region src/client-module-presentation.ts
|
|
7444
|
+
// src/client-module-presentation.ts
|
|
7036
7445
|
/** Group boot-protected entries before considering their package namespace.
|
|
7037
7446
|
* @param entry - Catalog entry with server-owned required and dependency fields.
|
|
7038
7447
|
* @returns Display group, never an authorization or compatibility decision.
|
|
@@ -7109,6 +7518,21 @@ window.__ModuleLoader__.load({
|
|
|
7109
7518
|
}
|
|
7110
7519
|
return entries.filter((entry) => !keep.has(entry.id)).map((entry) => entry.id);
|
|
7111
7520
|
}
|
|
7521
|
+
/**
|
|
7522
|
+
* Describe the optional modules removed by the minimal preset without treating unmeasured sizes as zero.
|
|
7523
|
+
* @param entries - The complete displayed catalog, including required dependencies.
|
|
7524
|
+
* @returns Excluded count, known gzip bytes when measured, and the number still unmeasured.
|
|
7525
|
+
*/
|
|
7526
|
+
function clientModuleMinimalImpact(entries) {
|
|
7527
|
+
const excluded = new Set(clientModuleMinimalExclusion(entries));
|
|
7528
|
+
const rows = entries.filter((entry) => excluded.has(entry.id));
|
|
7529
|
+
const measured = rows.filter((entry) => entry.gzipBytes !== void 0);
|
|
7530
|
+
return {
|
|
7531
|
+
count: rows.length,
|
|
7532
|
+
...measured.length === 0 ? {} : { gzipBytes: measured.reduce((sum, entry) => sum + entry.gzipBytes, 0) },
|
|
7533
|
+
unknown: rows.length - measured.length
|
|
7534
|
+
};
|
|
7535
|
+
}
|
|
7112
7536
|
/** Editable selections retain unknown server exclusions and never cascade dependencies. */
|
|
7113
7537
|
var ClientModuleDraft = class {
|
|
7114
7538
|
initial;
|
|
@@ -7236,8 +7660,7 @@ window.__ModuleLoader__.load({
|
|
|
7236
7660
|
return filter === "loaded" ? [] : this.invalidExclusions.filter((entry) => matchesQuery(entry.id, query));
|
|
7237
7661
|
}
|
|
7238
7662
|
};
|
|
7239
|
-
|
|
7240
|
-
//#region src/client-module-ui.ts
|
|
7663
|
+
// src/client-module-ui.ts
|
|
7241
7664
|
/** Device-local module selection and the computer's defaults share a read-only catalog. */
|
|
7242
7665
|
const CLIENT_MODULE_COPY = {
|
|
7243
7666
|
zh: {
|
|
@@ -7266,6 +7689,7 @@ window.__ModuleLoader__.load({
|
|
|
7266
7689
|
failed: "暂时无法读取模块。请确认移动访问已启用后重试。",
|
|
7267
7690
|
saveFailed: "未确认保存成功,已保留你的选择。可重新保存,或重新读取已保存设置。",
|
|
7268
7691
|
conflict: "无法保存:",
|
|
7692
|
+
catalogChanged: "模块目录已变化(插件或版本有更新),本次保存已取消。请点「重新读取」,确认后再保存。",
|
|
7269
7693
|
computerSource: "当前来源:电脑默认设置",
|
|
7270
7694
|
deviceSource: "当前来源:本设备设置",
|
|
7271
7695
|
pluginSource: "当前来源:插件默认设置",
|
|
@@ -7295,6 +7719,7 @@ window.__ModuleLoader__.load({
|
|
|
7295
7719
|
totalUnknown: "勾选合计:部分模块未测到体积",
|
|
7296
7720
|
minimal: "仅必需(最小加载)",
|
|
7297
7721
|
minimalConfirm: "把除了启动必需项及其依赖之外全部设为不加载?保存后下次打开生效。",
|
|
7722
|
+
minimalDetail: "将排除 {count} 个可选模块;已测 gzip 合计 {size},另有 {unknown} 项体积未知。启动必需项及其依赖会保留。",
|
|
7298
7723
|
retry: "重新读取",
|
|
7299
7724
|
saving: "正在保存…",
|
|
7300
7725
|
readTimeout: "读取超时。当前页面和已保存设置未变,请重试。",
|
|
@@ -7332,6 +7757,7 @@ window.__ModuleLoader__.load({
|
|
|
7332
7757
|
failed: "Could not read modules. Enable mobile access and try again.",
|
|
7333
7758
|
saveFailed: "Saving was not confirmed. Your choices are kept. Save again or reread the saved settings.",
|
|
7334
7759
|
conflict: "Could not save: ",
|
|
7760
|
+
catalogChanged: "The module catalog changed (a plugin or version update). This save was cancelled; reread the settings, then confirm again.",
|
|
7335
7761
|
computerSource: "Source: computer defaults",
|
|
7336
7762
|
deviceSource: "Source: this device’s settings",
|
|
7337
7763
|
pluginSource: "Source: plugin defaults",
|
|
@@ -7361,6 +7787,7 @@ window.__ModuleLoader__.load({
|
|
|
7361
7787
|
totalUnknown: "Selection total: some sizes are unknown",
|
|
7362
7788
|
minimal: "Required only (minimal load)",
|
|
7363
7789
|
minimalConfirm: "Mark everything except required modules and their dependencies as not loaded? Applies on the next open after saving.",
|
|
7790
|
+
minimalDetail: "This excludes {count} optional modules; measured gzip total: {size}; {unknown} remain unmeasured. Required modules and their dependencies stay loaded.",
|
|
7364
7791
|
retry: "Reread settings",
|
|
7365
7792
|
saving: "Saving…",
|
|
7366
7793
|
readTimeout: "Reading timed out. This page and saved settings are unchanged; try again.",
|
|
@@ -7398,6 +7825,7 @@ window.__ModuleLoader__.load({
|
|
|
7398
7825
|
failed: "Impossibile leggere i moduli. Abilita accesso mobile e riprova.",
|
|
7399
7826
|
saveFailed: "Salvataggio non confermato. Le scelte restano; salva di nuovo o rileggi le impostazioni salvate.",
|
|
7400
7827
|
conflict: "Impossibile salvare: ",
|
|
7828
|
+
catalogChanged: "Il catalogo dei moduli è cambiato (aggiornamento di plugin o versione). Salvataggio annullato: rileggi le impostazioni e conferma di nuovo.",
|
|
7401
7829
|
computerSource: "Origine: predefiniti del computer",
|
|
7402
7830
|
deviceSource: "Origine: impostazioni del dispositivo",
|
|
7403
7831
|
pluginSource: "Origine: predefiniti del plugin",
|
|
@@ -7427,6 +7855,7 @@ window.__ModuleLoader__.load({
|
|
|
7427
7855
|
totalUnknown: "Totale selezione: alcune dimensioni sono sconosciute",
|
|
7428
7856
|
minimal: "Solo obbligatori (caricamento minimo)",
|
|
7429
7857
|
minimalConfirm: "Impostare come non caricati tutti i moduli tranne gli obbligatori e le loro dipendenze? Vale alla prossima apertura dopo il salvataggio.",
|
|
7858
|
+
minimalDetail: "Verranno esclusi {count} moduli facoltativi; totale gzip misurato: {size}; {unknown} non misurati. Gli obbligatori e le loro dipendenze restano caricati.",
|
|
7430
7859
|
retry: "Rileggi impostazioni",
|
|
7431
7860
|
saving: "Salvataggio…",
|
|
7432
7861
|
readTimeout: "Lettura scaduta. Pagina e impostazioni salvate non cambiano; riprova.",
|
|
@@ -7441,9 +7870,11 @@ window.__ModuleLoader__.load({
|
|
|
7441
7870
|
};
|
|
7442
7871
|
var ClientModuleUiConflict = class extends Error {
|
|
7443
7872
|
detail;
|
|
7444
|
-
|
|
7873
|
+
code;
|
|
7874
|
+
constructor(detail, code = "invalid_selection") {
|
|
7445
7875
|
super("client_module_conflict");
|
|
7446
7876
|
this.detail = detail;
|
|
7877
|
+
this.code = code;
|
|
7447
7878
|
}
|
|
7448
7879
|
};
|
|
7449
7880
|
/** A deadline does not imply that a POST was rolled back by the server. */
|
|
@@ -7503,12 +7934,16 @@ window.__ModuleLoader__.load({
|
|
|
7503
7934
|
};
|
|
7504
7935
|
});
|
|
7505
7936
|
if (new Set(entries.map((entry) => entry.id)).size !== entries.length) throw new Error("invalid_module_catalog");
|
|
7937
|
+
const revision = value.revision;
|
|
7938
|
+
if (revision !== void 0 && (typeof revision !== "string" || revision === "" || revision.length > 64)) throw new Error("invalid_module_catalog");
|
|
7939
|
+
const excludedClientModules = value.excludedClientModules.map((id) => {
|
|
7940
|
+
if (typeof id !== "string") throw new Error("invalid_module_catalog");
|
|
7941
|
+
return id;
|
|
7942
|
+
});
|
|
7506
7943
|
return {
|
|
7507
7944
|
entries,
|
|
7508
|
-
|
|
7509
|
-
|
|
7510
|
-
return id;
|
|
7511
|
-
}),
|
|
7945
|
+
...typeof revision === "string" ? { revision } : {},
|
|
7946
|
+
excludedClientModules,
|
|
7512
7947
|
source: value.source === "device" ? "device" : value.source === "computer" ? "computer" : "plugin"
|
|
7513
7948
|
};
|
|
7514
7949
|
}
|
|
@@ -7555,7 +7990,9 @@ window.__ModuleLoader__.load({
|
|
|
7555
7990
|
const value = await response.json();
|
|
7556
7991
|
if (!response.ok) {
|
|
7557
7992
|
const detail = typeof value === "object" && value !== null && "detail" in value && typeof value.detail === "string" ? value.detail.slice(0, 512) : "";
|
|
7558
|
-
|
|
7993
|
+
const code = typeof value === "object" && value !== null && "error" in value && typeof value.error === "string" ? value.error : "";
|
|
7994
|
+
if (response.status === 409 && detail !== "" && code === "client_module_catalog_changed") throw new ClientModuleUiConflict(detail, "catalog_changed");
|
|
7995
|
+
if (response.status === 409 && detail !== "" && code === "excluded_client_modules_invalid") throw new ClientModuleUiConflict(detail);
|
|
7559
7996
|
throw new Error("client_module_request_failed");
|
|
7560
7997
|
}
|
|
7561
7998
|
return parseClientModuleView(value);
|
|
@@ -7715,6 +8152,7 @@ window.__ModuleLoader__.load({
|
|
|
7715
8152
|
let measurementController;
|
|
7716
8153
|
let generation = 0;
|
|
7717
8154
|
let draft;
|
|
8155
|
+
let catalogRevision;
|
|
7718
8156
|
let unconfirmedWrite = false;
|
|
7719
8157
|
const expansion = /* @__PURE__ */ new Map([
|
|
7720
8158
|
["extensions", true],
|
|
@@ -7886,12 +8324,13 @@ window.__ModuleLoader__.load({
|
|
|
7886
8324
|
};
|
|
7887
8325
|
const render = (view) => {
|
|
7888
8326
|
draft = new ClientModuleDraft(view.entries, view.excludedClientModules);
|
|
8327
|
+
catalogRevision = view.revision;
|
|
7889
8328
|
source.textContent = view.source === "device" ? copy.deviceSource : view.source === "computer" ? copy.computerSource : copy.pluginSource;
|
|
7890
8329
|
renderList();
|
|
7891
8330
|
};
|
|
7892
8331
|
const failed = (error, mutation) => {
|
|
7893
8332
|
status.classList.add("dsh-module-error");
|
|
7894
|
-
status.textContent = error instanceof ClientModuleUiConflict ? `${copy.conflict}${error.detail}` : error instanceof ClientModuleRequestTimeout ? error.mutation ? copy.writeTimeout : copy.readTimeout : mutation ? copy.saveFailed : copy.failed;
|
|
8333
|
+
status.textContent = error instanceof ClientModuleUiConflict ? error.code === "catalog_changed" ? copy.catalogChanged : `${copy.conflict}${error.detail}` : error instanceof ClientModuleRequestTimeout ? error.mutation ? copy.writeTimeout : copy.readTimeout : mutation ? copy.saveFailed : copy.failed;
|
|
7895
8334
|
status.focus({ preventScroll: true });
|
|
7896
8335
|
};
|
|
7897
8336
|
const runRequest = (payload) => {
|
|
@@ -7933,13 +8372,24 @@ window.__ModuleLoader__.load({
|
|
|
7933
8372
|
search.addEventListener("input", renderList);
|
|
7934
8373
|
filter.addEventListener("change", renderList);
|
|
7935
8374
|
save.addEventListener("click", () => {
|
|
7936
|
-
if ((draft?.changeCount ?? 0) > 0) runRequest({
|
|
8375
|
+
if ((draft?.changeCount ?? 0) > 0) runRequest({
|
|
8376
|
+
excludedClientModules: draft?.excludedIds,
|
|
8377
|
+
...catalogRevision === void 0 ? {} : { revision: catalogRevision }
|
|
8378
|
+
});
|
|
7937
8379
|
});
|
|
7938
8380
|
reset.addEventListener("click", () => {
|
|
7939
8381
|
if (busy === void 0 && draft !== void 0 && window.confirm(copy.resetConfirm)) runRequest({ reset: true });
|
|
7940
8382
|
});
|
|
7941
8383
|
minimal.addEventListener("click", () => {
|
|
7942
|
-
if (busy !== void 0 || draft === void 0
|
|
8384
|
+
if (busy !== void 0 || draft === void 0) return;
|
|
8385
|
+
const impact = clientModuleMinimalImpact(draft.entries);
|
|
8386
|
+
const detail = copy.minimalDetail.replace("{count}", String(impact.count)).replace("{size}", impact.gzipBytes === void 0 ? "—" : formatClientModuleSize({
|
|
8387
|
+
id: "",
|
|
8388
|
+
required: false,
|
|
8389
|
+
dependencies: [],
|
|
8390
|
+
gzipBytes: impact.gzipBytes
|
|
8391
|
+
}) ?? "—").replace("{unknown}", String(impact.unknown));
|
|
8392
|
+
if (!window.confirm(`${copy.minimalConfirm}\n\n${detail}`)) return;
|
|
7943
8393
|
if (draft.applyMinimalSelection()) {
|
|
7944
8394
|
renderList();
|
|
7945
8395
|
search.focus({ preventScroll: true });
|
|
@@ -8018,8 +8468,7 @@ window.__ModuleLoader__.load({
|
|
|
8018
8468
|
}
|
|
8019
8469
|
}, copy.open));
|
|
8020
8470
|
}
|
|
8021
|
-
|
|
8022
|
-
//#region src/extension-recovery-ui.ts
|
|
8471
|
+
// src/extension-recovery-ui.ts
|
|
8023
8472
|
/** Validate the Host response and select only stopped workers, never in-process hosts. */
|
|
8024
8473
|
function parseUnavailableExtensionHosts(payload) {
|
|
8025
8474
|
if (typeof payload !== "object" || payload === null || !("hosts" in payload) || !Array.isArray(payload.hosts)) return void 0;
|
|
@@ -8221,8 +8670,7 @@ window.__ModuleLoader__.load({
|
|
|
8221
8670
|
.dsh-mobile-control__extension-recovery button:active:not(:disabled){background:var(--dsw-alias-interactive-bg-active,var(--dsw-alias-interactive-bg-hover))}
|
|
8222
8671
|
.dsh-mobile-control__extension-recovery .dsh-mobile-control__extension-recovery-error{color:var(--dsw-alias-label-primary)}
|
|
8223
8672
|
`;
|
|
8224
|
-
|
|
8225
|
-
//#region src/native-capability.ts
|
|
8673
|
+
// src/native-capability.ts
|
|
8226
8674
|
/** Cancel queued calls before native effects start; started effects are not rolled back. */
|
|
8227
8675
|
function invokeBoundNativeCapability(bridge, currentBridge, action, input, signal) {
|
|
8228
8676
|
const abortReason = () => signal.reason ?? new DOMException("mobile extension disposed", "AbortError");
|
|
@@ -8256,8 +8704,7 @@ window.__ModuleLoader__.load({
|
|
|
8256
8704
|
});
|
|
8257
8705
|
});
|
|
8258
8706
|
}
|
|
8259
|
-
|
|
8260
|
-
//#region src/mobile-custom-assets.ts
|
|
8707
|
+
// src/mobile-custom-assets.ts
|
|
8261
8708
|
const COPY = {
|
|
8262
8709
|
en: {
|
|
8263
8710
|
gateway_required: "Custom mobile CSS, scripts and extensions require a paired DSH Mobile access entry. This page is not using the Mobile gateway.",
|
|
@@ -8397,8 +8844,7 @@ window.__ModuleLoader__.load({
|
|
|
8397
8844
|
reader.releaseLock();
|
|
8398
8845
|
}
|
|
8399
8846
|
}
|
|
8400
|
-
|
|
8401
|
-
//#region src/mobile-customization-notice.ts
|
|
8847
|
+
// src/mobile-customization-notice.ts
|
|
8402
8848
|
/** Copy for the notice, per locale, kept beside the existing dictionaries. */
|
|
8403
8849
|
const NOTICE_COPY = {
|
|
8404
8850
|
en: {
|
|
@@ -8516,8 +8962,7 @@ window.__ModuleLoader__.load({
|
|
|
8516
8962
|
style.remove();
|
|
8517
8963
|
};
|
|
8518
8964
|
}
|
|
8519
|
-
|
|
8520
|
-
//#region src/extension-limits.ts
|
|
8965
|
+
// src/extension-limits.ts
|
|
8521
8966
|
/** Maximum sizes accepted for legacy mobile customization resources. */
|
|
8522
8967
|
const LEGACY_CUSTOM_ASSET_LIMIT = 262144;
|
|
8523
8968
|
/** Maximum sizes enforced when reading local extension files. */
|
|
@@ -8530,8 +8975,7 @@ window.__ModuleLoader__.load({
|
|
|
8530
8975
|
assetBytes: 33554432,
|
|
8531
8976
|
assetDepth: 8
|
|
8532
8977
|
});
|
|
8533
|
-
|
|
8534
|
-
//#region src/client-recovery.ts
|
|
8978
|
+
// src/client-recovery.ts
|
|
8535
8979
|
/** Only a visible, disconnected public transport needs an immediate resume nudge. */
|
|
8536
8980
|
function shouldNudgeReconnect(visibility, connection) {
|
|
8537
8981
|
return visibility === "visible" && connection !== "connected";
|
|
@@ -8711,15 +9155,13 @@ window.__ModuleLoader__.load({
|
|
|
8711
9155
|
onRejected?.(rejected, retry);
|
|
8712
9156
|
return dispose;
|
|
8713
9157
|
}
|
|
8714
|
-
|
|
8715
|
-
//#region src/browser-ui-locale.ts
|
|
9158
|
+
// src/browser-ui-locale.ts
|
|
8716
9159
|
const UI_LOCALE_COOKIE = "dsh_ma_ui_locale";
|
|
8717
9160
|
/** Host-only, non-secret preference, independent of the short authentication session. */
|
|
8718
9161
|
function browserUiLocaleCookie(locale, secure) {
|
|
8719
9162
|
return `${UI_LOCALE_COOKIE}=${locale}; Path=/mobile-access; Max-Age=31536000; SameSite=Lax${secure ? "; Secure" : ""}`;
|
|
8720
9163
|
}
|
|
8721
|
-
|
|
8722
|
-
//#region src/mobile-ui-locale.ts
|
|
9164
|
+
// src/mobile-ui-locale.ts
|
|
8723
9165
|
/** Remember the DSH display language only on authenticated Mobile Gateway documents. */
|
|
8724
9166
|
function installMobileUiLocalePersistence(page, view) {
|
|
8725
9167
|
if (page.querySelector("meta[name=\"dsh-mobile-gateway\"][content=\"authenticated\"]") === null) return () => {};
|
|
@@ -8748,8 +9190,7 @@ window.__ModuleLoader__.load({
|
|
|
8748
9190
|
observer.disconnect();
|
|
8749
9191
|
};
|
|
8750
9192
|
}
|
|
8751
|
-
|
|
8752
|
-
//#region src/mobile-push/browser-api.ts
|
|
9193
|
+
// src/mobile-push/browser-api.ts
|
|
8753
9194
|
function apiError(code) {
|
|
8754
9195
|
return Object.assign(/* @__PURE__ */ new Error(code === "stale_generation" ? "Push settings changed elsewhere." : "Push request failed."), { code });
|
|
8755
9196
|
}
|
|
@@ -8815,16 +9256,14 @@ window.__ModuleLoader__.load({
|
|
|
8815
9256
|
}
|
|
8816
9257
|
};
|
|
8817
9258
|
}
|
|
8818
|
-
|
|
8819
|
-
//#region src/mobile-push/installation-id.ts
|
|
9259
|
+
// src/mobile-push/installation-id.ts
|
|
8820
9260
|
/** Browser-safe installation-id validation shared by the browser controller and the Gateway. */
|
|
8821
9261
|
const INSTALLATION_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu;
|
|
8822
9262
|
/** True only for a UUID-shaped installation id with an allowed version and variant nibble. */
|
|
8823
9263
|
function isPushInstallationId(value) {
|
|
8824
9264
|
return typeof value === "string" && INSTALLATION_ID.test(value);
|
|
8825
9265
|
}
|
|
8826
|
-
|
|
8827
|
-
//#region src/mobile-push/client.ts
|
|
9266
|
+
// src/mobile-push/client.ts
|
|
8828
9267
|
const ID_KEY = "dsh-mobile-push-installation";
|
|
8829
9268
|
const defaults = Object.freeze({
|
|
8830
9269
|
question: true,
|
|
@@ -9259,8 +9698,7 @@ window.__ModuleLoader__.load({
|
|
|
9259
9698
|
locale: view.document.documentElement.lang.toLowerCase().startsWith("zh") ? "zh-CN" : view.document.documentElement.lang.toLowerCase().startsWith("it") ? "it" : "en"
|
|
9260
9699
|
};
|
|
9261
9700
|
}
|
|
9262
|
-
|
|
9263
|
-
//#region src/mobile-push/switch-component.ts
|
|
9701
|
+
// src/mobile-push/switch-component.ts
|
|
9264
9702
|
/**
|
|
9265
9703
|
* Lazily require the public Switch from the DSH module loader at category render time.
|
|
9266
9704
|
*
|
|
@@ -9280,8 +9718,7 @@ window.__ModuleLoader__.load({
|
|
|
9280
9718
|
return;
|
|
9281
9719
|
}
|
|
9282
9720
|
}
|
|
9283
|
-
|
|
9284
|
-
//#region src/mobile-push/settings.ts
|
|
9721
|
+
// src/mobile-push/settings.ts
|
|
9285
9722
|
const MOBILE_PUSH_SETTINGS_COPY = {
|
|
9286
9723
|
en: {
|
|
9287
9724
|
title: "Web push notifications",
|
|
@@ -9393,11 +9830,15 @@ window.__ModuleLoader__.load({
|
|
|
9393
9830
|
};
|
|
9394
9831
|
return (0, react.createElement)("div", {
|
|
9395
9832
|
className: "dsh-mobile-settings_row",
|
|
9396
|
-
style: {
|
|
9833
|
+
style: {
|
|
9834
|
+
flexDirection: "column",
|
|
9835
|
+
alignItems: "stretch",
|
|
9836
|
+
gap: 12
|
|
9837
|
+
},
|
|
9397
9838
|
lang: locale === "zh" ? "zh-CN" : locale
|
|
9398
9839
|
}, (0, react.createElement)("div", {
|
|
9399
9840
|
className: "dsh-mobile-settings_rowText",
|
|
9400
|
-
style: { paddingRight:
|
|
9841
|
+
style: { paddingRight: 0 }
|
|
9401
9842
|
}, (0, react.createElement)("div", { className: "dsh-mobile-settings_title" }, copy.title), (0, react.createElement)("div", {
|
|
9402
9843
|
className: "dsh-mobile-settings_desc",
|
|
9403
9844
|
"aria-live": "polite"
|
|
@@ -9441,8 +9882,7 @@ window.__ModuleLoader__.load({
|
|
|
9441
9882
|
disabled: true
|
|
9442
9883
|
}, copy.busy)));
|
|
9443
9884
|
}
|
|
9444
|
-
|
|
9445
|
-
//#region src/mobile-push/navigation.ts
|
|
9885
|
+
// src/mobile-push/navigation.ts
|
|
9446
9886
|
const REF_PARAMETER = "mobile-push";
|
|
9447
9887
|
/**
|
|
9448
9888
|
* Consume one authenticated tap reference after the public Workspace and Session
|
|
@@ -9521,8 +9961,7 @@ window.__ModuleLoader__.load({
|
|
|
9521
9961
|
const snapshot = ctx.sessions.list.getSnapshot();
|
|
9522
9962
|
return snapshot.phase === "ready" && snapshot.ids.includes(sessionId) && snapshot.byId[sessionId] !== void 0;
|
|
9523
9963
|
}
|
|
9524
|
-
|
|
9525
|
-
//#region src/mobile-directory-browser.ts
|
|
9964
|
+
// src/mobile-directory-browser.ts
|
|
9526
9965
|
/** Expected Gateway or response-validation failure for one read-only listing. */
|
|
9527
9966
|
var MobileDirectoryReadError = class extends Error {
|
|
9528
9967
|
code;
|
|
@@ -9916,8 +10355,7 @@ window.__ModuleLoader__.load({
|
|
|
9916
10355
|
for (const listener of this.listeners) listener();
|
|
9917
10356
|
}
|
|
9918
10357
|
};
|
|
9919
|
-
|
|
9920
|
-
//#region src/mobile-directory-picker.ts
|
|
10358
|
+
// src/mobile-directory-picker.ts
|
|
9921
10359
|
/** Dedicated Mobile directory-flow occupant; stock DSH retains its own chooser. */
|
|
9922
10360
|
const MESSAGES = {
|
|
9923
10361
|
zh: {
|
|
@@ -10589,8 +11027,7 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
|
|
|
10589
11027
|
if (failures.length > 0) throw new AggregateError(failures, "Mobile directory picker disposal failed");
|
|
10590
11028
|
};
|
|
10591
11029
|
}
|
|
10592
|
-
|
|
10593
|
-
//#region src/client.ts
|
|
11030
|
+
// src/client.ts
|
|
10594
11031
|
/** Map a host-reported provider onto the UI union, defaulting to the built-in one. */
|
|
10595
11032
|
function parseMobileRemoteProvider(value) {
|
|
10596
11033
|
return value === "cpolar" || value === "cloudflared" || value === "frp" || value === "origin" || value === "iroh" ? value : "tailscale";
|
|
@@ -10670,11 +11107,28 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
|
|
|
10670
11107
|
if (!escape.defaultPrevented) blocked();
|
|
10671
11108
|
return;
|
|
10672
11109
|
}
|
|
11110
|
+
if (top.getAttribute("data-shortcut-modal") === "sidebar" && top.closest("[data-sidebar-drawer]") !== null) {
|
|
11111
|
+
if (layers.some((layer) => layer !== top && !top.contains(layer))) {
|
|
11112
|
+
blocked();
|
|
11113
|
+
return;
|
|
11114
|
+
}
|
|
11115
|
+
const focused = page.activeElement;
|
|
11116
|
+
const target = focused !== null && top.contains(focused) ? focused : top;
|
|
11117
|
+
const escape = new KeyboardEvent("keydown", {
|
|
11118
|
+
key: "Escape",
|
|
11119
|
+
code: "Escape",
|
|
11120
|
+
bubbles: true,
|
|
11121
|
+
cancelable: true
|
|
11122
|
+
});
|
|
11123
|
+
target.dispatchEvent(escape);
|
|
11124
|
+
if (!escape.defaultPrevented) blocked();
|
|
11125
|
+
return;
|
|
11126
|
+
}
|
|
10673
11127
|
if (top.getAttribute("role") === "dialog") {
|
|
10674
11128
|
const wrapper = top.parentElement;
|
|
10675
11129
|
const mask = wrapper?.firstElementChild;
|
|
10676
11130
|
const maskStyle = mask === void 0 || mask === null ? void 0 : view.getComputedStyle(mask);
|
|
10677
|
-
if (wrapper?.getAttribute("role") === "presentation" && wrapper.children.length === 2 && wrapper.lastElementChild === top && mask?.tagName === "DIV" && mask.getAttribute("aria-hidden") === "
|
|
11131
|
+
if (wrapper?.getAttribute("role") === "presentation" && wrapper.children.length === 2 && wrapper.lastElementChild === top && mask?.tagName === "DIV" && mask.getAttribute("aria-hidden") !== "false" && mask.getAttribute("role") === null && mask.getAttribute("tabindex") === null && mask.getAttribute("contenteditable") === null && mask.children.length === 0 && (mask.textContent ?? "").trim() === "" && mask.isConnected && !mask.hidden && maskStyle?.display !== "none" && maskStyle?.visibility !== "hidden" && mask.getClientRects().length > 0) {
|
|
10678
11132
|
mask.click();
|
|
10679
11133
|
return;
|
|
10680
11134
|
}
|
|
@@ -11028,7 +11482,8 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
|
|
|
11028
11482
|
mode: "attach",
|
|
11029
11483
|
entryTls: form.entryTls,
|
|
11030
11484
|
...form.entryTls === "self-signed" || form.vhostHttpPort === void 0 ? {} : { vhostHttpPort: form.vhostHttpPort },
|
|
11031
|
-
...form.publicPort === void 0 ? {} : { publicPort: form.publicPort }
|
|
11485
|
+
...form.publicPort === void 0 ? {} : { publicPort: form.publicPort },
|
|
11486
|
+
...form.user === void 0 || form.user === "" ? {} : { user: form.user }
|
|
11032
11487
|
});
|
|
11033
11488
|
}
|
|
11034
11489
|
/**
|
|
@@ -11282,7 +11737,8 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
|
|
|
11282
11737
|
const facts = entry.facts !== null && typeof entry.facts === "object" ? entry.facts : {};
|
|
11283
11738
|
const copyReason = facts.viaProxy === true && (reason === "remote-ready" || reason === "remote-rate-limited") ? `${reason}-via-proxy` : reason;
|
|
11284
11739
|
const catalog = DIAGNOSTIC_REASON_MESSAGES[locale];
|
|
11285
|
-
const
|
|
11740
|
+
const networkCatalog = DIAGNOSTIC_NETWORK_MESSAGES[locale];
|
|
11741
|
+
const templates = Object.prototype.hasOwnProperty.call(networkCatalog, copyReason) ? networkCatalog[copyReason] : Object.prototype.hasOwnProperty.call(catalog, copyReason) ? catalog[copyReason] : void 0;
|
|
11286
11742
|
if (templates === void 0) return serverCopy;
|
|
11287
11743
|
const providerNames = {
|
|
11288
11744
|
tailscale: "Tailscale Funnel",
|
|
@@ -11305,6 +11761,15 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
|
|
|
11305
11761
|
const interpolate = (template) => template.replace(/\{(\w+)\}/gu, (_match, key) => values[key] ?? "");
|
|
11306
11762
|
let detail = reason === "remote-controller-error" && controllerCode === "" ? t("remoteError") : interpolate(templates[0]);
|
|
11307
11763
|
let action = interpolate(templates[1]);
|
|
11764
|
+
if (reason.startsWith("dns-")) {
|
|
11765
|
+
const families = {
|
|
11766
|
+
ipv4: "IPv4",
|
|
11767
|
+
ipv6: "IPv6",
|
|
11768
|
+
dual: "IPv4 + IPv6"
|
|
11769
|
+
};
|
|
11770
|
+
const family = typeof facts.dnsFamily === "string" && Object.hasOwn(families, facts.dnsFamily) ? families[facts.dnsFamily] : void 0;
|
|
11771
|
+
if (family !== void 0) detail += ` (${family})`;
|
|
11772
|
+
}
|
|
11308
11773
|
if (reason === "versions-current") {
|
|
11309
11774
|
const fields = versions !== null && typeof versions === "object" ? versions : {};
|
|
11310
11775
|
if ([
|
|
@@ -11942,6 +12407,16 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
|
|
|
11942
12407
|
frpToken.autocomplete = "off";
|
|
11943
12408
|
frpToken.spellcheck = false;
|
|
11944
12409
|
frpToken.placeholder = t("frpTokenPlaceholder");
|
|
12410
|
+
const frpUserLabel = element("label", "dsh-mobile-control__field");
|
|
12411
|
+
frpUserLabel.textContent = t("frpUser");
|
|
12412
|
+
const frpUser = element("input");
|
|
12413
|
+
frpUser.type = "text";
|
|
12414
|
+
frpUser.autocomplete = "off";
|
|
12415
|
+
frpUser.spellcheck = false;
|
|
12416
|
+
frpUser.placeholder = t("frpUserPlaceholder");
|
|
12417
|
+
const frpUserHint = element("p", "dsh-mobile-control__frp-hint");
|
|
12418
|
+
frpUserHint.textContent = t("frpUserHint");
|
|
12419
|
+
frpUserLabel.append(frpUser, frpUserHint);
|
|
11945
12420
|
const frpOriginLabel = element("label", "dsh-mobile-control__field");
|
|
11946
12421
|
frpOriginLabel.textContent = t("frpPublicOrigin");
|
|
11947
12422
|
const frpOrigin = element("input");
|
|
@@ -12004,6 +12479,7 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
|
|
|
12004
12479
|
serverAddress: frpServer,
|
|
12005
12480
|
serverPort: frpPort,
|
|
12006
12481
|
token: frpToken,
|
|
12482
|
+
user: frpUser,
|
|
12007
12483
|
publicOrigin: frpOrigin,
|
|
12008
12484
|
mode: frpMode,
|
|
12009
12485
|
entryTls: frpEntryTls,
|
|
@@ -12014,6 +12490,7 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
|
|
|
12014
12490
|
serverAddress: frpServerLabel,
|
|
12015
12491
|
serverPort: frpPortLabel,
|
|
12016
12492
|
token: frpTokenLabel,
|
|
12493
|
+
user: frpUserLabel,
|
|
12017
12494
|
publicOrigin: frpOriginLabel,
|
|
12018
12495
|
mode: frpModeLabel,
|
|
12019
12496
|
entryTls: frpEntryTlsLabel,
|
|
@@ -12024,6 +12501,7 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
|
|
|
12024
12501
|
serverAddress: "frpServerAddress",
|
|
12025
12502
|
serverPort: "frpServerPort",
|
|
12026
12503
|
token: "frpToken",
|
|
12504
|
+
user: "frpUser",
|
|
12027
12505
|
publicOrigin: "frpPublicOrigin",
|
|
12028
12506
|
mode: "frpMode",
|
|
12029
12507
|
entryTls: "frpEntryTls",
|
|
@@ -12046,7 +12524,7 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
|
|
|
12046
12524
|
frpOriginHint.textContent = t("frpPublicOriginHint");
|
|
12047
12525
|
frpOriginLabel.append(frpOriginHint);
|
|
12048
12526
|
frpOrigin.setAttribute("aria-describedby", `${frpOriginHint.id} ${frpOrigin.getAttribute("aria-describedby") ?? ""}`);
|
|
12049
|
-
frpFields.append(frpServerLabel, frpPortLabel, frpTokenLabel, frpOriginLabel, frpModeLabel, frpEntryTlsLabel, frpVhostLabel, frpPublicPortLabel);
|
|
12527
|
+
frpFields.append(frpServerLabel, frpPortLabel, frpTokenLabel, frpUserLabel, frpOriginLabel, frpModeLabel, frpEntryTlsLabel, frpVhostLabel, frpPublicPortLabel);
|
|
12050
12528
|
frpStep1.append(frpStep1Title, frpStep1Text, frpFields);
|
|
12051
12529
|
const frpStep2 = element("section", "dsh-mobile-control__frp-step");
|
|
12052
12530
|
const frpStep2Title = element("strong");
|
|
@@ -12406,6 +12884,7 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
|
|
|
12406
12884
|
const irohQr = element("div", "dsh-mobile-control__qr is-expandable");
|
|
12407
12885
|
irohQr.hidden = true;
|
|
12408
12886
|
const irohPairStatus = element("p", "dsh-mobile-control__component-status");
|
|
12887
|
+
irohPairStatus.setAttribute("aria-live", "polite");
|
|
12409
12888
|
const irohCopyDescriptor = element("button", "dsh-mobile-control__secondary");
|
|
12410
12889
|
irohCopyDescriptor.type = "button";
|
|
12411
12890
|
irohCopyDescriptor.textContent = t("copyPairLink");
|
|
@@ -12735,6 +13214,16 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
|
|
|
12735
13214
|
disclosure.hidden = true;
|
|
12736
13215
|
setupDetailsRow.append(disclosure);
|
|
12737
13216
|
}
|
|
13217
|
+
const macosFolderHelp = element("details", "dsh-mobile-control__details");
|
|
13218
|
+
macosFolderHelp.hidden = true;
|
|
13219
|
+
const macosFolderHelpSummary = element("summary");
|
|
13220
|
+
macosFolderHelpSummary.textContent = t("macosFolderHelpTitle");
|
|
13221
|
+
const macosFolderHelpBody = element("div", "dsh-mobile-control__details-body");
|
|
13222
|
+
const macosFolderHelpNote = element("p");
|
|
13223
|
+
macosFolderHelpNote.textContent = t("macosFolderHelpNote");
|
|
13224
|
+
macosFolderHelpBody.append(macosFolderHelpNote);
|
|
13225
|
+
macosFolderHelp.append(macosFolderHelpSummary, macosFolderHelpBody);
|
|
13226
|
+
setupDetailsRow.append(macosFolderHelp);
|
|
12738
13227
|
remoteWorkspace.append(remoteStatus, remoteAccess, remoteGuide, providerSetupBody, remoteQr, pairingValidity, providerInstallRow, remoteActions, remotePairLink, setupDetailsRow);
|
|
12739
13228
|
const diagnosticsView = element("div", "dsh-mobile-control__view is-diagnostics");
|
|
12740
13229
|
diagnosticsView.hidden = true;
|
|
@@ -12884,6 +13373,8 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
|
|
|
12884
13373
|
let configuredFrpOrigin = "";
|
|
12885
13374
|
let configuredFrpVhostPort = 7080;
|
|
12886
13375
|
let configuredFrpPublicPort = 33080;
|
|
13376
|
+
let configuredFrpUser = "";
|
|
13377
|
+
let frpUserDraft = false;
|
|
12887
13378
|
/** Proxy name the host writes into its frpc.toml; the local clipboard copy must match. */
|
|
12888
13379
|
let configuredFrpProxyName;
|
|
12889
13380
|
let frpConfiguredMode = "deploy";
|
|
@@ -13261,6 +13752,17 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
|
|
|
13261
13752
|
irohQr.hidden = false;
|
|
13262
13753
|
irohQr.append(placeholder);
|
|
13263
13754
|
};
|
|
13755
|
+
const clearIrohPairing = () => {
|
|
13756
|
+
activeIrohDescriptor = "";
|
|
13757
|
+
activeIrohPairExpiresAt = 0;
|
|
13758
|
+
activeIrohQrSvg = "";
|
|
13759
|
+
clearQrTarget(irohQr);
|
|
13760
|
+
irohQr.hidden = true;
|
|
13761
|
+
const wasZoomed = !irohQrZoom.hidden;
|
|
13762
|
+
setIrohQrZoomOpen(false);
|
|
13763
|
+
irohQrZoomImage.removeAttribute("src");
|
|
13764
|
+
if (wasZoomed && !irohPair.disabled && !irohPair.hidden) irohPair.focus();
|
|
13765
|
+
};
|
|
13264
13766
|
const showRemoteQrPlaceholder = (text) => {
|
|
13265
13767
|
clearQrTarget(remoteQr);
|
|
13266
13768
|
const placeholder = element("span", "dsh-mobile-control__qr-placeholder");
|
|
@@ -13532,6 +14034,9 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
|
|
|
13532
14034
|
if (frpConfigured && !frpEntryTlsDraft) frpEntryTls.value = configuredFrpEntryTls;
|
|
13533
14035
|
if (typeof frpConfiguration.vhostHttpPort === "number") configuredFrpVhostPort = frpConfiguration.vhostHttpPort;
|
|
13534
14036
|
if (typeof frpConfiguration.publicPort === "number") configuredFrpPublicPort = frpConfiguration.publicPort;
|
|
14037
|
+
configuredFrpUser = typeof frpConfiguration.user === "string" ? frpConfiguration.user : "";
|
|
14038
|
+
if (!frpUserDraft) frpUser.value = configuredFrpUser;
|
|
14039
|
+
else if (frpUser.value.trim() === configuredFrpUser) frpUserDraft = false;
|
|
13535
14040
|
configuredFrpProxyName = typeof frpConfiguration.proxyName === "string" && frpConfiguration.proxyName !== "" ? frpConfiguration.proxyName : void 0;
|
|
13536
14041
|
if (!frpVhostDraft) {
|
|
13537
14042
|
if (frpMode.value === "attach" && configuredFrpMode === "attach" && configuredFrpEntryTls === "public-ip-cert") {
|
|
@@ -13543,6 +14048,7 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
|
|
|
13543
14048
|
const attachSelected = frpMode.value === "attach";
|
|
13544
14049
|
const selfSignedSelected = attachSelected && frpEntryTls.value === "self-signed";
|
|
13545
14050
|
frpStep2Title.textContent = t(attachSelected ? "frpStep2TitleAttach" : "frpStep2Title");
|
|
14051
|
+
frpVpsSummary.textContent = t(attachSelected ? "frpStep2TitleAttach" : "frpStep2Title");
|
|
13546
14052
|
frpStep2Text.textContent = attachSelected && configuredFrpProxyName === void 0 ? t("loadingRemoteStatus") : t(attachSelected ? "frpStep2TextAttach" : "frpStep2Text");
|
|
13547
14053
|
frpStep4Text.textContent = t(attachSelected ? "frpStep4TextAttach" : "frpStep4Text");
|
|
13548
14054
|
frpAppRequirement.textContent = t(selfSignedSelected ? "frpAppRequirementSelfSigned" : "frpAppRequirement");
|
|
@@ -13695,6 +14201,7 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
|
|
|
13695
14201
|
}[errorCode] ?? "";
|
|
13696
14202
|
const needsFunnelSetup = state === "error" && remoteSetupUrl !== "";
|
|
13697
14203
|
remoteReady = remoteRunning && state === "ready" && remoteOrigin !== "";
|
|
14204
|
+
macosFolderHelp.hidden = data.macosHost !== true || !remoteReady;
|
|
13698
14205
|
frpChoiceBadge.textContent = frpConfigured && frpInstalled ? t("ready") : t("advanced");
|
|
13699
14206
|
originChoiceBadge.textContent = managedOrigin ? t(remoteReady ? "ready" : "advanced") : originListening ? t("originBackendReady") : t("advanced");
|
|
13700
14207
|
if (remoteStatus.style) remoteStatus.style.display = state === "off" && remoteFailureText === "" ? "none" : "";
|
|
@@ -13709,7 +14216,7 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
|
|
|
13709
14216
|
starting: cpolar ? t("remoteStartingCpolar") : cloudflared ? t("remoteStartingCloudflared") : frp ? t("remoteStartingFrp") : origin ? t("originStarting") : iroh ? t("irohStarting") : t("remoteStartingTailscale"),
|
|
13710
14217
|
"needs-login": t("remoteNeedsLogin"),
|
|
13711
14218
|
connecting: cpolar ? t("remoteConnectingCpolar") : cloudflared ? t("remoteConnectingCloudflared") : frp ? t("remoteConnectingFrp") : iroh ? t("irohConnecting") : t("remoteConnectingTailscale"),
|
|
13712
|
-
ready: origin ? t(managedOrigin ? "caddyVerified" : "originReady") : t("remoteReady"),
|
|
14219
|
+
ready: origin ? t(managedOrigin ? "caddyVerified" : "originReady") : tailscale ? t("funnelListenerReady") : t("remoteReady"),
|
|
13713
14220
|
error: t("remoteError")
|
|
13714
14221
|
};
|
|
13715
14222
|
const errorLabels = translatedRemoteErrors();
|
|
@@ -13747,15 +14254,15 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
|
|
|
13747
14254
|
irohPair.disabled = !remoteReady || !iroh || remoteProviderBusy;
|
|
13748
14255
|
irohPair.hidden = !iroh;
|
|
13749
14256
|
irohCopyDescriptor.hidden = !iroh;
|
|
13750
|
-
|
|
13751
|
-
|
|
13752
|
-
|
|
13753
|
-
|
|
13754
|
-
|
|
13755
|
-
|
|
13756
|
-
|
|
13757
|
-
|
|
13758
|
-
|
|
14257
|
+
const irohPairingExpired = activeIrohPairExpiresAt > 0 && activeIrohPairExpiresAt <= Date.now();
|
|
14258
|
+
if (activeIrohDescriptor !== "" && (!iroh || !irohInstalled || !remoteReady || irohPairingExpired)) {
|
|
14259
|
+
clearIrohPairing();
|
|
14260
|
+
irohPairStatus.textContent = iroh && irohInstalled && remoteReady && irohPairingExpired ? t("pairingExpired") : "";
|
|
14261
|
+
}
|
|
14262
|
+
if (!iroh || !irohInstalled) irohQr.hidden = true;
|
|
14263
|
+
else if (activeIrohQrSvg === "") {
|
|
14264
|
+
if (activeIrohDescriptor === "") showIrohQrPlaceholder();
|
|
14265
|
+
else irohQr.hidden = true;
|
|
13759
14266
|
}
|
|
13760
14267
|
irohCopyDescriptor.disabled = !iroh || !remoteReady || remoteProviderBusy || activeIrohDescriptor === "" || activeIrohPairExpiresAt <= Date.now();
|
|
13761
14268
|
if (origin) {
|
|
@@ -13944,8 +14451,7 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
|
|
|
13944
14451
|
});
|
|
13945
14452
|
const openIrohPairing = async () => {
|
|
13946
14453
|
const generation = remotePairingGeneration;
|
|
13947
|
-
|
|
13948
|
-
activeIrohPairExpiresAt = 0;
|
|
14454
|
+
clearIrohPairing();
|
|
13949
14455
|
irohCopyDescriptor.disabled = true;
|
|
13950
14456
|
const data = await controlRequestJson("/api/mobile-access/remote/iroh/pairing/begin", {
|
|
13951
14457
|
method: "POST",
|
|
@@ -13956,12 +14462,12 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
|
|
|
13956
14462
|
const qrSvg = typeof record.qrSvg === "string" ? record.qrSvg : "";
|
|
13957
14463
|
const code = typeof record.irohCode === "string" ? record.irohCode : "";
|
|
13958
14464
|
const expiresAt = typeof record.expiresAt === "number" && Number.isFinite(record.expiresAt) ? record.expiresAt : 0;
|
|
13959
|
-
|
|
13960
|
-
if (qrSvg === "" || code === "" || expiresAt <= Date.now()) {
|
|
13961
|
-
activeIrohQrSvg = "";
|
|
14465
|
+
if (!/^\d{6}$/u.test(code) || expiresAt <= Date.now()) {
|
|
13962
14466
|
irohPairStatus.textContent = t("keyGenerationFailed");
|
|
13963
14467
|
return;
|
|
13964
14468
|
}
|
|
14469
|
+
if (qrSvg === "") irohQr.hidden = true;
|
|
14470
|
+
else showQr(qrSvg, irohQr);
|
|
13965
14471
|
activeIrohQrSvg = qrSvg;
|
|
13966
14472
|
const fields = [
|
|
13967
14473
|
"version",
|
|
@@ -13979,7 +14485,7 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
|
|
|
13979
14485
|
for (const field of fields) descriptor[field] = record[field];
|
|
13980
14486
|
activeIrohDescriptor = JSON.stringify(descriptor);
|
|
13981
14487
|
activeIrohPairExpiresAt = expiresAt;
|
|
13982
|
-
irohPairStatus.textContent = t("irohPairingReady", { code });
|
|
14488
|
+
irohPairStatus.textContent = qrSvg === "" ? t("irohPairingCopyOnly") : t("irohPairingReady", { code });
|
|
13983
14489
|
};
|
|
13984
14490
|
irohPair.addEventListener("click", () => {
|
|
13985
14491
|
if (remoteProviderBusy || !remoteReady || remoteProvider !== "iroh") return;
|
|
@@ -14297,6 +14803,7 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
|
|
|
14297
14803
|
serverAddress: String(frpServer.value ?? "").trim(),
|
|
14298
14804
|
serverPort: Number(frpPort.value),
|
|
14299
14805
|
token: String(frpToken.value ?? ""),
|
|
14806
|
+
user: String(frpUser.value ?? "").trim(),
|
|
14300
14807
|
publicOrigin: String(frpOrigin.value ?? "").trim(),
|
|
14301
14808
|
mode,
|
|
14302
14809
|
entryTls: frpEntryTls.value === "self-signed" ? "self-signed" : "public-ip-cert",
|
|
@@ -14315,7 +14822,8 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
|
|
|
14315
14822
|
publicOrigin: form.publicOrigin,
|
|
14316
14823
|
entryTls: form.entryTls,
|
|
14317
14824
|
...form.entryTls === "self-signed" || form.vhostHttpPort === void 0 ? {} : { vhostHttpPort: form.vhostHttpPort },
|
|
14318
|
-
...form.publicPort === void 0 ? {} : { publicPort: form.publicPort }
|
|
14825
|
+
...form.publicPort === void 0 ? {} : { publicPort: form.publicPort },
|
|
14826
|
+
...form.user === "" ? {} : { user: form.user }
|
|
14319
14827
|
});
|
|
14320
14828
|
const validFrpForm = (form) => {
|
|
14321
14829
|
return validateFrpForm(form).length === 0;
|
|
@@ -14346,6 +14854,7 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
|
|
|
14346
14854
|
return issues.length === 0;
|
|
14347
14855
|
};
|
|
14348
14856
|
for (const [name, input] of Object.entries(frpInputs)) input.addEventListener(name === "mode" || name === "entryTls" ? "change" : "input", () => {
|
|
14857
|
+
if (name === "user") frpUserDraft = true;
|
|
14349
14858
|
if (frpValidationShown) renderFrpIssues(validateFrpForm(frpForm(), frpValidationAllowsSavedToken));
|
|
14350
14859
|
});
|
|
14351
14860
|
frpCopyTemplate.addEventListener("click", () => {
|
|
@@ -14528,7 +15037,8 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
|
|
|
14528
15037
|
mode: form.mode,
|
|
14529
15038
|
entryTls: form.entryTls,
|
|
14530
15039
|
...form.vhostHttpPort === void 0 ? {} : { vhostHttpPort: form.vhostHttpPort },
|
|
14531
|
-
...form.publicPort === void 0 ? {} : { publicPort: form.publicPort }
|
|
15040
|
+
...form.publicPort === void 0 ? {} : { publicPort: form.publicPort },
|
|
15041
|
+
user: form.user
|
|
14532
15042
|
};
|
|
14533
15043
|
};
|
|
14534
15044
|
const validVpsFrpForm = () => {
|
|
@@ -14768,9 +15278,10 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
|
|
|
14768
15278
|
frpConfigure.addEventListener("click", () => {
|
|
14769
15279
|
if (remoteProviderBusy || !frpInstalled) return;
|
|
14770
15280
|
const form = frpForm();
|
|
14771
|
-
const unchanged = frpConfigured && form.token === "" && form.serverAddress === configuredFrpServer && form.serverPort === configuredFrpPort && form.publicOrigin === configuredFrpOrigin && form.mode === (frpConfiguredMode === "attach" ? "attach" : "deploy") && form.entryTls === (frpConfiguredEntryTls === "self-signed" ? "self-signed" : "public-ip-cert") && (form.vhostHttpPort ?? configuredFrpVhostPort) === configuredFrpVhostPort && (form.publicPort ?? configuredFrpPublicPort) === configuredFrpPublicPort;
|
|
15281
|
+
const unchanged = frpConfigured && form.token === "" && form.serverAddress === configuredFrpServer && form.serverPort === configuredFrpPort && form.publicOrigin === configuredFrpOrigin && form.mode === (frpConfiguredMode === "attach" ? "attach" : "deploy") && form.entryTls === (frpConfiguredEntryTls === "self-signed" ? "self-signed" : "public-ip-cert") && (form.vhostHttpPort ?? configuredFrpVhostPort) === configuredFrpVhostPort && (form.publicPort ?? configuredFrpPublicPort) === configuredFrpPublicPort && form.user === configuredFrpUser;
|
|
14772
15282
|
if (!unchanged) {
|
|
14773
|
-
|
|
15283
|
+
const sameServer = frpConfigured && form.serverAddress === configuredFrpServer && form.serverPort === configuredFrpPort;
|
|
15284
|
+
if (!checkFrpForm(form, sameServer)) return;
|
|
14774
15285
|
}
|
|
14775
15286
|
renderFrpIssues([]);
|
|
14776
15287
|
remoteProviderBusy = true;
|
|
@@ -15250,11 +15761,13 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
|
|
|
15250
15761
|
});
|
|
15251
15762
|
});
|
|
15252
15763
|
const renderDiagnostics = (data) => {
|
|
15764
|
+
const scopeCopy = DIAGNOSTIC_SCOPE_MESSAGES[locale];
|
|
15765
|
+
const scopeOf = (entry) => entry.scope === "configuration" || entry.id === "versions" ? scopeCopy.configuration : entry.scope === "phone" || entry.id === "phone-network" ? scopeCopy.phone : scopeCopy.computer;
|
|
15253
15766
|
const entries = [...diagnosticEntriesForRender(data)];
|
|
15254
15767
|
const overall = diagnosticOverallForChecks(data.overall, entries.map((entry) => entry.status));
|
|
15255
15768
|
diagnosticsSummary.className = `dsh-mobile-control__diagnostic-summary is-${overall}`;
|
|
15256
|
-
diagnosticsSummaryTitle.textContent = overall === "ok" ? t("diagnosticsComplete") : overall === "attention" ? t("diagnosticsAttention") : t("diagnosticsProblem")
|
|
15257
|
-
diagnosticsSummaryText.textContent =
|
|
15769
|
+
diagnosticsSummaryTitle.textContent = `${scopeCopy.computer} · ${overall === "ok" ? t("diagnosticsComplete") : overall === "attention" ? t("diagnosticsAttention") : t("diagnosticsProblem")}`;
|
|
15770
|
+
diagnosticsSummaryText.textContent = scopeCopy.coverage;
|
|
15258
15771
|
diagnosticsChecks.replaceChildren();
|
|
15259
15772
|
const statusLabels = {
|
|
15260
15773
|
ok: t("diagnosticStatusOk"),
|
|
@@ -15299,8 +15812,14 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
|
|
|
15299
15812
|
const localizedCopy = localizedEntryCopy(entry);
|
|
15300
15813
|
const detail = element("p");
|
|
15301
15814
|
detail.textContent = localizedCopy.detail;
|
|
15815
|
+
if (entry.id === "versions") rowTitle.textContent = scopeCopy.versions;
|
|
15816
|
+
else if (entry.id === "remote-service") rowTitle.textContent = scopeCopy.provider;
|
|
15817
|
+
else if (entry.id === "remote-dns") rowTitle.textContent = scopeCopy.dns;
|
|
15818
|
+
else if (entry.id === "plugin-inspection" || entry.id === "remote-plugin-conflict") rowTitle.textContent = scopeCopy.scripts;
|
|
15819
|
+
const scope = element("small", "dsh-mobile-control__diagnostic-scope");
|
|
15820
|
+
scope.textContent = scopeOf(entry);
|
|
15302
15821
|
rowHeader.append(rowTitle, badge);
|
|
15303
|
-
rowBody.append(rowHeader, detail);
|
|
15822
|
+
rowBody.append(rowHeader, scope, detail);
|
|
15304
15823
|
if (localizedCopy.action !== "") {
|
|
15305
15824
|
const action = element("p", "dsh-mobile-control__diagnostic-action");
|
|
15306
15825
|
const actionLabel = element("span");
|
|
@@ -15330,11 +15849,13 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
|
|
|
15330
15849
|
const labelKey = typeof entry.id === "string" ? diagnosticLabelKeys[entry.id] : void 0;
|
|
15331
15850
|
const label = labelKey === void 0 && typeof entry.label === "string" ? entry.label : labelKey === void 0 ? t("diagnosticCheck") : t(labelKey);
|
|
15332
15851
|
const localizedCopy = localizedEntryCopy(entry);
|
|
15333
|
-
|
|
15852
|
+
const scopedLabel = entry.id === "versions" ? scopeCopy.versions : entry.id === "remote-service" ? scopeCopy.provider : entry.id === "remote-dns" ? scopeCopy.dns : entry.id === "plugin-inspection" || entry.id === "remote-plugin-conflict" ? scopeCopy.scripts : label;
|
|
15853
|
+
return `[${statusLabels[state]}][${scopeOf(entry)}] ${scopedLabel}: ${localizedCopy.detail}${localizedCopy.action === "" ? "" : ` ${localizedCopy.action}`}`;
|
|
15334
15854
|
});
|
|
15335
15855
|
copiedDiagnosticReport = [
|
|
15336
15856
|
reportCopy.reportTitle,
|
|
15337
15857
|
`${reportCopy.generated}: ${generatedAt}`,
|
|
15858
|
+
scopeCopy.coverage,
|
|
15338
15859
|
...lines
|
|
15339
15860
|
].join("\n");
|
|
15340
15861
|
diagnosticsReport.textContent = copiedDiagnosticReport;
|
|
@@ -16444,6 +16965,7 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
|
|
|
16444
16965
|
manifestEtag = "";
|
|
16445
16966
|
};
|
|
16446
16967
|
const refreshExtensions = async (signal) => {
|
|
16968
|
+
let failureStage = "manifest_unavailable";
|
|
16447
16969
|
try {
|
|
16448
16970
|
const headers = {};
|
|
16449
16971
|
if (manifestEtag !== "") headers["if-none-match"] = manifestEtag;
|
|
@@ -16486,6 +17008,7 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
|
|
|
16486
17008
|
failed("manifest_invalid", signal);
|
|
16487
17009
|
return false;
|
|
16488
17010
|
}
|
|
17011
|
+
failureStage = "resource_unavailable";
|
|
16489
17012
|
events?.setEnabled(true);
|
|
16490
17013
|
const entries = payload.extensions;
|
|
16491
17014
|
const seen = new Set(entries.map((entry) => entry.id));
|
|
@@ -16645,7 +17168,7 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
|
|
|
16645
17168
|
} else manifestEtag = "";
|
|
16646
17169
|
return refreshComplete;
|
|
16647
17170
|
} catch {
|
|
16648
|
-
failed(
|
|
17171
|
+
failed(failureStage, signal);
|
|
16649
17172
|
return false;
|
|
16650
17173
|
}
|
|
16651
17174
|
};
|
|
@@ -16777,7 +17300,7 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
|
|
|
16777
17300
|
style rule of its own. */
|
|
16778
17301
|
.dsh-mobile-control__cpolar-setup{margin:0 0 12px;padding:12px;border:1px solid var(--dsw-alias-border-l2,#dbe1e8);border-radius:13px;background:var(--dsw-alias-bg-layer-2,#fff)}.dsh-mobile-control__cpolar-setup[hidden],.dsh-mobile-control__cpolar-account[hidden],.dsh-mobile-control__details[hidden],.dsh-mobile-control__view.is-remote .dsh-mobile-control__actions[hidden],.dsh-mobile-control__danger[hidden]{display:none}.dsh-mobile-control__component-status,.dsh-mobile-control__component-note{margin:0 0 10px;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:1.55}.dsh-mobile-control__progress{box-sizing:border-box;width:100%;height:6px;margin:0 0 10px}.dsh-mobile-control__progress[hidden]{display:none}.dsh-mobile-control__cpolar-setup>.dsh-mobile-control__primary{width:100%;min-height:44px;padding:9px 12px;border-radius:10px;font:600 12px/1.3 system-ui;cursor:pointer}.dsh-mobile-control__cpolar-account{margin-top:10px}.dsh-mobile-control__link-row{display:flex;flex-wrap:wrap;gap:6px 12px;margin:0 0 10px}.dsh-mobile-control__text-link{color:var(--dsw-alias-label-primary-bluish,#2563eb);font-size:11px;text-decoration:none}.dsh-mobile-control__text-link:hover{text-decoration:underline}.dsh-mobile-control__token-label{display:flex;flex-direction:column;gap:5px;margin:0 0 8px;color:var(--dsw-alias-label-secondary,#606873);font-size:11px}.dsh-mobile-control__token{box-sizing:border-box;width:100%;min-height:44px;padding:9px 10px;border:1px solid var(--dsw-alias-border-l3,#cfd5dd);border-radius:10px;background:var(--dsw-alias-bg-layer-3,var(--dsw-alias-bg-layer-2,#fff));color:var(--dsw-alias-label-primary,#16181d);font:16px/1.4 system-ui}.dsh-mobile-control__cpolar-connect{display:flex;align-items:center;justify-content:center;box-sizing:border-box;width:100%;min-height:44px;padding:10px 14px;border-radius:12px;font:650 13px/1.2 system-ui;cursor:pointer;transition:background-color 160ms ease,border-color 160ms ease,opacity 160ms ease}.dsh-mobile-control__cpolar-connect:hover:not(:disabled){border-color:#1d4ed8;background:#1d4ed8}.dsh-mobile-control__cpolar-connect:active:not(:disabled){border-color:#1e40af;background:#1e40af}.dsh-mobile-control__cpolar-connect:disabled{cursor:wait;opacity:.55}.dsh-mobile-control__details{margin:10px 0 0;border-top:1px solid var(--dsw-alias-border-l2,#e1e5eb);padding-top:9px}.dsh-mobile-control__details>summary{min-height:36px;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:30px;cursor:pointer}.dsh-mobile-control__details-body{display:flex;flex-wrap:wrap;align-items:center;gap:7px 12px;padding:4px 0}.dsh-mobile-control__details-body p{flex:1 0 100%;margin:0;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:1.5}.dsh-mobile-control__storage{display:block;flex:1 0 100%;max-width:100%;overflow:hidden;padding:7px 8px;border-radius:8px;background:var(--dsw-alias-bg-layer-1,#f3f5f8);color:var(--dsw-alias-label-secondary,#475569);font:11px/1.4 ui-monospace,SFMono-Regular,Consolas,monospace;text-overflow:ellipsis;white-space:nowrap}.dsh-mobile-control__danger{flex:1 0 100%;min-height:44px;margin-top:3px;padding:7px 10px;border:1px solid var(--dsw-alias-state-error-primary,#dc2626);border-radius:9px;background:transparent;color:var(--dsw-alias-label-primary,#dc2626);font:12px/1.3 system-ui;cursor:pointer}
|
|
16779
17302
|
.dsh-mobile-control__danger:hover:not(:disabled),.dsh-mobile-control__device-revoke:hover{background:var(--dsw-alias-interactive-bg-hover-danger,rgb(220 38 38 / 8%))}
|
|
16780
|
-
.dsh-mobile-control__frp-setup{margin:0;padding:12px;border:1px solid var(--dsw-alias-border-l2,#dbe1e8);border-radius:13px;background:var(--dsw-alias-bg-layer-2,#fff)}.dsh-mobile-control__frp-setup[hidden]{display:none}.dsh-mobile-control__frp-step{padding:11px 0}.dsh-mobile-control__frp-step + .dsh-mobile-control__frp-step{border-top:1px solid var(--dsw-alias-border-l2,#e1e5eb)}.dsh-mobile-control__frp-step>strong{display:block;margin-bottom:3px;font-size:12px;line-height:1.4}.dsh-mobile-control__frp-step>p{margin:0 0 9px;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:1.5}.dsh-mobile-control__frp-changes{margin:0 0 9px;padding:0;list-style:none;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:1.5}.dsh-mobile-control__frp-changes li{position:relative;margin:0;padding-left:12px}.dsh-mobile-control__frp-changes li+li{margin-top:5px}.dsh-mobile-control__frp-changes li::before{content:"•";position:absolute;left:2px;color:var(--dsw-alias-label-tertiary,#98a1ad)}.dsh-mobile-control__frp-step>.dsh-mobile-control__frp-requirement{padding:8px 9px;border-radius:9px;background:var(--dsw-alias-bg-layer-1,#f3f5f8);color:var(--dsw-alias-label-primary,#384152);font-size:11px}.dsh-mobile-control__frp-fields{display:grid;grid-template-columns:minmax(0,1fr) 96px;gap:8px}.dsh-mobile-control__frp-fields>.dsh-mobile-control__field:nth-child(5),.dsh-mobile-control__frp-fields>.dsh-mobile-control__field:nth-child(6){grid-column:1/-1}.dsh-mobile-control__frp-fields>.dsh-mobile-control__field[hidden]{display:none}.dsh-mobile-control__frp-fields select{box-sizing:border-box;width:100%;min-height:44px;padding:9px 32px 9px 10px;border:1px solid var(--dsw-alias-border-l3,#cfd5dd);border-radius:10px;background:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-alias-label-primary,#16181d);font:14px/1.4 system-ui}.dsh-mobile-control__frp-fields select:disabled{cursor:not-allowed;opacity:.55}.dsh-mobile-control__frp-hint{margin:0;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:1.5}.dsh-mobile-control__field{display:flex;min-width:0;flex-direction:column;gap:5px;color:var(--dsw-alias-label-secondary,#606873);font-size:11px}.dsh-mobile-control__field:nth-child(3),.dsh-mobile-control__field:nth-child(4){grid-column:1/-1}.dsh-mobile-control__field input{box-sizing:border-box;width:100%;min-height:44px;padding:9px 10px;border:1px solid var(--dsw-alias-border-l3,#cfd5dd);border-radius:10px;background:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-alias-label-primary,#16181d);font:16px/1.4 system-ui}.dsh-mobile-control__frp-action{box-sizing:border-box;width:100%;min-height:44px;padding:9px 12px;border-radius:10px;font:650 12px/1.3 system-ui;cursor:pointer}.dsh-mobile-control__frp-action:disabled{cursor:not-allowed;opacity:.5}.dsh-mobile-control__remote-workspace{margin:0;padding:12px;border:1px solid var(--dsw-alias-border-l2,#dbe1e8);border-radius:15px;background:var(--dsw-alias-bg-layer-1,#f7f8fa)}.dsh-mobile-control__stage-header{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:9px}.dsh-mobile-control__stage-header .dsh-mobile-control__section-title{margin:0}.dsh-mobile-control__stage-meta{display:flex;min-width:0;align-items:center;justify-content:flex-end;gap:5px}.dsh-mobile-control__stage-value{max-width:115px;overflow:hidden;color:var(--dsw-alias-label-primary,#16181d);font:650 11px/1.3 system-ui;text-overflow:ellipsis;white-space:nowrap}.dsh-mobile-control__state-badge{flex:none;padding:3px 7px;border-radius:999px;background:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-alias-label-secondary,#606873);font:650 11px/1.25 system-ui}.dsh-mobile-control__state-badge.is-ready{background:var(--dsw-alias-state-success-tertiary,#e6f7f0);color:var(--dsw-alias-label-primary,#087454)}.dsh-mobile-control__state-badge.is-busy{background:var(--dsw-alias-state-business-tertiary,#e8f0ff);color:var(--dsw-alias-label-primary,#1d4ed8)}.dsh-mobile-control__state-badge.is-attention{background:var(--dsw-alias-state-warn-tertiary,#fff4dc);color:var(--dsw-alias-label-primary,#935100)}.dsh-mobile-control__remote-workspace>.dsh-mobile-control__status{box-sizing:border-box;margin:0 0 10px;padding:9px 10px;border-radius:10px;background:var(--dsw-alias-bg-layer-2,#fff);font-size:11px;line-height:1.45}.dsh-mobile-control__provider-setup-body{margin:0 0 10px}.dsh-mobile-control__provider-setup-body>.dsh-mobile-control__cpolar-setup{margin:0}.dsh-mobile-control__provider-setup-body>.dsh-mobile-control__cpolar-setup>.dsh-mobile-control__section-title,.dsh-mobile-control__provider-setup-body>.dsh-mobile-control__frp-setup>.dsh-mobile-control__section-title{display:none}.dsh-mobile-control__provider-setup-body>.dsh-mobile-control__details{margin:0;padding:9px 10px;border:1px solid var(--dsw-alias-border-l2,#dbe1e8);border-radius:11px;background:var(--dsw-alias-bg-layer-2,#fff)}.dsh-mobile-control__remote-workspace>.dsh-mobile-control__actions{margin-top:2px}.dsh-mobile-control__remote-workspace>.dsh-mobile-control__qr{margin:10px 0 0}.dsh-mobile-control__remote-workspace>.dsh-mobile-control__manage-row{margin-top:10px;padding-top:10px;border-top:1px solid var(--dsw-alias-border-l2,#e1e5eb)}
|
|
17303
|
+
.dsh-mobile-control__frp-setup{margin:0;padding:12px;border:1px solid var(--dsw-alias-border-l2,#dbe1e8);border-radius:13px;background:var(--dsw-alias-bg-layer-2,#fff)}.dsh-mobile-control__frp-setup[hidden]{display:none}.dsh-mobile-control__frp-step{padding:11px 0}.dsh-mobile-control__frp-step + .dsh-mobile-control__frp-step{border-top:1px solid var(--dsw-alias-border-l2,#e1e5eb)}.dsh-mobile-control__frp-step>strong{display:block;margin-bottom:3px;font-size:12px;line-height:1.4}.dsh-mobile-control__frp-step>p{margin:0 0 9px;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:1.5}.dsh-mobile-control__frp-changes{margin:0 0 9px;padding:0;list-style:none;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:1.5}.dsh-mobile-control__frp-changes li{position:relative;margin:0;padding-left:12px}.dsh-mobile-control__frp-changes li+li{margin-top:5px}.dsh-mobile-control__frp-changes li::before{content:"•";position:absolute;left:2px;color:var(--dsw-alias-label-tertiary,#98a1ad)}.dsh-mobile-control__frp-step>.dsh-mobile-control__frp-requirement{padding:8px 9px;border-radius:9px;background:var(--dsw-alias-bg-layer-1,#f3f5f8);color:var(--dsw-alias-label-primary,#384152);font-size:11px}.dsh-mobile-control__frp-fields{display:grid;grid-template-columns:minmax(0,1fr) 96px;gap:8px}.dsh-mobile-control__frp-fields[hidden]{display:none}.dsh-mobile-control__frp-fields>.dsh-mobile-control__field:nth-child(5),.dsh-mobile-control__frp-fields>.dsh-mobile-control__field:nth-child(6),.dsh-mobile-control__frp-fields>.dsh-mobile-control__field:nth-child(7){grid-column:1/-1}.dsh-mobile-control__frp-fields>.dsh-mobile-control__field[hidden]{display:none}.dsh-mobile-control__frp-fields select{box-sizing:border-box;width:100%;min-height:44px;padding:9px 32px 9px 10px;border:1px solid var(--dsw-alias-border-l3,#cfd5dd);border-radius:10px;background:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-alias-label-primary,#16181d);font:14px/1.4 system-ui}.dsh-mobile-control__frp-fields select:disabled{cursor:not-allowed;opacity:.55}.dsh-mobile-control__frp-hint{margin:0;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:1.5}.dsh-mobile-control__field{display:flex;min-width:0;flex-direction:column;gap:5px;color:var(--dsw-alias-label-secondary,#606873);font-size:11px}.dsh-mobile-control__field:nth-child(3),.dsh-mobile-control__field:nth-child(4){grid-column:1/-1}.dsh-mobile-control__field input{box-sizing:border-box;width:100%;min-height:44px;padding:9px 10px;border:1px solid var(--dsw-alias-border-l3,#cfd5dd);border-radius:10px;background:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-alias-label-primary,#16181d);font:16px/1.4 system-ui}.dsh-mobile-control__frp-action{box-sizing:border-box;width:100%;min-height:44px;padding:9px 12px;border-radius:10px;font:650 12px/1.3 system-ui;cursor:pointer}.dsh-mobile-control__frp-action:disabled{cursor:not-allowed;opacity:.5}.dsh-mobile-control__remote-workspace{margin:0;padding:12px;border:1px solid var(--dsw-alias-border-l2,#dbe1e8);border-radius:15px;background:var(--dsw-alias-bg-layer-1,#f7f8fa)}.dsh-mobile-control__stage-header{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:9px}.dsh-mobile-control__stage-header .dsh-mobile-control__section-title{margin:0}.dsh-mobile-control__stage-meta{display:flex;min-width:0;align-items:center;justify-content:flex-end;gap:5px}.dsh-mobile-control__stage-value{max-width:115px;overflow:hidden;color:var(--dsw-alias-label-primary,#16181d);font:650 11px/1.3 system-ui;text-overflow:ellipsis;white-space:nowrap}.dsh-mobile-control__state-badge{flex:none;padding:3px 7px;border-radius:999px;background:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-alias-label-secondary,#606873);font:650 11px/1.25 system-ui}.dsh-mobile-control__state-badge.is-ready{background:var(--dsw-alias-state-success-tertiary,#e6f7f0);color:var(--dsw-alias-label-primary,#087454)}.dsh-mobile-control__state-badge.is-busy{background:var(--dsw-alias-state-business-tertiary,#e8f0ff);color:var(--dsw-alias-label-primary,#1d4ed8)}.dsh-mobile-control__state-badge.is-attention{background:var(--dsw-alias-state-warn-tertiary,#fff4dc);color:var(--dsw-alias-label-primary,#935100)}.dsh-mobile-control__remote-workspace>.dsh-mobile-control__status{box-sizing:border-box;margin:0 0 10px;padding:9px 10px;border-radius:10px;background:var(--dsw-alias-bg-layer-2,#fff);font-size:11px;line-height:1.45}.dsh-mobile-control__provider-setup-body{margin:0 0 10px}.dsh-mobile-control__provider-setup-body>.dsh-mobile-control__cpolar-setup{margin:0}.dsh-mobile-control__provider-setup-body>.dsh-mobile-control__cpolar-setup>.dsh-mobile-control__section-title,.dsh-mobile-control__provider-setup-body>.dsh-mobile-control__frp-setup>.dsh-mobile-control__section-title{display:none}.dsh-mobile-control__provider-setup-body>.dsh-mobile-control__details{margin:0;padding:9px 10px;border:1px solid var(--dsw-alias-border-l2,#dbe1e8);border-radius:11px;background:var(--dsw-alias-bg-layer-2,#fff)}.dsh-mobile-control__remote-workspace>.dsh-mobile-control__actions{margin-top:2px}.dsh-mobile-control__remote-workspace>.dsh-mobile-control__qr{margin:10px 0 0}.dsh-mobile-control__remote-workspace>.dsh-mobile-control__manage-row{margin-top:10px;padding-top:10px;border-top:1px solid var(--dsw-alias-border-l2,#e1e5eb)}
|
|
16781
17304
|
.dsh-mobile-control__frp-overview{display:grid;grid-template-columns:32px minmax(0,1fr);align-items:center;gap:10px;margin:0 0 10px;padding:10px;border:1px solid var(--dsw-alias-state-success-primary,#a9dfc9);border-radius:11px;background:var(--dsw-alias-state-success-tertiary,#edf9f4)}.dsh-mobile-control__frp-overview[hidden]{display:none}.dsh-mobile-control__frp-overview-mark{display:grid;width:32px;height:32px;place-items:center;border-radius:50%;background:#087454;color:#fff;font:700 15px/1 system-ui}.dsh-mobile-control__frp-overview-body{display:flex;min-width:0;flex-direction:column;gap:2px}.dsh-mobile-control__frp-overview-body strong{color:var(--dsw-alias-label-primary,#075d46);font-size:12px;line-height:1.35}.dsh-mobile-control__frp-overview-body span{overflow:hidden;color:var(--dsw-alias-label-secondary,#357061);font:11px/1.4 ui-monospace,SFMono-Regular,Consolas,monospace;text-overflow:ellipsis;white-space:nowrap}.dsh-mobile-control__frp-group{margin:8px 0 0;overflow:hidden;border:1px solid var(--dsw-alias-border-l2,#dbe1e8);border-radius:11px;background:var(--dsw-alias-bg-layer-1,#f8fafc)}.dsh-mobile-control__frp-group>summary{box-sizing:border-box;min-height:44px;padding:12px 34px 10px 12px;color:var(--dsw-alias-label-primary,#16181d);font:650 12px/1.4 system-ui;cursor:pointer}.dsh-mobile-control__frp-group[open]>summary{border-bottom:1px solid var(--dsw-alias-border-l2,#e1e5eb);background:var(--dsw-alias-bg-layer-2,#fff)}.dsh-mobile-control__frp-group>.dsh-mobile-control__frp-step{padding:12px}.dsh-mobile-control__frp-group>.dsh-mobile-control__frp-step>strong:first-child{display:none}.dsh-mobile-control__frp-group .dsh-mobile-control__frp-step{border-top:0}.dsh-mobile-control__frp-setup>.dsh-mobile-control__frp-step{margin-bottom:8px;padding:10px;border:1px solid var(--dsw-alias-border-l2,#dbe1e8);border-radius:11px;background:var(--dsw-alias-bg-layer-1,#f8fafc)}.dsh-mobile-control__tunnel{margin:0 0 10px}.dsh-mobile-control__tunnel[hidden]{display:none}
|
|
16782
17305
|
.dsh-mobile-control__lan-setup{box-sizing:border-box;margin:0 0 12px;padding:14px;border:1px solid #6f96db;border-radius:15px;background:var(--dsw-alias-bg-layer-1,#f5f8ff)}.dsh-mobile-control__lan-setup[hidden],.dsh-mobile-control__lan-setup-form[hidden]{display:none}.dsh-mobile-control__lan-setup>.dsh-mobile-control__section-title{margin-bottom:5px}.dsh-mobile-control__lan-setup>.dsh-mobile-control__intro{margin-bottom:12px}.dsh-mobile-control__lan-setup-form{display:grid;gap:9px}.dsh-mobile-control__lan-setup .dsh-mobile-control__field select{box-sizing:border-box;width:100%;min-height:44px;padding:9px 32px 9px 10px;border:1px solid var(--dsw-alias-border-l3,#cfd5dd);border-radius:10px;background:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-alias-label-primary,#16181d);font:14px/1.4 system-ui}.dsh-mobile-control__lan-setup .dsh-mobile-control__component-note{margin:0}.dsh-mobile-control__lan-setup-actions{display:grid;grid-template-columns:1fr 1.35fr;gap:8px}.dsh-mobile-control__lan-setup-actions button{box-sizing:border-box;min-width:0;min-height:44px;padding:9px 10px;border-radius:10px;font:650 12px/1.3 system-ui;cursor:pointer}.dsh-mobile-control__lan-setup-actions button:disabled{cursor:wait;opacity:.55}.dsh-mobile-control__lan-setup>.dsh-mobile-control__status{margin:10px 0 0;line-height:1.5}.dsh-mobile-control__lan-setup>.dsh-mobile-control__status:empty{display:none}
|
|
16783
17306
|
.dsh-mobile-control__access{display:flex;align-items:baseline;gap:6px;min-width:0;margin:0 0 12px}.dsh-mobile-control__access[hidden]{display:none}.dsh-mobile-control__access-label{flex:none;color:var(--dsw-alias-label-secondary,#606873);white-space:nowrap}.dsh-mobile-control__access-label::after{content:":"}.dsh-mobile-control__access-link{min-width:0;overflow:hidden;color:var(--dsw-alias-label-primary-bluish,#2563eb);text-decoration:none;text-overflow:ellipsis;white-space:nowrap}.dsh-mobile-control__access-link:hover{text-decoration:underline}.dsh-mobile-control__qr{display:flex;justify-content:center;margin:0 0 12px}.dsh-mobile-control__qr[hidden]{display:none}.dsh-mobile-control__qr img{border-radius:12px;background:#fff;padding:8px}.dsh-mobile-control__qr.is-expandable{cursor:zoom-in}.dsh-mobile-control__qr.is-expandable:focus-visible{outline:3px solid var(--dsw-alias-state-business-primary,#2563eb);outline-offset:2px;border-radius:12px}.dsh-mobile-control__qr-zoom{position:fixed;inset:0;z-index:1001;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,.72)}.dsh-mobile-control__qr-zoom[hidden]{display:none}.dsh-mobile-control__qr-zoom-image{width:min(84vw,360px);height:min(84vw,360px);border-radius:12px;background:#fff;padding:12px}.dsh-mobile-control__qr-zoom-close{position:absolute;top:12px;right:16px;min-width:44px;min-height:44px;border-radius:999px;border:1px solid var(--dsw-alias-border-l2,#dbe1e8);background:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-alias-label-primary,#16181d);font:600 18px/1 system-ui;cursor:pointer}
|
|
@@ -17142,9 +17665,10 @@ dialog.dshm-picker[open]{display:grid;place-items:center}dialog.dshm-picker::bac
|
|
|
17142
17665
|
}
|
|
17143
17666
|
/** Client services required by the mobile adaptation. */
|
|
17144
17667
|
const inject = ["slots"];
|
|
17145
|
-
//#endregion
|
|
17146
17668
|
exports.CONTROL_STYLES = CONTROL_STYLES;
|
|
17669
|
+
exports.DIAGNOSTIC_NETWORK_MESSAGES = DIAGNOSTIC_NETWORK_MESSAGES;
|
|
17147
17670
|
exports.DIAGNOSTIC_REASON_MESSAGES = DIAGNOSTIC_REASON_MESSAGES;
|
|
17671
|
+
exports.DIAGNOSTIC_SCOPE_MESSAGES = DIAGNOSTIC_SCOPE_MESSAGES;
|
|
17148
17672
|
exports.LOCALIZED_DIAGNOSTIC_COPY = LOCALIZED_DIAGNOSTIC_COPY;
|
|
17149
17673
|
exports.MOBILE_CONTROL_MESSAGES = MOBILE_CONTROL_MESSAGES;
|
|
17150
17674
|
exports.PerIdActivationLifecycle = PerIdActivationLifecycle;
|