@le-space/ui 0.3.17 → 0.3.18

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.17",
3
+ "version": "0.3.18",
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.17",
40
- "@le-space/core": "0.3.17",
39
+ "@le-space/browser": "0.3.18",
40
+ "@le-space/core": "0.3.18",
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.17";
42
+ var UI_PACKAGE_VERSION = "0.3.18";
43
43
 
44
44
  // src/shared/format.ts
45
45
  function shortHash(value, head = 8, tail = 6) {
@@ -1219,14 +1219,14 @@ async function inspectDeploymentResult2(itemHash, options) {
1219
1219
  async function waitForDeploymentResult2(itemHash, options) {
1220
1220
  const attempts = Math.max(1, Number(options.attempts ?? 15));
1221
1221
  const delayMs = Math.max(0, Number(options.delayMs ?? 2e3));
1222
- const sleep = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
1222
+ const sleep2 = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
1223
1223
  let lastResult = await inspectDeploymentResult2(itemHash, options);
1224
1224
  options.onAttempt?.(lastResult, 1, attempts);
1225
1225
  for (let attempt = 1; attempt < attempts; attempt += 1) {
1226
1226
  if (lastResult.status === "processed" || lastResult.status === "rejected") {
1227
1227
  return lastResult;
1228
1228
  }
1229
- await sleep(delayMs);
1229
+ await sleep2(delayMs);
1230
1230
  lastResult = await inspectDeploymentResult2(itemHash, options);
1231
1231
  options.onAttempt?.(lastResult, attempt + 1, attempts);
1232
1232
  }
@@ -1884,14 +1884,14 @@ async function fetchVmRuntime(args) {
1884
1884
  async function waitForVmRuntime(args) {
1885
1885
  const attempts = Math.max(1, Number(args.attempts ?? 20));
1886
1886
  const delayMs = Math.max(0, Number(args.delayMs ?? 4e3));
1887
- const sleep = args.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
1887
+ const sleep2 = args.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
1888
1888
  let lastRuntime = await fetchVmRuntime(args);
1889
1889
  args.onAttempt?.(lastRuntime, 1, attempts);
1890
1890
  for (let attempt = 0; attempt < attempts - 1; attempt += 1) {
1891
1891
  if (lastRuntime.hostIpv4 && Object.keys(lastRuntime.mappedPorts ?? {}).length > 0) {
1892
1892
  return lastRuntime;
1893
1893
  }
1894
- await sleep(delayMs);
1894
+ await sleep2(delayMs);
1895
1895
  lastRuntime = await fetchVmRuntime(args);
1896
1896
  args.onAttempt?.(lastRuntime, attempt + 2, attempts);
1897
1897
  }
@@ -1970,7 +1970,7 @@ function isRetryableAllocationNotifyReason(reason) {
1970
1970
  async function notifyCrnAllocationWithRetry(args) {
1971
1971
  const attempts = Math.max(1, Number(args.attempts ?? 6));
1972
1972
  const delayMs = Math.max(0, Number(args.delayMs ?? 2e3));
1973
- const sleep = args.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
1973
+ const sleep2 = args.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
1974
1974
  let lastResult = null;
1975
1975
  for (let attempt = 0; attempt < attempts; attempt += 1) {
1976
1976
  args.onProgress?.({
@@ -1996,7 +1996,7 @@ async function notifyCrnAllocationWithRetry(args) {
1996
1996
  return result;
1997
1997
  }
1998
1998
  if (attempt < attempts - 1) {
1999
- await sleep(delayMs);
1999
+ await sleep2(delayMs);
2000
2000
  }
2001
2001
  }
2002
2002
  return lastResult ?? {
@@ -2007,7 +2007,7 @@ async function notifyCrnAllocationWithRetry(args) {
2007
2007
  async function waitForSetupEndpoint(args) {
2008
2008
  const attempts = Math.max(1, Number(args.attempts ?? 15));
2009
2009
  const delayMs = Math.max(0, Number(args.delayMs ?? 4e3));
2010
- const sleep = args.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
2010
+ const sleep2 = args.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
2011
2011
  const url = `http://${args.hostIpv4}:${args.setupPort}/health`;
2012
2012
  let result = await defaultHttpProbe(
2013
2013
  args.fetch,
@@ -2017,7 +2017,7 @@ async function waitForSetupEndpoint(args) {
2017
2017
  args.onAttempt?.(result, 1, attempts);
2018
2018
  for (let attempt = 1; attempt < attempts; attempt += 1) {
2019
2019
  if (result.ok) return result;
2020
- await sleep(delayMs);
2020
+ await sleep2(delayMs);
2021
2021
  result = await defaultHttpProbe(
2022
2022
  args.fetch,
2023
2023
  url,
@@ -2076,7 +2076,7 @@ async function configureOrbitdbRelaySetup2(args) {
2076
2076
  async function fetchUcGoPeerMetadata(args) {
2077
2077
  const attempts = Math.max(1, Number(args.attempts ?? 60));
2078
2078
  const delayMs = Math.max(0, Number(args.delayMs ?? 3e3));
2079
- const sleep = args.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
2079
+ const sleep2 = args.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
2080
2080
  let lastPayload = null;
2081
2081
  let lastError = null;
2082
2082
  for (let attempt = 0; attempt < attempts; attempt += 1) {
@@ -2136,7 +2136,7 @@ async function fetchUcGoPeerMetadata(args) {
2136
2136
  clearTimeout(timeout);
2137
2137
  }
2138
2138
  if (attempt < attempts - 1) {
2139
- await sleep(delayMs);
2139
+ await sleep2(delayMs);
2140
2140
  }
2141
2141
  }
2142
2142
  throw new Error(
@@ -2531,6 +2531,51 @@ function selectCurrentRelayBootstrapPosts(posts, options = {}) {
2531
2531
  }
2532
2532
 
2533
2533
  // ../core/src/bootstrap-registration.ts
2534
+ function sleep(ms) {
2535
+ return new Promise((resolve) => setTimeout(resolve, ms));
2536
+ }
2537
+ async function waitForRelayBootstrapRegistration(args) {
2538
+ const attempts = Math.max(1, Number(args.attempts ?? 10));
2539
+ const delayMs = Math.max(0, Number(args.delayMs ?? 2e3));
2540
+ const expectedSender = args.sender.trim().toLowerCase();
2541
+ const expectedRegistrationId = args.registrationId?.trim() || null;
2542
+ const expectedPeerId = args.peerId?.trim() || null;
2543
+ for (let attempt = 0; attempt < attempts; attempt += 1) {
2544
+ const posts = await fetchAlephBootstrapPosts({
2545
+ apiHost: args.apiHost ?? DEFAULT_ALEPH_API_HOST3,
2546
+ channel: args.channel,
2547
+ ref: args.ref,
2548
+ postType: args.postType,
2549
+ fetch: args.fetch
2550
+ });
2551
+ const currentPosts = selectCurrentRelayBootstrapPosts(posts);
2552
+ const match = currentPosts.find((post) => {
2553
+ const senderMatches = post.address?.toLowerCase() === expectedSender;
2554
+ if (!senderMatches) return false;
2555
+ if (expectedRegistrationId && post.content?.registrationId === expectedRegistrationId) {
2556
+ return true;
2557
+ }
2558
+ if (expectedPeerId && post.content?.peerId === expectedPeerId) {
2559
+ return true;
2560
+ }
2561
+ return false;
2562
+ });
2563
+ if (match?.content) {
2564
+ return {
2565
+ itemHash: match.itemHash ?? null,
2566
+ hash: match.hash ?? null,
2567
+ registrationId: match.content.registrationId,
2568
+ peerId: match.content.peerId,
2569
+ multiaddrs: Array.isArray(match.content.multiaddrs) ? match.content.multiaddrs : [],
2570
+ browserMultiaddrs: Array.isArray(match.content.browserMultiaddrs) ? match.content.browserMultiaddrs : []
2571
+ };
2572
+ }
2573
+ if (attempt < attempts - 1) {
2574
+ await sleep(delayMs);
2575
+ }
2576
+ }
2577
+ return null;
2578
+ }
2534
2579
  async function publishRelayBootstrapRegistration(args) {
2535
2580
  const publisherAddress = args.publisherAddress ?? args.sender;
2536
2581
  const ownerAddress = args.ownerAddress;
@@ -3602,6 +3647,34 @@ var SponsorRelayController = class {
3602
3647
  metadata: relayMetadata,
3603
3648
  publication
3604
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."
3657
+ });
3658
+ const visibleRegistration = await waitForRelayBootstrapRegistration({
3659
+ sender: this.state.wallet.address,
3660
+ registrationId,
3661
+ peerId,
3662
+ fetch: asJsonFetch,
3663
+ apiHost: this.client.apiHost,
3664
+ attempts: 12,
3665
+ delayMs: 2500
3666
+ });
3667
+ this.trace("deploy:bootstrap-registration-visible", {
3668
+ itemHash: args.itemHash,
3669
+ registrationId,
3670
+ peerId,
3671
+ visibleRegistration
3672
+ });
3673
+ if (!visibleRegistration) {
3674
+ throw new Error(
3675
+ "Relay bootstrap registration did not become visible on Aleph."
3676
+ );
3677
+ }
3605
3678
  const reconcileResult = await reconcileOwnerRelayBootstrapRegistrations({
3606
3679
  instanceOwnerAddress: this.state.wallet.address,
3607
3680
  sender: this.state.wallet.address,
@@ -4116,12 +4189,14 @@ var SponsorRelayController = class {
4116
4189
  for (const [candidateIndex, candidateCrn] of orderedCrns.entries()) {
4117
4190
  let attemptItemHash = null;
4118
4191
  let attemptDeploymentToken = null;
4192
+ const crnAttemptLabel = `CRN ${candidateIndex + 1}/${orderedCrns.length}`;
4193
+ const crnDisplayName = candidateCrn.name ?? candidateCrn.hash;
4119
4194
  this.emitProgress({
4120
4195
  stage: "selecting-crn",
4121
- label: "Selecting CRN",
4196
+ label: `Selecting ${crnAttemptLabel}`,
4122
4197
  progress: 18,
4123
4198
  status: "info",
4124
- detail: `Trying ${candidateCrn.name ?? candidateCrn.hash} (${candidateIndex + 1}/${orderedCrns.length})`
4199
+ detail: `Trying ${crnDisplayName}`
4125
4200
  });
4126
4201
  try {
4127
4202
  const profile = relayProfileForManifest(this.state.manifest);
@@ -4331,7 +4406,7 @@ var SponsorRelayController = class {
4331
4406
  return;
4332
4407
  } catch (error) {
4333
4408
  lastError = error instanceof Error ? error : new Error(String(error));
4334
- const attemptLabel = candidateCrn.name ?? candidateCrn.hash;
4409
+ const attemptLabel = crnDisplayName;
4335
4410
  attemptErrors.push(`${attemptLabel}: ${lastError.message}`);
4336
4411
  this.trace("deploy:crn-attempt-error", {
4337
4412
  crnHash: candidateCrn.hash,
@@ -4400,7 +4475,7 @@ var SponsorRelayController = class {
4400
4475
  if (candidateIndex < orderedCrns.length - 1) {
4401
4476
  this.emitProgress({
4402
4477
  stage: "selecting-crn",
4403
- label: "Retrying another CRN",
4478
+ label: `Retrying after ${crnAttemptLabel}`,
4404
4479
  progress: 20,
4405
4480
  status: "warning",
4406
4481
  itemHash: attemptItemHash,
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.17";
307
+ declare const UI_PACKAGE_VERSION = "0.3.18";
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.17";
41
+ var UI_PACKAGE_VERSION = "0.3.18";
42
42
 
43
43
  // src/shared/format.ts
44
44
  function shortHash(value, head = 8, tail = 6) {
@@ -1218,14 +1218,14 @@ async function inspectDeploymentResult2(itemHash, options) {
1218
1218
  async function waitForDeploymentResult2(itemHash, options) {
1219
1219
  const attempts = Math.max(1, Number(options.attempts ?? 15));
1220
1220
  const delayMs = Math.max(0, Number(options.delayMs ?? 2e3));
1221
- const sleep = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
1221
+ const sleep2 = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
1222
1222
  let lastResult = await inspectDeploymentResult2(itemHash, options);
1223
1223
  options.onAttempt?.(lastResult, 1, attempts);
1224
1224
  for (let attempt = 1; attempt < attempts; attempt += 1) {
1225
1225
  if (lastResult.status === "processed" || lastResult.status === "rejected") {
1226
1226
  return lastResult;
1227
1227
  }
1228
- await sleep(delayMs);
1228
+ await sleep2(delayMs);
1229
1229
  lastResult = await inspectDeploymentResult2(itemHash, options);
1230
1230
  options.onAttempt?.(lastResult, attempt + 1, attempts);
1231
1231
  }
@@ -1883,14 +1883,14 @@ async function fetchVmRuntime(args) {
1883
1883
  async function waitForVmRuntime(args) {
1884
1884
  const attempts = Math.max(1, Number(args.attempts ?? 20));
1885
1885
  const delayMs = Math.max(0, Number(args.delayMs ?? 4e3));
1886
- const sleep = args.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
1886
+ const sleep2 = args.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
1887
1887
  let lastRuntime = await fetchVmRuntime(args);
1888
1888
  args.onAttempt?.(lastRuntime, 1, attempts);
1889
1889
  for (let attempt = 0; attempt < attempts - 1; attempt += 1) {
1890
1890
  if (lastRuntime.hostIpv4 && Object.keys(lastRuntime.mappedPorts ?? {}).length > 0) {
1891
1891
  return lastRuntime;
1892
1892
  }
1893
- await sleep(delayMs);
1893
+ await sleep2(delayMs);
1894
1894
  lastRuntime = await fetchVmRuntime(args);
1895
1895
  args.onAttempt?.(lastRuntime, attempt + 2, attempts);
1896
1896
  }
@@ -1969,7 +1969,7 @@ function isRetryableAllocationNotifyReason(reason) {
1969
1969
  async function notifyCrnAllocationWithRetry(args) {
1970
1970
  const attempts = Math.max(1, Number(args.attempts ?? 6));
1971
1971
  const delayMs = Math.max(0, Number(args.delayMs ?? 2e3));
1972
- const sleep = args.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
1972
+ const sleep2 = args.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
1973
1973
  let lastResult = null;
1974
1974
  for (let attempt = 0; attempt < attempts; attempt += 1) {
1975
1975
  args.onProgress?.({
@@ -1995,7 +1995,7 @@ async function notifyCrnAllocationWithRetry(args) {
1995
1995
  return result;
1996
1996
  }
1997
1997
  if (attempt < attempts - 1) {
1998
- await sleep(delayMs);
1998
+ await sleep2(delayMs);
1999
1999
  }
2000
2000
  }
2001
2001
  return lastResult ?? {
@@ -2006,7 +2006,7 @@ async function notifyCrnAllocationWithRetry(args) {
2006
2006
  async function waitForSetupEndpoint(args) {
2007
2007
  const attempts = Math.max(1, Number(args.attempts ?? 15));
2008
2008
  const delayMs = Math.max(0, Number(args.delayMs ?? 4e3));
2009
- const sleep = args.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
2009
+ const sleep2 = args.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
2010
2010
  const url = `http://${args.hostIpv4}:${args.setupPort}/health`;
2011
2011
  let result = await defaultHttpProbe(
2012
2012
  args.fetch,
@@ -2016,7 +2016,7 @@ async function waitForSetupEndpoint(args) {
2016
2016
  args.onAttempt?.(result, 1, attempts);
2017
2017
  for (let attempt = 1; attempt < attempts; attempt += 1) {
2018
2018
  if (result.ok) return result;
2019
- await sleep(delayMs);
2019
+ await sleep2(delayMs);
2020
2020
  result = await defaultHttpProbe(
2021
2021
  args.fetch,
2022
2022
  url,
@@ -2075,7 +2075,7 @@ async function configureOrbitdbRelaySetup2(args) {
2075
2075
  async function fetchUcGoPeerMetadata(args) {
2076
2076
  const attempts = Math.max(1, Number(args.attempts ?? 60));
2077
2077
  const delayMs = Math.max(0, Number(args.delayMs ?? 3e3));
2078
- const sleep = args.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
2078
+ const sleep2 = args.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
2079
2079
  let lastPayload = null;
2080
2080
  let lastError = null;
2081
2081
  for (let attempt = 0; attempt < attempts; attempt += 1) {
@@ -2135,7 +2135,7 @@ async function fetchUcGoPeerMetadata(args) {
2135
2135
  clearTimeout(timeout);
2136
2136
  }
2137
2137
  if (attempt < attempts - 1) {
2138
- await sleep(delayMs);
2138
+ await sleep2(delayMs);
2139
2139
  }
2140
2140
  }
2141
2141
  throw new Error(
@@ -2530,6 +2530,51 @@ function selectCurrentRelayBootstrapPosts(posts, options = {}) {
2530
2530
  }
2531
2531
 
2532
2532
  // ../core/src/bootstrap-registration.ts
2533
+ function sleep(ms) {
2534
+ return new Promise((resolve) => setTimeout(resolve, ms));
2535
+ }
2536
+ async function waitForRelayBootstrapRegistration(args) {
2537
+ const attempts = Math.max(1, Number(args.attempts ?? 10));
2538
+ const delayMs = Math.max(0, Number(args.delayMs ?? 2e3));
2539
+ const expectedSender = args.sender.trim().toLowerCase();
2540
+ const expectedRegistrationId = args.registrationId?.trim() || null;
2541
+ const expectedPeerId = args.peerId?.trim() || null;
2542
+ for (let attempt = 0; attempt < attempts; attempt += 1) {
2543
+ const posts = await fetchAlephBootstrapPosts({
2544
+ apiHost: args.apiHost ?? DEFAULT_ALEPH_API_HOST3,
2545
+ channel: args.channel,
2546
+ ref: args.ref,
2547
+ postType: args.postType,
2548
+ fetch: args.fetch
2549
+ });
2550
+ const currentPosts = selectCurrentRelayBootstrapPosts(posts);
2551
+ const match = currentPosts.find((post) => {
2552
+ const senderMatches = post.address?.toLowerCase() === expectedSender;
2553
+ if (!senderMatches) return false;
2554
+ if (expectedRegistrationId && post.content?.registrationId === expectedRegistrationId) {
2555
+ return true;
2556
+ }
2557
+ if (expectedPeerId && post.content?.peerId === expectedPeerId) {
2558
+ return true;
2559
+ }
2560
+ return false;
2561
+ });
2562
+ if (match?.content) {
2563
+ return {
2564
+ itemHash: match.itemHash ?? null,
2565
+ hash: match.hash ?? null,
2566
+ registrationId: match.content.registrationId,
2567
+ peerId: match.content.peerId,
2568
+ multiaddrs: Array.isArray(match.content.multiaddrs) ? match.content.multiaddrs : [],
2569
+ browserMultiaddrs: Array.isArray(match.content.browserMultiaddrs) ? match.content.browserMultiaddrs : []
2570
+ };
2571
+ }
2572
+ if (attempt < attempts - 1) {
2573
+ await sleep(delayMs);
2574
+ }
2575
+ }
2576
+ return null;
2577
+ }
2533
2578
  async function publishRelayBootstrapRegistration(args) {
2534
2579
  const publisherAddress = args.publisherAddress ?? args.sender;
2535
2580
  const ownerAddress = args.ownerAddress;
@@ -3601,6 +3646,34 @@ var SponsorRelayController = class {
3601
3646
  metadata: relayMetadata,
3602
3647
  publication
3603
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."
3656
+ });
3657
+ const visibleRegistration = await waitForRelayBootstrapRegistration({
3658
+ sender: this.state.wallet.address,
3659
+ registrationId,
3660
+ peerId,
3661
+ fetch: asJsonFetch,
3662
+ apiHost: this.client.apiHost,
3663
+ attempts: 12,
3664
+ delayMs: 2500
3665
+ });
3666
+ this.trace("deploy:bootstrap-registration-visible", {
3667
+ itemHash: args.itemHash,
3668
+ registrationId,
3669
+ peerId,
3670
+ visibleRegistration
3671
+ });
3672
+ if (!visibleRegistration) {
3673
+ throw new Error(
3674
+ "Relay bootstrap registration did not become visible on Aleph."
3675
+ );
3676
+ }
3604
3677
  const reconcileResult = await reconcileOwnerRelayBootstrapRegistrations({
3605
3678
  instanceOwnerAddress: this.state.wallet.address,
3606
3679
  sender: this.state.wallet.address,
@@ -4115,12 +4188,14 @@ var SponsorRelayController = class {
4115
4188
  for (const [candidateIndex, candidateCrn] of orderedCrns.entries()) {
4116
4189
  let attemptItemHash = null;
4117
4190
  let attemptDeploymentToken = null;
4191
+ const crnAttemptLabel = `CRN ${candidateIndex + 1}/${orderedCrns.length}`;
4192
+ const crnDisplayName = candidateCrn.name ?? candidateCrn.hash;
4118
4193
  this.emitProgress({
4119
4194
  stage: "selecting-crn",
4120
- label: "Selecting CRN",
4195
+ label: `Selecting ${crnAttemptLabel}`,
4121
4196
  progress: 18,
4122
4197
  status: "info",
4123
- detail: `Trying ${candidateCrn.name ?? candidateCrn.hash} (${candidateIndex + 1}/${orderedCrns.length})`
4198
+ detail: `Trying ${crnDisplayName}`
4124
4199
  });
4125
4200
  try {
4126
4201
  const profile = relayProfileForManifest(this.state.manifest);
@@ -4330,7 +4405,7 @@ var SponsorRelayController = class {
4330
4405
  return;
4331
4406
  } catch (error) {
4332
4407
  lastError = error instanceof Error ? error : new Error(String(error));
4333
- const attemptLabel = candidateCrn.name ?? candidateCrn.hash;
4408
+ const attemptLabel = crnDisplayName;
4334
4409
  attemptErrors.push(`${attemptLabel}: ${lastError.message}`);
4335
4410
  this.trace("deploy:crn-attempt-error", {
4336
4411
  crnHash: candidateCrn.hash,
@@ -4399,7 +4474,7 @@ var SponsorRelayController = class {
4399
4474
  if (candidateIndex < orderedCrns.length - 1) {
4400
4475
  this.emitProgress({
4401
4476
  stage: "selecting-crn",
4402
- label: "Retrying another CRN",
4477
+ label: `Retrying after ${crnAttemptLabel}`,
4403
4478
  progress: 20,
4404
4479
  status: "warning",
4405
4480
  itemHash: attemptItemHash,