@le-space/ui 0.3.7 → 0.3.8
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 +3 -3
- package/react/index.js +254 -180
- package/shared/index.js +253 -179
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@le-space/ui",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.8",
|
|
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.
|
|
40
|
-
"@le-space/core": "0.3.
|
|
39
|
+
"@le-space/browser": "0.3.8",
|
|
40
|
+
"@le-space/core": "0.3.8",
|
|
41
41
|
"viem": "^2.38.5"
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|
package/react/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import React from "react";
|
|
|
4
4
|
// package.json
|
|
5
5
|
var package_default = {
|
|
6
6
|
name: "@le-space/ui",
|
|
7
|
-
version: "0.3.
|
|
7
|
+
version: "0.3.8",
|
|
8
8
|
description: "Floating Aleph sponsor relay UI components for Svelte and React.",
|
|
9
9
|
license: "MIT",
|
|
10
10
|
type: "module",
|
|
@@ -3677,158 +3677,156 @@ var SponsorRelayController = class {
|
|
|
3677
3677
|
this.state.pricingSummary.pricing,
|
|
3678
3678
|
this.state.pricingSummary.tier
|
|
3679
3679
|
);
|
|
3680
|
-
this.
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
});
|
|
3687
|
-
const content = createInstanceContent({
|
|
3688
|
-
address: this.state.wallet.address,
|
|
3689
|
-
name: this.state.instanceName.trim(),
|
|
3690
|
-
sshPublicKey: this.state.sshPublicKey.trim(),
|
|
3691
|
-
rootfsItemHash: this.state.manifest.rootfsItemHash,
|
|
3692
|
-
rootfsSizeMiB: Math.max(
|
|
3693
|
-
this.state.manifest.rootfsSizeMiB,
|
|
3694
|
-
spec.diskMiB
|
|
3695
|
-
),
|
|
3696
|
-
vcpus: spec.vcpus,
|
|
3697
|
-
memoryMiB: spec.memoryMiB,
|
|
3698
|
-
rootfsVersion: this.state.manifest.version,
|
|
3699
|
-
crnHash: this.state.selectedCrn?.hash
|
|
3700
|
-
});
|
|
3701
|
-
const result = await deployInstance({
|
|
3702
|
-
sender: this.state.wallet.address,
|
|
3703
|
-
content,
|
|
3704
|
-
hasher: sha256Hex,
|
|
3705
|
-
signer: personalSign,
|
|
3706
|
-
fetch: (url, init) => fetch(url, init),
|
|
3707
|
-
apiHost: this.client.apiHost,
|
|
3708
|
-
sync: false,
|
|
3709
|
-
onProgress: (event) => {
|
|
3710
|
-
this.emitProgress(event);
|
|
3711
|
-
}
|
|
3712
|
-
});
|
|
3713
|
-
this.patch({
|
|
3714
|
-
statusText: `Deployment submitted: ${result.itemHash}`,
|
|
3715
|
-
lastDeploymentHash: result.itemHash
|
|
3716
|
-
});
|
|
3717
|
-
this.trace("deploy:broadcasted", result);
|
|
3718
|
-
this.lastRuntimeReadyHash = null;
|
|
3719
|
-
const inspection = await waitForDeploymentResult2(result.itemHash, {
|
|
3720
|
-
rootfsRef: this.state.manifest.rootfsItemHash,
|
|
3721
|
-
apiHost: this.client.apiHost,
|
|
3722
|
-
fetch: (url, init) => fetch(url, init),
|
|
3723
|
-
attempts: UI_DEPLOY_WAIT_ATTEMPTS,
|
|
3724
|
-
delayMs: UI_DEPLOY_WAIT_DELAY_MS,
|
|
3725
|
-
onAttempt: (inspectionResult) => {
|
|
3726
|
-
if (inspectionResult.status === "processed") {
|
|
3727
|
-
this.emitProgress({
|
|
3728
|
-
stage: "deployment-confirmed",
|
|
3729
|
-
label: "Deployment accepted by Aleph",
|
|
3730
|
-
progress: 82,
|
|
3731
|
-
status: "success",
|
|
3732
|
-
itemHash: result.itemHash,
|
|
3733
|
-
detail: "Aleph processed the instance message."
|
|
3734
|
-
});
|
|
3735
|
-
return;
|
|
3736
|
-
}
|
|
3737
|
-
if (inspectionResult.status === "rejected") {
|
|
3738
|
-
this.emitProgress({
|
|
3739
|
-
stage: "deployment-rejected",
|
|
3740
|
-
label: "Deployment rejected",
|
|
3741
|
-
progress: 100,
|
|
3742
|
-
status: "error",
|
|
3743
|
-
itemHash: result.itemHash,
|
|
3744
|
-
detail: inspectionResult.rejectionReason ?? "Aleph rejected the deployment.",
|
|
3745
|
-
error: inspectionResult.rejectionReason ?? "Aleph rejected the deployment."
|
|
3746
|
-
});
|
|
3747
|
-
return;
|
|
3748
|
-
}
|
|
3749
|
-
this.emitProgress({
|
|
3750
|
-
stage: "waiting-for-aleph",
|
|
3751
|
-
label: "Waiting for Aleph",
|
|
3752
|
-
progress: 76,
|
|
3753
|
-
status: "info",
|
|
3754
|
-
itemHash: result.itemHash,
|
|
3755
|
-
detail: "Deployment submitted. Waiting for Aleph to process the instance message."
|
|
3756
|
-
});
|
|
3680
|
+
const compatibleCrns2 = compatibleCrnsForTier(this.state.crns, {
|
|
3681
|
+
...this.state,
|
|
3682
|
+
pricingSummary: {
|
|
3683
|
+
...this.state.pricingSummary,
|
|
3684
|
+
pricing: this.state.pricingSummary.pricing,
|
|
3685
|
+
tier: this.state.pricingSummary.tier
|
|
3757
3686
|
}
|
|
3758
3687
|
});
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
)
|
|
3688
|
+
const preferredCrnHash = this.state.selectedCrn?.hash ?? null;
|
|
3689
|
+
const orderedCrns = [
|
|
3690
|
+
...compatibleCrns2.filter((crn) => crn.hash === preferredCrnHash),
|
|
3691
|
+
...compatibleCrns2.filter((crn) => crn.hash !== preferredCrnHash)
|
|
3692
|
+
].slice(0, 5);
|
|
3693
|
+
if (orderedCrns.length === 0) {
|
|
3694
|
+
throw new Error("No compatible CRN is currently available for this tier.");
|
|
3763
3695
|
}
|
|
3764
|
-
|
|
3765
|
-
|
|
3696
|
+
const attemptErrors = [];
|
|
3697
|
+
let lastError = null;
|
|
3698
|
+
for (const [candidateIndex, candidateCrn] of orderedCrns.entries()) {
|
|
3699
|
+
let attemptItemHash = null;
|
|
3766
3700
|
this.emitProgress({
|
|
3767
|
-
stage: "
|
|
3768
|
-
label: "
|
|
3769
|
-
progress:
|
|
3701
|
+
stage: "selecting-crn",
|
|
3702
|
+
label: "Selecting CRN",
|
|
3703
|
+
progress: 18,
|
|
3770
3704
|
status: "info",
|
|
3771
|
-
|
|
3772
|
-
detail: "Publishing the required Aleph port-forward aggregate from the manifest."
|
|
3773
|
-
});
|
|
3774
|
-
await ensureInstancePortForwards({
|
|
3775
|
-
sender: this.state.wallet.address,
|
|
3776
|
-
instanceItemHash: result.itemHash,
|
|
3777
|
-
manifest: toSharedRootfsManifest(this.state.manifest),
|
|
3778
|
-
signer: personalSign,
|
|
3779
|
-
hasher: sha256Hex,
|
|
3780
|
-
fetch: (url, init) => fetch(url, init),
|
|
3781
|
-
apiHost: this.client.apiHost,
|
|
3782
|
-
sync: true
|
|
3783
|
-
});
|
|
3784
|
-
this.trace("deploy:port-forwards-published", {
|
|
3785
|
-
itemHash: result.itemHash,
|
|
3786
|
-
requiredPortForwards: this.state.manifest.requiredPortForwards
|
|
3705
|
+
detail: `Trying ${candidateCrn.name ?? candidateCrn.hash} (${candidateIndex + 1}/${orderedCrns.length})`
|
|
3787
3706
|
});
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3707
|
+
try {
|
|
3708
|
+
const content = createInstanceContent({
|
|
3709
|
+
address: this.state.wallet.address,
|
|
3710
|
+
name: this.state.instanceName.trim(),
|
|
3711
|
+
sshPublicKey: this.state.sshPublicKey.trim(),
|
|
3712
|
+
rootfsItemHash: this.state.manifest.rootfsItemHash,
|
|
3713
|
+
rootfsSizeMiB: Math.max(
|
|
3714
|
+
this.state.manifest.rootfsSizeMiB,
|
|
3715
|
+
spec.diskMiB
|
|
3716
|
+
),
|
|
3717
|
+
vcpus: spec.vcpus,
|
|
3718
|
+
memoryMiB: spec.memoryMiB,
|
|
3719
|
+
rootfsVersion: this.state.manifest.version,
|
|
3720
|
+
crnHash: candidateCrn.hash
|
|
3721
|
+
});
|
|
3722
|
+
const result = await deployInstance({
|
|
3723
|
+
sender: this.state.wallet.address,
|
|
3724
|
+
content,
|
|
3725
|
+
hasher: sha256Hex,
|
|
3726
|
+
signer: personalSign,
|
|
3727
|
+
fetch: (url, init) => fetch(url, init),
|
|
3728
|
+
apiHost: this.client.apiHost,
|
|
3729
|
+
sync: false,
|
|
3730
|
+
onProgress: (event) => {
|
|
3731
|
+
this.emitProgress(event);
|
|
3732
|
+
}
|
|
3733
|
+
});
|
|
3734
|
+
attemptItemHash = result.itemHash;
|
|
3735
|
+
this.patch({
|
|
3736
|
+
statusText: `Deployment submitted: ${result.itemHash}`,
|
|
3737
|
+
lastDeploymentHash: result.itemHash
|
|
3738
|
+
});
|
|
3739
|
+
this.trace("deploy:broadcasted", {
|
|
3740
|
+
...result,
|
|
3741
|
+
crnHash: candidateCrn.hash,
|
|
3742
|
+
crnName: candidateCrn.name
|
|
3743
|
+
});
|
|
3744
|
+
this.lastRuntimeReadyHash = null;
|
|
3745
|
+
const inspection = await waitForDeploymentResult2(result.itemHash, {
|
|
3746
|
+
rootfsRef: this.state.manifest.rootfsItemHash,
|
|
3747
|
+
apiHost: this.client.apiHost,
|
|
3748
|
+
fetch: (url, init) => fetch(url, init),
|
|
3749
|
+
attempts: UI_DEPLOY_WAIT_ATTEMPTS,
|
|
3750
|
+
delayMs: UI_DEPLOY_WAIT_DELAY_MS,
|
|
3751
|
+
onAttempt: (inspectionResult) => {
|
|
3752
|
+
if (inspectionResult.status === "processed") {
|
|
3753
|
+
this.emitProgress({
|
|
3754
|
+
stage: "deployment-confirmed",
|
|
3755
|
+
label: "Deployment accepted by Aleph",
|
|
3756
|
+
progress: 82,
|
|
3757
|
+
status: "success",
|
|
3758
|
+
itemHash: result.itemHash,
|
|
3759
|
+
detail: "Aleph processed the instance message."
|
|
3760
|
+
});
|
|
3761
|
+
return;
|
|
3762
|
+
}
|
|
3763
|
+
if (inspectionResult.status === "rejected") {
|
|
3764
|
+
this.emitProgress({
|
|
3765
|
+
stage: "deployment-rejected",
|
|
3766
|
+
label: "Deployment rejected",
|
|
3767
|
+
progress: 100,
|
|
3768
|
+
status: "error",
|
|
3769
|
+
itemHash: result.itemHash,
|
|
3770
|
+
detail: inspectionResult.rejectionReason ?? "Aleph rejected the deployment.",
|
|
3771
|
+
error: inspectionResult.rejectionReason ?? "Aleph rejected the deployment."
|
|
3772
|
+
});
|
|
3773
|
+
return;
|
|
3774
|
+
}
|
|
3775
|
+
this.emitProgress({
|
|
3776
|
+
stage: "waiting-for-aleph",
|
|
3777
|
+
label: "Waiting for Aleph",
|
|
3778
|
+
progress: 76,
|
|
3779
|
+
status: "info",
|
|
3780
|
+
itemHash: result.itemHash,
|
|
3781
|
+
detail: "Deployment submitted. Waiting for Aleph to process the instance message."
|
|
3782
|
+
});
|
|
3783
|
+
}
|
|
3784
|
+
});
|
|
3785
|
+
if (inspection.status !== "processed") {
|
|
3786
|
+
throw new Error(
|
|
3787
|
+
inspection.rejectionReason ?? `Deployment ${result.itemHash} stayed ${inspection.status} on Aleph.`
|
|
3788
|
+
);
|
|
3802
3789
|
}
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
this.emitProgress({
|
|
3806
|
-
stage: "deployment-confirmed",
|
|
3807
|
-
label: "Waiting for runtime",
|
|
3808
|
-
progress: 90,
|
|
3809
|
-
status: "warning",
|
|
3810
|
-
itemHash: result.itemHash,
|
|
3811
|
-
detail: "Aleph accepted the deployment. Waiting for runtime networking and mapped ports."
|
|
3812
|
-
});
|
|
3813
|
-
const runtime = await waitForVmRuntime({
|
|
3814
|
-
itemHash: result.itemHash,
|
|
3815
|
-
fetch: (url, init) => fetch(url, init),
|
|
3816
|
-
crnHash: this.state.selectedCrn?.hash,
|
|
3817
|
-
crns: this.state.crns,
|
|
3818
|
-
crnListUrl: this.props.crnListUrl,
|
|
3819
|
-
attempts: UI_RUNTIME_WAIT_ATTEMPTS,
|
|
3820
|
-
delayMs: UI_RUNTIME_WAIT_DELAY_MS,
|
|
3821
|
-
onAttempt: (runtime2) => {
|
|
3822
|
-
if (runtime2.hostIpv4 && Object.keys(runtime2.mappedPorts ?? {}).length > 0) {
|
|
3790
|
+
this.trace("deploy:aleph-processed", inspection);
|
|
3791
|
+
if ((this.state.manifest.requiredPortForwards?.length ?? 0) > 0) {
|
|
3823
3792
|
this.emitProgress({
|
|
3824
|
-
stage: "
|
|
3825
|
-
label: "
|
|
3826
|
-
progress:
|
|
3827
|
-
status: "
|
|
3793
|
+
stage: "refreshing-instances",
|
|
3794
|
+
label: "Publishing port forwards",
|
|
3795
|
+
progress: 86,
|
|
3796
|
+
status: "info",
|
|
3797
|
+
itemHash: result.itemHash,
|
|
3798
|
+
detail: "Publishing the required Aleph port-forward aggregate from the manifest."
|
|
3799
|
+
});
|
|
3800
|
+
await ensureInstancePortForwards({
|
|
3801
|
+
sender: this.state.wallet.address,
|
|
3802
|
+
instanceItemHash: result.itemHash,
|
|
3803
|
+
manifest: toSharedRootfsManifest(this.state.manifest),
|
|
3804
|
+
signer: personalSign,
|
|
3805
|
+
hasher: sha256Hex,
|
|
3806
|
+
fetch: (url, init) => fetch(url, init),
|
|
3807
|
+
apiHost: this.client.apiHost,
|
|
3808
|
+
sync: true
|
|
3809
|
+
});
|
|
3810
|
+
this.trace("deploy:port-forwards-published", {
|
|
3811
|
+
itemHash: result.itemHash,
|
|
3812
|
+
requiredPortForwards: this.state.manifest.requiredPortForwards
|
|
3813
|
+
});
|
|
3814
|
+
}
|
|
3815
|
+
if (candidateCrn.address) {
|
|
3816
|
+
this.trace("deploy:notifying-crn", {
|
|
3817
|
+
itemHash: result.itemHash,
|
|
3818
|
+
crnName: candidateCrn.name,
|
|
3819
|
+
crnHash: candidateCrn.hash,
|
|
3820
|
+
crnUrl: candidateCrn.address
|
|
3821
|
+
});
|
|
3822
|
+
await notifyCrnAllocationWithRetry({
|
|
3823
|
+
crnUrl: candidateCrn.address,
|
|
3828
3824
|
itemHash: result.itemHash,
|
|
3829
|
-
|
|
3825
|
+
fetch: (url, init) => fetch(url, init),
|
|
3826
|
+
onProgress: (event) => {
|
|
3827
|
+
this.emitProgress(event);
|
|
3828
|
+
}
|
|
3830
3829
|
});
|
|
3831
|
-
return;
|
|
3832
3830
|
}
|
|
3833
3831
|
this.emitProgress({
|
|
3834
3832
|
stage: "deployment-confirmed",
|
|
@@ -3836,46 +3834,122 @@ var SponsorRelayController = class {
|
|
|
3836
3834
|
progress: 90,
|
|
3837
3835
|
status: "warning",
|
|
3838
3836
|
itemHash: result.itemHash,
|
|
3839
|
-
detail:
|
|
3837
|
+
detail: "Aleph accepted the deployment. Waiting for runtime networking and mapped ports."
|
|
3838
|
+
});
|
|
3839
|
+
const runtime = await waitForVmRuntime({
|
|
3840
|
+
itemHash: result.itemHash,
|
|
3841
|
+
fetch: (url, init) => fetch(url, init),
|
|
3842
|
+
crnHash: candidateCrn.hash,
|
|
3843
|
+
crns: this.state.crns,
|
|
3844
|
+
crnListUrl: this.props.crnListUrl,
|
|
3845
|
+
attempts: UI_RUNTIME_WAIT_ATTEMPTS,
|
|
3846
|
+
delayMs: UI_RUNTIME_WAIT_DELAY_MS,
|
|
3847
|
+
onAttempt: (runtime2) => {
|
|
3848
|
+
if (runtime2.hostIpv4 && Object.keys(runtime2.mappedPorts ?? {}).length > 0) {
|
|
3849
|
+
this.emitProgress({
|
|
3850
|
+
stage: "completed",
|
|
3851
|
+
label: "Runtime ready",
|
|
3852
|
+
progress: 100,
|
|
3853
|
+
status: "success",
|
|
3854
|
+
itemHash: result.itemHash,
|
|
3855
|
+
detail: "Runtime networking and mapped ports are now available."
|
|
3856
|
+
});
|
|
3857
|
+
return;
|
|
3858
|
+
}
|
|
3859
|
+
this.emitProgress({
|
|
3860
|
+
stage: "deployment-confirmed",
|
|
3861
|
+
label: "Waiting for runtime",
|
|
3862
|
+
progress: 90,
|
|
3863
|
+
status: "warning",
|
|
3864
|
+
itemHash: result.itemHash,
|
|
3865
|
+
detail: runtime2.diagnostics?.reason ?? "Waiting for CRN runtime networking and mapped ports."
|
|
3866
|
+
});
|
|
3867
|
+
}
|
|
3868
|
+
});
|
|
3869
|
+
if (!runtime.hostIpv4 || Object.keys(runtime.mappedPorts ?? {}).length === 0) {
|
|
3870
|
+
throw new Error(
|
|
3871
|
+
runtime.diagnostics?.reason ?? "Deployment was processed, but runtime networking never exposed mapped ports."
|
|
3872
|
+
);
|
|
3873
|
+
}
|
|
3874
|
+
this.trace("deploy:runtime-ready", runtime);
|
|
3875
|
+
this.lastRuntimeReadyHash = result.itemHash;
|
|
3876
|
+
this.rememberRuntimeDetails(result.itemHash, {
|
|
3877
|
+
messageStatus: "processed",
|
|
3878
|
+
allocationSource: runtime.allocation?.source ?? null,
|
|
3879
|
+
crnUrl: runtime.allocation?.crnUrl ?? runtime.execution?.crnUrl ?? null,
|
|
3880
|
+
hostIpv4: runtime.hostIpv4 ?? null,
|
|
3881
|
+
ipv6: runtime.ipv6 ?? null,
|
|
3882
|
+
vmIpv4: runtime.execution?.networking?.ipv4_ip ?? null,
|
|
3883
|
+
webUrl: runtime.webAccessUrl ?? runtime.proxyUrl ?? runtime.execution?.networking?.proxy_url ?? null,
|
|
3884
|
+
sshCommand: runtime.sshCommand ?? null,
|
|
3885
|
+
mappedPorts: runtime.execution != null ? mappedPorts(runtime.execution) : runtimeMappedPorts(runtime.mappedPorts),
|
|
3886
|
+
execution: runtime.execution ?? null,
|
|
3887
|
+
error: null
|
|
3888
|
+
});
|
|
3889
|
+
await this.configureRelayBootstrapRegistration({
|
|
3890
|
+
itemHash: result.itemHash,
|
|
3891
|
+
runtime
|
|
3892
|
+
});
|
|
3893
|
+
this.patch({
|
|
3894
|
+
busy: { deploying: false }
|
|
3895
|
+
});
|
|
3896
|
+
this.emitProgress({
|
|
3897
|
+
stage: "refreshing-instances",
|
|
3898
|
+
label: "Refreshing instances",
|
|
3899
|
+
progress: 96,
|
|
3900
|
+
status: "info",
|
|
3901
|
+
itemHash: result.itemHash,
|
|
3902
|
+
detail: "Reloading deployments and runtime state."
|
|
3840
3903
|
});
|
|
3904
|
+
await this.refresh();
|
|
3905
|
+
return;
|
|
3906
|
+
} catch (error) {
|
|
3907
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
3908
|
+
const attemptLabel = candidateCrn.name ?? candidateCrn.hash;
|
|
3909
|
+
attemptErrors.push(`${attemptLabel}: ${lastError.message}`);
|
|
3910
|
+
this.trace("deploy:crn-attempt-error", {
|
|
3911
|
+
crnHash: candidateCrn.hash,
|
|
3912
|
+
crnName: candidateCrn.name,
|
|
3913
|
+
itemHash: attemptItemHash,
|
|
3914
|
+
error: lastError.message
|
|
3915
|
+
});
|
|
3916
|
+
if (attemptItemHash) {
|
|
3917
|
+
await forgetAlephMessages({
|
|
3918
|
+
sender: this.state.wallet.address,
|
|
3919
|
+
hashes: [attemptItemHash],
|
|
3920
|
+
reason: `Discard failed Sponsor Relay deployment attempt on ${attemptLabel}`,
|
|
3921
|
+
signer: personalSign,
|
|
3922
|
+
hasher: sha256Hex,
|
|
3923
|
+
fetch: (url, init) => fetch(url, init).then(async (response) => ({
|
|
3924
|
+
ok: response.ok,
|
|
3925
|
+
status: response.status,
|
|
3926
|
+
json: async () => await response.json()
|
|
3927
|
+
})),
|
|
3928
|
+
apiHost: this.client.apiHost
|
|
3929
|
+
}).catch((cleanupError) => {
|
|
3930
|
+
this.trace("deploy:cleanup-error", {
|
|
3931
|
+
itemHash: attemptItemHash,
|
|
3932
|
+
error: cleanupError instanceof Error ? cleanupError.message : String(cleanupError)
|
|
3933
|
+
});
|
|
3934
|
+
});
|
|
3935
|
+
}
|
|
3936
|
+
if (candidateIndex < orderedCrns.length - 1) {
|
|
3937
|
+
this.emitProgress({
|
|
3938
|
+
stage: "selecting-crn",
|
|
3939
|
+
label: "Retrying another CRN",
|
|
3940
|
+
progress: 20,
|
|
3941
|
+
status: "warning",
|
|
3942
|
+
itemHash: attemptItemHash,
|
|
3943
|
+
detail: `${attemptLabel} failed: ${lastError.message}`,
|
|
3944
|
+
error: lastError.message
|
|
3945
|
+
});
|
|
3946
|
+
continue;
|
|
3947
|
+
}
|
|
3841
3948
|
}
|
|
3842
|
-
});
|
|
3843
|
-
if (!runtime.hostIpv4 || Object.keys(runtime.mappedPorts ?? {}).length === 0) {
|
|
3844
|
-
throw new Error(
|
|
3845
|
-
runtime.diagnostics?.reason ?? "Deployment was processed, but runtime networking never exposed mapped ports."
|
|
3846
|
-
);
|
|
3847
3949
|
}
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
messageStatus: "processed",
|
|
3852
|
-
allocationSource: runtime.allocation?.source ?? null,
|
|
3853
|
-
crnUrl: runtime.allocation?.crnUrl ?? runtime.execution?.crnUrl ?? null,
|
|
3854
|
-
hostIpv4: runtime.hostIpv4 ?? null,
|
|
3855
|
-
ipv6: runtime.ipv6 ?? null,
|
|
3856
|
-
vmIpv4: runtime.execution?.networking?.ipv4_ip ?? null,
|
|
3857
|
-
webUrl: runtime.webAccessUrl ?? runtime.proxyUrl ?? runtime.execution?.networking?.proxy_url ?? null,
|
|
3858
|
-
sshCommand: runtime.sshCommand ?? null,
|
|
3859
|
-
mappedPorts: runtime.execution != null ? mappedPorts(runtime.execution) : runtimeMappedPorts(runtime.mappedPorts),
|
|
3860
|
-
execution: runtime.execution ?? null,
|
|
3861
|
-
error: null
|
|
3862
|
-
});
|
|
3863
|
-
await this.configureRelayBootstrapRegistration({
|
|
3864
|
-
itemHash: result.itemHash,
|
|
3865
|
-
runtime
|
|
3866
|
-
});
|
|
3867
|
-
this.patch({
|
|
3868
|
-
busy: { deploying: false }
|
|
3869
|
-
});
|
|
3870
|
-
this.emitProgress({
|
|
3871
|
-
stage: "refreshing-instances",
|
|
3872
|
-
label: "Refreshing instances",
|
|
3873
|
-
progress: 96,
|
|
3874
|
-
status: "info",
|
|
3875
|
-
itemHash: result.itemHash,
|
|
3876
|
-
detail: "Reloading deployments and runtime state."
|
|
3877
|
-
});
|
|
3878
|
-
await this.refresh();
|
|
3950
|
+
throw new Error(
|
|
3951
|
+
attemptErrors.length > 0 ? `All compatible CRNs failed. ${attemptErrors.join(" | ")}` : lastError?.message ?? "All compatible CRNs failed."
|
|
3952
|
+
);
|
|
3879
3953
|
} catch (error) {
|
|
3880
3954
|
this.trace("deploy:error", error);
|
|
3881
3955
|
this.patch({
|
package/shared/index.js
CHANGED
|
@@ -3645,158 +3645,156 @@ var SponsorRelayController = class {
|
|
|
3645
3645
|
this.state.pricingSummary.pricing,
|
|
3646
3646
|
this.state.pricingSummary.tier
|
|
3647
3647
|
);
|
|
3648
|
-
this.
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
});
|
|
3655
|
-
const content = createInstanceContent({
|
|
3656
|
-
address: this.state.wallet.address,
|
|
3657
|
-
name: this.state.instanceName.trim(),
|
|
3658
|
-
sshPublicKey: this.state.sshPublicKey.trim(),
|
|
3659
|
-
rootfsItemHash: this.state.manifest.rootfsItemHash,
|
|
3660
|
-
rootfsSizeMiB: Math.max(
|
|
3661
|
-
this.state.manifest.rootfsSizeMiB,
|
|
3662
|
-
spec.diskMiB
|
|
3663
|
-
),
|
|
3664
|
-
vcpus: spec.vcpus,
|
|
3665
|
-
memoryMiB: spec.memoryMiB,
|
|
3666
|
-
rootfsVersion: this.state.manifest.version,
|
|
3667
|
-
crnHash: this.state.selectedCrn?.hash
|
|
3668
|
-
});
|
|
3669
|
-
const result = await deployInstance({
|
|
3670
|
-
sender: this.state.wallet.address,
|
|
3671
|
-
content,
|
|
3672
|
-
hasher: sha256Hex,
|
|
3673
|
-
signer: personalSign,
|
|
3674
|
-
fetch: (url, init) => fetch(url, init),
|
|
3675
|
-
apiHost: this.client.apiHost,
|
|
3676
|
-
sync: false,
|
|
3677
|
-
onProgress: (event) => {
|
|
3678
|
-
this.emitProgress(event);
|
|
3679
|
-
}
|
|
3680
|
-
});
|
|
3681
|
-
this.patch({
|
|
3682
|
-
statusText: `Deployment submitted: ${result.itemHash}`,
|
|
3683
|
-
lastDeploymentHash: result.itemHash
|
|
3684
|
-
});
|
|
3685
|
-
this.trace("deploy:broadcasted", result);
|
|
3686
|
-
this.lastRuntimeReadyHash = null;
|
|
3687
|
-
const inspection = await waitForDeploymentResult2(result.itemHash, {
|
|
3688
|
-
rootfsRef: this.state.manifest.rootfsItemHash,
|
|
3689
|
-
apiHost: this.client.apiHost,
|
|
3690
|
-
fetch: (url, init) => fetch(url, init),
|
|
3691
|
-
attempts: UI_DEPLOY_WAIT_ATTEMPTS,
|
|
3692
|
-
delayMs: UI_DEPLOY_WAIT_DELAY_MS,
|
|
3693
|
-
onAttempt: (inspectionResult) => {
|
|
3694
|
-
if (inspectionResult.status === "processed") {
|
|
3695
|
-
this.emitProgress({
|
|
3696
|
-
stage: "deployment-confirmed",
|
|
3697
|
-
label: "Deployment accepted by Aleph",
|
|
3698
|
-
progress: 82,
|
|
3699
|
-
status: "success",
|
|
3700
|
-
itemHash: result.itemHash,
|
|
3701
|
-
detail: "Aleph processed the instance message."
|
|
3702
|
-
});
|
|
3703
|
-
return;
|
|
3704
|
-
}
|
|
3705
|
-
if (inspectionResult.status === "rejected") {
|
|
3706
|
-
this.emitProgress({
|
|
3707
|
-
stage: "deployment-rejected",
|
|
3708
|
-
label: "Deployment rejected",
|
|
3709
|
-
progress: 100,
|
|
3710
|
-
status: "error",
|
|
3711
|
-
itemHash: result.itemHash,
|
|
3712
|
-
detail: inspectionResult.rejectionReason ?? "Aleph rejected the deployment.",
|
|
3713
|
-
error: inspectionResult.rejectionReason ?? "Aleph rejected the deployment."
|
|
3714
|
-
});
|
|
3715
|
-
return;
|
|
3716
|
-
}
|
|
3717
|
-
this.emitProgress({
|
|
3718
|
-
stage: "waiting-for-aleph",
|
|
3719
|
-
label: "Waiting for Aleph",
|
|
3720
|
-
progress: 76,
|
|
3721
|
-
status: "info",
|
|
3722
|
-
itemHash: result.itemHash,
|
|
3723
|
-
detail: "Deployment submitted. Waiting for Aleph to process the instance message."
|
|
3724
|
-
});
|
|
3648
|
+
const compatibleCrns2 = compatibleCrnsForTier(this.state.crns, {
|
|
3649
|
+
...this.state,
|
|
3650
|
+
pricingSummary: {
|
|
3651
|
+
...this.state.pricingSummary,
|
|
3652
|
+
pricing: this.state.pricingSummary.pricing,
|
|
3653
|
+
tier: this.state.pricingSummary.tier
|
|
3725
3654
|
}
|
|
3726
3655
|
});
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
)
|
|
3656
|
+
const preferredCrnHash = this.state.selectedCrn?.hash ?? null;
|
|
3657
|
+
const orderedCrns = [
|
|
3658
|
+
...compatibleCrns2.filter((crn) => crn.hash === preferredCrnHash),
|
|
3659
|
+
...compatibleCrns2.filter((crn) => crn.hash !== preferredCrnHash)
|
|
3660
|
+
].slice(0, 5);
|
|
3661
|
+
if (orderedCrns.length === 0) {
|
|
3662
|
+
throw new Error("No compatible CRN is currently available for this tier.");
|
|
3731
3663
|
}
|
|
3732
|
-
|
|
3733
|
-
|
|
3664
|
+
const attemptErrors = [];
|
|
3665
|
+
let lastError = null;
|
|
3666
|
+
for (const [candidateIndex, candidateCrn] of orderedCrns.entries()) {
|
|
3667
|
+
let attemptItemHash = null;
|
|
3734
3668
|
this.emitProgress({
|
|
3735
|
-
stage: "
|
|
3736
|
-
label: "
|
|
3737
|
-
progress:
|
|
3669
|
+
stage: "selecting-crn",
|
|
3670
|
+
label: "Selecting CRN",
|
|
3671
|
+
progress: 18,
|
|
3738
3672
|
status: "info",
|
|
3739
|
-
|
|
3740
|
-
detail: "Publishing the required Aleph port-forward aggregate from the manifest."
|
|
3741
|
-
});
|
|
3742
|
-
await ensureInstancePortForwards({
|
|
3743
|
-
sender: this.state.wallet.address,
|
|
3744
|
-
instanceItemHash: result.itemHash,
|
|
3745
|
-
manifest: toSharedRootfsManifest(this.state.manifest),
|
|
3746
|
-
signer: personalSign,
|
|
3747
|
-
hasher: sha256Hex,
|
|
3748
|
-
fetch: (url, init) => fetch(url, init),
|
|
3749
|
-
apiHost: this.client.apiHost,
|
|
3750
|
-
sync: true
|
|
3751
|
-
});
|
|
3752
|
-
this.trace("deploy:port-forwards-published", {
|
|
3753
|
-
itemHash: result.itemHash,
|
|
3754
|
-
requiredPortForwards: this.state.manifest.requiredPortForwards
|
|
3673
|
+
detail: `Trying ${candidateCrn.name ?? candidateCrn.hash} (${candidateIndex + 1}/${orderedCrns.length})`
|
|
3755
3674
|
});
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
3675
|
+
try {
|
|
3676
|
+
const content = createInstanceContent({
|
|
3677
|
+
address: this.state.wallet.address,
|
|
3678
|
+
name: this.state.instanceName.trim(),
|
|
3679
|
+
sshPublicKey: this.state.sshPublicKey.trim(),
|
|
3680
|
+
rootfsItemHash: this.state.manifest.rootfsItemHash,
|
|
3681
|
+
rootfsSizeMiB: Math.max(
|
|
3682
|
+
this.state.manifest.rootfsSizeMiB,
|
|
3683
|
+
spec.diskMiB
|
|
3684
|
+
),
|
|
3685
|
+
vcpus: spec.vcpus,
|
|
3686
|
+
memoryMiB: spec.memoryMiB,
|
|
3687
|
+
rootfsVersion: this.state.manifest.version,
|
|
3688
|
+
crnHash: candidateCrn.hash
|
|
3689
|
+
});
|
|
3690
|
+
const result = await deployInstance({
|
|
3691
|
+
sender: this.state.wallet.address,
|
|
3692
|
+
content,
|
|
3693
|
+
hasher: sha256Hex,
|
|
3694
|
+
signer: personalSign,
|
|
3695
|
+
fetch: (url, init) => fetch(url, init),
|
|
3696
|
+
apiHost: this.client.apiHost,
|
|
3697
|
+
sync: false,
|
|
3698
|
+
onProgress: (event) => {
|
|
3699
|
+
this.emitProgress(event);
|
|
3700
|
+
}
|
|
3701
|
+
});
|
|
3702
|
+
attemptItemHash = result.itemHash;
|
|
3703
|
+
this.patch({
|
|
3704
|
+
statusText: `Deployment submitted: ${result.itemHash}`,
|
|
3705
|
+
lastDeploymentHash: result.itemHash
|
|
3706
|
+
});
|
|
3707
|
+
this.trace("deploy:broadcasted", {
|
|
3708
|
+
...result,
|
|
3709
|
+
crnHash: candidateCrn.hash,
|
|
3710
|
+
crnName: candidateCrn.name
|
|
3711
|
+
});
|
|
3712
|
+
this.lastRuntimeReadyHash = null;
|
|
3713
|
+
const inspection = await waitForDeploymentResult2(result.itemHash, {
|
|
3714
|
+
rootfsRef: this.state.manifest.rootfsItemHash,
|
|
3715
|
+
apiHost: this.client.apiHost,
|
|
3716
|
+
fetch: (url, init) => fetch(url, init),
|
|
3717
|
+
attempts: UI_DEPLOY_WAIT_ATTEMPTS,
|
|
3718
|
+
delayMs: UI_DEPLOY_WAIT_DELAY_MS,
|
|
3719
|
+
onAttempt: (inspectionResult) => {
|
|
3720
|
+
if (inspectionResult.status === "processed") {
|
|
3721
|
+
this.emitProgress({
|
|
3722
|
+
stage: "deployment-confirmed",
|
|
3723
|
+
label: "Deployment accepted by Aleph",
|
|
3724
|
+
progress: 82,
|
|
3725
|
+
status: "success",
|
|
3726
|
+
itemHash: result.itemHash,
|
|
3727
|
+
detail: "Aleph processed the instance message."
|
|
3728
|
+
});
|
|
3729
|
+
return;
|
|
3730
|
+
}
|
|
3731
|
+
if (inspectionResult.status === "rejected") {
|
|
3732
|
+
this.emitProgress({
|
|
3733
|
+
stage: "deployment-rejected",
|
|
3734
|
+
label: "Deployment rejected",
|
|
3735
|
+
progress: 100,
|
|
3736
|
+
status: "error",
|
|
3737
|
+
itemHash: result.itemHash,
|
|
3738
|
+
detail: inspectionResult.rejectionReason ?? "Aleph rejected the deployment.",
|
|
3739
|
+
error: inspectionResult.rejectionReason ?? "Aleph rejected the deployment."
|
|
3740
|
+
});
|
|
3741
|
+
return;
|
|
3742
|
+
}
|
|
3743
|
+
this.emitProgress({
|
|
3744
|
+
stage: "waiting-for-aleph",
|
|
3745
|
+
label: "Waiting for Aleph",
|
|
3746
|
+
progress: 76,
|
|
3747
|
+
status: "info",
|
|
3748
|
+
itemHash: result.itemHash,
|
|
3749
|
+
detail: "Deployment submitted. Waiting for Aleph to process the instance message."
|
|
3750
|
+
});
|
|
3751
|
+
}
|
|
3752
|
+
});
|
|
3753
|
+
if (inspection.status !== "processed") {
|
|
3754
|
+
throw new Error(
|
|
3755
|
+
inspection.rejectionReason ?? `Deployment ${result.itemHash} stayed ${inspection.status} on Aleph.`
|
|
3756
|
+
);
|
|
3770
3757
|
}
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
this.emitProgress({
|
|
3774
|
-
stage: "deployment-confirmed",
|
|
3775
|
-
label: "Waiting for runtime",
|
|
3776
|
-
progress: 90,
|
|
3777
|
-
status: "warning",
|
|
3778
|
-
itemHash: result.itemHash,
|
|
3779
|
-
detail: "Aleph accepted the deployment. Waiting for runtime networking and mapped ports."
|
|
3780
|
-
});
|
|
3781
|
-
const runtime = await waitForVmRuntime({
|
|
3782
|
-
itemHash: result.itemHash,
|
|
3783
|
-
fetch: (url, init) => fetch(url, init),
|
|
3784
|
-
crnHash: this.state.selectedCrn?.hash,
|
|
3785
|
-
crns: this.state.crns,
|
|
3786
|
-
crnListUrl: this.props.crnListUrl,
|
|
3787
|
-
attempts: UI_RUNTIME_WAIT_ATTEMPTS,
|
|
3788
|
-
delayMs: UI_RUNTIME_WAIT_DELAY_MS,
|
|
3789
|
-
onAttempt: (runtime2) => {
|
|
3790
|
-
if (runtime2.hostIpv4 && Object.keys(runtime2.mappedPorts ?? {}).length > 0) {
|
|
3758
|
+
this.trace("deploy:aleph-processed", inspection);
|
|
3759
|
+
if ((this.state.manifest.requiredPortForwards?.length ?? 0) > 0) {
|
|
3791
3760
|
this.emitProgress({
|
|
3792
|
-
stage: "
|
|
3793
|
-
label: "
|
|
3794
|
-
progress:
|
|
3795
|
-
status: "
|
|
3761
|
+
stage: "refreshing-instances",
|
|
3762
|
+
label: "Publishing port forwards",
|
|
3763
|
+
progress: 86,
|
|
3764
|
+
status: "info",
|
|
3765
|
+
itemHash: result.itemHash,
|
|
3766
|
+
detail: "Publishing the required Aleph port-forward aggregate from the manifest."
|
|
3767
|
+
});
|
|
3768
|
+
await ensureInstancePortForwards({
|
|
3769
|
+
sender: this.state.wallet.address,
|
|
3770
|
+
instanceItemHash: result.itemHash,
|
|
3771
|
+
manifest: toSharedRootfsManifest(this.state.manifest),
|
|
3772
|
+
signer: personalSign,
|
|
3773
|
+
hasher: sha256Hex,
|
|
3774
|
+
fetch: (url, init) => fetch(url, init),
|
|
3775
|
+
apiHost: this.client.apiHost,
|
|
3776
|
+
sync: true
|
|
3777
|
+
});
|
|
3778
|
+
this.trace("deploy:port-forwards-published", {
|
|
3779
|
+
itemHash: result.itemHash,
|
|
3780
|
+
requiredPortForwards: this.state.manifest.requiredPortForwards
|
|
3781
|
+
});
|
|
3782
|
+
}
|
|
3783
|
+
if (candidateCrn.address) {
|
|
3784
|
+
this.trace("deploy:notifying-crn", {
|
|
3785
|
+
itemHash: result.itemHash,
|
|
3786
|
+
crnName: candidateCrn.name,
|
|
3787
|
+
crnHash: candidateCrn.hash,
|
|
3788
|
+
crnUrl: candidateCrn.address
|
|
3789
|
+
});
|
|
3790
|
+
await notifyCrnAllocationWithRetry({
|
|
3791
|
+
crnUrl: candidateCrn.address,
|
|
3796
3792
|
itemHash: result.itemHash,
|
|
3797
|
-
|
|
3793
|
+
fetch: (url, init) => fetch(url, init),
|
|
3794
|
+
onProgress: (event) => {
|
|
3795
|
+
this.emitProgress(event);
|
|
3796
|
+
}
|
|
3798
3797
|
});
|
|
3799
|
-
return;
|
|
3800
3798
|
}
|
|
3801
3799
|
this.emitProgress({
|
|
3802
3800
|
stage: "deployment-confirmed",
|
|
@@ -3804,46 +3802,122 @@ var SponsorRelayController = class {
|
|
|
3804
3802
|
progress: 90,
|
|
3805
3803
|
status: "warning",
|
|
3806
3804
|
itemHash: result.itemHash,
|
|
3807
|
-
detail:
|
|
3805
|
+
detail: "Aleph accepted the deployment. Waiting for runtime networking and mapped ports."
|
|
3806
|
+
});
|
|
3807
|
+
const runtime = await waitForVmRuntime({
|
|
3808
|
+
itemHash: result.itemHash,
|
|
3809
|
+
fetch: (url, init) => fetch(url, init),
|
|
3810
|
+
crnHash: candidateCrn.hash,
|
|
3811
|
+
crns: this.state.crns,
|
|
3812
|
+
crnListUrl: this.props.crnListUrl,
|
|
3813
|
+
attempts: UI_RUNTIME_WAIT_ATTEMPTS,
|
|
3814
|
+
delayMs: UI_RUNTIME_WAIT_DELAY_MS,
|
|
3815
|
+
onAttempt: (runtime2) => {
|
|
3816
|
+
if (runtime2.hostIpv4 && Object.keys(runtime2.mappedPorts ?? {}).length > 0) {
|
|
3817
|
+
this.emitProgress({
|
|
3818
|
+
stage: "completed",
|
|
3819
|
+
label: "Runtime ready",
|
|
3820
|
+
progress: 100,
|
|
3821
|
+
status: "success",
|
|
3822
|
+
itemHash: result.itemHash,
|
|
3823
|
+
detail: "Runtime networking and mapped ports are now available."
|
|
3824
|
+
});
|
|
3825
|
+
return;
|
|
3826
|
+
}
|
|
3827
|
+
this.emitProgress({
|
|
3828
|
+
stage: "deployment-confirmed",
|
|
3829
|
+
label: "Waiting for runtime",
|
|
3830
|
+
progress: 90,
|
|
3831
|
+
status: "warning",
|
|
3832
|
+
itemHash: result.itemHash,
|
|
3833
|
+
detail: runtime2.diagnostics?.reason ?? "Waiting for CRN runtime networking and mapped ports."
|
|
3834
|
+
});
|
|
3835
|
+
}
|
|
3836
|
+
});
|
|
3837
|
+
if (!runtime.hostIpv4 || Object.keys(runtime.mappedPorts ?? {}).length === 0) {
|
|
3838
|
+
throw new Error(
|
|
3839
|
+
runtime.diagnostics?.reason ?? "Deployment was processed, but runtime networking never exposed mapped ports."
|
|
3840
|
+
);
|
|
3841
|
+
}
|
|
3842
|
+
this.trace("deploy:runtime-ready", runtime);
|
|
3843
|
+
this.lastRuntimeReadyHash = result.itemHash;
|
|
3844
|
+
this.rememberRuntimeDetails(result.itemHash, {
|
|
3845
|
+
messageStatus: "processed",
|
|
3846
|
+
allocationSource: runtime.allocation?.source ?? null,
|
|
3847
|
+
crnUrl: runtime.allocation?.crnUrl ?? runtime.execution?.crnUrl ?? null,
|
|
3848
|
+
hostIpv4: runtime.hostIpv4 ?? null,
|
|
3849
|
+
ipv6: runtime.ipv6 ?? null,
|
|
3850
|
+
vmIpv4: runtime.execution?.networking?.ipv4_ip ?? null,
|
|
3851
|
+
webUrl: runtime.webAccessUrl ?? runtime.proxyUrl ?? runtime.execution?.networking?.proxy_url ?? null,
|
|
3852
|
+
sshCommand: runtime.sshCommand ?? null,
|
|
3853
|
+
mappedPorts: runtime.execution != null ? mappedPorts(runtime.execution) : runtimeMappedPorts(runtime.mappedPorts),
|
|
3854
|
+
execution: runtime.execution ?? null,
|
|
3855
|
+
error: null
|
|
3856
|
+
});
|
|
3857
|
+
await this.configureRelayBootstrapRegistration({
|
|
3858
|
+
itemHash: result.itemHash,
|
|
3859
|
+
runtime
|
|
3860
|
+
});
|
|
3861
|
+
this.patch({
|
|
3862
|
+
busy: { deploying: false }
|
|
3863
|
+
});
|
|
3864
|
+
this.emitProgress({
|
|
3865
|
+
stage: "refreshing-instances",
|
|
3866
|
+
label: "Refreshing instances",
|
|
3867
|
+
progress: 96,
|
|
3868
|
+
status: "info",
|
|
3869
|
+
itemHash: result.itemHash,
|
|
3870
|
+
detail: "Reloading deployments and runtime state."
|
|
3808
3871
|
});
|
|
3872
|
+
await this.refresh();
|
|
3873
|
+
return;
|
|
3874
|
+
} catch (error) {
|
|
3875
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
3876
|
+
const attemptLabel = candidateCrn.name ?? candidateCrn.hash;
|
|
3877
|
+
attemptErrors.push(`${attemptLabel}: ${lastError.message}`);
|
|
3878
|
+
this.trace("deploy:crn-attempt-error", {
|
|
3879
|
+
crnHash: candidateCrn.hash,
|
|
3880
|
+
crnName: candidateCrn.name,
|
|
3881
|
+
itemHash: attemptItemHash,
|
|
3882
|
+
error: lastError.message
|
|
3883
|
+
});
|
|
3884
|
+
if (attemptItemHash) {
|
|
3885
|
+
await forgetAlephMessages({
|
|
3886
|
+
sender: this.state.wallet.address,
|
|
3887
|
+
hashes: [attemptItemHash],
|
|
3888
|
+
reason: `Discard failed Sponsor Relay deployment attempt on ${attemptLabel}`,
|
|
3889
|
+
signer: personalSign,
|
|
3890
|
+
hasher: sha256Hex,
|
|
3891
|
+
fetch: (url, init) => fetch(url, init).then(async (response) => ({
|
|
3892
|
+
ok: response.ok,
|
|
3893
|
+
status: response.status,
|
|
3894
|
+
json: async () => await response.json()
|
|
3895
|
+
})),
|
|
3896
|
+
apiHost: this.client.apiHost
|
|
3897
|
+
}).catch((cleanupError) => {
|
|
3898
|
+
this.trace("deploy:cleanup-error", {
|
|
3899
|
+
itemHash: attemptItemHash,
|
|
3900
|
+
error: cleanupError instanceof Error ? cleanupError.message : String(cleanupError)
|
|
3901
|
+
});
|
|
3902
|
+
});
|
|
3903
|
+
}
|
|
3904
|
+
if (candidateIndex < orderedCrns.length - 1) {
|
|
3905
|
+
this.emitProgress({
|
|
3906
|
+
stage: "selecting-crn",
|
|
3907
|
+
label: "Retrying another CRN",
|
|
3908
|
+
progress: 20,
|
|
3909
|
+
status: "warning",
|
|
3910
|
+
itemHash: attemptItemHash,
|
|
3911
|
+
detail: `${attemptLabel} failed: ${lastError.message}`,
|
|
3912
|
+
error: lastError.message
|
|
3913
|
+
});
|
|
3914
|
+
continue;
|
|
3915
|
+
}
|
|
3809
3916
|
}
|
|
3810
|
-
});
|
|
3811
|
-
if (!runtime.hostIpv4 || Object.keys(runtime.mappedPorts ?? {}).length === 0) {
|
|
3812
|
-
throw new Error(
|
|
3813
|
-
runtime.diagnostics?.reason ?? "Deployment was processed, but runtime networking never exposed mapped ports."
|
|
3814
|
-
);
|
|
3815
3917
|
}
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
messageStatus: "processed",
|
|
3820
|
-
allocationSource: runtime.allocation?.source ?? null,
|
|
3821
|
-
crnUrl: runtime.allocation?.crnUrl ?? runtime.execution?.crnUrl ?? null,
|
|
3822
|
-
hostIpv4: runtime.hostIpv4 ?? null,
|
|
3823
|
-
ipv6: runtime.ipv6 ?? null,
|
|
3824
|
-
vmIpv4: runtime.execution?.networking?.ipv4_ip ?? null,
|
|
3825
|
-
webUrl: runtime.webAccessUrl ?? runtime.proxyUrl ?? runtime.execution?.networking?.proxy_url ?? null,
|
|
3826
|
-
sshCommand: runtime.sshCommand ?? null,
|
|
3827
|
-
mappedPorts: runtime.execution != null ? mappedPorts(runtime.execution) : runtimeMappedPorts(runtime.mappedPorts),
|
|
3828
|
-
execution: runtime.execution ?? null,
|
|
3829
|
-
error: null
|
|
3830
|
-
});
|
|
3831
|
-
await this.configureRelayBootstrapRegistration({
|
|
3832
|
-
itemHash: result.itemHash,
|
|
3833
|
-
runtime
|
|
3834
|
-
});
|
|
3835
|
-
this.patch({
|
|
3836
|
-
busy: { deploying: false }
|
|
3837
|
-
});
|
|
3838
|
-
this.emitProgress({
|
|
3839
|
-
stage: "refreshing-instances",
|
|
3840
|
-
label: "Refreshing instances",
|
|
3841
|
-
progress: 96,
|
|
3842
|
-
status: "info",
|
|
3843
|
-
itemHash: result.itemHash,
|
|
3844
|
-
detail: "Reloading deployments and runtime state."
|
|
3845
|
-
});
|
|
3846
|
-
await this.refresh();
|
|
3918
|
+
throw new Error(
|
|
3919
|
+
attemptErrors.length > 0 ? `All compatible CRNs failed. ${attemptErrors.join(" | ")}` : lastError?.message ?? "All compatible CRNs failed."
|
|
3920
|
+
);
|
|
3847
3921
|
} catch (error) {
|
|
3848
3922
|
this.trace("deploy:error", error);
|
|
3849
3923
|
this.patch({
|