@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/package.json +9 -1
- package/react/index.d.ts +17 -0
- package/react/index.js +849 -110
- package/shared/index.d.ts +27 -1
- package/shared/index.js +264 -7
- package/le-space-ui-0.1.54.tgz +0 -0
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
|
-
|
|
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({
|
|
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(
|
|
710
|
-
address
|
|
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
|
|
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
|
};
|
package/le-space-ui-0.1.54.tgz
DELETED
|
Binary file
|