@le-space/ui 0.3.18 → 0.3.19

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.3.18",
3
+ "version": "0.3.19",
4
4
  "description": "Floating Aleph sponsor relay UI components for Svelte and React.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -36,8 +36,8 @@
36
36
  "access": "public"
37
37
  },
38
38
  "dependencies": {
39
- "@le-space/browser": "0.3.18",
40
- "@le-space/core": "0.3.18",
39
+ "@le-space/browser": "0.3.19",
40
+ "@le-space/core": "0.3.19",
41
41
  "viem": "^2.38.5"
42
42
  },
43
43
  "peerDependencies": {
package/react/index.js CHANGED
@@ -39,7 +39,7 @@ var RECENT_INSTANCE_RUNTIME_GRACE_MS = 10 * 60 * 1e3;
39
39
  var DEPLOYMENT_PENDING_WARNING_MS = 3 * 60 * 1e3;
40
40
 
41
41
  // src/shared/package-version.ts
42
- var UI_PACKAGE_VERSION = "0.3.18";
42
+ var UI_PACKAGE_VERSION = "0.3.19";
43
43
 
44
44
  // src/shared/format.ts
45
45
  function shortHash(value, head = 8, tail = 6) {
@@ -2152,31 +2152,6 @@ var DEFAULT_ALEPH_BOOTSTRAP_REF = "simple-todo-bootstrap";
2152
2152
  var DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE = "relay-bootstrap";
2153
2153
  var DEFAULT_BOOTSTRAP_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
2154
2154
  var DEFAULT_BOOTSTRAP_PAGINATION = 50;
2155
- var RELAY_BOOTSTRAP_SIGNATURE_SCHEME = "personal_sign";
2156
- function serializeOwnerAuthorizationPayload(payload) {
2157
- return JSON.stringify({
2158
- ownerAddress: payload.ownerAddress,
2159
- publisherAddress: payload.publisherAddress,
2160
- peerId: payload.peerId,
2161
- registrationId: payload.registrationId,
2162
- profile: payload.profile,
2163
- version: payload.version,
2164
- instanceItemHash: payload.instanceItemHash,
2165
- issuedAt: payload.issuedAt,
2166
- expiresAt: payload.expiresAt
2167
- });
2168
- }
2169
- function serializeRelayProofPayload(payload) {
2170
- return JSON.stringify({
2171
- peerId: payload.peerId,
2172
- multiaddrs: dedupeMultiaddrs(payload.multiaddrs),
2173
- browserMultiaddrs: payload.browserMultiaddrs ? dedupeMultiaddrs(payload.browserMultiaddrs) : void 0,
2174
- registrationId: payload.registrationId,
2175
- profile: payload.profile,
2176
- version: payload.version,
2177
- updatedAt: payload.updatedAt
2178
- });
2179
- }
2180
2155
  function asTrimmedString(value) {
2181
2156
  return typeof value === "string" && value.trim() ? value.trim() : null;
2182
2157
  }
@@ -2188,48 +2163,9 @@ function asNumber4(value) {
2188
2163
  }
2189
2164
  return null;
2190
2165
  }
2191
- function normalizeHost(host) {
2192
- return host.trim().toLowerCase();
2193
- }
2194
2166
  function normalizeAddress(address) {
2195
2167
  return address.trim().toLowerCase();
2196
2168
  }
2197
- function normalizeSignature(signature) {
2198
- const trimmed = signature.trim();
2199
- return trimmed.startsWith("0x") ? trimmed : `0x${trimmed}`;
2200
- }
2201
- function splitMultiaddr(addr) {
2202
- return addr.split("/").filter(Boolean);
2203
- }
2204
- function isPrivateIpv4(ip) {
2205
- const parts = ip.split(".").map((part) => Number(part));
2206
- if (parts.length !== 4 || parts.some((part) => !Number.isInteger(part) || part < 0 || part > 255)) {
2207
- return false;
2208
- }
2209
- if (parts[0] === 10) return true;
2210
- if (parts[0] === 127) return true;
2211
- if (parts[0] === 0) return true;
2212
- if (parts[0] === 169 && parts[1] === 254) return true;
2213
- if (parts[0] === 172 && parts[1] >= 16 && parts[1] <= 31) return true;
2214
- if (parts[0] === 192 && parts[1] === 168) return true;
2215
- if (parts[0] === 100 && parts[1] >= 64 && parts[1] <= 127) return true;
2216
- return false;
2217
- }
2218
- function isPrivateIpv6(ip) {
2219
- const normalized = ip.trim().toLowerCase();
2220
- return normalized === "::1" || normalized.startsWith("fc") || normalized.startsWith("fd") || normalized.startsWith("fe8") || normalized.startsWith("fe9") || normalized.startsWith("fea") || normalized.startsWith("feb");
2221
- }
2222
- function isLocalHostname(host) {
2223
- const normalized = normalizeHost(host);
2224
- return normalized === "localhost" || normalized.endsWith(".localhost") || normalized.endsWith(".local");
2225
- }
2226
- function hasPeerId(addr) {
2227
- return splitMultiaddr(addr).includes("p2p");
2228
- }
2229
- function isBrowserDialableMultiaddr(addr) {
2230
- const normalized = addr.toLowerCase();
2231
- return normalized.includes("/ws") || normalized.includes("/wss") || normalized.includes("/webtransport") || normalized.includes("/webrtc-direct");
2232
- }
2233
2169
  function dedupeMultiaddrs(addrs) {
2234
2170
  const seen = /* @__PURE__ */ new Set();
2235
2171
  const result = [];
@@ -2241,33 +2177,6 @@ function dedupeMultiaddrs(addrs) {
2241
2177
  }
2242
2178
  return result;
2243
2179
  }
2244
- function isPublicMultiaddr(addr) {
2245
- const parts = splitMultiaddr(addr);
2246
- for (let index = 0; index < parts.length; index += 1) {
2247
- const protocol = parts[index];
2248
- const value = parts[index + 1];
2249
- if (protocol === "ip4" && value) {
2250
- return !isPrivateIpv4(value);
2251
- }
2252
- if (protocol === "ip6" && value) {
2253
- return !isPrivateIpv6(value);
2254
- }
2255
- if ((protocol === "dns4" || protocol === "dns6" || protocol === "dnsaddr") && value) {
2256
- return !isLocalHostname(value);
2257
- }
2258
- }
2259
- return false;
2260
- }
2261
- function filterPublicMultiaddrs(addrs, options = {}) {
2262
- return dedupeMultiaddrs(addrs).filter((addr) => {
2263
- if (!isPublicMultiaddr(addr)) return false;
2264
- if (options.requirePeerId !== false && !hasPeerId(addr)) return false;
2265
- if (options.browserDialableOnly && !isBrowserDialableMultiaddr(addr)) {
2266
- return false;
2267
- }
2268
- return true;
2269
- });
2270
- }
2271
2180
  function normalizeRelayBootstrapContent(value) {
2272
2181
  if (!value || typeof value !== "object") return null;
2273
2182
  const content = value;
@@ -2362,104 +2271,6 @@ function normalizeRelayBootstrapPostRecord(value) {
2362
2271
  content: normalizeRelayBootstrapContent(entry.content)
2363
2272
  };
2364
2273
  }
2365
- function buildRelayBootstrapPostContent(args) {
2366
- const now = args.now ?? Date.now() / 1e3;
2367
- const updatedAt = args.now ?? Date.now();
2368
- return {
2369
- type: args.postType ?? DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE,
2370
- address: args.sender,
2371
- ...args.ref ? { ref: args.ref } : {},
2372
- content: {
2373
- peerId: args.peerId,
2374
- multiaddrs: filterPublicMultiaddrs(args.multiaddrs),
2375
- browserMultiaddrs: args.browserMultiaddrs ? filterPublicMultiaddrs(args.browserMultiaddrs, {
2376
- browserDialableOnly: true
2377
- }) : void 0,
2378
- registrationId: args.registrationId,
2379
- profile: args.profile,
2380
- version: args.version,
2381
- ownerAddress: args.ownerAddress,
2382
- publisherAddress: args.publisherAddress,
2383
- authorization: args.authorization,
2384
- relayProof: args.relayProof,
2385
- updatedAt: Math.round(updatedAt)
2386
- },
2387
- time: now
2388
- };
2389
- }
2390
- async function createRelayBootstrapPost(args) {
2391
- const nowMillis = args.now ?? Date.now();
2392
- const nowSeconds = nowMillis / 1e3;
2393
- const itemContent = buildRelayBootstrapPostContent({
2394
- sender: args.sender,
2395
- peerId: args.peerId,
2396
- multiaddrs: args.multiaddrs,
2397
- browserMultiaddrs: args.browserMultiaddrs,
2398
- registrationId: args.registrationId,
2399
- ref: args.ref ?? DEFAULT_ALEPH_BOOTSTRAP_REF,
2400
- postType: args.postType ?? DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE,
2401
- profile: args.profile,
2402
- version: args.version,
2403
- ownerAddress: args.ownerAddress,
2404
- publisherAddress: args.publisherAddress,
2405
- authorization: args.authorization,
2406
- relayProof: args.relayProof,
2407
- now: nowMillis
2408
- });
2409
- itemContent.time = nowSeconds;
2410
- const serialized = JSON.stringify(itemContent);
2411
- const itemHash = await args.hasher(serialized);
2412
- return {
2413
- channel: args.channel ?? DEFAULT_ALEPH_BOOTSTRAP_CHANNEL,
2414
- sender: args.sender,
2415
- chain: "ETH",
2416
- type: "POST",
2417
- time: nowSeconds,
2418
- item_type: "inline",
2419
- item_content: serialized,
2420
- item_hash: itemHash
2421
- };
2422
- }
2423
- async function signRelayBootstrapAuthorization(args) {
2424
- const payload = {
2425
- ownerAddress: args.ownerAddress,
2426
- publisherAddress: args.publisherAddress,
2427
- peerId: args.peerId,
2428
- registrationId: args.registrationId,
2429
- profile: args.profile,
2430
- version: args.version,
2431
- instanceItemHash: args.instanceItemHash,
2432
- issuedAt: args.issuedAt ?? Date.now(),
2433
- expiresAt: args.expiresAt
2434
- };
2435
- const serialized = serializeOwnerAuthorizationPayload(payload);
2436
- const signature = await args.signer(args.ownerAddress, serialized);
2437
- return {
2438
- scheme: RELAY_BOOTSTRAP_SIGNATURE_SCHEME,
2439
- payload,
2440
- signature: normalizeSignature(signature)
2441
- };
2442
- }
2443
- async function signRelayBootstrapProof(args) {
2444
- const payload = {
2445
- peerId: args.peerId,
2446
- multiaddrs: filterPublicMultiaddrs(args.multiaddrs),
2447
- browserMultiaddrs: args.browserMultiaddrs ? filterPublicMultiaddrs(args.browserMultiaddrs, {
2448
- browserDialableOnly: true
2449
- }) : void 0,
2450
- registrationId: args.registrationId,
2451
- profile: args.profile,
2452
- version: args.version,
2453
- updatedAt: args.updatedAt ?? Date.now()
2454
- };
2455
- const serialized = serializeRelayProofPayload(payload);
2456
- const signature = await args.signer(args.publisherAddress, serialized);
2457
- return {
2458
- scheme: RELAY_BOOTSTRAP_SIGNATURE_SCHEME,
2459
- payload,
2460
- signature: normalizeSignature(signature)
2461
- };
2462
- }
2463
2274
  async function fetchAlephBootstrapPosts(options = {}) {
2464
2275
  const fetchImpl = options.fetch ?? globalThis.fetch?.bind(globalThis);
2465
2276
  if (typeof fetchImpl !== "function") {
@@ -2537,7 +2348,7 @@ function sleep(ms) {
2537
2348
  async function waitForRelayBootstrapRegistration(args) {
2538
2349
  const attempts = Math.max(1, Number(args.attempts ?? 10));
2539
2350
  const delayMs = Math.max(0, Number(args.delayMs ?? 2e3));
2540
- const expectedSender = args.sender.trim().toLowerCase();
2351
+ const expectedSender = args.sender?.trim().toLowerCase() || null;
2541
2352
  const expectedRegistrationId = args.registrationId?.trim() || null;
2542
2353
  const expectedPeerId = args.peerId?.trim() || null;
2543
2354
  for (let attempt = 0; attempt < attempts; attempt += 1) {
@@ -2550,8 +2361,9 @@ async function waitForRelayBootstrapRegistration(args) {
2550
2361
  });
2551
2362
  const currentPosts = selectCurrentRelayBootstrapPosts(posts);
2552
2363
  const match = currentPosts.find((post) => {
2553
- const senderMatches = post.address?.toLowerCase() === expectedSender;
2554
- if (!senderMatches) return false;
2364
+ if (expectedSender && post.address?.toLowerCase() !== expectedSender) {
2365
+ return false;
2366
+ }
2555
2367
  if (expectedRegistrationId && post.content?.registrationId === expectedRegistrationId) {
2556
2368
  return true;
2557
2369
  }
@@ -2564,6 +2376,7 @@ async function waitForRelayBootstrapRegistration(args) {
2564
2376
  return {
2565
2377
  itemHash: match.itemHash ?? null,
2566
2378
  hash: match.hash ?? null,
2379
+ sender: typeof match.address === "string" ? match.address : null,
2567
2380
  registrationId: match.content.registrationId,
2568
2381
  peerId: match.content.peerId,
2569
2382
  multiaddrs: Array.isArray(match.content.multiaddrs) ? match.content.multiaddrs : [],
@@ -2576,109 +2389,6 @@ async function waitForRelayBootstrapRegistration(args) {
2576
2389
  }
2577
2390
  return null;
2578
2391
  }
2579
- async function publishRelayBootstrapRegistration(args) {
2580
- const publisherAddress = args.publisherAddress ?? args.sender;
2581
- const ownerAddress = args.ownerAddress;
2582
- let ownerAuthorization = args.ownerAuthorization;
2583
- let relayProof = args.relayProof;
2584
- if (!ownerAuthorization && ownerAddress && args.ownerSigner) {
2585
- ownerAuthorization = await signRelayBootstrapAuthorization({
2586
- ownerAddress,
2587
- publisherAddress,
2588
- peerId: args.peerId,
2589
- registrationId: args.registrationId,
2590
- profile: args.profile,
2591
- version: args.version,
2592
- instanceItemHash: args.instanceItemHash,
2593
- issuedAt: args.authorizationIssuedAt ?? args.now ?? Date.now(),
2594
- expiresAt: args.authorizationExpiresAt,
2595
- signer: args.ownerSigner
2596
- });
2597
- }
2598
- if (!relayProof && args.publisherSigner) {
2599
- relayProof = await signRelayBootstrapProof({
2600
- publisherAddress,
2601
- peerId: args.peerId,
2602
- multiaddrs: args.multiaddrs,
2603
- browserMultiaddrs: args.browserMultiaddrs,
2604
- registrationId: args.registrationId,
2605
- profile: args.profile,
2606
- version: args.version,
2607
- updatedAt: args.now ?? Date.now(),
2608
- signer: args.publisherSigner
2609
- });
2610
- }
2611
- const unsigned = await createRelayBootstrapPost({
2612
- sender: args.sender,
2613
- peerId: args.peerId,
2614
- multiaddrs: args.multiaddrs,
2615
- browserMultiaddrs: args.browserMultiaddrs,
2616
- registrationId: args.registrationId,
2617
- channel: args.channel,
2618
- ref: args.ref,
2619
- postType: args.postType,
2620
- profile: args.profile,
2621
- version: args.version,
2622
- ownerAddress,
2623
- publisherAddress,
2624
- authorization: ownerAuthorization,
2625
- relayProof,
2626
- now: args.now,
2627
- hasher: args.hasher
2628
- });
2629
- const content = JSON.parse(unsigned.item_content);
2630
- if ((content.content?.multiaddrs?.length ?? 0) === 0) {
2631
- return {
2632
- status: "skipped",
2633
- reason: "No public relay multiaddrs remained after filtering.",
2634
- publishedMultiaddrs: [],
2635
- publishedBrowserMultiaddrs: content.content?.browserMultiaddrs ?? []
2636
- };
2637
- }
2638
- const message = await signAlephMessage(unsigned, args.signer);
2639
- const { response, httpStatus } = await broadcastAlephMessage2(message, {
2640
- apiHost: args.apiHost ?? DEFAULT_ALEPH_API_HOST3,
2641
- sync: args.sync ?? true,
2642
- fetch: args.fetch
2643
- });
2644
- let forgottenHashes = [];
2645
- let forgetResult;
2646
- if (args.forgetPrevious && args.registrationId) {
2647
- const previousPosts = await fetchAlephBootstrapPosts({
2648
- apiHost: args.apiHost ?? DEFAULT_ALEPH_API_HOST3,
2649
- channel: args.channel,
2650
- ref: args.ref,
2651
- postType: args.postType,
2652
- fetch: args.fetch
2653
- });
2654
- forgottenHashes = previousPosts.filter(
2655
- (post) => post.address?.toLowerCase() === args.sender.toLowerCase() && post.content?.registrationId === args.registrationId && (post.itemHash ?? post.hash) != null && (post.itemHash ?? post.hash) !== unsigned.item_hash
2656
- ).map((post) => post.itemHash ?? post.hash ?? "").filter(Boolean);
2657
- if (forgottenHashes.length > 0) {
2658
- forgetResult = await forgetAlephMessages({
2659
- sender: args.sender,
2660
- hashes: forgottenHashes,
2661
- reason: args.forgetPreviousReason ?? `Replace older relay bootstrap records for ${args.registrationId}`,
2662
- signer: args.signer,
2663
- hasher: args.hasher,
2664
- fetch: args.fetch,
2665
- apiHost: args.apiHost ?? DEFAULT_ALEPH_API_HOST3,
2666
- sync: args.sync ?? true
2667
- });
2668
- }
2669
- }
2670
- return {
2671
- status: "published",
2672
- itemHash: unsigned.item_hash,
2673
- message,
2674
- response,
2675
- httpStatus,
2676
- publishedMultiaddrs: content.content?.multiaddrs ?? [],
2677
- publishedBrowserMultiaddrs: content.content?.browserMultiaddrs ?? [],
2678
- forgottenHashes,
2679
- forgetResult
2680
- };
2681
- }
2682
2392
 
2683
2393
  // ../core/src/bootstrap-config.ts
2684
2394
  var VM_BOOTSTRAP_CONFIG_AGGREGATE_KEY = "vm-bootstrap-config";
@@ -2832,24 +2542,6 @@ function extractRelayMetadata(payload) {
2832
2542
  browserBootstrapMultiaddrs
2833
2543
  };
2834
2544
  }
2835
- async function fetchOwnerInstances(address, options) {
2836
- const url = new URL("/api/v0/messages.json", options.apiHost ?? DEFAULT_ALEPH_API_HOST2);
2837
- url.searchParams.set("msgTypes", "INSTANCE");
2838
- url.searchParams.set("addresses", address);
2839
- url.searchParams.set("message_statuses", "processed,pending,rejected,removing");
2840
- url.searchParams.set("pagination", "100");
2841
- url.searchParams.set("page", "1");
2842
- url.searchParams.set("sortOrder", "-1");
2843
- const response = await options.fetch(url.toString(), { cache: "no-cache" });
2844
- if (!response.ok) {
2845
- throw new Error(`Instance list request failed: ${response.status}`);
2846
- }
2847
- const payload = await response.json();
2848
- return (payload.messages ?? []).map((message) => ({
2849
- ...message,
2850
- status: typeof message.status === "string" && message.status.trim() ? message.status : message.confirmed ? "processed" : "pending"
2851
- }));
2852
- }
2853
2545
  async function fetchRelayMetadataForRuntime(args) {
2854
2546
  const setupPort = args.runtime.mappedPorts?.["80"]?.host ?? 80;
2855
2547
  const metadataUrl = args.preferSecureMetadata ? secureBootstrapMetadataUrl(args.runtime.proxyUrl) : null;
@@ -2876,123 +2568,6 @@ async function fetchRelayMetadataForRuntime(args) {
2876
2568
  }).catch(() => null);
2877
2569
  return extractRelayMetadata(payload);
2878
2570
  }
2879
- async function reconcileOwnerRelayBootstrapRegistrations(args) {
2880
- const result = {
2881
- refreshedRegistrations: [],
2882
- forgottenHashes: [],
2883
- skippedInstanceHashes: [],
2884
- errors: []
2885
- };
2886
- const liveRegistrationIds = /* @__PURE__ */ new Set();
2887
- if (args.current?.registrationId) {
2888
- liveRegistrationIds.add(args.current.registrationId);
2889
- result.refreshedRegistrations.push(args.current.registrationId);
2890
- }
2891
- const instances = await fetchOwnerInstances(args.instanceOwnerAddress, {
2892
- apiHost: args.apiHost,
2893
- fetch: args.fetch
2894
- });
2895
- const processedInstances = instances.filter((instance) => {
2896
- const status = String(instance.status ?? "").trim().toLowerCase();
2897
- return status === "processed";
2898
- });
2899
- for (const instance of processedInstances) {
2900
- if (instance.item_hash === args.current?.itemHash) continue;
2901
- const registrationId = createRelayBootstrapRegistrationId(
2902
- args.profile,
2903
- instance.content?.metadata?.name,
2904
- instance.item_hash
2905
- );
2906
- try {
2907
- const runtime = await fetchVmRuntime({
2908
- itemHash: instance.item_hash,
2909
- fetch: args.fetch,
2910
- crns: args.crns,
2911
- crnListUrl: args.crnListUrl
2912
- });
2913
- if (!runtime.hostIpv4 || Object.keys(runtime.mappedPorts ?? {}).length === 0) {
2914
- result.skippedInstanceHashes.push(instance.item_hash);
2915
- continue;
2916
- }
2917
- const relayMetadata = await fetchRelayMetadataForRuntime({
2918
- runtime,
2919
- fetch: args.fetch,
2920
- preferSecureMetadata: args.preferSecureMetadata,
2921
- attempts: 3,
2922
- delayMs: 1e3,
2923
- timeoutMs: 1e4
2924
- });
2925
- if (!relayMetadata) {
2926
- result.skippedInstanceHashes.push(instance.item_hash);
2927
- continue;
2928
- }
2929
- liveRegistrationIds.add(registrationId);
2930
- await publishRelayBootstrapRegistration({
2931
- sender: args.sender,
2932
- signer: args.signer,
2933
- hasher: args.hasher,
2934
- fetch: args.fetch,
2935
- apiHost: args.apiHost,
2936
- channel: args.channel,
2937
- ref: args.ref,
2938
- postType: args.postType,
2939
- peerId: relayMetadata.peerId,
2940
- multiaddrs: relayMetadata.probeMultiaddrs,
2941
- browserMultiaddrs: relayMetadata.browserBootstrapMultiaddrs,
2942
- registrationId,
2943
- ownerAddress: args.ownerAddress,
2944
- publisherAddress: args.publisherAddress,
2945
- ownerSigner: args.ownerSigner,
2946
- publisherSigner: args.publisherSigner,
2947
- forgetPrevious: true,
2948
- profile: args.profile,
2949
- version: args.version,
2950
- instanceItemHash: instance.item_hash,
2951
- sync: true
2952
- });
2953
- result.refreshedRegistrations.push(registrationId);
2954
- } catch (error) {
2955
- result.errors.push({
2956
- phase: "publish",
2957
- itemHash: instance.item_hash,
2958
- registrationId,
2959
- message: error instanceof Error ? error.message : String(error)
2960
- });
2961
- }
2962
- }
2963
- try {
2964
- const bootstrapPosts = await fetchAlephBootstrapPosts({
2965
- apiHost: args.apiHost ?? DEFAULT_ALEPH_API_HOST2,
2966
- channel: args.channel,
2967
- ref: args.ref,
2968
- postType: args.postType,
2969
- fetch: args.fetch
2970
- });
2971
- const currentPosts = selectCurrentRelayBootstrapPosts(bootstrapPosts);
2972
- const staleHashes = currentPosts.filter(
2973
- (post) => post.address?.toLowerCase() === args.sender.toLowerCase() && post.content?.profile === args.profile && post.content?.registrationId && !liveRegistrationIds.has(post.content.registrationId)
2974
- ).map((post) => post.itemHash ?? post.hash ?? "").filter(Boolean);
2975
- if (staleHashes.length > 0) {
2976
- await forgetAlephMessages({
2977
- sender: args.sender,
2978
- hashes: staleHashes,
2979
- reason: `Forget stale ${args.profile} relay bootstrap registrations after owner reconcile`,
2980
- signer: args.signer,
2981
- hasher: args.hasher,
2982
- fetch: args.fetch,
2983
- apiHost: args.apiHost ?? DEFAULT_ALEPH_API_HOST2,
2984
- sync: true
2985
- });
2986
- result.forgottenHashes.push(...staleHashes);
2987
- }
2988
- } catch (error) {
2989
- result.errors.push({
2990
- phase: "forget",
2991
- message: error instanceof Error ? error.message : String(error)
2992
- });
2993
- }
2994
- return result;
2995
- }
2996
2571
 
2997
2572
  // src/shared/events.ts
2998
2573
  function createDeploymentProgressEmitter() {
@@ -3612,7 +3187,7 @@ var SponsorRelayController = class {
3612
3187
  if (!relayMetadata) {
3613
3188
  throw new Error("Relay metadata did not include a peer ID and public multiaddrs.");
3614
3189
  }
3615
- const { peerId, probeMultiaddrs, browserBootstrapMultiaddrs } = relayMetadata;
3190
+ const { peerId } = relayMetadata;
3616
3191
  const registrationId = createRelayBootstrapRegistrationId(
3617
3192
  profile,
3618
3193
  this.state.instanceName.trim(),
@@ -3620,48 +3195,18 @@ var SponsorRelayController = class {
3620
3195
  );
3621
3196
  this.emitProgress({
3622
3197
  stage: "publishing-bootstrap",
3623
- label: "Publishing bootstrap registration",
3198
+ label: "Waiting for guest bootstrap registration",
3624
3199
  progress: 96,
3625
3200
  status: "info",
3626
3201
  itemHash: args.itemHash,
3627
- detail: "Writing the relay bootstrap registration to Aleph."
3628
- });
3629
- const publication = await publishRelayBootstrapRegistration({
3630
- sender: this.state.wallet.address,
3631
- signer: personalSign,
3632
- hasher: sha256Hex,
3633
- fetch: asJsonFetch,
3634
- apiHost: this.client.apiHost,
3635
- peerId,
3636
- multiaddrs: probeMultiaddrs,
3637
- browserMultiaddrs: browserBootstrapMultiaddrs,
3638
- registrationId,
3639
- profile,
3640
- version: this.state.manifest?.version,
3641
- forgetPrevious: true,
3642
- sync: true
3643
- });
3644
- this.trace("deploy:bootstrap-registration", {
3645
- itemHash: args.itemHash,
3646
- peerId,
3647
- metadata: relayMetadata,
3648
- publication
3649
- });
3650
- this.emitProgress({
3651
- stage: "publishing-bootstrap",
3652
- label: "Verifying bootstrap registration",
3653
- progress: 97,
3654
- status: "info",
3655
- itemHash: args.itemHash,
3656
- detail: "Waiting for the relay bootstrap registration to appear on Aleph."
3202
+ detail: "Waiting for the relay VM to publish its own bootstrap registration to Aleph."
3657
3203
  });
3658
3204
  const visibleRegistration = await waitForRelayBootstrapRegistration({
3659
- sender: this.state.wallet.address,
3660
3205
  registrationId,
3661
3206
  peerId,
3662
3207
  fetch: asJsonFetch,
3663
3208
  apiHost: this.client.apiHost,
3664
- attempts: 12,
3209
+ attempts: 24,
3665
3210
  delayMs: 2500
3666
3211
  });
3667
3212
  this.trace("deploy:bootstrap-registration-visible", {
@@ -3675,31 +3220,6 @@ var SponsorRelayController = class {
3675
3220
  "Relay bootstrap registration did not become visible on Aleph."
3676
3221
  );
3677
3222
  }
3678
- const reconcileResult = await reconcileOwnerRelayBootstrapRegistrations({
3679
- instanceOwnerAddress: this.state.wallet.address,
3680
- sender: this.state.wallet.address,
3681
- signer: personalSign,
3682
- hasher: sha256Hex,
3683
- fetch: asJsonFetch,
3684
- profile,
3685
- apiHost: this.client.apiHost,
3686
- crns: this.state.crns,
3687
- crnListUrl: this.props.crnListUrl,
3688
- preferSecureMetadata: profile === "uc-go-peer",
3689
- current: {
3690
- itemHash: args.itemHash,
3691
- registrationId,
3692
- peerId,
3693
- probeMultiaddrs,
3694
- browserBootstrapMultiaddrs
3695
- }
3696
- });
3697
- if (reconcileResult.errors.length > 0) {
3698
- this.trace("deploy:owner-bootstrap-reconcile-errors", {
3699
- itemHash: args.itemHash,
3700
- errors: reconcileResult.errors
3701
- });
3702
- }
3703
3223
  if (profile === "uc-go-peer" && args.deploymentToken) {
3704
3224
  await deleteVmBootstrapConfig({
3705
3225
  sender: this.state.wallet.address,
@@ -4537,29 +4057,6 @@ var SponsorRelayController = class {
4537
4057
  this.emitProgress(event);
4538
4058
  }
4539
4059
  });
4540
- const profile = relayProfileForManifest(this.state.manifest);
4541
- if (profile) {
4542
- await reconcileOwnerRelayBootstrapRegistrations({
4543
- instanceOwnerAddress: this.state.wallet.address,
4544
- sender: this.state.wallet.address,
4545
- signer: personalSign,
4546
- hasher: sha256Hex,
4547
- fetch: asJsonFetch,
4548
- profile,
4549
- apiHost: this.client.apiHost,
4550
- crns: this.state.crns,
4551
- crnListUrl: this.props.crnListUrl,
4552
- preferSecureMetadata: profile === "uc-go-peer"
4553
- }).catch(
4554
- (error) => {
4555
- this.trace("delete:owner-bootstrap-reconcile-error", {
4556
- instanceHash,
4557
- profile,
4558
- error: error instanceof Error ? error.message : String(error)
4559
- });
4560
- }
4561
- );
4562
- }
4563
4060
  this.patch({
4564
4061
  busy: { deletingInstanceHash: null },
4565
4062
  statusText: `Deletion submitted for ${instanceHash}`
package/shared/index.d.ts CHANGED
@@ -304,7 +304,7 @@ declare const STALE_INSTANCE_ALLOCATION_COOLDOWN_MS: number;
304
304
  declare const RECENT_INSTANCE_RUNTIME_GRACE_MS: number;
305
305
  declare const DEPLOYMENT_PENDING_WARNING_MS: number;
306
306
 
307
- declare const UI_PACKAGE_VERSION = "0.3.18";
307
+ declare const UI_PACKAGE_VERSION = "0.3.19";
308
308
 
309
309
  interface RootfsRequiredPortForward {
310
310
  port: number;
package/shared/index.js CHANGED
@@ -38,7 +38,7 @@ var RECENT_INSTANCE_RUNTIME_GRACE_MS = 10 * 60 * 1e3;
38
38
  var DEPLOYMENT_PENDING_WARNING_MS = 3 * 60 * 1e3;
39
39
 
40
40
  // src/shared/package-version.ts
41
- var UI_PACKAGE_VERSION = "0.3.18";
41
+ var UI_PACKAGE_VERSION = "0.3.19";
42
42
 
43
43
  // src/shared/format.ts
44
44
  function shortHash(value, head = 8, tail = 6) {
@@ -2151,31 +2151,6 @@ var DEFAULT_ALEPH_BOOTSTRAP_REF = "simple-todo-bootstrap";
2151
2151
  var DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE = "relay-bootstrap";
2152
2152
  var DEFAULT_BOOTSTRAP_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
2153
2153
  var DEFAULT_BOOTSTRAP_PAGINATION = 50;
2154
- var RELAY_BOOTSTRAP_SIGNATURE_SCHEME = "personal_sign";
2155
- function serializeOwnerAuthorizationPayload(payload) {
2156
- return JSON.stringify({
2157
- ownerAddress: payload.ownerAddress,
2158
- publisherAddress: payload.publisherAddress,
2159
- peerId: payload.peerId,
2160
- registrationId: payload.registrationId,
2161
- profile: payload.profile,
2162
- version: payload.version,
2163
- instanceItemHash: payload.instanceItemHash,
2164
- issuedAt: payload.issuedAt,
2165
- expiresAt: payload.expiresAt
2166
- });
2167
- }
2168
- function serializeRelayProofPayload(payload) {
2169
- return JSON.stringify({
2170
- peerId: payload.peerId,
2171
- multiaddrs: dedupeMultiaddrs(payload.multiaddrs),
2172
- browserMultiaddrs: payload.browserMultiaddrs ? dedupeMultiaddrs(payload.browserMultiaddrs) : void 0,
2173
- registrationId: payload.registrationId,
2174
- profile: payload.profile,
2175
- version: payload.version,
2176
- updatedAt: payload.updatedAt
2177
- });
2178
- }
2179
2154
  function asTrimmedString(value) {
2180
2155
  return typeof value === "string" && value.trim() ? value.trim() : null;
2181
2156
  }
@@ -2187,48 +2162,9 @@ function asNumber4(value) {
2187
2162
  }
2188
2163
  return null;
2189
2164
  }
2190
- function normalizeHost(host) {
2191
- return host.trim().toLowerCase();
2192
- }
2193
2165
  function normalizeAddress(address) {
2194
2166
  return address.trim().toLowerCase();
2195
2167
  }
2196
- function normalizeSignature(signature) {
2197
- const trimmed = signature.trim();
2198
- return trimmed.startsWith("0x") ? trimmed : `0x${trimmed}`;
2199
- }
2200
- function splitMultiaddr(addr) {
2201
- return addr.split("/").filter(Boolean);
2202
- }
2203
- function isPrivateIpv4(ip) {
2204
- const parts = ip.split(".").map((part) => Number(part));
2205
- if (parts.length !== 4 || parts.some((part) => !Number.isInteger(part) || part < 0 || part > 255)) {
2206
- return false;
2207
- }
2208
- if (parts[0] === 10) return true;
2209
- if (parts[0] === 127) return true;
2210
- if (parts[0] === 0) return true;
2211
- if (parts[0] === 169 && parts[1] === 254) return true;
2212
- if (parts[0] === 172 && parts[1] >= 16 && parts[1] <= 31) return true;
2213
- if (parts[0] === 192 && parts[1] === 168) return true;
2214
- if (parts[0] === 100 && parts[1] >= 64 && parts[1] <= 127) return true;
2215
- return false;
2216
- }
2217
- function isPrivateIpv6(ip) {
2218
- const normalized = ip.trim().toLowerCase();
2219
- return normalized === "::1" || normalized.startsWith("fc") || normalized.startsWith("fd") || normalized.startsWith("fe8") || normalized.startsWith("fe9") || normalized.startsWith("fea") || normalized.startsWith("feb");
2220
- }
2221
- function isLocalHostname(host) {
2222
- const normalized = normalizeHost(host);
2223
- return normalized === "localhost" || normalized.endsWith(".localhost") || normalized.endsWith(".local");
2224
- }
2225
- function hasPeerId(addr) {
2226
- return splitMultiaddr(addr).includes("p2p");
2227
- }
2228
- function isBrowserDialableMultiaddr(addr) {
2229
- const normalized = addr.toLowerCase();
2230
- return normalized.includes("/ws") || normalized.includes("/wss") || normalized.includes("/webtransport") || normalized.includes("/webrtc-direct");
2231
- }
2232
2168
  function dedupeMultiaddrs(addrs) {
2233
2169
  const seen = /* @__PURE__ */ new Set();
2234
2170
  const result = [];
@@ -2240,33 +2176,6 @@ function dedupeMultiaddrs(addrs) {
2240
2176
  }
2241
2177
  return result;
2242
2178
  }
2243
- function isPublicMultiaddr(addr) {
2244
- const parts = splitMultiaddr(addr);
2245
- for (let index = 0; index < parts.length; index += 1) {
2246
- const protocol = parts[index];
2247
- const value = parts[index + 1];
2248
- if (protocol === "ip4" && value) {
2249
- return !isPrivateIpv4(value);
2250
- }
2251
- if (protocol === "ip6" && value) {
2252
- return !isPrivateIpv6(value);
2253
- }
2254
- if ((protocol === "dns4" || protocol === "dns6" || protocol === "dnsaddr") && value) {
2255
- return !isLocalHostname(value);
2256
- }
2257
- }
2258
- return false;
2259
- }
2260
- function filterPublicMultiaddrs(addrs, options = {}) {
2261
- return dedupeMultiaddrs(addrs).filter((addr) => {
2262
- if (!isPublicMultiaddr(addr)) return false;
2263
- if (options.requirePeerId !== false && !hasPeerId(addr)) return false;
2264
- if (options.browserDialableOnly && !isBrowserDialableMultiaddr(addr)) {
2265
- return false;
2266
- }
2267
- return true;
2268
- });
2269
- }
2270
2179
  function normalizeRelayBootstrapContent(value) {
2271
2180
  if (!value || typeof value !== "object") return null;
2272
2181
  const content = value;
@@ -2361,104 +2270,6 @@ function normalizeRelayBootstrapPostRecord(value) {
2361
2270
  content: normalizeRelayBootstrapContent(entry.content)
2362
2271
  };
2363
2272
  }
2364
- function buildRelayBootstrapPostContent(args) {
2365
- const now = args.now ?? Date.now() / 1e3;
2366
- const updatedAt = args.now ?? Date.now();
2367
- return {
2368
- type: args.postType ?? DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE,
2369
- address: args.sender,
2370
- ...args.ref ? { ref: args.ref } : {},
2371
- content: {
2372
- peerId: args.peerId,
2373
- multiaddrs: filterPublicMultiaddrs(args.multiaddrs),
2374
- browserMultiaddrs: args.browserMultiaddrs ? filterPublicMultiaddrs(args.browserMultiaddrs, {
2375
- browserDialableOnly: true
2376
- }) : void 0,
2377
- registrationId: args.registrationId,
2378
- profile: args.profile,
2379
- version: args.version,
2380
- ownerAddress: args.ownerAddress,
2381
- publisherAddress: args.publisherAddress,
2382
- authorization: args.authorization,
2383
- relayProof: args.relayProof,
2384
- updatedAt: Math.round(updatedAt)
2385
- },
2386
- time: now
2387
- };
2388
- }
2389
- async function createRelayBootstrapPost(args) {
2390
- const nowMillis = args.now ?? Date.now();
2391
- const nowSeconds = nowMillis / 1e3;
2392
- const itemContent = buildRelayBootstrapPostContent({
2393
- sender: args.sender,
2394
- peerId: args.peerId,
2395
- multiaddrs: args.multiaddrs,
2396
- browserMultiaddrs: args.browserMultiaddrs,
2397
- registrationId: args.registrationId,
2398
- ref: args.ref ?? DEFAULT_ALEPH_BOOTSTRAP_REF,
2399
- postType: args.postType ?? DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE,
2400
- profile: args.profile,
2401
- version: args.version,
2402
- ownerAddress: args.ownerAddress,
2403
- publisherAddress: args.publisherAddress,
2404
- authorization: args.authorization,
2405
- relayProof: args.relayProof,
2406
- now: nowMillis
2407
- });
2408
- itemContent.time = nowSeconds;
2409
- const serialized = JSON.stringify(itemContent);
2410
- const itemHash = await args.hasher(serialized);
2411
- return {
2412
- channel: args.channel ?? DEFAULT_ALEPH_BOOTSTRAP_CHANNEL,
2413
- sender: args.sender,
2414
- chain: "ETH",
2415
- type: "POST",
2416
- time: nowSeconds,
2417
- item_type: "inline",
2418
- item_content: serialized,
2419
- item_hash: itemHash
2420
- };
2421
- }
2422
- async function signRelayBootstrapAuthorization(args) {
2423
- const payload = {
2424
- ownerAddress: args.ownerAddress,
2425
- publisherAddress: args.publisherAddress,
2426
- peerId: args.peerId,
2427
- registrationId: args.registrationId,
2428
- profile: args.profile,
2429
- version: args.version,
2430
- instanceItemHash: args.instanceItemHash,
2431
- issuedAt: args.issuedAt ?? Date.now(),
2432
- expiresAt: args.expiresAt
2433
- };
2434
- const serialized = serializeOwnerAuthorizationPayload(payload);
2435
- const signature = await args.signer(args.ownerAddress, serialized);
2436
- return {
2437
- scheme: RELAY_BOOTSTRAP_SIGNATURE_SCHEME,
2438
- payload,
2439
- signature: normalizeSignature(signature)
2440
- };
2441
- }
2442
- async function signRelayBootstrapProof(args) {
2443
- const payload = {
2444
- peerId: args.peerId,
2445
- multiaddrs: filterPublicMultiaddrs(args.multiaddrs),
2446
- browserMultiaddrs: args.browserMultiaddrs ? filterPublicMultiaddrs(args.browserMultiaddrs, {
2447
- browserDialableOnly: true
2448
- }) : void 0,
2449
- registrationId: args.registrationId,
2450
- profile: args.profile,
2451
- version: args.version,
2452
- updatedAt: args.updatedAt ?? Date.now()
2453
- };
2454
- const serialized = serializeRelayProofPayload(payload);
2455
- const signature = await args.signer(args.publisherAddress, serialized);
2456
- return {
2457
- scheme: RELAY_BOOTSTRAP_SIGNATURE_SCHEME,
2458
- payload,
2459
- signature: normalizeSignature(signature)
2460
- };
2461
- }
2462
2273
  async function fetchAlephBootstrapPosts(options = {}) {
2463
2274
  const fetchImpl = options.fetch ?? globalThis.fetch?.bind(globalThis);
2464
2275
  if (typeof fetchImpl !== "function") {
@@ -2536,7 +2347,7 @@ function sleep(ms) {
2536
2347
  async function waitForRelayBootstrapRegistration(args) {
2537
2348
  const attempts = Math.max(1, Number(args.attempts ?? 10));
2538
2349
  const delayMs = Math.max(0, Number(args.delayMs ?? 2e3));
2539
- const expectedSender = args.sender.trim().toLowerCase();
2350
+ const expectedSender = args.sender?.trim().toLowerCase() || null;
2540
2351
  const expectedRegistrationId = args.registrationId?.trim() || null;
2541
2352
  const expectedPeerId = args.peerId?.trim() || null;
2542
2353
  for (let attempt = 0; attempt < attempts; attempt += 1) {
@@ -2549,8 +2360,9 @@ async function waitForRelayBootstrapRegistration(args) {
2549
2360
  });
2550
2361
  const currentPosts = selectCurrentRelayBootstrapPosts(posts);
2551
2362
  const match = currentPosts.find((post) => {
2552
- const senderMatches = post.address?.toLowerCase() === expectedSender;
2553
- if (!senderMatches) return false;
2363
+ if (expectedSender && post.address?.toLowerCase() !== expectedSender) {
2364
+ return false;
2365
+ }
2554
2366
  if (expectedRegistrationId && post.content?.registrationId === expectedRegistrationId) {
2555
2367
  return true;
2556
2368
  }
@@ -2563,6 +2375,7 @@ async function waitForRelayBootstrapRegistration(args) {
2563
2375
  return {
2564
2376
  itemHash: match.itemHash ?? null,
2565
2377
  hash: match.hash ?? null,
2378
+ sender: typeof match.address === "string" ? match.address : null,
2566
2379
  registrationId: match.content.registrationId,
2567
2380
  peerId: match.content.peerId,
2568
2381
  multiaddrs: Array.isArray(match.content.multiaddrs) ? match.content.multiaddrs : [],
@@ -2575,109 +2388,6 @@ async function waitForRelayBootstrapRegistration(args) {
2575
2388
  }
2576
2389
  return null;
2577
2390
  }
2578
- async function publishRelayBootstrapRegistration(args) {
2579
- const publisherAddress = args.publisherAddress ?? args.sender;
2580
- const ownerAddress = args.ownerAddress;
2581
- let ownerAuthorization = args.ownerAuthorization;
2582
- let relayProof = args.relayProof;
2583
- if (!ownerAuthorization && ownerAddress && args.ownerSigner) {
2584
- ownerAuthorization = await signRelayBootstrapAuthorization({
2585
- ownerAddress,
2586
- publisherAddress,
2587
- peerId: args.peerId,
2588
- registrationId: args.registrationId,
2589
- profile: args.profile,
2590
- version: args.version,
2591
- instanceItemHash: args.instanceItemHash,
2592
- issuedAt: args.authorizationIssuedAt ?? args.now ?? Date.now(),
2593
- expiresAt: args.authorizationExpiresAt,
2594
- signer: args.ownerSigner
2595
- });
2596
- }
2597
- if (!relayProof && args.publisherSigner) {
2598
- relayProof = await signRelayBootstrapProof({
2599
- publisherAddress,
2600
- peerId: args.peerId,
2601
- multiaddrs: args.multiaddrs,
2602
- browserMultiaddrs: args.browserMultiaddrs,
2603
- registrationId: args.registrationId,
2604
- profile: args.profile,
2605
- version: args.version,
2606
- updatedAt: args.now ?? Date.now(),
2607
- signer: args.publisherSigner
2608
- });
2609
- }
2610
- const unsigned = await createRelayBootstrapPost({
2611
- sender: args.sender,
2612
- peerId: args.peerId,
2613
- multiaddrs: args.multiaddrs,
2614
- browserMultiaddrs: args.browserMultiaddrs,
2615
- registrationId: args.registrationId,
2616
- channel: args.channel,
2617
- ref: args.ref,
2618
- postType: args.postType,
2619
- profile: args.profile,
2620
- version: args.version,
2621
- ownerAddress,
2622
- publisherAddress,
2623
- authorization: ownerAuthorization,
2624
- relayProof,
2625
- now: args.now,
2626
- hasher: args.hasher
2627
- });
2628
- const content = JSON.parse(unsigned.item_content);
2629
- if ((content.content?.multiaddrs?.length ?? 0) === 0) {
2630
- return {
2631
- status: "skipped",
2632
- reason: "No public relay multiaddrs remained after filtering.",
2633
- publishedMultiaddrs: [],
2634
- publishedBrowserMultiaddrs: content.content?.browserMultiaddrs ?? []
2635
- };
2636
- }
2637
- const message = await signAlephMessage(unsigned, args.signer);
2638
- const { response, httpStatus } = await broadcastAlephMessage2(message, {
2639
- apiHost: args.apiHost ?? DEFAULT_ALEPH_API_HOST3,
2640
- sync: args.sync ?? true,
2641
- fetch: args.fetch
2642
- });
2643
- let forgottenHashes = [];
2644
- let forgetResult;
2645
- if (args.forgetPrevious && args.registrationId) {
2646
- const previousPosts = await fetchAlephBootstrapPosts({
2647
- apiHost: args.apiHost ?? DEFAULT_ALEPH_API_HOST3,
2648
- channel: args.channel,
2649
- ref: args.ref,
2650
- postType: args.postType,
2651
- fetch: args.fetch
2652
- });
2653
- forgottenHashes = previousPosts.filter(
2654
- (post) => post.address?.toLowerCase() === args.sender.toLowerCase() && post.content?.registrationId === args.registrationId && (post.itemHash ?? post.hash) != null && (post.itemHash ?? post.hash) !== unsigned.item_hash
2655
- ).map((post) => post.itemHash ?? post.hash ?? "").filter(Boolean);
2656
- if (forgottenHashes.length > 0) {
2657
- forgetResult = await forgetAlephMessages({
2658
- sender: args.sender,
2659
- hashes: forgottenHashes,
2660
- reason: args.forgetPreviousReason ?? `Replace older relay bootstrap records for ${args.registrationId}`,
2661
- signer: args.signer,
2662
- hasher: args.hasher,
2663
- fetch: args.fetch,
2664
- apiHost: args.apiHost ?? DEFAULT_ALEPH_API_HOST3,
2665
- sync: args.sync ?? true
2666
- });
2667
- }
2668
- }
2669
- return {
2670
- status: "published",
2671
- itemHash: unsigned.item_hash,
2672
- message,
2673
- response,
2674
- httpStatus,
2675
- publishedMultiaddrs: content.content?.multiaddrs ?? [],
2676
- publishedBrowserMultiaddrs: content.content?.browserMultiaddrs ?? [],
2677
- forgottenHashes,
2678
- forgetResult
2679
- };
2680
- }
2681
2391
 
2682
2392
  // ../core/src/bootstrap-config.ts
2683
2393
  var VM_BOOTSTRAP_CONFIG_AGGREGATE_KEY = "vm-bootstrap-config";
@@ -2831,24 +2541,6 @@ function extractRelayMetadata(payload) {
2831
2541
  browserBootstrapMultiaddrs
2832
2542
  };
2833
2543
  }
2834
- async function fetchOwnerInstances(address, options) {
2835
- const url = new URL("/api/v0/messages.json", options.apiHost ?? DEFAULT_ALEPH_API_HOST2);
2836
- url.searchParams.set("msgTypes", "INSTANCE");
2837
- url.searchParams.set("addresses", address);
2838
- url.searchParams.set("message_statuses", "processed,pending,rejected,removing");
2839
- url.searchParams.set("pagination", "100");
2840
- url.searchParams.set("page", "1");
2841
- url.searchParams.set("sortOrder", "-1");
2842
- const response = await options.fetch(url.toString(), { cache: "no-cache" });
2843
- if (!response.ok) {
2844
- throw new Error(`Instance list request failed: ${response.status}`);
2845
- }
2846
- const payload = await response.json();
2847
- return (payload.messages ?? []).map((message) => ({
2848
- ...message,
2849
- status: typeof message.status === "string" && message.status.trim() ? message.status : message.confirmed ? "processed" : "pending"
2850
- }));
2851
- }
2852
2544
  async function fetchRelayMetadataForRuntime(args) {
2853
2545
  const setupPort = args.runtime.mappedPorts?.["80"]?.host ?? 80;
2854
2546
  const metadataUrl = args.preferSecureMetadata ? secureBootstrapMetadataUrl(args.runtime.proxyUrl) : null;
@@ -2875,123 +2567,6 @@ async function fetchRelayMetadataForRuntime(args) {
2875
2567
  }).catch(() => null);
2876
2568
  return extractRelayMetadata(payload);
2877
2569
  }
2878
- async function reconcileOwnerRelayBootstrapRegistrations(args) {
2879
- const result = {
2880
- refreshedRegistrations: [],
2881
- forgottenHashes: [],
2882
- skippedInstanceHashes: [],
2883
- errors: []
2884
- };
2885
- const liveRegistrationIds = /* @__PURE__ */ new Set();
2886
- if (args.current?.registrationId) {
2887
- liveRegistrationIds.add(args.current.registrationId);
2888
- result.refreshedRegistrations.push(args.current.registrationId);
2889
- }
2890
- const instances = await fetchOwnerInstances(args.instanceOwnerAddress, {
2891
- apiHost: args.apiHost,
2892
- fetch: args.fetch
2893
- });
2894
- const processedInstances = instances.filter((instance) => {
2895
- const status = String(instance.status ?? "").trim().toLowerCase();
2896
- return status === "processed";
2897
- });
2898
- for (const instance of processedInstances) {
2899
- if (instance.item_hash === args.current?.itemHash) continue;
2900
- const registrationId = createRelayBootstrapRegistrationId(
2901
- args.profile,
2902
- instance.content?.metadata?.name,
2903
- instance.item_hash
2904
- );
2905
- try {
2906
- const runtime = await fetchVmRuntime({
2907
- itemHash: instance.item_hash,
2908
- fetch: args.fetch,
2909
- crns: args.crns,
2910
- crnListUrl: args.crnListUrl
2911
- });
2912
- if (!runtime.hostIpv4 || Object.keys(runtime.mappedPorts ?? {}).length === 0) {
2913
- result.skippedInstanceHashes.push(instance.item_hash);
2914
- continue;
2915
- }
2916
- const relayMetadata = await fetchRelayMetadataForRuntime({
2917
- runtime,
2918
- fetch: args.fetch,
2919
- preferSecureMetadata: args.preferSecureMetadata,
2920
- attempts: 3,
2921
- delayMs: 1e3,
2922
- timeoutMs: 1e4
2923
- });
2924
- if (!relayMetadata) {
2925
- result.skippedInstanceHashes.push(instance.item_hash);
2926
- continue;
2927
- }
2928
- liveRegistrationIds.add(registrationId);
2929
- await publishRelayBootstrapRegistration({
2930
- sender: args.sender,
2931
- signer: args.signer,
2932
- hasher: args.hasher,
2933
- fetch: args.fetch,
2934
- apiHost: args.apiHost,
2935
- channel: args.channel,
2936
- ref: args.ref,
2937
- postType: args.postType,
2938
- peerId: relayMetadata.peerId,
2939
- multiaddrs: relayMetadata.probeMultiaddrs,
2940
- browserMultiaddrs: relayMetadata.browserBootstrapMultiaddrs,
2941
- registrationId,
2942
- ownerAddress: args.ownerAddress,
2943
- publisherAddress: args.publisherAddress,
2944
- ownerSigner: args.ownerSigner,
2945
- publisherSigner: args.publisherSigner,
2946
- forgetPrevious: true,
2947
- profile: args.profile,
2948
- version: args.version,
2949
- instanceItemHash: instance.item_hash,
2950
- sync: true
2951
- });
2952
- result.refreshedRegistrations.push(registrationId);
2953
- } catch (error) {
2954
- result.errors.push({
2955
- phase: "publish",
2956
- itemHash: instance.item_hash,
2957
- registrationId,
2958
- message: error instanceof Error ? error.message : String(error)
2959
- });
2960
- }
2961
- }
2962
- try {
2963
- const bootstrapPosts = await fetchAlephBootstrapPosts({
2964
- apiHost: args.apiHost ?? DEFAULT_ALEPH_API_HOST2,
2965
- channel: args.channel,
2966
- ref: args.ref,
2967
- postType: args.postType,
2968
- fetch: args.fetch
2969
- });
2970
- const currentPosts = selectCurrentRelayBootstrapPosts(bootstrapPosts);
2971
- const staleHashes = currentPosts.filter(
2972
- (post) => post.address?.toLowerCase() === args.sender.toLowerCase() && post.content?.profile === args.profile && post.content?.registrationId && !liveRegistrationIds.has(post.content.registrationId)
2973
- ).map((post) => post.itemHash ?? post.hash ?? "").filter(Boolean);
2974
- if (staleHashes.length > 0) {
2975
- await forgetAlephMessages({
2976
- sender: args.sender,
2977
- hashes: staleHashes,
2978
- reason: `Forget stale ${args.profile} relay bootstrap registrations after owner reconcile`,
2979
- signer: args.signer,
2980
- hasher: args.hasher,
2981
- fetch: args.fetch,
2982
- apiHost: args.apiHost ?? DEFAULT_ALEPH_API_HOST2,
2983
- sync: true
2984
- });
2985
- result.forgottenHashes.push(...staleHashes);
2986
- }
2987
- } catch (error) {
2988
- result.errors.push({
2989
- phase: "forget",
2990
- message: error instanceof Error ? error.message : String(error)
2991
- });
2992
- }
2993
- return result;
2994
- }
2995
2570
 
2996
2571
  // src/shared/events.ts
2997
2572
  function createDeploymentProgressEmitter() {
@@ -3611,7 +3186,7 @@ var SponsorRelayController = class {
3611
3186
  if (!relayMetadata) {
3612
3187
  throw new Error("Relay metadata did not include a peer ID and public multiaddrs.");
3613
3188
  }
3614
- const { peerId, probeMultiaddrs, browserBootstrapMultiaddrs } = relayMetadata;
3189
+ const { peerId } = relayMetadata;
3615
3190
  const registrationId = createRelayBootstrapRegistrationId(
3616
3191
  profile,
3617
3192
  this.state.instanceName.trim(),
@@ -3619,48 +3194,18 @@ var SponsorRelayController = class {
3619
3194
  );
3620
3195
  this.emitProgress({
3621
3196
  stage: "publishing-bootstrap",
3622
- label: "Publishing bootstrap registration",
3197
+ label: "Waiting for guest bootstrap registration",
3623
3198
  progress: 96,
3624
3199
  status: "info",
3625
3200
  itemHash: args.itemHash,
3626
- detail: "Writing the relay bootstrap registration to Aleph."
3627
- });
3628
- const publication = await publishRelayBootstrapRegistration({
3629
- sender: this.state.wallet.address,
3630
- signer: personalSign,
3631
- hasher: sha256Hex,
3632
- fetch: asJsonFetch,
3633
- apiHost: this.client.apiHost,
3634
- peerId,
3635
- multiaddrs: probeMultiaddrs,
3636
- browserMultiaddrs: browserBootstrapMultiaddrs,
3637
- registrationId,
3638
- profile,
3639
- version: this.state.manifest?.version,
3640
- forgetPrevious: true,
3641
- sync: true
3642
- });
3643
- this.trace("deploy:bootstrap-registration", {
3644
- itemHash: args.itemHash,
3645
- peerId,
3646
- metadata: relayMetadata,
3647
- publication
3648
- });
3649
- this.emitProgress({
3650
- stage: "publishing-bootstrap",
3651
- label: "Verifying bootstrap registration",
3652
- progress: 97,
3653
- status: "info",
3654
- itemHash: args.itemHash,
3655
- detail: "Waiting for the relay bootstrap registration to appear on Aleph."
3201
+ detail: "Waiting for the relay VM to publish its own bootstrap registration to Aleph."
3656
3202
  });
3657
3203
  const visibleRegistration = await waitForRelayBootstrapRegistration({
3658
- sender: this.state.wallet.address,
3659
3204
  registrationId,
3660
3205
  peerId,
3661
3206
  fetch: asJsonFetch,
3662
3207
  apiHost: this.client.apiHost,
3663
- attempts: 12,
3208
+ attempts: 24,
3664
3209
  delayMs: 2500
3665
3210
  });
3666
3211
  this.trace("deploy:bootstrap-registration-visible", {
@@ -3674,31 +3219,6 @@ var SponsorRelayController = class {
3674
3219
  "Relay bootstrap registration did not become visible on Aleph."
3675
3220
  );
3676
3221
  }
3677
- const reconcileResult = await reconcileOwnerRelayBootstrapRegistrations({
3678
- instanceOwnerAddress: this.state.wallet.address,
3679
- sender: this.state.wallet.address,
3680
- signer: personalSign,
3681
- hasher: sha256Hex,
3682
- fetch: asJsonFetch,
3683
- profile,
3684
- apiHost: this.client.apiHost,
3685
- crns: this.state.crns,
3686
- crnListUrl: this.props.crnListUrl,
3687
- preferSecureMetadata: profile === "uc-go-peer",
3688
- current: {
3689
- itemHash: args.itemHash,
3690
- registrationId,
3691
- peerId,
3692
- probeMultiaddrs,
3693
- browserBootstrapMultiaddrs
3694
- }
3695
- });
3696
- if (reconcileResult.errors.length > 0) {
3697
- this.trace("deploy:owner-bootstrap-reconcile-errors", {
3698
- itemHash: args.itemHash,
3699
- errors: reconcileResult.errors
3700
- });
3701
- }
3702
3222
  if (profile === "uc-go-peer" && args.deploymentToken) {
3703
3223
  await deleteVmBootstrapConfig({
3704
3224
  sender: this.state.wallet.address,
@@ -4536,29 +4056,6 @@ var SponsorRelayController = class {
4536
4056
  this.emitProgress(event);
4537
4057
  }
4538
4058
  });
4539
- const profile = relayProfileForManifest(this.state.manifest);
4540
- if (profile) {
4541
- await reconcileOwnerRelayBootstrapRegistrations({
4542
- instanceOwnerAddress: this.state.wallet.address,
4543
- sender: this.state.wallet.address,
4544
- signer: personalSign,
4545
- hasher: sha256Hex,
4546
- fetch: asJsonFetch,
4547
- profile,
4548
- apiHost: this.client.apiHost,
4549
- crns: this.state.crns,
4550
- crnListUrl: this.props.crnListUrl,
4551
- preferSecureMetadata: profile === "uc-go-peer"
4552
- }).catch(
4553
- (error) => {
4554
- this.trace("delete:owner-bootstrap-reconcile-error", {
4555
- instanceHash,
4556
- profile,
4557
- error: error instanceof Error ? error.message : String(error)
4558
- });
4559
- }
4560
- );
4561
- }
4562
4059
  this.patch({
4563
4060
  busy: { deletingInstanceHash: null },
4564
4061
  statusText: `Deletion submitted for ${instanceHash}`