dsh-mobile 0.6.8 → 0.6.9

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/lib/index.mjs CHANGED
@@ -10610,6 +10610,8 @@ var RemoteProviderCoordinator = class {
10610
10610
  store;
10611
10611
  selectedValue;
10612
10612
  queue = Promise.resolve();
10613
+ closing = false;
10614
+ closeTask;
10613
10615
  constructor(selected, controllers, store) {
10614
10616
  this.controllers = controllers;
10615
10617
  this.store = store;
@@ -10661,8 +10663,16 @@ var RemoteProviderCoordinator = class {
10661
10663
  }
10662
10664
  });
10663
10665
  }
10666
+ /** Stop admitting mutations and wait for accepted work before callers release provider resources. */
10667
+ close() {
10668
+ this.closing = true;
10669
+ this.closeTask ??= this.queue;
10670
+ return this.closeTask;
10671
+ }
10664
10672
  enqueue(operation) {
10665
- const task = this.queue.then(() => this.runAndEnforce(operation), () => this.runAndEnforce(operation));
10673
+ if (this.closing) return Promise.reject(/* @__PURE__ */ new Error("remote_provider_closed"));
10674
+ const run = () => this.closing ? Promise.reject(/* @__PURE__ */ new Error("remote_provider_closed")) : this.runAndEnforce(operation);
10675
+ const task = this.queue.then(run, run);
10666
10676
  this.queue = task.then(() => void 0, () => void 0);
10667
10677
  return task;
10668
10678
  }
