@le-space/ui 0.4.3 → 0.4.4
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 +133 -6
- package/shared/index.d.ts +1 -1
- package/shared/index.js +132 -6
- package/svelte/SponsorRelayFab.svelte +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@le-space/ui",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.4",
|
|
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.4.
|
|
40
|
-
"@le-space/core": "0.4.
|
|
39
|
+
"@le-space/browser": "0.4.4",
|
|
40
|
+
"@le-space/core": "0.4.4",
|
|
41
41
|
"viem": "^2.38.5"
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|
package/react/index.js
CHANGED
|
@@ -28,7 +28,7 @@ var RECENT_INSTANCE_RUNTIME_GRACE_MS = 10 * 60 * 1e3;
|
|
|
28
28
|
var DEPLOYMENT_PENDING_WARNING_MS = 3 * 60 * 1e3;
|
|
29
29
|
|
|
30
30
|
// src/shared/package-version.ts
|
|
31
|
-
var UI_PACKAGE_VERSION = "0.4.
|
|
31
|
+
var UI_PACKAGE_VERSION = "0.4.4";
|
|
32
32
|
|
|
33
33
|
// src/shared/format.ts
|
|
34
34
|
function shortHash(value, head = 8, tail = 6) {
|
|
@@ -3201,7 +3201,7 @@ function rootfsHealth(args) {
|
|
|
3201
3201
|
return {
|
|
3202
3202
|
tone: "error",
|
|
3203
3203
|
label: "not found on Aleph",
|
|
3204
|
-
detail: "The
|
|
3204
|
+
detail: "The manifest points to a rootfs STORE message that Aleph cannot find. Check that the manifest URL is correct and that the referenced rootfs was not forgotten."
|
|
3205
3205
|
};
|
|
3206
3206
|
}
|
|
3207
3207
|
if (!args.resolution) {
|
|
@@ -3234,8 +3234,8 @@ function rootfsHealth(args) {
|
|
|
3234
3234
|
}
|
|
3235
3235
|
return {
|
|
3236
3236
|
tone: "error",
|
|
3237
|
-
label: "not deployable",
|
|
3238
|
-
detail: args.resolution.rejectionReason ?? "Aleph rejected the rootfs reference."
|
|
3237
|
+
label: "manifest rootfs not deployable",
|
|
3238
|
+
detail: args.resolution.rejectionReason ?? (args.resolution.messageType === "STORE" ? "This manifest points to a rootfs STORE message that exists but is not deployable anymore, for example because it was forgotten or replaced. Double-check the manifest URL." : "Aleph rejected the rootfs reference. Double-check that the manifest URL points to the intended current rootfs.")
|
|
3239
3239
|
};
|
|
3240
3240
|
}
|
|
3241
3241
|
async function resolveManifest(args) {
|
|
@@ -3795,6 +3795,16 @@ var SponsorRelayController = class {
|
|
|
3795
3795
|
});
|
|
3796
3796
|
}
|
|
3797
3797
|
if (!relayMetadata) {
|
|
3798
|
+
await this.refresh().catch(() => void 0);
|
|
3799
|
+
const confirmedAfterRefresh = this.state.bootstrapRegistrations.some(
|
|
3800
|
+
(entry) => entry.instanceItemHash === args.itemHash && entry.confirmed
|
|
3801
|
+
);
|
|
3802
|
+
if (confirmedAfterRefresh) {
|
|
3803
|
+
this.trace("deploy:relay-metadata-recovered-from-refresh", {
|
|
3804
|
+
itemHash: args.itemHash
|
|
3805
|
+
});
|
|
3806
|
+
return;
|
|
3807
|
+
}
|
|
3798
3808
|
throw new Error("Relay metadata did not include a peer ID and public multiaddrs.");
|
|
3799
3809
|
}
|
|
3800
3810
|
const { peerId } = relayMetadata;
|
|
@@ -4071,6 +4081,20 @@ var SponsorRelayController = class {
|
|
|
4071
4081
|
});
|
|
4072
4082
|
return;
|
|
4073
4083
|
}
|
|
4084
|
+
const hasConfirmedBootstrapRegistration = this.state.bootstrapRegistrations.some(
|
|
4085
|
+
(entry) => entry.instanceItemHash === itemHash && entry.confirmed
|
|
4086
|
+
);
|
|
4087
|
+
if (hasConfirmedBootstrapRegistration) {
|
|
4088
|
+
this.emitProgress({
|
|
4089
|
+
stage: "completed",
|
|
4090
|
+
label: "Relay ready",
|
|
4091
|
+
progress: 100,
|
|
4092
|
+
status: "success",
|
|
4093
|
+
itemHash,
|
|
4094
|
+
detail: "Runtime networking is available and the relay bootstrap registration is confirmed on Aleph."
|
|
4095
|
+
});
|
|
4096
|
+
return;
|
|
4097
|
+
}
|
|
4074
4098
|
this.emitProgress({
|
|
4075
4099
|
stage: "deployment-confirmed",
|
|
4076
4100
|
label: "Runtime ready",
|
|
@@ -4467,9 +4491,9 @@ var SponsorRelayController = class {
|
|
|
4467
4491
|
this.patch({ errorText: "Connect MetaMask before deploying." });
|
|
4468
4492
|
return;
|
|
4469
4493
|
}
|
|
4470
|
-
if (!this.state.manifest ||
|
|
4494
|
+
if (!this.state.manifest || this.state.rootfsHealth.tone !== "ok" || !this.state.pricingSummary.pricing || !this.state.pricingSummary.tier) {
|
|
4471
4495
|
this.patch({
|
|
4472
|
-
errorText: "Manifest, rootfs, and pricing must be ready before deploying."
|
|
4496
|
+
errorText: this.state.rootfsHealth.tone === "error" ? `Cannot deploy: ${this.state.rootfsHealth.detail ?? this.state.rootfsHealth.label}` : "Manifest, rootfs, and pricing must be ready before deploying."
|
|
4473
4497
|
});
|
|
4474
4498
|
return;
|
|
4475
4499
|
}
|
|
@@ -4511,6 +4535,7 @@ var SponsorRelayController = class {
|
|
|
4511
4535
|
for (const [candidateIndex, candidateCrn] of orderedCrns.entries()) {
|
|
4512
4536
|
let attemptItemHash = null;
|
|
4513
4537
|
let attemptDeploymentToken = null;
|
|
4538
|
+
let attemptProfile = null;
|
|
4514
4539
|
const crnAttemptLabel = `CRN ${candidateIndex + 1}/${orderedCrns.length}`;
|
|
4515
4540
|
const crnDisplayName = candidateCrn.name ?? candidateCrn.hash;
|
|
4516
4541
|
this.emitProgress({
|
|
@@ -4522,6 +4547,7 @@ var SponsorRelayController = class {
|
|
|
4522
4547
|
});
|
|
4523
4548
|
try {
|
|
4524
4549
|
const profile = relayProfileForManifest(this.state.manifest);
|
|
4550
|
+
attemptProfile = profile;
|
|
4525
4551
|
const sshPublicKey = profile === "uc-go-peer" ? appendDeploymentTokenToSshPublicKey(
|
|
4526
4552
|
this.state.sshPublicKey.trim(),
|
|
4527
4553
|
this.state.wallet.address,
|
|
@@ -4757,6 +4783,106 @@ var SponsorRelayController = class {
|
|
|
4757
4783
|
itemHash: attemptItemHash,
|
|
4758
4784
|
error: lastError.message
|
|
4759
4785
|
});
|
|
4786
|
+
if (attemptItemHash && attemptDeploymentToken && attemptProfile && !failedDueToInvalidIpv6) {
|
|
4787
|
+
try {
|
|
4788
|
+
const latestRuntime = await fetchVmRuntime({
|
|
4789
|
+
itemHash: attemptItemHash,
|
|
4790
|
+
fetch: (url, init) => fetch(url, init),
|
|
4791
|
+
crnHash: candidateCrn.hash,
|
|
4792
|
+
crns: this.state.crns,
|
|
4793
|
+
crnListUrl: this.props.crnListUrl,
|
|
4794
|
+
requirePublicGuestIpv6ForProxy: true
|
|
4795
|
+
});
|
|
4796
|
+
if (latestRuntime.diagnostics?.state === "ready") {
|
|
4797
|
+
const reconciledRelayMetadata = await fetchRelayMetadataForRuntime({
|
|
4798
|
+
runtime: latestRuntime,
|
|
4799
|
+
fetch: (url, init) => fetch(url, init),
|
|
4800
|
+
preferSecureMetadata: attemptProfile === "uc-go-peer" && Boolean(latestRuntime.proxyUrl),
|
|
4801
|
+
attempts: 3,
|
|
4802
|
+
delayMs: 1e3,
|
|
4803
|
+
timeoutMs: 15e3
|
|
4804
|
+
}).catch(() => null);
|
|
4805
|
+
if (reconciledRelayMetadata) {
|
|
4806
|
+
const registrationId = createRelayBootstrapRegistrationId(
|
|
4807
|
+
attemptProfile,
|
|
4808
|
+
this.state.instanceName.trim(),
|
|
4809
|
+
attemptItemHash
|
|
4810
|
+
);
|
|
4811
|
+
const visibleRegistration = await waitForRelayBootstrapRegistration({
|
|
4812
|
+
registrationId,
|
|
4813
|
+
peerId: reconciledRelayMetadata.peerId,
|
|
4814
|
+
fetch: asJsonFetch,
|
|
4815
|
+
apiHost: this.client.apiHost,
|
|
4816
|
+
attempts: 3,
|
|
4817
|
+
delayMs: 1e3
|
|
4818
|
+
}).catch(() => null);
|
|
4819
|
+
if (visibleRegistration) {
|
|
4820
|
+
this.trace("deploy:recovered-after-error", {
|
|
4821
|
+
itemHash: attemptItemHash,
|
|
4822
|
+
registrationId,
|
|
4823
|
+
peerId: reconciledRelayMetadata.peerId,
|
|
4824
|
+
error: lastError.message
|
|
4825
|
+
});
|
|
4826
|
+
this.rememberRuntimeDetails(attemptItemHash, {
|
|
4827
|
+
messageStatus: "processed",
|
|
4828
|
+
allocationSource: latestRuntime.allocation?.source ?? null,
|
|
4829
|
+
crnUrl: latestRuntime.allocation?.crnUrl ?? latestRuntime.execution?.crnUrl ?? null,
|
|
4830
|
+
hostIpv4: latestRuntime.hostIpv4 ?? null,
|
|
4831
|
+
ipv6: latestRuntime.ipv6 ?? null,
|
|
4832
|
+
vmIpv4: latestRuntime.execution?.networking?.ipv4_ip ?? null,
|
|
4833
|
+
webUrl: latestRuntime.webAccessUrl ?? latestRuntime.proxyUrl ?? latestRuntime.execution?.networking?.proxy_url ?? null,
|
|
4834
|
+
sshCommand: latestRuntime.sshCommand ?? null,
|
|
4835
|
+
mappedPorts: latestRuntime.execution != null ? mappedPorts(latestRuntime.execution) : runtimeMappedPorts(latestRuntime.mappedPorts),
|
|
4836
|
+
execution: latestRuntime.execution ?? null,
|
|
4837
|
+
error: null
|
|
4838
|
+
});
|
|
4839
|
+
this.patch({
|
|
4840
|
+
busy: { deploying: false }
|
|
4841
|
+
});
|
|
4842
|
+
await this.refresh();
|
|
4843
|
+
this.lastCompletedDeploymentHash = attemptItemHash;
|
|
4844
|
+
this.emitProgress({
|
|
4845
|
+
stage: "completed",
|
|
4846
|
+
label: "Relay ready",
|
|
4847
|
+
progress: 100,
|
|
4848
|
+
status: "success",
|
|
4849
|
+
itemHash: attemptItemHash,
|
|
4850
|
+
detail: "The relay completed startup after a transient UI polling error. Runtime and bootstrap registration are confirmed."
|
|
4851
|
+
});
|
|
4852
|
+
return;
|
|
4853
|
+
}
|
|
4854
|
+
}
|
|
4855
|
+
}
|
|
4856
|
+
} catch (reconcileError) {
|
|
4857
|
+
this.trace("deploy:recovery-check-error", {
|
|
4858
|
+
itemHash: attemptItemHash,
|
|
4859
|
+
error: reconcileError instanceof Error ? reconcileError.message : String(reconcileError)
|
|
4860
|
+
});
|
|
4861
|
+
}
|
|
4862
|
+
await this.refresh().catch(() => void 0);
|
|
4863
|
+
const recoveredRegistration = this.state.bootstrapRegistrations.some(
|
|
4864
|
+
(entry) => entry.instanceItemHash === attemptItemHash && entry.confirmed
|
|
4865
|
+
);
|
|
4866
|
+
if (recoveredRegistration) {
|
|
4867
|
+
this.trace("deploy:recovered-from-refresh-state", {
|
|
4868
|
+
itemHash: attemptItemHash,
|
|
4869
|
+
error: lastError.message
|
|
4870
|
+
});
|
|
4871
|
+
this.patch({
|
|
4872
|
+
busy: { deploying: false }
|
|
4873
|
+
});
|
|
4874
|
+
this.lastCompletedDeploymentHash = attemptItemHash;
|
|
4875
|
+
this.emitProgress({
|
|
4876
|
+
stage: "completed",
|
|
4877
|
+
label: "Relay ready",
|
|
4878
|
+
progress: 100,
|
|
4879
|
+
status: "success",
|
|
4880
|
+
itemHash: attemptItemHash,
|
|
4881
|
+
detail: "The relay completed startup after a transient browser-side polling error. Runtime and bootstrap registration are confirmed."
|
|
4882
|
+
});
|
|
4883
|
+
return;
|
|
4884
|
+
}
|
|
4885
|
+
}
|
|
4760
4886
|
if (attemptItemHash) {
|
|
4761
4887
|
this.emitProgress({
|
|
4762
4888
|
stage: "deployment-confirmed",
|
|
@@ -5912,6 +6038,7 @@ function SponsorRelayFab(props) {
|
|
|
5912
6038
|
{
|
|
5913
6039
|
type: "button",
|
|
5914
6040
|
onClick: () => void (state.wallet.connected ? controller.deploy() : controller.connectWallet()),
|
|
6041
|
+
disabled: state.wallet.connected ? state.busy.deploying || state.rootfsHealth.tone !== "ok" : state.busy.connectingWallet,
|
|
5915
6042
|
style: { ...primaryButtonStyle, width: "100%", marginTop: "1rem" },
|
|
5916
6043
|
children: state.wallet.connected ? state.busy.deploying ? "Deploying\u2026" : "Deploy Relay" : "Connect MetaMask"
|
|
5917
6044
|
}
|
package/shared/index.d.ts
CHANGED
|
@@ -311,7 +311,7 @@ declare const STALE_INSTANCE_ALLOCATION_COOLDOWN_MS: number;
|
|
|
311
311
|
declare const RECENT_INSTANCE_RUNTIME_GRACE_MS: number;
|
|
312
312
|
declare const DEPLOYMENT_PENDING_WARNING_MS: number;
|
|
313
313
|
|
|
314
|
-
declare const UI_PACKAGE_VERSION = "0.4.
|
|
314
|
+
declare const UI_PACKAGE_VERSION = "0.4.4";
|
|
315
315
|
|
|
316
316
|
interface RootfsRequiredPortForward {
|
|
317
317
|
port: number;
|
package/shared/index.js
CHANGED
|
@@ -27,7 +27,7 @@ var RECENT_INSTANCE_RUNTIME_GRACE_MS = 10 * 60 * 1e3;
|
|
|
27
27
|
var DEPLOYMENT_PENDING_WARNING_MS = 3 * 60 * 1e3;
|
|
28
28
|
|
|
29
29
|
// src/shared/package-version.ts
|
|
30
|
-
var UI_PACKAGE_VERSION = "0.4.
|
|
30
|
+
var UI_PACKAGE_VERSION = "0.4.4";
|
|
31
31
|
|
|
32
32
|
// src/shared/format.ts
|
|
33
33
|
function shortHash(value, head = 8, tail = 6) {
|
|
@@ -3200,7 +3200,7 @@ function rootfsHealth(args) {
|
|
|
3200
3200
|
return {
|
|
3201
3201
|
tone: "error",
|
|
3202
3202
|
label: "not found on Aleph",
|
|
3203
|
-
detail: "The
|
|
3203
|
+
detail: "The manifest points to a rootfs STORE message that Aleph cannot find. Check that the manifest URL is correct and that the referenced rootfs was not forgotten."
|
|
3204
3204
|
};
|
|
3205
3205
|
}
|
|
3206
3206
|
if (!args.resolution) {
|
|
@@ -3233,8 +3233,8 @@ function rootfsHealth(args) {
|
|
|
3233
3233
|
}
|
|
3234
3234
|
return {
|
|
3235
3235
|
tone: "error",
|
|
3236
|
-
label: "not deployable",
|
|
3237
|
-
detail: args.resolution.rejectionReason ?? "Aleph rejected the rootfs reference."
|
|
3236
|
+
label: "manifest rootfs not deployable",
|
|
3237
|
+
detail: args.resolution.rejectionReason ?? (args.resolution.messageType === "STORE" ? "This manifest points to a rootfs STORE message that exists but is not deployable anymore, for example because it was forgotten or replaced. Double-check the manifest URL." : "Aleph rejected the rootfs reference. Double-check that the manifest URL points to the intended current rootfs.")
|
|
3238
3238
|
};
|
|
3239
3239
|
}
|
|
3240
3240
|
async function resolveManifest(args) {
|
|
@@ -3794,6 +3794,16 @@ var SponsorRelayController = class {
|
|
|
3794
3794
|
});
|
|
3795
3795
|
}
|
|
3796
3796
|
if (!relayMetadata) {
|
|
3797
|
+
await this.refresh().catch(() => void 0);
|
|
3798
|
+
const confirmedAfterRefresh = this.state.bootstrapRegistrations.some(
|
|
3799
|
+
(entry) => entry.instanceItemHash === args.itemHash && entry.confirmed
|
|
3800
|
+
);
|
|
3801
|
+
if (confirmedAfterRefresh) {
|
|
3802
|
+
this.trace("deploy:relay-metadata-recovered-from-refresh", {
|
|
3803
|
+
itemHash: args.itemHash
|
|
3804
|
+
});
|
|
3805
|
+
return;
|
|
3806
|
+
}
|
|
3797
3807
|
throw new Error("Relay metadata did not include a peer ID and public multiaddrs.");
|
|
3798
3808
|
}
|
|
3799
3809
|
const { peerId } = relayMetadata;
|
|
@@ -4070,6 +4080,20 @@ var SponsorRelayController = class {
|
|
|
4070
4080
|
});
|
|
4071
4081
|
return;
|
|
4072
4082
|
}
|
|
4083
|
+
const hasConfirmedBootstrapRegistration = this.state.bootstrapRegistrations.some(
|
|
4084
|
+
(entry) => entry.instanceItemHash === itemHash && entry.confirmed
|
|
4085
|
+
);
|
|
4086
|
+
if (hasConfirmedBootstrapRegistration) {
|
|
4087
|
+
this.emitProgress({
|
|
4088
|
+
stage: "completed",
|
|
4089
|
+
label: "Relay ready",
|
|
4090
|
+
progress: 100,
|
|
4091
|
+
status: "success",
|
|
4092
|
+
itemHash,
|
|
4093
|
+
detail: "Runtime networking is available and the relay bootstrap registration is confirmed on Aleph."
|
|
4094
|
+
});
|
|
4095
|
+
return;
|
|
4096
|
+
}
|
|
4073
4097
|
this.emitProgress({
|
|
4074
4098
|
stage: "deployment-confirmed",
|
|
4075
4099
|
label: "Runtime ready",
|
|
@@ -4466,9 +4490,9 @@ var SponsorRelayController = class {
|
|
|
4466
4490
|
this.patch({ errorText: "Connect MetaMask before deploying." });
|
|
4467
4491
|
return;
|
|
4468
4492
|
}
|
|
4469
|
-
if (!this.state.manifest ||
|
|
4493
|
+
if (!this.state.manifest || this.state.rootfsHealth.tone !== "ok" || !this.state.pricingSummary.pricing || !this.state.pricingSummary.tier) {
|
|
4470
4494
|
this.patch({
|
|
4471
|
-
errorText: "Manifest, rootfs, and pricing must be ready before deploying."
|
|
4495
|
+
errorText: this.state.rootfsHealth.tone === "error" ? `Cannot deploy: ${this.state.rootfsHealth.detail ?? this.state.rootfsHealth.label}` : "Manifest, rootfs, and pricing must be ready before deploying."
|
|
4472
4496
|
});
|
|
4473
4497
|
return;
|
|
4474
4498
|
}
|
|
@@ -4510,6 +4534,7 @@ var SponsorRelayController = class {
|
|
|
4510
4534
|
for (const [candidateIndex, candidateCrn] of orderedCrns.entries()) {
|
|
4511
4535
|
let attemptItemHash = null;
|
|
4512
4536
|
let attemptDeploymentToken = null;
|
|
4537
|
+
let attemptProfile = null;
|
|
4513
4538
|
const crnAttemptLabel = `CRN ${candidateIndex + 1}/${orderedCrns.length}`;
|
|
4514
4539
|
const crnDisplayName = candidateCrn.name ?? candidateCrn.hash;
|
|
4515
4540
|
this.emitProgress({
|
|
@@ -4521,6 +4546,7 @@ var SponsorRelayController = class {
|
|
|
4521
4546
|
});
|
|
4522
4547
|
try {
|
|
4523
4548
|
const profile = relayProfileForManifest(this.state.manifest);
|
|
4549
|
+
attemptProfile = profile;
|
|
4524
4550
|
const sshPublicKey = profile === "uc-go-peer" ? appendDeploymentTokenToSshPublicKey(
|
|
4525
4551
|
this.state.sshPublicKey.trim(),
|
|
4526
4552
|
this.state.wallet.address,
|
|
@@ -4756,6 +4782,106 @@ var SponsorRelayController = class {
|
|
|
4756
4782
|
itemHash: attemptItemHash,
|
|
4757
4783
|
error: lastError.message
|
|
4758
4784
|
});
|
|
4785
|
+
if (attemptItemHash && attemptDeploymentToken && attemptProfile && !failedDueToInvalidIpv6) {
|
|
4786
|
+
try {
|
|
4787
|
+
const latestRuntime = await fetchVmRuntime({
|
|
4788
|
+
itemHash: attemptItemHash,
|
|
4789
|
+
fetch: (url, init) => fetch(url, init),
|
|
4790
|
+
crnHash: candidateCrn.hash,
|
|
4791
|
+
crns: this.state.crns,
|
|
4792
|
+
crnListUrl: this.props.crnListUrl,
|
|
4793
|
+
requirePublicGuestIpv6ForProxy: true
|
|
4794
|
+
});
|
|
4795
|
+
if (latestRuntime.diagnostics?.state === "ready") {
|
|
4796
|
+
const reconciledRelayMetadata = await fetchRelayMetadataForRuntime({
|
|
4797
|
+
runtime: latestRuntime,
|
|
4798
|
+
fetch: (url, init) => fetch(url, init),
|
|
4799
|
+
preferSecureMetadata: attemptProfile === "uc-go-peer" && Boolean(latestRuntime.proxyUrl),
|
|
4800
|
+
attempts: 3,
|
|
4801
|
+
delayMs: 1e3,
|
|
4802
|
+
timeoutMs: 15e3
|
|
4803
|
+
}).catch(() => null);
|
|
4804
|
+
if (reconciledRelayMetadata) {
|
|
4805
|
+
const registrationId = createRelayBootstrapRegistrationId(
|
|
4806
|
+
attemptProfile,
|
|
4807
|
+
this.state.instanceName.trim(),
|
|
4808
|
+
attemptItemHash
|
|
4809
|
+
);
|
|
4810
|
+
const visibleRegistration = await waitForRelayBootstrapRegistration({
|
|
4811
|
+
registrationId,
|
|
4812
|
+
peerId: reconciledRelayMetadata.peerId,
|
|
4813
|
+
fetch: asJsonFetch,
|
|
4814
|
+
apiHost: this.client.apiHost,
|
|
4815
|
+
attempts: 3,
|
|
4816
|
+
delayMs: 1e3
|
|
4817
|
+
}).catch(() => null);
|
|
4818
|
+
if (visibleRegistration) {
|
|
4819
|
+
this.trace("deploy:recovered-after-error", {
|
|
4820
|
+
itemHash: attemptItemHash,
|
|
4821
|
+
registrationId,
|
|
4822
|
+
peerId: reconciledRelayMetadata.peerId,
|
|
4823
|
+
error: lastError.message
|
|
4824
|
+
});
|
|
4825
|
+
this.rememberRuntimeDetails(attemptItemHash, {
|
|
4826
|
+
messageStatus: "processed",
|
|
4827
|
+
allocationSource: latestRuntime.allocation?.source ?? null,
|
|
4828
|
+
crnUrl: latestRuntime.allocation?.crnUrl ?? latestRuntime.execution?.crnUrl ?? null,
|
|
4829
|
+
hostIpv4: latestRuntime.hostIpv4 ?? null,
|
|
4830
|
+
ipv6: latestRuntime.ipv6 ?? null,
|
|
4831
|
+
vmIpv4: latestRuntime.execution?.networking?.ipv4_ip ?? null,
|
|
4832
|
+
webUrl: latestRuntime.webAccessUrl ?? latestRuntime.proxyUrl ?? latestRuntime.execution?.networking?.proxy_url ?? null,
|
|
4833
|
+
sshCommand: latestRuntime.sshCommand ?? null,
|
|
4834
|
+
mappedPorts: latestRuntime.execution != null ? mappedPorts(latestRuntime.execution) : runtimeMappedPorts(latestRuntime.mappedPorts),
|
|
4835
|
+
execution: latestRuntime.execution ?? null,
|
|
4836
|
+
error: null
|
|
4837
|
+
});
|
|
4838
|
+
this.patch({
|
|
4839
|
+
busy: { deploying: false }
|
|
4840
|
+
});
|
|
4841
|
+
await this.refresh();
|
|
4842
|
+
this.lastCompletedDeploymentHash = attemptItemHash;
|
|
4843
|
+
this.emitProgress({
|
|
4844
|
+
stage: "completed",
|
|
4845
|
+
label: "Relay ready",
|
|
4846
|
+
progress: 100,
|
|
4847
|
+
status: "success",
|
|
4848
|
+
itemHash: attemptItemHash,
|
|
4849
|
+
detail: "The relay completed startup after a transient UI polling error. Runtime and bootstrap registration are confirmed."
|
|
4850
|
+
});
|
|
4851
|
+
return;
|
|
4852
|
+
}
|
|
4853
|
+
}
|
|
4854
|
+
}
|
|
4855
|
+
} catch (reconcileError) {
|
|
4856
|
+
this.trace("deploy:recovery-check-error", {
|
|
4857
|
+
itemHash: attemptItemHash,
|
|
4858
|
+
error: reconcileError instanceof Error ? reconcileError.message : String(reconcileError)
|
|
4859
|
+
});
|
|
4860
|
+
}
|
|
4861
|
+
await this.refresh().catch(() => void 0);
|
|
4862
|
+
const recoveredRegistration = this.state.bootstrapRegistrations.some(
|
|
4863
|
+
(entry) => entry.instanceItemHash === attemptItemHash && entry.confirmed
|
|
4864
|
+
);
|
|
4865
|
+
if (recoveredRegistration) {
|
|
4866
|
+
this.trace("deploy:recovered-from-refresh-state", {
|
|
4867
|
+
itemHash: attemptItemHash,
|
|
4868
|
+
error: lastError.message
|
|
4869
|
+
});
|
|
4870
|
+
this.patch({
|
|
4871
|
+
busy: { deploying: false }
|
|
4872
|
+
});
|
|
4873
|
+
this.lastCompletedDeploymentHash = attemptItemHash;
|
|
4874
|
+
this.emitProgress({
|
|
4875
|
+
stage: "completed",
|
|
4876
|
+
label: "Relay ready",
|
|
4877
|
+
progress: 100,
|
|
4878
|
+
status: "success",
|
|
4879
|
+
itemHash: attemptItemHash,
|
|
4880
|
+
detail: "The relay completed startup after a transient browser-side polling error. Runtime and bootstrap registration are confirmed."
|
|
4881
|
+
});
|
|
4882
|
+
return;
|
|
4883
|
+
}
|
|
4884
|
+
}
|
|
4759
4885
|
if (attemptItemHash) {
|
|
4760
4886
|
this.emitProgress({
|
|
4761
4887
|
stage: "deployment-confirmed",
|
|
@@ -193,7 +193,7 @@ export let apiHost = undefined
|
|
|
193
193
|
|
|
194
194
|
<div class="actions">
|
|
195
195
|
{#if state.wallet.connected}
|
|
196
|
-
<button class="primary" type="button" on:click={() => controller.deploy()} disabled={state.busy.deploying ||
|
|
196
|
+
<button class="primary" type="button" on:click={() => controller.deploy()} disabled={state.busy.deploying || state.rootfsHealth.tone !== 'ok'}>
|
|
197
197
|
{state.busy.deploying ? 'Deploying…' : 'Deploy Relay'}
|
|
198
198
|
</button>
|
|
199
199
|
{:else}
|