@le-space/ui 0.3.11 → 0.3.13
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 +635 -130
- package/shared/index.d.ts +1 -1
- package/shared/index.js +635 -130
package/react/index.js
CHANGED
|
@@ -39,7 +39,7 @@ var RECENT_INSTANCE_RUNTIME_GRACE_MS = 10 * 60 * 1e3;
|
|
|
39
39
|
var DEPLOYMENT_PENDING_WARNING_MS = 3 * 60 * 1e3;
|
|
40
40
|
|
|
41
41
|
// src/shared/package-version.ts
|
|
42
|
-
var UI_PACKAGE_VERSION = "0.3.
|
|
42
|
+
var UI_PACKAGE_VERSION = "0.3.13";
|
|
43
43
|
|
|
44
44
|
// src/shared/format.ts
|
|
45
45
|
function shortHash(value, head = 8, tail = 6) {
|
|
@@ -1471,6 +1471,24 @@ function normalizeSshPublicKey(value) {
|
|
|
1471
1471
|
function isValidSshPublicKey(value) {
|
|
1472
1472
|
return SSH_PUBLIC_KEY_PATTERN.test(normalizeSshPublicKey(value));
|
|
1473
1473
|
}
|
|
1474
|
+
function createDeploymentToken() {
|
|
1475
|
+
const randomUuid = globalThis.crypto?.randomUUID?.();
|
|
1476
|
+
if (typeof randomUuid === "string" && randomUuid.trim()) {
|
|
1477
|
+
return randomUuid;
|
|
1478
|
+
}
|
|
1479
|
+
return `deploy-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 12)}`;
|
|
1480
|
+
}
|
|
1481
|
+
function appendDeploymentTokenToSshPublicKey(sshPublicKey, ownerAddress, deploymentToken) {
|
|
1482
|
+
const normalized = normalizeSshPublicKey(sshPublicKey);
|
|
1483
|
+
if (!normalized) return normalized;
|
|
1484
|
+
const [algorithm = "", key = ""] = normalized.split(/\s+/, 3);
|
|
1485
|
+
const owner = ownerAddress.trim().toLowerCase();
|
|
1486
|
+
const token = deploymentToken.trim();
|
|
1487
|
+
if (!algorithm || !key || !owner || !token) {
|
|
1488
|
+
return normalized;
|
|
1489
|
+
}
|
|
1490
|
+
return `${algorithm} ${key} aleph-bootstrap-config:${owner}:${token}`;
|
|
1491
|
+
}
|
|
1474
1492
|
function createReleaseMetadata(name, rootfsVersion, deployer = "shared-aleph-tooling") {
|
|
1475
1493
|
return {
|
|
1476
1494
|
name,
|
|
@@ -2009,51 +2027,6 @@ async function waitForSetupEndpoint(args) {
|
|
|
2009
2027
|
}
|
|
2010
2028
|
return result;
|
|
2011
2029
|
}
|
|
2012
|
-
async function configureUcGoPeer(args) {
|
|
2013
|
-
const controller = new AbortController();
|
|
2014
|
-
const timeout = setTimeout(
|
|
2015
|
-
() => controller.abort(),
|
|
2016
|
-
Number(args.timeoutMs ?? 18e4)
|
|
2017
|
-
);
|
|
2018
|
-
const payload = {
|
|
2019
|
-
public_ipv4: args.hostIpv4,
|
|
2020
|
-
public_ipv6: args.publicIpv6 ?? void 0,
|
|
2021
|
-
proxy_url: args.proxyUrl ?? void 0,
|
|
2022
|
-
tcp_port: args.tcpPort ?? void 0,
|
|
2023
|
-
ws_port: args.wsPort ?? void 0,
|
|
2024
|
-
udp_port: args.udpPort ?? void 0,
|
|
2025
|
-
quic_port: args.quicPort ?? void 0,
|
|
2026
|
-
webrtc_port: args.webrtcPort ?? void 0,
|
|
2027
|
-
bootstrap_publisher_private_key: args.bootstrapPublisherPrivateKey ?? void 0,
|
|
2028
|
-
bootstrap_publisher_libp2p_identity_b64: args.bootstrapPublisherLibp2pIdentityBase64 ?? void 0,
|
|
2029
|
-
bootstrap_owner_private_key: args.bootstrapOwnerPrivateKey ?? void 0,
|
|
2030
|
-
bootstrap_owner_authorization_b64: args.bootstrapOwnerAuthorizationBase64 ?? void 0,
|
|
2031
|
-
bootstrap_registration_id: args.bootstrapRegistrationId ?? void 0,
|
|
2032
|
-
no_start: args.noStart === true ? true : void 0
|
|
2033
|
-
};
|
|
2034
|
-
try {
|
|
2035
|
-
const response = await args.fetch(
|
|
2036
|
-
`http://${args.hostIpv4}:${args.setupPort}/configure`,
|
|
2037
|
-
{
|
|
2038
|
-
method: "POST",
|
|
2039
|
-
headers: {
|
|
2040
|
-
"content-type": "application/json"
|
|
2041
|
-
},
|
|
2042
|
-
body: JSON.stringify(payload),
|
|
2043
|
-
signal: controller.signal
|
|
2044
|
-
}
|
|
2045
|
-
);
|
|
2046
|
-
const responsePayload = await response.json().catch(() => null);
|
|
2047
|
-
if (!response.ok) {
|
|
2048
|
-
throw new Error(
|
|
2049
|
-
`Relay setup request failed: ${response.status} ${typeof responsePayload === "string" ? responsePayload : JSON.stringify(responsePayload ?? {})}`
|
|
2050
|
-
);
|
|
2051
|
-
}
|
|
2052
|
-
return responsePayload;
|
|
2053
|
-
} finally {
|
|
2054
|
-
clearTimeout(timeout);
|
|
2055
|
-
}
|
|
2056
|
-
}
|
|
2057
2030
|
async function configureOrbitdbRelaySetup2(args) {
|
|
2058
2031
|
const controller = new AbortController();
|
|
2059
2032
|
const timeout = setTimeout(
|
|
@@ -2111,24 +2084,30 @@ async function fetchUcGoPeerMetadata(args) {
|
|
|
2111
2084
|
() => controller.abort(),
|
|
2112
2085
|
Number(args.timeoutMs ?? 18e4)
|
|
2113
2086
|
);
|
|
2087
|
+
const requestUrl = args.metadataUrl && args.metadataUrl.trim() ? args.metadataUrl : `http://${args.hostIpv4}:${args.setupPort}/metadata`;
|
|
2114
2088
|
try {
|
|
2115
2089
|
const response = await args.fetch(
|
|
2116
|
-
|
|
2090
|
+
requestUrl,
|
|
2117
2091
|
{
|
|
2118
2092
|
signal: controller.signal
|
|
2119
2093
|
}
|
|
2120
2094
|
);
|
|
2121
2095
|
const payload = await response.json().catch(() => null);
|
|
2122
2096
|
lastPayload = payload;
|
|
2123
|
-
|
|
2124
|
-
payload
|
|
2125
|
-
Boolean(
|
|
2126
|
-
response.ok && payload && typeof payload === "object" && payload.status === "ready"
|
|
2127
|
-
),
|
|
2128
|
-
attempt + 1,
|
|
2129
|
-
attempts
|
|
2097
|
+
const ready = Boolean(
|
|
2098
|
+
response.ok && payload && typeof payload === "object" && payload.status === "ready"
|
|
2130
2099
|
);
|
|
2131
|
-
|
|
2100
|
+
args.onAttempt?.({
|
|
2101
|
+
payload,
|
|
2102
|
+
ready,
|
|
2103
|
+
attempt: attempt + 1,
|
|
2104
|
+
attempts,
|
|
2105
|
+
requestUrl,
|
|
2106
|
+
ok: response.ok,
|
|
2107
|
+
status: response.status,
|
|
2108
|
+
error: null
|
|
2109
|
+
});
|
|
2110
|
+
if (ready) {
|
|
2132
2111
|
return payload;
|
|
2133
2112
|
}
|
|
2134
2113
|
if (response.status >= 500) {
|
|
@@ -2136,6 +2115,18 @@ async function fetchUcGoPeerMetadata(args) {
|
|
|
2136
2115
|
`Relay metadata request failed: ${response.status} ${typeof payload === "string" ? payload : JSON.stringify(payload ?? {})}`
|
|
2137
2116
|
);
|
|
2138
2117
|
}
|
|
2118
|
+
} catch (error) {
|
|
2119
|
+
args.onAttempt?.({
|
|
2120
|
+
payload: null,
|
|
2121
|
+
ready: false,
|
|
2122
|
+
attempt: attempt + 1,
|
|
2123
|
+
attempts,
|
|
2124
|
+
requestUrl,
|
|
2125
|
+
ok: false,
|
|
2126
|
+
status: null,
|
|
2127
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2128
|
+
});
|
|
2129
|
+
throw error;
|
|
2139
2130
|
} finally {
|
|
2140
2131
|
clearTimeout(timeout);
|
|
2141
2132
|
}
|
|
@@ -2195,6 +2186,9 @@ function asNumber4(value) {
|
|
|
2195
2186
|
function normalizeHost(host) {
|
|
2196
2187
|
return host.trim().toLowerCase();
|
|
2197
2188
|
}
|
|
2189
|
+
function normalizeAddress(address) {
|
|
2190
|
+
return address.trim().toLowerCase();
|
|
2191
|
+
}
|
|
2198
2192
|
function normalizeSignature(signature) {
|
|
2199
2193
|
const trimmed = signature.trim();
|
|
2200
2194
|
return trimmed.startsWith("0x") ? trimmed : `0x${trimmed}`;
|
|
@@ -2496,6 +2490,40 @@ async function fetchAlephBootstrapPosts(options = {}) {
|
|
|
2496
2490
|
const payload = await response.json();
|
|
2497
2491
|
return (payload.posts ?? []).map((entry) => normalizeRelayBootstrapPostRecord(entry)).filter((entry) => entry != null);
|
|
2498
2492
|
}
|
|
2493
|
+
function compareRelayBootstrapPostRecency(left, right) {
|
|
2494
|
+
const leftUpdatedAt = left.content?.updatedAt ?? 0;
|
|
2495
|
+
const rightUpdatedAt = right.content?.updatedAt ?? 0;
|
|
2496
|
+
if (leftUpdatedAt !== rightUpdatedAt) return leftUpdatedAt - rightUpdatedAt;
|
|
2497
|
+
const leftTime = left.time ?? 0;
|
|
2498
|
+
const rightTime = right.time ?? 0;
|
|
2499
|
+
return leftTime - rightTime;
|
|
2500
|
+
}
|
|
2501
|
+
function relayBootstrapRecordIdentity(post) {
|
|
2502
|
+
const content = post.content;
|
|
2503
|
+
if (!content) return null;
|
|
2504
|
+
if (content.registrationId) return `registration:${content.registrationId}`;
|
|
2505
|
+
if (post.address) return `sender:${normalizeAddress(post.address)}`;
|
|
2506
|
+
return content.peerId ? `peer:${content.peerId}` : null;
|
|
2507
|
+
}
|
|
2508
|
+
function selectCurrentRelayBootstrapPosts(posts, options = {}) {
|
|
2509
|
+
const maxAgeMs = options.maxAgeMs ?? DEFAULT_BOOTSTRAP_MAX_AGE_MS;
|
|
2510
|
+
const now = options.now ?? Date.now();
|
|
2511
|
+
const selected = /* @__PURE__ */ new Map();
|
|
2512
|
+
for (const post of posts) {
|
|
2513
|
+
const content = post.content;
|
|
2514
|
+
if (!content) continue;
|
|
2515
|
+
if (now - content.updatedAt > maxAgeMs) continue;
|
|
2516
|
+
const identity = relayBootstrapRecordIdentity(post);
|
|
2517
|
+
if (!identity) continue;
|
|
2518
|
+
const previous = selected.get(identity);
|
|
2519
|
+
if (!previous || compareRelayBootstrapPostRecency(post, previous) > 0) {
|
|
2520
|
+
selected.set(identity, post);
|
|
2521
|
+
}
|
|
2522
|
+
}
|
|
2523
|
+
return [...selected.values()].sort(
|
|
2524
|
+
(left, right) => compareRelayBootstrapPostRecency(right, left)
|
|
2525
|
+
);
|
|
2526
|
+
}
|
|
2499
2527
|
|
|
2500
2528
|
// ../core/src/bootstrap-registration.ts
|
|
2501
2529
|
async function publishRelayBootstrapRegistration(args) {
|
|
@@ -2602,6 +2630,319 @@ async function publishRelayBootstrapRegistration(args) {
|
|
|
2602
2630
|
};
|
|
2603
2631
|
}
|
|
2604
2632
|
|
|
2633
|
+
// ../core/src/bootstrap-config.ts
|
|
2634
|
+
var VM_BOOTSTRAP_CONFIG_AGGREGATE_KEY = "vm-bootstrap-config";
|
|
2635
|
+
async function fetchVmBootstrapConfigAggregate(address, options) {
|
|
2636
|
+
const requestUrl = new URL(`/api/v0/aggregates/${address}.json`, options.apiHost ?? DEFAULT_ALEPH_API_HOST2);
|
|
2637
|
+
requestUrl.searchParams.set("keys", VM_BOOTSTRAP_CONFIG_AGGREGATE_KEY);
|
|
2638
|
+
const response = await options.fetch(requestUrl.toString(), { cache: "no-cache" });
|
|
2639
|
+
if (response.status === 404) return {};
|
|
2640
|
+
if (!response.ok) {
|
|
2641
|
+
throw new Error(`VM bootstrap config aggregate request failed: ${response.status}`);
|
|
2642
|
+
}
|
|
2643
|
+
const payload = await response.json();
|
|
2644
|
+
const aggregate = payload.data?.[VM_BOOTSTRAP_CONFIG_AGGREGATE_KEY];
|
|
2645
|
+
if (!aggregate || typeof aggregate !== "object" || Array.isArray(aggregate)) return {};
|
|
2646
|
+
return aggregate;
|
|
2647
|
+
}
|
|
2648
|
+
function normalizeVmBootstrapConfigAggregate(aggregate) {
|
|
2649
|
+
if (!aggregate || typeof aggregate !== "object") return {};
|
|
2650
|
+
return Object.fromEntries(
|
|
2651
|
+
Object.entries(aggregate).filter(
|
|
2652
|
+
(entry) => Boolean(entry[1] && typeof entry[1] === "object" && !Array.isArray(entry[1]))
|
|
2653
|
+
)
|
|
2654
|
+
);
|
|
2655
|
+
}
|
|
2656
|
+
function createVmBootstrapConfigAggregateContent(args) {
|
|
2657
|
+
const content = normalizeVmBootstrapConfigAggregate(args.existingAggregate);
|
|
2658
|
+
content[args.record.deploymentToken] = args.record;
|
|
2659
|
+
return {
|
|
2660
|
+
address: args.sender,
|
|
2661
|
+
key: VM_BOOTSTRAP_CONFIG_AGGREGATE_KEY,
|
|
2662
|
+
content,
|
|
2663
|
+
time: args.now ?? Date.now() / 1e3
|
|
2664
|
+
};
|
|
2665
|
+
}
|
|
2666
|
+
async function createUnsignedVmBootstrapConfigAggregateMessage(args) {
|
|
2667
|
+
const itemContent = JSON.stringify(args.content);
|
|
2668
|
+
const itemHash = await args.hasher(itemContent);
|
|
2669
|
+
return {
|
|
2670
|
+
sender: args.sender,
|
|
2671
|
+
chain: "ETH",
|
|
2672
|
+
type: "AGGREGATE",
|
|
2673
|
+
item_hash: itemHash,
|
|
2674
|
+
item_type: "inline",
|
|
2675
|
+
item_content: itemContent,
|
|
2676
|
+
time: args.now ?? Date.now() / 1e3,
|
|
2677
|
+
channel: args.channel ?? DEFAULT_ALEPH_CHANNEL
|
|
2678
|
+
};
|
|
2679
|
+
}
|
|
2680
|
+
async function publishVmBootstrapConfigAggregate(args) {
|
|
2681
|
+
const unsignedMessage = await createUnsignedVmBootstrapConfigAggregateMessage({
|
|
2682
|
+
sender: args.sender,
|
|
2683
|
+
content: args.content,
|
|
2684
|
+
hasher: args.hasher,
|
|
2685
|
+
channel: args.channel
|
|
2686
|
+
});
|
|
2687
|
+
const message = await signAlephMessage(unsignedMessage, args.signer);
|
|
2688
|
+
const { response, httpStatus } = await broadcastAlephMessage2(message, {
|
|
2689
|
+
apiHost: args.apiHost,
|
|
2690
|
+
sync: args.sync,
|
|
2691
|
+
fetch: args.fetch
|
|
2692
|
+
});
|
|
2693
|
+
const aggregateStatus = httpStatus >= 200 && httpStatus < 300 ? response.message_status ?? "processed" : "unknown";
|
|
2694
|
+
if (aggregateStatus === "rejected") {
|
|
2695
|
+
throw new Error(`VM bootstrap config aggregate was rejected by Aleph: ${JSON.stringify(response.details ?? response)}`);
|
|
2696
|
+
}
|
|
2697
|
+
return {
|
|
2698
|
+
aggregateItemHash: message.item_hash,
|
|
2699
|
+
aggregateStatus
|
|
2700
|
+
};
|
|
2701
|
+
}
|
|
2702
|
+
async function publishVmBootstrapConfig(args) {
|
|
2703
|
+
const aggregate = await fetchVmBootstrapConfigAggregate(args.sender, {
|
|
2704
|
+
apiHost: args.apiHost,
|
|
2705
|
+
fetch: args.fetch
|
|
2706
|
+
});
|
|
2707
|
+
const content = createVmBootstrapConfigAggregateContent({
|
|
2708
|
+
sender: args.sender,
|
|
2709
|
+
record: args.record,
|
|
2710
|
+
existingAggregate: aggregate
|
|
2711
|
+
});
|
|
2712
|
+
const result = await publishVmBootstrapConfigAggregate({
|
|
2713
|
+
sender: args.sender,
|
|
2714
|
+
content,
|
|
2715
|
+
signer: args.signer,
|
|
2716
|
+
hasher: args.hasher,
|
|
2717
|
+
fetch: args.fetch,
|
|
2718
|
+
channel: args.channel,
|
|
2719
|
+
apiHost: args.apiHost,
|
|
2720
|
+
sync: args.sync
|
|
2721
|
+
});
|
|
2722
|
+
return {
|
|
2723
|
+
...result,
|
|
2724
|
+
aggregate: content.content
|
|
2725
|
+
};
|
|
2726
|
+
}
|
|
2727
|
+
async function deleteVmBootstrapConfig(args) {
|
|
2728
|
+
const aggregate = await fetchVmBootstrapConfigAggregate(args.sender, {
|
|
2729
|
+
apiHost: args.apiHost,
|
|
2730
|
+
fetch: args.fetch
|
|
2731
|
+
});
|
|
2732
|
+
const content = normalizeVmBootstrapConfigAggregate(aggregate);
|
|
2733
|
+
delete content[args.deploymentToken];
|
|
2734
|
+
const publishResult = await publishVmBootstrapConfigAggregate({
|
|
2735
|
+
sender: args.sender,
|
|
2736
|
+
content: {
|
|
2737
|
+
address: args.sender,
|
|
2738
|
+
key: VM_BOOTSTRAP_CONFIG_AGGREGATE_KEY,
|
|
2739
|
+
content,
|
|
2740
|
+
time: Date.now() / 1e3
|
|
2741
|
+
},
|
|
2742
|
+
signer: args.signer,
|
|
2743
|
+
hasher: args.hasher,
|
|
2744
|
+
fetch: args.fetch,
|
|
2745
|
+
channel: args.channel,
|
|
2746
|
+
apiHost: args.apiHost,
|
|
2747
|
+
sync: args.sync
|
|
2748
|
+
});
|
|
2749
|
+
return {
|
|
2750
|
+
...publishResult,
|
|
2751
|
+
aggregate: content
|
|
2752
|
+
};
|
|
2753
|
+
}
|
|
2754
|
+
|
|
2755
|
+
// ../core/src/bootstrap-reconcile.ts
|
|
2756
|
+
function createRelayBootstrapRegistrationId(profile, instanceName, itemHash) {
|
|
2757
|
+
const normalizedName = String(instanceName ?? "").trim();
|
|
2758
|
+
const normalizedHash = String(itemHash ?? "").trim();
|
|
2759
|
+
if (!normalizedHash) {
|
|
2760
|
+
return `relay:${profile}:${normalizedName || "instance"}`;
|
|
2761
|
+
}
|
|
2762
|
+
return `relay:${profile}:${normalizedName || normalizedHash}:${normalizedHash}`;
|
|
2763
|
+
}
|
|
2764
|
+
function secureBootstrapMetadataUrl(proxyUrl) {
|
|
2765
|
+
const normalized = String(proxyUrl ?? "").trim();
|
|
2766
|
+
if (!normalized) return null;
|
|
2767
|
+
try {
|
|
2768
|
+
return new URL("/bootstrap/metadata", normalized).toString();
|
|
2769
|
+
} catch {
|
|
2770
|
+
return null;
|
|
2771
|
+
}
|
|
2772
|
+
}
|
|
2773
|
+
function extractRelayMetadata(payload) {
|
|
2774
|
+
const metadata = payload && typeof payload === "object" && payload.metadata && typeof payload.metadata === "object" ? payload.metadata : null;
|
|
2775
|
+
const peerId = typeof metadata?.peer_id === "string" ? metadata.peer_id : null;
|
|
2776
|
+
const probeMultiaddrs = Array.isArray(metadata?.probe_multiaddrs) ? metadata.probe_multiaddrs.filter((entry) => typeof entry === "string") : [];
|
|
2777
|
+
const browserBootstrapMultiaddrs = Array.isArray(metadata?.browser_bootstrap_multiaddrs) ? metadata.browser_bootstrap_multiaddrs.filter((entry) => typeof entry === "string") : [];
|
|
2778
|
+
if (!peerId || probeMultiaddrs.length === 0) return null;
|
|
2779
|
+
return {
|
|
2780
|
+
peerId,
|
|
2781
|
+
probeMultiaddrs,
|
|
2782
|
+
browserBootstrapMultiaddrs
|
|
2783
|
+
};
|
|
2784
|
+
}
|
|
2785
|
+
async function fetchOwnerInstances(address, options) {
|
|
2786
|
+
const url = new URL("/api/v0/messages.json", options.apiHost ?? DEFAULT_ALEPH_API_HOST2);
|
|
2787
|
+
url.searchParams.set("msgTypes", "INSTANCE");
|
|
2788
|
+
url.searchParams.set("addresses", address);
|
|
2789
|
+
url.searchParams.set("message_statuses", "processed,pending,rejected,removing");
|
|
2790
|
+
url.searchParams.set("pagination", "100");
|
|
2791
|
+
url.searchParams.set("page", "1");
|
|
2792
|
+
url.searchParams.set("sortOrder", "-1");
|
|
2793
|
+
const response = await options.fetch(url.toString(), { cache: "no-cache" });
|
|
2794
|
+
if (!response.ok) {
|
|
2795
|
+
throw new Error(`Instance list request failed: ${response.status}`);
|
|
2796
|
+
}
|
|
2797
|
+
const payload = await response.json();
|
|
2798
|
+
return (payload.messages ?? []).map((message) => ({
|
|
2799
|
+
...message,
|
|
2800
|
+
status: typeof message.status === "string" && message.status.trim() ? message.status : message.confirmed ? "processed" : "pending"
|
|
2801
|
+
}));
|
|
2802
|
+
}
|
|
2803
|
+
async function fetchRelayMetadataForRuntime(args) {
|
|
2804
|
+
const setupPort = args.runtime.mappedPorts?.["80"]?.host ?? 80;
|
|
2805
|
+
const metadataUrl = args.preferSecureMetadata ? secureBootstrapMetadataUrl(args.runtime.proxyUrl) : null;
|
|
2806
|
+
if (args.preferSecureMetadata && !metadataUrl) {
|
|
2807
|
+
return null;
|
|
2808
|
+
}
|
|
2809
|
+
const payload = await fetchUcGoPeerMetadata({
|
|
2810
|
+
hostIpv4: args.runtime.hostIpv4 ?? "",
|
|
2811
|
+
setupPort,
|
|
2812
|
+
metadataUrl,
|
|
2813
|
+
fetch: args.fetch,
|
|
2814
|
+
attempts: args.attempts,
|
|
2815
|
+
delayMs: args.delayMs,
|
|
2816
|
+
timeoutMs: args.timeoutMs,
|
|
2817
|
+
onAttempt: (result) => {
|
|
2818
|
+
args.onAttempt?.({
|
|
2819
|
+
...result,
|
|
2820
|
+
metadataUrl,
|
|
2821
|
+
hostIpv4: args.runtime.hostIpv4 ?? null,
|
|
2822
|
+
setupPort
|
|
2823
|
+
});
|
|
2824
|
+
}
|
|
2825
|
+
}).catch(() => null);
|
|
2826
|
+
return extractRelayMetadata(payload);
|
|
2827
|
+
}
|
|
2828
|
+
async function reconcileOwnerRelayBootstrapRegistrations(args) {
|
|
2829
|
+
const result = {
|
|
2830
|
+
refreshedRegistrations: [],
|
|
2831
|
+
forgottenHashes: [],
|
|
2832
|
+
skippedInstanceHashes: [],
|
|
2833
|
+
errors: []
|
|
2834
|
+
};
|
|
2835
|
+
const liveRegistrationIds = /* @__PURE__ */ new Set();
|
|
2836
|
+
if (args.current?.registrationId) {
|
|
2837
|
+
liveRegistrationIds.add(args.current.registrationId);
|
|
2838
|
+
result.refreshedRegistrations.push(args.current.registrationId);
|
|
2839
|
+
}
|
|
2840
|
+
const instances = await fetchOwnerInstances(args.instanceOwnerAddress, {
|
|
2841
|
+
apiHost: args.apiHost,
|
|
2842
|
+
fetch: args.fetch
|
|
2843
|
+
});
|
|
2844
|
+
const processedInstances = instances.filter((instance) => {
|
|
2845
|
+
const status = String(instance.status ?? "").trim().toLowerCase();
|
|
2846
|
+
return status === "processed";
|
|
2847
|
+
});
|
|
2848
|
+
for (const instance of processedInstances) {
|
|
2849
|
+
if (instance.item_hash === args.current?.itemHash) continue;
|
|
2850
|
+
const registrationId = createRelayBootstrapRegistrationId(
|
|
2851
|
+
args.profile,
|
|
2852
|
+
instance.content?.metadata?.name,
|
|
2853
|
+
instance.item_hash
|
|
2854
|
+
);
|
|
2855
|
+
try {
|
|
2856
|
+
const runtime = await fetchVmRuntime({
|
|
2857
|
+
itemHash: instance.item_hash,
|
|
2858
|
+
fetch: args.fetch,
|
|
2859
|
+
crns: args.crns,
|
|
2860
|
+
crnListUrl: args.crnListUrl
|
|
2861
|
+
});
|
|
2862
|
+
if (!runtime.hostIpv4 || Object.keys(runtime.mappedPorts ?? {}).length === 0) {
|
|
2863
|
+
result.skippedInstanceHashes.push(instance.item_hash);
|
|
2864
|
+
continue;
|
|
2865
|
+
}
|
|
2866
|
+
const relayMetadata = await fetchRelayMetadataForRuntime({
|
|
2867
|
+
runtime,
|
|
2868
|
+
fetch: args.fetch,
|
|
2869
|
+
preferSecureMetadata: args.preferSecureMetadata,
|
|
2870
|
+
attempts: 3,
|
|
2871
|
+
delayMs: 1e3,
|
|
2872
|
+
timeoutMs: 1e4
|
|
2873
|
+
});
|
|
2874
|
+
if (!relayMetadata) {
|
|
2875
|
+
result.skippedInstanceHashes.push(instance.item_hash);
|
|
2876
|
+
continue;
|
|
2877
|
+
}
|
|
2878
|
+
liveRegistrationIds.add(registrationId);
|
|
2879
|
+
await publishRelayBootstrapRegistration({
|
|
2880
|
+
sender: args.sender,
|
|
2881
|
+
signer: args.signer,
|
|
2882
|
+
hasher: args.hasher,
|
|
2883
|
+
fetch: args.fetch,
|
|
2884
|
+
apiHost: args.apiHost,
|
|
2885
|
+
channel: args.channel,
|
|
2886
|
+
ref: args.ref,
|
|
2887
|
+
postType: args.postType,
|
|
2888
|
+
peerId: relayMetadata.peerId,
|
|
2889
|
+
multiaddrs: relayMetadata.probeMultiaddrs,
|
|
2890
|
+
browserMultiaddrs: relayMetadata.browserBootstrapMultiaddrs,
|
|
2891
|
+
registrationId,
|
|
2892
|
+
ownerAddress: args.ownerAddress,
|
|
2893
|
+
publisherAddress: args.publisherAddress,
|
|
2894
|
+
ownerSigner: args.ownerSigner,
|
|
2895
|
+
publisherSigner: args.publisherSigner,
|
|
2896
|
+
forgetPrevious: true,
|
|
2897
|
+
profile: args.profile,
|
|
2898
|
+
version: args.version,
|
|
2899
|
+
instanceItemHash: instance.item_hash,
|
|
2900
|
+
sync: true
|
|
2901
|
+
});
|
|
2902
|
+
result.refreshedRegistrations.push(registrationId);
|
|
2903
|
+
} catch (error) {
|
|
2904
|
+
result.errors.push({
|
|
2905
|
+
phase: "publish",
|
|
2906
|
+
itemHash: instance.item_hash,
|
|
2907
|
+
registrationId,
|
|
2908
|
+
message: error instanceof Error ? error.message : String(error)
|
|
2909
|
+
});
|
|
2910
|
+
}
|
|
2911
|
+
}
|
|
2912
|
+
try {
|
|
2913
|
+
const bootstrapPosts = await fetchAlephBootstrapPosts({
|
|
2914
|
+
apiHost: args.apiHost ?? DEFAULT_ALEPH_API_HOST2,
|
|
2915
|
+
channel: args.channel,
|
|
2916
|
+
ref: args.ref,
|
|
2917
|
+
postType: args.postType,
|
|
2918
|
+
fetch: args.fetch
|
|
2919
|
+
});
|
|
2920
|
+
const currentPosts = selectCurrentRelayBootstrapPosts(bootstrapPosts);
|
|
2921
|
+
const staleHashes = currentPosts.filter(
|
|
2922
|
+
(post) => post.address?.toLowerCase() === args.sender.toLowerCase() && post.content?.profile === args.profile && post.content?.registrationId && !liveRegistrationIds.has(post.content.registrationId)
|
|
2923
|
+
).map((post) => post.itemHash ?? post.hash ?? "").filter(Boolean);
|
|
2924
|
+
if (staleHashes.length > 0) {
|
|
2925
|
+
await forgetAlephMessages({
|
|
2926
|
+
sender: args.sender,
|
|
2927
|
+
hashes: staleHashes,
|
|
2928
|
+
reason: `Forget stale ${args.profile} relay bootstrap registrations after owner reconcile`,
|
|
2929
|
+
signer: args.signer,
|
|
2930
|
+
hasher: args.hasher,
|
|
2931
|
+
fetch: args.fetch,
|
|
2932
|
+
apiHost: args.apiHost ?? DEFAULT_ALEPH_API_HOST2,
|
|
2933
|
+
sync: true
|
|
2934
|
+
});
|
|
2935
|
+
result.forgottenHashes.push(...staleHashes);
|
|
2936
|
+
}
|
|
2937
|
+
} catch (error) {
|
|
2938
|
+
result.errors.push({
|
|
2939
|
+
phase: "forget",
|
|
2940
|
+
message: error instanceof Error ? error.message : String(error)
|
|
2941
|
+
});
|
|
2942
|
+
}
|
|
2943
|
+
return result;
|
|
2944
|
+
}
|
|
2945
|
+
|
|
2605
2946
|
// src/shared/events.ts
|
|
2606
2947
|
function createDeploymentProgressEmitter() {
|
|
2607
2948
|
const listeners = /* @__PURE__ */ new Set();
|
|
@@ -2622,6 +2963,13 @@ function createDeploymentProgressEmitter() {
|
|
|
2622
2963
|
}
|
|
2623
2964
|
|
|
2624
2965
|
// src/shared/controller.ts
|
|
2966
|
+
function asJsonFetch(input, init) {
|
|
2967
|
+
return fetch(input, init).then(async (response) => ({
|
|
2968
|
+
ok: response.ok,
|
|
2969
|
+
status: response.status,
|
|
2970
|
+
json: async () => await response.json()
|
|
2971
|
+
}));
|
|
2972
|
+
}
|
|
2625
2973
|
function isConfirmedRelaySetupResult(value) {
|
|
2626
2974
|
return Boolean(
|
|
2627
2975
|
value && typeof value === "object" && "status" in value && value.status === "configured"
|
|
@@ -3064,36 +3412,36 @@ var SponsorRelayController = class {
|
|
|
3064
3412
|
if (!setupPort) {
|
|
3065
3413
|
throw new Error("Relay runtime did not expose the temporary setup endpoint.");
|
|
3066
3414
|
}
|
|
3067
|
-
this.emitProgress({
|
|
3068
|
-
stage: "deployment-confirmed",
|
|
3069
|
-
label: "Configuring relay",
|
|
3070
|
-
progress: 93,
|
|
3071
|
-
status: "info",
|
|
3072
|
-
itemHash: args.itemHash,
|
|
3073
|
-
detail: "Waiting for the guest setup endpoint before collecting relay metadata."
|
|
3074
|
-
});
|
|
3075
|
-
const setupHealth = await waitForSetupEndpoint({
|
|
3076
|
-
hostIpv4: args.runtime.hostIpv4,
|
|
3077
|
-
setupPort,
|
|
3078
|
-
fetch: (url, init) => fetch(url, init),
|
|
3079
|
-
attempts: 15,
|
|
3080
|
-
delayMs: 4e3,
|
|
3081
|
-
httpTimeoutMs: 1e4
|
|
3082
|
-
});
|
|
3083
|
-
if (!setupHealth.ok) {
|
|
3084
|
-
throw new Error(
|
|
3085
|
-
`Relay setup endpoint did not become reachable at http://${args.runtime.hostIpv4}:${setupPort}/health.`
|
|
3086
|
-
);
|
|
3087
|
-
}
|
|
3088
|
-
this.emitProgress({
|
|
3089
|
-
stage: "deployment-confirmed",
|
|
3090
|
-
label: "Applying relay networking",
|
|
3091
|
-
progress: 94,
|
|
3092
|
-
status: "info",
|
|
3093
|
-
itemHash: args.itemHash,
|
|
3094
|
-
detail: "Publishing the host port mapping into the guest relay configuration."
|
|
3095
|
-
});
|
|
3096
3415
|
if (profile === "orbitdb-relay-pinner") {
|
|
3416
|
+
this.emitProgress({
|
|
3417
|
+
stage: "deployment-confirmed",
|
|
3418
|
+
label: "Configuring relay",
|
|
3419
|
+
progress: 93,
|
|
3420
|
+
status: "info",
|
|
3421
|
+
itemHash: args.itemHash,
|
|
3422
|
+
detail: "Waiting for the guest setup endpoint before collecting relay metadata."
|
|
3423
|
+
});
|
|
3424
|
+
const setupHealth = await waitForSetupEndpoint({
|
|
3425
|
+
hostIpv4: args.runtime.hostIpv4,
|
|
3426
|
+
setupPort,
|
|
3427
|
+
fetch: (url, init) => fetch(url, init),
|
|
3428
|
+
attempts: 15,
|
|
3429
|
+
delayMs: 4e3,
|
|
3430
|
+
httpTimeoutMs: 1e4
|
|
3431
|
+
});
|
|
3432
|
+
if (!setupHealth.ok) {
|
|
3433
|
+
throw new Error(
|
|
3434
|
+
`Relay setup endpoint did not become reachable at http://${args.runtime.hostIpv4}:${setupPort}/health.`
|
|
3435
|
+
);
|
|
3436
|
+
}
|
|
3437
|
+
this.emitProgress({
|
|
3438
|
+
stage: "deployment-confirmed",
|
|
3439
|
+
label: "Applying relay networking",
|
|
3440
|
+
progress: 94,
|
|
3441
|
+
status: "info",
|
|
3442
|
+
itemHash: args.itemHash,
|
|
3443
|
+
detail: "Publishing the host port mapping into the guest relay configuration."
|
|
3444
|
+
});
|
|
3097
3445
|
const tcpPort = mappedPorts2["9091"]?.host ?? 0;
|
|
3098
3446
|
const wsPort = mappedPorts2["9092"]?.host ?? mappedPorts2["443"]?.host ?? 0;
|
|
3099
3447
|
if (!tcpPort || !wsPort) {
|
|
@@ -3119,24 +3467,57 @@ var SponsorRelayController = class {
|
|
|
3119
3467
|
);
|
|
3120
3468
|
}
|
|
3121
3469
|
} else {
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
publicIpv6: args.runtime.ipv6,
|
|
3125
|
-
setupPort,
|
|
3126
|
-
tcpPort: mappedPorts2["9095"]?.host ?? null,
|
|
3127
|
-
wsPort: mappedPorts2["9097"]?.host ?? mappedPorts2["9095"]?.host ?? null,
|
|
3128
|
-
udpPort: mappedPorts2["9095"]?.udp === true ? mappedPorts2["9095"]?.host ?? null : null,
|
|
3129
|
-
quicPort: mappedPorts2["9095"]?.udp === true ? mappedPorts2["9095"]?.host ?? null : null,
|
|
3130
|
-
webrtcPort: mappedPorts2["9095"]?.udp === true ? mappedPorts2["9095"]?.host ?? null : null,
|
|
3131
|
-
proxyUrl: args.runtime.proxyUrl ?? void 0,
|
|
3132
|
-
fetch: (url, init) => fetch(url, init),
|
|
3133
|
-
timeoutMs: 18e4
|
|
3134
|
-
});
|
|
3135
|
-
if (!isConfirmedRelaySetupResult(configureResult)) {
|
|
3136
|
-
throw new Error(
|
|
3137
|
-
`Relay guest configuration could not be confirmed at http://${args.runtime.hostIpv4}:${setupPort}/configure.`
|
|
3138
|
-
);
|
|
3470
|
+
if (!args.deploymentToken) {
|
|
3471
|
+
throw new Error("Missing deployment token for Aleph bootstrap config handoff.");
|
|
3139
3472
|
}
|
|
3473
|
+
this.emitProgress({
|
|
3474
|
+
stage: "deployment-confirmed",
|
|
3475
|
+
label: "Publishing relay config",
|
|
3476
|
+
progress: 94,
|
|
3477
|
+
status: "info",
|
|
3478
|
+
itemHash: args.itemHash,
|
|
3479
|
+
detail: "Publishing runtime networking into the Aleph guest bootstrap config aggregate."
|
|
3480
|
+
});
|
|
3481
|
+
const record = {
|
|
3482
|
+
deploymentToken: args.deploymentToken,
|
|
3483
|
+
profile,
|
|
3484
|
+
ownerAddress: this.state.wallet.address,
|
|
3485
|
+
instanceItemHash: args.itemHash,
|
|
3486
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3487
|
+
expiresAt: new Date(Date.now() + 30 * 6e4).toISOString(),
|
|
3488
|
+
status: "pending",
|
|
3489
|
+
runtime: {
|
|
3490
|
+
publicIpv4: args.runtime.hostIpv4,
|
|
3491
|
+
publicIpv6: args.runtime.ipv6 ?? null,
|
|
3492
|
+
proxyUrl: args.runtime.proxyUrl ?? null,
|
|
3493
|
+
mappedPorts: mappedPorts2
|
|
3494
|
+
},
|
|
3495
|
+
bootstrap: {
|
|
3496
|
+
registrationId: createRelayBootstrapRegistrationId(
|
|
3497
|
+
profile,
|
|
3498
|
+
this.state.instanceName.trim(),
|
|
3499
|
+
args.itemHash
|
|
3500
|
+
)
|
|
3501
|
+
}
|
|
3502
|
+
};
|
|
3503
|
+
const bootstrapConfigPublication = await publishVmBootstrapConfig({
|
|
3504
|
+
sender: this.state.wallet.address,
|
|
3505
|
+
record,
|
|
3506
|
+
signer: personalSign,
|
|
3507
|
+
hasher: sha256Hex,
|
|
3508
|
+
fetch: asJsonFetch,
|
|
3509
|
+
apiHost: this.client.apiHost,
|
|
3510
|
+
sync: true
|
|
3511
|
+
});
|
|
3512
|
+
this.trace("deploy:bootstrap-config-published", {
|
|
3513
|
+
itemHash: args.itemHash,
|
|
3514
|
+
deploymentToken: args.deploymentToken,
|
|
3515
|
+
registrationId: record.bootstrap?.registrationId ?? null,
|
|
3516
|
+
proxyUrl: record.runtime.proxyUrl ?? null,
|
|
3517
|
+
mappedPorts: record.runtime.mappedPorts,
|
|
3518
|
+
aggregateItemHash: bootstrapConfigPublication.aggregateItemHash,
|
|
3519
|
+
aggregateStatus: bootstrapConfigPublication.aggregateStatus
|
|
3520
|
+
});
|
|
3140
3521
|
}
|
|
3141
3522
|
this.emitProgress({
|
|
3142
3523
|
stage: "publishing-bootstrap",
|
|
@@ -3146,27 +3527,46 @@ var SponsorRelayController = class {
|
|
|
3146
3527
|
itemHash: args.itemHash,
|
|
3147
3528
|
detail: "Waiting for the relay to report its final public multiaddrs."
|
|
3148
3529
|
});
|
|
3149
|
-
const
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3530
|
+
const relayMetadata = await fetchRelayMetadataForRuntime({
|
|
3531
|
+
runtime: args.runtime,
|
|
3532
|
+
fetch,
|
|
3533
|
+
preferSecureMetadata: profile === "uc-go-peer",
|
|
3153
3534
|
attempts: 80,
|
|
3154
3535
|
delayMs: 3e3,
|
|
3155
|
-
timeoutMs: 24e4
|
|
3536
|
+
timeoutMs: 24e4,
|
|
3537
|
+
onAttempt: (result) => {
|
|
3538
|
+
const payload = result.payload && typeof result.payload === "object" ? result.payload : null;
|
|
3539
|
+
const metadata = payload?.metadata && typeof payload.metadata === "object" ? payload.metadata : null;
|
|
3540
|
+
this.trace("deploy:relay-metadata-attempt", {
|
|
3541
|
+
itemHash: args.itemHash,
|
|
3542
|
+
attempt: result.attempt,
|
|
3543
|
+
attempts: result.attempts,
|
|
3544
|
+
requestUrl: result.requestUrl,
|
|
3545
|
+
metadataUrl: result.metadataUrl,
|
|
3546
|
+
hostIpv4: result.hostIpv4,
|
|
3547
|
+
setupPort: result.setupPort,
|
|
3548
|
+
ok: result.ok,
|
|
3549
|
+
status: result.status,
|
|
3550
|
+
ready: result.ready,
|
|
3551
|
+
error: result.error ?? null,
|
|
3552
|
+
payloadStatus: payload && typeof payload.status === "string" ? payload.status : null,
|
|
3553
|
+
peerId: metadata && typeof metadata.peer_id === "string" ? metadata.peer_id : null,
|
|
3554
|
+
probeMultiaddrCount: Array.isArray(metadata?.probe_multiaddrs) ? metadata.probe_multiaddrs.length : 0,
|
|
3555
|
+
browserBootstrapMultiaddrCount: Array.isArray(
|
|
3556
|
+
metadata?.browser_bootstrap_multiaddrs
|
|
3557
|
+
) ? metadata.browser_bootstrap_multiaddrs.length : 0
|
|
3558
|
+
});
|
|
3559
|
+
}
|
|
3156
3560
|
});
|
|
3157
|
-
|
|
3158
|
-
const peerId = typeof metadata?.peer_id === "string" ? metadata.peer_id : null;
|
|
3159
|
-
const probeMultiaddrs = Array.isArray(metadata?.probe_multiaddrs) ? metadata.probe_multiaddrs.filter(
|
|
3160
|
-
(entry) => typeof entry === "string"
|
|
3161
|
-
) : [];
|
|
3162
|
-
const browserBootstrapMultiaddrs = Array.isArray(
|
|
3163
|
-
metadata?.browser_bootstrap_multiaddrs
|
|
3164
|
-
) ? metadata.browser_bootstrap_multiaddrs.filter(
|
|
3165
|
-
(entry) => typeof entry === "string"
|
|
3166
|
-
) : [];
|
|
3167
|
-
if (!peerId || probeMultiaddrs.length === 0) {
|
|
3561
|
+
if (!relayMetadata) {
|
|
3168
3562
|
throw new Error("Relay metadata did not include a peer ID and public multiaddrs.");
|
|
3169
3563
|
}
|
|
3564
|
+
const { peerId, probeMultiaddrs, browserBootstrapMultiaddrs } = relayMetadata;
|
|
3565
|
+
const registrationId = createRelayBootstrapRegistrationId(
|
|
3566
|
+
profile,
|
|
3567
|
+
this.state.instanceName.trim(),
|
|
3568
|
+
args.itemHash
|
|
3569
|
+
);
|
|
3170
3570
|
this.emitProgress({
|
|
3171
3571
|
stage: "publishing-bootstrap",
|
|
3172
3572
|
label: "Publishing bootstrap registration",
|
|
@@ -3179,25 +3579,65 @@ var SponsorRelayController = class {
|
|
|
3179
3579
|
sender: this.state.wallet.address,
|
|
3180
3580
|
signer: personalSign,
|
|
3181
3581
|
hasher: sha256Hex,
|
|
3182
|
-
fetch:
|
|
3183
|
-
ok: response.ok,
|
|
3184
|
-
status: response.status,
|
|
3185
|
-
json: async () => await response.json()
|
|
3186
|
-
})),
|
|
3582
|
+
fetch: asJsonFetch,
|
|
3187
3583
|
apiHost: this.client.apiHost,
|
|
3188
3584
|
peerId,
|
|
3189
3585
|
multiaddrs: probeMultiaddrs,
|
|
3190
3586
|
browserMultiaddrs: browserBootstrapMultiaddrs,
|
|
3587
|
+
registrationId,
|
|
3191
3588
|
profile,
|
|
3192
3589
|
version: this.state.manifest?.version,
|
|
3590
|
+
forgetPrevious: true,
|
|
3193
3591
|
sync: true
|
|
3194
3592
|
});
|
|
3195
3593
|
this.trace("deploy:bootstrap-registration", {
|
|
3196
3594
|
itemHash: args.itemHash,
|
|
3197
3595
|
peerId,
|
|
3198
|
-
metadata,
|
|
3596
|
+
metadata: relayMetadata,
|
|
3199
3597
|
publication
|
|
3200
3598
|
});
|
|
3599
|
+
const reconcileResult = await reconcileOwnerRelayBootstrapRegistrations({
|
|
3600
|
+
instanceOwnerAddress: this.state.wallet.address,
|
|
3601
|
+
sender: this.state.wallet.address,
|
|
3602
|
+
signer: personalSign,
|
|
3603
|
+
hasher: sha256Hex,
|
|
3604
|
+
fetch: asJsonFetch,
|
|
3605
|
+
profile,
|
|
3606
|
+
apiHost: this.client.apiHost,
|
|
3607
|
+
crns: this.state.crns,
|
|
3608
|
+
crnListUrl: this.props.crnListUrl,
|
|
3609
|
+
preferSecureMetadata: profile === "uc-go-peer",
|
|
3610
|
+
current: {
|
|
3611
|
+
itemHash: args.itemHash,
|
|
3612
|
+
registrationId,
|
|
3613
|
+
peerId,
|
|
3614
|
+
probeMultiaddrs,
|
|
3615
|
+
browserBootstrapMultiaddrs
|
|
3616
|
+
}
|
|
3617
|
+
});
|
|
3618
|
+
if (reconcileResult.errors.length > 0) {
|
|
3619
|
+
this.trace("deploy:owner-bootstrap-reconcile-errors", {
|
|
3620
|
+
itemHash: args.itemHash,
|
|
3621
|
+
errors: reconcileResult.errors
|
|
3622
|
+
});
|
|
3623
|
+
}
|
|
3624
|
+
if (profile === "uc-go-peer" && args.deploymentToken) {
|
|
3625
|
+
await deleteVmBootstrapConfig({
|
|
3626
|
+
sender: this.state.wallet.address,
|
|
3627
|
+
deploymentToken: args.deploymentToken,
|
|
3628
|
+
signer: personalSign,
|
|
3629
|
+
hasher: sha256Hex,
|
|
3630
|
+
fetch: asJsonFetch,
|
|
3631
|
+
apiHost: this.client.apiHost,
|
|
3632
|
+
sync: true
|
|
3633
|
+
}).catch((error) => {
|
|
3634
|
+
this.trace("deploy:bootstrap-config-cleanup-error", {
|
|
3635
|
+
itemHash: args.itemHash,
|
|
3636
|
+
deploymentToken: args.deploymentToken,
|
|
3637
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3638
|
+
});
|
|
3639
|
+
});
|
|
3640
|
+
}
|
|
3201
3641
|
}
|
|
3202
3642
|
syncLatestDeploymentProgress(instances) {
|
|
3203
3643
|
const itemHash = this.state.lastDeploymentHash;
|
|
@@ -3669,6 +4109,7 @@ var SponsorRelayController = class {
|
|
|
3669
4109
|
let lastError = null;
|
|
3670
4110
|
for (const [candidateIndex, candidateCrn] of orderedCrns.entries()) {
|
|
3671
4111
|
let attemptItemHash = null;
|
|
4112
|
+
let attemptDeploymentToken = null;
|
|
3672
4113
|
this.emitProgress({
|
|
3673
4114
|
stage: "selecting-crn",
|
|
3674
4115
|
label: "Selecting CRN",
|
|
@@ -3677,10 +4118,16 @@ var SponsorRelayController = class {
|
|
|
3677
4118
|
detail: `Trying ${candidateCrn.name ?? candidateCrn.hash} (${candidateIndex + 1}/${orderedCrns.length})`
|
|
3678
4119
|
});
|
|
3679
4120
|
try {
|
|
4121
|
+
const profile = relayProfileForManifest(this.state.manifest);
|
|
4122
|
+
const sshPublicKey = profile === "uc-go-peer" ? appendDeploymentTokenToSshPublicKey(
|
|
4123
|
+
this.state.sshPublicKey.trim(),
|
|
4124
|
+
this.state.wallet.address,
|
|
4125
|
+
attemptDeploymentToken = createDeploymentToken()
|
|
4126
|
+
) : this.state.sshPublicKey.trim();
|
|
3680
4127
|
const content = createInstanceContent({
|
|
3681
4128
|
address: this.state.wallet.address,
|
|
3682
4129
|
name: this.state.instanceName.trim(),
|
|
3683
|
-
sshPublicKey
|
|
4130
|
+
sshPublicKey,
|
|
3684
4131
|
rootfsItemHash: this.state.manifest.rootfsItemHash,
|
|
3685
4132
|
rootfsSizeMiB: Math.max(
|
|
3686
4133
|
this.state.manifest.rootfsSizeMiB,
|
|
@@ -3860,7 +4307,8 @@ var SponsorRelayController = class {
|
|
|
3860
4307
|
});
|
|
3861
4308
|
await this.configureRelayBootstrapRegistration({
|
|
3862
4309
|
itemHash: result.itemHash,
|
|
3863
|
-
runtime
|
|
4310
|
+
runtime,
|
|
4311
|
+
deploymentToken: attemptDeploymentToken
|
|
3864
4312
|
});
|
|
3865
4313
|
this.patch({
|
|
3866
4314
|
busy: { deploying: false }
|
|
@@ -3886,6 +4334,39 @@ var SponsorRelayController = class {
|
|
|
3886
4334
|
error: lastError.message
|
|
3887
4335
|
});
|
|
3888
4336
|
if (attemptItemHash) {
|
|
4337
|
+
if (attemptDeploymentToken) {
|
|
4338
|
+
this.trace("deploy:bootstrap-config-cleanup-start", {
|
|
4339
|
+
itemHash: attemptItemHash,
|
|
4340
|
+
deploymentToken: attemptDeploymentToken
|
|
4341
|
+
});
|
|
4342
|
+
await deleteVmBootstrapConfig({
|
|
4343
|
+
sender: this.state.wallet.address,
|
|
4344
|
+
deploymentToken: attemptDeploymentToken,
|
|
4345
|
+
signer: personalSign,
|
|
4346
|
+
hasher: sha256Hex,
|
|
4347
|
+
fetch: asJsonFetch,
|
|
4348
|
+
apiHost: this.client.apiHost,
|
|
4349
|
+
sync: true
|
|
4350
|
+
}).then((cleanupResult) => {
|
|
4351
|
+
this.trace("deploy:bootstrap-config-cleanup-complete", {
|
|
4352
|
+
itemHash: attemptItemHash,
|
|
4353
|
+
deploymentToken: attemptDeploymentToken,
|
|
4354
|
+
aggregateItemHash: cleanupResult.aggregateItemHash,
|
|
4355
|
+
aggregateStatus: cleanupResult.aggregateStatus
|
|
4356
|
+
});
|
|
4357
|
+
}).catch((cleanupError) => {
|
|
4358
|
+
this.trace("deploy:bootstrap-config-cleanup-error", {
|
|
4359
|
+
itemHash: attemptItemHash,
|
|
4360
|
+
deploymentToken: attemptDeploymentToken,
|
|
4361
|
+
error: cleanupError instanceof Error ? cleanupError.message : String(cleanupError)
|
|
4362
|
+
});
|
|
4363
|
+
});
|
|
4364
|
+
}
|
|
4365
|
+
this.trace("deploy:forget-failed-attempt-start", {
|
|
4366
|
+
itemHash: attemptItemHash,
|
|
4367
|
+
crnHash: candidateCrn.hash,
|
|
4368
|
+
crnName: candidateCrn.name
|
|
4369
|
+
});
|
|
3889
4370
|
await forgetAlephMessages({
|
|
3890
4371
|
sender: this.state.wallet.address,
|
|
3891
4372
|
hashes: [attemptItemHash],
|
|
@@ -3904,6 +4385,11 @@ var SponsorRelayController = class {
|
|
|
3904
4385
|
error: cleanupError instanceof Error ? cleanupError.message : String(cleanupError)
|
|
3905
4386
|
});
|
|
3906
4387
|
});
|
|
4388
|
+
this.trace("deploy:forget-failed-attempt-complete", {
|
|
4389
|
+
itemHash: attemptItemHash,
|
|
4390
|
+
crnHash: candidateCrn.hash,
|
|
4391
|
+
crnName: candidateCrn.name
|
|
4392
|
+
});
|
|
3907
4393
|
}
|
|
3908
4394
|
if (candidateIndex < orderedCrns.length - 1) {
|
|
3909
4395
|
this.emitProgress({
|
|
@@ -3964,16 +4450,35 @@ var SponsorRelayController = class {
|
|
|
3964
4450
|
reason: "Deleted from Sponsor Relay panel",
|
|
3965
4451
|
signer: personalSign,
|
|
3966
4452
|
hasher: sha256Hex,
|
|
3967
|
-
fetch:
|
|
3968
|
-
ok: response.ok,
|
|
3969
|
-
status: response.status,
|
|
3970
|
-
json: async () => await response.json()
|
|
3971
|
-
})),
|
|
4453
|
+
fetch: asJsonFetch,
|
|
3972
4454
|
apiHost: this.client.apiHost,
|
|
3973
4455
|
onProgress: (event) => {
|
|
3974
4456
|
this.emitProgress(event);
|
|
3975
4457
|
}
|
|
3976
4458
|
});
|
|
4459
|
+
const profile = relayProfileForManifest(this.state.manifest);
|
|
4460
|
+
if (profile) {
|
|
4461
|
+
await reconcileOwnerRelayBootstrapRegistrations({
|
|
4462
|
+
instanceOwnerAddress: this.state.wallet.address,
|
|
4463
|
+
sender: this.state.wallet.address,
|
|
4464
|
+
signer: personalSign,
|
|
4465
|
+
hasher: sha256Hex,
|
|
4466
|
+
fetch: asJsonFetch,
|
|
4467
|
+
profile,
|
|
4468
|
+
apiHost: this.client.apiHost,
|
|
4469
|
+
crns: this.state.crns,
|
|
4470
|
+
crnListUrl: this.props.crnListUrl,
|
|
4471
|
+
preferSecureMetadata: profile === "uc-go-peer"
|
|
4472
|
+
}).catch(
|
|
4473
|
+
(error) => {
|
|
4474
|
+
this.trace("delete:owner-bootstrap-reconcile-error", {
|
|
4475
|
+
instanceHash,
|
|
4476
|
+
profile,
|
|
4477
|
+
error: error instanceof Error ? error.message : String(error)
|
|
4478
|
+
});
|
|
4479
|
+
}
|
|
4480
|
+
);
|
|
4481
|
+
}
|
|
3977
4482
|
this.patch({
|
|
3978
4483
|
busy: { deletingInstanceHash: null },
|
|
3979
4484
|
statusText: `Deletion submitted for ${instanceHash}`
|