@le-space/ui 0.6.24 → 0.6.26

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/README.md CHANGED
@@ -4,7 +4,7 @@ Floating Aleph relay deployment UI components for Svelte and React.
4
4
 
5
5
  Primary goals:
6
6
 
7
- - Svelte-first floating `Sponsor Relay` panel
7
+ - Svelte-first floating `Relay Button` panel
8
8
  - lightweight React wrapper
9
9
  - shared controller and browser-safe Aleph helpers
10
10
  - minimal host configuration beyond a rootfs manifest URL
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@le-space/ui",
3
- "version": "0.6.24",
4
- "description": "Floating Aleph sponsor relay UI components for Svelte and React.",
3
+ "version": "0.6.26",
4
+ "description": "Floating Aleph Relay Button UI components for Svelte and React.",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "files": [
@@ -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.24",
48
- "@le-space/core": "0.6.24",
47
+ "@le-space/browser": "0.6.26",
48
+ "@le-space/core": "0.6.26",
49
49
  "viem": "^2.53.1"
50
50
  },
51
51
  "peerDependencies": {
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.24";
46
+ var UI_PACKAGE_VERSION = "0.6.26";
47
47
 
48
48
  // src/shared/format.ts
49
49
  function shortHash(value, head = 8, tail = 6) {
@@ -2486,8 +2486,7 @@ import { keccak256, recoverMessageAddress, stringToHex } from "viem";
2486
2486
  var DEFAULT_ALEPH_API_HOST3 = "https://api.aleph.im";
2487
2487
  var DEFAULT_ALEPH_BOOTSTRAP_CHANNEL = "simple-todo";
2488
2488
  var DEFAULT_ALEPH_BOOTSTRAP_REF = "simple-todo-bootstrap";
2489
- var DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE = "relay-bootstrap";
2490
- var DEFAULT_ALEPH_BOOTSTRAP_COMPACT_POST_TYPE = "relay-bootstrap-v2";
2489
+ var DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE = "relay-bootstrap-v2";
2491
2490
  var DEFAULT_BOOTSTRAP_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
2492
2491
  var DEFAULT_BOOTSTRAP_PAGINATION = 50;
2493
2492
  var DEFAULT_BOOTSTRAP_COMPACT_MULTIADDR_LIMIT = 3;
@@ -2521,9 +2520,6 @@ function serializeRelayProofPayload(payload) {
2521
2520
  function relayBootstrapMultiaddrsHash(addrs) {
2522
2521
  return keccak256(stringToHex(JSON.stringify(dedupeMultiaddrs(addrs))));
2523
2522
  }
2524
- function compactPostType(postType) {
2525
- return (postType ?? DEFAULT_ALEPH_BOOTSTRAP_COMPACT_POST_TYPE) === DEFAULT_ALEPH_BOOTSTRAP_COMPACT_POST_TYPE;
2526
- }
2527
2523
  function browserMultiaddrPreference(addr) {
2528
2524
  const normalized = addr.toLowerCase();
2529
2525
  if (normalized.includes("/tcp/443/tls/ws/")) return 0;
@@ -2537,7 +2533,8 @@ function browserMultiaddrTransport(addr) {
2537
2533
  const normalized = addr.toLowerCase();
2538
2534
  if (normalized.includes("/webtransport/")) return "webtransport";
2539
2535
  if (normalized.includes("/webrtc-direct/")) return "webrtc";
2540
- if (normalized.includes("/ws") || normalized.includes("/wss")) return "websocket";
2536
+ if (normalized.includes("/ws") || normalized.includes("/wss"))
2537
+ return "websocket";
2541
2538
  return "other";
2542
2539
  }
2543
2540
  function selectCompactRelayBootstrapMultiaddrs(addrs, limit = DEFAULT_BOOTSTRAP_COMPACT_MULTIADDR_LIMIT) {
@@ -2614,7 +2611,10 @@ function hasPeerId(addr) {
2614
2611
  }
2615
2612
  function isBrowserDialableMultiaddr(addr) {
2616
2613
  const normalized = addr.toLowerCase();
2617
- return normalized.includes("/ws") || normalized.includes("/wss") || normalized.includes("/webtransport") || normalized.includes("/webrtc-direct");
2614
+ if (normalized.includes("/webtransport") || normalized.includes("/webrtc-direct")) {
2615
+ return normalized.includes("/certhash/");
2616
+ }
2617
+ return normalized.includes("/ws") || normalized.includes("/wss");
2618
2618
  }
2619
2619
  function dedupeMultiaddrs(addrs) {
2620
2620
  const seen = /* @__PURE__ */ new Set();
@@ -2660,8 +2660,12 @@ function normalizeRelayBootstrapContent(value) {
2660
2660
  const peerId = asTrimmedString(content.peerId);
2661
2661
  const updatedAt = asNumber4(content.updatedAt);
2662
2662
  if (!peerId || updatedAt == null) return null;
2663
- const multiaddrs = Array.isArray(content.multiaddrs) ? content.multiaddrs.filter((entry) => typeof entry === "string") : [];
2664
- const browserMultiaddrs = Array.isArray(content.browserMultiaddrs) ? content.browserMultiaddrs.filter((entry) => typeof entry === "string") : void 0;
2663
+ const multiaddrs = Array.isArray(content.multiaddrs) ? content.multiaddrs.filter(
2664
+ (entry) => typeof entry === "string"
2665
+ ) : [];
2666
+ const browserMultiaddrs = Array.isArray(content.browserMultiaddrs) ? content.browserMultiaddrs.filter(
2667
+ (entry) => typeof entry === "string"
2668
+ ) : void 0;
2665
2669
  return {
2666
2670
  peerId,
2667
2671
  multiaddrs: dedupeMultiaddrs(multiaddrs),
@@ -2714,8 +2718,12 @@ function normalizeRelayBootstrapProofPayload(value) {
2714
2718
  const peerId = asTrimmedString(payload.peerId);
2715
2719
  const updatedAt = asNumber4(payload.updatedAt);
2716
2720
  if (!peerId || updatedAt == null) return null;
2717
- const multiaddrs = Array.isArray(payload.multiaddrs) ? payload.multiaddrs.filter((entry) => typeof entry === "string") : [];
2718
- const browserMultiaddrs = Array.isArray(payload.browserMultiaddrs) ? payload.browserMultiaddrs.filter((entry) => typeof entry === "string") : void 0;
2721
+ const multiaddrs = Array.isArray(payload.multiaddrs) ? payload.multiaddrs.filter(
2722
+ (entry) => typeof entry === "string"
2723
+ ) : [];
2724
+ const browserMultiaddrs = Array.isArray(payload.browserMultiaddrs) ? payload.browserMultiaddrs.filter(
2725
+ (entry) => typeof entry === "string"
2726
+ ) : void 0;
2719
2727
  return {
2720
2728
  peerId,
2721
2729
  multiaddrs: multiaddrs.length > 0 ? dedupeMultiaddrs(multiaddrs) : void 0,
@@ -2753,8 +2761,6 @@ function normalizeRelayBootstrapPostRecord(value) {
2753
2761
  function buildRelayBootstrapPostContent(args) {
2754
2762
  const now = args.now ?? Date.now() / 1e3;
2755
2763
  const updatedAt = args.now ?? Date.now();
2756
- const postType = args.postType ?? DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE;
2757
- const compact = args.compact ?? compactPostType(postType);
2758
2764
  const fullMultiaddrs = filterPublicMultiaddrs(args.multiaddrs);
2759
2765
  const fullBrowserMultiaddrs = args.browserMultiaddrs ? filterPublicMultiaddrs(args.browserMultiaddrs, {
2760
2766
  browserDialableOnly: true
@@ -2764,13 +2770,13 @@ function buildRelayBootstrapPostContent(args) {
2764
2770
  args.compactMultiaddrLimit
2765
2771
  );
2766
2772
  return {
2767
- type: postType,
2773
+ type: DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE,
2768
2774
  address: args.sender,
2769
2775
  ...args.ref ? { ref: args.ref } : {},
2770
2776
  content: {
2771
2777
  peerId: args.peerId,
2772
- multiaddrs: compact ? compactMultiaddrs : fullMultiaddrs,
2773
- browserMultiaddrs: compact ? void 0 : fullBrowserMultiaddrs,
2778
+ multiaddrs: compactMultiaddrs,
2779
+ browserMultiaddrs: void 0,
2774
2780
  registrationId: args.registrationId,
2775
2781
  profile: args.profile,
2776
2782
  version: args.version,
@@ -2793,14 +2799,12 @@ async function createRelayBootstrapPost(args) {
2793
2799
  browserMultiaddrs: args.browserMultiaddrs,
2794
2800
  registrationId: args.registrationId,
2795
2801
  ref: args.ref ?? DEFAULT_ALEPH_BOOTSTRAP_REF,
2796
- postType: args.postType ?? DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE,
2797
2802
  profile: args.profile,
2798
2803
  version: args.version,
2799
2804
  ownerAddress: args.ownerAddress,
2800
2805
  publisherAddress: args.publisherAddress,
2801
2806
  authorization: args.authorization,
2802
2807
  relayProof: args.relayProof,
2803
- compact: args.compact,
2804
2808
  compactMultiaddrLimit: args.compactMultiaddrLimit,
2805
2809
  now: nowMillis
2806
2810
  });
@@ -2847,12 +2851,11 @@ async function signRelayBootstrapProof(args) {
2847
2851
  fullBrowserMultiaddrs && fullBrowserMultiaddrs.length > 0 ? fullBrowserMultiaddrs : fullMultiaddrs,
2848
2852
  args.compactMultiaddrLimit
2849
2853
  );
2850
- const compact = args.compact ?? false;
2851
2854
  const payload = {
2852
2855
  peerId: args.peerId,
2853
- multiaddrs: compact ? void 0 : fullMultiaddrs,
2854
- browserMultiaddrs: compact ? void 0 : fullBrowserMultiaddrs,
2855
- multiaddrsHash: compact ? relayBootstrapMultiaddrsHash(compactMultiaddrs) : void 0,
2856
+ multiaddrs: void 0,
2857
+ browserMultiaddrs: void 0,
2858
+ multiaddrsHash: relayBootstrapMultiaddrsHash(compactMultiaddrs),
2856
2859
  registrationId: args.registrationId,
2857
2860
  profile: args.profile,
2858
2861
  version: args.version,
@@ -2882,10 +2885,7 @@ async function fetchAlephBootstrapPosts(options = {}) {
2882
2885
  options.channel ?? DEFAULT_ALEPH_BOOTSTRAP_CHANNEL
2883
2886
  );
2884
2887
  url.searchParams.set("refs", options.ref ?? DEFAULT_ALEPH_BOOTSTRAP_REF);
2885
- url.searchParams.set(
2886
- "types",
2887
- options.postType ?? DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE
2888
- );
2888
+ url.searchParams.set("types", DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE);
2889
2889
  url.searchParams.set(
2890
2890
  "pagination",
2891
2891
  String(options.pagination ?? DEFAULT_BOOTSTRAP_PAGINATION)
@@ -2899,7 +2899,21 @@ async function fetchAlephBootstrapPosts(options = {}) {
2899
2899
  throw new Error(`Aleph bootstrap post lookup failed: ${response.status}`);
2900
2900
  }
2901
2901
  const payload = await response.json();
2902
- return (payload.posts ?? []).map((entry) => normalizeRelayBootstrapPostRecord(entry)).filter((entry) => entry != null).sort((left, right) => compareRelayBootstrapPostRecency(right, left));
2902
+ const posts = (payload.posts ?? []).map((entry) => normalizeRelayBootstrapPostRecord(entry)).filter((entry) => entry != null).sort((left, right) => compareRelayBootstrapPostRecency(right, left));
2903
+ posts.forEach(assertSupportedRelayBootstrapPost);
2904
+ return posts;
2905
+ }
2906
+ function assertSupportedRelayBootstrapPost(post) {
2907
+ if (post.type === "relay-bootstrap") {
2908
+ throw new Error(
2909
+ "Legacy relay-bootstrap record encountered. Only relay-bootstrap-v2 is supported."
2910
+ );
2911
+ }
2912
+ if (post.type && post.type !== DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE) {
2913
+ throw new Error(
2914
+ `Unsupported relay bootstrap post type: ${post.type}. Expected ${DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE}.`
2915
+ );
2916
+ }
2903
2917
  }
2904
2918
  function compareRelayBootstrapPostRecency(left, right) {
2905
2919
  const leftUpdatedAt = left.content?.updatedAt ?? 0;
@@ -2921,6 +2935,7 @@ function selectCurrentRelayBootstrapPosts(posts, options = {}) {
2921
2935
  const now = options.now ?? Date.now();
2922
2936
  const selected = /* @__PURE__ */ new Map();
2923
2937
  for (const post of posts) {
2938
+ assertSupportedRelayBootstrapPost(post);
2924
2939
  const content = post.content;
2925
2940
  if (!content) continue;
2926
2941
  if (now - content.updatedAt > maxAgeMs) continue;
@@ -2946,14 +2961,12 @@ async function waitForRelayBootstrapRegistration(args) {
2946
2961
  const expectedSender = args.sender?.trim().toLowerCase() || null;
2947
2962
  const expectedRegistrationId = args.registrationId?.trim() || null;
2948
2963
  const expectedPeerId = args.peerId?.trim() || null;
2949
- const postType = args.postType ?? DEFAULT_ALEPH_BOOTSTRAP_COMPACT_POST_TYPE;
2950
2964
  const sleepImpl = args.sleep ?? sleep;
2951
2965
  for (let attempt = 0; attempt < attempts; attempt += 1) {
2952
2966
  const posts = await fetchAlephBootstrapPosts({
2953
2967
  apiHost: args.apiHost ?? DEFAULT_ALEPH_API_HOST3,
2954
2968
  channel: args.channel,
2955
2969
  ref: args.ref,
2956
- postType,
2957
2970
  fetch: args.fetch
2958
2971
  });
2959
2972
  const currentPosts = selectCurrentRelayBootstrapPosts(posts);
@@ -2992,8 +3005,6 @@ async function waitForRelayBootstrapRegistration(args) {
2992
3005
  async function publishRelayBootstrapRegistration(args) {
2993
3006
  const publisherAddress = args.publisherAddress ?? args.sender;
2994
3007
  const ownerAddress = args.ownerAddress;
2995
- const postType = args.postType ?? DEFAULT_ALEPH_BOOTSTRAP_COMPACT_POST_TYPE;
2996
- const compact = postType === DEFAULT_ALEPH_BOOTSTRAP_COMPACT_POST_TYPE;
2997
3008
  let ownerAuthorization = args.ownerAuthorization;
2998
3009
  let relayProof = args.relayProof;
2999
3010
  if (!ownerAuthorization && ownerAddress && args.ownerSigner) {
@@ -3020,7 +3031,6 @@ async function publishRelayBootstrapRegistration(args) {
3020
3031
  profile: args.profile,
3021
3032
  version: args.version,
3022
3033
  updatedAt: args.now ?? Date.now(),
3023
- compact,
3024
3034
  compactMultiaddrLimit: args.compactMultiaddrLimit,
3025
3035
  signer: args.publisherSigner
3026
3036
  });
@@ -3033,14 +3043,12 @@ async function publishRelayBootstrapRegistration(args) {
3033
3043
  registrationId: args.registrationId,
3034
3044
  channel: args.channel,
3035
3045
  ref: args.ref,
3036
- postType,
3037
3046
  profile: args.profile,
3038
3047
  version: args.version,
3039
3048
  ownerAddress,
3040
3049
  publisherAddress,
3041
3050
  authorization: ownerAuthorization,
3042
3051
  relayProof,
3043
- compact,
3044
3052
  compactMultiaddrLimit: args.compactMultiaddrLimit,
3045
3053
  now: args.now,
3046
3054
  hasher: args.hasher
@@ -3063,18 +3071,12 @@ async function publishRelayBootstrapRegistration(args) {
3063
3071
  let forgottenHashes = [];
3064
3072
  let forgetResult;
3065
3073
  if (args.forgetPrevious && args.registrationId) {
3066
- const previousPostTypes = compact ? [postType, DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE] : [postType];
3067
- const previousPosts = (await Promise.all(
3068
- previousPostTypes.map(
3069
- (previousPostType) => fetchAlephBootstrapPosts({
3070
- apiHost: args.apiHost ?? DEFAULT_ALEPH_API_HOST3,
3071
- channel: args.channel,
3072
- ref: args.ref,
3073
- postType: previousPostType,
3074
- fetch: args.fetch
3075
- })
3076
- )
3077
- )).flat();
3074
+ const previousPosts = await fetchAlephBootstrapPosts({
3075
+ apiHost: args.apiHost ?? DEFAULT_ALEPH_API_HOST3,
3076
+ channel: args.channel,
3077
+ ref: args.ref,
3078
+ fetch: args.fetch
3079
+ });
3078
3080
  const forgottenHashSet = new Set(
3079
3081
  previousPosts.filter((post) => {
3080
3082
  const hash = post.itemHash ?? post.hash;
@@ -3676,7 +3678,9 @@ function draftUcanStoreBootstrapErrors(args) {
3676
3678
  const errors = [];
3677
3679
  const { input } = args;
3678
3680
  if (!args.operatorAddress) {
3679
- errors.push("Connect MetaMask before configuring the ucan-store bootstrap package.");
3681
+ errors.push(
3682
+ "Connect MetaMask before configuring the ucan-store bootstrap package."
3683
+ );
3680
3684
  }
3681
3685
  if (!input.adminDid.trim().startsWith("did:")) {
3682
3686
  errors.push("Admin DID must be a non-empty DID string.");
@@ -3727,7 +3731,9 @@ function buildUcanStoreBootstrapPackage(args) {
3727
3731
  serviceDid: args.input.serviceDid.trim() || null,
3728
3732
  spaceDid: args.input.spaceDid.trim(),
3729
3733
  rootDelegationProof: args.input.rootDelegationProof.trim(),
3730
- allowedCapabilities: parseAllowedCapabilities(args.input.allowedCapabilities),
3734
+ allowedCapabilities: parseAllowedCapabilities(
3735
+ args.input.allowedCapabilities
3736
+ ),
3731
3737
  defaultUserDelegationExpiration: parseOptionalExpiration(
3732
3738
  args.input.defaultUserDelegationExpiration
3733
3739
  ),
@@ -3766,7 +3772,9 @@ function defaultState(props = {}) {
3766
3772
  instanceName: props.instanceName ?? DEFAULT_INSTANCE_NAME,
3767
3773
  ucanStoreBootstrap: defaultUcanStoreBootstrapInput(props),
3768
3774
  tierId: DEFAULT_TIER_ID,
3769
- showAdvanced: Boolean(props.manifestJson?.trim() || props.sshPublicKey?.trim()),
3775
+ showAdvanced: Boolean(
3776
+ props.manifestJson?.trim() || props.sshPublicKey?.trim()
3777
+ ),
3770
3778
  showInstances: props.showInstances ?? true,
3771
3779
  showPasteManifest: Boolean(props.manifestJson?.trim()),
3772
3780
  busy: {
@@ -4186,7 +4194,9 @@ var SponsorRelayController = class {
4186
4194
  const profile = bootstrapRelayProfileForManifest(this.state.manifest);
4187
4195
  if (!profile && deploymentProfile !== "ucan-store") return;
4188
4196
  if (profile && !this.state.wallet.address) {
4189
- throw new Error("A connected wallet is required to register relay bootstrap addresses.");
4197
+ throw new Error(
4198
+ "A connected wallet is required to register relay bootstrap addresses."
4199
+ );
4190
4200
  }
4191
4201
  const runtimeHostIpv4 = args.runtime.hostIpv4;
4192
4202
  if (!runtimeHostIpv4) {
@@ -4210,7 +4220,9 @@ var SponsorRelayController = class {
4210
4220
  }
4211
4221
  const walletAddress2 = this.state.wallet.address;
4212
4222
  if (!walletAddress2) {
4213
- throw new Error("A connected wallet is required to configure the ucan-store bootstrap package.");
4223
+ throw new Error(
4224
+ "A connected wallet is required to configure the ucan-store bootstrap package."
4225
+ );
4214
4226
  }
4215
4227
  const bootstrapValidation = buildUcanStoreBootstrapPackage({
4216
4228
  input: this.state.ucanStoreBootstrap,
@@ -4325,7 +4337,9 @@ var SponsorRelayController = class {
4325
4337
  if (!profile) return;
4326
4338
  const walletAddress = this.state.wallet.address;
4327
4339
  if (!walletAddress) {
4328
- throw new Error("A connected wallet is required to register relay bootstrap addresses.");
4340
+ throw new Error(
4341
+ "A connected wallet is required to register relay bootstrap addresses."
4342
+ );
4329
4343
  }
4330
4344
  let bootstrapSignalRelayMetadata = null;
4331
4345
  if (profile === "orbitdb-relay") {
@@ -4371,7 +4385,9 @@ var SponsorRelayController = class {
4371
4385
  const tcpPort = mappedPorts2["9091"]?.host ?? 0;
4372
4386
  const wsPort = mappedPorts2["9092"]?.host ?? mappedPorts2["443"]?.host ?? 0;
4373
4387
  if (!tcpPort || !wsPort) {
4374
- throw new Error("OrbitDB relay runtime is missing required mapped TCP/WS ports.");
4388
+ throw new Error(
4389
+ "OrbitDB relay runtime is missing required mapped TCP/WS ports."
4390
+ );
4375
4391
  }
4376
4392
  const configureResult = await configureOrbitdbRelaySetup2({
4377
4393
  hostIpv4: runtimeHostIpv4,
@@ -4394,7 +4410,9 @@ var SponsorRelayController = class {
4394
4410
  }
4395
4411
  } else {
4396
4412
  if (!args.deploymentToken) {
4397
- throw new Error("Missing deployment token for Aleph bootstrap config handoff.");
4413
+ throw new Error(
4414
+ "Missing deployment token for Aleph bootstrap config handoff."
4415
+ );
4398
4416
  }
4399
4417
  if (runtime.proxyUrl && runtime.webAccess?.active !== true) {
4400
4418
  this.emitProgress({
@@ -4620,7 +4638,19 @@ var SponsorRelayController = class {
4620
4638
  });
4621
4639
  return;
4622
4640
  }
4623
- throw new Error("Relay metadata did not include a peer ID and public multiaddrs.");
4641
+ throw new Error(
4642
+ "Relay metadata did not include a peer ID and public multiaddrs."
4643
+ );
4644
+ }
4645
+ if (profile === "uc-go-peer") {
4646
+ const browserDialableMultiaddrs = relayMetadata.browserBootstrapMultiaddrs.filter(
4647
+ (multiaddr) => /\/(?:tls\/ws|wss)\/p2p\//.test(multiaddr) || /\/(?:webtransport|webrtc-direct)\//.test(multiaddr) && /\/certhash\//.test(multiaddr)
4648
+ );
4649
+ if (browserDialableMultiaddrs.length === 0) {
4650
+ throw new Error(
4651
+ "Relay metadata did not include a browser-dialable WSS address or a WebTransport/WebRTC Direct address with certhash."
4652
+ );
4653
+ }
4624
4654
  }
4625
4655
  const { peerId } = relayMetadata;
4626
4656
  const registrationId = createRelayBootstrapRegistrationId(
@@ -5172,18 +5202,10 @@ var SponsorRelayController = class {
5172
5202
  const [nextBalance, rawInstances, rawBootstrapPosts] = await Promise.all([
5173
5203
  this.client.fetchBalance(this.state.wallet.address),
5174
5204
  this.state.showInstances ? this.client.fetchInstances(this.state.wallet.address) : Promise.resolve([]),
5175
- bootstrapEnabled ? Promise.all(
5176
- [
5177
- DEFAULT_ALEPH_BOOTSTRAP_COMPACT_POST_TYPE,
5178
- DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE
5179
- ].map(
5180
- (postType) => fetchAlephBootstrapPosts({
5181
- apiHost: this.client.apiHost,
5182
- postType,
5183
- fetch
5184
- }).catch(() => [])
5185
- )
5186
- ).then((pages) => pages.flat()) : Promise.resolve([])
5205
+ bootstrapEnabled ? fetchAlephBootstrapPosts({
5206
+ apiHost: this.client.apiHost,
5207
+ fetch
5208
+ }) : Promise.resolve([])
5187
5209
  ]);
5188
5210
  balance = nextBalance;
5189
5211
  instances = await Promise.all(
@@ -5247,7 +5269,9 @@ var SponsorRelayController = class {
5247
5269
  const activeInstanceHashes = new Set(
5248
5270
  instances.map((entry) => entry.instance.item_hash)
5249
5271
  );
5250
- bootstrapRegistrations = selectCurrentRelayBootstrapPosts(rawBootstrapPosts).filter(
5272
+ bootstrapRegistrations = selectCurrentRelayBootstrapPosts(
5273
+ rawBootstrapPosts
5274
+ ).filter(
5251
5275
  (entry) => relayBootstrapMatchesCurrentWallet(
5252
5276
  entry,
5253
5277
  normalizedWalletAddress,
@@ -5270,7 +5294,9 @@ var SponsorRelayController = class {
5270
5294
  peerId: entry.content.peerId,
5271
5295
  registrationId: entry.content.registrationId,
5272
5296
  multiaddrs: Array.isArray(entry.content.multiaddrs) ? entry.content.multiaddrs : [],
5273
- browserMultiaddrs: Array.isArray(entry.content.browserMultiaddrs) ? entry.content.browserMultiaddrs : [],
5297
+ browserMultiaddrs: Array.isArray(
5298
+ entry.content.browserMultiaddrs
5299
+ ) ? entry.content.browserMultiaddrs : [],
5274
5300
  ownerAddress: typeof entry.content.ownerAddress === "string" ? entry.content.ownerAddress : void 0,
5275
5301
  publisherAddress: typeof entry.content.publisherAddress === "string" ? entry.content.publisherAddress : void 0,
5276
5302
  updatedAt: entry.content.updatedAt
@@ -5391,7 +5417,9 @@ var SponsorRelayController = class {
5391
5417
  ...compatibleCrns2.filter((crn) => crn.hash !== preferredCrnHash)
5392
5418
  ].slice(0, 5);
5393
5419
  if (orderedCrns.length === 0) {
5394
- throw new Error("No compatible CRN is currently available for this tier.");
5420
+ throw new Error(
5421
+ "No compatible CRN is currently available for this tier."
5422
+ );
5395
5423
  }
5396
5424
  const attemptErrors = [];
5397
5425
  let lastError = null;
@@ -5824,7 +5852,7 @@ var SponsorRelayController = class {
5824
5852
  await forgetAlephMessages({
5825
5853
  sender: this.state.wallet.address,
5826
5854
  hashes: [attemptItemHash],
5827
- reason: `Discard failed Sponsor Relay deployment attempt on ${attemptLabel}`,
5855
+ reason: `Discard failed Relay Button deployment attempt on ${attemptLabel}`,
5828
5856
  signer: personalSign,
5829
5857
  hasher: sha256Hex,
5830
5858
  fetch: (url, init) => fetch(url, init).then(async (response) => ({
@@ -5934,7 +5962,7 @@ var SponsorRelayController = class {
5934
5962
  await forgetAlephMessages({
5935
5963
  sender: this.state.wallet.address,
5936
5964
  hashes: hashesToForget,
5937
- reason: linkedRegistrationCount > 0 ? `Deleted instance and ${linkedRegistrationCount} linked relay bootstrap registration${linkedRegistrationCount === 1 ? "" : "s"} from Sponsor Relay panel` : "Deleted from Sponsor Relay panel",
5965
+ reason: linkedRegistrationCount > 0 ? `Deleted instance and ${linkedRegistrationCount} linked relay bootstrap registration${linkedRegistrationCount === 1 ? "" : "s"} from Relay Button panel` : "Deleted from Relay Button panel",
5938
5966
  signer: personalSign,
5939
5967
  hasher: sha256Hex,
5940
5968
  fetch: asJsonFetch,
@@ -6003,7 +6031,7 @@ var SponsorRelayController = class {
6003
6031
  await forgetAlephMessages({
6004
6032
  sender: this.state.wallet.address,
6005
6033
  hashes: [registrationHash],
6006
- reason: "Deleted orphan relay bootstrap registration from Sponsor Relay panel",
6034
+ reason: "Deleted orphan relay bootstrap registration from Relay Button panel",
6007
6035
  signer: personalSign,
6008
6036
  hasher: sha256Hex,
6009
6037
  fetch: asJsonFetch,
@@ -6208,7 +6236,7 @@ function supportsBootstrapUi(state) {
6208
6236
  return stateDeploymentProfile(state) !== "ucan-store";
6209
6237
  }
6210
6238
  function deploymentPanelTitle(state) {
6211
- return stateDeploymentProfile(state) === "ucan-store" ? "Sponsor Service" : "Sponsor Relay";
6239
+ return stateDeploymentProfile(state) === "ucan-store" ? "Sponsor Service" : "Relay Button";
6212
6240
  }
6213
6241
  function deploymentLauncherLabel(state, compactInlineLabel, launcherMode) {
6214
6242
  if (launcherMode === "inline" && compactInlineLabel) {
package/shared/index.d.ts CHANGED
@@ -332,7 +332,7 @@ declare const STALE_INSTANCE_ALLOCATION_COOLDOWN_MS: number;
332
332
  declare const RECENT_INSTANCE_RUNTIME_GRACE_MS: number;
333
333
  declare const DEPLOYMENT_PENDING_WARNING_MS: number;
334
334
 
335
- declare const UI_PACKAGE_VERSION = "0.6.24";
335
+ declare const UI_PACKAGE_VERSION = "0.6.26";
336
336
 
337
337
  interface RootfsRequiredPortForward {
338
338
  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.24";
45
+ var UI_PACKAGE_VERSION = "0.6.26";
46
46
 
47
47
  // src/shared/format.ts
48
48
  function shortHash(value, head = 8, tail = 6) {
@@ -2485,8 +2485,7 @@ import { keccak256, recoverMessageAddress, stringToHex } from "viem";
2485
2485
  var DEFAULT_ALEPH_API_HOST3 = "https://api.aleph.im";
2486
2486
  var DEFAULT_ALEPH_BOOTSTRAP_CHANNEL = "simple-todo";
2487
2487
  var DEFAULT_ALEPH_BOOTSTRAP_REF = "simple-todo-bootstrap";
2488
- var DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE = "relay-bootstrap";
2489
- var DEFAULT_ALEPH_BOOTSTRAP_COMPACT_POST_TYPE = "relay-bootstrap-v2";
2488
+ var DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE = "relay-bootstrap-v2";
2490
2489
  var DEFAULT_BOOTSTRAP_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
2491
2490
  var DEFAULT_BOOTSTRAP_PAGINATION = 50;
2492
2491
  var DEFAULT_BOOTSTRAP_COMPACT_MULTIADDR_LIMIT = 3;
@@ -2520,9 +2519,6 @@ function serializeRelayProofPayload(payload) {
2520
2519
  function relayBootstrapMultiaddrsHash(addrs) {
2521
2520
  return keccak256(stringToHex(JSON.stringify(dedupeMultiaddrs(addrs))));
2522
2521
  }
2523
- function compactPostType(postType) {
2524
- return (postType ?? DEFAULT_ALEPH_BOOTSTRAP_COMPACT_POST_TYPE) === DEFAULT_ALEPH_BOOTSTRAP_COMPACT_POST_TYPE;
2525
- }
2526
2522
  function browserMultiaddrPreference(addr) {
2527
2523
  const normalized = addr.toLowerCase();
2528
2524
  if (normalized.includes("/tcp/443/tls/ws/")) return 0;
@@ -2536,7 +2532,8 @@ function browserMultiaddrTransport(addr) {
2536
2532
  const normalized = addr.toLowerCase();
2537
2533
  if (normalized.includes("/webtransport/")) return "webtransport";
2538
2534
  if (normalized.includes("/webrtc-direct/")) return "webrtc";
2539
- if (normalized.includes("/ws") || normalized.includes("/wss")) return "websocket";
2535
+ if (normalized.includes("/ws") || normalized.includes("/wss"))
2536
+ return "websocket";
2540
2537
  return "other";
2541
2538
  }
2542
2539
  function selectCompactRelayBootstrapMultiaddrs(addrs, limit = DEFAULT_BOOTSTRAP_COMPACT_MULTIADDR_LIMIT) {
@@ -2613,7 +2610,10 @@ function hasPeerId(addr) {
2613
2610
  }
2614
2611
  function isBrowserDialableMultiaddr(addr) {
2615
2612
  const normalized = addr.toLowerCase();
2616
- return normalized.includes("/ws") || normalized.includes("/wss") || normalized.includes("/webtransport") || normalized.includes("/webrtc-direct");
2613
+ if (normalized.includes("/webtransport") || normalized.includes("/webrtc-direct")) {
2614
+ return normalized.includes("/certhash/");
2615
+ }
2616
+ return normalized.includes("/ws") || normalized.includes("/wss");
2617
2617
  }
2618
2618
  function dedupeMultiaddrs(addrs) {
2619
2619
  const seen = /* @__PURE__ */ new Set();
@@ -2659,8 +2659,12 @@ function normalizeRelayBootstrapContent(value) {
2659
2659
  const peerId = asTrimmedString(content.peerId);
2660
2660
  const updatedAt = asNumber4(content.updatedAt);
2661
2661
  if (!peerId || updatedAt == null) return null;
2662
- const multiaddrs = Array.isArray(content.multiaddrs) ? content.multiaddrs.filter((entry) => typeof entry === "string") : [];
2663
- const browserMultiaddrs = Array.isArray(content.browserMultiaddrs) ? content.browserMultiaddrs.filter((entry) => typeof entry === "string") : void 0;
2662
+ const multiaddrs = Array.isArray(content.multiaddrs) ? content.multiaddrs.filter(
2663
+ (entry) => typeof entry === "string"
2664
+ ) : [];
2665
+ const browserMultiaddrs = Array.isArray(content.browserMultiaddrs) ? content.browserMultiaddrs.filter(
2666
+ (entry) => typeof entry === "string"
2667
+ ) : void 0;
2664
2668
  return {
2665
2669
  peerId,
2666
2670
  multiaddrs: dedupeMultiaddrs(multiaddrs),
@@ -2713,8 +2717,12 @@ function normalizeRelayBootstrapProofPayload(value) {
2713
2717
  const peerId = asTrimmedString(payload.peerId);
2714
2718
  const updatedAt = asNumber4(payload.updatedAt);
2715
2719
  if (!peerId || updatedAt == null) return null;
2716
- const multiaddrs = Array.isArray(payload.multiaddrs) ? payload.multiaddrs.filter((entry) => typeof entry === "string") : [];
2717
- const browserMultiaddrs = Array.isArray(payload.browserMultiaddrs) ? payload.browserMultiaddrs.filter((entry) => typeof entry === "string") : void 0;
2720
+ const multiaddrs = Array.isArray(payload.multiaddrs) ? payload.multiaddrs.filter(
2721
+ (entry) => typeof entry === "string"
2722
+ ) : [];
2723
+ const browserMultiaddrs = Array.isArray(payload.browserMultiaddrs) ? payload.browserMultiaddrs.filter(
2724
+ (entry) => typeof entry === "string"
2725
+ ) : void 0;
2718
2726
  return {
2719
2727
  peerId,
2720
2728
  multiaddrs: multiaddrs.length > 0 ? dedupeMultiaddrs(multiaddrs) : void 0,
@@ -2752,8 +2760,6 @@ function normalizeRelayBootstrapPostRecord(value) {
2752
2760
  function buildRelayBootstrapPostContent(args) {
2753
2761
  const now = args.now ?? Date.now() / 1e3;
2754
2762
  const updatedAt = args.now ?? Date.now();
2755
- const postType = args.postType ?? DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE;
2756
- const compact = args.compact ?? compactPostType(postType);
2757
2763
  const fullMultiaddrs = filterPublicMultiaddrs(args.multiaddrs);
2758
2764
  const fullBrowserMultiaddrs = args.browserMultiaddrs ? filterPublicMultiaddrs(args.browserMultiaddrs, {
2759
2765
  browserDialableOnly: true
@@ -2763,13 +2769,13 @@ function buildRelayBootstrapPostContent(args) {
2763
2769
  args.compactMultiaddrLimit
2764
2770
  );
2765
2771
  return {
2766
- type: postType,
2772
+ type: DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE,
2767
2773
  address: args.sender,
2768
2774
  ...args.ref ? { ref: args.ref } : {},
2769
2775
  content: {
2770
2776
  peerId: args.peerId,
2771
- multiaddrs: compact ? compactMultiaddrs : fullMultiaddrs,
2772
- browserMultiaddrs: compact ? void 0 : fullBrowserMultiaddrs,
2777
+ multiaddrs: compactMultiaddrs,
2778
+ browserMultiaddrs: void 0,
2773
2779
  registrationId: args.registrationId,
2774
2780
  profile: args.profile,
2775
2781
  version: args.version,
@@ -2792,14 +2798,12 @@ async function createRelayBootstrapPost(args) {
2792
2798
  browserMultiaddrs: args.browserMultiaddrs,
2793
2799
  registrationId: args.registrationId,
2794
2800
  ref: args.ref ?? DEFAULT_ALEPH_BOOTSTRAP_REF,
2795
- postType: args.postType ?? DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE,
2796
2801
  profile: args.profile,
2797
2802
  version: args.version,
2798
2803
  ownerAddress: args.ownerAddress,
2799
2804
  publisherAddress: args.publisherAddress,
2800
2805
  authorization: args.authorization,
2801
2806
  relayProof: args.relayProof,
2802
- compact: args.compact,
2803
2807
  compactMultiaddrLimit: args.compactMultiaddrLimit,
2804
2808
  now: nowMillis
2805
2809
  });
@@ -2846,12 +2850,11 @@ async function signRelayBootstrapProof(args) {
2846
2850
  fullBrowserMultiaddrs && fullBrowserMultiaddrs.length > 0 ? fullBrowserMultiaddrs : fullMultiaddrs,
2847
2851
  args.compactMultiaddrLimit
2848
2852
  );
2849
- const compact = args.compact ?? false;
2850
2853
  const payload = {
2851
2854
  peerId: args.peerId,
2852
- multiaddrs: compact ? void 0 : fullMultiaddrs,
2853
- browserMultiaddrs: compact ? void 0 : fullBrowserMultiaddrs,
2854
- multiaddrsHash: compact ? relayBootstrapMultiaddrsHash(compactMultiaddrs) : void 0,
2855
+ multiaddrs: void 0,
2856
+ browserMultiaddrs: void 0,
2857
+ multiaddrsHash: relayBootstrapMultiaddrsHash(compactMultiaddrs),
2855
2858
  registrationId: args.registrationId,
2856
2859
  profile: args.profile,
2857
2860
  version: args.version,
@@ -2881,10 +2884,7 @@ async function fetchAlephBootstrapPosts(options = {}) {
2881
2884
  options.channel ?? DEFAULT_ALEPH_BOOTSTRAP_CHANNEL
2882
2885
  );
2883
2886
  url.searchParams.set("refs", options.ref ?? DEFAULT_ALEPH_BOOTSTRAP_REF);
2884
- url.searchParams.set(
2885
- "types",
2886
- options.postType ?? DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE
2887
- );
2887
+ url.searchParams.set("types", DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE);
2888
2888
  url.searchParams.set(
2889
2889
  "pagination",
2890
2890
  String(options.pagination ?? DEFAULT_BOOTSTRAP_PAGINATION)
@@ -2898,7 +2898,21 @@ async function fetchAlephBootstrapPosts(options = {}) {
2898
2898
  throw new Error(`Aleph bootstrap post lookup failed: ${response.status}`);
2899
2899
  }
2900
2900
  const payload = await response.json();
2901
- return (payload.posts ?? []).map((entry) => normalizeRelayBootstrapPostRecord(entry)).filter((entry) => entry != null).sort((left, right) => compareRelayBootstrapPostRecency(right, left));
2901
+ const posts = (payload.posts ?? []).map((entry) => normalizeRelayBootstrapPostRecord(entry)).filter((entry) => entry != null).sort((left, right) => compareRelayBootstrapPostRecency(right, left));
2902
+ posts.forEach(assertSupportedRelayBootstrapPost);
2903
+ return posts;
2904
+ }
2905
+ function assertSupportedRelayBootstrapPost(post) {
2906
+ if (post.type === "relay-bootstrap") {
2907
+ throw new Error(
2908
+ "Legacy relay-bootstrap record encountered. Only relay-bootstrap-v2 is supported."
2909
+ );
2910
+ }
2911
+ if (post.type && post.type !== DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE) {
2912
+ throw new Error(
2913
+ `Unsupported relay bootstrap post type: ${post.type}. Expected ${DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE}.`
2914
+ );
2915
+ }
2902
2916
  }
2903
2917
  function compareRelayBootstrapPostRecency(left, right) {
2904
2918
  const leftUpdatedAt = left.content?.updatedAt ?? 0;
@@ -2920,6 +2934,7 @@ function selectCurrentRelayBootstrapPosts(posts, options = {}) {
2920
2934
  const now = options.now ?? Date.now();
2921
2935
  const selected = /* @__PURE__ */ new Map();
2922
2936
  for (const post of posts) {
2937
+ assertSupportedRelayBootstrapPost(post);
2923
2938
  const content = post.content;
2924
2939
  if (!content) continue;
2925
2940
  if (now - content.updatedAt > maxAgeMs) continue;
@@ -2945,14 +2960,12 @@ async function waitForRelayBootstrapRegistration(args) {
2945
2960
  const expectedSender = args.sender?.trim().toLowerCase() || null;
2946
2961
  const expectedRegistrationId = args.registrationId?.trim() || null;
2947
2962
  const expectedPeerId = args.peerId?.trim() || null;
2948
- const postType = args.postType ?? DEFAULT_ALEPH_BOOTSTRAP_COMPACT_POST_TYPE;
2949
2963
  const sleepImpl = args.sleep ?? sleep;
2950
2964
  for (let attempt = 0; attempt < attempts; attempt += 1) {
2951
2965
  const posts = await fetchAlephBootstrapPosts({
2952
2966
  apiHost: args.apiHost ?? DEFAULT_ALEPH_API_HOST3,
2953
2967
  channel: args.channel,
2954
2968
  ref: args.ref,
2955
- postType,
2956
2969
  fetch: args.fetch
2957
2970
  });
2958
2971
  const currentPosts = selectCurrentRelayBootstrapPosts(posts);
@@ -2991,8 +3004,6 @@ async function waitForRelayBootstrapRegistration(args) {
2991
3004
  async function publishRelayBootstrapRegistration(args) {
2992
3005
  const publisherAddress = args.publisherAddress ?? args.sender;
2993
3006
  const ownerAddress = args.ownerAddress;
2994
- const postType = args.postType ?? DEFAULT_ALEPH_BOOTSTRAP_COMPACT_POST_TYPE;
2995
- const compact = postType === DEFAULT_ALEPH_BOOTSTRAP_COMPACT_POST_TYPE;
2996
3007
  let ownerAuthorization = args.ownerAuthorization;
2997
3008
  let relayProof = args.relayProof;
2998
3009
  if (!ownerAuthorization && ownerAddress && args.ownerSigner) {
@@ -3019,7 +3030,6 @@ async function publishRelayBootstrapRegistration(args) {
3019
3030
  profile: args.profile,
3020
3031
  version: args.version,
3021
3032
  updatedAt: args.now ?? Date.now(),
3022
- compact,
3023
3033
  compactMultiaddrLimit: args.compactMultiaddrLimit,
3024
3034
  signer: args.publisherSigner
3025
3035
  });
@@ -3032,14 +3042,12 @@ async function publishRelayBootstrapRegistration(args) {
3032
3042
  registrationId: args.registrationId,
3033
3043
  channel: args.channel,
3034
3044
  ref: args.ref,
3035
- postType,
3036
3045
  profile: args.profile,
3037
3046
  version: args.version,
3038
3047
  ownerAddress,
3039
3048
  publisherAddress,
3040
3049
  authorization: ownerAuthorization,
3041
3050
  relayProof,
3042
- compact,
3043
3051
  compactMultiaddrLimit: args.compactMultiaddrLimit,
3044
3052
  now: args.now,
3045
3053
  hasher: args.hasher
@@ -3062,18 +3070,12 @@ async function publishRelayBootstrapRegistration(args) {
3062
3070
  let forgottenHashes = [];
3063
3071
  let forgetResult;
3064
3072
  if (args.forgetPrevious && args.registrationId) {
3065
- const previousPostTypes = compact ? [postType, DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE] : [postType];
3066
- const previousPosts = (await Promise.all(
3067
- previousPostTypes.map(
3068
- (previousPostType) => fetchAlephBootstrapPosts({
3069
- apiHost: args.apiHost ?? DEFAULT_ALEPH_API_HOST3,
3070
- channel: args.channel,
3071
- ref: args.ref,
3072
- postType: previousPostType,
3073
- fetch: args.fetch
3074
- })
3075
- )
3076
- )).flat();
3073
+ const previousPosts = await fetchAlephBootstrapPosts({
3074
+ apiHost: args.apiHost ?? DEFAULT_ALEPH_API_HOST3,
3075
+ channel: args.channel,
3076
+ ref: args.ref,
3077
+ fetch: args.fetch
3078
+ });
3077
3079
  const forgottenHashSet = new Set(
3078
3080
  previousPosts.filter((post) => {
3079
3081
  const hash = post.itemHash ?? post.hash;
@@ -3675,7 +3677,9 @@ function draftUcanStoreBootstrapErrors(args) {
3675
3677
  const errors = [];
3676
3678
  const { input } = args;
3677
3679
  if (!args.operatorAddress) {
3678
- errors.push("Connect MetaMask before configuring the ucan-store bootstrap package.");
3680
+ errors.push(
3681
+ "Connect MetaMask before configuring the ucan-store bootstrap package."
3682
+ );
3679
3683
  }
3680
3684
  if (!input.adminDid.trim().startsWith("did:")) {
3681
3685
  errors.push("Admin DID must be a non-empty DID string.");
@@ -3726,7 +3730,9 @@ function buildUcanStoreBootstrapPackage(args) {
3726
3730
  serviceDid: args.input.serviceDid.trim() || null,
3727
3731
  spaceDid: args.input.spaceDid.trim(),
3728
3732
  rootDelegationProof: args.input.rootDelegationProof.trim(),
3729
- allowedCapabilities: parseAllowedCapabilities(args.input.allowedCapabilities),
3733
+ allowedCapabilities: parseAllowedCapabilities(
3734
+ args.input.allowedCapabilities
3735
+ ),
3730
3736
  defaultUserDelegationExpiration: parseOptionalExpiration(
3731
3737
  args.input.defaultUserDelegationExpiration
3732
3738
  ),
@@ -3765,7 +3771,9 @@ function defaultState(props = {}) {
3765
3771
  instanceName: props.instanceName ?? DEFAULT_INSTANCE_NAME,
3766
3772
  ucanStoreBootstrap: defaultUcanStoreBootstrapInput(props),
3767
3773
  tierId: DEFAULT_TIER_ID,
3768
- showAdvanced: Boolean(props.manifestJson?.trim() || props.sshPublicKey?.trim()),
3774
+ showAdvanced: Boolean(
3775
+ props.manifestJson?.trim() || props.sshPublicKey?.trim()
3776
+ ),
3769
3777
  showInstances: props.showInstances ?? true,
3770
3778
  showPasteManifest: Boolean(props.manifestJson?.trim()),
3771
3779
  busy: {
@@ -4185,7 +4193,9 @@ var SponsorRelayController = class {
4185
4193
  const profile = bootstrapRelayProfileForManifest(this.state.manifest);
4186
4194
  if (!profile && deploymentProfile !== "ucan-store") return;
4187
4195
  if (profile && !this.state.wallet.address) {
4188
- throw new Error("A connected wallet is required to register relay bootstrap addresses.");
4196
+ throw new Error(
4197
+ "A connected wallet is required to register relay bootstrap addresses."
4198
+ );
4189
4199
  }
4190
4200
  const runtimeHostIpv4 = args.runtime.hostIpv4;
4191
4201
  if (!runtimeHostIpv4) {
@@ -4209,7 +4219,9 @@ var SponsorRelayController = class {
4209
4219
  }
4210
4220
  const walletAddress2 = this.state.wallet.address;
4211
4221
  if (!walletAddress2) {
4212
- throw new Error("A connected wallet is required to configure the ucan-store bootstrap package.");
4222
+ throw new Error(
4223
+ "A connected wallet is required to configure the ucan-store bootstrap package."
4224
+ );
4213
4225
  }
4214
4226
  const bootstrapValidation = buildUcanStoreBootstrapPackage({
4215
4227
  input: this.state.ucanStoreBootstrap,
@@ -4324,7 +4336,9 @@ var SponsorRelayController = class {
4324
4336
  if (!profile) return;
4325
4337
  const walletAddress = this.state.wallet.address;
4326
4338
  if (!walletAddress) {
4327
- throw new Error("A connected wallet is required to register relay bootstrap addresses.");
4339
+ throw new Error(
4340
+ "A connected wallet is required to register relay bootstrap addresses."
4341
+ );
4328
4342
  }
4329
4343
  let bootstrapSignalRelayMetadata = null;
4330
4344
  if (profile === "orbitdb-relay") {
@@ -4370,7 +4384,9 @@ var SponsorRelayController = class {
4370
4384
  const tcpPort = mappedPorts2["9091"]?.host ?? 0;
4371
4385
  const wsPort = mappedPorts2["9092"]?.host ?? mappedPorts2["443"]?.host ?? 0;
4372
4386
  if (!tcpPort || !wsPort) {
4373
- throw new Error("OrbitDB relay runtime is missing required mapped TCP/WS ports.");
4387
+ throw new Error(
4388
+ "OrbitDB relay runtime is missing required mapped TCP/WS ports."
4389
+ );
4374
4390
  }
4375
4391
  const configureResult = await configureOrbitdbRelaySetup2({
4376
4392
  hostIpv4: runtimeHostIpv4,
@@ -4393,7 +4409,9 @@ var SponsorRelayController = class {
4393
4409
  }
4394
4410
  } else {
4395
4411
  if (!args.deploymentToken) {
4396
- throw new Error("Missing deployment token for Aleph bootstrap config handoff.");
4412
+ throw new Error(
4413
+ "Missing deployment token for Aleph bootstrap config handoff."
4414
+ );
4397
4415
  }
4398
4416
  if (runtime.proxyUrl && runtime.webAccess?.active !== true) {
4399
4417
  this.emitProgress({
@@ -4619,7 +4637,19 @@ var SponsorRelayController = class {
4619
4637
  });
4620
4638
  return;
4621
4639
  }
4622
- throw new Error("Relay metadata did not include a peer ID and public multiaddrs.");
4640
+ throw new Error(
4641
+ "Relay metadata did not include a peer ID and public multiaddrs."
4642
+ );
4643
+ }
4644
+ if (profile === "uc-go-peer") {
4645
+ const browserDialableMultiaddrs = relayMetadata.browserBootstrapMultiaddrs.filter(
4646
+ (multiaddr) => /\/(?:tls\/ws|wss)\/p2p\//.test(multiaddr) || /\/(?:webtransport|webrtc-direct)\//.test(multiaddr) && /\/certhash\//.test(multiaddr)
4647
+ );
4648
+ if (browserDialableMultiaddrs.length === 0) {
4649
+ throw new Error(
4650
+ "Relay metadata did not include a browser-dialable WSS address or a WebTransport/WebRTC Direct address with certhash."
4651
+ );
4652
+ }
4623
4653
  }
4624
4654
  const { peerId } = relayMetadata;
4625
4655
  const registrationId = createRelayBootstrapRegistrationId(
@@ -5171,18 +5201,10 @@ var SponsorRelayController = class {
5171
5201
  const [nextBalance, rawInstances, rawBootstrapPosts] = await Promise.all([
5172
5202
  this.client.fetchBalance(this.state.wallet.address),
5173
5203
  this.state.showInstances ? this.client.fetchInstances(this.state.wallet.address) : Promise.resolve([]),
5174
- bootstrapEnabled ? Promise.all(
5175
- [
5176
- DEFAULT_ALEPH_BOOTSTRAP_COMPACT_POST_TYPE,
5177
- DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE
5178
- ].map(
5179
- (postType) => fetchAlephBootstrapPosts({
5180
- apiHost: this.client.apiHost,
5181
- postType,
5182
- fetch
5183
- }).catch(() => [])
5184
- )
5185
- ).then((pages) => pages.flat()) : Promise.resolve([])
5204
+ bootstrapEnabled ? fetchAlephBootstrapPosts({
5205
+ apiHost: this.client.apiHost,
5206
+ fetch
5207
+ }) : Promise.resolve([])
5186
5208
  ]);
5187
5209
  balance = nextBalance;
5188
5210
  instances = await Promise.all(
@@ -5246,7 +5268,9 @@ var SponsorRelayController = class {
5246
5268
  const activeInstanceHashes = new Set(
5247
5269
  instances.map((entry) => entry.instance.item_hash)
5248
5270
  );
5249
- bootstrapRegistrations = selectCurrentRelayBootstrapPosts(rawBootstrapPosts).filter(
5271
+ bootstrapRegistrations = selectCurrentRelayBootstrapPosts(
5272
+ rawBootstrapPosts
5273
+ ).filter(
5250
5274
  (entry) => relayBootstrapMatchesCurrentWallet(
5251
5275
  entry,
5252
5276
  normalizedWalletAddress,
@@ -5269,7 +5293,9 @@ var SponsorRelayController = class {
5269
5293
  peerId: entry.content.peerId,
5270
5294
  registrationId: entry.content.registrationId,
5271
5295
  multiaddrs: Array.isArray(entry.content.multiaddrs) ? entry.content.multiaddrs : [],
5272
- browserMultiaddrs: Array.isArray(entry.content.browserMultiaddrs) ? entry.content.browserMultiaddrs : [],
5296
+ browserMultiaddrs: Array.isArray(
5297
+ entry.content.browserMultiaddrs
5298
+ ) ? entry.content.browserMultiaddrs : [],
5273
5299
  ownerAddress: typeof entry.content.ownerAddress === "string" ? entry.content.ownerAddress : void 0,
5274
5300
  publisherAddress: typeof entry.content.publisherAddress === "string" ? entry.content.publisherAddress : void 0,
5275
5301
  updatedAt: entry.content.updatedAt
@@ -5390,7 +5416,9 @@ var SponsorRelayController = class {
5390
5416
  ...compatibleCrns2.filter((crn) => crn.hash !== preferredCrnHash)
5391
5417
  ].slice(0, 5);
5392
5418
  if (orderedCrns.length === 0) {
5393
- throw new Error("No compatible CRN is currently available for this tier.");
5419
+ throw new Error(
5420
+ "No compatible CRN is currently available for this tier."
5421
+ );
5394
5422
  }
5395
5423
  const attemptErrors = [];
5396
5424
  let lastError = null;
@@ -5823,7 +5851,7 @@ var SponsorRelayController = class {
5823
5851
  await forgetAlephMessages({
5824
5852
  sender: this.state.wallet.address,
5825
5853
  hashes: [attemptItemHash],
5826
- reason: `Discard failed Sponsor Relay deployment attempt on ${attemptLabel}`,
5854
+ reason: `Discard failed Relay Button deployment attempt on ${attemptLabel}`,
5827
5855
  signer: personalSign,
5828
5856
  hasher: sha256Hex,
5829
5857
  fetch: (url, init) => fetch(url, init).then(async (response) => ({
@@ -5933,7 +5961,7 @@ var SponsorRelayController = class {
5933
5961
  await forgetAlephMessages({
5934
5962
  sender: this.state.wallet.address,
5935
5963
  hashes: hashesToForget,
5936
- reason: linkedRegistrationCount > 0 ? `Deleted instance and ${linkedRegistrationCount} linked relay bootstrap registration${linkedRegistrationCount === 1 ? "" : "s"} from Sponsor Relay panel` : "Deleted from Sponsor Relay panel",
5964
+ reason: linkedRegistrationCount > 0 ? `Deleted instance and ${linkedRegistrationCount} linked relay bootstrap registration${linkedRegistrationCount === 1 ? "" : "s"} from Relay Button panel` : "Deleted from Relay Button panel",
5937
5965
  signer: personalSign,
5938
5966
  hasher: sha256Hex,
5939
5967
  fetch: asJsonFetch,
@@ -6002,7 +6030,7 @@ var SponsorRelayController = class {
6002
6030
  await forgetAlephMessages({
6003
6031
  sender: this.state.wallet.address,
6004
6032
  hashes: [registrationHash],
6005
- reason: "Deleted orphan relay bootstrap registration from Sponsor Relay panel",
6033
+ reason: "Deleted orphan relay bootstrap registration from Relay Button panel",
6006
6034
  signer: personalSign,
6007
6035
  hasher: sha256Hex,
6008
6036
  fetch: asJsonFetch,
@@ -51,7 +51,7 @@ export let apiHosts = undefined
51
51
  }
52
52
 
53
53
  function deploymentTitle() {
54
- return deploymentProfile() === 'ucan-store' ? 'Sponsor Service' : 'Sponsor Relay'
54
+ return deploymentProfile() === 'ucan-store' ? 'Service Button' : 'Relay Button'
55
55
  }
56
56
 
57
57
  function deploymentInstanceFallbackLabel() {
@@ -5,7 +5,7 @@
5
5
  </script>
6
6
 
7
7
  <button class={`launcher ${mode} ${open ? 'open' : ''}`} type="button" on:click={onToggle}>
8
- <span>Sponsor Relay</span>
8
+ <span>Relay Button</span>
9
9
  </button>
10
10
 
11
11
  <style>