@le-space/ui 0.1.55 → 0.1.56

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.1.55",
3
+ "version": "0.1.56",
4
4
  "description": "Floating Aleph sponsor relay UI components for Svelte and React.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/react/index.d.ts CHANGED
@@ -174,12 +174,12 @@ interface RootfsResolution {
174
174
  gatewayError?: string | null;
175
175
  }
176
176
 
177
- type DeploymentProgressStage = 'idle' | 'validating' | 'loading-manifest' | 'verifying-rootfs' | 'loading-pricing' | 'loading-balance' | 'selecting-crn' | 'building-message' | 'signing-message' | 'broadcasting' | 'waiting-for-aleph' | 'deployment-confirmed' | 'deployment-rejected' | 'building-delete-message' | 'signing-delete-message' | 'broadcasting-delete' | 'delete-completed' | 'refreshing-instances' | 'completed' | 'error';
177
+ type DeploymentProgressStage = "idle" | "validating" | "loading-manifest" | "verifying-rootfs" | "loading-pricing" | "loading-balance" | "selecting-crn" | "building-message" | "signing-message" | "broadcasting" | "notifying-crn" | "waiting-for-aleph" | "deployment-confirmed" | "deployment-rejected" | "building-delete-message" | "signing-delete-message" | "broadcasting-delete" | "delete-completed" | "refreshing-instances" | "completed" | "error";
178
178
  interface DeploymentProgressEvent {
179
179
  stage: DeploymentProgressStage;
180
180
  label: string;
181
181
  progress: number;
182
- status: 'info' | 'success' | 'warning' | 'error';
182
+ status: "info" | "success" | "warning" | "error";
183
183
  itemHash?: string | null;
184
184
  detail?: string | null;
185
185
  error?: string | null;
package/react/index.js CHANGED
@@ -1228,6 +1228,88 @@ async function deployInstance(args) {
1228
1228
  };
1229
1229
  }
1230
1230
 
1231
+ // ../core/src/guest.ts
1232
+ async function notifyCrnAllocation2(args) {
1233
+ const normalizedCrnUrl = typeof args.crnUrl === "string" ? args.crnUrl.trim().replace(/\/+$/, "") : "";
1234
+ if (!normalizedCrnUrl) {
1235
+ return {
1236
+ status: "skipped",
1237
+ reason: "No CRN URL available for allocation notification."
1238
+ };
1239
+ }
1240
+ try {
1241
+ const response = await args.fetch(
1242
+ `${normalizedCrnUrl}/control/allocation/notify`,
1243
+ {
1244
+ method: "POST",
1245
+ headers: {
1246
+ "content-type": "application/json"
1247
+ },
1248
+ body: JSON.stringify({ instance: args.itemHash })
1249
+ }
1250
+ );
1251
+ const payload = await response.json().catch(() => null);
1252
+ const responseText = payload == null ? "" : typeof payload === "string" ? payload : JSON.stringify(payload);
1253
+ if (!response.ok) {
1254
+ return {
1255
+ status: "unconfirmed",
1256
+ reason: `CRN allocation notify returned ${response.status}${responseText ? ` ${responseText}` : ""}.`,
1257
+ payload
1258
+ };
1259
+ }
1260
+ return {
1261
+ status: "confirmed",
1262
+ payload
1263
+ };
1264
+ } catch (error) {
1265
+ return {
1266
+ status: "unconfirmed",
1267
+ reason: error instanceof Error ? error.message : String(error)
1268
+ };
1269
+ }
1270
+ }
1271
+ function isRetryableAllocationNotifyReason(reason) {
1272
+ const normalized = String(reason ?? "").toLowerCase();
1273
+ return normalized.includes("503") && (normalized.includes("node hash not yet discovered") || normalized.includes("cannot accept targeted allocations"));
1274
+ }
1275
+ async function notifyCrnAllocationWithRetry(args) {
1276
+ const attempts = Math.max(1, Number(args.attempts ?? 6));
1277
+ const delayMs = Math.max(0, Number(args.delayMs ?? 2e3));
1278
+ const sleep = args.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
1279
+ let lastResult = null;
1280
+ for (let attempt = 0; attempt < attempts; attempt += 1) {
1281
+ args.onProgress?.({
1282
+ stage: "notifying-crn",
1283
+ label: "Notifying selected CRN",
1284
+ progress: 84,
1285
+ status: "info",
1286
+ itemHash: args.itemHash,
1287
+ detail: `${attempt + 1}/${attempts} ${String(args.crnUrl ?? "").trim() || "selected CRN"}`,
1288
+ error: null,
1289
+ timestamp: Date.now()
1290
+ });
1291
+ const result = await notifyCrnAllocation2({
1292
+ crnUrl: args.crnUrl,
1293
+ itemHash: args.itemHash,
1294
+ fetch: args.fetch
1295
+ });
1296
+ if (result.status === "confirmed" || result.status === "skipped") {
1297
+ return result;
1298
+ }
1299
+ lastResult = result;
1300
+ if (!isRetryableAllocationNotifyReason(result.reason)) {
1301
+ return result;
1302
+ }
1303
+ if (attempt < attempts - 1) {
1304
+ await sleep(delayMs);
1305
+ }
1306
+ }
1307
+ return lastResult ?? {
1308
+ status: "unconfirmed",
1309
+ reason: "CRN allocation notify was not confirmed."
1310
+ };
1311
+ }
1312
+
1231
1313
  // src/shared/events.ts
