dsh-mobile 0.8.2 → 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 +13 -0
- package/CONTRIBUTORS.md +9 -3
- package/README.en.md +4 -3
- package/README.md +4 -3
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/docs/ATTACH_EXISTING_FRPS.en.md +2 -0
- package/docs/ATTACH_EXISTING_FRPS.md +2 -0
- package/docs/CONNECTION_DIAGNOSTICS.en.md +7 -1
- package/docs/CONNECTION_DIAGNOSTICS.md +7 -1
- package/docs/IROH.en.md +1 -1
- package/docs/IROH.md +1 -1
- package/docs/MOBILE_PLUGIN_ADAPTATION.en.md +1 -1
- package/docs/MOBILE_PLUGIN_ADAPTATION.md +1 -1
- package/docs/SLOW_CONNECTIONS.en.md +3 -1
- package/docs/SLOW_CONNECTIONS.md +3 -1
- package/lib/client.js +515 -134
- package/lib/client.js.map +1 -1
- package/lib/index.d.mts +8 -0
- package/lib/index.mjs +54 -31
- package/lib/index.mjs.map +1 -1
- package/lib/mobile-layout.js +114 -29
- package/lib/mobile-layout.js.map +1 -1
- package/package.json +2 -2
- package/packages/question-fixes/package.json +1 -1
package/lib/index.d.mts
CHANGED
|
@@ -1554,6 +1554,12 @@ interface FrpSettings {
|
|
|
1554
1554
|
readonly vhostHttpPort?: number;
|
|
1555
1555
|
/** Public entry port of the self-signed TCP proxy; defaults to 33080. */
|
|
1556
1556
|
readonly publicPort?: number;
|
|
1557
|
+
/**
|
|
1558
|
+
* Optional frpc `user` field for shared frps services that namespace proxies
|
|
1559
|
+
* per user. When set, frps registers the proxy as `<user>.<proxyName>`;
|
|
1560
|
+
* the locally derived proxy name is unchanged. Absent keeps upstream behaviour.
|
|
1561
|
+
*/
|
|
1562
|
+
readonly user?: string;
|
|
1557
1563
|
}
|
|
1558
1564
|
/** Safe FRP configuration fields returned to the desktop UI. */
|
|
1559
1565
|
interface FrpConfigurationStatus {
|
|
@@ -1572,6 +1578,8 @@ interface FrpConfigurationStatus {
|
|
|
1572
1578
|
readonly entryTls?: FrpEntryTls;
|
|
1573
1579
|
/** Present only when a non-default public entry port is saved. */
|
|
1574
1580
|
readonly publicPort?: number;
|
|
1581
|
+
/** Present only when the optional frpc `user` field is saved. */
|
|
1582
|
+
readonly user?: string;
|
|
1575
1583
|
}
|
|
1576
1584
|
/** Validate the FRP server hostname or IP address. */
|
|
1577
1585
|
export declare function validateFrpServerAddress(value: unknown): string;
|
package/lib/index.mjs
CHANGED
|
@@ -10954,7 +10954,8 @@ const FRP_SETTINGS_KEYS = /* @__PURE__ */ new Set([
|
|
|
10954
10954
|
"mode",
|
|
10955
10955
|
"entryTls",
|
|
10956
10956
|
"vhostHttpPort",
|
|
10957
|
-
"publicPort"
|
|
10957
|
+
"publicPort",
|
|
10958
|
+
"user"
|
|
10958
10959
|
]);
|
|
10959
10960
|
function hostname$2(value) {
|
|
10960
10961
|
if (value.length > 253 || !value.includes(".")) return false;
|
|
@@ -10977,6 +10978,11 @@ function validateFrpToken(value) {
|
|
|
10977
10978
|
if (typeof value !== "string" || value.length < 16 || value.length > 512 || /[\s\u0000-\u001f\u007f]/u.test(value)) throw new Error("frp_token_invalid");
|
|
10978
10979
|
return value;
|
|
10979
10980
|
}
|
|
10981
|
+
/** Validate the optional frpc `user` field; it must stay one safe TOML token. */
|
|
10982
|
+
function validateFrpUser(value) {
|
|
10983
|
+
if (typeof value !== "string" || value.length < 1 || value.length > 128 || !/^[A-Za-z0-9._-]+$/u.test(value)) throw new Error("frp_user_invalid");
|
|
10984
|
+
return value;
|
|
10985
|
+
}
|
|
10980
10986
|
/** Validate the public HTTPS origin used by Caddy and Android pairing. */
|
|
10981
10987
|
function validateFrpPublicOrigin(value) {
|
|
10982
10988
|
if (typeof value !== "string" || value.length > 512) throw new Error("frp_public_origin_invalid");
|
|
@@ -11067,6 +11073,7 @@ function parseFrpSettings(value) {
|
|
|
11067
11073
|
const entryTls = record.entryTls === void 0 ? void 0 : validateFrpEntryTls(record.entryTls);
|
|
11068
11074
|
const vhostHttpPort = record.vhostHttpPort === void 0 ? void 0 : validateFrpVhostHttpPort(record.vhostHttpPort);
|
|
11069
11075
|
const publicPort = record.publicPort === void 0 ? void 0 : validateFrpPublicPort(record.publicPort);
|
|
11076
|
+
const user = record.user === void 0 || record.user === "" ? void 0 : validateFrpUser(record.user);
|
|
11070
11077
|
const resolvedMode = mode ?? "deploy";
|
|
11071
11078
|
const resolvedEntryTls = entryTls ?? "public-ip-cert";
|
|
11072
11079
|
if (resolvedEntryTls === "self-signed" && resolvedMode !== "attach") throw new Error("frp_entry_tls_invalid");
|
|
@@ -11082,7 +11089,8 @@ function parseFrpSettings(value) {
|
|
|
11082
11089
|
...mode === void 0 ? {} : { mode },
|
|
11083
11090
|
...entryTls === void 0 ? {} : { entryTls },
|
|
11084
11091
|
...vhostHttpPort === void 0 ? {} : { vhostHttpPort },
|
|
11085
|
-
...publicPort === void 0 ? {} : { publicPort }
|
|
11092
|
+
...publicPort === void 0 ? {} : { publicPort },
|
|
11093
|
+
...user === void 0 ? {} : { user }
|
|
11086
11094
|
});
|
|
11087
11095
|
}
|
|
11088
11096
|
/**
|
|
@@ -11101,6 +11109,7 @@ function mergeSavedFrpSettings(partial, saved) {
|
|
|
11101
11109
|
const entryTls = pick("entryTls");
|
|
11102
11110
|
const vhostHttpPort = pick("vhostHttpPort");
|
|
11103
11111
|
const publicPort = pick("publicPort");
|
|
11112
|
+
const user = partial.user === void 0 ? saved?.user : partial.user;
|
|
11104
11113
|
const merged = {
|
|
11105
11114
|
serverAddress: partial.serverAddress === "" || partial.serverAddress === void 0 ? saved?.serverAddress : partial.serverAddress,
|
|
11106
11115
|
serverPort: typeof partial.serverPort === "number" && Number.isSafeInteger(partial.serverPort) && partial.serverPort >= 1 ? partial.serverPort : saved?.serverPort,
|
|
@@ -11109,7 +11118,8 @@ function mergeSavedFrpSettings(partial, saved) {
|
|
|
11109
11118
|
...mode === "" || mode === void 0 ? {} : { mode },
|
|
11110
11119
|
...entryTls === "" || entryTls === void 0 ? {} : { entryTls },
|
|
11111
11120
|
...vhostHttpPort === "" || vhostHttpPort === void 0 ? {} : { vhostHttpPort },
|
|
11112
|
-
...publicPort === "" || publicPort === void 0 ? {} : { publicPort }
|
|
11121
|
+
...publicPort === "" || publicPort === void 0 ? {} : { publicPort },
|
|
11122
|
+
...user === "" || user === void 0 ? {} : { user }
|
|
11113
11123
|
};
|
|
11114
11124
|
if (merged.serverAddress === void 0 && merged.serverPort === void 0 && merged.token === void 0 && merged.publicOrigin === void 0) throw new Error("frp_config_missing");
|
|
11115
11125
|
return parseFrpSettings(merged);
|
|
@@ -11179,6 +11189,7 @@ function createFrpcToml(settings, localPort, proxyName = FRP_DEFAULT_PROXY_NAME)
|
|
|
11179
11189
|
`serverPort = ${String(settings.serverPort)}`,
|
|
11180
11190
|
"auth.method = \"token\"",
|
|
11181
11191
|
`auth.token = ${tomlString(settings.token)}`,
|
|
11192
|
+
...settings.user === void 0 ? [] : [`user = ${tomlString(settings.user)}`],
|
|
11182
11193
|
"transport.tls.enable = true",
|
|
11183
11194
|
"",
|
|
11184
11195
|
"[[proxies]]",
|
|
@@ -11291,7 +11302,8 @@ var FrpConfigStore = class {
|
|
|
11291
11302
|
...this.errorCode === void 0 ? {} : { errorCode: this.errorCode },
|
|
11292
11303
|
...mode === void 0 || mode === "deploy" ? {} : { mode },
|
|
11293
11304
|
...entryTls === void 0 || entryTls === "public-ip-cert" ? {} : { entryTls },
|
|
11294
|
-
...settings?.publicPort === void 0 ? {} : { publicPort: settings.publicPort }
|
|
11305
|
+
...settings?.publicPort === void 0 ? {} : { publicPort: settings.publicPort },
|
|
11306
|
+
...settings?.user === void 0 ? {} : { user: settings.user }
|
|
11295
11307
|
});
|
|
11296
11308
|
}
|
|
11297
11309
|
/** Return private settings only to the provider lifecycle. */
|
|
@@ -13652,7 +13664,7 @@ var OriginController = class {
|
|
|
13652
13664
|
const MAX_ARCHIVE_LIST_BYTES = 1048576;
|
|
13653
13665
|
const MAX_ARCHIVE_ENTRIES = 256;
|
|
13654
13666
|
const DOWNLOAD_TIMEOUT_MS = 3e5;
|
|
13655
|
-
const CLOUDFLARED_VERSION = "2026.
|
|
13667
|
+
const CLOUDFLARED_VERSION = "2026.10.7";
|
|
13656
13668
|
/** Pinned official cloudflared release metadata for supported desktop targets. */
|
|
13657
13669
|
const CLOUDFLARED_COMPONENT_RELEASES = Object.freeze(Object.fromEntries([
|
|
13658
13670
|
{
|
|
@@ -13660,44 +13672,44 @@ const CLOUDFLARED_COMPONENT_RELEASES = Object.freeze(Object.fromEntries([
|
|
|
13660
13672
|
platform: "win32",
|
|
13661
13673
|
arch: "x64",
|
|
13662
13674
|
downloadUrl: `https://github.com/cloudflare/cloudflared/releases/download/${CLOUDFLARED_VERSION}/cloudflared-windows-amd64.exe`,
|
|
13663
|
-
downloadBytes:
|
|
13664
|
-
downloadSha256: "
|
|
13675
|
+
downloadBytes: 55390512,
|
|
13676
|
+
downloadSha256: "2493dbc168923bb3e59e5e7716f71deced92992eea9acd6e9d74f84ac7751343",
|
|
13665
13677
|
executableName: "cloudflared.exe",
|
|
13666
|
-
executableBytes:
|
|
13667
|
-
executableSha256: "
|
|
13678
|
+
executableBytes: 55390512,
|
|
13679
|
+
executableSha256: "2493dbc168923bb3e59e5e7716f71deced92992eea9acd6e9d74f84ac7751343"
|
|
13668
13680
|
},
|
|
13669
13681
|
{
|
|
13670
13682
|
version: CLOUDFLARED_VERSION,
|
|
13671
13683
|
platform: "linux",
|
|
13672
13684
|
arch: "x64",
|
|
13673
13685
|
downloadUrl: `https://github.com/cloudflare/cloudflared/releases/download/${CLOUDFLARED_VERSION}/cloudflared-linux-amd64`,
|
|
13674
|
-
downloadBytes:
|
|
13675
|
-
downloadSha256: "
|
|
13686
|
+
downloadBytes: 40274445,
|
|
13687
|
+
downloadSha256: "1f99fb518b83dec2ba8d870a7cc991d82a77e6196295a3d2754ba17ab9f91872",
|
|
13676
13688
|
executableName: "cloudflared",
|
|
13677
|
-
executableBytes:
|
|
13678
|
-
executableSha256: "
|
|
13689
|
+
executableBytes: 40274445,
|
|
13690
|
+
executableSha256: "1f99fb518b83dec2ba8d870a7cc991d82a77e6196295a3d2754ba17ab9f91872"
|
|
13679
13691
|
},
|
|
13680
13692
|
{
|
|
13681
13693
|
version: CLOUDFLARED_VERSION,
|
|
13682
13694
|
platform: "linux",
|
|
13683
13695
|
arch: "arm64",
|
|
13684
13696
|
downloadUrl: `https://github.com/cloudflare/cloudflared/releases/download/${CLOUDFLARED_VERSION}/cloudflared-linux-arm64`,
|
|
13685
|
-
downloadBytes:
|
|
13686
|
-
downloadSha256: "
|
|
13697
|
+
downloadBytes: 37667293,
|
|
13698
|
+
downloadSha256: "3df43aedc9ff291d1735b5cb576cb97e0b157488796db2e32b28aecabb445775",
|
|
13687
13699
|
executableName: "cloudflared",
|
|
13688
|
-
executableBytes:
|
|
13689
|
-
executableSha256: "
|
|
13700
|
+
executableBytes: 37667293,
|
|
13701
|
+
executableSha256: "3df43aedc9ff291d1735b5cb576cb97e0b157488796db2e32b28aecabb445775"
|
|
13690
13702
|
},
|
|
13691
13703
|
{
|
|
13692
13704
|
version: CLOUDFLARED_VERSION,
|
|
13693
13705
|
platform: "darwin",
|
|
13694
13706
|
arch: "x64",
|
|
13695
13707
|
downloadUrl: `https://github.com/cloudflare/cloudflared/releases/download/${CLOUDFLARED_VERSION}/cloudflared-darwin-amd64.tgz`,
|
|
13696
|
-
downloadBytes:
|
|
13697
|
-
downloadSha256: "
|
|
13708
|
+
downloadBytes: 21834416,
|
|
13709
|
+
downloadSha256: "02f3edfd87684dd5b705607688e4eb4b323f6e777b81e7b3a85af556aa356848",
|
|
13698
13710
|
executableName: "cloudflared",
|
|
13699
|
-
executableBytes:
|
|
13700
|
-
executableSha256: "
|
|
13711
|
+
executableBytes: 42430512,
|
|
13712
|
+
executableSha256: "5c55e77da7012cebca19170357e196176c48c9647cc2ead404702fa125ddbd86",
|
|
13701
13713
|
archive: {
|
|
13702
13714
|
format: "tgz",
|
|
13703
13715
|
member: "cloudflared"
|
|
@@ -13708,11 +13720,11 @@ const CLOUDFLARED_COMPONENT_RELEASES = Object.freeze(Object.fromEntries([
|
|
|
13708
13720
|
platform: "darwin",
|
|
13709
13721
|
arch: "arm64",
|
|
13710
13722
|
downloadUrl: `https://github.com/cloudflare/cloudflared/releases/download/${CLOUDFLARED_VERSION}/cloudflared-darwin-arm64.tgz`,
|
|
13711
|
-
downloadBytes:
|
|
13712
|
-
downloadSha256: "
|
|
13723
|
+
downloadBytes: 19847161,
|
|
13724
|
+
downloadSha256: "3586ccf397e98e5f437e60e7c307ca6ac463e110580503af8bb8e6f9ebf831bd",
|
|
13713
13725
|
executableName: "cloudflared",
|
|
13714
|
-
executableBytes:
|
|
13715
|
-
executableSha256: "
|
|
13726
|
+
executableBytes: 39487168,
|
|
13727
|
+
executableSha256: "2136431d5eb467bf447d2ee514b713e192719b143aec1d9e09bf7dc290d5bb12",
|
|
13716
13728
|
archive: {
|
|
13717
13729
|
format: "tgz",
|
|
13718
13730
|
member: "cloudflared"
|
|
@@ -15378,6 +15390,14 @@ function validatePairingDescriptor(value, options = {}) {
|
|
|
15378
15390
|
function encodePairingDescriptor(value, options = {}) {
|
|
15379
15391
|
return JSON.stringify(validatePairingDescriptor(value, options));
|
|
15380
15392
|
}
|
|
15393
|
+
/** Draw the canonical pairing payload with its four-module quiet zone inside the SVG. */
|
|
15394
|
+
function renderIrohPairingQr(encoded) {
|
|
15395
|
+
return QRCode.toString(encoded, {
|
|
15396
|
+
type: "svg",
|
|
15397
|
+
margin: 4,
|
|
15398
|
+
errorCorrectionLevel: "M"
|
|
15399
|
+
});
|
|
15400
|
+
}
|
|
15381
15401
|
/** Decode untrusted QR text, validating its expiry and public CA before use. */
|
|
15382
15402
|
function decodePairingDescriptor(encoded, options = {}) {
|
|
15383
15403
|
if (typeof encoded !== "string" || Buffer.byteLength(encoded, "utf8") > 2200) reject("pairing_descriptor_too_large");
|
|
@@ -24368,7 +24388,8 @@ async function apply(ctx, config) {
|
|
|
24368
24388
|
}, cpolarComponent.status(), cloudflaredComponent.status(), cloudflaredTunnel.status(), frpComponent.status(), frpConfig.status(), originConfig.status(), caddyComponent.status(), irohComponent.status()),
|
|
24369
24389
|
originMode: originController.mode(),
|
|
24370
24390
|
caddyConfiguration: caddyConfig.status(),
|
|
24371
|
-
caddyState: caddyController.status()
|
|
24391
|
+
caddyState: caddyController.status(),
|
|
24392
|
+
...process.platform === "darwin" ? { macosHost: true } : {}
|
|
24372
24393
|
});
|
|
24373
24394
|
const lanPayload = () => ({
|
|
24374
24395
|
...loaded.kind === "unconfigured" ? {
|
|
@@ -24866,7 +24887,12 @@ async function apply(ctx, config) {
|
|
|
24866
24887
|
if (request.method === "POST" && target.decodedPathname === `/api/mobile-access/remote/frp/configure`) {
|
|
24867
24888
|
const body = await readJsonObject(request, 4096);
|
|
24868
24889
|
await remoteProviders.mutate(async () => {
|
|
24869
|
-
|
|
24890
|
+
const saved = frpConfig.settings();
|
|
24891
|
+
const reuseToken = body.token === "" && saved !== void 0 && body.serverAddress === saved.serverAddress && body.serverPort === saved.serverPort;
|
|
24892
|
+
await frpConfig.configure(reuseToken ? {
|
|
24893
|
+
...body,
|
|
24894
|
+
token: saved.token
|
|
24895
|
+
} : body);
|
|
24870
24896
|
if (remoteControllers.frp.status().enabled) await remoteControllers.frp.reconnect();
|
|
24871
24897
|
});
|
|
24872
24898
|
sendJson(response, 200, remotePayload(), false);
|
|
@@ -24913,10 +24939,7 @@ async function apply(ctx, config) {
|
|
|
24913
24939
|
});
|
|
24914
24940
|
let qrSvg = "";
|
|
24915
24941
|
try {
|
|
24916
|
-
qrSvg = await
|
|
24917
|
-
type: "svg",
|
|
24918
|
-
margin: 1
|
|
24919
|
-
});
|
|
24942
|
+
qrSvg = await renderIrohPairingQr(pairing.encoded);
|
|
24920
24943
|
} catch {}
|
|
24921
24944
|
logger.info("iroh pairing window opened");
|
|
24922
24945
|
sendJson(response, 201, {
|