@le-space/ui 0.6.46 → 0.8.0

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/react/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/react/SponsorRelayFab.tsx
2
- import React from "react";
2
+ import React2 from "react";
3
3
 
4
4
  // src/shared/constants.ts
5
5
  var DEFAULT_INSTANCE_NAME = "sponsor-relay";
@@ -43,7 +43,7 @@ var RECENT_INSTANCE_RUNTIME_GRACE_MS = 10 * 60 * 1e3;
43
43
  var DEPLOYMENT_PENDING_WARNING_MS = 3 * 60 * 1e3;
44
44
 
45
45
  // src/shared/package-version.ts
46
- var UI_PACKAGE_VERSION = "0.6.46";
46
+ var UI_PACKAGE_VERSION = "0.8.0";
47
47
 
48
48
  // src/shared/format.ts
49
49
  function shortHash(value, head = 8, tail = 6) {
@@ -3832,7 +3832,8 @@ function defaultState(props = {}) {
3832
3832
  bootstrapRegistrations: [],
3833
3833
  orphanBootstrapRegistrations: [],
3834
3834
  lastDeploymentHash: null,
3835
- deploymentProgress: IDLE_DEPLOYMENT_PROGRESS
3835
+ deploymentProgress: IDLE_DEPLOYMENT_PROGRESS,
3836
+ instanceAddresses: {}
3836
3837
  };
3837
3838
  }
3838
3839
  function manifestLoadErrorState(error) {
@@ -3860,6 +3861,83 @@ async function sha256Hex(payload) {
3860
3861
  );
3861
3862
  return Array.from(new Uint8Array(digest)).map((byte) => byte.toString(16).padStart(2, "0")).join("");
3862
3863
  }