1232
1314
  function createDeploymentProgressEmitter() {
1233
1315
  const listeners = /* @__PURE__ */ new Set();
@@ -1301,14 +1383,19 @@ function defaultState(props = {}) {
1301
1383
  };
1302
1384
  }
1303
1385
  async function sha256Hex(payload) {
1304
- const digest = await globalThis.crypto.subtle.digest("SHA-256", new TextEncoder().encode(payload));
1386
+ const digest = await globalThis.crypto.subtle.digest(
1387
+ "SHA-256",
1388
+ new TextEncoder().encode(payload)
1389
+ );
1305
1390
  return Array.from(new Uint8Array(digest)).map((byte) => byte.toString(16).padStart(2, "0")).join("");
1306
1391
  }
1307
1392
  function mappedPorts(execution) {
1308
- return Object.entries(execution?.networking?.mapped_ports ?? {}).map(([port, mapping]) => ({
1309
- label: `${port}/${mapping.udp ? "udp" : "tcp"}`,
1310
- hostPort: mapping.host ?? null
1311
- }));
1393
+ return Object.entries(execution?.networking?.mapped_ports ?? {}).map(
1394
+ ([port, mapping]) => ({
1395
+ label: `${port}/${mapping.udp ? "udp" : "tcp"}`,
1396
+ hostPort: mapping.host ?? null
1397
+ })
1398
+ );
1312
1399
  }
