@le-space/ui 0.3.27 → 0.3.30
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 +242 -11
- package/shared/index.d.ts +1 -1
- package/shared/index.js +242 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@le-space/ui",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.30",
|
|
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.30",
|
|
40
|
+
"@le-space/core": "0.3.30",
|
|
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.3.
|
|
31
|
+
var UI_PACKAGE_VERSION = "0.3.30";
|
|
32
32
|
|
|
33
33
|
// src/shared/format.ts
|
|
34
34
|
function shortHash(value, head = 8, tail = 6) {
|
|
@@ -1878,6 +1878,13 @@ async function waitForVmRuntime(args) {
|
|
|
1878
1878
|
}
|
|
1879
1879
|
|
|
1880
1880
|
// ../core/src/guest.ts
|
|
1881
|
+
function proxyHostnameFromUrl(value) {
|
|
1882
|
+
try {
|
|
1883
|
+
return value ? new URL(value).hostname : null;
|
|
1884
|
+
} catch {
|
|
1885
|
+
return null;
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1881
1888
|
async function defaultHttpProbe(fetch2, url, timeoutMs = 1e4) {
|
|
1882
1889
|
try {
|
|
1883
1890
|
const controller = new AbortController();
|
|
@@ -2119,6 +2126,59 @@ async function fetchUcGoPeerMetadata(args) {
|
|
|
2119
2126
|
`Relay metadata did not become ready after ${attempts} attempts: ${lastError ? lastError : typeof lastPayload === "string" ? lastPayload : JSON.stringify(lastPayload ?? {})}`
|
|
2120
2127
|
);
|
|
2121
2128
|
}
|
|
2129
|
+
async function verifyUcGoPeerReachability(args) {
|
|
2130
|
+
const checks = {};
|
|
2131
|
+
const mappedPorts2 = args.mappedPorts ?? {};
|
|
2132
|
+
const hostIpv4 = args.hostIpv4;
|
|
2133
|
+
const skippedInternalPorts = new Set(
|
|
2134
|
+
(args.skipInternalPorts ?? ["80"]).map((value) => String(value))
|
|
2135
|
+
);
|
|
2136
|
+
const httpProbe = args.httpProbe ?? ((url, timeoutMs) => defaultHttpProbe(args.fetch, url, timeoutMs));
|
|
2137
|
+
if (hostIpv4) {
|
|
2138
|
+
for (const [internalPort, mapping] of Object.entries(mappedPorts2)) {
|
|
2139
|
+
if (skippedInternalPorts.has(String(internalPort))) continue;
|
|
2140
|
+
if (mapping?.tcp === true && mapping?.host) {
|
|
2141
|
+
checks[`tcp:${internalPort}`] = {
|
|
2142
|
+
host: hostIpv4,
|
|
2143
|
+
port: mapping.host,
|
|
2144
|
+
...await args.tcpProbe(
|
|
2145
|
+
hostIpv4,
|
|
2146
|
+
mapping.host,
|
|
2147
|
+
Number(args.tcpTimeoutMs ?? 5e3)
|
|
2148
|
+
)
|
|
2149
|
+
};
|
|
2150
|
+
} else if (mapping?.udp === true && mapping?.host) {
|
|
2151
|
+
checks[`udp:${internalPort}`] = {
|
|
2152
|
+
host: hostIpv4,
|
|
2153
|
+
port: mapping.host,
|
|
2154
|
+
ok: null,
|
|
2155
|
+
note: "UDP mapping published; CI does not perform an application-level UDP handshake probe."
|
|
2156
|
+
};
|
|
2157
|
+
}
|
|
2158
|
+
}
|
|
2159
|
+
}
|
|
2160
|
+
if (args.proxyUrl && args.verifyProxyHttp !== false) {
|
|
2161
|
+
checks["https:proxy"] = await httpProbe(
|
|
2162
|
+
args.proxyUrl,
|
|
2163
|
+
Number(args.httpTimeoutMs ?? 1e4)
|
|
2164
|
+
);
|
|
2165
|
+
}
|
|
2166
|
+
const proxyHostname = proxyHostnameFromUrl(args.proxyUrl);
|
|
2167
|
+
if (proxyHostname) {
|
|
2168
|
+
checks["tcp:proxy-443"] = await args.tcpProbe(
|
|
2169
|
+
proxyHostname,
|
|
2170
|
+
443,
|
|
2171
|
+
Number(args.tcpTimeoutMs ?? 5e3)
|
|
2172
|
+
);
|
|
2173
|
+
}
|
|
2174
|
+
const failedChecks = Object.entries(checks).filter(
|
|
2175
|
+
([, value]) => value?.ok === false
|
|
2176
|
+
);
|
|
2177
|
+
return {
|
|
2178
|
+
ok: failedChecks.length === 0,
|
|
2179
|
+
checks
|
|
2180
|
+
};
|
|
2181
|
+
}
|
|
2122
2182
|
|
|
2123
2183
|
// ../aleph-bootstrap/src/index.ts
|
|
2124
2184
|
import { recoverMessageAddress } from "viem";
|
|
@@ -3219,6 +3279,8 @@ var UI_DEPLOY_WAIT_ATTEMPTS = 60;
|
|
|
3219
3279
|
var UI_DEPLOY_WAIT_DELAY_MS = 5e3;
|
|
3220
3280
|
var UI_RUNTIME_WAIT_ATTEMPTS = 40;
|
|
3221
3281
|
var UI_RUNTIME_WAIT_DELAY_MS = 5e3;
|
|
3282
|
+
var UI_REACHABILITY_VERIFY_ATTEMPTS = 25;
|
|
3283
|
+
var UI_REACHABILITY_VERIFY_DELAY_MS = 3e3;
|
|
3222
3284
|
function hasUsableRuntime(details) {
|
|
3223
3285
|
return Boolean(details.hostIpv4) || Boolean(details.vmIpv4) || details.mappedPorts.length > 0 || Boolean(details.webUrl) || Boolean(details.execution);
|
|
3224
3286
|
}
|
|
@@ -3325,15 +3387,16 @@ var SponsorRelayController = class {
|
|
|
3325
3387
|
this.progressEmitter.emit(nextEvent);
|
|
3326
3388
|
}
|
|
3327
3389
|
async configureRelayBootstrapRegistration(args) {
|
|
3390
|
+
let runtime = args.runtime;
|
|
3328
3391
|
const profile = relayProfileForManifest(this.state.manifest);
|
|
3329
3392
|
if (!profile) return;
|
|
3330
3393
|
if (!this.state.wallet.address) {
|
|
3331
3394
|
throw new Error("A connected wallet is required to register relay bootstrap addresses.");
|
|
3332
3395
|
}
|
|
3333
|
-
if (!
|
|
3396
|
+
if (!runtime.hostIpv4) {
|
|
3334
3397
|
throw new Error("Relay runtime did not expose a host IPv4 address.");
|
|
3335
3398
|
}
|
|
3336
|
-
|
|
3399
|
+
let mappedPorts2 = runtime.mappedPorts ?? {};
|
|
3337
3400
|
const setupPort = mappedPorts2["80"]?.host ?? null;
|
|
3338
3401
|
if (!setupPort) {
|
|
3339
3402
|
throw new Error("Relay runtime did not expose the temporary setup endpoint.");
|
|
@@ -3348,7 +3411,7 @@ var SponsorRelayController = class {
|
|
|
3348
3411
|
detail: "Waiting for the guest setup endpoint before collecting relay metadata."
|
|
3349
3412
|
});
|
|
3350
3413
|
const setupHealth = await waitForSetupEndpoint({
|
|
3351
|
-
hostIpv4:
|
|
3414
|
+
hostIpv4: runtime.hostIpv4,
|
|
3352
3415
|
setupPort,
|
|
3353
3416
|
fetch: (url, init) => fetch(url, init),
|
|
3354
3417
|
attempts: 15,
|
|
@@ -3374,12 +3437,12 @@ var SponsorRelayController = class {
|
|
|
3374
3437
|
throw new Error("OrbitDB relay runtime is missing required mapped TCP/WS ports.");
|
|
3375
3438
|
}
|
|
3376
3439
|
const configureResult = await configureOrbitdbRelaySetup2({
|
|
3377
|
-
hostIpv4:
|
|
3378
|
-
publicIpv6:
|
|
3440
|
+
hostIpv4: runtime.hostIpv4,
|
|
3441
|
+
publicIpv6: runtime.ipv6,
|
|
3379
3442
|
setupPort,
|
|
3380
3443
|
tcpPort,
|
|
3381
3444
|
wsPort,
|
|
3382
|
-
proxyUrl:
|
|
3445
|
+
proxyUrl: runtime.proxyUrl ?? void 0,
|
|
3383
3446
|
metricsPort: mappedPorts2["9090"]?.host ?? null,
|
|
3384
3447
|
metricsHttpsPort: mappedPorts2["443"]?.host ?? null,
|
|
3385
3448
|
webrtcPort: mappedPorts2["9093"]?.host ?? null,
|
|
@@ -3396,6 +3459,59 @@ var SponsorRelayController = class {
|
|
|
3396
3459
|
if (!args.deploymentToken) {
|
|
3397
3460
|
throw new Error("Missing deployment token for Aleph bootstrap config handoff.");
|
|
3398
3461
|
}
|
|
3462
|
+
if (runtime.proxyUrl && runtime.webAccess?.active !== true) {
|
|
3463
|
+
this.emitProgress({
|
|
3464
|
+
stage: "deployment-confirmed",
|
|
3465
|
+
label: "Waiting for HTTPS route",
|
|
3466
|
+
progress: 93,
|
|
3467
|
+
status: "warning",
|
|
3468
|
+
itemHash: args.itemHash,
|
|
3469
|
+
detail: "The relay received a 2n6 hostname, but it is not active yet. Waiting before handing HTTPS config to the guest."
|
|
3470
|
+
});
|
|
3471
|
+
let latestRuntime = runtime;
|
|
3472
|
+
for (let attempt = 0; attempt < UI_RUNTIME_WAIT_ATTEMPTS; attempt += 1) {
|
|
3473
|
+
if (latestRuntime.webAccess?.active === true) {
|
|
3474
|
+
break;
|
|
3475
|
+
}
|
|
3476
|
+
await new Promise(
|
|
3477
|
+
(resolve) => globalThis.setTimeout(resolve, UI_RUNTIME_WAIT_DELAY_MS)
|
|
3478
|
+
);
|
|
3479
|
+
latestRuntime = await fetchVmRuntime({
|
|
3480
|
+
itemHash: args.itemHash,
|
|
3481
|
+
fetch: (url, init) => fetch(url, init),
|
|
3482
|
+
crnHash: runtime.selectedCrn?.hash ?? runtime.allocation?.crnHash ?? void 0,
|
|
3483
|
+
crns: this.state.crns,
|
|
3484
|
+
crnListUrl: this.props.crnListUrl
|
|
3485
|
+
}).catch(() => latestRuntime);
|
|
3486
|
+
this.emitProgress({
|
|
3487
|
+
stage: "deployment-confirmed",
|
|
3488
|
+
label: "Waiting for HTTPS route",
|
|
3489
|
+
progress: 93,
|
|
3490
|
+
status: latestRuntime.webAccess?.active === true ? "info" : "warning",
|
|
3491
|
+
itemHash: args.itemHash,
|
|
3492
|
+
detail: `2n6 activation ${attempt + 1}/${UI_RUNTIME_WAIT_ATTEMPTS}: ${latestRuntime.webAccess?.active === true ? "active" : "still pending"} for ${latestRuntime.proxyUrl ?? runtime.proxyUrl ?? "reserved proxy URL"}.`
|
|
3493
|
+
});
|
|
3494
|
+
this.trace("deploy:bootstrap-proxy-activation", {
|
|
3495
|
+
itemHash: args.itemHash,
|
|
3496
|
+
attempt: attempt + 1,
|
|
3497
|
+
attempts: UI_RUNTIME_WAIT_ATTEMPTS,
|
|
3498
|
+
active: latestRuntime.webAccess?.active === true,
|
|
3499
|
+
proxyUrl: latestRuntime.proxyUrl ?? null
|
|
3500
|
+
});
|
|
3501
|
+
}
|
|
3502
|
+
runtime = latestRuntime;
|
|
3503
|
+
mappedPorts2 = runtime.mappedPorts ?? mappedPorts2;
|
|
3504
|
+
if (runtime.proxyUrl && runtime.webAccess?.active !== true) {
|
|
3505
|
+
throw new Error(
|
|
3506
|
+
"Aleph reserved a 2n6 proxy URL, but it never became active in time. Aborting guest HTTPS configuration to avoid a broken Caddy setup."
|
|
3507
|
+
);
|
|
3508
|
+
}
|
|
3509
|
+
}
|
|
3510
|
+
if (!runtime.hostIpv4) {
|
|
3511
|
+
throw new Error("Relay runtime lost its host IPv4 address while waiting for HTTPS activation.");
|
|
3512
|
+
}
|
|
3513
|
+
const runtimeHostIpv4 = runtime.hostIpv4;
|
|
3514
|
+
const activeProxyUrl = runtime.webAccess?.active === true ? runtime.proxyUrl ?? null : null;
|
|
3399
3515
|
this.emitProgress({
|
|
3400
3516
|
stage: "deployment-confirmed",
|
|
3401
3517
|
label: "Publishing relay config",
|
|
@@ -3413,9 +3529,9 @@ var SponsorRelayController = class {
|
|
|
3413
3529
|
expiresAt: new Date(Date.now() + 30 * 6e4).toISOString(),
|
|
3414
3530
|
status: "pending",
|
|
3415
3531
|
runtime: {
|
|
3416
|
-
publicIpv4:
|
|
3417
|
-
publicIpv6:
|
|
3418
|
-
proxyUrl:
|
|
3532
|
+
publicIpv4: runtimeHostIpv4,
|
|
3533
|
+
publicIpv6: runtime.ipv6 ?? null,
|
|
3534
|
+
proxyUrl: activeProxyUrl,
|
|
3419
3535
|
mappedPorts: mappedPorts2
|
|
3420
3536
|
},
|
|
3421
3537
|
bootstrap: {
|
|
@@ -3481,7 +3597,7 @@ var SponsorRelayController = class {
|
|
|
3481
3597
|
detail: "Waiting for the relay to report its final public multiaddrs."
|
|
3482
3598
|
});
|
|
3483
3599
|
const relayMetadata = await fetchRelayMetadataForRuntime({
|
|
3484
|
-
runtime
|
|
3600
|
+
runtime,
|
|
3485
3601
|
fetch: (url, init) => fetch(url, init),
|
|
3486
3602
|
preferSecureMetadata: profile === "uc-go-peer",
|
|
3487
3603
|
attempts: 80,
|
|
@@ -3514,6 +3630,55 @@ var SponsorRelayController = class {
|
|
|
3514
3630
|
if (!relayMetadata) {
|
|
3515
3631
|
throw new Error("Relay metadata did not include a peer ID and public multiaddrs.");
|
|
3516
3632
|
}
|
|
3633
|
+
if (profile === "uc-go-peer" && runtime.proxyUrl) {
|
|
3634
|
+
this.emitProgress({
|
|
3635
|
+
stage: "publishing-bootstrap",
|
|
3636
|
+
label: "Verifying reachability",
|
|
3637
|
+
progress: 96,
|
|
3638
|
+
status: "info",
|
|
3639
|
+
itemHash: args.itemHash,
|
|
3640
|
+
detail: "Checking that the secure relay endpoint is reachable before trusting the deployment as ready."
|
|
3641
|
+
});
|
|
3642
|
+
const verificationUrl = (() => {
|
|
3643
|
+
try {
|
|
3644
|
+
return new URL("/bootstrap/metadata", runtime.proxyUrl).toString();
|
|
3645
|
+
} catch {
|
|
3646
|
+
return runtime.proxyUrl ?? "";
|
|
3647
|
+
}
|
|
3648
|
+
})();
|
|
3649
|
+
let verificationResult = null;
|
|
3650
|
+
for (let attempt = 0; attempt < UI_REACHABILITY_VERIFY_ATTEMPTS; attempt += 1) {
|
|
3651
|
+
verificationResult = await verifyUcGoPeerReachability({
|
|
3652
|
+
proxyUrl: verificationUrl,
|
|
3653
|
+
verifyProxyHttp: true,
|
|
3654
|
+
fetch: (url, init) => fetch(url, init),
|
|
3655
|
+
tcpProbe: async () => ({ ok: null })
|
|
3656
|
+
});
|
|
3657
|
+
this.trace("deploy:reachability-verification-attempt", {
|
|
3658
|
+
itemHash: args.itemHash,
|
|
3659
|
+
attempt: attempt + 1,
|
|
3660
|
+
attempts: UI_REACHABILITY_VERIFY_ATTEMPTS,
|
|
3661
|
+
verificationUrl,
|
|
3662
|
+
ok: verificationResult.ok,
|
|
3663
|
+
checks: verificationResult.checks
|
|
3664
|
+
});
|
|
3665
|
+
const proxyHttpCheck2 = verificationResult.checks["https:proxy"];
|
|
3666
|
+
if (verificationResult.ok && proxyHttpCheck2?.ok === true) {
|
|
3667
|
+
break;
|
|
3668
|
+
}
|
|
3669
|
+
if (attempt < UI_REACHABILITY_VERIFY_ATTEMPTS - 1) {
|
|
3670
|
+
await new Promise(
|
|
3671
|
+
(resolve) => globalThis.setTimeout(resolve, UI_REACHABILITY_VERIFY_DELAY_MS)
|
|
3672
|
+
);
|
|
3673
|
+
}
|
|
3674
|
+
}
|
|
3675
|
+
const proxyHttpCheck = verificationResult?.checks["https:proxy"];
|
|
3676
|
+
if (!verificationResult?.ok || proxyHttpCheck?.ok !== true) {
|
|
3677
|
+
throw new Error(
|
|
3678
|
+
proxyHttpCheck?.error ? `Secure relay endpoint did not become reachable in time: ${proxyHttpCheck.error}` : "Secure relay endpoint did not become reachable in time."
|
|
3679
|
+
);
|
|
3680
|
+
}
|
|
3681
|
+
}
|
|
3517
3682
|
const { peerId } = relayMetadata;
|
|
3518
3683
|
const registrationId = createRelayBootstrapRegistrationId(
|
|
3519
3684
|
profile,
|
|
@@ -3631,6 +3796,7 @@ var SponsorRelayController = class {
|
|
|
3631
3796
|
const currentProgress = this.state.deploymentProgress;
|
|
3632
3797
|
const currentProgressIsForLatestHash = currentProgress.itemHash === itemHash || currentProgress.itemHash == null && currentProgress.stage !== "idle" && currentProgress.stage !== "error";
|
|
3633
3798
|
const keepTerminalSuccess = this.lastCompletedDeploymentHash === itemHash || currentProgressIsForLatestHash && currentProgress.stage === "completed" && currentProgress.status === "success";
|
|
3799
|
+
const keepSpecificInFlightProgress = currentProgressIsForLatestHash && currentProgress.stage !== "completed" && currentProgress.stage !== "error" && currentProgress.progress >= 93;
|
|
3634
3800
|
const status = latest.details.messageStatus;
|
|
3635
3801
|
if (status === "rejected") {
|
|
3636
3802
|
this.emitProgress({
|
|
@@ -3673,6 +3839,16 @@ var SponsorRelayController = class {
|
|
|
3673
3839
|
});
|
|
3674
3840
|
return;
|
|
3675
3841
|
}
|
|
3842
|
+
if (keepSpecificInFlightProgress) {
|
|
3843
|
+
this.trace("progress:retain-inflight", {
|
|
3844
|
+
reason: "latest refresh would overwrite a more specific in-flight deployment phase",
|
|
3845
|
+
itemHash,
|
|
3846
|
+
currentStage: currentProgress.stage,
|
|
3847
|
+
currentLabel: currentProgress.label,
|
|
3848
|
+
currentProgress: currentProgress.progress
|
|
3849
|
+
});
|
|
3850
|
+
return;
|
|
3851
|
+
}
|
|
3676
3852
|
this.emitProgress({
|
|
3677
3853
|
stage: "deployment-confirmed",
|
|
3678
3854
|
label: "Waiting for runtime",
|
|
@@ -3683,6 +3859,16 @@ var SponsorRelayController = class {
|
|
|
3683
3859
|
});
|
|
3684
3860
|
return;
|
|
3685
3861
|
}
|
|
3862
|
+
if (keepSpecificInFlightProgress) {
|
|
3863
|
+
this.trace("progress:retain-inflight", {
|
|
3864
|
+
reason: "latest refresh would overwrite a more specific in-flight deployment phase",
|
|
3865
|
+
itemHash,
|
|
3866
|
+
currentStage: currentProgress.stage,
|
|
3867
|
+
currentLabel: currentProgress.label,
|
|
3868
|
+
currentProgress: currentProgress.progress
|
|
3869
|
+
});
|
|
3870
|
+
return;
|
|
3871
|
+
}
|
|
3686
3872
|
this.emitProgress({
|
|
3687
3873
|
stage: "deployment-confirmed",
|
|
3688
3874
|
label: "Runtime ready",
|
|
@@ -4313,6 +4499,15 @@ var SponsorRelayController = class {
|
|
|
4313
4499
|
});
|
|
4314
4500
|
if (attemptItemHash) {
|
|
4315
4501
|
if (attemptDeploymentToken) {
|
|
4502
|
+
this.emitProgress({
|
|
4503
|
+
stage: "refreshing-instances",
|
|
4504
|
+
label: "Cleaning up failed attempt",
|
|
4505
|
+
progress: 16,
|
|
4506
|
+
status: "warning",
|
|
4507
|
+
itemHash: attemptItemHash,
|
|
4508
|
+
detail: `Removing bootstrap handoff state for failed deployment on ${attemptLabel}.`,
|
|
4509
|
+
error: lastError.message
|
|
4510
|
+
});
|
|
4316
4511
|
this.trace("deploy:bootstrap-config-cleanup-start", {
|
|
4317
4512
|
itemHash: attemptItemHash,
|
|
4318
4513
|
deploymentToken: attemptDeploymentToken
|
|
@@ -4338,8 +4533,26 @@ var SponsorRelayController = class {
|
|
|
4338
4533
|
deploymentToken: attemptDeploymentToken,
|
|
4339
4534
|
error: cleanupError instanceof Error ? cleanupError.message : String(cleanupError)
|
|
4340
4535
|
});
|
|
4536
|
+
this.emitProgress({
|
|
4537
|
+
stage: "refreshing-instances",
|
|
4538
|
+
label: "Cleanup warning",
|
|
4539
|
+
progress: 16,
|
|
4540
|
+
status: "warning",
|
|
4541
|
+
itemHash: attemptItemHash,
|
|
4542
|
+
detail: `Bootstrap cleanup reported an issue for ${attemptLabel}, but retry cleanup will continue.`,
|
|
4543
|
+
error: cleanupError instanceof Error ? cleanupError.message : String(cleanupError)
|
|
4544
|
+
});
|
|
4341
4545
|
});
|
|
4342
4546
|
}
|
|
4547
|
+
this.emitProgress({
|
|
4548
|
+
stage: "refreshing-instances",
|
|
4549
|
+
label: "Discarding failed deployment",
|
|
4550
|
+
progress: 17,
|
|
4551
|
+
status: "warning",
|
|
4552
|
+
itemHash: attemptItemHash,
|
|
4553
|
+
detail: `Forgetting failed deployment ${attemptItemHash.slice(0, 12)} on ${attemptLabel} before retrying.`,
|
|
4554
|
+
error: lastError.message
|
|
4555
|
+
});
|
|
4343
4556
|
this.trace("deploy:forget-failed-attempt-start", {
|
|
4344
4557
|
itemHash: attemptItemHash,
|
|
4345
4558
|
crnHash: candidateCrn.hash,
|
|
@@ -4362,12 +4575,30 @@ var SponsorRelayController = class {
|
|
|
4362
4575
|
itemHash: attemptItemHash,
|
|
4363
4576
|
error: cleanupError instanceof Error ? cleanupError.message : String(cleanupError)
|
|
4364
4577
|
});
|
|
4578
|
+
this.emitProgress({
|
|
4579
|
+
stage: "refreshing-instances",
|
|
4580
|
+
label: "Cleanup warning",
|
|
4581
|
+
progress: 17,
|
|
4582
|
+
status: "warning",
|
|
4583
|
+
itemHash: attemptItemHash,
|
|
4584
|
+
detail: `Failed deployment cleanup reported an issue for ${attemptLabel}.`,
|
|
4585
|
+
error: cleanupError instanceof Error ? cleanupError.message : String(cleanupError)
|
|
4586
|
+
});
|
|
4365
4587
|
});
|
|
4366
4588
|
this.trace("deploy:forget-failed-attempt-complete", {
|
|
4367
4589
|
itemHash: attemptItemHash,
|
|
4368
4590
|
crnHash: candidateCrn.hash,
|
|
4369
4591
|
crnName: candidateCrn.name
|
|
4370
4592
|
});
|
|
4593
|
+
this.emitProgress({
|
|
4594
|
+
stage: "refreshing-instances",
|
|
4595
|
+
label: "Cleanup complete",
|
|
4596
|
+
progress: 18,
|
|
4597
|
+
status: "info",
|
|
4598
|
+
itemHash: attemptItemHash,
|
|
4599
|
+
detail: `Finished cleaning up failed deployment on ${attemptLabel}.`,
|
|
4600
|
+
error: null
|
|
4601
|
+
});
|
|
4371
4602
|
}
|
|
4372
4603
|
if (candidateIndex < orderedCrns.length - 1) {
|
|
4373
4604
|
this.emitProgress({
|
package/shared/index.d.ts
CHANGED
|
@@ -290,7 +290,7 @@ declare const STALE_INSTANCE_ALLOCATION_COOLDOWN_MS: number;
|
|
|
290
290
|
declare const RECENT_INSTANCE_RUNTIME_GRACE_MS: number;
|
|
291
291
|
declare const DEPLOYMENT_PENDING_WARNING_MS: number;
|
|
292
292
|
|
|
293
|
-
declare const UI_PACKAGE_VERSION = "0.3.
|
|
293
|
+
declare const UI_PACKAGE_VERSION = "0.3.30";
|
|
294
294
|
|
|
295
295
|
interface RootfsRequiredPortForward {
|
|
296
296
|
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.3.
|
|
30
|
+
var UI_PACKAGE_VERSION = "0.3.30";
|
|
31
31
|
|
|
32
32
|
// src/shared/format.ts
|
|
33
33
|
function shortHash(value, head = 8, tail = 6) {
|
|
@@ -1877,6 +1877,13 @@ async function waitForVmRuntime(args) {
|
|
|
1877
1877
|
}
|
|
1878
1878
|
|
|
1879
1879
|
// ../core/src/guest.ts
|
|
1880
|
+
function proxyHostnameFromUrl(value) {
|
|
1881
|
+
try {
|
|
1882
|
+
return value ? new URL(value).hostname : null;
|
|
1883
|
+
} catch {
|
|
1884
|
+
return null;
|
|
1885
|
+
}
|
|
1886
|
+
}
|
|
1880
1887
|
async function defaultHttpProbe(fetch2, url, timeoutMs = 1e4) {
|
|
1881
1888
|
try {
|
|
1882
1889
|
const controller = new AbortController();
|
|
@@ -2118,6 +2125,59 @@ async function fetchUcGoPeerMetadata(args) {
|
|
|
2118
2125
|
`Relay metadata did not become ready after ${attempts} attempts: ${lastError ? lastError : typeof lastPayload === "string" ? lastPayload : JSON.stringify(lastPayload ?? {})}`
|
|
2119
2126
|
);
|
|
2120
2127
|
}
|
|
2128
|
+
async function verifyUcGoPeerReachability(args) {
|
|
2129
|
+
const checks = {};
|
|
2130
|
+
const mappedPorts2 = args.mappedPorts ?? {};
|
|
2131
|
+
const hostIpv4 = args.hostIpv4;
|
|
2132
|
+
const skippedInternalPorts = new Set(
|
|
2133
|
+
(args.skipInternalPorts ?? ["80"]).map((value) => String(value))
|
|
2134
|
+
);
|
|
2135
|
+
const httpProbe = args.httpProbe ?? ((url, timeoutMs) => defaultHttpProbe(args.fetch, url, timeoutMs));
|
|
2136
|
+
if (hostIpv4) {
|
|
2137
|
+
for (const [internalPort, mapping] of Object.entries(mappedPorts2)) {
|
|
2138
|
+
if (skippedInternalPorts.has(String(internalPort))) continue;
|
|
2139
|
+
if (mapping?.tcp === true && mapping?.host) {
|
|
2140
|
+
checks[`tcp:${internalPort}`] = {
|
|
2141
|
+
host: hostIpv4,
|
|
2142
|
+
port: mapping.host,
|
|
2143
|
+
...await args.tcpProbe(
|
|
2144
|
+
hostIpv4,
|
|
2145
|
+
mapping.host,
|
|
2146
|
+
Number(args.tcpTimeoutMs ?? 5e3)
|
|
2147
|
+
)
|
|
2148
|
+
};
|
|
2149
|
+
} else if (mapping?.udp === true && mapping?.host) {
|
|
2150
|
+
checks[`udp:${internalPort}`] = {
|
|
2151
|
+
host: hostIpv4,
|
|
2152
|
+
port: mapping.host,
|
|
2153
|
+
ok: null,
|
|
2154
|
+
note: "UDP mapping published; CI does not perform an application-level UDP handshake probe."
|
|
2155
|
+
};
|
|
2156
|
+
}
|
|
2157
|
+
}
|
|
2158
|
+
}
|
|
2159
|
+
if (args.proxyUrl && args.verifyProxyHttp !== false) {
|
|
2160
|
+
checks["https:proxy"] = await httpProbe(
|
|
2161
|
+
args.proxyUrl,
|
|
2162
|
+
Number(args.httpTimeoutMs ?? 1e4)
|
|
2163
|
+
);
|
|
2164
|
+
}
|
|
2165
|
+
const proxyHostname = proxyHostnameFromUrl(args.proxyUrl);
|
|
2166
|
+
if (proxyHostname) {
|
|
2167
|
+
checks["tcp:proxy-443"] = await args.tcpProbe(
|
|
2168
|
+
proxyHostname,
|
|
2169
|
+
443,
|
|
2170
|
+
Number(args.tcpTimeoutMs ?? 5e3)
|
|
2171
|
+
);
|
|
2172
|
+
}
|
|
2173
|
+
const failedChecks = Object.entries(checks).filter(
|
|
2174
|
+
([, value]) => value?.ok === false
|
|
2175
|
+
);
|
|
2176
|
+
return {
|
|
2177
|
+
ok: failedChecks.length === 0,
|
|
2178
|
+
checks
|
|
2179
|
+
};
|
|
2180
|
+
}
|
|
2121
2181
|
|
|
2122
2182
|
// ../aleph-bootstrap/src/index.ts
|
|
2123
2183
|
import { recoverMessageAddress } from "viem";
|
|
@@ -3218,6 +3278,8 @@ var UI_DEPLOY_WAIT_ATTEMPTS = 60;
|
|
|
3218
3278
|
var UI_DEPLOY_WAIT_DELAY_MS = 5e3;
|
|
3219
3279
|
var UI_RUNTIME_WAIT_ATTEMPTS = 40;
|
|
3220
3280
|
var UI_RUNTIME_WAIT_DELAY_MS = 5e3;
|
|
3281
|
+
var UI_REACHABILITY_VERIFY_ATTEMPTS = 25;
|
|
3282
|
+
var UI_REACHABILITY_VERIFY_DELAY_MS = 3e3;
|
|
3221
3283
|
function hasUsableRuntime(details) {
|
|
3222
3284
|
return Boolean(details.hostIpv4) || Boolean(details.vmIpv4) || details.mappedPorts.length > 0 || Boolean(details.webUrl) || Boolean(details.execution);
|
|
3223
3285
|
}
|
|
@@ -3324,15 +3386,16 @@ var SponsorRelayController = class {
|
|
|
3324
3386
|
this.progressEmitter.emit(nextEvent);
|
|
3325
3387
|
}
|
|
3326
3388
|
async configureRelayBootstrapRegistration(args) {
|
|
3389
|
+
let runtime = args.runtime;
|
|
3327
3390
|
const profile = relayProfileForManifest(this.state.manifest);
|
|
3328
3391
|
if (!profile) return;
|
|
3329
3392
|
if (!this.state.wallet.address) {
|
|
3330
3393
|
throw new Error("A connected wallet is required to register relay bootstrap addresses.");
|
|
3331
3394
|
}
|
|
3332
|
-
if (!
|
|
3395
|
+
if (!runtime.hostIpv4) {
|
|
3333
3396
|
throw new Error("Relay runtime did not expose a host IPv4 address.");
|
|
3334
3397
|
}
|
|
3335
|
-
|
|
3398
|
+
let mappedPorts2 = runtime.mappedPorts ?? {};
|
|
3336
3399
|
const setupPort = mappedPorts2["80"]?.host ?? null;
|
|
3337
3400
|
if (!setupPort) {
|
|
3338
3401
|
throw new Error("Relay runtime did not expose the temporary setup endpoint.");
|
|
@@ -3347,7 +3410,7 @@ var SponsorRelayController = class {
|
|
|
3347
3410
|
detail: "Waiting for the guest setup endpoint before collecting relay metadata."
|
|
3348
3411
|
});
|
|
3349
3412
|
const setupHealth = await waitForSetupEndpoint({
|
|
3350
|
-
hostIpv4:
|
|
3413
|
+
hostIpv4: runtime.hostIpv4,
|
|
3351
3414
|
setupPort,
|
|
3352
3415
|
fetch: (url, init) => fetch(url, init),
|
|
3353
3416
|
attempts: 15,
|
|
@@ -3373,12 +3436,12 @@ var SponsorRelayController = class {
|
|
|
3373
3436
|
throw new Error("OrbitDB relay runtime is missing required mapped TCP/WS ports.");
|
|
3374
3437
|
}
|
|
3375
3438
|
const configureResult = await configureOrbitdbRelaySetup2({
|
|
3376
|
-
hostIpv4:
|
|
3377
|
-
publicIpv6:
|
|
3439
|
+
hostIpv4: runtime.hostIpv4,
|
|
3440
|
+
publicIpv6: runtime.ipv6,
|
|
3378
3441
|
setupPort,
|
|
3379
3442
|
tcpPort,
|
|
3380
3443
|
wsPort,
|
|
3381
|
-
proxyUrl:
|
|
3444
|
+
proxyUrl: runtime.proxyUrl ?? void 0,
|
|
3382
3445
|
metricsPort: mappedPorts2["9090"]?.host ?? null,
|
|
3383
3446
|
metricsHttpsPort: mappedPorts2["443"]?.host ?? null,
|
|
3384
3447
|
webrtcPort: mappedPorts2["9093"]?.host ?? null,
|
|
@@ -3395,6 +3458,59 @@ var SponsorRelayController = class {
|
|
|
3395
3458
|
if (!args.deploymentToken) {
|
|
3396
3459
|
throw new Error("Missing deployment token for Aleph bootstrap config handoff.");
|
|
3397
3460
|
}
|
|
3461
|
+
if (runtime.proxyUrl && runtime.webAccess?.active !== true) {
|
|
3462
|
+
this.emitProgress({
|
|
3463
|
+
stage: "deployment-confirmed",
|
|
3464
|
+
label: "Waiting for HTTPS route",
|
|
3465
|
+
progress: 93,
|
|
3466
|
+
status: "warning",
|
|
3467
|
+
itemHash: args.itemHash,
|
|
3468
|
+
detail: "The relay received a 2n6 hostname, but it is not active yet. Waiting before handing HTTPS config to the guest."
|
|
3469
|
+
});
|
|
3470
|
+
let latestRuntime = runtime;
|
|
3471
|
+
for (let attempt = 0; attempt < UI_RUNTIME_WAIT_ATTEMPTS; attempt += 1) {
|
|
3472
|
+
if (latestRuntime.webAccess?.active === true) {
|
|
3473
|
+
break;
|
|
3474
|
+
}
|
|
3475
|
+
await new Promise(
|
|
3476
|
+
(resolve) => globalThis.setTimeout(resolve, UI_RUNTIME_WAIT_DELAY_MS)
|
|
3477
|
+
);
|
|
3478
|
+
latestRuntime = await fetchVmRuntime({
|
|
3479
|
+
itemHash: args.itemHash,
|
|
3480
|
+
fetch: (url, init) => fetch(url, init),
|
|
3481
|
+
crnHash: runtime.selectedCrn?.hash ?? runtime.allocation?.crnHash ?? void 0,
|
|
3482
|
+
crns: this.state.crns,
|
|
3483
|
+
crnListUrl: this.props.crnListUrl
|
|
3484
|
+
}).catch(() => latestRuntime);
|
|
3485
|
+
this.emitProgress({
|
|
3486
|
+
stage: "deployment-confirmed",
|
|
3487
|
+
label: "Waiting for HTTPS route",
|
|
3488
|
+
progress: 93,
|
|
3489
|
+
status: latestRuntime.webAccess?.active === true ? "info" : "warning",
|
|
3490
|
+
itemHash: args.itemHash,
|
|
3491
|
+
detail: `2n6 activation ${attempt + 1}/${UI_RUNTIME_WAIT_ATTEMPTS}: ${latestRuntime.webAccess?.active === true ? "active" : "still pending"} for ${latestRuntime.proxyUrl ?? runtime.proxyUrl ?? "reserved proxy URL"}.`
|
|
3492
|
+
});
|
|
3493
|
+
this.trace("deploy:bootstrap-proxy-activation", {
|
|
3494
|
+
itemHash: args.itemHash,
|
|
3495
|
+
attempt: attempt + 1,
|
|
3496
|
+
attempts: UI_RUNTIME_WAIT_ATTEMPTS,
|
|
3497
|
+
active: latestRuntime.webAccess?.active === true,
|
|
3498
|
+
proxyUrl: latestRuntime.proxyUrl ?? null
|
|
3499
|
+
});
|
|
3500
|
+
}
|
|
3501
|
+
runtime = latestRuntime;
|
|
3502
|
+
mappedPorts2 = runtime.mappedPorts ?? mappedPorts2;
|
|
3503
|
+
if (runtime.proxyUrl && runtime.webAccess?.active !== true) {
|
|
3504
|
+
throw new Error(
|
|
3505
|
+
"Aleph reserved a 2n6 proxy URL, but it never became active in time. Aborting guest HTTPS configuration to avoid a broken Caddy setup."
|
|
3506
|
+
);
|
|
3507
|
+
}
|
|
3508
|
+
}
|
|
3509
|
+
if (!runtime.hostIpv4) {
|
|
3510
|
+
throw new Error("Relay runtime lost its host IPv4 address while waiting for HTTPS activation.");
|
|
3511
|
+
}
|
|
3512
|
+
const runtimeHostIpv4 = runtime.hostIpv4;
|
|
3513
|
+
const activeProxyUrl = runtime.webAccess?.active === true ? runtime.proxyUrl ?? null : null;
|
|
3398
3514
|
this.emitProgress({
|
|
3399
3515
|
stage: "deployment-confirmed",
|
|
3400
3516
|
label: "Publishing relay config",
|
|
@@ -3412,9 +3528,9 @@ var SponsorRelayController = class {
|
|
|
3412
3528
|
expiresAt: new Date(Date.now() + 30 * 6e4).toISOString(),
|
|
3413
3529
|
status: "pending",
|
|
3414
3530
|
runtime: {
|
|
3415
|
-
publicIpv4:
|
|
3416
|
-
publicIpv6:
|
|
3417
|
-
proxyUrl:
|
|
3531
|
+
publicIpv4: runtimeHostIpv4,
|
|
3532
|
+
publicIpv6: runtime.ipv6 ?? null,
|
|
3533
|
+
proxyUrl: activeProxyUrl,
|
|
3418
3534
|
mappedPorts: mappedPorts2
|
|
3419
3535
|
},
|
|
3420
3536
|
bootstrap: {
|
|
@@ -3480,7 +3596,7 @@ var SponsorRelayController = class {
|
|
|
3480
3596
|
detail: "Waiting for the relay to report its final public multiaddrs."
|
|
3481
3597
|
});
|
|
3482
3598
|
const relayMetadata = await fetchRelayMetadataForRuntime({
|
|
3483
|
-
runtime
|
|
3599
|
+
runtime,
|
|
3484
3600
|
fetch: (url, init) => fetch(url, init),
|
|
3485
3601
|
preferSecureMetadata: profile === "uc-go-peer",
|
|
3486
3602
|
attempts: 80,
|
|
@@ -3513,6 +3629,55 @@ var SponsorRelayController = class {
|
|
|
3513
3629
|
if (!relayMetadata) {
|
|
3514
3630
|
throw new Error("Relay metadata did not include a peer ID and public multiaddrs.");
|
|
3515
3631
|
}
|
|
3632
|
+
if (profile === "uc-go-peer" && runtime.proxyUrl) {
|
|
3633
|
+
this.emitProgress({
|
|
3634
|
+
stage: "publishing-bootstrap",
|
|
3635
|
+
label: "Verifying reachability",
|
|
3636
|
+
progress: 96,
|
|
3637
|
+
status: "info",
|
|
3638
|
+
itemHash: args.itemHash,
|
|
3639
|
+
detail: "Checking that the secure relay endpoint is reachable before trusting the deployment as ready."
|
|
3640
|
+
});
|
|
3641
|
+
const verificationUrl = (() => {
|
|
3642
|
+
try {
|
|
3643
|
+
return new URL("/bootstrap/metadata", runtime.proxyUrl).toString();
|
|
3644
|
+
} catch {
|
|
3645
|
+
return runtime.proxyUrl ?? "";
|
|
3646
|
+
}
|
|
3647
|
+
})();
|
|
3648
|
+
let verificationResult = null;
|
|
3649
|
+
for (let attempt = 0; attempt < UI_REACHABILITY_VERIFY_ATTEMPTS; attempt += 1) {
|
|
3650
|
+
verificationResult = await verifyUcGoPeerReachability({
|
|
3651
|
+
proxyUrl: verificationUrl,
|
|
3652
|
+
verifyProxyHttp: true,
|
|
3653
|
+
fetch: (url, init) => fetch(url, init),
|
|
3654
|
+
tcpProbe: async () => ({ ok: null })
|
|
3655
|
+
});
|
|
3656
|
+
this.trace("deploy:reachability-verification-attempt", {
|
|
3657
|
+
itemHash: args.itemHash,
|
|
3658
|
+
attempt: attempt + 1,
|
|
3659
|
+
attempts: UI_REACHABILITY_VERIFY_ATTEMPTS,
|
|
3660
|
+
verificationUrl,
|
|
3661
|
+
ok: verificationResult.ok,
|
|
3662
|
+
checks: verificationResult.checks
|
|
3663
|
+
});
|
|
3664
|
+
const proxyHttpCheck2 = verificationResult.checks["https:proxy"];
|
|
3665
|
+
if (verificationResult.ok && proxyHttpCheck2?.ok === true) {
|
|
3666
|
+
break;
|
|
3667
|
+
}
|
|
3668
|
+
if (attempt < UI_REACHABILITY_VERIFY_ATTEMPTS - 1) {
|
|
3669
|
+
await new Promise(
|
|
3670
|
+
(resolve) => globalThis.setTimeout(resolve, UI_REACHABILITY_VERIFY_DELAY_MS)
|
|
3671
|
+
);
|
|
3672
|
+
}
|
|
3673
|
+
}
|
|
3674
|
+
const proxyHttpCheck = verificationResult?.checks["https:proxy"];
|
|
3675
|
+
if (!verificationResult?.ok || proxyHttpCheck?.ok !== true) {
|
|
3676
|
+
throw new Error(
|
|
3677
|
+
proxyHttpCheck?.error ? `Secure relay endpoint did not become reachable in time: ${proxyHttpCheck.error}` : "Secure relay endpoint did not become reachable in time."
|
|
3678
|
+
);
|
|
3679
|
+
}
|
|
3680
|
+
}
|
|
3516
3681
|
const { peerId } = relayMetadata;
|
|
3517
3682
|
const registrationId = createRelayBootstrapRegistrationId(
|
|
3518
3683
|
profile,
|
|
@@ -3630,6 +3795,7 @@ var SponsorRelayController = class {
|
|
|
3630
3795
|
const currentProgress = this.state.deploymentProgress;
|
|
3631
3796
|
const currentProgressIsForLatestHash = currentProgress.itemHash === itemHash || currentProgress.itemHash == null && currentProgress.stage !== "idle" && currentProgress.stage !== "error";
|
|
3632
3797
|
const keepTerminalSuccess = this.lastCompletedDeploymentHash === itemHash || currentProgressIsForLatestHash && currentProgress.stage === "completed" && currentProgress.status === "success";
|
|
3798
|
+
const keepSpecificInFlightProgress = currentProgressIsForLatestHash && currentProgress.stage !== "completed" && currentProgress.stage !== "error" && currentProgress.progress >= 93;
|
|
3633
3799
|
const status = latest.details.messageStatus;
|
|
3634
3800
|
if (status === "rejected") {
|
|
3635
3801
|
this.emitProgress({
|
|
@@ -3672,6 +3838,16 @@ var SponsorRelayController = class {
|
|
|
3672
3838
|
});
|
|
3673
3839
|
return;
|
|
3674
3840
|
}
|
|
3841
|
+
if (keepSpecificInFlightProgress) {
|
|
3842
|
+
this.trace("progress:retain-inflight", {
|
|
3843
|
+
reason: "latest refresh would overwrite a more specific in-flight deployment phase",
|
|
3844
|
+
itemHash,
|
|
3845
|
+
currentStage: currentProgress.stage,
|
|
3846
|
+
currentLabel: currentProgress.label,
|
|
3847
|
+
currentProgress: currentProgress.progress
|
|
3848
|
+
});
|
|
3849
|
+
return;
|
|
3850
|
+
}
|
|
3675
3851
|
this.emitProgress({
|
|
3676
3852
|
stage: "deployment-confirmed",
|
|
3677
3853
|
label: "Waiting for runtime",
|
|
@@ -3682,6 +3858,16 @@ var SponsorRelayController = class {
|
|
|
3682
3858
|
});
|
|
3683
3859
|
return;
|
|
3684
3860
|
}
|
|
3861
|
+
if (keepSpecificInFlightProgress) {
|
|
3862
|
+
this.trace("progress:retain-inflight", {
|
|
3863
|
+
reason: "latest refresh would overwrite a more specific in-flight deployment phase",
|
|
3864
|
+
itemHash,
|
|
3865
|
+
currentStage: currentProgress.stage,
|
|
3866
|
+
currentLabel: currentProgress.label,
|
|
3867
|
+
currentProgress: currentProgress.progress
|
|
3868
|
+
});
|
|
3869
|
+
return;
|
|
3870
|
+
}
|
|
3685
3871
|
this.emitProgress({
|
|
3686
3872
|
stage: "deployment-confirmed",
|
|
3687
3873
|
label: "Runtime ready",
|
|
@@ -4312,6 +4498,15 @@ var SponsorRelayController = class {
|
|
|
4312
4498
|
});
|
|
4313
4499
|
if (attemptItemHash) {
|
|
4314
4500
|
if (attemptDeploymentToken) {
|
|
4501
|
+
this.emitProgress({
|
|
4502
|
+
stage: "refreshing-instances",
|
|
4503
|
+
label: "Cleaning up failed attempt",
|
|
4504
|
+
progress: 16,
|
|
4505
|
+
status: "warning",
|
|
4506
|
+
itemHash: attemptItemHash,
|
|
4507
|
+
detail: `Removing bootstrap handoff state for failed deployment on ${attemptLabel}.`,
|
|
4508
|
+
error: lastError.message
|
|
4509
|
+
});
|
|
4315
4510
|
this.trace("deploy:bootstrap-config-cleanup-start", {
|
|
4316
4511
|
itemHash: attemptItemHash,
|
|
4317
4512
|
deploymentToken: attemptDeploymentToken
|
|
@@ -4337,8 +4532,26 @@ var SponsorRelayController = class {
|
|
|
4337
4532
|
deploymentToken: attemptDeploymentToken,
|
|
4338
4533
|
error: cleanupError instanceof Error ? cleanupError.message : String(cleanupError)
|
|
4339
4534
|
});
|
|
4535
|
+
this.emitProgress({
|
|
4536
|
+
stage: "refreshing-instances",
|
|
4537
|
+
label: "Cleanup warning",
|
|
4538
|
+
progress: 16,
|
|
4539
|
+
status: "warning",
|
|
4540
|
+
itemHash: attemptItemHash,
|
|
4541
|
+
detail: `Bootstrap cleanup reported an issue for ${attemptLabel}, but retry cleanup will continue.`,
|
|
4542
|
+
error: cleanupError instanceof Error ? cleanupError.message : String(cleanupError)
|
|
4543
|
+
});
|
|
4340
4544
|
});
|
|
4341
4545
|
}
|
|
4546
|
+
this.emitProgress({
|
|
4547
|
+
stage: "refreshing-instances",
|
|
4548
|
+
label: "Discarding failed deployment",
|
|
4549
|
+
progress: 17,
|
|
4550
|
+
status: "warning",
|
|
4551
|
+
itemHash: attemptItemHash,
|
|
4552
|
+
detail: `Forgetting failed deployment ${attemptItemHash.slice(0, 12)} on ${attemptLabel} before retrying.`,
|
|
4553
|
+
error: lastError.message
|
|
4554
|
+
});
|
|
4342
4555
|
this.trace("deploy:forget-failed-attempt-start", {
|
|
4343
4556
|
itemHash: attemptItemHash,
|
|
4344
4557
|
crnHash: candidateCrn.hash,
|
|
@@ -4361,12 +4574,30 @@ var SponsorRelayController = class {
|
|
|
4361
4574
|
itemHash: attemptItemHash,
|
|
4362
4575
|
error: cleanupError instanceof Error ? cleanupError.message : String(cleanupError)
|
|
4363
4576
|
});
|
|
4577
|
+
this.emitProgress({
|
|
4578
|
+
stage: "refreshing-instances",
|
|
4579
|
+
label: "Cleanup warning",
|
|
4580
|
+
progress: 17,
|
|
4581
|
+
status: "warning",
|
|
4582
|
+
itemHash: attemptItemHash,
|
|
4583
|
+
detail: `Failed deployment cleanup reported an issue for ${attemptLabel}.`,
|
|
4584
|
+
error: cleanupError instanceof Error ? cleanupError.message : String(cleanupError)
|
|
4585
|
+
});
|
|
4364
4586
|
});
|
|
4365
4587
|
this.trace("deploy:forget-failed-attempt-complete", {
|
|
4366
4588
|
itemHash: attemptItemHash,
|
|
4367
4589
|
crnHash: candidateCrn.hash,
|
|
4368
4590
|
crnName: candidateCrn.name
|
|
4369
4591
|
});
|
|
4592
|
+
this.emitProgress({
|
|
4593
|
+
stage: "refreshing-instances",
|
|
4594
|
+
label: "Cleanup complete",
|
|
4595
|
+
progress: 18,
|
|
4596
|
+
status: "info",
|
|
4597
|
+
itemHash: attemptItemHash,
|
|
4598
|
+
detail: `Finished cleaning up failed deployment on ${attemptLabel}.`,
|
|
4599
|
+
error: null
|
|
4600
|
+
});
|
|
4370
4601
|
}
|
|
4371
4602
|
if (candidateIndex < orderedCrns.length - 1) {
|
|
4372
4603
|
this.emitProgress({
|