3864
+ function hostnameOfUrl(value) {
3865
+ if (!value) return null;
3866
+ try {
3867
+ return new URL(value).hostname || null;
3868
+ } catch {
3869
+ return null;
3870
+ }
3871
+ }
3872
+ function emptyInstanceAddresses() {
3873
+ return {
3874
+ status: "idle",
3875
+ groups: [],
3876
+ pwaEnv: null,
3877
+ payload: null,
3878
+ peerId: null,
3879
+ version: null,
3880
+ fetchedAt: null,
3881
+ error: null,
3882
+ sourceUrl: null
3883
+ };
3884
+ }
3885
+ var TRANSPORT_LABELS = {
3886
+ tcp: "TCP",
3887
+ websocket: "WebSocket",
3888
+ webrtc: "WebRTC",
3889
+ direct_tcp: "Direct TCP",
3890
+ autotls_wss: "AutoTLS WSS",
3891
+ proxy_wss: "Proxy WSS",
3892
+ webtransport: "WebTransport",
3893
+ webrtc_direct: "WebRTC Direct",
3894
+ browser_bootstrap: "Browser bootstrap",
3895
+ probe: "Probe"
3896
+ };
3897
+ function transportLabel(key) {
3898
+ return TRANSPORT_LABELS[key] ?? key.replace(/[_-]+/g, " ").replace(/^./, (first) => first.toUpperCase());
3899
+ }
3900
+ function addressList(value) {
3901
+ return Array.isArray(value) ? value.filter((entry) => typeof entry === "string" && Boolean(entry.trim())) : [];
3902
+ }
3903
+ function parseInstanceAddressPayload(payload) {
3904
+ const groups = [];
3905
+ const byTransport = payload.byTransport;
3906
+ if (byTransport && typeof byTransport === "object") {
3907
+ for (const [key, value] of Object.entries(
3908
+ byTransport
3909
+ )) {
3910
+ const addresses = addressList(value);
3911
+ if (addresses.length > 0) {
3912
+ groups.push({ key, label: transportLabel(key), addresses });
3913
+ }
3914
+ }
3915
+ }
3916
+ for (const [key, value] of Object.entries(payload)) {
3917
+ if (!key.endsWith("_multiaddrs")) continue;
3918
+ const addresses = addressList(value);
3919
+ if (addresses.length === 0) continue;
3920
+ const groupKey = key.replace(/_multiaddrs$/, "");
3921
+ groups.push({
3922
+ key: groupKey,
3923
+ label: transportLabel(groupKey),
3924
+ addresses
3925
+ });
3926
+ }
3927
+ const pwaEnvRaw = payload.pwa_env;
3928
+ const pwaEnv = pwaEnvRaw && typeof pwaEnvRaw === "object" ? Object.fromEntries(
3929
+ Object.entries(pwaEnvRaw).filter(([, entry]) => typeof entry === "string").map(([entryKey, entry]) => [entryKey, entry])
3930
+ ) : null;
3931
+ const peerId = typeof payload.peerId === "string" ? payload.peerId : typeof payload.peer_id === "string" ? payload.peer_id : null;
3932
+ return {
3933
+ ...emptyInstanceAddresses(),
3934
+ groups,
3935
+ pwaEnv,
3936
+ payload,
3937
+ peerId,
3938
+ version: typeof payload.version === "string" ? payload.version : null
3939
+ };
3940
+ }
3863
3941
  function mappedPorts(execution) {
3864
3942
  return Object.entries(execution?.networking?.mapped_ports ?? {}).map(
3865
3943
  ([port, mapping]) => ({
@@ -4008,6 +4086,7 @@ async function inspectInstanceRuntime(args) {
4008
4086
  vmIpv4: null,
4009
4087
  webUrl: null,
4010
4088
  sshCommand: null,
4089
+ proxyHostname: null,
4011
4090
  mappedPorts: [],
4012
4091
  execution: null,
4013
4092
  error: null
@@ -4072,6 +4151,7 @@ async function inspectInstanceRuntime(args) {
4072
4151
  details.ipv6 = execution.networking.ipv6_ip ?? execution.networking.ipv6 ?? details.ipv6;
4073
4152
  details.vmIpv4 = execution.networking.ipv4_ip ?? null;
4074
4153
  details.webUrl = execution.networking.proxy_url ?? details.webUrl;
4154
+ details.proxyHostname = hostnameOfUrl(details.webUrl);
4075
4155
  details.mappedPorts = mappedPorts(execution);
4076
4156
  details.sshCommand = buildSshCommand(details.hostIpv4, details.mappedPorts);
4077
4157
  return { details, lookup };
@@ -4421,10 +4501,14 @@ var SponsorRelayController = class {
4421
4501
  detail: "Publishing the host port mapping into the guest relay configuration."
4422
4502
  });
4423
4503
  const tcpPort = mappedPorts2["9091"]?.host ?? 0;
4424
- const wsPort = mappedPorts2["9092"]?.host ?? mappedPorts2["443"]?.host ?? 0;
4504
+ const wsPort = mappedPorts2["9092"]?.host ?? 0;
4425
4505
  if (!tcpPort || !wsPort) {
4506
+ const missing = [
4507
+ tcpPort ? null : "9091 (libp2p TCP)",
4508
+ wsPort ? null : "9092 (libp2p WebSocket)"
4509
+ ].filter(Boolean);
4426
4510
  throw new Error(
4427
- "OrbitDB relay runtime is missing required mapped TCP/WS ports."
4511
+ `OrbitDB relay runtime has no mapped host port for ${missing.join(" and ")}. Deploy a rootfs whose manifest requests these forwards.`
4428
4512
  );
4429
4513
  }
4430
4514
  const configureResult = await configureOrbitdbRelaySetup2({
@@ -5407,6 +5491,7 @@ var SponsorRelayController = class {
5407
5491
  vmIpv4: null,
5408
5492
  webUrl: null,
5409
5493
  sshCommand: null,
5494
+ proxyHostname: null,
5410
5495
  mappedPorts: [],
5411
5496
  execution: null,
5412
5497
  error: null
@@ -5822,6 +5907,9 @@ var SponsorRelayController = class {
5822
5907
  vmIpv4: runtime.execution?.networking?.ipv4_ip ?? null,
5823
5908
  webUrl: runtime.webAccessUrl ?? runtime.proxyUrl ?? runtime.execution?.networking?.proxy_url ?? null,
5824
5909
  sshCommand: runtime.sshCommand ?? null,
5910
+ proxyHostname: hostnameOfUrl(
5911
+ runtime.proxyUrl ?? runtime.webAccessUrl ?? runtime.execution?.networking?.proxy_url ?? null
5912
+ ),
5825
5913
  mappedPorts: runtime.execution != null ? mappedPorts(runtime.execution) : runtimeMappedPorts(runtime.mappedPorts),
5826
5914
  execution: runtime.execution ?? null,
5827
5915
  error: null
@@ -5919,6 +6007,9 @@ var SponsorRelayController = class {
5919
6007
  vmIpv4: latestRuntime.execution?.networking?.ipv4_ip ?? null,
5920
6008
  webUrl: latestRuntime.webAccessUrl ?? latestRuntime.proxyUrl ?? latestRuntime.execution?.networking?.proxy_url ?? null,
5921
6009
  sshCommand: latestRuntime.sshCommand ?? null,
6010
+ proxyHostname: hostnameOfUrl(
6011
+ latestRuntime.proxyUrl ?? latestRuntime.webAccessUrl ?? latestRuntime.execution?.networking?.proxy_url ?? null
6012
+ ),
5922
6013
  mappedPorts: latestRuntime.execution != null ? mappedPorts(latestRuntime.execution) : runtimeMappedPorts(latestRuntime.mappedPorts),
5923
6014
  execution: latestRuntime.execution ?? null,
5924
6015
  error: null
@@ -6099,6 +6190,82 @@ var SponsorRelayController = class {
6099
6190
  });
6100
6191
  }
6101
6192
  }
6193
+ /**
6194
+ * Read one deployment's own address document over its HTTPS proxy.
6195
+ *
6196
+ * The mapped ports are plain HTTP, which a browser on an HTTPS page refuses to
6197
+ * fetch, so the proxy hostname is the only way in. Deliberately single-shot:
6198
+ * unlike the deploy-time readiness probe this backs a button someone pressed,
6199
+ * and a caller who wants newer data presses it again.
6200
+ */
6201
+ async loadInstanceAddresses(instanceHash, options = {}) {
6202
+ const existing = this.state.instanceAddresses[instanceHash];
6203
+ if (!options.force && existing && existing.status !== "idle") return;
6204
+ const record = this.state.instances.find(
6205
+ (entry) => entry.instance.item_hash === instanceHash
6206
+ );
6207
+ const proxyHostname = record?.details.proxyHostname ?? null;
6208
+ if (!proxyHostname) {
6209
+ this.patchInstanceAddresses(instanceHash, {
6210
+ ...emptyInstanceAddresses(),
6211
+ status: "unsupported",
6212
+ error: "This deployment has no HTTPS proxy hostname yet, so its addresses cannot be read from the browser."
6213
+ });
6214
+ return;
6215
+ }
6216
+ const sourceUrl = `https://${proxyHostname}/multiaddrs`;
6217
+ this.patchInstanceAddresses(instanceHash, {
6218
+ ...existing ?? emptyInstanceAddresses(),
6219
+ status: "loading",
6220
+ sourceUrl,
6221
+ error: null
6222
+ });
6223
+ try {
6224
+ const abort = new AbortController();
6225
+ const timeout = globalThis.setTimeout(() => abort.abort(), 1e4);
6226
+ const response = await fetch(sourceUrl, {
6227
+ cache: "no-cache",
6228
+ signal: abort.signal
6229
+ });
6230
+ globalThis.clearTimeout(timeout);
6231
+ if (response.status === 404) {
6232
+ this.patchInstanceAddresses(instanceHash, {
6233
+ ...emptyInstanceAddresses(),
6234
+ status: "unsupported",
6235
+ sourceUrl,
6236
+ fetchedAt: Date.now(),
6237
+ error: "This profile does not publish an address document."
6238
+ });
6239
+ return;
6240
+ }
6241
+ if (!response.ok) {
6242
+ throw new Error(`${sourceUrl} answered ${response.status}.`);
6243
+ }
6244
+ const payload = await response.json();
6245
+ this.patchInstanceAddresses(instanceHash, {
6246
+ ...parseInstanceAddressPayload(payload),
6247
+ status: "ready",
6248
+ sourceUrl,
6249
+ fetchedAt: Date.now(),
6250
+ error: null
6251
+ });
6252
+ } catch (error) {
6253
+ this.patchInstanceAddresses(instanceHash, {
6254
+ ...this.state.instanceAddresses[instanceHash] ?? emptyInstanceAddresses(),
6255
+ status: "error",
6256
+ sourceUrl,
6257
+ error: error instanceof Error ? error.message : String(error)
6258
+ });
6259
+ }
6260
+ }
6261
+ patchInstanceAddresses(instanceHash, value) {
6262
+ this.patch({
6263
+ instanceAddresses: {
6264
+ ...this.state.instanceAddresses,
6265
+ [instanceHash]: value
6266
+ }
6267
+ });
6268
+ }
6102
6269
  async deleteInstance(instanceHash) {
6103
6270
  this.trace("delete:start", { instanceHash });
6104
6271
  if (!this.state.wallet.address) {
@@ -6272,8 +6439,45 @@ function createSponsorRelayController(props = {}) {
6272
6439
  return new SponsorRelayController(props);
6273
6440
  }
6274
6441
 
6442
+ // src/react/components/CopyButton.tsx
6443
+ import { useEffect, useRef, useState } from "react";
6444
+ import { jsx } from "react/jsx-runtime";
6445
+ var copyButtonStyle = {
6446
+ borderRadius: "999px",
6447
+ border: "1px solid var(--rb-border)",
6448
+ background: "transparent",
6449
+ color: "var(--rb-muted)",
6450
+ padding: "0.28rem 0.7rem",
6451
+ fontFamily: "var(--rb-font-mono, monospace)",
6452
+ fontSize: "0.6563rem",
6453
+ fontWeight: 700,
6454
+ lineHeight: 1,
6455
+ textTransform: "uppercase",
6456
+ letterSpacing: "0.06em",
6457
+ cursor: "pointer",
6458
+ flexShrink: 0
6459
+ };
6460
+ function CopyButton({ text, label = "Copy" }) {
6461
+ const [copied, setCopied] = useState(false);
6462
+ const timer = useRef(null);
6463
+ useEffect(
6464
+ () => () => {
6465
+ if (timer.current) clearTimeout(timer.current);
6466
+ },
6467
+ []
6468
+ );
6469
+ const handleCopy = async () => {
6470
+ if (!text) return;
6471
+ await navigator.clipboard.writeText(text);
6472
+ setCopied(true);
6473
+ if (timer.current) clearTimeout(timer.current);
6474
+ timer.current = setTimeout(() => setCopied(false), 1200);
6475
+ };
6476
+ return /* @__PURE__ */ jsx("button", { type: "button", style: copyButtonStyle, onClick: () => void handleCopy(), children: copied ? "Copied" : label });
6477
+ }
6478
+
6275
6479
  // src/react/hooks/useSponsorRelayController.ts
6276
- import { useEffect, useMemo, useSyncExternalStore } from "react";
6480
+ import { useEffect as useEffect2, useMemo, useSyncExternalStore } from "react";
6277
6481
  function useSponsorRelayController(props) {
6278
6482
  const controller = useMemo(
6279
6483
  () => createSponsorRelayController(props),
@@ -6293,12 +6497,12 @@ function useSponsorRelayController(props) {
6293
6497
  props.ucanStoreBootstrap
6294
6498
  ]
6295
6499
  );
6296
- useEffect(() => {
6500
+ useEffect2(() => {
6297
6501
  controller.updateProps({
6298
6502
  debug: props.debug
6299
6503
  });
6300
6504
  }, [controller, props.debug]);
6301
- useEffect(() => {
6505
+ useEffect2(() => {
6302
6506
  void controller.init();
6303
6507
  return () => {
6304
6508
  controller.destroy();
@@ -6313,7 +6517,7 @@ function useSponsorRelayController(props) {
6313
6517
  }
6314
6518
 
6315
6519
  // src/react/SponsorRelayFab.tsx
6316
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6520
+ import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
6317
6521
  var THEME_CSS = `
6318
6522
  :root {
6319
6523
  --rb-font-body: "Inter", -apple-system, "Segoe UI", Roboto, sans-serif;
@@ -6332,6 +6536,8 @@ var THEME_CSS = `
6332
6536
  --rb-panel-shadow: 0 28px 80px rgba(4, 6, 12, 0.55);
6333
6537
  --rb-surface: rgba(11, 14, 21, 0.55);
6334
6538
  --rb-field-bg: rgba(11, 14, 21, 0.85);
6539
+ /* Opaque on purpose - see optionStyle. */
6540
+ --rb-menu-bg: #0b0e15;
6335
6541
  --rb-accent: var(--rb-coral);
6336
6542
  --rb-accent-contrast: #0b0e15;
6337
6543
  --rb-link: var(--rb-cyan);
@@ -6356,6 +6562,7 @@ var THEME_CSS = `
6356
6562
  --rb-panel-shadow: 0 28px 80px rgba(20, 27, 46, 0.18);
6357
6563
  --rb-surface: rgba(20, 27, 46, 0.04);
6358
6564
  --rb-field-bg: #ffffff;
6565
+ --rb-menu-bg: #ffffff;
6359
6566
  --rb-accent-contrast: #ffffff;
6360
6567
  --rb-launcher-start: #ffffff;
6361
6568
  --rb-launcher-end: #f2f5fa;
@@ -6399,6 +6606,10 @@ var fieldStyle = {
6399
6606
  fontSize: "0.8125rem",
6400
6607
  lineHeight: 1.4
6401
6608
  };
6609
+ var optionStyle = {
6610
+ background: "var(--rb-menu-bg)",
6611
+ color: "var(--rb-text)"
6612
+ };
6402
6613
  var secondaryButtonStyle = {
6403
6614
  borderRadius: "0.5rem",
6404
6615
  border: "1px solid var(--rb-border)",
@@ -6433,6 +6644,53 @@ var containedContentStyle = {
6433
6644
  wordBreak: "break-word",
6434
6645
  whiteSpace: "normal"
6435
6646
  };
6647
+ var tabBarStyle = {
6648
+ display: "flex",
6649
+ gap: "0.35rem",
6650
+ margin: "0.55rem 0 0.5rem",
6651
+ borderBottom: "1px solid var(--rb-border)"
6652
+ };
6653
+ var tabStyle = (active) => ({
6654
+ border: 0,
6655
+ borderBottom: `2px solid ${active ? "var(--rb-accent)" : "transparent"}`,
6656
+ background: "transparent",
6657
+ color: active ? "var(--rb-text)" : "var(--rb-muted)",
6658
+ padding: "0.35rem 0.6rem",
6659
+ fontFamily: "var(--rb-font-mono, monospace)",
6660
+ fontSize: "0.6875rem",
6661
+ fontWeight: 700,
6662
+ textTransform: "uppercase",
6663
+ letterSpacing: "0.06em",
6664
+ cursor: "pointer"
6665
+ });
6666
+ var addressRowStyle = {
6667
+ display: "flex",
6668
+ alignItems: "center",
6669
+ justifyContent: "space-between",
6670
+ gap: "0.5rem",
6671
+ padding: "0.25rem 0",
6672
+ borderTop: "1px solid var(--rb-border)"
6673
+ };
6674
+ var payloadStyle = {
6675
+ maxHeight: "20rem",
6676
+ overflow: "auto",
6677
+ padding: "0.5rem",
6678
+ border: "1px solid var(--rb-border)",
6679
+ borderRadius: "0.5rem",
6680
+ fontFamily: "var(--rb-font-mono, monospace)",
6681
+ fontSize: "0.6875rem",
6682
+ lineHeight: 1.5
6683
+ };
6684
+ function addressTabLabel(addresses) {
6685
+ if (!addresses?.groups.length && addresses?.pwaEnv) return "Endpoints";
6686
+ return "Multiaddresses";
6687
+ }
6688
+ function copyAllText(addresses) {
6689
+ return addresses.groups.flatMap((group) => group.addresses).join("\n");
6690
+ }
6691
+ function pwaEnvText(addresses) {
6692
+ return Object.entries(addresses.pwaEnv ?? {}).map(([key, value]) => `${key}=${value}`).join("\n");
6693
+ }
6436
6694
  var dangerButtonStyle = {
6437
6695
  borderRadius: "0.5rem",
6438
6696
  border: "1px solid rgba(255, 77, 106, 0.45)",
@@ -6614,12 +6872,19 @@ function SponsorRelayFab(props) {
6614
6872
  (state.bootstrapRegistrations ?? []).filter((entry) => entry.confirmed && entry.instanceItemHash).map((entry) => [entry.instanceItemHash, entry])
6615
6873
  );
6616
6874
  const orphanRegistrations = state.orphanBootstrapRegistrations ?? [];
6617
- const [successFlash, setSuccessFlash] = React.useState(false);
6618
- const [hovered, setHovered] = React.useState(false);
6619
- const launcherRef = React.useRef(null);
6620
- const [inlinePanelStyle, setInlinePanelStyle] = React.useState(null);
6621
- const [compactInlineLabel, setCompactInlineLabel] = React.useState(false);
6622
- React.useEffect(() => {
6875
+ const [successFlash, setSuccessFlash] = React2.useState(false);
6876
+ const [hovered, setHovered] = React2.useState(false);
6877
+ const [instanceTabs, setInstanceTabs] = React2.useState({});
6878
+ const selectInstanceTab = (itemHash, tab) => {
6879
+ setInstanceTabs((current) => ({ ...current, [itemHash]: tab }));
6880
+ if (tab !== "general") {
6881
+ void controller.loadInstanceAddresses(itemHash);
6882
+ }
6883
+ };
6884
+ const launcherRef = React2.useRef(null);
6885
+ const [inlinePanelStyle, setInlinePanelStyle] = React2.useState(null);
6886
+ const [compactInlineLabel, setCompactInlineLabel] = React2.useState(false);
6887
+ React2.useEffect(() => {
6623
6888
  if (state.deploymentProgress.stage !== "completed" || state.deploymentProgress.status !== "success") {
6624
6889
  return;
6625
6890
  }
@@ -6635,7 +6900,7 @@ function SponsorRelayFab(props) {
6635
6900
  state.deploymentProgress.status,
6636
6901
  state.deploymentProgress.timestamp
6637
6902
  ]);
6638
- React.useEffect(() => {
6903
+ React2.useEffect(() => {
6639
6904
  if (state.deploymentProgress.stage !== "completed") {
6640
6905
  return;
6641
6906
  }
@@ -6646,7 +6911,7 @@ function SponsorRelayFab(props) {
6646
6911
  window.clearTimeout(timeout);
6647
6912
  };
6648
6913
  }, [state.deploymentProgress.stage, state.deploymentProgress.timestamp]);
6649
- React.useEffect(() => {
6914
+ React2.useEffect(() => {
6650
6915
  if (launcherMode !== "inline" || !state.open) {
6651
6916
  return;
6652
6917
  }
@@ -6676,7 +6941,7 @@ function SponsorRelayFab(props) {
6676
6941
  window.removeEventListener("scroll", updateInlinePanelStyle, true);
6677
6942
  };
6678
6943
  }, [launcherMode, state.open]);
6679
- React.useEffect(() => {
6944
+ React2.useEffect(() => {
6680
6945
  if (launcherMode !== "inline") {
6681
6946
  setCompactInlineLabel(false);
6682
6947
  return;
@@ -6715,7 +6980,7 @@ function SponsorRelayFab(props) {
6715
6980
  const rootfsBlocked = state.rootfsHealth.tone === "error";
6716
6981
  const deployCallToAction = state.wallet.connected ? state.busy.deploying ? "Deploying\u2026" : rootfsBlocked ? "Deployment blocked \u2014 Rootfs unavailable" : deploymentButtonLabel(state) : "Connect MetaMask";
6717
6982
  return /* @__PURE__ */ jsxs(Fragment, { children: [
6718
- /* @__PURE__ */ jsx("style", { children: THEME_CSS }),
6983
+ /* @__PURE__ */ jsx2("style", { children: THEME_CSS }),
6719
6984
  /* @__PURE__ */ jsxs(
6720
6985
  "button",
6721
6986
  {
@@ -6773,7 +7038,7 @@ function SponsorRelayFab(props) {
6773
7038
  flex: "none"
6774
7039
  },
6775
7040
  children: [
6776
- /* @__PURE__ */ jsx(
7041
+ /* @__PURE__ */ jsx2(
6777
7042
  "line",
6778
7043
  {
6779
7044
  x1: "17",
@@ -6785,8 +7050,8 @@ function SponsorRelayFab(props) {
6785
7050
  strokeLinecap: "round"
6786
7051
  }
6787
7052
  ),
6788
- /* @__PURE__ */ jsx("circle", { cx: "11.5", cy: "20.5", r: "7", fill: "var(--rb-coral)" }),
6789
- /* @__PURE__ */ jsx(
7053
+ /* @__PURE__ */ jsx2("circle", { cx: "11.5", cy: "20.5", r: "7", fill: "var(--rb-coral)" }),
7054
+ /* @__PURE__ */ jsx2(
6790
7055
  "circle",
6791
7056
  {
6792
7057
  cx: "23.5",
@@ -6800,7 +7065,7 @@ function SponsorRelayFab(props) {
6800
7065
  ]
6801
7066
  }
6802
7067
  ),
6803
- /* @__PURE__ */ jsx("span", { children: launcherLabel })
7068
+ /* @__PURE__ */ jsx2("span", { children: launcherLabel })
6804
7069
  ]
6805
7070
  }
6806
7071
  ),
@@ -6824,7 +7089,7 @@ function SponsorRelayFab(props) {
6824
7089
  boxShadow: launcherMode === "floating" ? void 0 : `inset 0 1px 0 rgba(255,255,255,0.08), 0 6px 16px ${progressToneColor(indicator.tone)}22`
6825
7090
  },
6826
7091
  children: [
6827
- /* @__PURE__ */ jsx(
7092
+ /* @__PURE__ */ jsx2(
6828
7093
  "span",
6829
7094
  {
6830
7095
  "aria-hidden": "true",
@@ -6840,7 +7105,7 @@ function SponsorRelayFab(props) {
6840
7105
  }
6841
7106
  }
6842
7107
  ),
6843
- /* @__PURE__ */ jsx("span", { children: indicator.label })
7108
+ /* @__PURE__ */ jsx2("span", { children: indicator.label })
6844
7109
  ]
6845
7110
  }
6846
7111
  )
@@ -6848,7 +7113,7 @@ function SponsorRelayFab(props) {
6848
7113
  }
6849
7114
  ),
6850
7115
  state.open ? /* @__PURE__ */ jsxs("div", { children: [
6851
- /* @__PURE__ */ jsx(
7116
+ /* @__PURE__ */ jsx2(
6852
7117
  "div",
6853
7118
  {
6854
7119
  onClick: () => controller.setOpen(false),
@@ -6887,8 +7152,8 @@ function SponsorRelayFab(props) {
6887
7152
  letterSpacing: "0.08em"
6888
7153
  },
6889
7154
  children: [
6890
- /* @__PURE__ */ jsx("span", { children: "Aleph VM credit deployer" }),
6891
- /* @__PURE__ */ jsx(
7155
+ /* @__PURE__ */ jsx2("span", { children: "Aleph VM credit deployer" }),
7156
+ /* @__PURE__ */ jsx2(
6892
7157
  "span",
6893
7158
  {
6894
7159
  style: {
@@ -6904,7 +7169,7 @@ function SponsorRelayFab(props) {
6904
7169
  ]
6905
7170
  }
6906
7171
  ),
6907
- /* @__PURE__ */ jsx(
7172
+ /* @__PURE__ */ jsx2(
6908
7173
  "h2",
6909
7174
  {
6910
7175
  style: {
@@ -6917,7 +7182,7 @@ function SponsorRelayFab(props) {
6917
7182
  }
6918
7183
  )
6919
7184
  ] }),
6920
- /* @__PURE__ */ jsx(
7185
+ /* @__PURE__ */ jsx2(
6921
7186
  "button",
6922
7187
  {
6923
7188
  type: "button",
@@ -6929,8 +7194,8 @@ function SponsorRelayFab(props) {
6929
7194
  ]
6930
7195
  }
6931
7196
  ),
6932
- /* @__PURE__ */ jsx("p", { style: { color: "var(--rb-muted)" }, children: state.statusText }),
6933
- state.errorText ? /* @__PURE__ */ jsx("p", { style: { color: "var(--rb-danger)" }, children: state.errorText }) : null,
7197
+ /* @__PURE__ */ jsx2("p", { style: { color: "var(--rb-muted)" }, children: state.statusText }),
7198
+ state.errorText ? /* @__PURE__ */ jsx2("p", { style: { color: "var(--rb-danger)" }, children: state.errorText }) : null,
6934
7199
  pollingState ? /* @__PURE__ */ jsxs(
6935
7200
  "div",
6936
7201
  {
@@ -6955,7 +7220,7 @@ function SponsorRelayFab(props) {
6955
7220
  gap: "0.45rem"
6956
7221
  },
6957
7222
  children: [
6958
- /* @__PURE__ */ jsx(
7223
+ /* @__PURE__ */ jsx2(
6959
7224
  "span",
6960
7225
  {
6961
7226
  "aria-hidden": "true",
@@ -6969,11 +7234,11 @@ function SponsorRelayFab(props) {
6969
7234
  }
6970
7235
  }
6971
7236
  ),
6972
- /* @__PURE__ */ jsx("strong", { style: { fontSize: "0.88rem" }, children: pollingState.label })
7237
+ /* @__PURE__ */ jsx2("strong", { style: { fontSize: "0.88rem" }, children: pollingState.label })
6973
7238
  ]
6974
7239
  }
6975
7240
  ),
6976
- /* @__PURE__ */ jsx("small", { style: { color: "var(--rb-muted)", lineHeight: 1.35 }, children: pollingState.detail })
7241
+ /* @__PURE__ */ jsx2("small", { style: { color: "var(--rb-muted)", lineHeight: 1.35 }, children: pollingState.detail })
6977
7242
  ]
6978
7243
  }
6979
7244
  ) : null,
@@ -7008,7 +7273,7 @@ function SponsorRelayFab(props) {
7008
7273
  minWidth: 0
7009
7274
  },
7010
7275
  children: [
7011
- /* @__PURE__ */ jsx(
7276
+ /* @__PURE__ */ jsx2(
7012
7277
  "span",
7013
7278
  {
7014
7279
  style: {
@@ -7030,7 +7295,7 @@ function SponsorRelayFab(props) {
7030
7295
  children: progressBadgeLabel(state.deploymentProgress.stage)
7031
7296
  }
7032
7297
  ),
7033
- /* @__PURE__ */ jsx(
7298
+ /* @__PURE__ */ jsx2(
7034
7299
  "strong",
7035
7300
  {
7036
7301
  style: {
@@ -7065,7 +7330,7 @@ function SponsorRelayFab(props) {
7065
7330
  ]
7066
7331
  }
7067
7332
  ),
7068
- /* @__PURE__ */ jsx(
7333
+ /* @__PURE__ */ jsx2(
7069
7334
  "div",
7070
7335
  {
7071
7336
  style: {
@@ -7076,7 +7341,7 @@ function SponsorRelayFab(props) {
7076
7341
  background: "rgba(168, 179, 199, 0.18)",
7077
7342
  overflow: "hidden"
7078
7343
  },
7079
- children: /* @__PURE__ */ jsx(
7344
+ children: /* @__PURE__ */ jsx2(
7080
7345
  "div",
7081
7346
  {
7082
7347
  style: {
@@ -7118,7 +7383,7 @@ function SponsorRelayFab(props) {
7118
7383
  ]
7119
7384
  }
7120
7385
  ) : null,
7121
- state.deploymentProgress.detail ? /* @__PURE__ */ jsx(
7386
+ state.deploymentProgress.detail ? /* @__PURE__ */ jsx2(
7122
7387
  "div",
7123
7388
  {
7124
7389
  style: {
@@ -7130,7 +7395,7 @@ function SponsorRelayFab(props) {
7130
7395
  children: state.deploymentProgress.detail
7131
7396
  }
7132
7397
  ) : null,
7133
- state.deploymentProgress.error ? /* @__PURE__ */ jsx(
7398
+ state.deploymentProgress.error ? /* @__PURE__ */ jsx2(
7134
7399
  "div",
7135
7400
  {
7136
7401
  style: {
@@ -7152,7 +7417,7 @@ function SponsorRelayFab(props) {
7152
7417
  {
7153
7418
  style: { display: "grid", gap: "0.75rem", marginTop: "0.9rem" },
7154
7419
  children: [
7155
- /* @__PURE__ */ jsx(
7420
+ /* @__PURE__ */ jsx2(
7156
7421
  "input",
7157
7422
  {
7158
7423
  style: fieldStyle,
@@ -7161,7 +7426,7 @@ function SponsorRelayFab(props) {
7161
7426
  placeholder: "Instance name"
7162
7427
  }
7163
7428
  ),
7164
- /* @__PURE__ */ jsx(
7429
+ /* @__PURE__ */ jsx2(
7165
7430
  "select",
7166
7431
  {
7167
7432
  style: fieldStyle,
@@ -7172,11 +7437,11 @@ function SponsorRelayFab(props) {
7172
7437
  const vcpus = unit ? unit.vcpus * tier.compute_units : null;
7173
7438
  const memoryMiB = unit ? unit.memory_mib * tier.compute_units : null;
7174
7439
  const diskMiB = unit ? unit.disk_mib * tier.compute_units : null;
7175
- return /* @__PURE__ */ jsx("option", { value: tier.id, children: `${tier.id} ${formatTierSpecLabel(vcpus, memoryMiB, diskMiB)}` }, tier.id);
7440
+ return /* @__PURE__ */ jsx2("option", { style: optionStyle, value: tier.id, children: `${tier.id} ${formatTierSpecLabel(vcpus, memoryMiB, diskMiB)}` }, tier.id);
7176
7441
  })
7177
7442
  }
7178
7443
  ),
7179
- /* @__PURE__ */ jsx(
7444
+ /* @__PURE__ */ jsx2(
7180
7445
  "div",
7181
7446
  {
7182
7447
  style: {
@@ -7200,7 +7465,7 @@ function SponsorRelayFab(props) {
7200
7465
  event.currentTarget.open
7201
7466
  ),
7202
7467
  children: [
7203
- /* @__PURE__ */ jsx("summary", { children: "Advanced" }),
7468
+ /* @__PURE__ */ jsx2("summary", { children: "Advanced" }),
7204
7469
  /* @__PURE__ */ jsxs(
7205
7470
  "div",
7206
7471
  {
@@ -7210,7 +7475,7 @@ function SponsorRelayFab(props) {
7210
7475
  marginTop: "0.65rem"
7211
7476
  },
7212
7477
  children: [
7213
- /* @__PURE__ */ jsx(
7478
+ /* @__PURE__ */ jsx2(
7214
7479
  "input",
7215
7480
  {
7216
7481
  style: fieldStyle,
@@ -7219,7 +7484,7 @@ function SponsorRelayFab(props) {
7219
7484
  placeholder: "Manifest URL"
7220
7485
  }
7221
7486
  ),
7222
- /* @__PURE__ */ jsx(
7487
+ /* @__PURE__ */ jsx2(
7223
7488
  "textarea",
7224
7489
  {
7225
7490
  style: fieldStyle,
@@ -7237,8 +7502,8 @@ function SponsorRelayFab(props) {
7237
7502
  event.currentTarget.open
7238
7503
  ),
7239
7504
  children: [
7240
- /* @__PURE__ */ jsx("summary", { children: "Paste Manifest" }),
7241
- /* @__PURE__ */ jsx(
7505
+ /* @__PURE__ */ jsx2("summary", { children: "Paste Manifest" }),
7506
+ /* @__PURE__ */ jsx2(
7242
7507
  "textarea",
7243
7508
  {
7244
7509
  style: { ...fieldStyle, marginTop: "0.65rem" },
@@ -7251,7 +7516,7 @@ function SponsorRelayFab(props) {
7251
7516
  }
7252
7517
  ),
7253
7518
  stateDeploymentProfile(state) === "ucan-store" ? /* @__PURE__ */ jsxs("details", { open: true, children: [
7254
- /* @__PURE__ */ jsx("summary", { children: "UCAN Store Bootstrap" }),
7519
+ /* @__PURE__ */ jsx2("summary", { children: "UCAN Store Bootstrap" }),
7255
7520
  /* @__PURE__ */ jsxs(
7256
7521
  "div",
7257
7522
  {
@@ -7261,7 +7526,7 @@ function SponsorRelayFab(props) {
7261
7526
  marginTop: "0.65rem"
7262
7527
  },
7263
7528
  children: [
7264
- /* @__PURE__ */ jsx(
7529
+ /* @__PURE__ */ jsx2(
7265
7530
  "input",
7266
7531
  {
7267
7532
  style: fieldStyle,
@@ -7273,7 +7538,7 @@ function SponsorRelayFab(props) {
7273
7538
  placeholder: "Admin DID"
7274
7539
  }
7275
7540
  ),
7276
- /* @__PURE__ */ jsx(
7541
+ /* @__PURE__ */ jsx2(
7277
7542
  "input",
7278
7543
  {
7279
7544
  style: fieldStyle,
@@ -7285,7 +7550,7 @@ function SponsorRelayFab(props) {
7285
7550
  placeholder: "Service DID override (optional)"
7286
7551
  }
7287
7552
  ),
7288
- /* @__PURE__ */ jsx(
7553
+ /* @__PURE__ */ jsx2(
7289
7554
  "input",
7290
7555
  {
7291
7556
  style: fieldStyle,
@@ -7297,7 +7562,7 @@ function SponsorRelayFab(props) {
7297
7562
  placeholder: "Space DID"
7298
7563
  }
7299
7564
  ),
7300
- /* @__PURE__ */ jsx(
7565
+ /* @__PURE__ */ jsx2(
7301
7566
  "textarea",
7302
7567
  {
7303
7568
  style: fieldStyle,
@@ -7310,7 +7575,7 @@ function SponsorRelayFab(props) {
7310
7575
  placeholder: "Root delegation proof"
7311
7576
  }
7312
7577
  ),
7313
- /* @__PURE__ */ jsx(
7578
+ /* @__PURE__ */ jsx2(
7314
7579
  "textarea",
7315
7580
  {
7316
7581
  style: fieldStyle,
@@ -7332,7 +7597,7 @@ function SponsorRelayFab(props) {
7332
7597
  gridTemplateColumns: "repeat(auto-fit, minmax(10rem, 1fr))"
7333
7598
  },
7334
7599
  children: [
7335
- /* @__PURE__ */ jsx(
7600
+ /* @__PURE__ */ jsx2(
7336
7601
  "input",
7337
7602
  {
7338
7603
  style: fieldStyle,
@@ -7344,7 +7609,7 @@ function SponsorRelayFab(props) {
7344
7609
  placeholder: "Default expiration (seconds)"
7345
7610
  }
7346
7611
  ),
7347
- /* @__PURE__ */ jsx(
7612
+ /* @__PURE__ */ jsx2(
7348
7613
  "input",
7349
7614
  {
7350
7615
  style: fieldStyle,
@@ -7359,7 +7624,7 @@ function SponsorRelayFab(props) {
7359
7624
  ]
7360
7625
  }
7361
7626
  ),
7362
- /* @__PURE__ */ jsx(
7627
+ /* @__PURE__ */ jsx2(
7363
7628
  "input",
7364
7629
  {
7365
7630
  style: fieldStyle,
@@ -7371,7 +7636,7 @@ function SponsorRelayFab(props) {
7371
7636
  placeholder: "PWA origin override (optional, defaults to current page origin)"
7372
7637
  }
7373
7638
  ),
7374
- /* @__PURE__ */ jsx(
7639
+ /* @__PURE__ */ jsx2(
7375
7640
  "input",
7376
7641
  {
7377
7642
  style: fieldStyle,
@@ -7383,7 +7648,7 @@ function SponsorRelayFab(props) {
7383
7648
  placeholder: "Service origin override (optional, defaults to runtime proxy URL)"
7384
7649
  }
7385
7650
  ),
7386
- /* @__PURE__ */ jsx(
7651
+ /* @__PURE__ */ jsx2(
7387
7652
  "div",
7388
7653
  {
7389
7654
  style: {
@@ -7417,20 +7682,21 @@ function SponsorRelayFab(props) {
7417
7682
  formatNumber(state.pricingSummary.requiredCredits, 0),
7418
7683
  " credits required"
7419
7684
  ] }),
7420
- /* @__PURE__ */ jsx("div", { children: state.rootfsHealth.label }),
7421
- /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs(
7685
+ /* @__PURE__ */ jsx2("div", { children: state.rootfsHealth.label }),
7686
+ /* @__PURE__ */ jsx2("div", { children: /* @__PURE__ */ jsxs(
7422
7687
  "select",
7423
7688
  {
7689
+ style: fieldStyle,
7424
7690
  "aria-label": "Select CRN",
7425
7691
  value: state.crnPinnedByUser ? state.selectedCrn?.hash ?? "" : "",
7426
7692
  onChange: (event) => controller.selectCrn(event.currentTarget.value || null),
7427
7693
  children: [
7428
- /* @__PURE__ */ jsxs("option", { value: "", children: [
7694
+ /* @__PURE__ */ jsxs("option", { style: optionStyle, value: "", children: [
7429
7695
  "Auto (",
7430
7696
  state.crnOptions[0]?.name ?? "best score",
7431
7697
  ")"
7432
7698
  ] }),
7433
- state.crnOptions.map((option) => /* @__PURE__ */ jsx("option", { value: option.hash, children: (option.name ?? option.hash.slice(0, 8)) + (option.score != null ? ` \xB7 ${option.score.toFixed(2)}` : "") }, option.hash))
7699
+ state.crnOptions.map((option) => /* @__PURE__ */ jsx2("option", { style: optionStyle, value: option.hash, children: (option.name ?? option.hash.slice(0, 8)) + (option.score != null ? ` \xB7 ${option.score.toFixed(2)}` : "") }, option.hash))
7434
7700
  ]
7435
7701
  }
7436
7702
  ) }),
@@ -7458,11 +7724,11 @@ function SponsorRelayFab(props) {
7458
7724
  color: "var(--rb-text)"
7459
7725
  },
7460
7726
  children: [
7461
- /* @__PURE__ */ jsx("strong", { children: "Rootfs unavailable \u2014 deployment blocked" }),
7462
- /* @__PURE__ */ jsx("span", { style: { fontSize: "0.82rem", lineHeight: 1.45 }, children: state.rootfsHealth.detail }),
7727
+ /* @__PURE__ */ jsx2("strong", { children: "Rootfs unavailable \u2014 deployment blocked" }),
7728
+ /* @__PURE__ */ jsx2("span", { style: { fontSize: "0.82rem", lineHeight: 1.45 }, children: state.rootfsHealth.detail }),
7463
7729
  /* @__PURE__ */ jsxs("span", { style: { fontSize: "0.75rem", lineHeight: 1.4 }, children: [
7464
7730
  "This is separate from the connected MetaMask balance. The manifest must reference an Aleph rootfs STORE with status ",
7465
- /* @__PURE__ */ jsx("code", { children: "processed" }),
7731
+ /* @__PURE__ */ jsx2("code", { children: "processed" }),
7466
7732
  "."
7467
7733
  ] }),
7468
7734
  state.manifest?.rootfsItemHash ? /* @__PURE__ */ jsxs("code", { style: { fontSize: "0.7rem", overflowWrap: "anywhere" }, children: [
@@ -7471,14 +7737,14 @@ function SponsorRelayFab(props) {
7471
7737
  state.rootfsResolution?.messageStatus ? ` \xB7 Aleph status: ${state.rootfsResolution.messageStatus}` : ""
7472
7738
  ] }) : null,
7473
7739
  /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexWrap: "wrap", gap: "0.5rem" }, children: [
7474
- /* @__PURE__ */ jsx("button", { type: "button", onClick: () => void controller.refresh(), disabled: state.busy.refreshing, style: { ...secondaryButtonStyle, padding: "0.55rem 0.7rem" }, children: state.busy.refreshing ? "Checking\u2026" : "Retry validation" }),
7475
- /* @__PURE__ */ jsx("button", { type: "button", onClick: () => controller.setShowAdvanced(true), style: { ...secondaryButtonStyle, padding: "0.55rem 0.7rem" }, children: "Edit manifest URL" }),
7476
- /^https?:\/\//.test(state.manifestUrl) ? /* @__PURE__ */ jsx("a", { href: state.manifestUrl, target: "_blank", rel: "noreferrer", style: { color: "var(--rb-link)", alignSelf: "center", fontSize: "0.78rem" }, children: "Open manifest" }) : null
7740
+ /* @__PURE__ */ jsx2("button", { type: "button", onClick: () => void controller.refresh(), disabled: state.busy.refreshing, style: { ...secondaryButtonStyle, padding: "0.55rem 0.7rem" }, children: state.busy.refreshing ? "Checking\u2026" : "Retry validation" }),
7741
+ /* @__PURE__ */ jsx2("button", { type: "button", onClick: () => controller.setShowAdvanced(true), style: { ...secondaryButtonStyle, padding: "0.55rem 0.7rem" }, children: "Edit manifest URL" }),
7742
+ /^https?:\/\//.test(state.manifestUrl) ? /* @__PURE__ */ jsx2("a", { href: state.manifestUrl, target: "_blank", rel: "noreferrer", style: { color: "var(--rb-link)", alignSelf: "center", fontSize: "0.78rem" }, children: "Open manifest" }) : null
7477
7743
  ] })
7478
7744
  ]
7479
7745
  }
7480
7746
  ) : null,
7481
- /* @__PURE__ */ jsx(
7747
+ /* @__PURE__ */ jsx2(
7482
7748
  "button",
7483
7749
  {
7484
7750
  type: "button",
@@ -7518,7 +7784,7 @@ function SponsorRelayFab(props) {
7518
7784
  open: true,
7519
7785
  style: containedContentStyle,
7520
7786
  children: [
7521
- /* @__PURE__ */ jsx("summary", { style: containedContentStyle, children: /* @__PURE__ */ jsxs(
7787
+ /* @__PURE__ */ jsx2("summary", { style: containedContentStyle, children: /* @__PURE__ */ jsxs(
7522
7788
  "span",
7523
7789
  {
7524
7790
  style: {
@@ -7544,7 +7810,7 @@ function SponsorRelayFab(props) {
7544
7810
  fontWeight: 700
7545
7811
  },
7546
7812
  children: [
7547
- /* @__PURE__ */ jsx(
7813
+ /* @__PURE__ */ jsx2(
7548
7814
  "span",
7549
7815
  {
7550
7816
  "aria-hidden": "true",
@@ -7574,57 +7840,264 @@ function SponsorRelayFab(props) {
7574
7840
  marginTop: "0.55rem"
7575
7841
  },
7576
7842
  children: [
7577
- /* @__PURE__ */ jsxs("div", { children: [
7578
- "Status: ",
7579
- entry.details.messageStatus
7580
- ] }),
7581
- bootstrapUiEnabled && confirmedRegistration ? /* @__PURE__ */ jsxs("div", { children: [
7582
- "Bootstrap registration:",
7583
- " ",
7584
- shortHash(
7585
- confirmedRegistration.messageHash ?? confirmedRegistration.content?.registrationId ?? "confirmed",
7586
- 14,
7587
- 8
7588
- )
7589
- ] }) : null,
7590
- /* @__PURE__ */ jsxs("div", { children: [
7591
- "Host IPv4: ",
7592
- entry.details.hostIpv4 ?? "-"
7593
- ] }),
7594
- /* @__PURE__ */ jsxs("div", { children: [
7595
- "IPv6: ",
7596
- entry.details.ipv6 ?? "-"
7597
- ] }),
7598
- /* @__PURE__ */ jsxs("div", { children: [
7599
- "VM IPv4: ",
7600
- entry.details.vmIpv4 ?? "-"
7601
- ] }),
7602
- /* @__PURE__ */ jsxs("div", { children: [
7603
- "SSH: ",
7604
- entry.details.sshCommand ?? "-"
7605
- ] }),
7606
- /* @__PURE__ */ jsxs("div", { children: [
7607
- "Ports: ",
7608
- joinMappedPorts(entry.details.mappedPorts)
7609
- ] }),
7610
- /* @__PURE__ */ jsxs("div", { children: [
7611
- "Submitted:",
7612
- " ",
7613
- formatDateTime(
7614
- entry.instance.reception_time ?? entry.instance.time
7843
+ (() => {
7844
+ const itemHash = entry.instance.item_hash;
7845
+ const tab = instanceTabs[itemHash] ?? "general";
7846
+ const addresses = state.instanceAddresses?.[itemHash] ?? null;
7847
+ const refreshRow = /* @__PURE__ */ jsxs(
7848
+ "div",
7849
+ {
7850
+ style: {
7851
+ display: "flex",
7852
+ alignItems: "center",
7853
+ justifyContent: "space-between",
7854
+ gap: "0.5rem",
7855
+ marginBottom: "0.5rem"
7856
+ },
7857
+ children: [
7858
+ /* @__PURE__ */ jsx2(
7859
+ "span",
7860
+ {
7861
+ style: {
7862
+ color: "var(--rb-muted)",
7863
+ fontSize: "0.6875rem",
7864
+ overflowWrap: "anywhere"
7865
+ },
7866
+ children: addresses?.sourceUrl ?? "Reading from the deployment"
7867
+ }
7868
+ ),
7869
+ /* @__PURE__ */ jsx2(
7870
+ "button",
7871
+ {
7872
+ type: "button",
7873
+ style: secondaryButtonStyle,
7874
+ disabled: addresses?.status === "loading",
7875
+ onClick: () => void controller.loadInstanceAddresses(
7876
+ itemHash,
7877
+ { force: true }
7878
+ ),
7879
+ children: addresses?.status === "loading" ? "Loading\u2026" : "Refresh"
7880
+ }
7881
+ )
7882
+ ]
7883
+ }
7884
+ );
7885
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
7886
+ /* @__PURE__ */ jsx2("div", { style: tabBarStyle, role: "tablist", children: [
7887
+ ["general", "General"],
7888
+ ["addresses", addressTabLabel(addresses)],
7889
+ ["health", "Health"]
7890
+ ].map(([key, label]) => /* @__PURE__ */ jsx2(
7891
+ "button",
7892
+ {
7893
+ type: "button",
7894
+ role: "tab",
7895
+ "aria-selected": tab === key,
7896
+ style: tabStyle(tab === key),
7897
+ onClick: () => selectInstanceTab(itemHash, key),
7898
+ children: label
7899
+ },
7900
+ key
7901
+ )) }),
7902
+ tab === "addresses" ? /* @__PURE__ */ jsxs("div", { style: containedContentStyle, children: [
7903
+ refreshRow,
7904
+ addresses?.status === "loading" && !addresses.groups.length ? /* @__PURE__ */ jsx2("div", { children: "Reading the deployment's address document\u2026" }) : addresses?.status === "unsupported" || addresses?.status === "error" ? /* @__PURE__ */ jsx2("div", { children: addresses.error }) : addresses?.groups.length ? /* @__PURE__ */ jsxs(Fragment, { children: [
7905
+ addresses.peerId ? /* @__PURE__ */ jsxs("div", { style: addressRowStyle, children: [
7906
+ /* @__PURE__ */ jsx2("code", { children: addresses.peerId }),
7907
+ /* @__PURE__ */ jsx2(CopyButton, { text: addresses.peerId })
7908
+ ] }) : null,
7909
+ addresses.groups.map((group) => /* @__PURE__ */ jsxs(
7910
+ "div",
7911
+ {
7912
+ style: { marginBottom: "0.75rem" },
7913
+ children: [
7914
+ /* @__PURE__ */ jsxs(
7915
+ "div",
7916
+ {
7917
+ style: {
7918
+ display: "flex",
7919
+ alignItems: "center",
7920
+ justifyContent: "space-between",
7921
+ gap: "0.5rem"
7922
+ },
7923
+ children: [
7924
+ /* @__PURE__ */ jsx2("strong", { children: group.label }),
7925
+ /* @__PURE__ */ jsx2(
7926
+ CopyButton,
7927
+ {
7928
+ text: group.addresses.join("\n"),
7929
+ label: "Copy group"
7930
+ }
7931
+ )
7932
+ ]
7933
+ }
7934
+ ),
7935
+ group.addresses.map((address) => /* @__PURE__ */ jsxs(
7936
+ "div",
7937
+ {
7938
+ style: addressRowStyle,
7939
+ children: [
7940
+ /* @__PURE__ */ jsx2("code", { children: address }),
7941
+ /* @__PURE__ */ jsx2(CopyButton, { text: address })
7942
+ ]
7943
+ },
7944
+ address
7945
+ ))
7946
+ ]
7947
+ },
7948
+ group.key
7949
+ )),
7950
+ /* @__PURE__ */ jsxs(
7951
+ "div",
7952
+ {
7953
+ style: { display: "flex", gap: "0.5rem" },
7954
+ children: [
7955
+ /* @__PURE__ */ jsx2(
7956
+ CopyButton,
7957
+ {
7958
+ text: copyAllText(addresses),
7959
+ label: "Copy all"
7960
+ }
7961
+ ),
7962
+ /* @__PURE__ */ jsx2(
7963
+ CopyButton,
7964
+ {
7965
+ text: JSON.stringify(
7966
+ addresses.payload,
7967
+ null,
7968
+ 2
7969
+ ),
7970
+ label: "Copy JSON"
7971
+ }
7972
+ )
7973
+ ]
7974
+ }
7975
+ )
7976
+ ] }) : addresses?.pwaEnv ? /* @__PURE__ */ jsxs(Fragment, { children: [
7977
+ /* @__PURE__ */ jsxs(
7978
+ "div",
7979
+ {
7980
+ style: {
7981
+ display: "flex",
7982
+ alignItems: "center",
7983
+ justifyContent: "space-between",
7984
+ gap: "0.5rem"
7985
+ },
7986
+ children: [
7987
+ /* @__PURE__ */ jsx2("strong", { children: "PWA environment" }),
7988
+ /* @__PURE__ */ jsx2(
7989
+ CopyButton,
7990
+ {
7991
+ text: pwaEnvText(addresses),
7992
+ label: "Copy block"
7993
+ }
7994
+ )
7995
+ ]
7996
+ }
7997
+ ),
7998
+ Object.entries(addresses.pwaEnv).map(
7999
+ ([key, value]) => /* @__PURE__ */ jsxs(
8000
+ "div",
8001
+ {
8002
+ style: addressRowStyle,
8003
+ children: [
8004
+ /* @__PURE__ */ jsx2("code", { children: `${key}=${value}` }),
8005
+ /* @__PURE__ */ jsx2(
8006
+ CopyButton,
8007
+ {
8008
+ text: `${key}=${value}`
8009
+ }
8010
+ )
8011
+ ]
8012
+ },
8013
+ key
8014
+ )
8015
+ )
8016
+ ] }) : /* @__PURE__ */ jsx2("div", { children: "This deployment reports no addresses yet." })
8017
+ ] }) : null,
8018
+ tab === "health" ? /* @__PURE__ */ jsxs("div", { style: containedContentStyle, children: [
8019
+ refreshRow,
8020
+ addresses?.payload ? /* @__PURE__ */ jsxs(Fragment, { children: [
8021
+ /* @__PURE__ */ jsx2("pre", { style: payloadStyle, children: JSON.stringify(
8022
+ addresses.payload,
8023
+ null,
8024
+ 2
8025
+ ) }),
8026
+ /* @__PURE__ */ jsx2(
8027
+ CopyButton,
8028
+ {
8029
+ text: JSON.stringify(
8030
+ addresses.payload,
8031
+ null,
8032
+ 2
8033
+ ),
8034
+ label: "Copy JSON"
8035
+ }
8036
+ )
8037
+ ] }) : addresses?.status === "loading" ? /* @__PURE__ */ jsx2("div", { children: "Reading the deployment's health document\u2026" }) : /* @__PURE__ */ jsx2("div", { children: addresses?.error ?? "No health document read yet." })
8038
+ ] }) : null
8039
+ ] });
8040
+ })(),
8041
+ (instanceTabs[entry.instance.item_hash] ?? "general") !== "general" ? null : /* @__PURE__ */ jsxs(Fragment, { children: [
8042
+ /* @__PURE__ */ jsxs("div", { children: [
8043
+ "Status: ",
8044
+ entry.details.messageStatus
8045
+ ] }),
8046
+ bootstrapUiEnabled && confirmedRegistration ? /* @__PURE__ */ jsxs("div", { children: [
8047
+ "Bootstrap registration:",
8048
+ " ",
8049
+ shortHash(
8050
+ confirmedRegistration.messageHash ?? confirmedRegistration.content?.registrationId ?? "confirmed",
8051
+ 14,
8052
+ 8
8053
+ )
8054
+ ] }) : null,
8055
+ /* @__PURE__ */ jsxs("div", { children: [
8056
+ "Host IPv4: ",
8057
+ entry.details.hostIpv4 ?? "-"
8058
+ ] }),
8059
+ /* @__PURE__ */ jsxs("div", { children: [
8060
+ "IPv6: ",
8061
+ entry.details.ipv6 ?? "-"
8062
+ ] }),
8063
+ /* @__PURE__ */ jsxs("div", { children: [
8064
+ "VM IPv4: ",
8065
+ entry.details.vmIpv4 ?? "-"
8066
+ ] }),
8067
+ /* @__PURE__ */ jsxs("div", { children: [
8068
+ "SSH: ",
8069
+ entry.details.sshCommand ?? "-"
8070
+ ] }),
8071
+ /* @__PURE__ */ jsxs("div", { children: [
8072
+ "Ports: ",
8073
+ joinMappedPorts(entry.details.mappedPorts)
8074
+ ] }),
8075
+ entry.details.proxyHostname ? /* @__PURE__ */ jsxs("div", { style: addressRowStyle, children: [
8076
+ /* @__PURE__ */ jsxs("code", { children: [
8077
+ "Proxy: ",
8078
+ entry.details.proxyHostname
8079
+ ] }),
8080
+ /* @__PURE__ */ jsx2(CopyButton, { text: entry.details.proxyHostname })
8081
+ ] }) : null,
8082
+ /* @__PURE__ */ jsxs("div", { children: [
8083
+ "Submitted:",
8084
+ " ",
8085
+ formatDateTime(
8086
+ entry.instance.reception_time ?? entry.instance.time
8087
+ )
8088
+ ] }),
8089
+ /* @__PURE__ */ jsx2(
8090
+ "button",
8091
+ {
8092
+ type: "button",
8093
+ style: dangerButtonStyle,
8094
+ onClick: () => void controller.deleteInstance(
8095
+ entry.instance.item_hash
8096
+ ),
8097
+ children: state.busy.deletingInstanceHash === entry.instance.item_hash ? "Deleting\u2026" : "Delete"
8098
+ }
7615
8099
  )
7616
- ] }),
7617
- /* @__PURE__ */ jsx(
7618
- "button",
7619
- {
7620
- type: "button",
7621
- style: dangerButtonStyle,
7622
- onClick: () => void controller.deleteInstance(
7623
- entry.instance.item_hash
7624
- ),
7625
- children: state.busy.deletingInstanceHash === entry.instance.item_hash ? "Deleting\u2026" : "Delete"
7626
- }
7627
- )
8100
+ ] })
7628
8101
  ]
7629
8102
  }
7630
8103
  )
@@ -7647,8 +8120,8 @@ function SponsorRelayFab(props) {
7647
8120
  },
7648
8121
  children: [
7649
8122
  /* @__PURE__ */ jsxs("div", { style: { display: "grid", gap: "0.2rem" }, children: [
7650
- /* @__PURE__ */ jsx("strong", { children: "Orphan bootstrap registrations" }),
7651
- /* @__PURE__ */ jsx("small", { style: { color: "var(--rb-muted)", lineHeight: 1.35 }, children: "Current-wallet registrations without a matching instance. Forget them directly from here." })
8123
+ /* @__PURE__ */ jsx2("strong", { children: "Orphan bootstrap registrations" }),
8124
+ /* @__PURE__ */ jsx2("small", { style: { color: "var(--rb-muted)", lineHeight: 1.35 }, children: "Current-wallet registrations without a matching instance. Forget them directly from here." })
7652
8125
  ] }),
7653
8126
  orphanRegistrations.map((entry) => {
7654
8127
  const registrationHash = entry.messageHash ?? entry.hash ?? null;
@@ -7665,7 +8138,7 @@ function SponsorRelayFab(props) {
7665
8138
  border: "1px solid var(--rb-border)"
7666
8139
  },
7667
8140
  children: [
7668
- /* @__PURE__ */ jsx(
8141
+ /* @__PURE__ */ jsx2(
7669
8142
  "div",
7670
8143
  {
7671
8144
  style: {
@@ -7694,7 +8167,7 @@ function SponsorRelayFab(props) {
7694
8167
  " ",
7695
8168
  formatDateTime(entry.content?.updatedAt ?? entry.time)
7696
8169
  ] }),
7697
- /* @__PURE__ */ jsx(
8170
+ /* @__PURE__ */ jsx2(
7698
8171
  "button",
7699
8172
  {
7700
8173
  type: "button",