@le-space/ui 0.6.5 → 0.6.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@le-space/ui",
3
- "version": "0.6.5",
3
+ "version": "0.6.6",
4
4
  "description": "Floating Aleph sponsor relay UI components for Svelte and React.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -44,8 +44,8 @@
44
44
  "url": "https://github.com/NiKrause/relay-button/issues"
45
45
  },
46
46
  "dependencies": {
47
- "@le-space/browser": "0.6.5",
48
- "@le-space/core": "0.6.5",
47
+ "@le-space/browser": "0.6.6",
48
+ "@le-space/core": "0.6.6",
49
49
  "viem": "^2.53.1"
50
50
  },
51
51
  "peerDependencies": {
package/react/index.d.ts CHANGED
@@ -211,6 +211,7 @@ interface SponsorRelayProps {
211
211
  launcherMode?: 'floating' | 'inline';
212
212
  version?: string;
213
213
  apiHost?: string;
214
+ apiHosts?: string | readonly string[];
214
215
  crnListUrl?: string;
215
216
  schedulerApiHost?: string;
216
217
  twoN6ApiHost?: string;
package/react/index.js CHANGED
@@ -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.5";
46
+ var UI_PACKAGE_VERSION = "0.6.6";
47
47
 
48
48
  // src/shared/format.ts
49
49
  function shortHash(value, head = 8, tail = 6) {
@@ -135,7 +135,12 @@ async function fetchWithTimeout(input, init = {}, timeoutMs = 15e3) {
135
135
  }
136
136
 
137
137
  // ../browser/src/aleph-api.ts
138
- var DEFAULT_ALEPH_API_HOST = "https://api.aleph.im";
138
+ var DEFAULT_ALEPH_API_HOSTS = [
139
+ "https://api3.aleph.im",
140
+ "https://api2.aleph.im",
141
+ "https://api.aleph.im"
142
+ ];
143
+ var DEFAULT_ALEPH_API_HOST = DEFAULT_ALEPH_API_HOSTS[0] ?? "https://api3.aleph.im";
139
144
  var DEFAULT_CRN_LIST_URL = "https://crns-list.aleph.sh/crns.json";
140
145
  var DEFAULT_ALEPH_SCHEDULER_API_HOST = "https://scheduler.api.aleph.cloud";
141
146
  var DEFAULT_2N6_API_HOST = "https://api.2n6.me";
@@ -805,29 +810,56 @@ function watchWallet(onChange, provider = getEthereumProvider()) {
805
810
  }
806
811
 
807
812
  // ../browser/src/client.ts
813
+ function normalizeApiHost(value) {
814
+ const trimmed = value.trim().replace(/\/+$/u, "");
815
+ return trimmed ? trimmed : null;
816
+ }
817
+ function normalizeApiHosts(input, fallbackApiHost) {
818
+ const rawValues = Array.isArray(input) ? input : typeof input === "string" ? input.split(/[\s,]+/u) : [];
819
+ const hosts = rawValues.map((value) => normalizeApiHost(String(value))).filter((value) => Boolean(value));
820
+ if (hosts.length > 0) return Array.from(new Set(hosts));
821
+ const fallback = normalizeApiHost(fallbackApiHost);
822
+ return fallback ? [fallback] : [...DEFAULT_ALEPH_API_HOSTS];
823
+ }
824
+ async function withApiHostFallback(apiHosts, run) {
825
+ let lastError = null;
826
+ for (let index = 0; index < apiHosts.length; index += 1) {
827
+ const apiHost = apiHosts[index];
828
+ try {
829
+ return await run(apiHost);
830
+ } catch (error) {
831
+ lastError = error;
832
+ if (index >= apiHosts.length - 1) break;
833
+ }
834
+ }
835
+ if (lastError instanceof Error) throw lastError;
836
+ throw new Error(String(lastError));
837
+ }
808
838
  function createAlephBrowserClient(options = {}) {
809
- const apiHost = options.apiHost ?? DEFAULT_ALEPH_API_HOST;
839
+ const apiHosts = options.apiHosts === void 0 && options.apiHost === void 0 ? [...DEFAULT_ALEPH_API_HOSTS] : normalizeApiHosts(options.apiHosts, options.apiHost ?? DEFAULT_ALEPH_API_HOST);
840
+ const apiHost = apiHosts[0] ?? DEFAULT_ALEPH_API_HOST;
810
841
  const crnListUrl = options.crnListUrl ?? DEFAULT_CRN_LIST_URL;
811
842
  const schedulerApiHost = options.schedulerApiHost ?? DEFAULT_ALEPH_SCHEDULER_API_HOST;
812
843
  const twoN6ApiHost = options.twoN6ApiHost ?? DEFAULT_2N6_API_HOST;
813
844
  return {
814
845
  apiHost,
846
+ apiHosts,
815
847
  crnListUrl,
816
848
  schedulerApiHost,
817
849
  fetchBalance(address) {
818
- return fetchBalance(address, apiHost);
850
+ return withApiHostFallback(apiHosts, (host) => fetchBalance(address, host));
819
851
  },
820
852
  fetchCrns() {
821
853
  return fetchCrns(crnListUrl);
822
854
  },
823
855
  fetchInstances(address) {
824
- return fetchInstances(address, apiHost);
856
+ return withApiHostFallback(apiHosts, (host) => fetchInstances(address, host));
825
857
  },
826
858
  fetch2n6WebAccessUrl(itemHash) {
827
859
  return fetch2n6WebAccessUrl(itemHash, twoN6ApiHost);
828
860
  },
829
861
  fetchMessageEnvelope(itemHash) {
830
- return fetchMessageEnvelope(itemHash, apiHost);
862
+ return withApiHostFallback(apiHosts, (host) => fetchMessageEnvelope(itemHash, host));
831
863
  },
832
864
  fetchSchedulerAllocation(itemHash) {
833
865
  return fetchSchedulerAllocation(itemHash, schedulerApiHost);
@@ -842,16 +874,16 @@ function createAlephBrowserClient(options = {}) {
842
874
  return configureOrbitdbRelaySetup(args);
843
875
  },
844
876
  inspectDeploymentResult(itemHash, rootfsRef) {
845
- return inspectDeploymentResult(itemHash, rootfsRef, apiHost);
877
+ return withApiHostFallback(apiHosts, (host) => inspectDeploymentResult(itemHash, rootfsRef, host));
846
878
  },
847
879
  waitForDeploymentResult(itemHash, rootfsRef, attempts, delayMs) {
848
- return waitForDeploymentResult(itemHash, rootfsRef, apiHost, attempts, delayMs);
880
+ return withApiHostFallback(apiHosts, (host) => waitForDeploymentResult(itemHash, rootfsRef, host, attempts, delayMs));
849
881
  },
850
882
  broadcastInstanceMessage(message, sync) {
851
- return broadcastInstanceMessage(message, apiHost, sync);
883
+ return withApiHostFallback(apiHosts, (host) => broadcastInstanceMessage(message, host, sync));
852
884
  },
853
885
  broadcastAlephMessage(message, sync) {
854
- return broadcastAlephMessage(message, apiHost, sync);
886
+ return withApiHostFallback(apiHosts, (host) => broadcastAlephMessage(message, host, sync));
855
887
  }
856
888
  };
857
889
  }
@@ -2487,15 +2519,35 @@ function browserMultiaddrPreference(addr) {
2487
2519
  if (normalized.includes("/ws")) return 4;
2488
2520
  return 5;
2489
2521
  }
2522
+ function browserMultiaddrTransport(addr) {
2523
+ const normalized = addr.toLowerCase();
2524
+ if (normalized.includes("/webtransport/")) return "webtransport";
2525
+ if (normalized.includes("/webrtc-direct/")) return "webrtc";
2526
+ if (normalized.includes("/ws") || normalized.includes("/wss")) return "websocket";
2527
+ return "other";
2528
+ }
2490
2529
  function selectCompactRelayBootstrapMultiaddrs(addrs, limit = DEFAULT_BOOTSTRAP_COMPACT_MULTIADDR_LIMIT) {
2491
2530
  const entries = filterPublicMultiaddrs(addrs, {
2492
2531
  browserDialableOnly: true
2493
- }).map((addr, index) => ({ addr, index }));
2532
+ }).map((addr, index) => ({
2533
+ addr,
2534
+ index,
2535
+ transport: browserMultiaddrTransport(addr)
2536
+ }));
2494
2537
  entries.sort((left, right) => {
2495
2538
  const preference = browserMultiaddrPreference(left.addr) - browserMultiaddrPreference(right.addr);
2496
2539
  return preference !== 0 ? preference : left.index - right.index;
2497
2540
  });
2498
- return entries.map((entry) => entry.addr).slice(0, Math.max(1, Math.floor(limit)));
2541
+ const perTransportLimit = Math.max(1, Math.floor(limit));
2542
+ const selectedByTransport = /* @__PURE__ */ new Map();
2543
+ const result = [];
2544
+ for (const entry of entries) {
2545
+ const selected = selectedByTransport.get(entry.transport) ?? 0;
2546
+ if (selected >= perTransportLimit) continue;
2547
+ selectedByTransport.set(entry.transport, selected + 1);
2548
+ result.push(entry.addr);
2549
+ }
2550
+ return result;
2499
2551
  }
2500
2552
  function asTrimmedString(value) {
2501
2553
  return typeof value === "string" && value.trim() ? value.trim() : null;
@@ -4042,6 +4094,7 @@ var SponsorRelayController = class {
4042
4094
  this.debugEnabled = isDebugEnabled(props);
4043
4095
  this.client = createAlephBrowserClient({
4044
4096
  apiHost: props.apiHost,
4097
+ apiHosts: props.apiHosts,
4045
4098
  crnListUrl: props.crnListUrl,
4046
4099
  schedulerApiHost: props.schedulerApiHost,
4047
4100
  twoN6ApiHost: props.twoN6ApiHost
@@ -5982,6 +6035,7 @@ function useSponsorRelayController(props) {
5982
6035
  () => createSponsorRelayController(props),
5983
6036
  [
5984
6037
  props.apiHost,
6038
+ props.apiHosts,
5985
6039
  props.crnListUrl,
5986
6040
  props.debug,
5987
6041
  props.instanceName,
package/shared/index.d.ts CHANGED
@@ -209,6 +209,7 @@ interface SponsorRelayProps {
209
209
  launcherMode?: 'floating' | 'inline';
210
210
  version?: string;
211
211
  apiHost?: string;
212
+ apiHosts?: string | readonly string[];
212
213
  crnListUrl?: string;
213
214
  schedulerApiHost?: string;
214
215
  twoN6ApiHost?: string;
@@ -330,7 +331,7 @@ declare const STALE_INSTANCE_ALLOCATION_COOLDOWN_MS: number;
330
331
  declare const RECENT_INSTANCE_RUNTIME_GRACE_MS: number;
331
332
  declare const DEPLOYMENT_PENDING_WARNING_MS: number;
332
333
 
333
- declare const UI_PACKAGE_VERSION = "0.6.5";
334
+ declare const UI_PACKAGE_VERSION = "0.6.6";
334
335
 
335
336
  interface RootfsRequiredPortForward {
336
337
  port: number;
package/shared/index.js CHANGED
@@ -42,7 +42,7 @@ var RECENT_INSTANCE_RUNTIME_GRACE_MS = 10 * 60 * 1e3;
42
42
  var DEPLOYMENT_PENDING_WARNING_MS = 3 * 60 * 1e3;
43
43
 
44
44
  // src/shared/package-version.ts
45
- var UI_PACKAGE_VERSION = "0.6.5";
45
+ var UI_PACKAGE_VERSION = "0.6.6";
46
46
 
47
47
  // src/shared/format.ts
48
48
  function shortHash(value, head = 8, tail = 6) {
@@ -134,7 +134,12 @@ async function fetchWithTimeout(input, init = {}, timeoutMs = 15e3) {
134
134
  }
135
135
 
136
136
  // ../browser/src/aleph-api.ts
137
- var DEFAULT_ALEPH_API_HOST = "https://api.aleph.im";
137
+ var DEFAULT_ALEPH_API_HOSTS = [
138
+ "https://api3.aleph.im",
139
+ "https://api2.aleph.im",
140
+ "https://api.aleph.im"
141
+ ];
142
+ var DEFAULT_ALEPH_API_HOST = DEFAULT_ALEPH_API_HOSTS[0] ?? "https://api3.aleph.im";
138
143
  var DEFAULT_CRN_LIST_URL = "https://crns-list.aleph.sh/crns.json";
139
144
  var DEFAULT_ALEPH_SCHEDULER_API_HOST = "https://scheduler.api.aleph.cloud";
140
145
  var DEFAULT_2N6_API_HOST = "https://api.2n6.me";
@@ -804,29 +809,56 @@ function watchWallet(onChange, provider = getEthereumProvider()) {
804
809
  }
805
810
 
806
811
  // ../browser/src/client.ts
812
+ function normalizeApiHost(value) {
813
+ const trimmed = value.trim().replace(/\/+$/u, "");
814
+ return trimmed ? trimmed : null;
815
+ }
816
+ function normalizeApiHosts(input, fallbackApiHost) {
817
+ const rawValues = Array.isArray(input) ? input : typeof input === "string" ? input.split(/[\s,]+/u) : [];
818
+ const hosts = rawValues.map((value) => normalizeApiHost(String(value))).filter((value) => Boolean(value));
819
+ if (hosts.length > 0) return Array.from(new Set(hosts));
820
+ const fallback = normalizeApiHost(fallbackApiHost);
821
+ return fallback ? [fallback] : [...DEFAULT_ALEPH_API_HOSTS];
822
+ }
823
+ async function withApiHostFallback(apiHosts, run) {
824
+ let lastError = null;
825
+ for (let index = 0; index < apiHosts.length; index += 1) {
826
+ const apiHost = apiHosts[index];
827
+ try {
828
+ return await run(apiHost);
829
+ } catch (error) {
830
+ lastError = error;
831
+ if (index >= apiHosts.length - 1) break;
832
+ }
833
+ }
834
+ if (lastError instanceof Error) throw lastError;
835
+ throw new Error(String(lastError));
836
+ }
807
837
  function createAlephBrowserClient(options = {}) {
808
- const apiHost = options.apiHost ?? DEFAULT_ALEPH_API_HOST;
838
+ const apiHosts = options.apiHosts === void 0 && options.apiHost === void 0 ? [...DEFAULT_ALEPH_API_HOSTS] : normalizeApiHosts(options.apiHosts, options.apiHost ?? DEFAULT_ALEPH_API_HOST);
839
+ const apiHost = apiHosts[0] ?? DEFAULT_ALEPH_API_HOST;
809
840
  const crnListUrl = options.crnListUrl ?? DEFAULT_CRN_LIST_URL;
810
841
  const schedulerApiHost = options.schedulerApiHost ?? DEFAULT_ALEPH_SCHEDULER_API_HOST;
811
842
  const twoN6ApiHost = options.twoN6ApiHost ?? DEFAULT_2N6_API_HOST;
812
843
  return {
813
844
  apiHost,
845
+ apiHosts,
814
846
  crnListUrl,
815
847
  schedulerApiHost,
816
848
  fetchBalance(address) {
817
- return fetchBalance(address, apiHost);
849
+ return withApiHostFallback(apiHosts, (host) => fetchBalance(address, host));
818
850
  },
819
851
  fetchCrns() {
820
852
  return fetchCrns(crnListUrl);
821
853
  },
822
854
  fetchInstances(address) {
823
- return fetchInstances(address, apiHost);
855
+ return withApiHostFallback(apiHosts, (host) => fetchInstances(address, host));
824
856
  },
825
857
  fetch2n6WebAccessUrl(itemHash) {
826
858
  return fetch2n6WebAccessUrl(itemHash, twoN6ApiHost);
827
859
  },
828
860
  fetchMessageEnvelope(itemHash) {
829
- return fetchMessageEnvelope(itemHash, apiHost);
861
+ return withApiHostFallback(apiHosts, (host) => fetchMessageEnvelope(itemHash, host));
830
862
  },
831
863
  fetchSchedulerAllocation(itemHash) {
832
864
  return fetchSchedulerAllocation(itemHash, schedulerApiHost);
@@ -841,16 +873,16 @@ function createAlephBrowserClient(options = {}) {
841
873
  return configureOrbitdbRelaySetup(args);
842
874
  },
843
875
  inspectDeploymentResult(itemHash, rootfsRef) {
844
- return inspectDeploymentResult(itemHash, rootfsRef, apiHost);
876
+ return withApiHostFallback(apiHosts, (host) => inspectDeploymentResult(itemHash, rootfsRef, host));
845
877
  },
846
878
  waitForDeploymentResult(itemHash, rootfsRef, attempts, delayMs) {
847
- return waitForDeploymentResult(itemHash, rootfsRef, apiHost, attempts, delayMs);
879
+ return withApiHostFallback(apiHosts, (host) => waitForDeploymentResult(itemHash, rootfsRef, host, attempts, delayMs));
848
880
  },
849
881
  broadcastInstanceMessage(message, sync) {
850
- return broadcastInstanceMessage(message, apiHost, sync);
882
+ return withApiHostFallback(apiHosts, (host) => broadcastInstanceMessage(message, host, sync));
851
883
  },
852
884
  broadcastAlephMessage(message, sync) {
853
- return broadcastAlephMessage(message, apiHost, sync);
885
+ return withApiHostFallback(apiHosts, (host) => broadcastAlephMessage(message, host, sync));
854
886
  }
855
887
  };
856
888
  }
@@ -2486,15 +2518,35 @@ function browserMultiaddrPreference(addr) {
2486
2518
  if (normalized.includes("/ws")) return 4;
2487
2519
  return 5;
2488
2520
  }
2521
+ function browserMultiaddrTransport(addr) {
2522
+ const normalized = addr.toLowerCase();
2523
+ if (normalized.includes("/webtransport/")) return "webtransport";
2524
+ if (normalized.includes("/webrtc-direct/")) return "webrtc";
2525
+ if (normalized.includes("/ws") || normalized.includes("/wss")) return "websocket";
2526
+ return "other";
2527
+ }
2489
2528
  function selectCompactRelayBootstrapMultiaddrs(addrs, limit = DEFAULT_BOOTSTRAP_COMPACT_MULTIADDR_LIMIT) {
2490
2529
  const entries = filterPublicMultiaddrs(addrs, {
2491
2530
  browserDialableOnly: true
2492
- }).map((addr, index) => ({ addr, index }));
2531
+ }).map((addr, index) => ({
2532
+ addr,
2533
+ index,
2534
+ transport: browserMultiaddrTransport(addr)
2535
+ }));
2493
2536
  entries.sort((left, right) => {
2494
2537
  const preference = browserMultiaddrPreference(left.addr) - browserMultiaddrPreference(right.addr);
2495
2538
  return preference !== 0 ? preference : left.index - right.index;
2496
2539
  });
2497
- return entries.map((entry) => entry.addr).slice(0, Math.max(1, Math.floor(limit)));
2540
+ const perTransportLimit = Math.max(1, Math.floor(limit));
2541
+ const selectedByTransport = /* @__PURE__ */ new Map();
2542
+ const result = [];
2543
+ for (const entry of entries) {
2544
+ const selected = selectedByTransport.get(entry.transport) ?? 0;
2545
+ if (selected >= perTransportLimit) continue;
2546
+ selectedByTransport.set(entry.transport, selected + 1);
2547
+ result.push(entry.addr);
2548
+ }
2549
+ return result;
2498
2550
  }
2499
2551
  function asTrimmedString(value) {
2500
2552
  return typeof value === "string" && value.trim() ? value.trim() : null;
@@ -4041,6 +4093,7 @@ var SponsorRelayController = class {
4041
4093
  this.debugEnabled = isDebugEnabled(props);
4042
4094
  this.client = createAlephBrowserClient({
4043
4095
  apiHost: props.apiHost,
4096
+ apiHosts: props.apiHosts,
4044
4097
  crnListUrl: props.crnListUrl,
4045
4098
  schedulerApiHost: props.schedulerApiHost,
4046
4099
  twoN6ApiHost: props.twoN6ApiHost
@@ -18,6 +18,7 @@ export let openByDefault = false
18
18
  export let launcherMode = 'floating'
19
19
  export let version = ''
20
20
  export let apiHost = undefined
21
+ export let apiHosts = undefined
21
22
  export let crnListUrl = undefined
22
23
  export let schedulerApiHost = undefined
23
24
  export let twoN6ApiHost = undefined
@@ -32,6 +33,7 @@ export let apiHost = undefined
32
33
  openByDefault,
33
34
  launcherMode,
34
35
  apiHost,
36
+ apiHosts,
35
37
  crnListUrl,
36
38
  schedulerApiHost,
37
39
  twoN6ApiHost