@le-space/ui 0.1.54 → 0.1.55

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/shared/index.d.ts CHANGED
@@ -172,6 +172,19 @@ 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';
176
+ interface DeploymentProgressEvent {
177
+ stage: DeploymentProgressStage;
178
+ label: string;
179
+ progress: number;
180
+ status: 'info' | 'success' | 'warning' | 'error';
181
+ itemHash?: string | null;
182
+ detail?: string | null;
183
+ error?: string | null;
184
+ timestamp: number;
185
+ }
186
+ type DeploymentProgressListener = (event: DeploymentProgressEvent) => void;
187
+
175
188
  type SponsorRelayHealthTone = 'ok' | 'caution' | 'error' | 'idle';
176
189
  interface SponsorRelayProps {
177
190
  libp2p?: unknown;
@@ -268,6 +281,7 @@ interface SponsorRelayState {
268
281
  instances: CompactInstanceRecord[];
269
282
  relayPing: RelayPingState;
270
283
  lastDeploymentHash: string | null;
284
+ deploymentProgress: DeploymentProgressEvent;
271
285
  }
272
286
  type SponsorRelaySubscriber = (state: SponsorRelayState) => void;
273
287
 
@@ -276,6 +290,7 @@ declare const DEFAULT_MANIFEST_URL = "./rootfs-manifest.json";
276
290
  declare const DEFAULT_TIER_ID = "tier-1";
277
291
  declare const ROOTFS_MISSING_STATE: SponsorRelayRootfsHealth;
278
292
  declare const RELAY_PING_IDLE_STATE: RelayPingState;
293
+ declare const IDLE_DEPLOYMENT_PROGRESS: DeploymentProgressEvent;
279
294
  declare const REFRESH_INTERVAL_MS = 30000;
280
295
  declare const RELAY_PING_INTERVAL_MS = 20000;
281
296
 
@@ -299,6 +314,7 @@ interface EthereumProviderLike {
299
314
  removeListener?(event: string, listener: (...args: unknown[]) => void): void;
300
315
  }
301
316
  declare function getEthereumProvider(): EthereumProviderLike | null;
317
+ declare function toChecksumAddress(address: string): string;
302
318
  declare function connectWallet(provider?: EthereumProviderLike | null): Promise<SponsorRelayWalletState>;
303
319
  declare function personalSign(address: string, message: string, provider?: EthereumProviderLike | null): Promise<string>;
304
320
  declare function watchWallet(onChange: () => void, provider?: EthereumProviderLike | null): () => void;
@@ -311,11 +327,14 @@ declare class SponsorRelayController {
311
327
  private pingTimer;
312
328
  private stopWalletWatch;
313
329
  private props;
330
+ private progressEmitter;
314
331
  constructor(props?: SponsorRelayProps);
332
+ subscribeToDeploymentProgress(listener: DeploymentProgressListener): () => void;
315
333
  subscribe(subscriber: SponsorRelaySubscriber): () => void;
316
334
  getState(): SponsorRelayState;
317
335
  private emit;
318
336
  private patch;
337
+ private emitProgress;
319
338
  init(): Promise<void>;
320
339
  destroy(): void;
321
340
  setOpen(open: boolean): void;
@@ -336,4 +355,11 @@ declare class SponsorRelayController {
336
355
  }
337
356
  declare function createSponsorRelayController(props?: SponsorRelayProps): SponsorRelayController;
338
357
 
339
- export { type CompactInstanceDetails, type CompactInstanceRecord, DEFAULT_INSTANCE_NAME, DEFAULT_MANIFEST_URL, DEFAULT_TIER_ID, type EthereumProviderLike, REFRESH_INTERVAL_MS, RELAY_PING_IDLE_STATE, RELAY_PING_INTERVAL_MS, ROOTFS_MISSING_STATE, type RelayPingState, SponsorRelayController, type SponsorRelayHealthTone, type SponsorRelayPricingSummary, type SponsorRelayProps, type SponsorRelayRootfsHealth, type SponsorRelayState, type SponsorRelaySubscriber, type SponsorRelayWalletState, buildSshCommand, connectWallet, createSponsorRelayController, formatDateTime, formatNumber, getEthereumProvider, joinMappedPorts, personalSign, resolveManifestSource, shortHash, watchWallet };
358
+ interface DeploymentProgressEmitter {
359
+ emit(event: DeploymentProgressEvent): void;
360
+ subscribe(listener: DeploymentProgressListener): () => void;
361
+ clear(): void;
362
+ }
363
+ declare function createDeploymentProgressEmitter(): DeploymentProgressEmitter;
364
+
365
+ export { type CompactInstanceDetails, type CompactInstanceRecord, DEFAULT_INSTANCE_NAME, DEFAULT_MANIFEST_URL, DEFAULT_TIER_ID, type DeploymentProgressEmitter, type EthereumProviderLike, IDLE_DEPLOYMENT_PROGRESS, REFRESH_INTERVAL_MS, RELAY_PING_IDLE_STATE, RELAY_PING_INTERVAL_MS, ROOTFS_MISSING_STATE, type RelayPingState, SponsorRelayController, type SponsorRelayHealthTone, type SponsorRelayPricingSummary, type SponsorRelayProps, type SponsorRelayRootfsHealth, type SponsorRelayState, type SponsorRelaySubscriber, type SponsorRelayWalletState, buildSshCommand, connectWallet, createDeploymentProgressEmitter, createSponsorRelayController, formatDateTime, formatNumber, getEthereumProvider, joinMappedPorts, personalSign, resolveManifestSource, shortHash, toChecksumAddress, watchWallet };
package/shared/index.js CHANGED
@@ -17,6 +17,16 @@ var RELAY_PING_IDLE_STATE = {
17
17
  lastReceivedAt: null,
18
18
  error: null
19
19
  };
20
+ var IDLE_DEPLOYMENT_PROGRESS = {
21
+ stage: "idle",
22
+ label: "Ready",
23
+ progress: 0,
24
+ status: "info",
25
+ itemHash: null,
26
+ detail: null,
27
+ error: null,
28
+ timestamp: Date.now()
29
+ };
20
30
  var REFRESH_INTERVAL_MS = 3e4;
21
31
  var RELAY_PING_INTERVAL_MS = 2e4;
22
32
 
@@ -696,18 +706,34 @@ function resolveManifestSource(args) {
696
706
  }
697
707
 
698
708
  // src/shared/wallet-controller.ts
709
+ import { keccak_256 } from "@noble/hashes/sha3";
699
710
  function getEthereumProvider() {
700
711
  return globalThis.window?.ethereum ?? null;
701
712
  }
713
+ function toChecksumAddress(address) {
714
+ if (!/^0x[0-9a-fA-F]{40}$/.test(address)) {
715
+ throw new Error("Invalid EVM address.");
716
+ }
717
+ const normalized = address.slice(2).toLowerCase();
718
+ const hash = Array.from(keccak_256(new TextEncoder().encode(normalized))).map((byte) => byte.toString(16).padStart(2, "0")).join("");
719
+ let result = "0x";
720
+ for (let index = 0; index < normalized.length; index += 1) {
721
+ result += Number.parseInt(hash[index], 16) >= 8 ? normalized[index].toUpperCase() : normalized[index];
722
+ }
723
+ return result;
724
+ }
702
725
  async function connectWallet(provider = getEthereumProvider()) {
703
726
  if (!provider) {
704
727
  throw new Error("MetaMask provider not found.");
705
728
  }
706
- const accounts = await provider.request({ method: "eth_requestAccounts" });
729
+ const accounts = await provider.request({
730
+ method: "eth_requestAccounts"
731
+ });
707
732
  const chainId = await provider.request({ method: "eth_chainId" });
733
+ const address = accounts[0] ? toChecksumAddress(accounts[0]) : null;
708
734
  return {
709
- connected: Boolean(accounts[0]),
710
- address: accounts[0] ?? null,
735
+ connected: Boolean(address),
736
+ address,
711
737
  chainId,
712
738
  isMetaMask: Boolean(provider.isMetaMask)
713
739
  };
@@ -963,6 +989,16 @@ async function createUnsignedForgetMessage(args) {
963
989
  };
964
990
  }
965
991
  async function forgetAlephMessages(args) {
992
+ args.onProgress?.({
993
+ stage: "building-delete-message",
994
+ label: "Building delete message",
995
+ progress: 18,
996
+ status: "info",
997
+ itemHash: null,
998
+ detail: [...new Set((args.hashes ?? []).filter(Boolean))].join(", ") || null,
999
+ error: null,
1000
+ timestamp: Date.now()
1001
+ });
966
1002
  const unsignedMessage = await createUnsignedForgetMessage({
967
1003
  sender: args.sender,
968
1004
  hashes: args.hashes,
@@ -972,18 +1008,49 @@ async function forgetAlephMessages(args) {
972
1008
  channel: args.channel,
973
1009
  now: args.now
974
1010
  });
1011
+ args.onProgress?.({
1012
+ stage: "signing-delete-message",
1013
+ label: "Waiting for delete signature",
1014
+ progress: 42,
1015
+ status: "info",
1016
+ itemHash: unsignedMessage.item_hash,
1017
+ detail: unsignedMessage.item_hash,
1018
+ error: null,
1019
+ timestamp: Date.now()
1020
+ });
975
1021
  const message = await signAlephMessage(unsignedMessage, args.signer);
1022
+ args.onProgress?.({
1023
+ stage: "broadcasting-delete",
1024
+ label: "Broadcasting delete to Aleph",
1025
+ progress: 68,
1026
+ status: "warning",
1027
+ itemHash: message.item_hash,
1028
+ detail: message.item_hash,
1029
+ error: null,
1030
+ timestamp: Date.now()
1031
+ });
976
1032
  const { response, httpStatus } = await broadcastAlephMessage2(message, {
977
1033
  apiHost: args.apiHost,
978
1034
  sync: args.sync,
979
1035
  fetch: args.fetch
980
1036
  });
1037
+ const status = normalizeBroadcastStatus(httpStatus, response?.message_status);
1038
+ args.onProgress?.({
1039
+ stage: status === "rejected" ? "error" : "delete-completed",
1040
+ label: status === "rejected" ? "Delete rejected by Aleph" : "Delete submitted to Aleph",
1041
+ progress: 100,
1042
+ status: status === "rejected" ? "error" : "success",
1043
+ itemHash: message.item_hash,
1044
+ detail: status === "rejected" ? String(response?.details ?? "Aleph rejected this delete request.") : null,
1045
+ error: status === "rejected" ? String(response?.details ?? "Aleph rejected this delete request.") : null,
1046
+ timestamp: Date.now()
1047
+ });
981
1048
  return {
982
1049
  sender: args.sender,
983
1050
  itemHash: message.item_hash,
984
1051
  response,
985
1052
  httpStatus,
986
- status: normalizeBroadcastStatus(httpStatus, response?.message_status)
1053
+ status
987
1054
  };
988
1055
  }
989
1056
 
@@ -1090,6 +1157,16 @@ async function createUnsignedInstanceMessage(args) {
1090
1157
  };
1091
1158
  }
1092
1159
  async function deployInstance(args) {
1160
+ args.onProgress?.({
1161
+ stage: "building-message",
1162
+ label: "Building deployment message",
1163
+ progress: 32,
1164
+ status: "info",
1165
+ detail: args.content.metadata?.name ?? null,
1166
+ itemHash: null,
1167
+ error: null,
1168
+ timestamp: Date.now()
1169
+ });
1093
1170
  const unsignedMessage = await createUnsignedInstanceMessage({
1094
1171
  sender: args.sender,
1095
1172
  content: args.content,
@@ -1097,17 +1174,47 @@ async function deployInstance(args) {
1097
1174
  channel: args.channel,
1098
1175
  now: args.now
1099
1176
  });
1177
+ args.onProgress?.({
1178
+ stage: "signing-message",
1179
+ label: "Waiting for MetaMask signature",
1180
+ progress: 48,
1181
+ status: "info",
1182
+ detail: unsignedMessage.item_hash,
1183
+ itemHash: unsignedMessage.item_hash,
1184
+ error: null,
1185
+ timestamp: Date.now()
1186
+ });
1100
1187
  const signature = await args.signer(unsignedMessage.sender, [unsignedMessage.chain, unsignedMessage.sender, unsignedMessage.type, unsignedMessage.item_hash].join("\n"));
1101
1188
  const message = {
1102
1189
  ...unsignedMessage,
1103
1190
  signature: signature.startsWith("0x") ? signature : `0x${signature}`
1104
1191
  };
1192
+ args.onProgress?.({
1193
+ stage: "broadcasting",
1194
+ label: "Broadcasting to Aleph",
1195
+ progress: 64,
1196
+ status: "info",
1197
+ detail: message.item_hash,
1198
+ itemHash: message.item_hash,
1199
+ error: null,
1200
+ timestamp: Date.now()
1201
+ });
1105
1202
  const { response, httpStatus } = await broadcastAlephMessage2(message, {
1106
1203
  apiHost: args.apiHost,
1107
1204
  sync: args.sync,
1108
1205
  fetch: args.fetch
1109
1206
  });
1110
1207
  const status = httpStatus === 202 ? "pending" : typeof response.message_status === "string" ? response.message_status : "unknown";
1208
+ args.onProgress?.({
1209
+ stage: status === "processed" ? "deployment-confirmed" : status === "rejected" ? "deployment-rejected" : "waiting-for-aleph",
1210
+ label: status === "processed" ? "Deployment accepted by Aleph" : status === "rejected" ? "Deployment rejected by Aleph" : "Deployment submitted to Aleph",
1211
+ progress: status === "processed" ? 88 : status === "rejected" ? 100 : 78,
1212
+ status: status === "processed" ? "success" : status === "rejected" ? "error" : "warning",
1213
+ detail: status === "rejected" ? String(response.details ?? "Aleph rejected this deployment.") : null,
1214
+ itemHash: message.item_hash,
1215
+ error: status === "rejected" ? String(response.details ?? "Aleph rejected this deployment.") : null,
1216
+ timestamp: Date.now()
1217
+ });
1111
1218
  return {
1112
1219
  itemHash: message.item_hash,
1113
1220
  httpStatus,
@@ -1118,6 +1225,25 @@ async function deployInstance(args) {
1118
1225
  };
1119
1226
  }
1120
1227
 
1228
+ // src/shared/events.ts
1229
+ function createDeploymentProgressEmitter() {
1230
+ const listeners = /* @__PURE__ */ new Set();
1231
+ return {
1232
+ emit(event) {
1233
+ listeners.forEach((listener) => listener(event));
1234
+ },
1235
+ subscribe(listener) {
1236
+ listeners.add(listener);
1237
+ return () => {
1238
+ listeners.delete(listener);
1239
+ };
1240
+ },
1241
+ clear() {
1242
+ listeners.clear();
1243
+ }
1244
+ };
1245
+ }
1246
+
1121
1247
  // src/shared/controller.ts
1122
1248
  function defaultState(props = {}) {
1123
1249
  return {
@@ -1167,7 +1293,8 @@ function defaultState(props = {}) {
1167
1293
  selectedCrn: null,
1168
1294
  instances: [],
1169
1295
  relayPing: RELAY_PING_IDLE_STATE,
1170
- lastDeploymentHash: null
1296
+ lastDeploymentHash: null,
1297
+ deploymentProgress: IDLE_DEPLOYMENT_PROGRESS
1171
1298
  };
1172
1299
  }
1173
1300
  async function sha256Hex(payload) {
@@ -1361,6 +1488,7 @@ var SponsorRelayController = class {
1361
1488
  pingTimer = null;
1362
1489
  stopWalletWatch = null;
1363
1490
  props;
1491
+ progressEmitter = createDeploymentProgressEmitter();
1364
1492
  constructor(props = {}) {
1365
1493
  this.props = props;
1366
1494
  this.state = defaultState(props);
@@ -1371,6 +1499,9 @@ var SponsorRelayController = class {
1371
1499
  twoN6ApiHost: props.twoN6ApiHost
1372
1500
  });
1373
1501
  }
1502
+ subscribeToDeploymentProgress(listener) {
1503
+ return this.progressEmitter.subscribe(listener);
1504
+ }
1374
1505
  subscribe(subscriber) {
1375
1506
  this.subscribers.add(subscriber);
1376
1507
  return () => {
@@ -1395,6 +1526,18 @@ var SponsorRelayController = class {
1395
1526
  };
1396
1527
  this.emit();
1397
1528
  }
1529
+ emitProgress(event) {
1530
+ const nextEvent = {
1531
+ ...event,
1532
+ timestamp: Date.now()
1533
+ };
1534
+ this.patch({
1535
+ deploymentProgress: nextEvent,
1536
+ statusText: event.error ?? event.detail ?? event.label,
1537
+ errorText: event.status === "error" ? event.error ?? event.detail ?? event.label : this.state.errorText
1538
+ });
1539
+ this.progressEmitter.emit(nextEvent);
1540
+ }
1398
1541
  async init() {
1399
1542
  this.stopWalletWatch = watchWallet(() => {
1400
1543
  void this.refreshWalletDerivedState();
@@ -1514,11 +1657,25 @@ var SponsorRelayController = class {
1514
1657
  statusText: "Refreshing relay sponsor data"
1515
1658
  });
1516
1659
  try {
1660
+ this.emitProgress({
1661
+ stage: "loading-manifest",
1662
+ label: "Loading manifest",
1663
+ progress: 8,
1664
+ status: "info",
1665
+ detail: this.state.manifestUrl
1666
+ });
1517
1667
  const manifestState = await resolveManifest({
1518
1668
  manifestUrl: this.state.manifestUrl,
1519
1669
  manifestJson: this.state.manifestJson
1520
1670
  });
1521
1671
  const manifest = manifestState.manifest;
1672
+ this.emitProgress({
1673
+ stage: "loading-pricing",
1674
+ label: "Loading pricing and CRNs",
1675
+ progress: 18,
1676
+ status: "info",
1677
+ detail: "Fetching live Aleph pricing and compatible CRNs."
1678
+ });
1522
1679
  const [pricingSummary, crns] = await Promise.all([
1523
1680
  fetchInstancePricing(this.client.apiHost),
1524
1681
  this.client.fetchCrns()
@@ -1526,6 +1683,13 @@ var SponsorRelayController = class {
1526
1683
  let balance = this.state.balance;
1527
1684
  let instances = [];
1528
1685
  if (this.state.wallet.address) {
1686
+ this.emitProgress({
1687
+ stage: "loading-balance",
1688
+ label: "Loading wallet balance",
1689
+ progress: 28,
1690
+ status: "info",
1691
+ detail: this.state.wallet.address
1692
+ });
1529
1693
  const [nextBalance, rawInstances] = await Promise.all([
1530
1694
  this.client.fetchBalance(this.state.wallet.address),
1531
1695
  this.state.showInstances ? this.client.fetchInstances(this.state.wallet.address) : Promise.resolve([])
@@ -1545,6 +1709,13 @@ var SponsorRelayController = class {
1545
1709
  let rootfsVerified = false;
1546
1710
  let rootfsResolution = null;
1547
1711
  if (manifestState.valid && manifest) {
1712
+ this.emitProgress({
1713
+ stage: "verifying-rootfs",
1714
+ label: "Verifying rootfs",
1715
+ progress: 38,
1716
+ status: "info",
1717
+ detail: manifest.rootfsItemHash
1718
+ });
1548
1719
  rootfsVerified = await verifyRootfsExists(manifest.rootfsItemHash, this.client.apiHost);
1549
1720
  rootfsResolution = await resolveRootfsReference(manifest.rootfsItemHash, this.client.apiHost);
1550
1721
  }
@@ -1569,12 +1740,26 @@ var SponsorRelayController = class {
1569
1740
  statusText: "Relay sponsor data ready"
1570
1741
  });
1571
1742
  this.recomputePricingSummary();
1743
+ this.emitProgress({
1744
+ stage: "completed",
1745
+ label: "Data ready",
1746
+ progress: 100,
1747
+ status: "success",
1748
+ detail: "Manifest, pricing, and wallet state are ready."
1749
+ });
1572
1750
  } catch (error) {
1573
1751
  this.patch({
1574
1752
  busy: { refreshing: false },
1575
1753
  errorText: error instanceof Error ? error.message : String(error),
1576
1754
  statusText: "Refresh failed"
1577
1755
  });
1756
+ this.emitProgress({
1757
+ stage: "error",
1758
+ label: "Refresh failed",
1759
+ progress: 100,
1760
+ status: "error",
1761
+ error: error instanceof Error ? error.message : String(error)
1762
+ });
1578
1763
  }
1579
1764
  }
1580
1765
  async refreshRelayPing() {
@@ -1596,7 +1781,21 @@ var SponsorRelayController = class {
1596
1781
  statusText: "Broadcasting deployment"
1597
1782
  });
1598
1783
  try {
1784
+ this.emitProgress({
1785
+ stage: "validating",
1786
+ label: "Validating deployment",
1787
+ progress: 5,
1788
+ status: "info",
1789
+ detail: "Checking wallet, manifest, rootfs, pricing, and SSH key."
1790
+ });
1599
1791
  const spec = tierSpec(this.state.pricingSummary.pricing, this.state.pricingSummary.tier);
1792
+ this.emitProgress({
1793
+ stage: "selecting-crn",
1794
+ label: "Selecting CRN",
1795
+ progress: 18,
1796
+ status: "info",
1797
+ detail: this.state.selectedCrn?.name ?? this.state.selectedCrn?.hash ?? "Auto-selected compatible CRN"
1798
+ });
1600
1799
  const content = createInstanceContent({
1601
1800
  address: this.state.wallet.address,
1602
1801
  name: this.state.instanceName.trim(),
@@ -1615,20 +1814,47 @@ var SponsorRelayController = class {
1615
1814
  signer: personalSign,
1616
1815
  fetch: (url, init) => fetch(url, init),
1617
1816
  apiHost: this.client.apiHost,
1618
- sync: false
1817
+ sync: false,
1818
+ onProgress: (event) => {
1819
+ this.emitProgress(event);
1820
+ }
1619
1821
  });
1620
1822
  this.patch({
1621
1823
  busy: { deploying: false },
1622
1824
  statusText: `Deployment submitted: ${result.itemHash}`,
1623
1825
  lastDeploymentHash: result.itemHash
1624
1826
  });
1827
+ this.emitProgress({
1828
+ stage: "refreshing-instances",
1829
+ label: "Refreshing instances",
1830
+ progress: 92,
1831
+ status: "info",
1832
+ itemHash: result.itemHash,
1833
+ detail: "Reloading deployments and runtime state."
1834
+ });
1625
1835
  await this.refresh();
1836
+ this.emitProgress({
1837
+ stage: "completed",
1838
+ label: "Deployment completed",
1839
+ progress: 100,
1840
+ status: result.status === "rejected" ? "error" : "success",
1841
+ itemHash: result.itemHash,
1842
+ detail: result.status === "rejected" ? result.rejectionReason ?? "Aleph rejected the deployment." : "Deployment submitted and synced back into the panel.",
1843
+ error: result.status === "rejected" ? result.rejectionReason ?? "Aleph rejected the deployment." : null
1844
+ });
1626
1845
  } catch (error) {
1627
1846
  this.patch({
1628
1847
  busy: { deploying: false },
1629
1848
  errorText: error instanceof Error ? error.message : String(error),
1630
1849
  statusText: "Deployment failed"
1631
1850
  });
1851
+ this.emitProgress({
1852
+ stage: "error",
1853
+ label: "Deployment failed",
1854
+ progress: 100,
1855
+ status: "error",
1856
+ error: error instanceof Error ? error.message : String(error)
1857
+ });
1632
1858
  }
1633
1859
  }
1634
1860
  async deleteInstance(instanceHash) {
@@ -1642,6 +1868,14 @@ var SponsorRelayController = class {
1642
1868
  statusText: `Deleting ${instanceHash}`
1643
1869
  });
1644
1870
  try {
1871
+ this.emitProgress({
1872
+ stage: "validating",
1873
+ label: "Validating delete request",
1874
+ progress: 6,
1875
+ status: "warning",
1876
+ itemHash: instanceHash,
1877
+ detail: "Preparing Aleph FORGET message."
1878
+ });
1645
1879
  await forgetAlephMessages({
1646
1880
  sender: this.state.wallet.address,
1647
1881
  hashes: [instanceHash],
@@ -1653,13 +1887,33 @@ var SponsorRelayController = class {
1653
1887
  status: response.status,
1654
1888
  json: async () => await response.json()
1655
1889
  })),
1656
- apiHost: this.client.apiHost
1890
+ apiHost: this.client.apiHost,
1891
+ onProgress: (event) => {
1892
+ this.emitProgress(event);
1893
+ }
1657
1894
  });
1658
1895
  this.patch({
1659
1896
  busy: { deletingInstanceHash: null },
1660
1897
  statusText: `Deletion submitted for ${instanceHash}`
1661
1898
  });
1899
+ this.emitProgress({
1900
+ stage: "refreshing-instances",
1901
+ label: "Refreshing instances after delete",
1902
+ progress: 92,
1903
+ status: "info",
1904
+ itemHash: instanceHash,
1905
+ detail: "Reloading current deployments."
1906
+ });
1662
1907
  await this.refresh();
1908
+ this.emitProgress({
1909
+ stage: "completed",
1910
+ label: "Delete completed",
1911
+ progress: 100,
1912
+ status: "success",
1913
+ itemHash: instanceHash,
1914
+ detail: "Delete request submitted and deployments refreshed.",
1915
+ error: null
1916
+ });
1663
1917
  } catch (error) {
1664
1918
  this.patch({
1665
1919
  busy: { deletingInstanceHash: null },
@@ -1676,6 +1930,7 @@ export {
1676
1930
  DEFAULT_INSTANCE_NAME,
1677
1931
  DEFAULT_MANIFEST_URL,
1678
1932
  DEFAULT_TIER_ID,
1933
+ IDLE_DEPLOYMENT_PROGRESS,
1679
1934
  REFRESH_INTERVAL_MS,
1680
1935
  RELAY_PING_IDLE_STATE,
1681
1936
  RELAY_PING_INTERVAL_MS,
@@ -1683,6 +1938,7 @@ export {
1683
1938
  SponsorRelayController,
1684
1939
  buildSshCommand,
1685
1940
  connectWallet,
1941
+ createDeploymentProgressEmitter,
1686
1942
  createSponsorRelayController,
1687
1943
  formatDateTime,
1688
1944
  formatNumber,
@@ -1691,5 +1947,6 @@ export {
1691
1947
  personalSign,
1692
1948
  resolveManifestSource,
1693
1949
  shortHash,
1950
+ toChecksumAddress,
1694
1951
  watchWallet
1695
1952
  };
Binary file