@le-space/ui 0.6.4 → 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.4",
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,9 +44,9 @@
44
44
  "url": "https://github.com/NiKrause/relay-button/issues"
45
45
  },
46
46
  "dependencies": {
47
- "@le-space/browser": "0.6.4",
48
- "@le-space/core": "0.6.4",
49
- "viem": "^2.38.5"
47
+ "@le-space/browser": "0.6.6",
48
+ "@le-space/core": "0.6.6",
49
+ "viem": "^2.53.1"
50
50
  },
51
51
  "peerDependencies": {
52
52
  "react": ">=18",
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.4";
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
  }
@@ -2333,9 +2365,11 @@ async function configureUcanStore(args) {
2333
2365
  proxy_url: args.proxyUrl ?? void 0,
2334
2366
  service_did: args.serviceDid ?? void 0,
2335
2367
  service_origin: args.serviceOrigin ?? void 0,
2368
+ public_storage_origin: args.publicStorageOrigin ?? void 0,
2336
2369
  webauthn_origin: args.webauthnOrigin ?? void 0,
2337
2370
  webauthn_origin_fallbacks: args.webauthnOriginFallbacks ?? void 0,
2338
2371
  admin_did: args.adminDid ?? void 0,
2372
+ admin_api_token: args.adminApiToken ?? void 0,
2339
2373
  bootstrap_package: args.bootstrapPackage ?? void 0,
2340
2374
  no_start: args.noStart === true ? true : void 0
2341
2375
  };
@@ -2434,13 +2468,15 @@ async function fetchUcGoPeerMetadata(args) {
2434
2468
  }
2435
2469
 
2436
2470
  // ../aleph-bootstrap/src/index.ts
2437
- import { recoverMessageAddress } from "viem";
2471
+ import { keccak256, recoverMessageAddress, stringToHex } from "viem";
2438
2472
  var DEFAULT_ALEPH_API_HOST3 = "https://api.aleph.im";
2439
2473
  var DEFAULT_ALEPH_BOOTSTRAP_CHANNEL = "simple-todo";
2440
2474
  var DEFAULT_ALEPH_BOOTSTRAP_REF = "simple-todo-bootstrap";
2441
2475
  var DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE = "relay-bootstrap";
2476
+ var DEFAULT_ALEPH_BOOTSTRAP_COMPACT_POST_TYPE = "relay-bootstrap-v2";
2442
2477
  var DEFAULT_BOOTSTRAP_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
2443
2478
  var DEFAULT_BOOTSTRAP_PAGINATION = 50;
2479
+ var DEFAULT_BOOTSTRAP_COMPACT_MULTIADDR_LIMIT = 3;
2444
2480
  var RELAY_BOOTSTRAP_SIGNATURE_SCHEME = "personal_sign";