1313
1400
  function rootfsHealth(args) {
1314
1401
  if (!args.manifestState.valid || !args.manifestState.manifest) {
@@ -1366,7 +1453,9 @@ async function resolveManifest(args) {
1366
1453
  }
1367
1454
  async function inspectInstanceRuntime(args) {
1368
1455
  const details = {
1369
- messageStatus: String(args.instance.status ?? (args.instance.confirmed ? "processed" : "unknown")).toLowerCase(),
1456
+ messageStatus: String(
1457
+ args.instance.status ?? (args.instance.confirmed ? "processed" : "unknown")
1458
+ ).toLowerCase(),
1370
1459
  allocationSource: null,
1371
1460
  crnUrl: null,
1372
1461
  hostIpv4: null,
@@ -1397,11 +1486,15 @@ async function inspectInstanceRuntime(args) {
1397
1486
  details.allocationSource = allocation?.source ?? null;
1398
1487
  details.crnUrl = allocation?.crnUrl ?? null;
1399
1488
  details.ipv6 = allocation?.vmIpv6 ?? null;
1400
- details.webUrl = await args.client.fetch2n6WebAccessUrl(args.instance.item_hash);
1489
+ details.webUrl = await args.client.fetch2n6WebAccessUrl(
1490
+ args.instance.item_hash
1491
+ );
1401
1492
  if (!allocation?.crnUrl) {
1402
1493
  return details;
1403
1494
  }
1404
- const executionLookup = await args.client.fetchCrnExecutionMap(allocation.crnUrl);
1495
+ const executionLookup = await args.client.fetchCrnExecutionMap(
1496
+ allocation.crnUrl
1497
+ );
1405
1498
  const executionPayload = executionLookup.payload?.[args.instance.item_hash];
1406
1499
  if (!executionPayload) {
1407
1500
  return details;
@@ -1429,7 +1522,10 @@ function compatibleCrnsForTier(crns, state) {
1429
1522
  if (!state.pricingSummary.pricing || !state.pricingSummary.tier) {
1430
1523
  return [];
1431
1524
  }
1432
- const spec = tierSpec(state.pricingSummary.pricing, state.pricingSummary.tier);
1525
+ const spec = tierSpec(
1526
+ state.pricingSummary.pricing,
1527
+ state.pricingSummary.tier
1528
+ );
1433
1529
  return filterDeployableCrns(crns, { spec });
1434
1530
  }
1435
1531
  async function pingPeer(libp2p) {
@@ -1719,8 +1815,14 @@ var SponsorRelayController = class {
1719
1815
  status: "info",
1720
1816
  detail: manifest.rootfsItemHash
1721
1817
  });
1722
- rootfsVerified = await verifyRootfsExists(manifest.rootfsItemHash, this.client.apiHost);
1723
- rootfsResolution = await resolveRootfsReference(manifest.rootfsItemHash, this.client.apiHost);
1818
+ rootfsVerified = await verifyRootfsExists(
1819
+ manifest.rootfsItemHash,
1820
+ this.client.apiHost
1821
+ );
1822
+ rootfsResolution = await resolveRootfsReference(
1823
+ manifest.rootfsItemHash,
1824
+ this.client.apiHost
1825
+ );
1724
1826
  }
1725
1827
  this.patch({
1726
1828
  manifestState,
@@ -1775,7 +1877,9 @@ var SponsorRelayController = class {
1775
1877
  return;
1776
1878
  }
1777
1879
  if (!this.state.manifest || !this.state.rootfsVerified || !this.state.pricingSummary.pricing || !this.state.pricingSummary.tier) {
1778
- this.patch({ errorText: "Manifest, rootfs, and pricing must be ready before deploying." });
1880
+ this.patch({
1881
+ errorText: "Manifest, rootfs, and pricing must be ready before deploying."
1882
+ });
1779
1883
  return;
1780
1884
  }
1781
1885
  this.patch({
@@ -1791,7 +1895,10 @@ var SponsorRelayController = class {
1791
1895
  status: "info",
1792
1896
  detail: "Checking wallet, manifest, rootfs, pricing, and SSH key."
1793
1897
  });
1794
- const spec = tierSpec(this.state.pricingSummary.pricing, this.state.pricingSummary.tier);
1898
+ const spec = tierSpec(
1899
+ this.state.pricingSummary.pricing,
1900
+ this.state.pricingSummary.tier
1901
+ );
1795
1902
  this.emitProgress({
1796
1903
  stage: "selecting-crn",
1797
1904
  label: "Selecting CRN",
@@ -1804,7 +1911,10 @@ var SponsorRelayController = class {
1804
1911
  name: this.state.instanceName.trim(),
1805
1912
  sshPublicKey: this.state.sshPublicKey.trim(),
1806
1913
  rootfsItemHash: this.state.manifest.rootfsItemHash,
1807
- rootfsSizeMiB: Math.max(this.state.manifest.rootfsSizeMiB, spec.diskMiB),
1914
+ rootfsSizeMiB: Math.max(
1915
+ this.state.manifest.rootfsSizeMiB,
1916
+ spec.diskMiB
1917
+ ),
1808
1918
  vcpus: spec.vcpus,
1809
1919
  memoryMiB: spec.memoryMiB,
1810
1920
  rootfsVersion: this.state.manifest.version,
@@ -1827,6 +1937,16 @@ var SponsorRelayController = class {
1827
1937
  statusText: `Deployment submitted: ${result.itemHash}`,
1828
1938
  lastDeploymentHash: result.itemHash
1829
1939
  });
1940
+ if (result.status === "processed" && this.state.selectedCrn?.address) {
1941
+ await notifyCrnAllocationWithRetry({
1942
+ crnUrl: this.state.selectedCrn.address,
1943
+ itemHash: result.itemHash,
1944
+ fetch: (url, init) => fetch(url, init),
1945
+ onProgress: (event) => {
1946
+ this.emitProgress(event);
1947
+ }
1948
+ });
1949
+ }
1830
1950
  this.emitProgress({
1831
1951
  stage: "refreshing-instances",
1832
1952
  label: "Refreshing instances",
package/shared/index.d.ts CHANGED
@@ -172,12 +172,12 @@ interface RootfsResolution {
172
172
  gatewayError?: string | null;
173
173
  }
174
174
 
175
- type DeploymentProgressStage = 'idle' | 'validating' | 'loading-manifest' | 'verifying-rootfs' | 'loading-pricing' | 'loading-balance' | 'selecting-crn' | 'building-message' | 'signing-message' | 'broadcasting' | 'waiting-for-aleph' | 'deployment-confirmed' | 'deployment-rejected' | 'building-delete-message' | 'signing-delete-message' | 'broadcasting-delete' | 'delete-completed' | 'refreshing-instances' | 'completed' | 'error';
175
+ type DeploymentProgressStage = "idle" | "validating" | "loading-manifest" | "verifying-rootfs" | "loading-pricing" | "loading-balance" | "selecting-crn" | "building-message" | "signing-message" | "broadcasting" | "notifying-crn" | "waiting-for-aleph" | "deployment-confirmed" | "deployment-rejected" | "building-delete-message" | "signing-delete-message" | "broadcasting-delete" | "delete-completed" | "refreshing-instances" | "completed" | "error";
176
176
  interface DeploymentProgressEvent {
177
177
  stage: DeploymentProgressStage;
178
178
  label: string;
179
179
  progress: number;
180
- status: 'info' | 'success' | 'warning' | 'error';
180
+ status: "info" | "success" | "warning" | "error";
181
181
  itemHash?: string | null;
182
182
  detail?: string | null;
183
183
  error?: string | null;
package/shared/index.js CHANGED
@@ -1225,6 +1225,88 @@ async function deployInstance(args) {
1225
1225
  };
1226
1226
  }
1227
1227
 
1228
+ // ../core/src/guest.ts
1229
+ async function notifyCrnAllocation2(args) {
1230
+ const normalizedCrnUrl = typeof args.crnUrl === "string" ? args.crnUrl.trim().replace(/\/+$/, "") : "";
1231
+ if (!normalizedCrnUrl) {
1232
+ return {
1233
+ status: "skipped",
1234
+ reason: "No CRN URL available for allocation notification."
1235
+ };
1236
+ }
1237
+ try {
1238
+ const response = await args.fetch(
1239
+ `${normalizedCrnUrl}/control/allocation/notify`,
1240
+ {
1241
+ method: "POST",
1242
+ headers: {
1243
+ "content-type": "application/json"
1244
+ },
1245
+ body: JSON.stringify({ instance: args.itemHash })
1246
+ }
1247
+ );
1248
+ const payload = await response.json().catch(() => null);
1249
+ const responseText = payload == null ? "" : typeof payload === "string" ? payload : JSON.stringify(payload);
1250
+ if (!response.ok) {
1251
+ return {
1252
+ status: "unconfirmed",
1253
+ reason: `CRN allocation notify returned ${response.status}${responseText ? ` ${responseText}` : ""}.`,
1254
+ payload
1255
+ };
1256
+ }
1257
+ return {
1258
+ status: "confirmed",
1259
+ payload
1260
+ };
1261
+ } catch (error) {
1262
+ return {
1263
+ status: "unconfirmed",
1264
+ reason: error instanceof Error ? error.message : String(error)
1265
+ };
1266
+ }
1267
+ }
1268
+ function isRetryableAllocationNotifyReason(reason) {
1269
+ const normalized = String(reason ?? "").toLowerCase();
1270
+ return normalized.includes("503") && (normalized.includes("node hash not yet discovered") || normalized.includes("cannot accept targeted allocations"));
1271
+ }
1272
+ async function notifyCrnAllocationWithRetry(args) {
1273
+ const attempts = Math.max(1, Number(args.attempts ?? 6));
1274
+ const delayMs = Math.max(0, Number(args.delayMs ?? 2e3));
1275
+ const sleep = args.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
1276
+ let lastResult = null;
1277
+ for (let attempt = 0; attempt < attempts; attempt += 1) {
1278
+ args.onProgress?.({
1279
+ stage: "notifying-crn",
1280
+ label: "Notifying selected CRN",
1281
+ progress: 84,
1282
+ status: "info",
1283
+ itemHash: args.itemHash,
1284
+ detail: `${attempt + 1}/${attempts} ${String(args.crnUrl ?? "").trim() || "selected CRN"}`,
1285
+ error: null,
1286
+ timestamp: Date.now()
1287
+ });
1288
+ const result = await notifyCrnAllocation2({
1289
+ crnUrl: args.crnUrl,
1290
+ itemHash: args.itemHash,
1291
+ fetch: args.fetch
1292
+ });
1293
+ if (result.status === "confirmed" || result.status === "skipped") {
1294
+ return result;
1295
+ }
1296
+ lastResult = result;
1297
+ if (!isRetryableAllocationNotifyReason(result.reason)) {
1298
+ return result;
1299
+ }
1300
+ if (attempt < attempts - 1) {
1301
+ await sleep(delayMs);
1302
+ }
1303
+ }
1304
+ return lastResult ?? {
1305
+ status: "unconfirmed",
1306
+ reason: "CRN allocation notify was not confirmed."
1307
+ };
1308
+ }
1309
+
1228
1310
  // src/shared/events.ts
1229
1311
  function createDeploymentProgressEmitter() {
1230
1312
  const listeners = /* @__PURE__ */ new Set();
@@ -1298,14 +1380,19 @@ function defaultState(props = {}) {
1298
1380
  };
1299
1381
  }
1300
1382
  async function sha256Hex(payload) {
1301
- const digest = await globalThis.crypto.subtle.digest("SHA-256", new TextEncoder().encode(payload));
1383
+ const digest = await globalThis.crypto.subtle.digest(
1384
+ "SHA-256",
1385
+ new TextEncoder().encode(payload)
1386
+ );
1302
1387
  return Array.from(new Uint8Array(digest)).map((byte) => byte.toString(16).padStart(2, "0")).join("");
1303
1388
  }
1304
1389
  function mappedPorts(execution) {
1305
- return Object.entries(execution?.networking?.mapped_ports ?? {}).map(([port, mapping]) => ({
1306
- label: `${port}/${mapping.udp ? "udp" : "tcp"}`,
1307
- hostPort: mapping.host ?? null
1308
- }));
1390
+ return Object.entries(execution?.networking?.mapped_ports ?? {}).map(
1391
+ ([port, mapping]) => ({
1392
+ label: `${port}/${mapping.udp ? "udp" : "tcp"}`,
1393
+ hostPort: mapping.host ?? null
1394
+ })
1395
+ );
1309
1396
  }
1310
1397
  function rootfsHealth(args) {
1311
1398
  if (!args.manifestState.valid || !args.manifestState.manifest) {
@@ -1363,7 +1450,9 @@ async function resolveManifest(args) {
1363
1450
  }
1364
1451
  async function inspectInstanceRuntime(args) {
1365
1452
  const details = {
1366
- messageStatus: String(args.instance.status ?? (args.instance.confirmed ? "processed" : "unknown")).toLowerCase(),
1453
+ messageStatus: String(
1454
+ args.instance.status ?? (args.instance.confirmed ? "processed" : "unknown")
1455
+ ).toLowerCase(),
1367
1456
  allocationSource: null,
1368
1457
  crnUrl: null,
1369
1458
  hostIpv4: null,
@@ -1394,11 +1483,15 @@ async function inspectInstanceRuntime(args) {
1394
1483
  details.allocationSource = allocation?.source ?? null;
1395
1484
  details.crnUrl = allocation?.crnUrl ?? null;
1396
1485
  details.ipv6 = allocation?.vmIpv6 ?? null;
1397
- details.webUrl = await args.client.fetch2n6WebAccessUrl(args.instance.item_hash);
1486
+ details.webUrl = await args.client.fetch2n6WebAccessUrl(
1487
+ args.instance.item_hash
1488
+ );
1398
1489
  if (!allocation?.crnUrl) {
1399
1490
  return details;
1400
1491
  }
1401
- const executionLookup = await args.client.fetchCrnExecutionMap(allocation.crnUrl);
1492
+ const executionLookup = await args.client.fetchCrnExecutionMap(
1493
+ allocation.crnUrl
1494
+ );
1402
1495
  const executionPayload = executionLookup.payload?.[args.instance.item_hash];
1403
1496
  if (!executionPayload) {
1404
1497
  return details;
@@ -1426,7 +1519,10 @@ function compatibleCrnsForTier(crns, state) {
1426
1519
  if (!state.pricingSummary.pricing || !state.pricingSummary.tier) {
1427
1520
  return [];
1428
1521
  }
1429
- const spec = tierSpec(state.pricingSummary.pricing, state.pricingSummary.tier);
1522
+ const spec = tierSpec(
1523
+ state.pricingSummary.pricing,
1524
+ state.pricingSummary.tier
1525
+ );
1430
1526
  return filterDeployableCrns(crns, { spec });
1431
1527
  }
1432
1528
  async function pingPeer(libp2p) {
@@ -1716,8 +1812,14 @@ var SponsorRelayController = class {
1716
1812
  status: "info",
1717
1813
  detail: manifest.rootfsItemHash
1718
1814
  });
1719
- rootfsVerified = await verifyRootfsExists(manifest.rootfsItemHash, this.client.apiHost);
1720
- rootfsResolution = await resolveRootfsReference(manifest.rootfsItemHash, this.client.apiHost);
1815
+ rootfsVerified = await verifyRootfsExists(
1816
+ manifest.rootfsItemHash,
1817
+ this.client.apiHost
1818
+ );
1819
+ rootfsResolution = await resolveRootfsReference(
1820
+ manifest.rootfsItemHash,
1821
+ this.client.apiHost
1822
+ );
1721
1823
  }
1722
1824
  this.patch({
1723
1825
  manifestState,
@@ -1772,7 +1874,9 @@ var SponsorRelayController = class {
1772
1874
  return;
1773
1875
  }
1774
1876
  if (!this.state.manifest || !this.state.rootfsVerified || !this.state.pricingSummary.pricing || !this.state.pricingSummary.tier) {
1775
- this.patch({ errorText: "Manifest, rootfs, and pricing must be ready before deploying." });
1877
+ this.patch({
1878
+ errorText: "Manifest, rootfs, and pricing must be ready before deploying."
1879
+ });
1776
1880
  return;
1777
1881
  }
1778
1882
  this.patch({
@@ -1788,7 +1892,10 @@ var SponsorRelayController = class {
1788
1892
  status: "info",
1789
1893
  detail: "Checking wallet, manifest, rootfs, pricing, and SSH key."
1790
1894
  });
1791
- const spec = tierSpec(this.state.pricingSummary.pricing, this.state.pricingSummary.tier);
1895
+ const spec = tierSpec(
1896
+ this.state.pricingSummary.pricing,
1897
+ this.state.pricingSummary.tier
1898
+ );
1792
1899
  this.emitProgress({
1793
1900
  stage: "selecting-crn",
1794
1901
  label: "Selecting CRN",
@@ -1801,7 +1908,10 @@ var SponsorRelayController = class {
1801
1908
  name: this.state.instanceName.trim(),
1802
1909
  sshPublicKey: this.state.sshPublicKey.trim(),
1803
1910
  rootfsItemHash: this.state.manifest.rootfsItemHash,
1804
- rootfsSizeMiB: Math.max(this.state.manifest.rootfsSizeMiB, spec.diskMiB),
1911
+ rootfsSizeMiB: Math.max(
1912
+ this.state.manifest.rootfsSizeMiB,
1913
+ spec.diskMiB
1914
+ ),
1805
1915
  vcpus: spec.vcpus,
1806
1916
  memoryMiB: spec.memoryMiB,
1807
1917
  rootfsVersion: this.state.manifest.version,
@@ -1824,6 +1934,16 @@ var SponsorRelayController = class {
1824
1934
  statusText: `Deployment submitted: ${result.itemHash}`,
1825
1935
  lastDeploymentHash: result.itemHash
1826
1936
  });
1937
+ if (result.status === "processed" && this.state.selectedCrn?.address) {
1938
+ await notifyCrnAllocationWithRetry({
1939
+ crnUrl: this.state.selectedCrn.address,
1940
+ itemHash: result.itemHash,
1941
+ fetch: (url, init) => fetch(url, init),
1942
+ onProgress: (event) => {
1943
+ this.emitProgress(event);
1944
+ }
1945
+ });
1946
+ }
1827
1947
  this.emitProgress({
1828
1948
  stage: "refreshing-instances",
1829
1949
  label: "Refreshing instances",