@linxin666/dsh-remote-web-ui 0.4.4 → 0.4.6
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.i18n.yaml +2 -2
- package/README.md +22 -7
- package/README.zh.md +21 -6
- package/lib/client.js +75 -138
- package/lib/client.js.map +1 -1
- package/lib/index.js +162 -22
- package/lib/types/client/PluginSettingsCard.d.ts +7 -0
- package/lib/types/client/PluginSettingsCard.d.ts.map +1 -1
- package/lib/types/client/PluginSettingsCard.js +2 -2
- package/lib/types/client/RemoteSettingsCard.d.ts.map +1 -1
- package/lib/types/client/RemoteSettingsCard.js +2 -1
- package/lib/types/client/index.js +3 -3
- package/lib/types/client/locales.d.ts +0 -4
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/client/locales.js +5 -9
- package/lib/types/client/mobile-adapt.d.ts +2 -2
- package/lib/types/client/mobile-adapt.d.ts.map +1 -1
- package/lib/types/client/mobile-adapt.js +51 -131
- package/lib/types/client/plugin-card-seat.d.ts +5 -0
- package/lib/types/client/plugin-card-seat.d.ts.map +1 -1
- package/lib/types/client/plugin-card-seat.js +2 -0
- package/lib/types/client/settings-form.d.ts +16 -0
- package/lib/types/client/settings-form.d.ts.map +1 -1
- package/lib/types/client/settings-form.js +27 -1
- package/lib/types/detached-work.d.ts +45 -0
- package/lib/types/detached-work.d.ts.map +1 -0
- package/lib/types/detached-work.js +55 -0
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +31 -10
- package/lib/types/lan-bind.d.ts +21 -4
- package/lib/types/lan-bind.d.ts.map +1 -1
- package/lib/types/lan-bind.js +103 -17
- package/lib/types/remote-channel-boot.d.ts.map +1 -1
- package/lib/types/remote-channel-boot.js +4 -1
- package/package.json +19 -19
- package/src/client/PluginSettingsCard.tsx +9 -0
- package/src/client/RemoteSettingsCard.tsx +2 -0
- package/src/client/index.ts +3 -3
- package/src/client/locales.ts +5 -9
- package/src/client/mobile-adapt.ts +53 -136
- package/src/client/plugin-card-seat.ts +7 -0
- package/src/client/settings-card.module.css +31 -5
- package/src/client/settings-form.ts +27 -1
- package/src/detached-work.ts +58 -0
- package/src/index.ts +31 -10
- package/src/lan-bind.ts +111 -17
- package/src/remote-channel-boot.ts +4 -1
package/lib/index.js
CHANGED
|
@@ -13,6 +13,7 @@ import { spawn, spawnSync } from "node:child_process";
|
|
|
13
13
|
import { parseDocument } from "yaml";
|
|
14
14
|
import { EventEmitter } from "node:events";
|
|
15
15
|
import { Tunnel, bin, install } from "cloudflared";
|
|
16
|
+
import { AsyncResource } from "node:async_hooks";
|
|
16
17
|
//#region src/pairing.ts
|
|
17
18
|
/**
|
|
18
19
|
* Pairing state machine: one active one-time token, a device-session table,
|
|
@@ -2746,16 +2747,100 @@ function readPatchContent(file) {
|
|
|
2746
2747
|
if (!existsSync(file)) return "";
|
|
2747
2748
|
return readFileSync(file, "utf8");
|
|
2748
2749
|
}
|
|
2749
|
-
/**
|
|
2750
|
-
|
|
2751
|
-
|
|
2750
|
+
/**
|
|
2751
|
+
* Split a block-sequence region into its top-level items. Only a column-0 `-`
|
|
2752
|
+
* starts an item: that is the shape every writer of this file produces - the
|
|
2753
|
+
* managed block itself and the YAML document API's block-style re-emission.
|
|
2754
|
+
* @param region - text between two line boundaries.
|
|
2755
|
+
* @returns the items in source order; text outside them is not returned.
|
|
2756
|
+
*/
|
|
2757
|
+
function blockItems(region) {
|
|
2758
|
+
const items = [];
|
|
2759
|
+
let start = -1;
|
|
2760
|
+
let offset = 0;
|
|
2761
|
+
for (const line of region.split("\n")) {
|
|
2762
|
+
if (line.startsWith("- ") || line === "-") {
|
|
2763
|
+
if (start !== -1) items.push({
|
|
2764
|
+
start,
|
|
2765
|
+
end: offset,
|
|
2766
|
+
text: region.slice(start, offset)
|
|
2767
|
+
});
|
|
2768
|
+
start = offset;
|
|
2769
|
+
}
|
|
2770
|
+
offset += line.length + 1;
|
|
2771
|
+
}
|
|
2772
|
+
if (start !== -1) items.push({
|
|
2773
|
+
start,
|
|
2774
|
+
end: region.length,
|
|
2775
|
+
text: region.slice(start)
|
|
2776
|
+
});
|
|
2777
|
+
return items;
|
|
2778
|
+
}
|
|
2779
|
+
/**
|
|
2780
|
+
* Whether one top-level item is the webserver row this plugin's block owns.
|
|
2781
|
+
* The row id is the whole signal: the markers declare everything inside them
|
|
2782
|
+
* managed, our block always writes `- id: webserver`, and a same-id row later
|
|
2783
|
+
* in the patch replaces this one wholesale anyway - so an id-webserver row
|
|
2784
|
+
* found inside our markers is this plugin's row (a hand-truncated block may
|
|
2785
|
+
* have lost its `name` line).
|
|
2786
|
+
* @param item - one top-level item's text.
|
|
2787
|
+
* @returns true when the item is the managed webserver row.
|
|
2788
|
+
*/
|
|
2789
|
+
function isManagedWebserverItem(item) {
|
|
2790
|
+
return /^- id:\s*['"]?webserver['"]?[ \t]*(?:\r?\n|$)/.test(item);
|
|
2752
2791
|
}
|
|
2753
|
-
/**
|
|
2792
|
+
/**
|
|
2793
|
+
* The text between a block's BEGIN and END markers: from the character after
|
|
2794
|
+
* the BEGIN line's terminator to the start of the END marker's line (or to
|
|
2795
|
+
* the end of the content without an END marker).
|
|
2796
|
+
* @param content - the patch file text.
|
|
2797
|
+
* @param begin - index of the BEGIN marker.
|
|
2798
|
+
* @param end - index of the END marker, or -1 when the block is unterminated.
|
|
2799
|
+
* @returns the region's text.
|
|
2800
|
+
*/
|
|
2801
|
+
function managedRegion(content, begin, end) {
|
|
2802
|
+
const newlineAfterBegin = content.indexOf("\n", begin);
|
|
2803
|
+
const innerStart = newlineAfterBegin === -1 ? content.length : newlineAfterBegin + 1;
|
|
2804
|
+
const endLineStart = end === -1 ? content.length : content.lastIndexOf("\n", end - 1) + 1;
|
|
2805
|
+
return content.slice(innerStart, Math.max(innerStart, endLineStart));
|
|
2806
|
+
}
|
|
2807
|
+
/**
|
|
2808
|
+
* Remove the managed block (its markers and the webserver row this plugin
|
|
2809
|
+
* wrote) from patch content, keeping every other row.
|
|
2810
|
+
*
|
|
2811
|
+
* The markers travel with the file through writers that append rows through
|
|
2812
|
+
* the YAML document API: the appended rows land at the end of the sequence,
|
|
2813
|
+
* which is BEFORE a trailing END comment, so the region between the markers
|
|
2814
|
+
* can hold rows this plugin never wrote. Deleting the whole region silently
|
|
2815
|
+
* removed the user's model, plugin and remote-control rows on the next rewrite
|
|
2816
|
+
* - the remote-control row carries the LAN toggle itself, so the feature reset
|
|
2817
|
+
* to `undefined` and the phone was locked out again after a restart (DSH
|
|
2818
|
+
* Desktop report, 2026-09-30). Only the managed item is removed here; every
|
|
2819
|
+
* foreign row is kept in place and the fresh block is appended after them (the
|
|
2820
|
+
* same-id row last wins).
|
|
2821
|
+
* @param content - the patch file text.
|
|
2822
|
+
* @returns the text with the markers and the managed row removed.
|
|
2823
|
+
*/
|
|
2754
2824
|
function stripManagedBlock(content) {
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2825
|
+
let text = content;
|
|
2826
|
+
for (;;) {
|
|
2827
|
+
const begin = text.indexOf(LAN_BIND_BLOCK_BEGIN);
|
|
2828
|
+
if (begin === -1) return text;
|
|
2829
|
+
const end = text.indexOf(LAN_BIND_BLOCK_END, begin);
|
|
2830
|
+
const blockStart = text.lastIndexOf("\n", begin - 1) + 1;
|
|
2831
|
+
const newlineAfterEnd = end === -1 ? -1 : text.indexOf("\n", end);
|
|
2832
|
+
const resumeAt = end === -1 ? text.length : newlineAfterEnd === -1 ? text.length : newlineAfterEnd + 1;
|
|
2833
|
+
const region = managedRegion(text, begin, end);
|
|
2834
|
+
let kept = "";
|
|
2835
|
+
let cursor = 0;
|
|
2836
|
+
for (const item of blockItems(region)) {
|
|
2837
|
+
if (!isManagedWebserverItem(item.text)) continue;
|
|
2838
|
+
kept += region.slice(cursor, item.start);
|
|
2839
|
+
cursor = item.end;
|
|
2840
|
+
}
|
|
2841
|
+
kept += region.slice(cursor);
|
|
2842
|
+
text = text.slice(0, blockStart) + kept + text.slice(resumeAt);
|
|
2843
|
+
}
|
|
2759
2844
|
}
|
|
2760
2845
|
/**
|
|
2761
2846
|
* Render the managed block for one bind state. The values are static: the
|
|
@@ -2827,10 +2912,11 @@ function managedBlock(host, port) {
|
|
|
2827
2912
|
function managedBindOf(content) {
|
|
2828
2913
|
const begin = content.indexOf(LAN_BIND_BLOCK_BEGIN);
|
|
2829
2914
|
if (begin === -1) return void 0;
|
|
2830
|
-
const
|
|
2831
|
-
const
|
|
2832
|
-
const
|
|
2833
|
-
const
|
|
2915
|
+
const region = managedRegion(content, begin, content.indexOf(LAN_BIND_BLOCK_END, begin));
|
|
2916
|
+
const items = blockItems(region).filter((item) => isManagedWebserverItem(item.text));
|
|
2917
|
+
const scope = items.length > 0 ? items.map((item) => item.text).join("") : region;
|
|
2918
|
+
const hostMatch = /host:\s*'([^']+)'/.exec(scope);
|
|
2919
|
+
const portMatch = /port:\s*(\d+)/.exec(scope);
|
|
2834
2920
|
return {
|
|
2835
2921
|
host: hostMatch?.[1] ?? "",
|
|
2836
2922
|
port: portMatch !== null ? Number(portMatch[1]) : void 0
|
|
@@ -2851,9 +2937,10 @@ function lanBindState(profile, home = dshHome()) {
|
|
|
2851
2937
|
* patch file is preserved; the block is rewritten atomically (unique temp
|
|
2852
2938
|
* file + rename, so concurrent writers can never rename a half-written
|
|
2853
2939
|
* file) with the original file's permissions preserved. A hand-truncated
|
|
2854
|
-
* unterminated block (BEGIN marker without END
|
|
2855
|
-
*
|
|
2856
|
-
* never stack a second webserver row onto the
|
|
2940
|
+
* unterminated block (BEGIN marker without END) is consumed by
|
|
2941
|
+
* stripManagedBlock as well - markers and managed row removed, foreign rows
|
|
2942
|
+
* kept - so the rewrite can never stack a second webserver row onto the
|
|
2943
|
+
* orphan.
|
|
2857
2944
|
*
|
|
2858
2945
|
* The written file is always exactly one valid YAML document: a base the
|
|
2859
2946
|
* plugin manager left in flow style is re-emitted as a block sequence before
|
|
@@ -2861,9 +2948,7 @@ function lanBindState(profile, home = dshHome()) {
|
|
|
2861
2948
|
*/
|
|
2862
2949
|
function writeLanBind(host, port, profile, home = dshHome()) {
|
|
2863
2950
|
const file = profilePatchFile(profile, home);
|
|
2864
|
-
const
|
|
2865
|
-
const orphanBegin = stripped.indexOf(LAN_BIND_BLOCK_BEGIN);
|
|
2866
|
-
const content = mergePatchContent((orphanBegin === -1 ? stripped : stripped.slice(0, orphanBegin)).trimEnd().replace(/\[\s*\]\s*$/, "").trimEnd(), managedBlock(host, port), file);
|
|
2951
|
+
const content = mergePatchContent(stripManagedBlock(readPatchContent(file)).trimEnd().replace(/\[\s*\]\s*$/, "").trimEnd(), managedBlock(host, port), file);
|
|
2867
2952
|
const mode = existsSync(file) ? statSync(file).mode & 511 : 384;
|
|
2868
2953
|
mkdirSync(dirname(file), { recursive: true });
|
|
2869
2954
|
const temp = `${file}.remote-web-ui-tmp-${process.pid.toString(36)}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
@@ -3911,6 +3996,61 @@ function mountOnce(packageName, fn) {
|
|
|
3911
3996
|
return mount;
|
|
3912
3997
|
}
|
|
3913
3998
|
//#endregion
|
|
3999
|
+
//#region src/detached-work.ts
|
|
4000
|
+
/**
|
|
4001
|
+
* Run one piece of work outside the caller's async context.
|
|
4002
|
+
*
|
|
4003
|
+
* A Host mutation that runs inside `hmr.runExclusive` marks the running async
|
|
4004
|
+
* context with an AsyncLocalStorage store. Side effects on that path that write
|
|
4005
|
+
* a file the HMR config watcher refreshes from - `cordis.patch.yml` above all -
|
|
4006
|
+
* must not run under that mark, or the watcher's refresh re-enters the
|
|
4007
|
+
* exclusive transaction and is refused with "HMR transactions cannot be nested"
|
|
4008
|
+
* (#1751, #1754, #1816).
|
|
4009
|
+
*
|
|
4010
|
+
* Deferring is NOT enough, and the earlier belt that this one replaces was
|
|
4011
|
+
* built on a disproven premise: Node propagates an AsyncLocalStorage store into
|
|
4012
|
+
* `setImmediate`, into `node:timers`, into promise continuations, and into any
|
|
4013
|
+
* AsyncResource scoped to the current async id. Measured on Node 24:
|
|
4014
|
+
*
|
|
4015
|
+
* ```
|
|
4016
|
+
* als.run(true, () => setImmediate(() => als.getStore())) // -> true
|
|
4017
|
+
* ```
|
|
4018
|
+
*
|
|
4019
|
+
* What DOES start clean is an AsyncResource whose `triggerAsyncId` is not the
|
|
4020
|
+
* transaction. A resource created once at module scope - that is, before any
|
|
4021
|
+
* transaction existed - carries no store, and everything it schedules inherits
|
|
4022
|
+
* that emptiness rather than the caller's mark:
|
|
4023
|
+
*
|
|
4024
|
+
* ```
|
|
4025
|
+
* const detached = new AsyncResource('...') // module scope
|
|
4026
|
+
* als.run(true, () => detached.runInAsyncScope(() => setImmediate(() => als.getStore())))
|
|
4027
|
+
* // -> undefined
|
|
4028
|
+
* ```
|
|
4029
|
+
*
|
|
4030
|
+
* @module dsh-web-shared/host/detached-work
|
|
4031
|
+
*/
|
|
4032
|
+
/**
|
|
4033
|
+
* The escape hatch, created at module scope on purpose: a resource built while
|
|
4034
|
+
* a transaction is running would capture that transaction, so this single
|
|
4035
|
+
* instance is the only one the module ever needs. It carries no context of its
|
|
4036
|
+
* own, so every job run through it starts from the process's root context.
|
|
4037
|
+
*/
|
|
4038
|
+
const DETACHED = new AsyncResource("dsh-web:detached-work", { triggerAsyncId: 0 });
|
|
4039
|
+
/**
|
|
4040
|
+
* Run `work` outside the caller's AsyncLocalStorage context.
|
|
4041
|
+
*
|
|
4042
|
+
* The call itself is synchronous - this schedules, it does not defer. Work that
|
|
4043
|
+
* must not block the caller should schedule its own `setImmediate` inside
|
|
4044
|
+
* `work`, which then also starts clean because it inherits this resource's
|
|
4045
|
+
* empty context rather than the caller's.
|
|
4046
|
+
*
|
|
4047
|
+
* @param work - the side effect to detach from the caller's async context.
|
|
4048
|
+
* @returns whatever `work` returns.
|
|
4049
|
+
*/
|
|
4050
|
+
function runDetached(work) {
|
|
4051
|
+
return DETACHED.runInAsyncScope(work);
|
|
4052
|
+
}
|
|
4053
|
+
//#endregion
|
|
3914
4054
|
//#region src/remote-channel-boot.ts
|
|
3915
4055
|
/**
|
|
3916
4056
|
* Parse-time remote-channel boot patch (issue #987): the browser-half patch
|
|
@@ -3955,7 +4095,7 @@ function buildRemoteChannelBootScript(rules = REMOTE_CHANNEL_RULES) {
|
|
|
3955
4095
|
}
|
|
3956
4096
|
/** Boot-watchdog latch: one self-reload per session while the boot is broken. */
|
|
3957
4097
|
const BOOT_WATCHDOG_KEY = "dsh-remote-boot-reload";
|
|
3958
|
-
/**
|
|
4098
|
+
/** Post-load wait for the app's first conversation surface before the reload. */
|
|
3959
4099
|
const BOOT_WATCHDOG_WAIT_MS = 15e3;
|
|
3960
4100
|
/** Watchdog poll cadence. */
|
|
3961
4101
|
const BOOT_WATCHDOG_POLL_MS = 1e3;
|
|
@@ -3970,7 +4110,7 @@ const BOOT_WATCHDOG_POLL_MS = 1e3;
|
|
|
3970
4110
|
*/
|
|
3971
4111
|
function buildBootWatchdogScript(waitMs = BOOT_WATCHDOG_WAIT_MS, pollMs = BOOT_WATCHDOG_POLL_MS) {
|
|
3972
4112
|
const key = JSON.stringify(BOOT_WATCHDOG_KEY);
|
|
3973
|
-
return ";function wBoot(){try{return !!(w.document&&w.document.querySelector&&(w.document.querySelector(\"[data-conversation-scroll]\")||w.document.querySelector(\"[data-slot=\\\"conversation\\\"]\")))}catch(e){return false}}function wTick(n){try{if(wBoot()){try{w.sessionStorage.removeItem(" + key + ")}catch(e){}return}if(n<" + waitMs + "){w.setTimeout(function(){wTick(n+" + pollMs + ")}," + pollMs + ");return}var done=false;try{done=w.sessionStorage.getItem(" + key + ")===\"1\"}catch(e){}if(done)return;try{w.sessionStorage.setItem(" + key + ",\"1\")}catch(e){}w.location.reload()}catch(e){}}if(typeof w.setTimeout===\"function\")w.setTimeout(function(){wTick(0)}," + pollMs + ");";
|
|
4113
|
+
return ";function wBoot(){try{return !!(w.document&&w.document.querySelector&&(w.document.querySelector(\"[data-conversation-scroll]\")||w.document.querySelector(\"[data-slot=\\\"conversation\\\"]\")))}catch(e){return false}}function wTick(n){try{if(wBoot()){try{w.sessionStorage.removeItem(" + key + ")}catch(e){}return}if(!w.document||w.document.readyState!==\"complete\"){w.setTimeout(function(){wTick(0)}," + pollMs + ");return}if(n<" + waitMs + "){w.setTimeout(function(){wTick(n+" + pollMs + ")}," + pollMs + ");return}var done=false;try{done=w.sessionStorage.getItem(" + key + ")===\"1\"}catch(e){}if(done)return;try{w.sessionStorage.setItem(" + key + ",\"1\")}catch(e){}w.location.reload()}catch(e){}}if(typeof w.setTimeout===\"function\")w.setTimeout(function(){wTick(0)}," + pollMs + ");";
|
|
3974
4114
|
}
|
|
3975
4115
|
/** The script this plugin contributes; built once from the live rules. */
|
|
3976
4116
|
const REMOTE_CHANNEL_BOOT_SCRIPT = buildRemoteChannelBootScript();
|
|
@@ -4421,14 +4561,14 @@ function applyImpl(ctx, config) {
|
|
|
4421
4561
|
const scheduleLanBindWork = () => {
|
|
4422
4562
|
if (lanBindWorkPending) return;
|
|
4423
4563
|
lanBindWorkPending = true;
|
|
4424
|
-
setImmediate(() => {
|
|
4564
|
+
runDetached(() => setImmediate(() => {
|
|
4425
4565
|
lanBindWorkPending = false;
|
|
4426
4566
|
try {
|
|
4427
4567
|
applyLanBindWork(resolve());
|
|
4428
4568
|
} catch (error) {
|
|
4429
4569
|
console.error(`remote-web-ui: the deferred lan-bind assertion failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
4430
4570
|
}
|
|
4431
|
-
});
|
|
4571
|
+
}));
|
|
4432
4572
|
};
|
|
4433
4573
|
ctx.effect(() => () => {
|
|
4434
4574
|
lanBindWorkPending = false;
|
|
@@ -24,6 +24,13 @@ export interface PluginSettingsCardProps<TKey extends string = string> {
|
|
|
24
24
|
descriptionKey: TKey;
|
|
25
25
|
/** Optional rich header description rendered instead of the plain t(descriptionKey) text (the plain text stays as the tooltip). */
|
|
26
26
|
descriptionNode?: ReactNode;
|
|
27
|
+
/**
|
|
28
|
+
* Optional leading mark identifying the plugin. A card without one keeps the
|
|
29
|
+
* plain official header shape, so the chrome stays a readable sibling of the
|
|
30
|
+
* built-in PluginCard wherever a family plugin lands in the official bundle
|
|
31
|
+
* seat.
|
|
32
|
+
*/
|
|
33
|
+
icon?: ReactNode;
|
|
27
34
|
/** The card's form state: availability, writability, and what a save would do. */
|
|
28
35
|
state: CardShell;
|
|
29
36
|
/** Write every staged edit. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PluginSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/client/PluginSettingsCard.tsx"],"names":[],"mappings":"AACA;;;;;;;GAOG;AAEH,OAAO,EAAiF,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AACrH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAGnD,oGAAoG;AACpG,eAAO,MAAM,cAAc,kMAUjB,CAAA;AAEV,6CAA6C;AAC7C,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAA;AAEzD,oEAAoE;AACpE,MAAM,MAAM,eAAe,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM,IAAI,IAAI,GAAG,WAAW,CAAA;AAE9E,wDAAwD;AACxD,MAAM,WAAW,uBAAuB,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM;IACnE,0CAA0C;IAC1C,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,KAAK,MAAM,CAAA;IACnF,uCAAuC;IACvC,QAAQ,EAAE,IAAI,CAAA;IACd,4EAA4E;IAC5E,cAAc,EAAE,IAAI,CAAA;IACpB,mIAAmI;IACnI,eAAe,CAAC,EAAE,SAAS,CAAA;IAC3B,kFAAkF;IAClF,KAAK,EAAE,SAAS,CAAA;IAChB,+BAA+B;IAC/B,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,8BAA8B;IAC9B,SAAS,EAAE,MAAM,IAAI,CAAA;IACrB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,mFAAmF;IACnF,4BAA4B,CAAC,EAAE,OAAO,CAAA;IACtC,wFAAwF;IACxF,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B,6BAA6B;IAC7B,QAAQ,EAAE,SAAS,CAAA;CACpB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,uBAAuB,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"PluginSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/client/PluginSettingsCard.tsx"],"names":[],"mappings":"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"}
|
|
@@ -40,8 +40,8 @@ export function PluginSettingsCard(props) {
|
|
|
40
40
|
// With alwaysOpen the nav entry already provides the selection, so the
|
|
41
41
|
// header is a static title row instead of a disclosure button.
|
|
42
42
|
const header = alwaysOpen === true
|
|
43
|
-
? (_jsxs("div", { className: css.headerStatic, children: [_jsxs("span", { className: css.headText, children: [_jsx("span", { className: css.name, title: title, children: title }), _jsx("span", { className: css.description, title: description, children: props.descriptionNode ?? description })] }), state.dirty ? _jsx("span", { className: css.pending, title: props.t('settings.unsaved'), children: props.t('settings.unsaved') }) : null] }))
|
|
44
|
-
: (_jsxs("button", { type: "button", className: css.header, "aria-expanded": open, "aria-label": `${props.t(open ? 'settings.collapse' : 'settings.expand')}: ${title}`, onClick: () => { setOpen(!open); }, children: [_jsxs("span", { className: css.headText, children: [_jsx("span", { className: css.name, title: title, children: title }), _jsx("span", { className: css.description, title: description, children: props.descriptionNode ?? description })] }), state.dirty ? _jsx("span", { className: css.pending, title: props.t('settings.unsaved'), children: props.t('settings.unsaved') }) : null, _jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", xmlns: "http://www.w3.org/2000/svg", className: open ? `${css.chevron} ${css.chevronOpen}` : css.chevron, children: _jsx("path", { d: "M11.8486 5.5L11.4238 5.92383L8.69727 8.65137C8.44157 8.90706 8.21562 9.13382 8.01172 9.29785C7.79912 9.46883 7.55595 9.61756 7.25 9.66602C7.08435 9.69222 6.91565 9.69222 6.75 9.66602C6.44405 9.61756 6.20088 9.46883 5.98828 9.29785C5.78438 9.13382 5.55843 8.90706 5.30273 8.65137L2.57617 5.92383L2.15137 5.5L3 4.65137L3.42383 5.07617L6.15137 7.80273C6.42595 8.07732 6.59876 8.24849 6.74023 8.3623C6.87291 8.46904 6.92272 8.47813 6.9375 8.48047C6.97895 8.48703 7.02105 8.48703 7.0625 8.48047C7.07728 8.47813 7.12709 8.46904 7.25977 8.3623C7.40124 8.24849 7.57405 8.07732 7.84863 7.80273L10.5762 5.07617L11 4.65137L11.8486 5.5Z", fill: "currentColor" }) })] }));
|
|
43
|
+
? (_jsxs("div", { className: css.headerStatic, children: [props.icon !== undefined ? _jsx("span", { className: css.mark, "aria-hidden": "true", children: props.icon }) : null, _jsxs("span", { className: css.headText, children: [_jsx("span", { className: css.name, title: title, children: title }), _jsx("span", { className: css.description, title: description, children: props.descriptionNode ?? description })] }), state.dirty ? _jsx("span", { className: css.pending, title: props.t('settings.unsaved'), children: props.t('settings.unsaved') }) : null] }))
|
|
44
|
+
: (_jsxs("button", { type: "button", className: css.header, "aria-expanded": open, "aria-label": `${props.t(open ? 'settings.collapse' : 'settings.expand')}: ${title}`, onClick: () => { setOpen(!open); }, children: [props.icon !== undefined ? _jsx("span", { className: css.mark, "aria-hidden": "true", children: props.icon }) : null, _jsxs("span", { className: css.headText, children: [_jsx("span", { className: css.name, title: title, children: title }), _jsx("span", { className: css.description, title: description, children: props.descriptionNode ?? description })] }), state.dirty ? _jsx("span", { className: css.pending, title: props.t('settings.unsaved'), children: props.t('settings.unsaved') }) : null, _jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", xmlns: "http://www.w3.org/2000/svg", className: open ? `${css.chevron} ${css.chevronOpen}` : css.chevron, children: _jsx("path", { d: "M11.8486 5.5L11.4238 5.92383L8.69727 8.65137C8.44157 8.90706 8.21562 9.13382 8.01172 9.29785C7.79912 9.46883 7.55595 9.61756 7.25 9.66602C7.08435 9.69222 6.91565 9.69222 6.75 9.66602C6.44405 9.61756 6.20088 9.46883 5.98828 9.29785C5.78438 9.13382 5.55843 8.90706 5.30273 8.65137L2.57617 5.92383L2.15137 5.5L3 4.65137L3.42383 5.07617L6.15137 7.80273C6.42595 8.07732 6.59876 8.24849 6.74023 8.3623C6.87291 8.46904 6.92272 8.47813 6.9375 8.48047C6.97895 8.48703 7.02105 8.48703 7.0625 8.48047C7.07728 8.47813 7.12709 8.46904 7.25977 8.3623C7.40124 8.24849 7.57405 8.07732 7.84863 7.80273L10.5762 5.07617L11 4.65137L11.8486 5.5Z", fill: "currentColor" }) })] }));
|
|
45
45
|
// The namespace exists but the Host does not serve it to this client (the
|
|
46
46
|
// official settings allowlist omits third-party namespaces): show a card
|
|
47
47
|
// that explains the gap instead of vanishing, so a missing card never
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RemoteSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/client/RemoteSettingsCard.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AAC7F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4CAA4C,CAAA;AAC5E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAA;
|
|
1
|
+
{"version":3,"file":"RemoteSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/client/RemoteSettingsCard.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AAC7F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4CAA4C,CAAA;AAC5E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAA;AAGlE,OAAO,EAA+D,KAAK,WAAW,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,IAAI,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAIrK,+EAA+E;AAC/E,MAAM,WAAW,cAAc;IAC7B,oCAAoC;IACpC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,yEAAyE;IACzE,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,sDAAsD;IACtD,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,iDAAiD;IACjD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,6FAA6F;IAC7F,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B,qEAAqE;IACrE,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAA;IACf;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,4CAA4C;AAC5C,MAAM,WAAW,uBAAwB,SAAQ,SAAS;IACxD,qBAAqB;IACrB,OAAO,EAAE,cAAc,CAAA;IACvB,sBAAsB;IACtB,UAAU,EAAE,cAAc,CAAA;IAC1B,gCAAgC;IAChC,cAAc,EAAE,cAAc,CAAA;IAC9B,yBAAyB;IACzB,UAAU,EAAE,cAAc,CAAA;IAC1B,0BAA0B;IAC1B,YAAY,EAAE,cAAc,CAAA;IAC5B,0BAA0B;IAC1B,UAAU,EAAE,cAAc,CAAA;IAC1B,sBAAsB;IACtB,oBAAoB,EAAE,cAAc,CAAA;IACpC,kCAAkC;IAClC,aAAa,EAAE,cAAc,CAAA;IAC7B,iCAAiC;IACjC,UAAU,EAAE,cAAc,CAAA;IAC1B,wDAAwD;IACxD,WAAW,EAAE,cAAc,CAAA;IAC3B,kCAAkC;IAClC,KAAK,EAAE,cAAc,CAAA;IACrB,uBAAuB;IACvB,OAAO,EAAE,cAAc,CAAA;CACxB;AAED,gEAAgE;AAChE,MAAM,WAAW,sBAAuB,SAAQ,WAAW;IACzD,KAAK,EAAE;QACL,oEAAoE;QACpE,kBAAkB,EAAE,aAAa,CAAC,uBAAuB,CAAC,CAAA;KAC3D,CAAA;CACF;AAED,oEAAoE;AACpE,qBAAa,4BAA4B;IACvC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA0B;IAC/C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAwC;IAE9D,2EAA2E;gBAC/D,KAAK,EAAE,UAAU,CAAC,cAAc,CAAC;IAkB7C,OAAO,CAAC,UAAU;IAkBlB;;;OAGG;IACH,MAAM,IAAI,sBAAsB;IAIhC;;;OAGG;IACH,OAAO,IAAI,IAAI;CAGhB;AAED,4DAA4D;AAC5D,MAAM,MAAM,uBAAuB,GACjC,YAAY,CAAC,oBAAoB,CAAC,GAChC,WAAW,CAAC,QAAQ,CAAC,GACrB,UAAU,CAAC,sBAAsB,CAAC,CAAA;AAEtC;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,+BAyJhE"}
|
|
@@ -6,6 +6,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
6
6
|
*/
|
|
7
7
|
import { useEffect, useState } from 'react';
|
|
8
8
|
import { PluginSettingsCard, ValueField, BooleanField } from "./PluginSettingsCard.js";
|
|
9
|
+
import { PhoneIcon } from "./PhoneIcon.js";
|
|
9
10
|
import { CardForm, booleanField, numberField, secretField, textField } from "./settings-form.js";
|
|
10
11
|
import { LanBindStatusError, readLanBindStatus, shouldStopLanBindPoll } from "./pair-api.js";
|
|
11
12
|
/** Bridges the `remote-web-ui` form onto the card's staged form. */
|
|
@@ -77,7 +78,7 @@ export function RemoteSettingsCard(props) {
|
|
|
77
78
|
invalidLabel: t('settings.invalidNumber'),
|
|
78
79
|
disabled,
|
|
79
80
|
};
|
|
80
|
-
return (_jsxs(PluginSettingsCard, { t: t, titleKey: "settings.title", descriptionKey: "settings.description", defaultOpen: false, state: state, onSave: props.save, onDiscard: props.discard, children: [_jsx(BooleanField, { id: "settings-remote-enabled", label: t('settings.enabled'), hint: t('settings.enabledHint'), inheritLabel: t('settings.inherit'), onLabel: t('settings.on'), offLabel: t('settings.off'), ...fieldProps, ...state.enabled, onEdit: (text) => { props.edit('enabled', text); }, onReset: () => { props.resetField('enabled'); } }), _jsx(ValueField, { id: "settings-remote-token-ttl", label: t('settings.tokenTtlMs'), hint: t('settings.tokenTtlMsHint'), numeric: true, ...fieldProps, ...state.tokenTtlMs, onEdit: (text) => { props.edit('tokenTtlMs', text); }, onReset: () => { props.resetField('tokenTtlMs'); } }), _jsx(ValueField, { id: "settings-remote-offline", label: t('settings.offlineAfterMs'), hint: t('settings.offlineAfterMsHint'), numeric: true, ...fieldProps, ...state.offlineAfterMs, onEdit: (text) => { props.edit('offlineAfterMs', text); }, onReset: () => { props.resetField('offlineAfterMs'); } }), _jsx(ValueField, { id: "settings-remote-max-devices", label: t('settings.maxDevices'), hint: t('settings.maxDevicesHint'), numeric: true, ...fieldProps, ...state.maxDevices, onEdit: (text) => { props.edit('maxDevices', text); }, onReset: () => { props.resetField('maxDevices'); } }), _jsx(ValueField, { id: "settings-remote-idle-expire", label: t('settings.idleExpireMs'), hint: t('settings.idleExpireMsHint'), numeric: true, ...fieldProps, ...state.idleExpireMs, onEdit: (text) => { props.edit('idleExpireMs', text); }, onReset: () => { props.resetField('idleExpireMs'); } }), _jsx(ValueField, { id: "settings-remote-cookie", label: t('settings.cookieName'), hint: t('settings.cookieNameHint'), ...fieldProps, ...state.cookieName, onEdit: (text) => { props.edit('cookieName', text); }, onReset: () => { props.resetField('cookieName'); } }), _jsx(BooleanField, { id: "settings-remote-fence", label: t('settings.requirePairingForLan'), hint: t('settings.requirePairingForLanHint'), inheritLabel: t('settings.inherit'), onLabel: t('settings.on'), offLabel: t('settings.off'), ...fieldProps, ...state.requirePairingForLan, onEdit: (text) => { props.edit('requirePairingForLan', text); }, onReset: () => { props.resetField('requirePairingForLan'); } }), _jsx(ValueField, { id: "settings-remote-public-base", label: t('settings.publicBaseUrl'), hint: t('settings.publicBaseUrlHint'), placeholder: "https://example.trycloudflare.com", ...fieldProps, ...state.publicBaseUrl, onEdit: (text) => { props.edit('publicBaseUrl', text); }, onReset: () => { props.resetField('publicBaseUrl'); } }), _jsx(BooleanField, { id: "settings-remote-auto-tunnel", label: t('settings.autoTunnel'), hint: t('settings.autoTunnelHint'), inheritLabel: t('settings.inherit'), onLabel: t('settings.on'), offLabel: t('settings.off'), ...fieldProps, ...state.autoTunnel, onEdit: (text) => { props.edit('autoTunnel', text); }, onReset: () => { props.resetField('autoTunnel'); } }), _jsx(ValueField, { id: "settings-remote-tunnel-token", label: t('settings.tunnelToken'), hint: t('settings.tunnelTokenHint'), placeholder: "eyJ...", ...fieldProps, ...state.tunnelToken, onEdit: (text) => { props.edit('tunnelToken', text); }, onReset: () => { props.resetField('tunnelToken'); } }), _jsx(BooleanField, { id: "settings-remote-relay", label: t('settings.relay'), hint: t('settings.relayHint'), inheritLabel: t('settings.inherit'), onLabel: t('settings.on'), offLabel: t('settings.off'), ...fieldProps, ...state.relay, onEdit: (text) => { props.edit('relay', text); }, onReset: () => { props.resetField('relay'); } }), _jsx(LanBindStatus, { t: t }), _jsx(BooleanField, { id: "settings-remote-lan-bind", label: t('settings.lanBind'), hint: t('settings.lanBindHint'), inheritLabel: t('settings.inherit'), onLabel: t('settings.on'), offLabel: t('settings.off'), ...fieldProps, ...state.lanBind, onEdit: (text) => { props.edit('lanBind', text); }, onReset: () => { props.resetField('lanBind'); } })] }));
|
|
81
|
+
return (_jsxs(PluginSettingsCard, { t: t, titleKey: "settings.title", descriptionKey: "settings.description", icon: _jsx(PhoneIcon, { size: 18 }), defaultOpen: false, state: state, onSave: props.save, onDiscard: props.discard, children: [_jsx(BooleanField, { id: "settings-remote-enabled", label: t('settings.enabled'), hint: t('settings.enabledHint'), inheritLabel: t('settings.inherit'), onLabel: t('settings.on'), offLabel: t('settings.off'), ...fieldProps, ...state.enabled, onEdit: (text) => { props.edit('enabled', text); }, onReset: () => { props.resetField('enabled'); } }), _jsx(ValueField, { id: "settings-remote-token-ttl", label: t('settings.tokenTtlMs'), hint: t('settings.tokenTtlMsHint'), numeric: true, ...fieldProps, ...state.tokenTtlMs, onEdit: (text) => { props.edit('tokenTtlMs', text); }, onReset: () => { props.resetField('tokenTtlMs'); } }), _jsx(ValueField, { id: "settings-remote-offline", label: t('settings.offlineAfterMs'), hint: t('settings.offlineAfterMsHint'), numeric: true, ...fieldProps, ...state.offlineAfterMs, onEdit: (text) => { props.edit('offlineAfterMs', text); }, onReset: () => { props.resetField('offlineAfterMs'); } }), _jsx(ValueField, { id: "settings-remote-max-devices", label: t('settings.maxDevices'), hint: t('settings.maxDevicesHint'), numeric: true, ...fieldProps, ...state.maxDevices, onEdit: (text) => { props.edit('maxDevices', text); }, onReset: () => { props.resetField('maxDevices'); } }), _jsx(ValueField, { id: "settings-remote-idle-expire", label: t('settings.idleExpireMs'), hint: t('settings.idleExpireMsHint'), numeric: true, ...fieldProps, ...state.idleExpireMs, onEdit: (text) => { props.edit('idleExpireMs', text); }, onReset: () => { props.resetField('idleExpireMs'); } }), _jsx(ValueField, { id: "settings-remote-cookie", label: t('settings.cookieName'), hint: t('settings.cookieNameHint'), ...fieldProps, ...state.cookieName, onEdit: (text) => { props.edit('cookieName', text); }, onReset: () => { props.resetField('cookieName'); } }), _jsx(BooleanField, { id: "settings-remote-fence", label: t('settings.requirePairingForLan'), hint: t('settings.requirePairingForLanHint'), inheritLabel: t('settings.inherit'), onLabel: t('settings.on'), offLabel: t('settings.off'), ...fieldProps, ...state.requirePairingForLan, onEdit: (text) => { props.edit('requirePairingForLan', text); }, onReset: () => { props.resetField('requirePairingForLan'); } }), _jsx(ValueField, { id: "settings-remote-public-base", label: t('settings.publicBaseUrl'), hint: t('settings.publicBaseUrlHint'), placeholder: "https://example.trycloudflare.com", ...fieldProps, ...state.publicBaseUrl, onEdit: (text) => { props.edit('publicBaseUrl', text); }, onReset: () => { props.resetField('publicBaseUrl'); } }), _jsx(BooleanField, { id: "settings-remote-auto-tunnel", label: t('settings.autoTunnel'), hint: t('settings.autoTunnelHint'), inheritLabel: t('settings.inherit'), onLabel: t('settings.on'), offLabel: t('settings.off'), ...fieldProps, ...state.autoTunnel, onEdit: (text) => { props.edit('autoTunnel', text); }, onReset: () => { props.resetField('autoTunnel'); } }), _jsx(ValueField, { id: "settings-remote-tunnel-token", label: t('settings.tunnelToken'), hint: t('settings.tunnelTokenHint'), placeholder: "eyJ...", ...fieldProps, ...state.tunnelToken, onEdit: (text) => { props.edit('tunnelToken', text); }, onReset: () => { props.resetField('tunnelToken'); } }), _jsx(BooleanField, { id: "settings-remote-relay", label: t('settings.relay'), hint: t('settings.relayHint'), inheritLabel: t('settings.inherit'), onLabel: t('settings.on'), offLabel: t('settings.off'), ...fieldProps, ...state.relay, onEdit: (text) => { props.edit('relay', text); }, onReset: () => { props.resetField('relay'); } }), _jsx(LanBindStatus, { t: t }), _jsx(BooleanField, { id: "settings-remote-lan-bind", label: t('settings.lanBind'), hint: t('settings.lanBindHint'), inheritLabel: t('settings.inherit'), onLabel: t('settings.on'), offLabel: t('settings.off'), ...fieldProps, ...state.lanBind, onEdit: (text) => { props.edit('lanBind', text); }, onReset: () => { props.resetField('lanBind'); } })] }));
|
|
81
82
|
}
|
|
82
83
|
/**
|
|
83
84
|
* Live LAN-bind facts above the toggle: the managed block's host, the live
|
|
@@ -151,9 +151,9 @@ export function apply(ctx) {
|
|
|
151
151
|
}
|
|
152
152
|
const t = ctx.locale.bind(NS);
|
|
153
153
|
// Hand the `remote` translate seat to the module-scope adaptation layer:
|
|
154
|
-
// the whale
|
|
155
|
-
//
|
|
156
|
-
//
|
|
154
|
+
// the whale label was rendered with the English fallback before any
|
|
155
|
+
// dictionary existed; the wiring plus the layer's own sync tick re-renders
|
|
156
|
+
// it in the active locale.
|
|
157
157
|
if (adapt !== undefined)
|
|
158
158
|
adapt.translate = t;
|
|
159
159
|
// The settings form this card edits. The family group's binder resolves a
|
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
export declare const zh: {
|
|
4
4
|
'entry.label': string;
|
|
5
5
|
'mobile.whale.open': string;
|
|
6
|
-
'mobile.composer.pickModel': string;
|
|
7
|
-
'mobile.composer.pickEffort': string;
|
|
8
6
|
title: string;
|
|
9
7
|
subtitle: string;
|
|
10
8
|
'card.title': string;
|
|
@@ -129,8 +127,6 @@ export type SettingsCardKey = RemoteKey;
|
|
|
129
127
|
export declare const en: {
|
|
130
128
|
'entry.label': string;
|
|
131
129
|
'mobile.whale.open': string;
|
|
132
|
-
'mobile.composer.pickModel': string;
|
|
133
|
-
'mobile.composer.pickEffort': string;
|
|
134
130
|
title: string;
|
|
135
131
|
subtitle: string;
|
|
136
132
|
'card.title': string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA,uEAAuE;AAEvE,mEAAmE;AACnE,eAAO,MAAM,EAAE
|
|
1
|
+
{"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA,uEAAuE;AAEvE,mEAAmE;AACnE,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwHmB,CAAA;AAElC,sCAAsC;AACtC,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,EAAE,CAAA;AAEvC,wDAAwD;AACxD,MAAM,MAAM,eAAe,GAAG,SAAS,CAAA;AAEvC,mEAAmE;AACnE,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwHsB,CAAA"}
|
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
export const zh = {
|
|
4
4
|
'entry.label': '远程访问',
|
|
5
5
|
'mobile.whale.open': '打开侧边栏',
|
|
6
|
-
'mobile.composer.pickModel': '选择模型',
|
|
7
|
-
'mobile.composer.pickEffort': '选择推理等级',
|
|
8
6
|
'title': '远程访问',
|
|
9
7
|
'subtitle': '通过手机或另一台电脑配对,远程使用同一份 Web 界面(官方界面 + 移动端适配)',
|
|
10
8
|
'card.title': '设备配对',
|
|
@@ -14,7 +12,7 @@ export const zh = {
|
|
|
14
12
|
'status.disconnected': '已配对设备离线',
|
|
15
13
|
'status.stopped': '已停止远程访问',
|
|
16
14
|
'status.lanRequired': '此功能需要局域网绑定或公网地址才能使用',
|
|
17
|
-
'status.lanRequiredHint': '当前服务仅绑定在 127.0.0.1 且未配置公网地址,手机无法访问。请在本插件的设置卡片中打开“局域网访问”(装在全家桶里时在「设置 → Web 插件 →
|
|
15
|
+
'status.lanRequiredHint': '当前服务仅绑定在 127.0.0.1 且未配置公网地址,手机无法访问。请在本插件的设置卡片中打开“局域网访问”(装在全家桶里时在「设置 → Web 插件 → 远程访问」,单独安装时在设置 → 插件 → 本插件行),或用 dsh web --host 0.0.0.0 重新启动,或填写内网穿透的公网地址。',
|
|
18
16
|
'status.loopbackRequired': '配对面板仅限本机使用',
|
|
19
17
|
'status.loopbackRequiredHint': '请通过 http://127.0.0.1 打开此页面后重试;手机请使用配对链接访问。',
|
|
20
18
|
'status.unreachable': '无法连接配对服务',
|
|
@@ -71,8 +69,8 @@ export const zh = {
|
|
|
71
69
|
'relay.failed': '固定域名同步失败:{error}。正在自动重试,期间二维码可能使用临时地址。',
|
|
72
70
|
'close.label': '关闭远程访问面板',
|
|
73
71
|
// 插件设置卡片(家族 list 席位,或官方 plugins.bundle.config 席位)。
|
|
74
|
-
'settings.title': '
|
|
75
|
-
'settings.description': '
|
|
72
|
+
'settings.title': '远程访问',
|
|
73
|
+
'settings.description': '手机配对、公网隧道与设备限额。',
|
|
76
74
|
'settings.enabled': '启用远程访问',
|
|
77
75
|
'settings.enabledHint': '关闭后移除侧边栏入口并停用配对路由与局域网栅栏。',
|
|
78
76
|
'settings.tokenTtlMs': '配对令牌有效期(毫秒)',
|
|
@@ -127,8 +125,6 @@ export const zh = {
|
|
|
127
125
|
export const en = {
|
|
128
126
|
'entry.label': 'Remote access',
|
|
129
127
|
'mobile.whale.open': 'Open sidebar',
|
|
130
|
-
'mobile.composer.pickModel': 'Pick model',
|
|
131
|
-
'mobile.composer.pickEffort': 'Pick reasoning effort',
|
|
132
128
|
'title': 'Remote access',
|
|
133
129
|
'subtitle': 'Pair a phone or another computer to share the same Web GUI (official UI + mobile adaptation)',
|
|
134
130
|
'card.title': 'Pair a device',
|
|
@@ -195,8 +191,8 @@ export const en = {
|
|
|
195
191
|
'relay.failed': 'Stable-hostname sync failed: {error}. Retrying automatically; the QR may use the ephemeral address meanwhile.',
|
|
196
192
|
'close.label': 'Close remote access panel',
|
|
197
193
|
// Plugin settings card (the family list seat, or the official bundle-config seat).
|
|
198
|
-
'settings.title': 'Remote access
|
|
199
|
-
'settings.description': '
|
|
194
|
+
'settings.title': 'Remote access',
|
|
195
|
+
'settings.description': 'Phone pairing, public tunnel and device limits.',
|
|
200
196
|
'settings.enabled': 'Enable remote access',
|
|
201
197
|
'settings.enabledHint': 'When off, the sidebar entry is removed and pairing routes plus the LAN fence stop.',
|
|
202
198
|
'settings.tokenTtlMs': 'Pairing token lifetime (ms)',
|
|
@@ -30,8 +30,8 @@ export interface RemoteAdaptGlobal {
|
|
|
30
30
|
closeDetails: (() => void) | null;
|
|
31
31
|
/**
|
|
32
32
|
* Wired by the plugin apply once the `remote` locale namespace is bound:
|
|
33
|
-
* the translate seat the injected
|
|
34
|
-
*
|
|
33
|
+
* the translate seat the injected surface (the whale) reads its label
|
|
34
|
+
* from. Null until then; label reads fall back to English
|
|
35
35
|
* (the SDK's universal fallback) and the 600ms sync tick re-renders the
|
|
36
36
|
* labels once the seat is wired.
|
|
37
37
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mobile-adapt.d.ts","sourceRoot":"","sources":["../../../src/client/mobile-adapt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAE7C,0EAA0E;AAC1E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,yDAAyD;IACzD,aAAa,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAA;IAClC,yDAAyD;IACzD,YAAY,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAA;IACjC;;;;;;OAMG;IACH,SAAS,EAAE,CAAC,CAAC,GAAG,EAAE,SAAS,KAAK,MAAM,CAAC,GAAG,IAAI,CAAA;IAC9C,wEAAwE;IACxE,UAAU,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAAA;IAC7B,4GAA4G;IAC5G,iBAAiB,IAAI,IAAI,CAAA;CAC1B;
|
|
1
|
+
{"version":3,"file":"mobile-adapt.d.ts","sourceRoot":"","sources":["../../../src/client/mobile-adapt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAE7C,0EAA0E;AAC1E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,yDAAyD;IACzD,aAAa,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAA;IAClC,yDAAyD;IACzD,YAAY,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAA;IACjC;;;;;;OAMG;IACH,SAAS,EAAE,CAAC,CAAC,GAAG,EAAE,SAAS,KAAK,MAAM,CAAC,GAAG,IAAI,CAAA;IAC9C,wEAAwE;IACxE,UAAU,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAAA;IAC7B,4GAA4G;IAC5G,iBAAiB,IAAI,IAAI,CAAA;CAC1B;AA+RD;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAi8BvC"}
|