dsh-mobile 0.6.6 → 0.6.7

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/client.js CHANGED
@@ -3397,6 +3397,13 @@ window.__ModuleLoader__.load({
3397
3397
  html.dsh-native-mobile-active [data-dsh-mobile-sidebar] [class*="_sessionRow"] [class*="_pinIndicator"] { display:none !important; }
3398
3398
  html.dsh-native-mobile-active [data-dsh-mobile-sidebar] [class*="_rowActions"] button { box-sizing:border-box !important; width:32px !important; min-width:32px !important; height:32px !important; min-height:32px !important; }
3399
3399
  [data-dsh-mobile-frame] { grid-template-columns:0 minmax(0,1fr) 0 !important; width:100% !important; height:100dvh !important; overflow:hidden !important; }
3400
+ /* The stock frame owns layout, not a tap target. Restore only its content
3401
+ columns; the stock shell-overlay retains its own descendant hit policy. */
3402
+ html.dsh-native-mobile-active [data-dsh-mobile-frame] { pointer-events:none !important; }
3403
+ html.dsh-native-mobile-active [data-dsh-mobile-frame] > :is([data-dsh-mobile-sidebar],[data-dsh-mobile-center],[class*="_rightbarCol"]) { pointer-events:auto !important; }
3404
+ /* Floating slot surfaces paint above mobile drawers; their empty layer
3405
+ stays click-through and each stock occupant retains its own hit policy. */
3406
+ html.dsh-native-mobile-active [data-shell-overlay] { z-index:300 !important; pointer-events:none !important; }
3400
3407
  [data-dsh-mobile-center] { grid-column:2 !important; width:100vw !important; min-width:0 !important; }
3401
3408
  [data-dsh-mobile-center] > * { min-width:0 !important; }
3402
3409
  [data-dsh-mobile-header] { box-sizing:border-box !important; width:calc(100% - 16px) !important; margin:0 8px !important; min-width:0; padding-top:max(4px,env(safe-area-inset-top)) !important; padding-right:8px !important; padding-left:42px !important; }
@@ -3418,6 +3425,10 @@ window.__ModuleLoader__.load({
3418
3425
  [data-dsh-mobile-sidebar] { position:fixed !important; z-index:240 !important; inset:0 auto 0 0 !important; width:0 !important; overflow:visible !important; }
3419
3426
  [data-dsh-mobile-sidebar-root] { position:fixed !important; z-index:241 !important; inset:max(env(safe-area-inset-top),0px) auto 0 0 !important; height:auto !important; transition:width 180ms var(--dsh-mobile-motion-ease),box-shadow 180ms ease !important; }
3420
3427
  [data-dsh-mobile-sidebar][data-open="true"] [data-dsh-mobile-sidebar-root] { width:min(88vw,340px) !important; padding-top:0 !important; box-shadow:18px 0 46px rgb(15 23 42 / 18%); }
3428
+ /* Extra panel/footer seats may exceed a short drawer. Keep a bounded
3429
+ workspace scrollport and let the drawer scroll to the remaining seats. */
3430
+ [data-dsh-mobile-sidebar][data-open="true"]:not(:has([data-dsh-mobile-settings])) [data-dsh-mobile-sidebar-root] { overflow-y:auto !important; overscroll-behavior-y:contain; }
3431
+ [data-dsh-mobile-sidebar][data-open="true"]:not(:has([data-dsh-mobile-settings])) [data-dsh-mobile-sidebar-root] > [class*="_regionArea"] { flex:1 0 50% !important; }
3421
3432
  [data-dsh-mobile-sidebar][data-open="true"] [data-dsh-mobile-sidebar-root] [class*="_logoRow"] { height:52px !important; padding:4px 0 4px 4px !important; margin-bottom:4px !important; }
3422
3433
  [data-dsh-mobile-sidebar][data-open="false"] [data-dsh-mobile-sidebar-root] { width:0 !important; border:0 !important; background:transparent !important; box-shadow:none !important; overflow:visible !important; }
3423
3434
  [data-dsh-mobile-sidebar][data-open="false"] [data-dsh-mobile-sidebar-root] > :not(:has([data-dsh-mobile-toggle])) { display:none !important; }
@@ -6807,6 +6818,122 @@ window.__ModuleLoader__.load({
6807
6818
  });
6808
6819
  }
6809
6820
  //#endregion
6821
+ //#region src/mobile-custom-assets.ts
6822
+ const COPY = {
6823
+ en: {
6824
+ gateway_required: "Custom mobile CSS, scripts and extensions require a paired DSH Mobile access entry. This page is not using the Mobile gateway.",
6825
+ authentication_required: "Mobile customization was not refreshed because device authentication is unavailable. Reconnect through the current Mobile access entry.",
6826
+ manifest_unavailable: "The mobile extension manifest is unavailable. Check the plugin version and proxy routing; legacy custom files can still load when authorized.",
6827
+ manifest_invalid: "The mobile extension manifest is invalid. Existing customization is retained; check the plugin version and proxy routing.",
6828
+ resource_unavailable: "A mobile customization resource could not be loaded or activated. Check the custom files and current Mobile access entry.",
6829
+ refresh_failed: "Mobile customization could not be refreshed. Check the connection and current Mobile access entry.",
6830
+ recovered: "Mobile customization is available again."
6831
+ },
6832
+ it: {
6833
+ gateway_required: "CSS, script ed estensioni mobili personalizzati richiedono un accesso DSH Mobile abbinato. Questa pagina non usa il gateway Mobile.",
6834
+ authentication_required: "La personalizzazione mobile non è stata aggiornata perché l’autenticazione del dispositivo non è disponibile. Riconnettiti tramite l’accesso Mobile attuale.",
6835
+ manifest_unavailable: "Il manifest delle estensioni mobili non è disponibile. Controlla la versione del plugin e le route del proxy; i file personalizzati legacy possono essere caricati se autorizzati.",
6836
+ manifest_invalid: "Il manifest delle estensioni mobili non è valido. La personalizzazione esistente viene mantenuta; controlla la versione del plugin e le route del proxy.",
6837
+ resource_unavailable: "Una risorsa mobile personalizzata non è stata caricata o attivata. Controlla i file personalizzati e l’accesso Mobile attuale.",
6838
+ refresh_failed: "Impossibile aggiornare la personalizzazione mobile. Controlla la connessione e l’accesso Mobile attuale.",
6839
+ recovered: "La personalizzazione mobile è di nuovo disponibile."
6840
+ },
6841
+ zh: {
6842
+ gateway_required: "自定义移动样式、脚本与扩展需要通过已配对的 DSH Mobile 入口访问;当前页面不是移动网关页面。",
6843
+ authentication_required: "设备认证不可用,移动定制暂未刷新;请通过当前移动访问入口重新连接。",
6844
+ manifest_unavailable: "移动扩展清单不可用;请检查插件版本及反向代理路由。通过认证时,旧版自定义文件仍可加载。",
6845
+ manifest_invalid: "移动扩展清单无效,保留现有定制;请检查插件版本及反向代理路由。",
6846
+ resource_unavailable: "移动定制资源加载或激活失败;请检查定制文件及当前移动访问入口。",
6847
+ refresh_failed: "移动定制暂未刷新;请检查网络及当前移动访问入口。",
6848
+ recovered: "移动定制已恢复加载。"
6849
+ }
6850
+ };
6851
+ /** Only the authenticated Gateway owns customization APIs; the older dedicated marker remains supported. */
6852
+ function ownsMobileCustomization(gateway, frontend) {
6853
+ return gateway === true || frontend === "dedicated";
6854
+ }
6855
+ /** Emit each safe failure once until recovery, and ignore work after cancellation or disposal. */
6856
+ function createMobileAssetLoadReporter(locale, output = console) {
6857
+ const reported = /* @__PURE__ */ new Set();
6858
+ let disposed = false;
6859
+ return {
6860
+ fail(reason, signal) {
6861
+ if (disposed || signal?.aborted === true || reported.has(reason)) return;
6862
+ if (reason === "resource_unavailable" && reported.has("authentication_required")) return;
6863
+ reported.add(reason);
6864
+ output.warn(`[DSH Mobile] ${COPY[locale()][reason]}`);
6865
+ },
6866
+ recover(signal) {
6867
+ if (disposed || signal.aborted || reported.size === 0) return;
6868
+ reported.clear();
6869
+ output.info(`[DSH Mobile] ${COPY[locale()].recovered}`);
6870
+ },
6871
+ dispose() {
6872
+ disposed = true;
6873
+ reported.clear();
6874
+ }
6875
+ };
6876
+ }
6877
+ /** Read customization text within its file budget; the aggregate manifest has no existing byte cap. */
6878
+ async function readMobileAssetText(response, signal, maxBytes) {
6879
+ const assertActive = () => {
6880
+ if (signal.aborted) throw signal.reason ?? new DOMException("mobile customization cancelled", "AbortError");
6881
+ };
6882
+ if (response.body === null) {
6883
+ assertActive();
6884
+ return "";
6885
+ }
6886
+ const reader = response.body.getReader();
6887
+ let cancelled;
6888
+ const cancel = () => cancelled ??= reader.cancel().catch((error) => {});
6889
+ const aborted = () => {
6890
+ cancel();
6891
+ };
6892
+ signal.addEventListener("abort", aborted, { once: true });
6893
+ let completed = false;
6894
+ try {
6895
+ assertActive();
6896
+ const chunks = [];
6897
+ let bytes = 0;
6898
+ while (true) {
6899
+ const next = await reader.read();
6900
+ assertActive();
6901
+ if (next.done) {
6902
+ completed = true;
6903
+ break;
6904
+ }
6905
+ bytes += next.value.byteLength;
6906
+ if (maxBytes !== void 0 && bytes > maxBytes) throw new Error("mobile customization resource is too large");
6907
+ chunks.push(next.value);
6908
+ }
6909
+ const body = new Uint8Array(bytes);
6910
+ let offset = 0;
6911
+ for (const chunk of chunks) {
6912
+ body.set(chunk, offset);
6913
+ offset += chunk.byteLength;
6914
+ }
6915
+ return new TextDecoder().decode(body);
6916
+ } finally {
6917
+ signal.removeEventListener("abort", aborted);
6918
+ if (!completed) await cancel();
6919
+ reader.releaseLock();
6920
+ }
6921
+ }
6922
+ //#endregion
6923
+ //#region src/extension-limits.ts
6924
+ /** Maximum sizes accepted for legacy mobile customization resources. */
6925
+ const LEGACY_CUSTOM_ASSET_LIMIT = 262144;
6926
+ /** Maximum sizes enforced when reading local extension files. */
6927
+ const EXTENSION_LIMITS = Object.freeze({
6928
+ manifest: 65536,
6929
+ script: 1048576,
6930
+ css: 524288,
6931
+ asset: 8388608,
6932
+ assetFiles: 256,
6933
+ assetBytes: 33554432,
6934
+ assetDepth: 8
6935
+ });
6936
+ //#endregion
6810
6937
  //#region src/client.ts
6811
6938
  /** Map a host-reported provider onto the UI union, defaulting to the built-in one. */
6812
6939
  function parseMobileRemoteProvider(value) {
@@ -11087,6 +11214,7 @@ window.__ModuleLoader__.load({
11087
11214
  }
11088
11215
  /** A missing manifest is authoritative before optional legacy resources finish refreshing. */
11089
11216
  async function handleMissingExtensionManifest(clearManifestResources, refreshLegacyResources, signal) {
11217
+ if (signal.aborted) return false;
11090
11218
  clearManifestResources();
11091
11219
  const results = await refreshLegacyResources();
11092
11220
  return !signal.aborted && results.every(Boolean);
@@ -11179,10 +11307,11 @@ window.__ModuleLoader__.load({
11179
11307
  function startExtensionChangeStream(changed, runtime = {
11180
11308
  window,
11181
11309
  create: (url) => new EventSource(url, { withCredentials: true })
11182
- }, onTaskEvent, onDeviceRevoked) {
11310
+ }, onTaskEvent, onDeviceRevoked, initiallyEnabled = true) {
11183
11311
  let source;
11184
11312
  let timer;
11185
11313
  let disposed = false;
11314
+ let enabled = initiallyEnabled;
11186
11315
  let retryMs = 1e3;
11187
11316
  const clearTimer = () => {
11188
11317
  if (timer === void 0) return;
@@ -11190,19 +11319,24 @@ window.__ModuleLoader__.load({
11190
11319
  timer = void 0;
11191
11320
  };
11192
11321
  const connect = () => {
11193
- if (disposed || source !== void 0) return;
11322
+ if (disposed || !enabled || source !== void 0) return;
11194
11323
  clearTimer();
11195
11324
  const next = runtime.create("/mobile-access/extensions/events");
11196
11325
  source = next;
11326
+ const current = () => !disposed && enabled && source === next;
11197
11327
  next.onopen = () => {
11198
- retryMs = 1e3;
11328
+ if (current()) retryMs = 1e3;
11199
11329
  };
11200
- next.addEventListener("extensions-changed", changed);
11330
+ next.addEventListener("extensions-changed", () => {
11331
+ if (current()) changed();
11332
+ });
11201
11333
  if (onTaskEvent !== void 0) next.addEventListener("task-notify", (message) => {
11334
+ if (!current()) return;
11202
11335
  const data = message.data;
11203
11336
  onTaskEvent(data);
11204
11337
  });
11205
11338
  if (onDeviceRevoked !== void 0) next.addEventListener("device-revoked", (message) => {
11339
+ if (!current()) return;
11206
11340
  const data = message.data;
11207
11341
  if (isDeviceRevokedPayload(data)) onDeviceRevoked();
11208
11342
  });
@@ -11210,14 +11344,14 @@ window.__ModuleLoader__.load({
11210
11344
  if (source !== next) return;
11211
11345
  next.close();
11212
11346
  source = void 0;
11213
- if (disposed) return;
11347
+ if (disposed || !enabled) return;
11214
11348
  const delay = retryMs;
11215
11349
  retryMs = Math.min(3e4, retryMs * 2);
11216
11350
  timer = runtime.window.setTimeout(connect, delay);
11217
11351
  };
11218
11352
  };
11219
11353
  const reconnectNow = () => {
11220
- if (disposed) return;
11354
+ if (disposed || !enabled) return;
11221
11355
  source?.close();
11222
11356
  source = void 0;
11223
11357
  retryMs = 1e3;
@@ -11225,13 +11359,23 @@ window.__ModuleLoader__.load({
11225
11359
  };
11226
11360
  runtime.window.addEventListener("online", reconnectNow);
11227
11361
  connect();
11228
- return () => {
11362
+ const stop = () => {
11229
11363
  disposed = true;
11230
11364
  clearTimer();
11231
11365
  source?.close();
11232
11366
  source = void 0;
11233
11367
  runtime.window.removeEventListener("online", reconnectNow);
11234
11368
  };
11369
+ return Object.assign(stop, { setEnabled(value) {
11370
+ if (disposed || value === enabled) return;
11371
+ enabled = value;
11372
+ if (value) connect();
11373
+ else {
11374
+ clearTimer();
11375
+ source?.close();
11376
+ source = void 0;
11377
+ }
11378
+ } });
11235
11379
  }
11236
11380
  /** Keep at most one activation in flight per id and commit only its latest generation. */
11237
11381
  var PerIdActivationLifecycle = class {
@@ -11359,7 +11503,10 @@ window.__ModuleLoader__.load({
11359
11503
  });
11360
11504
  }
11361
11505
  };
11506
+ /** Install authenticated mobile customization refresh, retaining loaded legacy assets through temporary failures. */
11362
11507
  function installCustomAssets() {
11508
+ const reporter = createMobileAssetLoadReporter(selectedMobileControlLocale);
11509
+ const customizationOwner = ownsMobileCustomization(document.querySelector("meta[name=\"dsh-mobile-gateway\"][content=\"authenticated\"]") !== null, window.__DSH_MOBILE_FRONTEND__);
11363
11510
  const legacyStyle = element("style");
11364
11511
  legacyStyle.dataset.plugin = "dsh-mobile-custom";
11365
11512
  document.head.append(legacyStyle);
@@ -11384,6 +11531,16 @@ window.__ModuleLoader__.load({
11384
11531
  const managedDefinitionIds = /* @__PURE__ */ new Set();
11385
11532
  let manifestEtag = "";
11386
11533
  let disposed = false;
11534
+ let events;
11535
+ const failed = (reason, signal) => {
11536
+ if (disposed || signal.aborted) return;
11537
+ reporter.fail(reason, signal);
11538
+ if (reason === "authentication_required") events?.setEnabled(false);
11539
+ };
11540
+ const unavailable = (response, signal, fallback) => {
11541
+ failed(response.status === 401 || response.status === 403 ? "authentication_required" : fallback, signal);
11542
+ response.body?.cancel().catch((error) => {});
11543
+ };
11387
11544
  let expectedDefinitionId;
11388
11545
  const SURFACE_HOST_STYLES = {
11389
11546
  "sidebar-action": "position:fixed;z-index:1100;top:calc(env(safe-area-inset-top) + 8px);left:8px;display:flex;flex-direction:column;gap:6px;pointer-events:none",
@@ -11421,6 +11578,16 @@ window.__ModuleLoader__.load({
11421
11578
  const stopNativeBack = installMobileNativeBack(window, document, () => {
11422
11579
  toast(mobileBackBlockedMessage(selectedMobileControlLocale()));
11423
11580
  });
11581
+ if (!customizationOwner) {
11582
+ reporter.fail("gateway_required");
11583
+ return () => {
11584
+ disposed = true;
11585
+ reporter.dispose();
11586
+ stopNativeBack();
11587
+ legacyStyle.remove();
11588
+ document.querySelector("[data-dsh-mobile-extension-layer]")?.remove();
11589
+ };
11590
+ }
11424
11591
  const materializeNativeFile = (value) => {
11425
11592
  if (typeof value !== "object" || value === null || !("base64" in value) || !("name" in value)) return value;
11426
11593
  const candidate = value;
@@ -11627,10 +11794,13 @@ window.__ModuleLoader__.load({
11627
11794
  signal
11628
11795
  });
11629
11796
  if (response.status === 304) return true;
11630
- if (!response.ok) return false;
11797
+ if (!response.ok) {
11798
+ unavailable(response, signal, "resource_unavailable");
11799
+ return false;
11800
+ }
11631
11801
  const nextEtag = response.headers.get("etag") ?? "";
11632
11802
  const nextModified = response.headers.get("last-modified") ?? "";
11633
- const next = await response.text();
11803
+ const next = await readMobileAssetText(response, signal, LEGACY_CUSTOM_ASSET_LIMIT);
11634
11804
  if (refreshAborted(signal)) return false;
11635
11805
  if (next === legacySource) {
11636
11806
  legacyJsEtag = nextEtag;
@@ -11686,6 +11856,7 @@ window.__ModuleLoader__.load({
11686
11856
  } catch {
11687
11857
  pendingRoot?.remove();
11688
11858
  legacyMount = previousMount;
11859
+ failed("resource_unavailable", signal);
11689
11860
  return false;
11690
11861
  }
11691
11862
  };
@@ -11723,16 +11894,40 @@ window.__ModuleLoader__.load({
11723
11894
  headers,
11724
11895
  signal
11725
11896
  });
11897
+ if (disposed || signal.aborted) {
11898
+ response.body?.cancel().catch((error) => {});
11899
+ return false;
11900
+ }
11726
11901
  if (response.status === 404) {
11902
+ unavailable(response, signal, "manifest_unavailable");
11727
11903
  legacyScriptRevision = "";
11728
11904
  legacyStyleRevision = "";
11729
- return handleMissingExtensionManifest(clearManifestExtensions, () => Promise.all([refreshLegacy(signal), refreshCssLegacy(legacyStyle, signal, legacyCssState)]), signal);
11905
+ if (!await handleMissingExtensionManifest(clearManifestExtensions, () => Promise.all([refreshLegacy(signal), refreshCssLegacy(legacyStyle, signal, legacyCssState, unavailable)]), signal)) failed("resource_unavailable", signal);
11906
+ return false;
11907
+ }
11908
+ if (response.status === 304) {
11909
+ if (!signal.aborted) events?.setEnabled(true);
11910
+ return true;
11911
+ }
11912
+ if (!response.ok) {
11913
+ unavailable(response, signal, "manifest_unavailable");
11914
+ return false;
11730
11915
  }
11731
- if (response.status === 304) return true;
11732
- if (!response.ok) return false;
11733
11916
  const nextManifestEtag = response.headers.get("etag") ?? "";
11734
- const payload = parseMobileExtensionManifest(await response.json());
11735
- if (refreshAborted(signal) || payload === void 0) return false;
11917
+ const manifestSource = await readMobileAssetText(response, signal, void 0);
11918
+ let payload;
11919
+ try {
11920
+ payload = parseMobileExtensionManifest(JSON.parse(manifestSource));
11921
+ } catch {
11922
+ failed("manifest_invalid", signal);
11923
+ return false;
11924
+ }
11925
+ if (refreshAborted(signal)) return false;
11926
+ if (payload === void 0) {
11927
+ failed("manifest_invalid", signal);
11928
+ return false;
11929
+ }
11930
+ events?.setEnabled(true);
11736
11931
  const entries = payload.extensions;
11737
11932
  const seen = new Set(entries.map((entry) => entry.id));
11738
11933
  const scriptRevision = payload.legacy.scriptRevision;
@@ -11743,8 +11938,11 @@ window.__ModuleLoader__.load({
11743
11938
  else refreshComplete = false;
11744
11939
  }
11745
11940
  if (styleRevision === "" || styleRevision !== legacyStyleRevision) {
11746
- if (await refreshCssLegacy(legacyStyle, signal, legacyCssState)) legacyStyleRevision = styleRevision;
11747
- else refreshComplete = false;
11941
+ if (await refreshCssLegacy(legacyStyle, signal, legacyCssState, unavailable)) legacyStyleRevision = styleRevision;
11942
+ else {
11943
+ failed("resource_unavailable", signal);
11944
+ refreshComplete = false;
11945
+ }
11748
11946
  }
11749
11947
  const commitStyle = (id, change, css, etag) => {
11750
11948
  if (change === "retain") return;
@@ -11786,9 +11984,12 @@ window.__ModuleLoader__.load({
11786
11984
  signal
11787
11985
  });
11788
11986
  if (cssResponse.status !== 304) {
11789
- if (!cssResponse.ok) throw new Error("mobile extension style failed to load");
11987
+ if (!cssResponse.ok) {
11988
+ unavailable(cssResponse, signal, "resource_unavailable");
11989
+ throw new Error("mobile extension style failed to load");
11990
+ }
11790
11991
  pendingStyleEtag = cssResponse.headers.get("etag") ?? void 0;
11791
- pendingCss = await cssResponse.text();
11992
+ pendingCss = await readMobileAssetText(cssResponse, signal, EXTENSION_LIMITS.css);
11792
11993
  styleChange = "replace";
11793
11994
  if (refreshAborted(signal)) return false;
11794
11995
  }
@@ -11815,9 +12016,12 @@ window.__ModuleLoader__.load({
11815
12016
  let nextDigest;
11816
12017
  let nextEtag;
11817
12018
  if (scriptResponse.status !== 304) {
11818
- if (!scriptResponse.ok) throw new Error("mobile extension script failed to load");
12019
+ if (!scriptResponse.ok) {
12020
+ unavailable(scriptResponse, signal, "resource_unavailable");
12021
+ throw new Error("mobile extension script failed to load");
12022
+ }
11819
12023
  nextEtag = scriptResponse.headers.get("etag") ?? void 0;
11820
- const source = await scriptResponse.text();
12024
+ const source = await readMobileAssetText(scriptResponse, signal, EXTENSION_LIMITS.script);
11821
12025
  if (refreshAborted(signal)) return false;
11822
12026
  const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(source));
11823
12027
  if (refreshAborted(signal)) return false;
@@ -11871,6 +12075,7 @@ window.__ModuleLoader__.load({
11871
12075
  failClosedExtensionGenerationReplacement(hadActiveGeneration, previousHostGeneration, entry.generation, () => {
11872
12076
  disposeManifestExtension(entry.id);
11873
12077
  });
12078
+ failed("resource_unavailable", signal);
11874
12079
  refreshComplete = false;
11875
12080
  }
11876
12081
  }
@@ -11881,13 +12086,17 @@ window.__ModuleLoader__.load({
11881
12086
  } else manifestEtag = "";
11882
12087
  return refreshComplete;
11883
12088
  } catch {
12089
+ failed("refresh_failed", signal);
11884
12090
  return false;
11885
12091
  }
11886
12092
  };
11887
12093
  started = true;
11888
12094
  for (const definition of definitions.values()) activateDefinition(definition);
11889
12095
  const stopRefresh = startLifecycleRefreshScheduler(async (signal) => {
11890
- await refreshExtensions(signal);
12096
+ if (await refreshExtensions(signal) && !disposed && !signal.aborted) {
12097
+ reporter.recover(signal);
12098
+ events?.setEnabled(true);
12099
+ }
11891
12100
  });
11892
12101
  const stopEvents = startExtensionChangeStream(() => {
11893
12102
  stopRefresh.refresh();
@@ -11905,9 +12114,11 @@ window.__ModuleLoader__.load({
11905
12114
  });
11906
12115
  }, () => {
11907
12116
  fireDeviceRevoked();
11908
- });
12117
+ }, false);
12118
+ events = stopEvents;
11909
12119
  return () => {
11910
12120
  disposed = true;
12121
+ reporter.dispose();
11911
12122
  stopNativeBack();
11912
12123
  stopEvents();
11913
12124
  stopRefresh();
@@ -11926,7 +12137,7 @@ window.__ModuleLoader__.load({
11926
12137
  else window.dshMobile = previous;
11927
12138
  };
11928
12139
  }
11929
- async function refreshCssLegacy(style, signal, state) {
12140
+ async function refreshCssLegacy(style, signal, state, unavailable) {
11930
12141
  try {
11931
12142
  const headers = {};
11932
12143
  if (state.etag !== "") headers["if-none-match"] = state.etag;
@@ -11950,13 +12161,14 @@ window.__ModuleLoader__.load({
11950
12161
  if (response.ok) {
11951
12162
  const nextEtag = response.headers.get("etag") ?? "";
11952
12163
  const nextModified = response.headers.get("last-modified") ?? "";
11953
- const css = await response.text();
12164
+ const css = await readMobileAssetText(response, signal, LEGACY_CUSTOM_ASSET_LIMIT);
11954
12165
  if (refreshAborted(signal)) return false;
11955
12166
  style.textContent = css;
11956
12167
  state.etag = nextEtag;
11957
12168
  state.modified = nextModified;
11958
12169
  return true;
11959
12170
  }
12171
+ unavailable(response, signal, "resource_unavailable");
11960
12172
  return false;
11961
12173
  } catch {
11962
12174
  return false;
@@ -12010,11 +12222,13 @@ window.__ModuleLoader__.load({
12010
12222
  }, "dsh-mobile: authenticated gateway client trust");
12011
12223
  ctx.effect(() => {
12012
12224
  const desktopAdmin = isDesktopAdminSurface(location.hostname, location.search, window.__DSH_MOBILE_FRONTEND__, location.protocol);
12225
+ const gatewayCustomization = ownsMobileCustomization(document.querySelector("meta[name=\"dsh-mobile-gateway\"][content=\"authenticated\"]") !== null, window.__DSH_MOBILE_FRONTEND__);
12013
12226
  const style = element("style");
12014
12227
  style.dataset.plugin = "dsh-mobile";
12015
12228
  style.textContent = desktopAdmin ? CONTROL_STYLES : NATIVE_MOBILE_STYLES;
12016
12229
  style.textContent += CLIENT_MODULE_STYLES;
12017
12230
  document.head.append(style);
12231
+ const removeCustom = !desktopAdmin || gatewayCustomization ? installCustomAssets() : () => void 0;
12018
12232
  const removeVoiceSession = installVoiceSession(!desktopAdmin);
12019
12233
  const removeModuleSettings = ctx.slots.inject("settings.general.item", () => ctx.slots.register({
12020
12234
  name: "settings.general.item",
@@ -12058,7 +12272,6 @@ window.__ModuleLoader__.load({
12058
12272
  removeFontSize();
12059
12273
  };
12060
12274
  });
12061
- const removeCustom = installCustomAssets();
12062
12275
  const removeSurface = installDshLanguageBoundSurface(() => installNativeMobileSurface({
12063
12276
  getLayout: () => ctx.get("layout"),
12064
12277
  getSidebarRight: () => ctx.get("sidebarRight")
@@ -12118,6 +12331,7 @@ window.__ModuleLoader__.load({
12118
12331
  disposeClientModuleDialogs();
12119
12332
  removeModuleSettings();
12120
12333
  removeControl();
12334
+ removeCustom();
12121
12335
  removeVoiceSession();
12122
12336
  style.remove();
12123
12337
  };
@@ -12151,6 +12365,7 @@ window.__ModuleLoader__.load({
12151
12365
  exports.frpAttachFormErrorCode = frpAttachFormErrorCode;
12152
12366
  exports.handleMissingExtensionManifest = handleMissingExtensionManifest;
12153
12367
  exports.inject = inject;
12368
+ exports.installCustomAssets = installCustomAssets;
12154
12369
  exports.installDshLanguageBoundSurface = installDshLanguageBoundSurface;
12155
12370
  exports.installMobileNativeBack = installMobileNativeBack;
12156
12371
  exports.mobileBackBlockedMessage = mobileBackBlockedMessage;