2445
2481
  function serializeOwnerAuthorizationPayload(payload) {
2446
2482
  return JSON.stringify({
@@ -2458,14 +2494,61 @@ function serializeOwnerAuthorizationPayload(payload) {
2458
2494
  function serializeRelayProofPayload(payload) {
2459
2495
  return JSON.stringify({
2460
2496
  peerId: payload.peerId,
2461
- multiaddrs: dedupeMultiaddrs(payload.multiaddrs),
2497
+ multiaddrs: payload.multiaddrs ? dedupeMultiaddrs(payload.multiaddrs) : void 0,
2462
2498
  browserMultiaddrs: payload.browserMultiaddrs ? dedupeMultiaddrs(payload.browserMultiaddrs) : void 0,
2499
+ multiaddrsHash: payload.multiaddrsHash,
2500
+ browserMultiaddrsHash: payload.browserMultiaddrsHash,
2463
2501
  registrationId: payload.registrationId,
2464
2502
  profile: payload.profile,
2465
2503
  version: payload.version,
2466
2504
  updatedAt: payload.updatedAt
2467
2505
  });
2468
2506
  }
2507
+ function relayBootstrapMultiaddrsHash(addrs) {
2508
+ return keccak256(stringToHex(JSON.stringify(dedupeMultiaddrs(addrs))));
2509
+ }
2510
+ function compactPostType(postType) {
2511
+ return (postType ?? DEFAULT_ALEPH_BOOTSTRAP_COMPACT_POST_TYPE) === DEFAULT_ALEPH_BOOTSTRAP_COMPACT_POST_TYPE;
2512
+ }
2513
+ function browserMultiaddrPreference(addr) {
2514
+ const normalized = addr.toLowerCase();
2515
+ if (normalized.includes("/tcp/443/tls/ws/")) return 0;
2516
+ if (normalized.includes("/tls/ws/")) return 1;
2517
+ if (normalized.includes("/webtransport/")) return 2;
2518
+ if (normalized.includes("/webrtc-direct/")) return 3;
2519
+ if (normalized.includes("/ws")) return 4;
2520
+ return 5;
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
+ }
2529
+ function selectCompactRelayBootstrapMultiaddrs(addrs, limit = DEFAULT_BOOTSTRAP_COMPACT_MULTIADDR_LIMIT) {
2530
+ const entries = filterPublicMultiaddrs(addrs, {
2531
+ browserDialableOnly: true
2532
+ }).map((addr, index) => ({
2533
+ addr,
2534
+ index,
2535
+ transport: browserMultiaddrTransport(addr)
2536
+ }));
2537
+ entries.sort((left, right) => {
2538
+ const preference = browserMultiaddrPreference(left.addr) - browserMultiaddrPreference(right.addr);
2539
+ return preference !== 0 ? preference : left.index - right.index;
2540
+ });
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;
2551
+ }
2469
2552
  function asTrimmedString(value) {
2470
2553
  return typeof value === "string" && value.trim() ? value.trim() : null;
2471
2554
  }
@@ -2621,8 +2704,10 @@ function normalizeRelayBootstrapProofPayload(value) {
2621
2704
  const browserMultiaddrs = Array.isArray(payload.browserMultiaddrs) ? payload.browserMultiaddrs.filter((entry) => typeof entry === "string") : void 0;
2622
2705
  return {
2623
2706
  peerId,
2624
- multiaddrs: dedupeMultiaddrs(multiaddrs),
2707
+ multiaddrs: multiaddrs.length > 0 ? dedupeMultiaddrs(multiaddrs) : void 0,
2625
2708
  browserMultiaddrs: browserMultiaddrs ? dedupeMultiaddrs(browserMultiaddrs) : void 0,
2709
+ multiaddrsHash: asTrimmedString(payload.multiaddrsHash) ?? void 0,
2710
+ browserMultiaddrsHash: asTrimmedString(payload.browserMultiaddrsHash) ?? void 0,
2626
2711
  registrationId: asTrimmedString(payload.registrationId) ?? void 0,
2627
2712
  profile: asTrimmedString(payload.profile) ?? void 0,
2628
2713
  version: asTrimmedString(payload.version) ?? void 0,
@@ -2654,16 +2739,24 @@ function normalizeRelayBootstrapPostRecord(value) {
2654
2739
  function buildRelayBootstrapPostContent(args) {
2655
2740
  const now = args.now ?? Date.now() / 1e3;
2656
2741
  const updatedAt = args.now ?? Date.now();
2742
+ const postType = args.postType ?? DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE;
2743
+ const compact = args.compact ?? compactPostType(postType);
2744
+ const fullMultiaddrs = filterPublicMultiaddrs(args.multiaddrs);
2745
+ const fullBrowserMultiaddrs = args.browserMultiaddrs ? filterPublicMultiaddrs(args.browserMultiaddrs, {
2746
+ browserDialableOnly: true
2747
+ }) : void 0;
2748
+ const compactMultiaddrs = selectCompactRelayBootstrapMultiaddrs(
2749
+ fullBrowserMultiaddrs && fullBrowserMultiaddrs.length > 0 ? fullBrowserMultiaddrs : fullMultiaddrs,
2750
+ args.compactMultiaddrLimit
2751
+ );
2657
2752
  return {
2658
- type: args.postType ?? DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE,
2753
+ type: postType,
2659
2754
  address: args.sender,
2660
2755
  ...args.ref ? { ref: args.ref } : {},
2661
2756
  content: {
2662
2757
  peerId: args.peerId,
2663
- multiaddrs: filterPublicMultiaddrs(args.multiaddrs),
2664
- browserMultiaddrs: args.browserMultiaddrs ? filterPublicMultiaddrs(args.browserMultiaddrs, {
2665
- browserDialableOnly: true
2666
- }) : void 0,
2758
+ multiaddrs: compact ? compactMultiaddrs : fullMultiaddrs,
2759
+ browserMultiaddrs: compact ? void 0 : fullBrowserMultiaddrs,
2667
2760
  registrationId: args.registrationId,
2668
2761
  profile: args.profile,
2669
2762
  version: args.version,
@@ -2693,6 +2786,8 @@ async function createRelayBootstrapPost(args) {
2693
2786
  publisherAddress: args.publisherAddress,
2694
2787
  authorization: args.authorization,
2695
2788
  relayProof: args.relayProof,
2789
+ compact: args.compact,
2790
+ compactMultiaddrLimit: args.compactMultiaddrLimit,
2696
2791
  now: nowMillis
2697
2792
  });
2698
2793
  itemContent.time = nowSeconds;
@@ -2730,12 +2825,20 @@ async function signRelayBootstrapAuthorization(args) {
2730
2825
  };
2731
2826
  }
2732
2827
  async function signRelayBootstrapProof(args) {
2828
+ const fullMultiaddrs = filterPublicMultiaddrs(args.multiaddrs);
2829
+ const fullBrowserMultiaddrs = args.browserMultiaddrs ? filterPublicMultiaddrs(args.browserMultiaddrs, {
2830
+ browserDialableOnly: true
2831
+ }) : void 0;
2832
+ const compactMultiaddrs = selectCompactRelayBootstrapMultiaddrs(
2833
+ fullBrowserMultiaddrs && fullBrowserMultiaddrs.length > 0 ? fullBrowserMultiaddrs : fullMultiaddrs,
2834
+ args.compactMultiaddrLimit
2835
+ );
2836
+ const compact = args.compact ?? false;
2733
2837
  const payload = {
2734
2838
  peerId: args.peerId,
2735
- multiaddrs: filterPublicMultiaddrs(args.multiaddrs),
2736
- browserMultiaddrs: args.browserMultiaddrs ? filterPublicMultiaddrs(args.browserMultiaddrs, {
2737
- browserDialableOnly: true
2738
- }) : void 0,
2839
+ multiaddrs: compact ? void 0 : fullMultiaddrs,
2840
+ browserMultiaddrs: compact ? void 0 : fullBrowserMultiaddrs,
2841
+ multiaddrsHash: compact ? relayBootstrapMultiaddrsHash(compactMultiaddrs) : void 0,
2739
2842
  registrationId: args.registrationId,
2740
2843
  profile: args.profile,
2741
2844
  version: args.version,
@@ -2782,7 +2885,7 @@ async function fetchAlephBootstrapPosts(options = {}) {
2782
2885
  throw new Error(`Aleph bootstrap post lookup failed: ${response.status}`);
2783
2886
  }
2784
2887
  const payload = await response.json();
2785
- return (payload.posts ?? []).map((entry) => normalizeRelayBootstrapPostRecord(entry)).filter((entry) => entry != null);
2888
+ return (payload.posts ?? []).map((entry) => normalizeRelayBootstrapPostRecord(entry)).filter((entry) => entry != null).sort((left, right) => compareRelayBootstrapPostRecency(right, left));
2786
2889
  }
2787
2890
  function compareRelayBootstrapPostRecency(left, right) {
2788
2891
  const leftUpdatedAt = left.content?.updatedAt ?? 0;
@@ -2829,12 +2932,14 @@ async function waitForRelayBootstrapRegistration(args) {
2829
2932
  const expectedSender = args.sender?.trim().toLowerCase() || null;
2830
2933
  const expectedRegistrationId = args.registrationId?.trim() || null;
2831
2934
  const expectedPeerId = args.peerId?.trim() || null;
2935
+ const postType = args.postType ?? DEFAULT_ALEPH_BOOTSTRAP_COMPACT_POST_TYPE;
2936
+ const sleepImpl = args.sleep ?? sleep;
2832
2937
  for (let attempt = 0; attempt < attempts; attempt += 1) {
2833
2938
  const posts = await fetchAlephBootstrapPosts({
2834
2939
  apiHost: args.apiHost ?? DEFAULT_ALEPH_API_HOST3,
2835
2940
  channel: args.channel,
2836
2941
  ref: args.ref,
2837
- postType: args.postType,
2942
+ postType,
2838
2943
  fetch: args.fetch
2839
2944
  });
2840
2945
  const currentPosts = selectCurrentRelayBootstrapPosts(posts);
@@ -2865,7 +2970,7 @@ async function waitForRelayBootstrapRegistration(args) {
2865
2970
  }
2866
2971
  args.onAttempt?.(null, attempt + 1, attempts);
2867
2972
  if (attempt < attempts - 1) {
2868
- await sleep(delayMs);
2973
+ await sleepImpl(delayMs);
2869
2974
  }
2870
2975
  }
2871
2976
  return null;
@@ -2873,6 +2978,8 @@ async function waitForRelayBootstrapRegistration(args) {
2873
2978
  async function publishRelayBootstrapRegistration(args) {
2874
2979
  const publisherAddress = args.publisherAddress ?? args.sender;
2875
2980
  const ownerAddress = args.ownerAddress;
2981
+ const postType = args.postType ?? DEFAULT_ALEPH_BOOTSTRAP_COMPACT_POST_TYPE;
2982
+ const compact = postType === DEFAULT_ALEPH_BOOTSTRAP_COMPACT_POST_TYPE;
2876
2983
  let ownerAuthorization = args.ownerAuthorization;
2877
2984
  let relayProof = args.relayProof;
2878
2985
  if (!ownerAuthorization && ownerAddress && args.ownerSigner) {
@@ -2899,6 +3006,8 @@ async function publishRelayBootstrapRegistration(args) {
2899
3006
  profile: args.profile,
2900
3007
  version: args.version,
2901
3008
  updatedAt: args.now ?? Date.now(),
3009
+ compact,
3010
+ compactMultiaddrLimit: args.compactMultiaddrLimit,
2902
3011
  signer: args.publisherSigner
2903
3012
  });
2904
3013
  }
@@ -2910,13 +3019,15 @@ async function publishRelayBootstrapRegistration(args) {
2910
3019
  registrationId: args.registrationId,
2911
3020
  channel: args.channel,
2912
3021
  ref: args.ref,
2913
- postType: args.postType,
3022
+ postType,
2914
3023
  profile: args.profile,
2915
3024
  version: args.version,
2916
3025
  ownerAddress,
2917
3026
  publisherAddress,
2918
3027
  authorization: ownerAuthorization,
2919
3028
  relayProof,
3029
+ compact,
3030
+ compactMultiaddrLimit: args.compactMultiaddrLimit,
2920
3031
  now: args.now,
2921
3032
  hasher: args.hasher
2922
3033
  });
@@ -2938,16 +3049,33 @@ async function publishRelayBootstrapRegistration(args) {
2938
3049
  let forgottenHashes = [];
2939
3050
  let forgetResult;
2940
3051
  if (args.forgetPrevious && args.registrationId) {
2941
- const previousPosts = await fetchAlephBootstrapPosts({
2942
- apiHost: args.apiHost ?? DEFAULT_ALEPH_API_HOST3,
2943
- channel: args.channel,
2944
- ref: args.ref,
2945
- postType: args.postType,
2946
- fetch: args.fetch
2947
- });
2948
- forgottenHashes = previousPosts.filter(
2949
- (post) => post.address?.toLowerCase() === args.sender.toLowerCase() && post.content?.registrationId === args.registrationId && (post.itemHash ?? post.hash) != null && (post.itemHash ?? post.hash) !== unsigned.item_hash
2950
- ).map((post) => post.itemHash ?? post.hash ?? "").filter(Boolean);
3052
+ const previousPostTypes = compact ? [postType, DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE] : [postType];
3053
+ const previousPosts = (await Promise.all(
3054
+ previousPostTypes.map(
3055
+ (previousPostType) => fetchAlephBootstrapPosts({
3056
+ apiHost: args.apiHost ?? DEFAULT_ALEPH_API_HOST3,
3057
+ channel: args.channel,
3058
+ ref: args.ref,
3059
+ postType: previousPostType,
3060
+ fetch: args.fetch
3061
+ })
3062
+ )
3063
+ )).flat();
3064
+ const forgottenHashSet = new Set(
3065
+ previousPosts.filter((post) => {
3066
+ const hash = post.itemHash ?? post.hash;
3067
+ if (!hash || hash === unsigned.item_hash) return false;
3068
+ if (post.address?.toLowerCase() !== args.sender.toLowerCase()) {
3069
+ return false;
3070
+ }
3071
+ const content2 = post.content;
3072
+ if (!content2) return false;
3073
+ if (content2.registrationId === args.registrationId) return true;
3074
+ if (content2.peerId !== args.peerId) return false;
3075
+ return !args.profile || content2.profile === args.profile;
3076
+ }).map((post) => post.itemHash ?? post.hash ?? "").filter(Boolean)
3077
+ );
3078
+ forgottenHashes = [...forgottenHashSet];
2951
3079
  if (forgottenHashes.length > 0) {
2952
3080
  forgetResult = await forgetAlephMessages({
2953
3081
  sender: args.sender,
@@ -2968,7 +3096,7 @@ async function publishRelayBootstrapRegistration(args) {
2968
3096
  response,
2969
3097
  httpStatus,
2970
3098
  publishedMultiaddrs: content.content?.multiaddrs ?? [],
2971
- publishedBrowserMultiaddrs: content.content?.browserMultiaddrs ?? [],
3099
+ publishedBrowserMultiaddrs: content.content?.browserMultiaddrs ?? content.content?.multiaddrs ?? [],
2972
3100
  forgottenHashes,
2973
3101
  forgetResult
2974
3102
  };
@@ -3966,6 +4094,7 @@ var SponsorRelayController = class {
3966
4094
  this.debugEnabled = isDebugEnabled(props);
3967
4095
  this.client = createAlephBrowserClient({
3968
4096
  apiHost: props.apiHost,
4097
+ apiHosts: props.apiHosts,
3969
4098
  crnListUrl: props.crnListUrl,
3970
4099
  schedulerApiHost: props.schedulerApiHost,
3971
4100
  twoN6ApiHost: props.twoN6ApiHost
@@ -4118,6 +4247,8 @@ var SponsorRelayController = class {
4118
4247
  setupPort,
4119
4248
  proxyUrl: serviceProxyUrl,
4120
4249
  webauthnOrigin: serviceProxyUrl,
4250
+ serviceDid: bootstrapValidation.bootstrapPackage.serviceDid,
4251
+ serviceOrigin: bootstrapValidation.bootstrapPackage.serviceOrigin,
4121
4252
  adminDid: bootstrapValidation.bootstrapPackage.adminDid,
4122
4253
  bootstrapPackage: bootstrapValidation.bootstrapPackage,
4123
4254
  fetch: (url, init) => fetch(url, init),
@@ -5020,10 +5151,18 @@ var SponsorRelayController = class {
5020
5151
  const [nextBalance, rawInstances, rawBootstrapPosts] = await Promise.all([
5021
5152
  this.client.fetchBalance(this.state.wallet.address),
5022
5153
  this.state.showInstances ? this.client.fetchInstances(this.state.wallet.address) : Promise.resolve([]),
5023
- bootstrapEnabled ? fetchAlephBootstrapPosts({
5024
- apiHost: this.client.apiHost,
5025
- fetch
5026
- }).catch(() => []) : Promise.resolve([])
5154
+ bootstrapEnabled ? Promise.all(
5155
+ [
5156
+ DEFAULT_ALEPH_BOOTSTRAP_COMPACT_POST_TYPE,
5157
+ DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE
5158
+ ].map(
5159
+ (postType) => fetchAlephBootstrapPosts({
5160
+ apiHost: this.client.apiHost,
5161
+ postType,
5162
+ fetch
5163
+ }).catch(() => [])
5164
+ )
5165
+ ).then((pages) => pages.flat()) : Promise.resolve([])
5027
5166
  ]);
5028
5167
  balance = nextBalance;
5029
5168
  instances = await Promise.all(
@@ -5896,6 +6035,7 @@ function useSponsorRelayController(props) {
5896
6035
  () => createSponsorRelayController(props),
5897
6036
  [
5898
6037
  props.apiHost,
6038
+ props.apiHosts,
5899
6039
  props.crnListUrl,
5900
6040
  props.debug,
5901
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.4";
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.4";
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
  }
@@ -2332,9 +2364,11 @@ async function configureUcanStore(args) {
2332
2364
  proxy_url: args.proxyUrl ?? void 0,
2333
2365
  service_did: args.serviceDid ?? void 0,
2334
2366
  service_origin: args.serviceOrigin ?? void 0,
2367
+ public_storage_origin: args.publicStorageOrigin ?? void 0,
2335
2368
  webauthn_origin: args.webauthnOrigin ?? void 0,
2336
2369
  webauthn_origin_fallbacks: args.webauthnOriginFallbacks ?? void 0,
2337
2370
  admin_did: args.adminDid ?? void 0,
2371
+ admin_api_token: args.adminApiToken ?? void 0,
2338
2372
  bootstrap_package: args.bootstrapPackage ?? void 0,
2339
2373
  no_start: args.noStart === true ? true : void 0
2340
2374
  };
@@ -2433,13 +2467,15 @@ async function fetchUcGoPeerMetadata(args) {
2433
2467
  }
2434
2468
 
2435
2469
  // ../aleph-bootstrap/src/index.ts
2436
- import { recoverMessageAddress } from "viem";
2470
+ import { keccak256, recoverMessageAddress, stringToHex } from "viem";
2437
2471
  var DEFAULT_ALEPH_API_HOST3 = "https://api.aleph.im";
2438
2472
  var DEFAULT_ALEPH_BOOTSTRAP_CHANNEL = "simple-todo";
2439
2473
  var DEFAULT_ALEPH_BOOTSTRAP_REF = "simple-todo-bootstrap";
2440
2474
  var DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE = "relay-bootstrap";
2475
+ var DEFAULT_ALEPH_BOOTSTRAP_COMPACT_POST_TYPE = "relay-bootstrap-v2";
2441
2476
  var DEFAULT_BOOTSTRAP_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
2442
2477
  var DEFAULT_BOOTSTRAP_PAGINATION = 50;
2478
+ var DEFAULT_BOOTSTRAP_COMPACT_MULTIADDR_LIMIT = 3;
2443
2479
  var RELAY_BOOTSTRAP_SIGNATURE_SCHEME = "personal_sign";
2444
2480
  function serializeOwnerAuthorizationPayload(payload) {
2445
2481
  return JSON.stringify({
@@ -2457,14 +2493,61 @@ function serializeOwnerAuthorizationPayload(payload) {
2457
2493
  function serializeRelayProofPayload(payload) {
2458
2494
  return JSON.stringify({
2459
2495
  peerId: payload.peerId,
2460
- multiaddrs: dedupeMultiaddrs(payload.multiaddrs),
2496
+ multiaddrs: payload.multiaddrs ? dedupeMultiaddrs(payload.multiaddrs) : void 0,
2461
2497
  browserMultiaddrs: payload.browserMultiaddrs ? dedupeMultiaddrs(payload.browserMultiaddrs) : void 0,
2498
+ multiaddrsHash: payload.multiaddrsHash,
2499
+ browserMultiaddrsHash: payload.browserMultiaddrsHash,
2462
2500
  registrationId: payload.registrationId,
2463
2501
  profile: payload.profile,
2464
2502
  version: payload.version,
2465
2503
  updatedAt: payload.updatedAt
2466
2504
  });
2467
2505
  }
2506
+ function relayBootstrapMultiaddrsHash(addrs) {
2507
+ return keccak256(stringToHex(JSON.stringify(dedupeMultiaddrs(addrs))));
2508
+ }
2509
+ function compactPostType(postType) {
2510
+ return (postType ?? DEFAULT_ALEPH_BOOTSTRAP_COMPACT_POST_TYPE) === DEFAULT_ALEPH_BOOTSTRAP_COMPACT_POST_TYPE;
2511
+ }
2512
+ function browserMultiaddrPreference(addr) {
2513
+ const normalized = addr.toLowerCase();
2514
+ if (normalized.includes("/tcp/443/tls/ws/")) return 0;
2515
+ if (normalized.includes("/tls/ws/")) return 1;
2516
+ if (normalized.includes("/webtransport/")) return 2;
2517
+ if (normalized.includes("/webrtc-direct/")) return 3;
2518
+ if (normalized.includes("/ws")) return 4;
2519
+ return 5;
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
+ }
2528
+ function selectCompactRelayBootstrapMultiaddrs(addrs, limit = DEFAULT_BOOTSTRAP_COMPACT_MULTIADDR_LIMIT) {
2529
+ const entries = filterPublicMultiaddrs(addrs, {
2530
+ browserDialableOnly: true
2531
+ }).map((addr, index) => ({
2532
+ addr,
2533
+ index,
2534
+ transport: browserMultiaddrTransport(addr)
2535
+ }));
2536
+ entries.sort((left, right) => {
2537
+ const preference = browserMultiaddrPreference(left.addr) - browserMultiaddrPreference(right.addr);
2538
+ return preference !== 0 ? preference : left.index - right.index;
2539
+ });
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;
2550
+ }
2468
2551
  function asTrimmedString(value) {
2469
2552
  return typeof value === "string" && value.trim() ? value.trim() : null;
2470
2553
  }
@@ -2620,8 +2703,10 @@ function normalizeRelayBootstrapProofPayload(value) {
2620
2703
  const browserMultiaddrs = Array.isArray(payload.browserMultiaddrs) ? payload.browserMultiaddrs.filter((entry) => typeof entry === "string") : void 0;
2621
2704
  return {
2622
2705
  peerId,
2623
- multiaddrs: dedupeMultiaddrs(multiaddrs),
2706
+ multiaddrs: multiaddrs.length > 0 ? dedupeMultiaddrs(multiaddrs) : void 0,
2624
2707
  browserMultiaddrs: browserMultiaddrs ? dedupeMultiaddrs(browserMultiaddrs) : void 0,
2708
+ multiaddrsHash: asTrimmedString(payload.multiaddrsHash) ?? void 0,
2709
+ browserMultiaddrsHash: asTrimmedString(payload.browserMultiaddrsHash) ?? void 0,
2625
2710
  registrationId: asTrimmedString(payload.registrationId) ?? void 0,
2626
2711
  profile: asTrimmedString(payload.profile) ?? void 0,
2627
2712
  version: asTrimmedString(payload.version) ?? void 0,
@@ -2653,16 +2738,24 @@ function normalizeRelayBootstrapPostRecord(value) {
2653
2738
  function buildRelayBootstrapPostContent(args) {
2654
2739
  const now = args.now ?? Date.now() / 1e3;
2655
2740
  const updatedAt = args.now ?? Date.now();
2741
+ const postType = args.postType ?? DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE;
2742
+ const compact = args.compact ?? compactPostType(postType);
2743
+ const fullMultiaddrs = filterPublicMultiaddrs(args.multiaddrs);
2744
+ const fullBrowserMultiaddrs = args.browserMultiaddrs ? filterPublicMultiaddrs(args.browserMultiaddrs, {
2745
+ browserDialableOnly: true
2746
+ }) : void 0;
2747
+ const compactMultiaddrs = selectCompactRelayBootstrapMultiaddrs(
2748
+ fullBrowserMultiaddrs && fullBrowserMultiaddrs.length > 0 ? fullBrowserMultiaddrs : fullMultiaddrs,
2749
+ args.compactMultiaddrLimit
2750
+ );
2656
2751
  return {
2657
- type: args.postType ?? DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE,
2752
+ type: postType,
2658
2753
  address: args.sender,
2659
2754
  ...args.ref ? { ref: args.ref } : {},
2660
2755
  content: {
2661
2756
  peerId: args.peerId,
2662
- multiaddrs: filterPublicMultiaddrs(args.multiaddrs),
2663
- browserMultiaddrs: args.browserMultiaddrs ? filterPublicMultiaddrs(args.browserMultiaddrs, {
2664
- browserDialableOnly: true
2665
- }) : void 0,
2757
+ multiaddrs: compact ? compactMultiaddrs : fullMultiaddrs,
2758
+ browserMultiaddrs: compact ? void 0 : fullBrowserMultiaddrs,
2666
2759
  registrationId: args.registrationId,
2667
2760
  profile: args.profile,
2668
2761
  version: args.version,
@@ -2692,6 +2785,8 @@ async function createRelayBootstrapPost(args) {
2692
2785
  publisherAddress: args.publisherAddress,
2693
2786
  authorization: args.authorization,
2694
2787
  relayProof: args.relayProof,
2788
+ compact: args.compact,
2789
+ compactMultiaddrLimit: args.compactMultiaddrLimit,
2695
2790
  now: nowMillis
2696
2791
  });
2697
2792
  itemContent.time = nowSeconds;
@@ -2729,12 +2824,20 @@ async function signRelayBootstrapAuthorization(args) {
2729
2824
  };
2730
2825
  }
2731
2826
  async function signRelayBootstrapProof(args) {
2827
+ const fullMultiaddrs = filterPublicMultiaddrs(args.multiaddrs);
2828
+ const fullBrowserMultiaddrs = args.browserMultiaddrs ? filterPublicMultiaddrs(args.browserMultiaddrs, {
2829
+ browserDialableOnly: true
2830
+ }) : void 0;
2831
+ const compactMultiaddrs = selectCompactRelayBootstrapMultiaddrs(
2832
+ fullBrowserMultiaddrs && fullBrowserMultiaddrs.length > 0 ? fullBrowserMultiaddrs : fullMultiaddrs,
2833
+ args.compactMultiaddrLimit
2834
+ );
2835
+ const compact = args.compact ?? false;
2732
2836
  const payload = {
2733
2837
  peerId: args.peerId,
2734
- multiaddrs: filterPublicMultiaddrs(args.multiaddrs),
2735
- browserMultiaddrs: args.browserMultiaddrs ? filterPublicMultiaddrs(args.browserMultiaddrs, {
2736
- browserDialableOnly: true
2737
- }) : void 0,
2838
+ multiaddrs: compact ? void 0 : fullMultiaddrs,
2839
+ browserMultiaddrs: compact ? void 0 : fullBrowserMultiaddrs,
2840
+ multiaddrsHash: compact ? relayBootstrapMultiaddrsHash(compactMultiaddrs) : void 0,
2738
2841
  registrationId: args.registrationId,
2739
2842
  profile: args.profile,
2740
2843
  version: args.version,
@@ -2781,7 +2884,7 @@ async function fetchAlephBootstrapPosts(options = {}) {
2781
2884
  throw new Error(`Aleph bootstrap post lookup failed: ${response.status}`);
2782
2885
  }
2783
2886
  const payload = await response.json();
2784
- return (payload.posts ?? []).map((entry) => normalizeRelayBootstrapPostRecord(entry)).filter((entry) => entry != null);
2887
+ return (payload.posts ?? []).map((entry) => normalizeRelayBootstrapPostRecord(entry)).filter((entry) => entry != null).sort((left, right) => compareRelayBootstrapPostRecency(right, left));
2785
2888
  }
2786
2889
  function compareRelayBootstrapPostRecency(left, right) {
2787
2890
  const leftUpdatedAt = left.content?.updatedAt ?? 0;
@@ -2828,12 +2931,14 @@ async function waitForRelayBootstrapRegistration(args) {
2828
2931
  const expectedSender = args.sender?.trim().toLowerCase() || null;
2829
2932
  const expectedRegistrationId = args.registrationId?.trim() || null;
2830
2933
  const expectedPeerId = args.peerId?.trim() || null;
2934
+ const postType = args.postType ?? DEFAULT_ALEPH_BOOTSTRAP_COMPACT_POST_TYPE;
2935
+ const sleepImpl = args.sleep ?? sleep;
2831
2936
  for (let attempt = 0; attempt < attempts; attempt += 1) {
2832
2937
  const posts = await fetchAlephBootstrapPosts({
2833
2938
  apiHost: args.apiHost ?? DEFAULT_ALEPH_API_HOST3,
2834
2939
  channel: args.channel,
2835
2940
  ref: args.ref,
2836
- postType: args.postType,
2941
+ postType,
2837
2942
  fetch: args.fetch
2838
2943
  });
2839
2944
  const currentPosts = selectCurrentRelayBootstrapPosts(posts);
@@ -2864,7 +2969,7 @@ async function waitForRelayBootstrapRegistration(args) {
2864
2969
  }
2865
2970
  args.onAttempt?.(null, attempt + 1, attempts);
2866
2971
  if (attempt < attempts - 1) {
2867
- await sleep(delayMs);
2972
+ await sleepImpl(delayMs);
2868
2973
  }
2869
2974
  }
2870
2975
  return null;
@@ -2872,6 +2977,8 @@ async function waitForRelayBootstrapRegistration(args) {
2872
2977
  async function publishRelayBootstrapRegistration(args) {
2873
2978
  const publisherAddress = args.publisherAddress ?? args.sender;
2874
2979
  const ownerAddress = args.ownerAddress;
2980
+ const postType = args.postType ?? DEFAULT_ALEPH_BOOTSTRAP_COMPACT_POST_TYPE;
2981
+ const compact = postType === DEFAULT_ALEPH_BOOTSTRAP_COMPACT_POST_TYPE;
2875
2982
  let ownerAuthorization = args.ownerAuthorization;
2876
2983
  let relayProof = args.relayProof;
2877
2984
  if (!ownerAuthorization && ownerAddress && args.ownerSigner) {
@@ -2898,6 +3005,8 @@ async function publishRelayBootstrapRegistration(args) {
2898
3005
  profile: args.profile,
2899
3006
  version: args.version,
2900
3007
  updatedAt: args.now ?? Date.now(),
3008
+ compact,
3009
+ compactMultiaddrLimit: args.compactMultiaddrLimit,
2901
3010
  signer: args.publisherSigner
2902
3011
  });
2903
3012
  }
@@ -2909,13 +3018,15 @@ async function publishRelayBootstrapRegistration(args) {
2909
3018
  registrationId: args.registrationId,
2910
3019
  channel: args.channel,
2911
3020
  ref: args.ref,
2912
- postType: args.postType,
3021
+ postType,
2913
3022
  profile: args.profile,
2914
3023
  version: args.version,
2915
3024
  ownerAddress,
2916
3025
  publisherAddress,
2917
3026
  authorization: ownerAuthorization,
2918
3027
  relayProof,
3028
+ compact,
3029
+ compactMultiaddrLimit: args.compactMultiaddrLimit,
2919
3030
  now: args.now,
2920
3031
  hasher: args.hasher
2921
3032
  });
@@ -2937,16 +3048,33 @@ async function publishRelayBootstrapRegistration(args) {
2937
3048
  let forgottenHashes = [];
2938
3049
  let forgetResult;
2939
3050
  if (args.forgetPrevious && args.registrationId) {
2940
- const previousPosts = await fetchAlephBootstrapPosts({
2941
- apiHost: args.apiHost ?? DEFAULT_ALEPH_API_HOST3,
2942
- channel: args.channel,
2943
- ref: args.ref,
2944
- postType: args.postType,
2945
- fetch: args.fetch
2946
- });
2947
- forgottenHashes = previousPosts.filter(
2948
- (post) => post.address?.toLowerCase() === args.sender.toLowerCase() && post.content?.registrationId === args.registrationId && (post.itemHash ?? post.hash) != null && (post.itemHash ?? post.hash) !== unsigned.item_hash
2949
- ).map((post) => post.itemHash ?? post.hash ?? "").filter(Boolean);
3051
+ const previousPostTypes = compact ? [postType, DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE] : [postType];
3052
+ const previousPosts = (await Promise.all(
3053
+ previousPostTypes.map(
3054
+ (previousPostType) => fetchAlephBootstrapPosts({
3055
+ apiHost: args.apiHost ?? DEFAULT_ALEPH_API_HOST3,
3056
+ channel: args.channel,
3057
+ ref: args.ref,
3058
+ postType: previousPostType,
3059
+ fetch: args.fetch
3060
+ })
3061
+ )
3062
+ )).flat();
3063
+ const forgottenHashSet = new Set(
3064
+ previousPosts.filter((post) => {
3065
+ const hash = post.itemHash ?? post.hash;
3066
+ if (!hash || hash === unsigned.item_hash) return false;
3067
+ if (post.address?.toLowerCase() !== args.sender.toLowerCase()) {
3068
+ return false;
3069
+ }
3070
+ const content2 = post.content;
3071
+ if (!content2) return false;
3072
+ if (content2.registrationId === args.registrationId) return true;
3073
+ if (content2.peerId !== args.peerId) return false;
3074
+ return !args.profile || content2.profile === args.profile;
3075
+ }).map((post) => post.itemHash ?? post.hash ?? "").filter(Boolean)
3076
+ );
3077
+ forgottenHashes = [...forgottenHashSet];
2950
3078
  if (forgottenHashes.length > 0) {
2951
3079
  forgetResult = await forgetAlephMessages({
2952
3080
  sender: args.sender,
@@ -2967,7 +3095,7 @@ async function publishRelayBootstrapRegistration(args) {
2967
3095
  response,
2968
3096
  httpStatus,
2969
3097
  publishedMultiaddrs: content.content?.multiaddrs ?? [],
2970
- publishedBrowserMultiaddrs: content.content?.browserMultiaddrs ?? [],
3098
+ publishedBrowserMultiaddrs: content.content?.browserMultiaddrs ?? content.content?.multiaddrs ?? [],
2971
3099
  forgottenHashes,
2972
3100
  forgetResult
2973
3101
  };
@@ -3965,6 +4093,7 @@ var SponsorRelayController = class {
3965
4093
  this.debugEnabled = isDebugEnabled(props);
3966
4094
  this.client = createAlephBrowserClient({
3967
4095
  apiHost: props.apiHost,
4096
+ apiHosts: props.apiHosts,
3968
4097
  crnListUrl: props.crnListUrl,
3969
4098
  schedulerApiHost: props.schedulerApiHost,
3970
4099
  twoN6ApiHost: props.twoN6ApiHost
@@ -4117,6 +4246,8 @@ var SponsorRelayController = class {
4117
4246
  setupPort,
4118
4247
  proxyUrl: serviceProxyUrl,
4119
4248
  webauthnOrigin: serviceProxyUrl,
4249
+ serviceDid: bootstrapValidation.bootstrapPackage.serviceDid,
4250
+ serviceOrigin: bootstrapValidation.bootstrapPackage.serviceOrigin,
4120
4251
  adminDid: bootstrapValidation.bootstrapPackage.adminDid,
4121
4252
  bootstrapPackage: bootstrapValidation.bootstrapPackage,
4122
4253
  fetch: (url, init) => fetch(url, init),
@@ -5019,10 +5150,18 @@ var SponsorRelayController = class {
5019
5150
  const [nextBalance, rawInstances, rawBootstrapPosts] = await Promise.all([
5020
5151
  this.client.fetchBalance(this.state.wallet.address),
5021
5152
  this.state.showInstances ? this.client.fetchInstances(this.state.wallet.address) : Promise.resolve([]),
5022
- bootstrapEnabled ? fetchAlephBootstrapPosts({
5023
- apiHost: this.client.apiHost,
5024
- fetch
5025
- }).catch(() => []) : Promise.resolve([])
5153
+ bootstrapEnabled ? Promise.all(
5154
+ [
5155
+ DEFAULT_ALEPH_BOOTSTRAP_COMPACT_POST_TYPE,
5156
+ DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE
5157
+ ].map(
5158
+ (postType) => fetchAlephBootstrapPosts({
5159
+ apiHost: this.client.apiHost,
5160
+ postType,
5161
+ fetch
5162
+ }).catch(() => [])
5163
+ )
5164
+ ).then((pages) => pages.flat()) : Promise.resolve([])
5026
5165
  ]);
5027
5166
  balance = nextBalance;
5028
5167
  instances = await Promise.all(
@@ -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