dsh-zen-remote 2.2.9 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/README.zh-CN.md +2 -2
- package/docs/interface.md +1 -1
- package/docs/remote-access.md +20 -0
- package/lan-gate.mjs +11 -1
- package/lib/adapters/dsh-better-sidebar/index.js +6 -2
- package/lib/adapters/dsh-better-sidebar/index.js.map +1 -1
- package/lib/adapters/dsh-better-sidebar/methods.js +3 -0
- package/lib/adapters/dsh-better-sidebar/methods.js.map +1 -1
- package/lib/admin-routes.js +33 -2
- package/lib/admin-routes.js.map +1 -1
- package/lib/client.js +3289 -6
- package/lib/config.js +70 -0
- package/lib/config.js.map +1 -1
- package/lib/index.js +232 -2
- package/lib/index.js.map +1 -1
- package/lib/intercept.js +43 -3
- package/lib/intercept.js.map +1 -1
- package/lib/lan-gate-server.cjs +29 -3
- package/lib/merge-streams.js +42 -12
- package/lib/merge-streams.js.map +1 -1
- package/lib/types/adapters/dsh-better-sidebar/index.d.ts +1 -1
- package/lib/types/adapters/dsh-better-sidebar/index.d.ts.map +1 -1
- package/lib/types/adapters/dsh-better-sidebar/methods.d.ts.map +1 -1
- package/lib/types/admin-routes.d.ts +13 -0
- package/lib/types/admin-routes.d.ts.map +1 -1
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/locales.d.ts +204 -1
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/client/wizard/GatewayWizard.d.ts +29 -0
- package/lib/types/client/wizard/GatewayWizard.d.ts.map +1 -0
- package/lib/types/client/wizard/WizardCard.d.ts +30 -0
- package/lib/types/client/wizard/WizardCard.d.ts.map +1 -0
- package/lib/types/client/wizard/cards/MigrateCard.d.ts +15 -0
- package/lib/types/client/wizard/cards/MigrateCard.d.ts.map +1 -0
- package/lib/types/client/wizard/cards/PortForwardCard.d.ts +15 -0
- package/lib/types/client/wizard/cards/PortForwardCard.d.ts.map +1 -0
- package/lib/types/client/wizard/cards/ProxyCard.d.ts +19 -0
- package/lib/types/client/wizard/cards/ProxyCard.d.ts.map +1 -0
- package/lib/types/client/wizard/cards/TokenCard.d.ts +20 -0
- package/lib/types/client/wizard/cards/TokenCard.d.ts.map +1 -0
- package/lib/types/client/wizard/register-wizard.d.ts +51 -0
- package/lib/types/client/wizard/register-wizard.d.ts.map +1 -0
- package/lib/types/client/wizard/wizard-css.d.ts +10 -0
- package/lib/types/client/wizard/wizard-css.d.ts.map +1 -0
- package/lib/types/client-data/qr.d.ts +20 -0
- package/lib/types/client-data/qr.d.ts.map +1 -0
- package/lib/types/client-data/settings-form.d.ts +7 -2
- package/lib/types/client-data/settings-form.d.ts.map +1 -1
- package/lib/types/client-data/wizard.d.ts +247 -0
- package/lib/types/client-data/wizard.d.ts.map +1 -0
- package/lib/types/config.d.ts +27 -0
- package/lib/types/config.d.ts.map +1 -1
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/intercept.d.ts.map +1 -1
- package/lib/types/merge-streams.d.ts.map +1 -1
- package/lib/types/wizard/binary-io.d.ts +111 -0
- package/lib/types/wizard/binary-io.d.ts.map +1 -0
- package/lib/types/wizard/binary.d.ts +118 -0
- package/lib/types/wizard/binary.d.ts.map +1 -0
- package/lib/types/wizard/caddy-process.d.ts +101 -0
- package/lib/types/wizard/caddy-process.d.ts.map +1 -0
- package/lib/types/wizard/caddy.d.ts +53 -0
- package/lib/types/wizard/caddy.d.ts.map +1 -0
- package/lib/types/wizard/cloudflare.d.ts +112 -0
- package/lib/types/wizard/cloudflare.d.ts.map +1 -0
- package/lib/types/wizard/cloudflared.d.ts +71 -0
- package/lib/types/wizard/cloudflared.d.ts.map +1 -0
- package/lib/types/wizard/probe.d.ts +66 -0
- package/lib/types/wizard/probe.d.ts.map +1 -0
- package/lib/types/wizard/proxy-snippets.d.ts +60 -0
- package/lib/types/wizard/proxy-snippets.d.ts.map +1 -0
- package/lib/types/wizard/routes.d.ts +152 -0
- package/lib/types/wizard/routes.d.ts.map +1 -0
- package/lib/types/wizard/source-detect.d.ts +53 -0
- package/lib/types/wizard/source-detect.d.ts.map +1 -0
- package/lib/types/wizard/status.d.ts +115 -0
- package/lib/types/wizard/status.d.ts.map +1 -0
- package/lib/types/wizard/token-store.d.ts +27 -0
- package/lib/types/wizard/token-store.d.ts.map +1 -0
- package/lib/types/wizard/tunnel-orchestrator.d.ts +90 -0
- package/lib/types/wizard/tunnel-orchestrator.d.ts.map +1 -0
- package/lib/types/wizard/verify.d.ts +97 -0
- package/lib/types/wizard/verify.d.ts.map +1 -0
- package/lib/wizard/binary-io.js +386 -0
- package/lib/wizard/binary-io.js.map +1 -0
- package/lib/wizard/binary.js +138 -0
- package/lib/wizard/binary.js.map +1 -0
- package/lib/wizard/caddy-process.js +162 -0
- package/lib/wizard/caddy-process.js.map +1 -0
- package/lib/wizard/caddy.js +80 -0
- package/lib/wizard/caddy.js.map +1 -0
- package/lib/wizard/cloudflare.js +334 -0
- package/lib/wizard/cloudflare.js.map +1 -0
- package/lib/wizard/cloudflared.js +158 -0
- package/lib/wizard/cloudflared.js.map +1 -0
- package/lib/wizard/probe.js +118 -0
- package/lib/wizard/probe.js.map +1 -0
- package/lib/wizard/proxy-snippets.js +112 -0
- package/lib/wizard/proxy-snippets.js.map +1 -0
- package/lib/wizard/routes.js +462 -0
- package/lib/wizard/routes.js.map +1 -0
- package/lib/wizard/source-detect.js +77 -0
- package/lib/wizard/source-detect.js.map +1 -0
- package/lib/wizard/status.js +94 -0
- package/lib/wizard/status.js.map +1 -0
- package/lib/wizard/token-store.js +71 -0
- package/lib/wizard/token-store.js.map +1 -0
- package/lib/wizard/tunnel-orchestrator.js +155 -0
- package/lib/wizard/tunnel-orchestrator.js.map +1 -0
- package/lib/wizard/verify.js +171 -0
- package/lib/wizard/verify.js.map +1 -0
- package/package.json +37 -37
- package/scripts/check-settings-form.mjs +5 -4
- package/scripts/check-wizard-ui.mjs +690 -0
- package/src/adapters/dsh-better-sidebar/index.ts +6 -2
- package/src/adapters/dsh-better-sidebar/methods.ts +3 -0
- package/src/admin-routes.ts +44 -2
- package/src/client/index.tsx +9 -0
- package/src/client/locales.ts +410 -2
- package/src/client/wizard/GatewayWizard.tsx +2220 -0
- package/src/client/wizard/WizardCard.tsx +81 -0
- package/src/client/wizard/cards/MigrateCard.tsx +42 -0
- package/src/client/wizard/cards/PortForwardCard.tsx +37 -0
- package/src/client/wizard/cards/ProxyCard.tsx +56 -0
- package/src/client/wizard/cards/TokenCard.tsx +81 -0
- package/src/client/wizard/register-wizard.ts +99 -0
- package/src/client/wizard/wizard-css.ts +948 -0
- package/src/client-data/qr.ts +284 -0
- package/src/client-data/settings-form.ts +12 -3
- package/src/client-data/wizard.ts +432 -0
- package/src/config.ts +87 -0
- package/src/index.ts +227 -2
- package/src/intercept.ts +43 -3
- package/src/merge-streams.ts +41 -12
- package/src/wizard/binary-io.ts +449 -0
- package/src/wizard/binary.ts +177 -0
- package/src/wizard/caddy-process.ts +228 -0
- package/src/wizard/caddy.ts +97 -0
- package/src/wizard/cloudflare.ts +413 -0
- package/src/wizard/cloudflared.ts +196 -0
- package/src/wizard/probe.ts +161 -0
- package/src/wizard/proxy-snippets.ts +128 -0
- package/src/wizard/routes.ts +537 -0
- package/src/wizard/source-detect.ts +87 -0
- package/src/wizard/status.ts +180 -0
- package/src/wizard/token-store.ts +73 -0
- package/src/wizard/tunnel-orchestrator.ts +197 -0
- package/src/wizard/verify.ts +236 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The dsh-better-sidebar adapter (PB-12), written against EXACTLY
|
|
3
|
-
* versions 0.25.0, 0.26.0, 0.26.1, 0.28.0-alpha.0 and 0.28.
|
|
3
|
+
* versions 0.25.0, 0.26.0, 0.26.1, 0.28.0-alpha.0, 0.28.0 and 0.28.1 (PB-15 widened the list; 0.26.1 is a
|
|
4
4
|
* perf-only patch with the same wire surface as 0.26.0; 0.26.0 is a JSON-api
|
|
5
5
|
* superset of 0.25.0 — it grows fs.readPage and the sidechat dequeue/model/
|
|
6
6
|
* models methods, and moves fs.write's content onto the new raw-text
|
|
@@ -62,7 +62,11 @@ export const dshBetterSidebarAdapter: BridgeAdapter = {
|
|
|
62
62
|
// 0.28.0 (stable, DSH 0.2.1-rc.1+): lib/index.js byte-identical to
|
|
63
63
|
// 0.28.0-alpha.0; the client bundles differ only in CSS-module map order
|
|
64
64
|
// and the service version string. alpha.0 stays for DSH 0.2.1-alpha.5.
|
|
65
|
-
|
|
65
|
+
// 0.28.1: same routes and WebSockets; the JSON api grows `git.history`
|
|
66
|
+
// (paged git-log companion to git.graph — session-scoped read via
|
|
67
|
+
// gitCwdOf, base64url cursor in / commits out, no session ids in the
|
|
68
|
+
// answer; verified against the npm build's lib/index.js:8986).
|
|
69
|
+
versions: ['0.25.0', '0.26.0', '0.26.1', '0.28.0-alpha.0', '0.28.0', '0.28.1'],
|
|
66
70
|
routes: [
|
|
67
71
|
{
|
|
68
72
|
// The JSON API: the method name rides the path tail, the session
|
|
@@ -115,6 +115,9 @@ export const SIDEBAR_METHODS: Readonly<Record<string, SidebarMethodSpec>> = {
|
|
|
115
115
|
'git.log': forward('read'),
|
|
116
116
|
// 0.28.0-alpha.0:只读拓扑提交图(lib/index.js:8626),sessionId 定位,响应无会话 id。
|
|
117
117
|
'git.graph': forward('read'),
|
|
118
|
+
// 0.28.1:git.graph 的分页 git-log 伴读(lib/index.js:8986),同样
|
|
119
|
+
// sessionId 定位、base64url 游标进 / 提交列表出,响应无会话 id。
|
|
120
|
+
'git.history': forward('read'),
|
|
118
121
|
'git.commit-diff': forward('read'),
|
|
119
122
|
'git.show': forward('read'),
|
|
120
123
|
'git.blame': forward('read'),
|
package/src/admin-routes.ts
CHANGED
|
@@ -129,6 +129,43 @@ export interface AdminConfigSnapshot {
|
|
|
129
129
|
sources: Record<keyof ZenRemoteConfig, ConfigSource>
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
+
/** The gateway-wizard declared fields (GW-1). They reach the browser only
|
|
133
|
+
* through the sanitized wizard/status projection (src/wizard/status.ts) —
|
|
134
|
+
* the raw config dump on admin/status strips them, the same redaction
|
|
135
|
+
* discipline that keeps `deviceToken` off every wire surface. */
|
|
136
|
+
const INGRESS_FIELDS = [
|
|
137
|
+
'ingressMode',
|
|
138
|
+
'ingressDomain',
|
|
139
|
+
'ingressHttpsPort',
|
|
140
|
+
'ingressAcmeEmail',
|
|
141
|
+
'ingressPublicUrl',
|
|
142
|
+
] as const
|
|
143
|
+
|
|
144
|
+
/** One {@link INGRESS_FIELDS} member. */
|
|
145
|
+
type IngressField = (typeof INGRESS_FIELDS)[number]
|
|
146
|
+
|
|
147
|
+
/** The admin/status config shape: the resolved snapshot minus the ingress fields. */
|
|
148
|
+
export interface AdminPublicConfig {
|
|
149
|
+
values: Omit<ZenRemoteConfig, IngressField>
|
|
150
|
+
sources: Omit<Record<keyof ZenRemoteConfig, ConfigSource>, IngressField>
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** Copy the snapshot without the wizard-declared fields (a copy, never the
|
|
154
|
+
* live object — the resolver's values are per-request but still shared with
|
|
155
|
+
* other readers of the same getConfig() answer). */
|
|
156
|
+
function publicConfigSnapshot(snapshot: AdminConfigSnapshot): AdminPublicConfig {
|
|
157
|
+
const values = { ...snapshot.values } as Record<string, unknown>
|
|
158
|
+
const sources = { ...snapshot.sources } as Record<string, unknown>
|
|
159
|
+
for (const field of INGRESS_FIELDS) {
|
|
160
|
+
delete values[field]
|
|
161
|
+
delete sources[field]
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
values: values as Omit<ZenRemoteConfig, IngressField>,
|
|
165
|
+
sources: sources as AdminPublicConfig['sources'],
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
132
169
|
export interface AdminHandlerOptions {
|
|
133
170
|
/** The connection service's admit, injected by apply(); tests fake it. */
|
|
134
171
|
admit: (req: IncomingMessage) => AdminAdmission
|
|
@@ -310,7 +347,7 @@ function testPushPayload(lang: ZenRemoteConfig['lang']): { title: string; body:
|
|
|
310
347
|
* plugin restart, so an apply-time snapshot would go stale. */
|
|
311
348
|
async function respondStatus(options: AdminHandlerOptions, req: IncomingMessage, res: ServerResponse): Promise<void> {
|
|
312
349
|
const viaGateway = req.headers['x-zen-remote-via'] !== undefined
|
|
313
|
-
const config = options.getConfig()
|
|
350
|
+
const config = publicConfigSnapshot(options.getConfig())
|
|
314
351
|
let gateway: unknown = null
|
|
315
352
|
let gatewayStatus: number | null = null
|
|
316
353
|
let gatewayReachable = false
|
|
@@ -327,9 +364,14 @@ async function respondStatus(options: AdminHandlerOptions, req: IncomingMessage,
|
|
|
327
364
|
// No answer at all (refused, reset, timeout, non-JSON): gatewayStatus
|
|
328
365
|
// stays null and the settings page renders from config alone.
|
|
329
366
|
}
|
|
330
|
-
// A remote device may see the device list but never the live pairing
|
|
367
|
+
// A remote device may see the device list but never the live pairing
|
|
368
|
+
// code — and never the untrusted-proxy detection or the web-claim record
|
|
369
|
+
// (GW-fix-2/L1, GW-9): both are server-owner surfaces carrying network
|
|
370
|
+
// topology facts and device ids a remote device has no business reading.
|
|
331
371
|
if (viaGateway && gateway !== null && typeof gateway === 'object') {
|
|
332
372
|
;(gateway as { pairing?: unknown }).pairing = null
|
|
373
|
+
;(gateway as { lastForwardedSource?: unknown }).lastForwardedSource = null
|
|
374
|
+
;(gateway as { lastWebClaim?: unknown }).lastWebClaim = null
|
|
333
375
|
}
|
|
334
376
|
responseJson(res, 200, { ok: true, gateway, gatewayReachable, gatewayStatus, config, viaGateway })
|
|
335
377
|
}
|
package/src/client/index.tsx
CHANGED
|
@@ -29,6 +29,8 @@ import { NS } from './locales.ts'
|
|
|
29
29
|
import type { MobileNavKey } from './locales.ts'
|
|
30
30
|
import { SettingsSection } from './settings/SettingsSection.tsx'
|
|
31
31
|
import { registerSettingsPage } from './settings/register-settings.ts'
|
|
32
|
+
import { GatewayWizard } from './wizard/GatewayWizard.tsx'
|
|
33
|
+
import { registerGatewayWizard } from './wizard/register-wizard.ts'
|
|
32
34
|
import { RemoteHeaderIcon } from './RemoteHeaderIcon.tsx'
|
|
33
35
|
import { RemoteShareMenuItem } from './RemoteShareMenu.tsx'
|
|
34
36
|
import { getSharesStore } from '../client-data/shares.ts'
|
|
@@ -115,6 +117,13 @@ export function apply(ctx: ClientContext): void {
|
|
|
115
117
|
// 数组,否则没有该服务的环境整个界面半边都加载不了)。
|
|
116
118
|
registerSettingsPage(ctx, SettingsSection)
|
|
117
119
|
|
|
120
|
+
// GW-10 网关配置引导「让手机连上来」:同样在桌面门之前注册——桌面端 App
|
|
121
|
+
// 正是主服务端,wizard 恰好是它最有用的入口。部件自身三重门控:subject
|
|
122
|
+
// 过滤(kind === 'row' && pkg.name === 'dsh-zen-remote')、保存角色检查
|
|
123
|
+
// (client 角色不渲染)、viaGateway 时全部操作禁用。样式全部作用在组件
|
|
124
|
+
// 自身的 data 属性下,≥1024px 的其他页面逐像素不受影响。
|
|
125
|
+
registerGatewayWizard(ctx, GatewayWizard)
|
|
126
|
+
|
|
118
127
|
// T33b 会话共享的三个入口里前两个(标题行远程图标、会话右键菜单项):
|
|
119
128
|
// 同样必须在桌面门之前注册——桌面端 App 就是主服务端,图标和菜单恰好
|
|
120
129
|
// 住在它的标题行与会话菜单里。部件自身按数据降级:shares 路由 404
|
package/src/client/locales.ts
CHANGED
|
@@ -196,7 +196,7 @@ export const zh = {
|
|
|
196
196
|
// T60: the pairing button's disabled reason while the device-name draft is invalid.
|
|
197
197
|
'settings.client.fixDeviceName': '请先修正设备名称',
|
|
198
198
|
'settings.client.pairingCode': '配对码',
|
|
199
|
-
'settings.client.pairingCodeHint': '在服务端设置页生成「桌面应用端」配对码后填入(8
|
|
199
|
+
'settings.client.pairingCodeHint': '在服务端设置页生成「桌面应用端」配对码后填入(8 位,自动转大写并过滤 0/O/1/I/L 与符号)。',
|
|
200
200
|
'settings.client.pair': '配对',
|
|
201
201
|
'settings.client.pairing': '配对中…',
|
|
202
202
|
'settings.client.failInvalid': '服务端地址不合法',
|
|
@@ -309,6 +309,210 @@ export const zh = {
|
|
|
309
309
|
'downloadToLocal': '下载到本机',
|
|
310
310
|
'downloadBusy': '下载中…',
|
|
311
311
|
'downloadFailed': '下载失败',
|
|
312
|
+
// --- GW-10: 远程访问与配对向导(服务端公网/局域网接入 + 手机/桌面客户端配对) ---
|
|
313
|
+
'wizard.title': '远程访问与设备配对',
|
|
314
|
+
'wizard.subtitle': '配置本机作为服务端(开放手机与另一台电脑连入)或作为客户端连接远端主机',
|
|
315
|
+
'wizard.off': '局域网模式 / 待配置',
|
|
316
|
+
'wizard.step.pick': '选择角色与接入',
|
|
317
|
+
'wizard.step.configure': '填写连接参数',
|
|
318
|
+
'wizard.step.verify': '连通验证与配对',
|
|
319
|
+
'wizard.role.sectionTitle': '本机角色',
|
|
320
|
+
'wizard.role.host': '作为服务端(主机)',
|
|
321
|
+
'wizard.role.hostDesc': '本机运行主力会话与网关,允许手机或另一台 DSH 电脑连入并操作会话',
|
|
322
|
+
'wizard.role.client': '作为桌面客户端(从机)',
|
|
323
|
+
'wizard.role.clientDesc': '本机连接到另一台 DSH 服务端,在侧边栏直接查看与操作远端共享的会话',
|
|
324
|
+
'wizard.role.clientPickNote': '切为客户端后,本机将连接到远端服务端的网关(支持公网 HTTPS 域名或局域网 / Tailscale 地址)。点击「下一步」填写服务端地址与配对码。',
|
|
325
|
+
'wizard.ingressSectionTitle': '服务端接入方式',
|
|
326
|
+
'wizard.path.caddy': '内置 Caddy(推荐)',
|
|
327
|
+
'wizard.path.caddyDesc': '适合有公网 IP 的环境。自动下载 Caddy 并通过 Cloudflare DNS 申请证书,无需手写反代配置',
|
|
328
|
+
'wizard.path.external': '使用已有反向代理',
|
|
329
|
+
'wizard.path.externalDesc': '适合已部署 Nginx、Caddy 或 Lucky 的环境。提供现成转发规则,直接填入现有反代即可',
|
|
330
|
+
'wizard.path.cloudflared': 'Cloudflare Tunnel 内网穿透',
|
|
331
|
+
'wizard.path.cloudflaredDesc': '无需公网 IP,也不必配置路由器端口映射。通过 Cloudflare 隧道直连本机,需域名已接入 Cloudflare',
|
|
332
|
+
'wizard.path.lan': '局域网 / Tailscale 直连',
|
|
333
|
+
'wizard.path.lanDesc': '在同一局域网或虚拟局域网内连接手机与另一台电脑,无需域名与公网证书',
|
|
334
|
+
'wizard.next': '下一步',
|
|
335
|
+
'wizard.back': '上一步',
|
|
336
|
+
'wizard.hostName': '服务端显示名称',
|
|
337
|
+
'wizard.hostNamePlaceholder': '例如:mac-mini',
|
|
338
|
+
'wizard.hostNameHint': '其他电脑或手机连入后在侧边栏看到的主机名称(可留空使用默认名称)',
|
|
339
|
+
'wizard.autoShare': '新建会话自动共享给已配对的桌面客户端',
|
|
340
|
+
'wizard.lanUrl': '局域网 / Tailscale 访问地址(可选)',
|
|
341
|
+
'wizard.lanUrlPlaceholder': 'http://192.168.1.10:3088',
|
|
342
|
+
'wizard.lanUrlHint': '填写本机局域网或 Tailscale 地址(如 http://192.168.1.10:3088),方便下一步直接生成手机扫码二维码与客户端连接信息',
|
|
343
|
+
'wizard.domain': '访问域名',
|
|
344
|
+
'wizard.domainHint': '填写完整域名,如 dsh.example.com(不带 https:// 和路径)',
|
|
345
|
+
'wizard.httpsPort': 'HTTPS 端口',
|
|
346
|
+
'wizard.cfToken': 'Cloudflare API 令牌',
|
|
347
|
+
'wizard.cfTokenHint': '用于自动申请证书或配置隧道,以 0600 权限保存在本机,不写入配置文件',
|
|
348
|
+
'wizard.cfTokenHowTo': '如何获取 API 令牌',
|
|
349
|
+
'wizard.serverUrl': '反代后的公网地址',
|
|
350
|
+
'wizard.serverUrlHint': '填写完整 HTTPS 根地址,如 https://dsh.example.com(不支持子目录)',
|
|
351
|
+
'wizard.proxySnippet': '查看 Nginx / Caddy / Lucky 配置参考',
|
|
352
|
+
'wizard.badDomain': '域名格式无效,请填写如 dsh.example.com 的域名',
|
|
353
|
+
'wizard.badPort': '端口号需为 1–65535 之间的整数',
|
|
354
|
+
'wizard.missingToken': '请填写 Cloudflare API 令牌',
|
|
355
|
+
'wizard.badServerUrl': '请填写有效的根路径地址(公网需 https://,局域网可用 http://,不含子目录)',
|
|
356
|
+
'wizard.verify.gateway': '本地网关就绪',
|
|
357
|
+
'wizard.verify.public': '访问地址连通',
|
|
358
|
+
'wizard.verify.pairing': '设备配对状态',
|
|
359
|
+
'wizard.light.pass': '正常',
|
|
360
|
+
'wizard.light.pending': '待验证',
|
|
361
|
+
'wizard.light.fail': '异常',
|
|
362
|
+
'wizard.pairTarget.web': '配对手机 / 浏览器(扫码)',
|
|
363
|
+
'wizard.pairTarget.desktop': '配对另一台电脑(桌面客户端)',
|
|
364
|
+
'wizard.startVerify': '生成配对二维码',
|
|
365
|
+
'wizard.reverify': '重新生成二维码',
|
|
366
|
+
'wizard.pairingCode': '配对码',
|
|
367
|
+
'wizard.pairingSeconds': '有效期剩余 {seconds} 秒',
|
|
368
|
+
'wizard.qrHint': '用手机相机或浏览器扫码打开配对页,输入上方配对码完成连接',
|
|
369
|
+
'wizard.verifyPass': '配对成功,设备 {deviceId} 已连接',
|
|
370
|
+
'wizard.verifyCookieInsecure': '手机已完成配对,但反向代理未传递 X-Forwarded-Proto: https,导致安全 Cookie 未生效。请检查转发头后重试',
|
|
371
|
+
'wizard.verifyExpired': '配对码已过期,请点击下方按钮重新生成',
|
|
372
|
+
'wizard.verifyStale': '接入配置已变更,请重新生成二维码',
|
|
373
|
+
'wizard.verifyPending': '请用手机扫描二维码并在页面中输入配对码…',
|
|
374
|
+
'wizard.verifyNotStarted': '点击下方按钮验证访问地址并生成手机配对二维码',
|
|
375
|
+
'wizard.desktop.addressLabel': '服务端连接地址(供客户端填写)',
|
|
376
|
+
'wizard.desktop.addressFallback': 'http://<本机局域网IP>:{port}',
|
|
377
|
+
'wizard.desktop.generate': '生成桌面客户端配对码',
|
|
378
|
+
'wizard.desktop.regenerate': '重新生成配对码',
|
|
379
|
+
'wizard.desktop.copyInfo': '复制地址与配对码',
|
|
380
|
+
'wizard.desktop.guide': '在另一台电脑打开本插件详情页,第 1 步选「作为桌面客户端」,第 2 步填入上方服务端地址与 8 位配对码即可完成连接。',
|
|
381
|
+
'wizard.desktop.pairedTitle': '已连接的桌面客户端({count})',
|
|
382
|
+
'wizard.desktop.pairedEmpty': '暂未配对桌面客户端',
|
|
383
|
+
'wizard.client.deviceName': '本机设备名称',
|
|
384
|
+
'wizard.client.deviceNamePlaceholder': '例如:macbook-pro',
|
|
385
|
+
'wizard.client.deviceNameHint': '配对后在服务端设备列表中显示的名称',
|
|
386
|
+
'wizard.client.serverUrl': '服务端地址',
|
|
387
|
+
'wizard.client.serverUrlPlaceholder': 'https://dsh.example.com 或 http://192.168.1.10:3088',
|
|
388
|
+
'wizard.client.serverUrlHint': '填写服务端的公网 HTTPS 地址,或局域网 / Tailscale 下的 http://<服务端IP>:3088',
|
|
389
|
+
'wizard.client.pairingCode': '8 位桌面配对码',
|
|
390
|
+
'wizard.client.pairingCodePlaceholder': '在服务端向导第 3 步切到「配对另一台电脑」生成',
|
|
391
|
+
'wizard.client.pairingCodeHint': '输入服务端生成的 8 位桌面客户端专用配对码(自动转大写,自动过滤 0/O/1/I/L 及符号)',
|
|
392
|
+
'wizard.client.pairAndConnect': '配对并连接服务端',
|
|
393
|
+
'wizard.client.pairingBusy': '正在配对并连接…',
|
|
394
|
+
'wizard.client.skipToStatus': '已配对,查看连接状态',
|
|
395
|
+
'wizard.client.lightCredential': '本地配对凭证',
|
|
396
|
+
'wizard.client.lightConnection': '服务端连接',
|
|
397
|
+
'wizard.client.lightSync': '会话与插件同步',
|
|
398
|
+
'wizard.client.reconfigure': '更换服务端 / 重新配对',
|
|
399
|
+
'wizard.startFailed': '验证未通过:{reason}',
|
|
400
|
+
'wizard.startFailedProbe': '无法访问该连接地址({detail})',
|
|
401
|
+
'wizard.startFailedRuntime': '入口服务尚未运行,请先在上方启动',
|
|
402
|
+
'wizard.startFailedGateway': '本地网关未响应,请检查网关运行状态',
|
|
403
|
+
'wizard.startFailedPair': '无法生成配对码({detail})',
|
|
404
|
+
'wizard.startFailedUrl': '公网地址格式无效',
|
|
405
|
+
'wizard.remoteOnly': '安全限制:公网接入向导仅限在服务端本机操作',
|
|
406
|
+
'wizard.notWired': '当前服务端版本不支持此功能,请升级后重试',
|
|
407
|
+
'wizard.card.proxyTitle': '反向代理配置参考',
|
|
408
|
+
'wizard.card.tokenTitle': '获取 Cloudflare API 令牌',
|
|
409
|
+
'wizard.card.copy': '复制配置',
|
|
410
|
+
'wizard.card.copied': '已复制',
|
|
411
|
+
'wizard.card.close': '关闭',
|
|
412
|
+
'wizard.card.tokenStep1': '登录 Cloudflare 控制台(dash.cloudflare.com),进入右上角「我的个人资料 → API 令牌」(用户令牌,以 cfut_ 开头),或左侧「管理账户 → 账户 API 令牌」(账户令牌,以 cfat_ 开头)',
|
|
413
|
+
'wizard.card.tokenStep2': '点击「创建令牌」(Create Token),选择「编辑区域 DNS」(Edit zone DNS)模板',
|
|
414
|
+
'wizard.card.tokenStep3': '在「权限」中保留默认的「区域(Zone)· DNS · 编辑(Edit)」权限',
|
|
415
|
+
'wizard.card.tokenStep4': '在「区域资源」(Zone Resources)中选择「包括(Include)· 特定区域(Specific zone)· 你的域名」',
|
|
416
|
+
'wizard.card.tokenStep5': '若使用 Cloudflare Tunnel,点击「+ 添加更多权限」补充下方所列的隧道、账户设置与区域读取权限',
|
|
417
|
+
'wizard.card.tokenStep6': '点击「继续以显示摘要」(Continue to summary),核对无误后点击「创建令牌」(Create Token)',
|
|
418
|
+
'wizard.card.tokenStep7': '复制生成的 API 令牌密钥(仅在创建完成页显示一次,关闭后无法再次查看)',
|
|
419
|
+
'wizard.card.tokenStep8': '粘贴到下方输入框并点击「保存令牌」',
|
|
420
|
+
'wizard.card.tokenPerms': '所需权限对照',
|
|
421
|
+
'wizard.card.tokenPermDns': '区域 · DNS · 编辑',
|
|
422
|
+
'wizard.card.tokenPermDnsWhy': '必选,用于 DNS-01 证书签发与解析记录配置',
|
|
423
|
+
'wizard.card.tokenPermTunnel': '账户 · Cloudflare Tunnel · 编辑',
|
|
424
|
+
'wizard.card.tokenPermTunnelWhy': '仅 Cloudflare Tunnel 方式需要',
|
|
425
|
+
'wizard.card.tokenPermAccount': '账户 · 账户设置 · 读取',
|
|
426
|
+
'wizard.card.tokenPermAccountWhy': '仅 Cloudflare Tunnel 方式需要(读取账户 ID)',
|
|
427
|
+
'wizard.card.tokenPermZoneRead': '区域 · 区域 · 读取',
|
|
428
|
+
'wizard.card.tokenPermZoneReadWhy': '仅 Cloudflare Tunnel 方式需要(定位域名所属区域)',
|
|
429
|
+
'wizard.card.tokenPaste': '粘贴 API 令牌',
|
|
430
|
+
'wizard.card.tokenUse': '保存令牌',
|
|
431
|
+
'wizard.card.migrateTitle': '将域名接入 Cloudflare',
|
|
432
|
+
'wizard.card.migrateStep1': '在域名注册商后台关闭 DNSSEC(若已开启),并确认域名未锁定 NS(名称服务器)修改',
|
|
433
|
+
'wizard.card.migrateStep2': '登录 Cloudflare 控制台,在左侧导航进入「域(Domains)→ 概览」,点击「接入域」(Onboard a domain)',
|
|
434
|
+
'wizard.card.migrateStep3': '输入你的根域名(如 example.com),选择快速扫描 DNS 记录,点击继续并选择 Free 计划',
|
|
435
|
+
'wizard.card.migrateStep4': '核对扫描出的 DNS 解析记录后继续,复制 Cloudflare 分配的两个名称服务器(Nameservers)地址',
|
|
436
|
+
'wizard.card.migrateStep5': '前往域名注册商后台,将原有 NS 替换为 Cloudflare 分配的两个名称服务器地址',
|
|
437
|
+
'wizard.card.migrateStep6': '等待状态变为「活动(Active)」(通常数分钟至数小时),返回此处点击「重新检测域名状态」',
|
|
438
|
+
'wizard.card.migrateRecheck': '重新检测域名状态',
|
|
439
|
+
'wizard.card.proxyCheck': '已配置完成,去验证',
|
|
440
|
+
'wizard.card.portForwardTitle': '路由器端口映射说明',
|
|
441
|
+
'wizard.card.portForwardStep1': '登录路由器管理后台(常见地址为 192.168.1.1 或 192.168.0.1)',
|
|
442
|
+
'wizard.card.portForwardStep2': '进入「端口转发 / 虚拟服务器 / NAT」设置页面',
|
|
443
|
+
'wizard.card.portForwardStep3': '新增 TCP 转发规则:外部端口 {port} 指向本机内网 IP 的 {port} 端口',
|
|
444
|
+
'wizard.card.portForwardStep4': '保存规则后,使用手机移动网络(关闭 Wi-Fi)测试公网连接',
|
|
445
|
+
'wizard.portForwardEntry': '非 443 端口:查看路由器端口映射说明',
|
|
446
|
+
'wizard.migrateEntry': '域名尚未接入 Cloudflare?',
|
|
447
|
+
'wizard.ingress': '入口服务',
|
|
448
|
+
'wizard.caddy.start': '启动 Caddy',
|
|
449
|
+
'wizard.caddy.starting': '正在下载并启动…',
|
|
450
|
+
'wizard.caddy.stop': '停止',
|
|
451
|
+
'wizard.caddy.running': 'Caddy 运行中',
|
|
452
|
+
'wizard.caddy.stopped': 'Caddy 已停止',
|
|
453
|
+
'wizard.caddy.neverStarted': 'Caddy 未启动',
|
|
454
|
+
'wizard.caddy.startOk': 'Caddy 已启动',
|
|
455
|
+
'wizard.caddy.startFailed': 'Caddy 启动失败:{reason}',
|
|
456
|
+
'wizard.caddy.failDownload': '自动下载失败,请手动安装后重试',
|
|
457
|
+
'wizard.caddy.failValidate': '生成的配置文件校验未通过',
|
|
458
|
+
'wizard.caddy.failAlreadyRunning': '服务已在运行中',
|
|
459
|
+
'wizard.caddy.failMissingToken': '请先在上一步保存 Cloudflare API 令牌',
|
|
460
|
+
'wizard.caddy.failNoDomain': '请先在上一步填写有效的访问域名',
|
|
461
|
+
'wizard.caddy.failBadConfig': '配置参数有误:{detail}',
|
|
462
|
+
'wizard.caddy.failSpawn': '无法拉起 Caddy 进程',
|
|
463
|
+
'wizard.token.saved': '已保存在本机',
|
|
464
|
+
'wizard.token.saveFailed': '令牌保存失败,请重试',
|
|
465
|
+
'wizard.tunnel.setup': '创建并启动隧道',
|
|
466
|
+
'wizard.tunnel.stop': '停止',
|
|
467
|
+
'wizard.tunnel.running': '隧道运行中',
|
|
468
|
+
'wizard.tunnel.stopped': '隧道已停止',
|
|
469
|
+
'wizard.tunnel.neverStarted': '隧道未启动',
|
|
470
|
+
'wizard.tunnel.ok': 'Cloudflare 隧道已就绪并开始运行',
|
|
471
|
+
'wizard.tunnel.conflict': '检测到同名隧道,请选择要复用的隧道:',
|
|
472
|
+
'wizard.tunnel.useExisting': '复用隧道',
|
|
473
|
+
'wizard.tunnel.zoneNotFound': '当前令牌下未找到该域名所属的 Cloudflare 区域,请确认域名已接入该账号',
|
|
474
|
+
'wizard.tunnel.dnsConflict': '该域名已存在指向 {detail} 的 CNAME 记录,请先在 Cloudflare DNS 中清理后再试',
|
|
475
|
+
'wizard.tunnel.auth': 'Cloudflare 认证失败,请检查令牌权限是否正确',
|
|
476
|
+
'wizard.tunnel.network': '无法连接 Cloudflare API,请检查网络',
|
|
477
|
+
'wizard.tunnel.api': 'Cloudflare 接口报错:{detail}',
|
|
478
|
+
'wizard.tunnel.spawnFailed': 'cloudflared 启动失败:{detail}',
|
|
479
|
+
'wizard.tunnel.noToken': '请先在上一步保存 Cloudflare API 令牌',
|
|
480
|
+
'wizard.tunnel.badDomain': '域名格式无效',
|
|
481
|
+
'wizard.tunnel.checking': '正在配置隧道并启动(首次自动下载 cloudflared)…',
|
|
482
|
+
'wizard.check.okOnCf': '已确认域名托管在 Cloudflare',
|
|
483
|
+
'wizard.check.okNotOnCf': '未在 Cloudflare 中找到该域名,请先完成域名接入',
|
|
484
|
+
'wizard.check.failed': '域名检测失败:{reason}',
|
|
485
|
+
'wizard.overview.roleLabel': '当前角色',
|
|
486
|
+
'wizard.overview.gatewayLabel': '本地网关',
|
|
487
|
+
'wizard.overview.gatewayReady': '运行正常 · 端口 {port}',
|
|
488
|
+
'wizard.overview.gatewayDown': '未响应',
|
|
489
|
+
'wizard.overview.ingressLabel': '接入方式与地址',
|
|
490
|
+
'wizard.overview.devicesLabel': '已配对设备',
|
|
491
|
+
'wizard.overview.devicesSummary': '手机/网页 {web} 台 · 桌面客户端 {desktop} 台',
|
|
492
|
+
'wizard.overview.devicesNone': '暂未配对设备',
|
|
493
|
+
'wizard.overview.clientCredLabel': '本地配对凭证',
|
|
494
|
+
'wizard.overview.clientConnLabel': '服务端连接',
|
|
495
|
+
'wizard.overview.clientServerLabel': '远端服务端地址',
|
|
496
|
+
'wizard.overview.startSetup': '开始配置向导',
|
|
497
|
+
'wizard.overview.reconfigure': '修改接入配置',
|
|
498
|
+
'wizard.overview.pairPhone': '配对手机 / 扫码',
|
|
499
|
+
'wizard.overview.pairDesktop': '配对另一台电脑',
|
|
500
|
+
'wizard.overview.clientDetail': '连接详情与配对向导',
|
|
501
|
+
'wizard.overview.emptyIntro': '尚未完成远程访问配置。点击右侧按钮启动向导,按步骤配置本机作为服务端(开放手机与另一台电脑连入)或作为桌面客户端连接远端主机。',
|
|
502
|
+
'wizard.modal.title': '远程访问与配对向导',
|
|
503
|
+
'wizard.modal.stepTag': '第 {num} 步',
|
|
504
|
+
'wizard.modal.step1Desc': '选择本机作为服务端还是桌面客户端;若作为服务端,选择外部设备的连入方式',
|
|
505
|
+
'wizard.modal.step2Desc': '根据上一步选择的方案,填写对应的连接地址、域名或配对凭证',
|
|
506
|
+
'wizard.modal.step3Desc': '检测连通状态,并扫码配对手机或生成桌面客户端配对码',
|
|
507
|
+
'wizard.modal.selectedPlan': '已选方案:{plan}',
|
|
508
|
+
'wizard.modal.cancel': '取消',
|
|
509
|
+
'wizard.modal.saveAndNext': '保存并进入验证',
|
|
510
|
+
'wizard.modal.finish': '完成',
|
|
511
|
+
'wizard.light.probing': '检测中…',
|
|
512
|
+
'wizard.overview.manageDevices': '管理设备',
|
|
513
|
+
'wizard.devicesModal.title': '已配对设备管理',
|
|
514
|
+
'wizard.devicesModal.subtitle': '查看与管理已配对的手机/网页设备及桌面客户端,支持改名、切换布局或吊销凭证',
|
|
515
|
+
'wizard.devicesModal.retest': '重新测试连通性',
|
|
312
516
|
} as const
|
|
313
517
|
|
|
314
518
|
/** English dictionary, key-identical to the Chinese source of truth. */
|
|
@@ -504,7 +708,7 @@ export const en: Record<MobileNavKey, string> = {
|
|
|
504
708
|
// T60: the pairing button's disabled reason while the device-name draft is invalid.
|
|
505
709
|
'settings.client.fixDeviceName': 'Fix the device name first',
|
|
506
710
|
'settings.client.pairingCode': 'Pairing code',
|
|
507
|
-
'settings.client.pairingCodeHint': 'Generate a desktop-client pairing code on the server\u2019s settings page and enter it here (8 characters
|
|
711
|
+
'settings.client.pairingCodeHint': 'Generate a desktop-client pairing code on the server\u2019s settings page and enter it here (8 characters; auto-uppercased and filters out 0/O/1/I/L and symbols).',
|
|
508
712
|
'settings.client.pair': 'Pair',
|
|
509
713
|
'settings.client.pairing': 'Pairing…',
|
|
510
714
|
'settings.client.failInvalid': 'The server address is not valid',
|
|
@@ -615,6 +819,210 @@ export const en: Record<MobileNavKey, string> = {
|
|
|
615
819
|
'downloadToLocal': 'Download to this computer',
|
|
616
820
|
'downloadBusy': 'Downloading…',
|
|
617
821
|
'downloadFailed': 'Download failed',
|
|
822
|
+
// --- GW-10: remote access & device pairing wizard ---
|
|
823
|
+
'wizard.title': 'Remote Access & Device Pairing',
|
|
824
|
+
'wizard.subtitle': 'Set up this machine as a server (for phones and other computers) or as a client connected to a remote host',
|
|
825
|
+
'wizard.off': 'LAN mode / Not configured',
|
|
826
|
+
'wizard.step.pick': 'Role & Access',
|
|
827
|
+
'wizard.step.configure': 'Connection Settings',
|
|
828
|
+
'wizard.step.verify': 'Verify & Pair',
|
|
829
|
+
'wizard.role.sectionTitle': 'Machine Role',
|
|
830
|
+
'wizard.role.host': 'Server (Host)',
|
|
831
|
+
'wizard.role.hostDesc': 'Runs main sessions and the gateway on this machine so phones or other DSH computers can connect',
|
|
832
|
+
'wizard.role.client': 'Desktop Client',
|
|
833
|
+
'wizard.role.clientDesc': 'Connects to another DSH server so shared remote sessions appear directly in this sidebar',
|
|
834
|
+
'wizard.role.clientPickNote': 'In Client mode, this machine connects to a remote server gateway over HTTPS or LAN / Tailscale. Click "Next" to enter the server address and pairing code.',
|
|
835
|
+
'wizard.ingressSectionTitle': 'Server Access Method',
|
|
836
|
+
'wizard.path.caddy': 'Managed Caddy (Recommended)',
|
|
837
|
+
'wizard.path.caddyDesc': 'Best when you have a public IP. Downloads Caddy and issues TLS certificates via Cloudflare DNS automatically',
|
|
838
|
+
'wizard.path.external': 'Existing Reverse Proxy',
|
|
839
|
+
'wizard.path.externalDesc': 'Already running Nginx, Caddy, or Lucky? Copy a ready-made proxy rule into your existing setup',
|
|
840
|
+
'wizard.path.cloudflared': 'Cloudflare Tunnel',
|
|
841
|
+
'wizard.path.cloudflaredDesc': 'No public IP or router port forwarding needed. Connects directly through a Cloudflare tunnel',
|
|
842
|
+
'wizard.path.lan': 'LAN / Tailscale Direct',
|
|
843
|
+
'wizard.path.lanDesc': 'Connect phones and computers on the same LAN or Tailscale network without a domain or TLS certificate',
|
|
844
|
+
'wizard.next': 'Next',
|
|
845
|
+
'wizard.back': 'Back',
|
|
846
|
+
'wizard.hostName': 'Server Display Name',
|
|
847
|
+
'wizard.hostNamePlaceholder': 'e.g. mac-mini',
|
|
848
|
+
'wizard.hostNameHint': 'Name shown in the sidebar of connected computers and phones (leave blank for default)',
|
|
849
|
+
'wizard.autoShare': 'Automatically share new sessions with paired desktop clients',
|
|
850
|
+
'wizard.lanUrl': 'LAN / Tailscale URL (optional)',
|
|
851
|
+
'wizard.lanUrlPlaceholder': 'http://192.168.1.10:3088',
|
|
852
|
+
'wizard.lanUrlHint': 'Enter this machine\u2019s LAN or Tailscale URL (e.g. http://192.168.1.10:3088) to generate a phone QR code and copyable client address in the next step',
|
|
853
|
+
'wizard.domain': 'Domain',
|
|
854
|
+
'wizard.domainHint': 'Full domain name, e.g. dsh.example.com (without https:// or path)',
|
|
855
|
+
'wizard.httpsPort': 'HTTPS Port',
|
|
856
|
+
'wizard.cfToken': 'Cloudflare API Token',
|
|
857
|
+
'wizard.cfTokenHint': 'Used for certificate issuance or tunnel setup. Stored locally (0600) and never written to config files',
|
|
858
|
+
'wizard.cfTokenHowTo': 'How to create an API token',
|
|
859
|
+
'wizard.serverUrl': 'Public HTTPS URL',
|
|
860
|
+
'wizard.serverUrlHint': 'Root HTTPS URL, e.g. https://dsh.example.com (subdirectories are not supported)',
|
|
861
|
+
'wizard.proxySnippet': 'View Nginx / Caddy / Lucky config snippets',
|
|
862
|
+
'wizard.badDomain': 'Invalid domain format (e.g. dsh.example.com)',
|
|
863
|
+
'wizard.badPort': 'Port must be an integer between 1 and 65535',
|
|
864
|
+
'wizard.missingToken': 'Enter your Cloudflare API token',
|
|
865
|
+
'wizard.badServerUrl': 'Enter a valid root URL (https:// for public, http:// for LAN, no path)',
|
|
866
|
+
'wizard.verify.gateway': 'Local gateway',
|
|
867
|
+
'wizard.verify.public': 'Access URL reachable',
|
|
868
|
+
'wizard.verify.pairing': 'Device paired',
|
|
869
|
+
'wizard.light.pass': 'Ready',
|
|
870
|
+
'wizard.light.pending': 'Waiting',
|
|
871
|
+
'wizard.light.fail': 'Failed',
|
|
872
|
+
'wizard.pairTarget.web': 'Pair Phone / Browser (QR)',
|
|
873
|
+
'wizard.pairTarget.desktop': 'Pair Another Computer (Desktop Client)',
|
|
874
|
+
'wizard.startVerify': 'Generate Pairing QR Code',
|
|
875
|
+
'wizard.reverify': 'Regenerate QR Code',
|
|
876
|
+
'wizard.pairingCode': 'Pairing code',
|
|
877
|
+
'wizard.pairingSeconds': 'Expires in {seconds}s',
|
|
878
|
+
'wizard.qrHint': 'Scan with your phone to open the pairing page, then enter the code above',
|
|
879
|
+
'wizard.verifyPass': 'Paired — device {deviceId} connected',
|
|
880
|
+
'wizard.verifyCookieInsecure': 'Paired, but the reverse proxy did not pass X-Forwarded-Proto: https. Add the header so secure cookies work, then verify again',
|
|
881
|
+
'wizard.verifyExpired': 'Pairing code expired — generate a new one below',
|
|
882
|
+
'wizard.verifyStale': 'Configuration changed — generate a new QR code',
|
|
883
|
+
'wizard.verifyPending': 'Scan the QR code on your phone and enter the pairing code…',
|
|
884
|
+
'wizard.verifyNotStarted': 'Click the button below to verify the access URL and generate a phone pairing QR code',
|
|
885
|
+
'wizard.desktop.addressLabel': 'Server Address (for client machine)',
|
|
886
|
+
'wizard.desktop.addressFallback': 'http://<LAN-IP>:{port}',
|
|
887
|
+
'wizard.desktop.generate': 'Generate Desktop Pairing Code',
|
|
888
|
+
'wizard.desktop.regenerate': 'Regenerate Code',
|
|
889
|
+
'wizard.desktop.copyInfo': 'Copy Address & Code',
|
|
890
|
+
'wizard.desktop.guide': 'On the other computer, open this plugin page, choose "Desktop Client" in Step 1, and enter the server address and 8-character code above in Step 2.',
|
|
891
|
+
'wizard.desktop.pairedTitle': 'Paired Desktop Clients ({count})',
|
|
892
|
+
'wizard.desktop.pairedEmpty': 'No desktop clients paired yet',
|
|
893
|
+
'wizard.client.deviceName': 'This Computer\u2019s Name',
|
|
894
|
+
'wizard.client.deviceNamePlaceholder': 'e.g. macbook-pro',
|
|
895
|
+
'wizard.client.deviceNameHint': 'Shown in the server\u2019s paired device list',
|
|
896
|
+
'wizard.client.serverUrl': 'Server Address',
|
|
897
|
+
'wizard.client.serverUrlPlaceholder': 'https://dsh.example.com or http://192.168.1.10:3088',
|
|
898
|
+
'wizard.client.serverUrlHint': 'Enter the server\u2019s public HTTPS URL or LAN / Tailscale http://<IP>:3088 address',
|
|
899
|
+
'wizard.client.pairingCode': '8-Character Desktop Pairing Code',
|
|
900
|
+
'wizard.client.pairingCodePlaceholder': 'Generated under "Pair Another Computer" in Step 3 on the server',
|
|
901
|
+
'wizard.client.pairingCodeHint': 'Enter the 8-character desktop client code generated on the server (auto-uppercased; 0/O/1/I/L and symbols are filtered out)',
|
|
902
|
+
'wizard.client.pairAndConnect': 'Pair & Connect',
|
|
903
|
+
'wizard.client.pairingBusy': 'Pairing & connecting…',
|
|
904
|
+
'wizard.client.skipToStatus': 'Already Paired — View Status',
|
|
905
|
+
'wizard.client.lightCredential': 'Pairing token',
|
|
906
|
+
'wizard.client.lightConnection': 'Server connection',
|
|
907
|
+
'wizard.client.lightSync': 'Session & plugin sync',
|
|
908
|
+
'wizard.client.reconfigure': 'Change Server / Re-pair',
|
|
909
|
+
'wizard.startFailed': 'Verification failed: {reason}',
|
|
910
|
+
'wizard.startFailedProbe': 'access URL could not reach this gateway ({detail})',
|
|
911
|
+
'wizard.startFailedRuntime': 'ingress service is not running — start it above first',
|
|
912
|
+
'wizard.startFailedGateway': 'local gateway did not respond',
|
|
913
|
+
'wizard.startFailedPair': 'failed to generate pairing code ({detail})',
|
|
914
|
+
'wizard.startFailedUrl': 'invalid public URL',
|
|
915
|
+
'wizard.remoteOnly': 'Security restriction: public access setup is only available directly on the host machine',
|
|
916
|
+
'wizard.notWired': 'This feature requires a newer server version',
|
|
917
|
+
'wizard.card.proxyTitle': 'Reverse Proxy Configuration',
|
|
918
|
+
'wizard.card.tokenTitle': 'Create a Cloudflare API Token',
|
|
919
|
+
'wizard.card.copy': 'Copy',
|
|
920
|
+
'wizard.card.copied': 'Copied',
|
|
921
|
+
'wizard.card.close': 'Close',
|
|
922
|
+
'wizard.card.tokenStep1': 'In the Cloudflare dashboard (dash.cloudflare.com), open "My Profile → API Tokens" (user token, cfut_) or "Manage Account → Account API tokens" (account token, cfat_)',
|
|
923
|
+
'wizard.card.tokenStep2': 'Select "Create Token" and choose the "Edit zone DNS" template',
|
|
924
|
+
'wizard.card.tokenStep3': 'Under Permissions, keep the default "Zone · DNS · Edit" permission',
|
|
925
|
+
'wizard.card.tokenStep4': 'Under "Zone Resources", select "Include · Specific zone · your domain"',
|
|
926
|
+
'wizard.card.tokenStep5': 'If using Cloudflare Tunnel, click "+ Add more" to add the tunnel, account settings, and zone read permissions listed below',
|
|
927
|
+
'wizard.card.tokenStep6': 'Select "Continue to summary", review the details, and select "Create Token"',
|
|
928
|
+
'wizard.card.tokenStep7': 'Copy the generated token secret (shown only once)',
|
|
929
|
+
'wizard.card.tokenStep8': 'Paste it below and click "Save Token"',
|
|
930
|
+
'wizard.card.tokenPerms': 'Required permissions',
|
|
931
|
+
'wizard.card.tokenPermDns': 'Zone · DNS · Edit',
|
|
932
|
+
'wizard.card.tokenPermDnsWhy': 'Required for DNS-01 certificate issuance and DNS records',
|
|
933
|
+
'wizard.card.tokenPermTunnel': 'Account · Cloudflare Tunnel · Edit',
|
|
934
|
+
'wizard.card.tokenPermTunnelWhy': 'Cloudflare Tunnel only',
|
|
935
|
+
'wizard.card.tokenPermAccount': 'Account · Account Settings · Read',
|
|
936
|
+
'wizard.card.tokenPermAccountWhy': 'Cloudflare Tunnel only (reads account ID)',
|
|
937
|
+
'wizard.card.tokenPermZoneRead': 'Zone · Zone · Read',
|
|
938
|
+
'wizard.card.tokenPermZoneReadWhy': 'Cloudflare Tunnel only (locates domain zone)',
|
|
939
|
+
'wizard.card.tokenPaste': 'Paste API token',
|
|
940
|
+
'wizard.card.tokenUse': 'Save Token',
|
|
941
|
+
'wizard.card.migrateTitle': 'Add Your Domain to Cloudflare',
|
|
942
|
+
'wizard.card.migrateStep1': 'Turn off DNSSEC at your domain registrar (if active) and ensure nameserver changes are unlocked',
|
|
943
|
+
'wizard.card.migrateStep2': 'In the Cloudflare dashboard, go to "Domains → Overview" and select "Onboard a domain"',
|
|
944
|
+
'wizard.card.migrateStep3': 'Enter your apex domain (e.g. example.com), scan DNS records, click Continue, and select the Free plan',
|
|
945
|
+
'wizard.card.migrateStep4': 'Review the scanned DNS records, continue, and copy the two assigned Cloudflare nameservers',
|
|
946
|
+
'wizard.card.migrateStep5': 'At your domain registrar, replace the existing nameservers with the two Cloudflare nameservers',
|
|
947
|
+
'wizard.card.migrateStep6': 'Once the domain status becomes "Active" on the Domains page, return here and click "Recheck Domain"',
|
|
948
|
+
'wizard.card.migrateRecheck': 'Recheck Domain',
|
|
949
|
+
'wizard.card.proxyCheck': 'Configured — Verify Now',
|
|
950
|
+
'wizard.card.portForwardTitle': 'Router Port Forwarding',
|
|
951
|
+
'wizard.card.portForwardStep1': 'Sign in to your router admin page (typically 192.168.1.1 or 192.168.0.1)',
|
|
952
|
+
'wizard.card.portForwardStep2': 'Open "Port Forwarding / Virtual Server / NAT"',
|
|
953
|
+
'wizard.card.portForwardStep3': 'Add a TCP rule: external port {port} → this machine\u2019s LAN IP on port {port}',
|
|
954
|
+
'wizard.card.portForwardStep4': 'Save the rule and test the public URL over mobile data (with Wi-Fi turned off)',
|
|
955
|
+
'wizard.portForwardEntry': 'Non-443 port: router port forwarding guide',
|
|
956
|
+
'wizard.migrateEntry': 'Domain not on Cloudflare yet?',
|
|
957
|
+
'wizard.ingress': 'Ingress service',
|
|
958
|
+
'wizard.caddy.start': 'Start Caddy',
|
|
959
|
+
'wizard.caddy.starting': 'Downloading & starting…',
|
|
960
|
+
'wizard.caddy.stop': 'Stop',
|
|
961
|
+
'wizard.caddy.running': 'Caddy running',
|
|
962
|
+
'wizard.caddy.stopped': 'Caddy stopped',
|
|
963
|
+
'wizard.caddy.neverStarted': 'Caddy not started',
|
|
964
|
+
'wizard.caddy.startOk': 'Caddy started',
|
|
965
|
+
'wizard.caddy.startFailed': 'Caddy failed to start: {reason}',
|
|
966
|
+
'wizard.caddy.failDownload': 'auto-download failed — install Caddy manually and retry',
|
|
967
|
+
'wizard.caddy.failValidate': 'generated config failed validation',
|
|
968
|
+
'wizard.caddy.failAlreadyRunning': 'already running',
|
|
969
|
+
'wizard.caddy.failMissingToken': 'save your Cloudflare API token in the previous step first',
|
|
970
|
+
'wizard.caddy.failNoDomain': 'save a valid domain in the previous step first',
|
|
971
|
+
'wizard.caddy.failBadConfig': 'invalid configuration: {detail}',
|
|
972
|
+
'wizard.caddy.failSpawn': 'failed to start Caddy process',
|
|
973
|
+
'wizard.token.saved': 'Saved locally',
|
|
974
|
+
'wizard.token.saveFailed': 'Failed to save token — please retry',
|
|
975
|
+
'wizard.tunnel.setup': 'Create & Start Tunnel',
|
|
976
|
+
'wizard.tunnel.stop': 'Stop',
|
|
977
|
+
'wizard.tunnel.running': 'Tunnel running',
|
|
978
|
+
'wizard.tunnel.stopped': 'Tunnel stopped',
|
|
979
|
+
'wizard.tunnel.neverStarted': 'Tunnel not started',
|
|
980
|
+
'wizard.tunnel.ok': 'Cloudflare tunnel is active and running',
|
|
981
|
+
'wizard.tunnel.conflict': 'A tunnel with this name already exists — select one to reuse:',
|
|
982
|
+
'wizard.tunnel.useExisting': 'Reuse tunnel',
|
|
983
|
+
'wizard.tunnel.zoneNotFound': 'Domain zone not found under this token — make sure the domain is active on this Cloudflare account',
|
|
984
|
+
'wizard.tunnel.dnsConflict': 'A CNAME record for this domain already points to {detail} — remove it in Cloudflare DNS first',
|
|
985
|
+
'wizard.tunnel.auth': 'Cloudflare authentication failed — check token permissions',
|
|
986
|
+
'wizard.tunnel.network': 'Could not reach Cloudflare API',
|
|
987
|
+
'wizard.tunnel.api': 'Cloudflare API error: {detail}',
|
|
988
|
+
'wizard.tunnel.spawnFailed': 'cloudflared failed to start: {detail}',
|
|
989
|
+
'wizard.tunnel.noToken': 'Save your Cloudflare API token in the previous step first',
|
|
990
|
+
'wizard.tunnel.badDomain': 'Invalid domain format',
|
|
991
|
+
'wizard.tunnel.checking': 'Configuring tunnel & starting (downloading cloudflared on first run)…',
|
|
992
|
+
'wizard.check.okOnCf': 'Domain is active on Cloudflare',
|
|
993
|
+
'wizard.check.okNotOnCf': 'Domain not found on Cloudflare — add it to Cloudflare first',
|
|
994
|
+
'wizard.check.failed': 'Domain check failed: {reason}',
|
|
995
|
+
'wizard.overview.roleLabel': 'Current Role',
|
|
996
|
+
'wizard.overview.gatewayLabel': 'Local Gateway',
|
|
997
|
+
'wizard.overview.gatewayReady': 'Running · port {port}',
|
|
998
|
+
'wizard.overview.gatewayDown': 'Unreachable',
|
|
999
|
+
'wizard.overview.ingressLabel': 'Access Method & URL',
|
|
1000
|
+
'wizard.overview.devicesLabel': 'Paired Devices',
|
|
1001
|
+
'wizard.overview.devicesSummary': 'Phone/Web {web} · Desktop {desktop}',
|
|
1002
|
+
'wizard.overview.devicesNone': 'No paired devices yet',
|
|
1003
|
+
'wizard.overview.clientCredLabel': 'Local Credential',
|
|
1004
|
+
'wizard.overview.clientConnLabel': 'Server Connection',
|
|
1005
|
+
'wizard.overview.clientServerLabel': 'Remote Server URL',
|
|
1006
|
+
'wizard.overview.startSetup': 'Start Setup Wizard',
|
|
1007
|
+
'wizard.overview.reconfigure': 'Reconfigure Wizard',
|
|
1008
|
+
'wizard.overview.pairPhone': 'Pair Phone (QR)',
|
|
1009
|
+
'wizard.overview.pairDesktop': 'Pair Desktop Client',
|
|
1010
|
+
'wizard.overview.clientDetail': 'Connection & Pairing Wizard',
|
|
1011
|
+
'wizard.overview.emptyIntro': 'Remote access is not configured yet. Click the button on the right to launch the step-by-step wizard for server access or desktop client pairing.',
|
|
1012
|
+
'wizard.modal.title': 'Remote Access & Pairing Wizard',
|
|
1013
|
+
'wizard.modal.stepTag': 'Step {num}',
|
|
1014
|
+
'wizard.modal.step1Desc': 'Choose whether this machine acts as the server or a desktop client, and select how devices connect',
|
|
1015
|
+
'wizard.modal.step2Desc': 'Fill in the connection URL, domain, or pairing code for your selected plan',
|
|
1016
|
+
'wizard.modal.step3Desc': 'Verify connectivity and pair your phone or desktop client',
|
|
1017
|
+
'wizard.modal.selectedPlan': 'Selected plan: {plan}',
|
|
1018
|
+
'wizard.modal.cancel': 'Cancel',
|
|
1019
|
+
'wizard.modal.saveAndNext': 'Save & Verify',
|
|
1020
|
+
'wizard.modal.finish': 'Done',
|
|
1021
|
+
'wizard.light.probing': 'Checking…',
|
|
1022
|
+
'wizard.overview.manageDevices': 'Manage Devices',
|
|
1023
|
+
'wizard.devicesModal.title': 'Paired Devices',
|
|
1024
|
+
'wizard.devicesModal.subtitle': 'View and manage paired phone/web and desktop client devices — rename, switch layout, or revoke access',
|
|
1025
|
+
'wizard.devicesModal.retest': 'Retest Connectivity',
|
|
618
1026
|
}
|
|
619
1027
|
|
|
620
1028
|
/** Key domain of the `mobileNav` namespace (zh is the source of truth). */
|