@@ -13353,6 +13363,8 @@ const MOBILE_CUSTOMIZATION_GUIDE_BODY = `你在为用户定制 DSH Mobile 的手
13353
13363
 
13354
13364
  动手前先读已有的定制文件。若要调整 DSH 自带的输入框、侧栏或设置等现有界面,先确认当前 DSH 版本与手机页面模式(专用移动页面或 ?frontend=stock),只读核对运行页面的 DOM、属性和样式;本机有同版本前端源码时可参考相应组件,没有源码时可查看已安装的客户端产物,不必下载源码。优先使用扩展 API、插槽和稳定的 data-* 标记,不凭猜测依赖构建类名。只读查看不改变前述写入范围。
13355
13365
 
13366
+ 旧 CSS 可能覆盖新版内置修复。先备份并在同一会话、方向和字号下对比有无该样式,不要无症状叠加旧补丁。CSS Modules 的后缀/子串匹配必须限定到已核对的区域祖先,例如 [data-dsh-mobile-header] [class*="_titleRow"];不要裸匹配整页。display: none 会让其中的操作不可用,不得把隐藏功能描述成折叠。
13367
+
13356
13368
  2. 电脑端能力 —— 手机需要读电脑文件、执行命令或访问硬件时,创建扩展:
13357
13369
  - 目录:$DSH_HOME/mobile-access/extensions/<id>/,id 用小写字母数字和连字符(如 media-remote)
13358
13370
  - extension.json:{"schemaVersion":1,"id":"<id>","name":"显示名","version":"0.1.0","description":"说明"}
@@ -15295,10 +15307,35 @@ async function removeCaddyTree(root, target) {
15295
15307
  }
15296
15308
  //#endregion
15297
15309
  //#region src/caddy-component.ts
15298
- const CADDY_VERSION = "2.11.6";
15310
+ const CADDY_VERSION = "2.11.7";
15299
15311
  const CADDY_DNS_PLUGIN_VERSION = "v0.4.3";
15300
- const CADDY_DOWNLOAD_PAGE = "https://caddyserver.com/download";
15301
- const CADDY_COMPONENT_RELEASES = Object.freeze({});
15312
+ const CADDY_DOWNLOAD_PAGE = "https://github.com/saya-ch/dsh-mobile/releases/tag/caddy-component-2.11.7-tencentcloud-0.4.3-r1";
15313
+ const CADDY_COMPONENT_RELEASES = Object.freeze({
15314
+ "linux-x64": Object.freeze({
15315
+ version: CADDY_VERSION,
15316
+ dnsPluginVersion: CADDY_DNS_PLUGIN_VERSION,
15317
+ platform: "linux",
15318
+ arch: "x64",
15319
+ executableName: "caddy",
15320
+ downloadUrl: "https://github.com/saya-ch/dsh-mobile/releases/download/caddy-component-2.11.7-tencentcloud-0.4.3-r1/caddy-2.11.7-tencentcloud-0.4.3-linux-x64",
15321
+ downloadBytes: 81995704,
15322
+ executableBytes: 81995704,
15323
+ downloadSha256: "13652ef9ea3792ebff772a5b873ade63ed6de1c0a794bb3403a523639b8f57af",
15324
+ executableSha256: "13652ef9ea3792ebff772a5b873ade63ed6de1c0a794bb3403a523639b8f57af"
15325
+ }),
15326
+ "win32-x64": Object.freeze({
15327
+ version: CADDY_VERSION,
15328
+ dnsPluginVersion: CADDY_DNS_PLUGIN_VERSION,
15329
+ platform: "win32",
15330
+ arch: "x64",
15331
+ executableName: "caddy.exe",
15332
+ downloadUrl: "https://github.com/saya-ch/dsh-mobile/releases/download/caddy-component-2.11.7-tencentcloud-0.4.3-r1/caddy-2.11.7-tencentcloud-0.4.3-win32-x64.exe",
15333
+ downloadBytes: 82816e3,
15334
+ executableBytes: 82816e3,
15335
+ downloadSha256: "962f7937a06e1e737513d2d1d4ad75df54ba503d36fa2a458912bd38fbd0094a",
15336
+ executableSha256: "962f7937a06e1e737513d2d1d4ad75df54ba503d36fa2a458912bd38fbd0094a"
15337
+ })
15338
+ });
15302
15339
  Object.freeze({
15303
15340
  version: CADDY_VERSION,
15304
15341
  dnsPluginVersion: CADDY_DNS_PLUGIN_VERSION
@@ -15322,14 +15359,16 @@ function caddyInspectionEnvironment(environment = process.env) {
15322
15359
  ]) if (environment[name] !== void 0) result[name] = environment[name];
15323
15360
  return result;
15324
15361
  }
15325
- async function inspect(executable) {
15362
+ async function inspect(executable, assertOpen) {
15326
15363
  const options = {
15327
15364
  env: caddyInspectionEnvironment(),
15328
15365
  timeout: 15e3,
15329
15366
  maxBuffer: 262144
15330
15367
  };
15368
+ const version = (await execFileText(executable, ["version"], options)).stdout.trim();
15369
+ assertOpen();
15331
15370
  return {
15332
- version: (await execFileText(executable, ["version"], options)).stdout.trim(),
15371
+ version,
15333
15372
  modules: (await execFileText(executable, ["list-modules", "--versions"], options)).stdout
15334
15373
  };
15335
15374
  }
@@ -15348,6 +15387,10 @@ var CaddyComponentManager = class {
15348
15387
  installed = false;
15349
15388
  errorCode;
15350
15389
  queue = Promise.resolve();
15390
+ closed = false;
15391
+ closing;
15392
+ download;
15393
+ cleanupPaths = /* @__PURE__ */ new Set();
15351
15394
  constructor(options) {
15352
15395
  if (!isAbsolute(options.stateDirectory)) throw new Error("caddy state directory must be absolute");
15353
15396
  this.stateDirectory = resolve(options.stateDirectory);
@@ -15357,7 +15400,7 @@ var CaddyComponentManager = class {
15357
15400
  if (artifact !== void 0 && (artifact.platform !== platform || artifact.arch !== arch || !/^https:\/\//u.test(artifact.downloadUrl) || !/^[a-f0-9]{64}$/u.test(artifact.downloadSha256) || !/^[a-f0-9]{64}$/u.test(artifact.executableSha256) || artifact.downloadBytes < 1 || artifact.executableBytes < 1 || !/^[a-z0-9.-]+$/u.test(artifact.executableName))) throw new Error("caddy_artifact_invalid");
15358
15401
  this.artifact = artifact;
15359
15402
  this.componentRoot = join(this.stateDirectory, "components", "caddy");
15360
- this.componentStorage = join(this.componentRoot, artifact?.version ?? "2.11.6");
15403
+ this.componentStorage = join(this.componentRoot, artifact?.version ?? "2.11.7");
15361
15404
  this.executable = join(this.componentStorage, artifact?.executableName ?? (platform === "win32" ? "caddy.exe" : "caddy"));
15362
15405
  this.logRoot = join(this.stateDirectory, "caddy", "logs");
15363
15406
  this.stagingRoot = join(this.stateDirectory, "staging", "caddy");
@@ -15367,41 +15410,48 @@ var CaddyComponentManager = class {
15367
15410
  expectedBytes: artifact?.downloadBytes ?? 0,
15368
15411
  errorPrefix: "caddy"
15369
15412
  }));
15370
- this.inspectExecutable = options.inspectExecutable ?? inspect;
15413
+ this.inspectExecutable = options.inspectExecutable ?? ((executable) => inspect(executable, () => this.assertOpen()));
15371
15414
  this.promote = options.promoteDirectory ?? ((source, destination) => renameCaddyPath(this.stateDirectory, source, destination));
15372
15415
  }
15373
15416
  /** Recheck a pinned executable before launching; no unverified local binary can run. */
15374
- async ensureExecutable() {
15417
+ ensureExecutable() {
15418
+ return this.enqueue(() => this.checkExecutable());
15419
+ }
15420
+ async checkExecutable() {
15375
15421
  const artifact = this.artifact;
15376
15422
  if (artifact === void 0) throw new Error("caddy_component_unavailable");
15377
15423
  await assertCaddyParents(this.stateDirectory, this.executable);
15424
+ this.assertOpen();
15378
15425
  const entry = await lstat(this.executable);
15379
15426
  if (!entry.isFile() || entry.isSymbolicLink() || entry.size !== artifact.executableBytes || await digest(this.executable) !== artifact.executableSha256) throw new Error("caddy_component_invalid");
15380
15427
  await this.verifyMetadata(this.executable, artifact);
15381
15428
  }
15382
15429
  async initialize() {
15383
- this.installed = false;
15384
- this.errorCode = void 0;
15385
- if (this.artifact === void 0) {
15386
- this.errorCode = "caddy_component_unavailable";
15387
- return;
15388
- }
15389
- try {
15390
- await this.ensureExecutable();
15391
- this.installed = true;
15392
- } catch (error) {
15393
- if (error.code !== "ENOENT") this.errorCode = "caddy_component_invalid";
15394
- }
15430
+ return this.enqueue(async () => {
15431
+ this.installed = false;
15432
+ this.errorCode = void 0;
15433
+ if (this.artifact === void 0) {
15434
+ this.errorCode = "caddy_component_unavailable";
15435
+ return;
15436
+ }
15437
+ try {
15438
+ await this.checkExecutable();
15439
+ this.installed = true;
15440
+ } catch (error) {
15441
+ this.assertOpen();
15442
+ if (error.code !== "ENOENT") this.errorCode = "caddy_component_invalid";
15443
+ }
15444
+ });
15395
15445
  }
15396
15446
  status() {
15397
15447
  const artifact = this.artifact;
15398
15448
  return Object.freeze({
15399
15449
  supported: artifact !== void 0,
15400
15450
  installed: this.installed,
15401
- version: artifact?.version ?? "2.11.6",
15451
+ version: artifact?.version ?? "2.11.7",
15402
15452
  downloadBytes: artifact?.downloadBytes ?? 0,
15403
15453
  installedBytes: this.installed ? artifact?.executableBytes ?? 0 : 0,
15404
- sourceUrl: artifact?.downloadUrl ?? "https://caddyserver.com/download",
15454
+ sourceUrl: artifact?.downloadUrl ?? "https://github.com/saya-ch/dsh-mobile/releases/tag/caddy-component-2.11.7-tencentcloud-0.4.3-r1",
15405
15455
  downloadPage: CADDY_DOWNLOAD_PAGE,
15406
15456
  storagePath: this.componentRoot,
15407
15457
  ...this.errorCode === void 0 ? {} : { errorCode: this.errorCode }
@@ -15413,28 +15463,40 @@ var CaddyComponentManager = class {
15413
15463
  const artifact = this.artifact;
15414
15464
  if (artifact === void 0) throw new Error("caddy_component_unavailable");
15415
15465
  await ensureCaddyDirectory(this.stateDirectory, this.stagingRoot);
15466
+ this.assertOpen();
15416
15467
  await ensureCaddyDirectory(this.stateDirectory, this.componentRoot);
15468
+ this.assertOpen();
15417
15469
  const staging = await mkdtemp(join(this.stagingRoot, "install-"));
15418
15470
  const candidate = join(this.componentRoot, ".install-" + randomBytes(12).toString("hex"));
15419
15471
  const backup = join(this.componentRoot, ".previous-" + randomBytes(12).toString("hex"));
15420
15472
  let previous = false;
15421
15473
  let promoted = false;
15422
15474
  let failed = false;
15475
+ let operationError;
15423
15476
  try {
15477
+ this.assertOpen();
15424
15478
  const controller = new AbortController();
15425
15479
  const timeout = setTimeout(() => {
15426
15480
  controller.abort();
15427
15481
  }, 6e5);
15428
15482
  timeout.unref();
15483
+ this.download = {
15484
+ controller,
15485
+ timeout
15486
+ };
15429
15487
  let bytes;
15430
15488
  try {
15431
15489
  bytes = await this.fetchArtifact(artifact.downloadUrl, controller.signal);
15432
15490
  } finally {
15433
15491
  clearTimeout(timeout);
15492
+ this.download = void 0;
15434
15493
  }
15494
+ this.assertOpen();
15495
+ controller.signal.throwIfAborted();
15435
15496
  if (bytes.byteLength !== artifact.downloadBytes) throw new Error("caddy_download_size_mismatch");
15436
15497
  if (createHash("sha256").update(bytes).digest("hex") !== artifact.downloadSha256) throw new Error("caddy_download_hash_mismatch");
15437
15498
  await ensureCaddyDirectory(this.stateDirectory, candidate);
15499
+ this.assertOpen();
15438
15500
  const executable = join(candidate, artifact.executableName);
15439
15501
  await writeFile(executable, bytes, {
15440
15502
  flag: "wx",
@@ -15443,8 +15505,10 @@ var CaddyComponentManager = class {
15443
15505
  await chmod(executable, 448);
15444
15506
  if (bytes.byteLength !== artifact.executableBytes || await digest(executable) !== artifact.executableSha256) throw new Error("caddy_executable_hash_mismatch");
15445
15507
  await this.verifyMetadata(executable, artifact);
15508
+ this.assertOpen();
15446
15509
  try {
15447
15510
  const entry = await lstat(this.componentStorage);
15511
+ this.assertOpen();
15448
15512
  if (!entry.isDirectory() || entry.isSymbolicLink()) throw new Error("caddy_path_invalid");
15449
15513
  await renameCaddyPath(this.stateDirectory, this.componentStorage, backup);
15450
15514
  previous = true;
@@ -15452,6 +15516,7 @@ var CaddyComponentManager = class {
15452
15516
  if (error.code !== "ENOENT") throw error;
15453
15517
  }
15454
15518
  try {
15519
+ this.assertOpen();
15455
15520
  await this.promote(candidate, this.componentStorage);
15456
15521
  promoted = true;
15457
15522
  } catch (error) {
@@ -15469,21 +15534,29 @@ var CaddyComponentManager = class {
15469
15534
  this.errorCode = void 0;
15470
15535
  } catch (error) {
15471
15536
  failed = true;
15537
+ operationError = error;
15472
15538
  throw error;
15473
15539
  } finally {
15474
- let cleanupError;
15540
+ const cleanupErrors = [];
15475
15541
  for (const path of [
15476
15542
  staging,
15477
15543
  candidate,
15478
15544
  ...previous && promoted ? [backup] : []
15479
- ]) try {
15480
- await removeCaddyTree(this.stateDirectory, path);
15481
- } catch (error) {
15482
- cleanupError ??= error;
15545
+ ]) {
15546
+ this.cleanupPaths.add(path);
15547
+ try {
15548
+ await removeCaddyTree(this.stateDirectory, path);
15549
+ this.cleanupPaths.delete(path);
15550
+ } catch (error) {
15551
+ cleanupErrors.push(error);
15552
+ }
15553
+ }
15554
+ if (cleanupErrors.length > 0) {
15555
+ if (!failed && cleanupErrors.length === 1) throw cleanupErrors[0];
15556
+ throw new AggregateError([...failed ? [operationError] : [], ...cleanupErrors], "caddy_component_cleanup_failed", failed ? { cause: operationError } : void 0);
15483
15557
  }
15484
- if (!failed && cleanupError !== void 0) throw cleanupError;
15485
15558
  }
15486
- });
15559
+ }).then(() => this.status());
15487
15560
  }
15488
15561
  /** Remove optional component files; callers stop the controller and purge runtime configuration separately. */
15489
15562
  purge() {
@@ -15492,18 +15565,57 @@ var CaddyComponentManager = class {
15492
15565
  await removeCaddyTree(this.stateDirectory, this.stagingRoot);
15493
15566
  this.installed = false;
15494
15567
  this.errorCode = this.artifact === void 0 ? "caddy_component_unavailable" : void 0;
15568
+ }).then(() => this.status());
15569
+ }
15570
+ /**
15571
+ * Permanently stop admission and abort downloads, then await admitted work and cleanup.
15572
+ * An already started promotion/purge settles normally; cancellation does not undo committed bytes.
15573
+ * A downloader that ignores abort remains owned until its promise settles. Failed temporary cleanup
15574
+ * is retried here; a failed close can be called again without reopening admission or deleting recovery backups.
15575
+ */
15576
+ close() {
15577
+ if (this.closing !== void 0) return this.closing;
15578
+ this.closed = true;
15579
+ if (this.download !== void 0) {
15580
+ clearTimeout(this.download.timeout);
15581
+ this.download.controller.abort(/* @__PURE__ */ new Error("caddy_component_closed"));
15582
+ }
15583
+ const task = this.queue.then(async () => {
15584
+ const errors = [];
15585
+ for (const path of this.cleanupPaths) try {
15586
+ await removeCaddyTree(this.stateDirectory, path);
15587
+ this.cleanupPaths.delete(path);
15588
+ } catch (error) {
15589
+ errors.push(error);
15590
+ }
15591
+ if (errors.length === 1) throw errors[0];
15592
+ if (errors.length > 1) throw new AggregateError(errors, "caddy_component_cleanup_failed");
15593
+ });
15594
+ this.closing = task;
15595
+ task.catch(() => {
15596
+ if (this.closing === task) this.closing = void 0;
15495
15597
  });
15598
+ return task;
15496
15599
  }
15497
15600
  async verifyMetadata(executable, artifact) {
15601
+ this.assertOpen();
15498
15602
  const info = await this.inspectExecutable(executable);
15603
+ this.assertOpen();
15499
15604
  if (!info.version.startsWith("v" + artifact.version + " ")) throw new Error("caddy_executable_version_mismatch");
15500
15605
  const nonstandard = info.modules.split(/\r?\n/u).filter((line) => line.startsWith("dns.providers."));
15501
15606
  if (nonstandard.length !== 1 || nonstandard[0] !== "dns.providers.tencentcloud " + artifact.dnsPluginVersion || !info.modules.includes("Non-standard modules: 1")) throw new Error("caddy_executable_modules_mismatch");
15502
15607
  }
15608
+ assertOpen() {
15609
+ if (this.closed) throw new Error("caddy_component_closed");
15610
+ }
15503
15611
  enqueue(operation) {
15504
- const task = this.queue.then(operation, operation);
15612
+ if (this.closed) return Promise.reject(/* @__PURE__ */ new Error("caddy_component_closed"));
15613
+ const task = this.queue.then(() => {
15614
+ this.assertOpen();
15615
+ return operation();
15616
+ });
15505
15617
  this.queue = task.then(() => void 0, () => void 0);
15506
- return task.then(() => this.status());
15618
+ return task;
15507
15619
  }
15508
15620
  };
15509
15621
  const MAX_CONFIG_BYTES = 16384;
@@ -15862,6 +15974,7 @@ var CaddyController = class {
15862
15974
  } catch {}
15863
15975
  }
15864
15976
  async start() {
15977
+ if (this.child !== void 0 || this.gatewayValue !== void 0) await this.stop();
15865
15978
  const generation = ++this.generation;
15866
15979
  const startup = new AbortController();
15867
15980
  this.startupAbort = startup;
@@ -15911,12 +16024,19 @@ var CaddyController = class {
15911
16024
  "--adapter",
15912
16025
  "caddyfile"
15913
16026
  ], environment);
15914
- this.child = child;
16027
+ const ownedChild = {
16028
+ process: child,
16029
+ closed: false
16030
+ };
16031
+ this.child = ownedChild;
16032
+ child.once("close", () => {
16033
+ ownedChild.closed = true;
16034
+ });
15915
16035
  child.stdout.resume();
15916
16036
  child.stderr.resume();
15917
16037
  child.stdin.end();
15918
16038
  const failed = (code) => {
15919
- if (generation !== this.generation || this.child !== child) return;
16039
+ if (generation !== this.generation || this.child !== ownedChild) return;
15920
16040
  childFailure = code;
15921
16041
  startup.abort();
15922
16042
  if (this.latest.state === "ready") this.enqueue(async () => {
@@ -15991,20 +16111,49 @@ var CaddyController = class {
15991
16111
  this.startupAbort?.abort();
15992
16112
  await this.stopResources();
15993
16113
  }
16114
+ waitForChildClose(child) {
16115
+ if (child.closed) return Promise.resolve();
16116
+ return new Promise((resolve, reject) => {
16117
+ const finish = (error) => {
16118
+ clearTimeout(timer);
16119
+ child.process.removeListener("close", closed);
16120
+ if (error === void 0) resolve();
16121
+ else reject(error);
16122
+ };
16123
+ const closed = () => {
16124
+ finish();
16125
+ };
16126
+ const timer = setTimeout(() => {
16127
+ finish(/* @__PURE__ */ new Error("caddy_process_close_timeout"));
16128
+ }, 1500);
16129
+ timer.unref();
16130
+ child.process.once("close", closed);
16131
+ });
16132
+ }
15994
16133
  async stopResources() {
15995
16134
  const child = this.child;
15996
16135
  const gateway = this.gatewayValue;
15997
- await settleRemoteResources([async () => {
15998
- if (child !== void 0) {
15999
- await (this.options.terminateProcess ?? terminateRemoteProcess)(child);
16000
- if (this.child === child) this.child = void 0;
16001
- }
16002
- }, async () => {
16003
- if (gateway !== void 0) {
16004
- await gateway.close();
16005
- if (this.gatewayValue === gateway) this.gatewayValue = void 0;
16006
- }
16007
- }], "caddy cleanup failed");
16136
+ try {
16137
+ await settleRemoteResources([async () => {
16138
+ if (child !== void 0) {
16139
+ await (this.options.terminateProcess ?? terminateRemoteProcess)(child.process);
16140
+ await this.waitForChildClose(child);
16141
+ if (this.child === child) this.child = void 0;
16142
+ }
16143
+ }, async () => {
16144
+ if (gateway !== void 0) {
16145
+ await gateway.close();
16146
+ if (this.gatewayValue === gateway) this.gatewayValue = void 0;
16147
+ }
16148
+ }], "caddy cleanup failed");
16149
+ } catch (error) {
16150
+ this.publish({
16151
+ enabled: this.enabled,
16152
+ state: "error",
16153
+ errorCode: "caddy_cleanup_failed"
16154
+ });
16155
+ throw error;
16156
+ }
16008
16157
  }
16009
16158
  };
16010
16159
  //#endregion
@@ -18020,6 +18169,11 @@ async function apply(ctx, config) {
18020
18169
  adminClosing = true;
18021
18170
  unregister();
18022
18171
  };
18172
+ const drainRemoteWork = async () => {
18173
+ const draining = remoteProviders.close();
18174
+ caddyController.cancelPendingStart();
18175
+ await settleCleanupSteps([() => caddyComponent.close(), () => draining]);
18176
+ };
18023
18177
  const disposeMobileCommand = ctx.commands.register({
18024
18178
  name: "mobile",
18025
18179
  description: "定制手机界面或添加电脑能力",
@@ -18086,6 +18240,7 @@ async function apply(ctx, config) {
18086
18240
  try {
18087
18241
  await settleCleanupSteps([
18088
18242
  stopAdmin,
18243
+ drainRemoteWork,
18089
18244
  () => trustedNetworksWrite,
18090
18245
  disposeMobileCommand,
18091
18246
  disposeTaskEvents,
@@ -18105,6 +18260,7 @@ async function apply(ctx, config) {
18105
18260
  return async () => {
18106
18261
  await settleCleanupSteps([
18107
18262
  stopAdmin,
18263
+ drainRemoteWork,
18108
18264
  () => trustedNetworksWrite,
18109
18265
  disposeMobileCommand,
18110
18266
  disposeTaskEvents,