@le-space/ui 0.1.62 → 0.3.0
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.d.ts +10 -1
- package/react/index.js +718 -24
- package/shared/index.d.ts +10 -1
- package/shared/index.js +711 -23
package/shared/index.js
CHANGED
|
@@ -1831,6 +1831,28 @@ async function waitForVmRuntime(args) {
|
|
|
1831
1831
|
}
|
|
1832
1832
|
|
|
1833
1833
|
// ../core/src/guest.ts
|
|
1834
|
+
async function defaultHttpProbe(fetch2, url, timeoutMs = 1e4) {
|
|
1835
|
+
try {
|
|
1836
|
+
const controller = new AbortController();
|
|
1837
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
1838
|
+
const response = await fetch2(url, {
|
|
1839
|
+
method: "GET",
|
|
1840
|
+
redirect: "follow",
|
|
1841
|
+
signal: controller.signal
|
|
1842
|
+
});
|
|
1843
|
+
clearTimeout(timeout);
|
|
1844
|
+
return {
|
|
1845
|
+
ok: response.ok,
|
|
1846
|
+
status: response.status,
|
|
1847
|
+
url: response.url
|
|
1848
|
+
};
|
|
1849
|
+
} catch (error) {
|
|
1850
|
+
return {
|
|
1851
|
+
ok: false,
|
|
1852
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1853
|
+
};
|
|
1854
|
+
}
|
|
1855
|
+
}
|
|
1834
1856
|
async function notifyCrnAllocation2(args) {
|
|
1835
1857
|
const normalizedCrnUrl = typeof args.crnUrl === "string" ? args.crnUrl.trim().replace(/\/+$/, "") : "";
|
|
1836
1858
|
if (!normalizedCrnUrl) {
|
|
@@ -1911,6 +1933,324 @@ async function notifyCrnAllocationWithRetry(args) {
|
|
|
1911
1933
|
reason: "CRN allocation notify was not confirmed."
|
|
1912
1934
|
};
|
|
1913
1935
|
}
|
|
1936
|
+
async function waitForSetupEndpoint(args) {
|
|
1937
|
+
const attempts = Math.max(1, Number(args.attempts ?? 15));
|
|
1938
|
+
const delayMs = Math.max(0, Number(args.delayMs ?? 4e3));
|
|
1939
|
+
const sleep = args.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
1940
|
+
const url = `http://${args.hostIpv4}:${args.setupPort}/health`;
|
|
1941
|
+
let result = await defaultHttpProbe(
|
|
1942
|
+
args.fetch,
|
|
1943
|
+
url,
|
|
1944
|
+
Number(args.httpTimeoutMs ?? 1e4)
|
|
1945
|
+
);
|
|
1946
|
+
args.onAttempt?.(result, 1, attempts);
|
|
1947
|
+
for (let attempt = 1; attempt < attempts; attempt += 1) {
|
|
1948
|
+
if (result.ok) return result;
|
|
1949
|
+
await sleep(delayMs);
|
|
1950
|
+
result = await defaultHttpProbe(
|
|
1951
|
+
args.fetch,
|
|
1952
|
+
url,
|
|
1953
|
+
Number(args.httpTimeoutMs ?? 1e4)
|
|
1954
|
+
);
|
|
1955
|
+
args.onAttempt?.(result, attempt + 1, attempts);
|
|
1956
|
+
}
|
|
1957
|
+
return result;
|
|
1958
|
+
}
|
|
1959
|
+
async function configureUcGoPeer(args) {
|
|
1960
|
+
const controller = new AbortController();
|
|
1961
|
+
const timeout = setTimeout(
|
|
1962
|
+
() => controller.abort(),
|
|
1963
|
+
Number(args.timeoutMs ?? 18e4)
|
|
1964
|
+
);
|
|
1965
|
+
const payload = {
|
|
1966
|
+
public_ipv4: args.hostIpv4,
|
|
1967
|
+
public_ipv6: args.publicIpv6 ?? void 0,
|
|
1968
|
+
proxy_url: args.proxyUrl ?? void 0,
|
|
1969
|
+
tcp_port: args.tcpPort ?? void 0,
|
|
1970
|
+
ws_port: args.wsPort ?? void 0,
|
|
1971
|
+
udp_port: args.udpPort ?? void 0,
|
|
1972
|
+
quic_port: args.quicPort ?? void 0,
|
|
1973
|
+
webrtc_port: args.webrtcPort ?? void 0
|
|
1974
|
+
};
|
|
1975
|
+
try {
|
|
1976
|
+
const response = await args.fetch(
|
|
1977
|
+
`http://${args.hostIpv4}:${args.setupPort}/configure`,
|
|
1978
|
+
{
|
|
1979
|
+
method: "POST",
|
|
1980
|
+
headers: {
|
|
1981
|
+
"content-type": "application/json"
|
|
1982
|
+
},
|
|
1983
|
+
body: JSON.stringify(payload),
|
|
1984
|
+
signal: controller.signal
|
|
1985
|
+
}
|
|
1986
|
+
);
|
|
1987
|
+
const responsePayload = await response.json().catch(() => null);
|
|
1988
|
+
if (!response.ok) {
|
|
1989
|
+
throw new Error(
|
|
1990
|
+
`Relay setup request failed: ${response.status} ${typeof responsePayload === "string" ? responsePayload : JSON.stringify(responsePayload ?? {})}`
|
|
1991
|
+
);
|
|
1992
|
+
}
|
|
1993
|
+
return responsePayload;
|
|
1994
|
+
} finally {
|
|
1995
|
+
clearTimeout(timeout);
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
async function configureOrbitdbRelaySetup2(args) {
|
|
1999
|
+
const controller = new AbortController();
|
|
2000
|
+
const timeout = setTimeout(
|
|
2001
|
+
() => controller.abort(),
|
|
2002
|
+
Number(args.timeoutMs ?? 18e4)
|
|
2003
|
+
);
|
|
2004
|
+
const payload = {
|
|
2005
|
+
public_ipv4: args.hostIpv4,
|
|
2006
|
+
public_ipv6: args.publicIpv6 ?? void 0,
|
|
2007
|
+
tcp_port: args.tcpPort,
|
|
2008
|
+
ws_port: args.wsPort,
|
|
2009
|
+
proxy_url: args.proxyUrl ?? void 0,
|
|
2010
|
+
metrics_port: args.metricsPort ?? void 0,
|
|
2011
|
+
metrics_https_port: args.metricsHttpsPort ?? void 0,
|
|
2012
|
+
webrtc_port: args.webrtcPort ?? void 0,
|
|
2013
|
+
quic_port: args.quicPort ?? void 0
|
|
2014
|
+
};
|
|
2015
|
+
try {
|
|
2016
|
+
const response = await args.fetch(
|
|
2017
|
+
`http://${args.hostIpv4}:${args.setupPort}/configure`,
|
|
2018
|
+
{
|
|
2019
|
+
method: "POST",
|
|
2020
|
+
headers: {
|
|
2021
|
+
"content-type": "application/json"
|
|
2022
|
+
},
|
|
2023
|
+
body: JSON.stringify(payload),
|
|
2024
|
+
signal: controller.signal
|
|
2025
|
+
}
|
|
2026
|
+
);
|
|
2027
|
+
const responsePayload = await response.json().catch(() => null);
|
|
2028
|
+
if (!response.ok) {
|
|
2029
|
+
throw new Error(
|
|
2030
|
+
`Relay setup request failed: ${response.status} ${typeof responsePayload === "string" ? responsePayload : JSON.stringify(responsePayload ?? {})}`
|
|
2031
|
+
);
|
|
2032
|
+
}
|
|
2033
|
+
return responsePayload;
|
|
2034
|
+
} finally {
|
|
2035
|
+
clearTimeout(timeout);
|
|
2036
|
+
}
|
|
2037
|
+
}
|
|
2038
|
+
async function fetchUcGoPeerMetadata(args) {
|
|
2039
|
+
const attempts = Math.max(1, Number(args.attempts ?? 60));
|
|
2040
|
+
const delayMs = Math.max(0, Number(args.delayMs ?? 3e3));
|
|
2041
|
+
const sleep = args.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
2042
|
+
let lastPayload = null;
|
|
2043
|
+
for (let attempt = 0; attempt < attempts; attempt += 1) {
|
|
2044
|
+
const controller = new AbortController();
|
|
2045
|
+
const timeout = setTimeout(
|
|
2046
|
+
() => controller.abort(),
|
|
2047
|
+
Number(args.timeoutMs ?? 18e4)
|
|
2048
|
+
);
|
|
2049
|
+
try {
|
|
2050
|
+
const response = await args.fetch(
|
|
2051
|
+
`http://${args.hostIpv4}:${args.setupPort}/metadata`,
|
|
2052
|
+
{
|
|
2053
|
+
signal: controller.signal
|
|
2054
|
+
}
|
|
2055
|
+
);
|
|
2056
|
+
const payload = await response.json().catch(() => null);
|
|
2057
|
+
lastPayload = payload;
|
|
2058
|
+
args.onAttempt?.(
|
|
2059
|
+
payload,
|
|
2060
|
+
Boolean(
|
|
2061
|
+
response.ok && payload && typeof payload === "object" && payload.status === "ready"
|
|
2062
|
+
),
|
|
2063
|
+
attempt + 1,
|
|
2064
|
+
attempts
|
|
2065
|
+
);
|
|
2066
|
+
if (response.ok && payload && typeof payload === "object" && payload.status === "ready") {
|
|
2067
|
+
return payload;
|
|
2068
|
+
}
|
|
2069
|
+
if (response.status >= 500) {
|
|
2070
|
+
throw new Error(
|
|
2071
|
+
`Relay metadata request failed: ${response.status} ${typeof payload === "string" ? payload : JSON.stringify(payload ?? {})}`
|
|
2072
|
+
);
|
|
2073
|
+
}
|
|
2074
|
+
} finally {
|
|
2075
|
+
clearTimeout(timeout);
|
|
2076
|
+
}
|
|
2077
|
+
if (attempt < attempts - 1) {
|
|
2078
|
+
await sleep(delayMs);
|
|
2079
|
+
}
|
|
2080
|
+
}
|
|
2081
|
+
throw new Error(
|
|
2082
|
+
`Relay metadata did not become ready after ${attempts} attempts: ${typeof lastPayload === "string" ? lastPayload : JSON.stringify(lastPayload ?? {})}`
|
|
2083
|
+
);
|
|
2084
|
+
}
|
|
2085
|
+
|
|
2086
|
+
// ../aleph-bootstrap/src/index.ts
|
|
2087
|
+
var DEFAULT_ALEPH_API_HOST3 = "https://api2.aleph.im";
|
|
2088
|
+
var DEFAULT_ALEPH_BOOTSTRAP_CHANNEL = "simple-todo";
|
|
2089
|
+
var DEFAULT_ALEPH_BOOTSTRAP_REF = "simple-todo-bootstrap";
|
|
2090
|
+
var DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE = "relay-bootstrap";
|
|
2091
|
+
var DEFAULT_BOOTSTRAP_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
2092
|
+
function normalizeHost(host) {
|
|
2093
|
+
return host.trim().toLowerCase();
|
|
2094
|
+
}
|
|
2095
|
+
function splitMultiaddr(addr) {
|
|
2096
|
+
return addr.split("/").filter(Boolean);
|
|
2097
|
+
}
|
|
2098
|
+
function isPrivateIpv4(ip) {
|
|
2099
|
+
const parts = ip.split(".").map((part) => Number(part));
|
|
2100
|
+
if (parts.length !== 4 || parts.some((part) => !Number.isInteger(part) || part < 0 || part > 255)) {
|
|
2101
|
+
return false;
|
|
2102
|
+
}
|
|
2103
|
+
if (parts[0] === 10) return true;
|
|
2104
|
+
if (parts[0] === 127) return true;
|
|
2105
|
+
if (parts[0] === 0) return true;
|
|
2106
|
+
if (parts[0] === 169 && parts[1] === 254) return true;
|
|
2107
|
+
if (parts[0] === 172 && parts[1] >= 16 && parts[1] <= 31) return true;
|
|
2108
|
+
if (parts[0] === 192 && parts[1] === 168) return true;
|
|
2109
|
+
if (parts[0] === 100 && parts[1] >= 64 && parts[1] <= 127) return true;
|
|
2110
|
+
return false;
|
|
2111
|
+
}
|
|
2112
|
+
function isPrivateIpv6(ip) {
|
|
2113
|
+
const normalized = ip.trim().toLowerCase();
|
|
2114
|
+
return normalized === "::1" || normalized.startsWith("fc") || normalized.startsWith("fd") || normalized.startsWith("fe8") || normalized.startsWith("fe9") || normalized.startsWith("fea") || normalized.startsWith("feb");
|
|
2115
|
+
}
|
|
2116
|
+
function isLocalHostname(host) {
|
|
2117
|
+
const normalized = normalizeHost(host);
|
|
2118
|
+
return normalized === "localhost" || normalized.endsWith(".localhost") || normalized.endsWith(".local");
|
|
2119
|
+
}
|
|
2120
|
+
function hasPeerId(addr) {
|
|
2121
|
+
return splitMultiaddr(addr).includes("p2p");
|
|
2122
|
+
}
|
|
2123
|
+
function isBrowserDialableMultiaddr(addr) {
|
|
2124
|
+
const normalized = addr.toLowerCase();
|
|
2125
|
+
return normalized.includes("/ws") || normalized.includes("/wss") || normalized.includes("/webtransport") || normalized.includes("/webrtc-direct");
|
|
2126
|
+
}
|
|
2127
|
+
function dedupeMultiaddrs(addrs) {
|
|
2128
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2129
|
+
const result = [];
|
|
2130
|
+
for (const value of addrs) {
|
|
2131
|
+
const trimmed = value.trim();
|
|
2132
|
+
if (!trimmed || seen.has(trimmed)) continue;
|
|
2133
|
+
seen.add(trimmed);
|
|
2134
|
+
result.push(trimmed);
|
|
2135
|
+
}
|
|
2136
|
+
return result;
|
|
2137
|
+
}
|
|
2138
|
+
function isPublicMultiaddr(addr) {
|
|
2139
|
+
const parts = splitMultiaddr(addr);
|
|
2140
|
+
for (let index = 0; index < parts.length; index += 1) {
|
|
2141
|
+
const protocol = parts[index];
|
|
2142
|
+
const value = parts[index + 1];
|
|
2143
|
+
if (protocol === "ip4" && value) {
|
|
2144
|
+
return !isPrivateIpv4(value);
|
|
2145
|
+
}
|
|
2146
|
+
if (protocol === "ip6" && value) {
|
|
2147
|
+
return !isPrivateIpv6(value);
|
|
2148
|
+
}
|
|
2149
|
+
if ((protocol === "dns4" || protocol === "dns6" || protocol === "dnsaddr") && value) {
|
|
2150
|
+
return !isLocalHostname(value);
|
|
2151
|
+
}
|
|
2152
|
+
}
|
|
2153
|
+
return false;
|
|
2154
|
+
}
|
|
2155
|
+
function filterPublicMultiaddrs(addrs, options = {}) {
|
|
2156
|
+
return dedupeMultiaddrs(addrs).filter((addr) => {
|
|
2157
|
+
if (!isPublicMultiaddr(addr)) return false;
|
|
2158
|
+
if (options.requirePeerId !== false && !hasPeerId(addr)) return false;
|
|
2159
|
+
if (options.browserDialableOnly && !isBrowserDialableMultiaddr(addr)) {
|
|
2160
|
+
return false;
|
|
2161
|
+
}
|
|
2162
|
+
return true;
|
|
2163
|
+
});
|
|
2164
|
+
}
|
|
2165
|
+
function buildRelayBootstrapPostContent(args) {
|
|
2166
|
+
const now = args.now ?? Date.now() / 1e3;
|
|
2167
|
+
const updatedAt = args.now ?? Date.now();
|
|
2168
|
+
return {
|
|
2169
|
+
type: args.postType ?? DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE,
|
|
2170
|
+
address: args.sender,
|
|
2171
|
+
...args.ref ? { ref: args.ref } : {},
|
|
2172
|
+
content: {
|
|
2173
|
+
peerId: args.peerId,
|
|
2174
|
+
multiaddrs: filterPublicMultiaddrs(args.multiaddrs),
|
|
2175
|
+
browserMultiaddrs: args.browserMultiaddrs ? filterPublicMultiaddrs(args.browserMultiaddrs, {
|
|
2176
|
+
browserDialableOnly: true
|
|
2177
|
+
}) : void 0,
|
|
2178
|
+
profile: args.profile,
|
|
2179
|
+
version: args.version,
|
|
2180
|
+
updatedAt: Math.round(updatedAt)
|
|
2181
|
+
},
|
|
2182
|
+
time: now
|
|
2183
|
+
};
|
|
2184
|
+
}
|
|
2185
|
+
async function createRelayBootstrapPost(args) {
|
|
2186
|
+
const nowMillis = args.now ?? Date.now();
|
|
2187
|
+
const nowSeconds = nowMillis / 1e3;
|
|
2188
|
+
const itemContent = buildRelayBootstrapPostContent({
|
|
2189
|
+
sender: args.sender,
|
|
2190
|
+
peerId: args.peerId,
|
|
2191
|
+
multiaddrs: args.multiaddrs,
|
|
2192
|
+
browserMultiaddrs: args.browserMultiaddrs,
|
|
2193
|
+
ref: args.ref ?? DEFAULT_ALEPH_BOOTSTRAP_REF,
|
|
2194
|
+
postType: args.postType ?? DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE,
|
|
2195
|
+
profile: args.profile,
|
|
2196
|
+
version: args.version,
|
|
2197
|
+
now: nowMillis
|
|
2198
|
+
});
|
|
2199
|
+
itemContent.time = nowSeconds;
|
|
2200
|
+
const serialized = JSON.stringify(itemContent);
|
|
2201
|
+
const itemHash = await args.hasher(serialized);
|
|
2202
|
+
return {
|
|
2203
|
+
channel: args.channel ?? DEFAULT_ALEPH_BOOTSTRAP_CHANNEL,
|
|
2204
|
+
sender: args.sender,
|
|
2205
|
+
chain: "ETH",
|
|
2206
|
+
type: "POST",
|
|
2207
|
+
time: nowSeconds,
|
|
2208
|
+
item_type: "inline",
|
|
2209
|
+
item_content: serialized,
|
|
2210
|
+
item_hash: itemHash
|
|
2211
|
+
};
|
|
2212
|
+
}
|
|
2213
|
+
|
|
2214
|
+
// ../core/src/bootstrap-registration.ts
|
|
2215
|
+
async function publishRelayBootstrapRegistration(args) {
|
|
2216
|
+
const unsigned = await createRelayBootstrapPost({
|
|
2217
|
+
sender: args.sender,
|
|
2218
|
+
peerId: args.peerId,
|
|
2219
|
+
multiaddrs: args.multiaddrs,
|
|
2220
|
+
browserMultiaddrs: args.browserMultiaddrs,
|
|
2221
|
+
channel: args.channel,
|
|
2222
|
+
ref: args.ref,
|
|
2223
|
+
postType: args.postType,
|
|
2224
|
+
profile: args.profile,
|
|
2225
|
+
version: args.version,
|
|
2226
|
+
now: args.now,
|
|
2227
|
+
hasher: args.hasher
|
|
2228
|
+
});
|
|
2229
|
+
const content = JSON.parse(unsigned.item_content);
|
|
2230
|
+
if ((content.content?.multiaddrs?.length ?? 0) === 0) {
|
|
2231
|
+
return {
|
|
2232
|
+
status: "skipped",
|
|
2233
|
+
reason: "No public relay multiaddrs remained after filtering.",
|
|
2234
|
+
publishedMultiaddrs: [],
|
|
2235
|
+
publishedBrowserMultiaddrs: content.content?.browserMultiaddrs ?? []
|
|
2236
|
+
};
|
|
2237
|
+
}
|
|
2238
|
+
const message = await signAlephMessage(unsigned, args.signer);
|
|
2239
|
+
const { response, httpStatus } = await broadcastAlephMessage2(message, {
|
|
2240
|
+
apiHost: args.apiHost ?? DEFAULT_ALEPH_API_HOST3,
|
|
2241
|
+
sync: args.sync ?? true,
|
|
2242
|
+
fetch: args.fetch
|
|
2243
|
+
});
|
|
2244
|
+
return {
|
|
2245
|
+
status: "published",
|
|
2246
|
+
itemHash: unsigned.item_hash,
|
|
2247
|
+
message,
|
|
2248
|
+
response,
|
|
2249
|
+
httpStatus,
|
|
2250
|
+
publishedMultiaddrs: content.content?.multiaddrs ?? [],
|
|
2251
|
+
publishedBrowserMultiaddrs: content.content?.browserMultiaddrs ?? []
|
|
2252
|
+
};
|
|
2253
|
+
}
|
|
1914
2254
|
|
|
1915
2255
|
// src/shared/events.ts
|
|
1916
2256
|
function createDeploymentProgressEmitter() {
|
|
@@ -1984,6 +2324,16 @@ function defaultState(props = {}) {
|
|
|
1984
2324
|
deploymentProgress: IDLE_DEPLOYMENT_PROGRESS
|
|
1985
2325
|
};
|
|
1986
2326
|
}
|
|
2327
|
+
function isDebugEnabled(props) {
|
|
2328
|
+
if (props.debug) {
|
|
2329
|
+
return true;
|
|
2330
|
+
}
|
|
2331
|
+
try {
|
|
2332
|
+
return globalThis.localStorage?.getItem("LE_SPACE_UI_DEBUG") === "1";
|
|
2333
|
+
} catch {
|
|
2334
|
+
return false;
|
|
2335
|
+
}
|
|
2336
|
+
}
|
|
1987
2337
|
async function sha256Hex(payload) {
|
|
1988
2338
|
const digest = await globalThis.crypto.subtle.digest(
|
|
1989
2339
|
"SHA-256",
|
|
@@ -1999,6 +2349,12 @@ function mappedPorts(execution) {
|
|
|
1999
2349
|
})
|
|
2000
2350
|
);
|
|
2001
2351
|
}
|
|
2352
|
+
function runtimeMappedPorts(mappedPortsRecord) {
|
|
2353
|
+
return Object.entries(mappedPortsRecord ?? {}).map(([port, mapping]) => ({
|
|
2354
|
+
label: `${port}/${mapping.udp ? "udp" : "tcp"}`,
|
|
2355
|
+
hostPort: mapping.host ?? null
|
|
2356
|
+
}));
|
|
2357
|
+
}
|
|
2002
2358
|
function rootfsHealth(args) {
|
|
2003
2359
|
if (!args.manifestState.valid || !args.manifestState.manifest) {
|
|
2004
2360
|
return {
|
|
@@ -2053,6 +2409,13 @@ async function resolveManifest(args) {
|
|
|
2053
2409
|
if (pasted) return pasted;
|
|
2054
2410
|
return loadRootfsManifest(args.manifestUrl);
|
|
2055
2411
|
}
|
|
2412
|
+
function relayProfileForManifest(manifest) {
|
|
2413
|
+
if (manifest?.profile === "uc-go-peer") return "uc-go-peer";
|
|
2414
|
+
if (manifest?.profile === "orbitdb-relay-pinner") {
|
|
2415
|
+
return "orbitdb-relay-pinner";
|
|
2416
|
+
}
|
|
2417
|
+
return null;
|
|
2418
|
+
}
|
|
2056
2419
|
async function inspectInstanceRuntime(args) {
|
|
2057
2420
|
const details = {
|
|
2058
2421
|
messageStatus: String(
|
|
@@ -2069,8 +2432,18 @@ async function inspectInstanceRuntime(args) {
|
|
|
2069
2432
|
execution: null,
|
|
2070
2433
|
error: null
|
|
2071
2434
|
};
|
|
2072
|
-
|
|
2073
|
-
|
|
2435
|
+
const lookup = {
|
|
2436
|
+
allocationFound: false,
|
|
2437
|
+
allocationSource: null,
|
|
2438
|
+
crnUrl: null,
|
|
2439
|
+
webUrl: null,
|
|
2440
|
+
executionPayloadFound: false,
|
|
2441
|
+
executionLookupBlocked: false,
|
|
2442
|
+
executionLookupRequestUrl: null,
|
|
2443
|
+
executionLookupVersion: null
|
|
2444
|
+
};
|
|
2445
|
+
if (details.messageStatus === "rejected" || details.messageStatus === "removing") {
|
|
2446
|
+
return { details, lookup };
|
|
2074
2447
|
}
|
|
2075
2448
|
try {
|
|
2076
2449
|
const allocation = await args.client.fetchSchedulerAllocation(args.instance.item_hash) ?? (() => {
|
|
@@ -2085,26 +2458,35 @@ async function inspectInstanceRuntime(args) {
|
|
|
2085
2458
|
period: null
|
|
2086
2459
|
} : null;
|
|
2087
2460
|
})();
|
|
2461
|
+
lookup.allocationFound = Boolean(allocation);
|
|
2462
|
+
lookup.allocationSource = allocation?.source ?? null;
|
|
2088
2463
|
details.allocationSource = allocation?.source ?? null;
|
|
2089
2464
|
details.crnUrl = allocation?.crnUrl ?? null;
|
|
2090
2465
|
details.ipv6 = allocation?.vmIpv6 ?? null;
|
|
2091
2466
|
details.webUrl = await args.client.fetch2n6WebAccessUrl(
|
|
2092
2467
|
args.instance.item_hash
|
|
2093
2468
|
);
|
|
2469
|
+
lookup.crnUrl = details.crnUrl;
|
|
2470
|
+
lookup.webUrl = details.webUrl;
|
|
2094
2471
|
if (!allocation?.crnUrl) {
|
|
2095
|
-
return details;
|
|
2472
|
+
return { details, lookup };
|
|
2096
2473
|
}
|
|
2097
2474
|
const executionLookup = await args.client.fetchCrnExecutionMap(
|
|
2098
2475
|
allocation.crnUrl
|
|
2099
2476
|
);
|
|
2477
|
+
lookup.executionLookupBlocked = executionLookup.blocked;
|
|
2478
|
+
lookup.executionLookupRequestUrl = executionLookup.requestUrl ?? null;
|
|
2479
|
+
lookup.executionLookupVersion = executionLookup.version ?? null;
|
|
2100
2480
|
const executionPayload = executionLookup.payload?.[args.instance.item_hash];
|
|
2481
|
+
lookup.executionPayloadFound = Boolean(executionPayload);
|
|
2101
2482
|
if (!executionPayload) {
|
|
2102
|
-
return details;
|
|
2483
|
+
return { details, lookup };
|
|
2103
2484
|
}
|
|
2104
2485
|
const execution = normalizeExecution(executionPayload, allocation.crnUrl);
|
|
2105
2486
|
if (!execution.networking.proxy_url && details.webUrl) {
|
|
2106
2487
|
execution.networking.proxy_url = details.webUrl;
|
|
2107
2488
|
}
|
|
2489
|
+
details.messageStatus = "processed";
|
|
2108
2490
|
details.execution = execution;
|
|
2109
2491
|
details.hostIpv4 = execution.networking.host_ipv4 ?? execution.networking.ipv4 ?? null;
|
|
2110
2492
|
details.ipv6 = execution.networking.ipv6_ip ?? execution.networking.ipv6 ?? details.ipv6;
|
|
@@ -2112,11 +2494,14 @@ async function inspectInstanceRuntime(args) {
|
|
|
2112
2494
|
details.webUrl = execution.networking.proxy_url ?? details.webUrl;
|
|
2113
2495
|
details.mappedPorts = mappedPorts(execution);
|
|
2114
2496
|
details.sshCommand = buildSshCommand(details.hostIpv4, details.mappedPorts);
|
|
2115
|
-
return details;
|
|
2497
|
+
return { details, lookup };
|
|
2116
2498
|
} catch (error) {
|
|
2117
2499
|
return {
|
|
2118
|
-
|
|
2119
|
-
|
|
2500
|
+
details: {
|
|
2501
|
+
...details,
|
|
2502
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2503
|
+
},
|
|
2504
|
+
lookup
|
|
2120
2505
|
};
|
|
2121
2506
|
}
|
|
2122
2507
|
}
|
|
@@ -2225,9 +2610,13 @@ var SponsorRelayController = class {
|
|
|
2225
2610
|
props;
|
|
2226
2611
|
progressEmitter = createDeploymentProgressEmitter();
|
|
2227
2612
|
runtimeCooldownByHash = /* @__PURE__ */ new Map();
|
|
2613
|
+
runtimeDetailsByHash = /* @__PURE__ */ new Map();
|
|
2614
|
+
debugEnabled;
|
|
2615
|
+
lastRuntimeReadyHash = null;
|
|
2228
2616
|
constructor(props = {}) {
|
|
2229
2617
|
this.props = props;
|
|
2230
2618
|
this.state = defaultState(props);
|
|
2619
|
+
this.debugEnabled = isDebugEnabled(props);
|
|
2231
2620
|
this.client = createAlephBrowserClient({
|
|
2232
2621
|
apiHost: props.apiHost,
|
|
2233
2622
|
crnListUrl: props.crnListUrl,
|
|
@@ -2247,10 +2636,24 @@ var SponsorRelayController = class {
|
|
|
2247
2636
|
getState() {
|
|
2248
2637
|
return this.state;
|
|
2249
2638
|
}
|
|
2639
|
+
updateProps(props) {
|
|
2640
|
+
this.props = { ...this.props, ...props };
|
|
2641
|
+
this.debugEnabled = isDebugEnabled(this.props);
|
|
2642
|
+
}
|
|
2250
2643
|
emit() {
|
|
2251
2644
|
const next = this.state;
|
|
2252
2645
|
this.subscribers.forEach((subscriber) => subscriber(next));
|
|
2253
2646
|
}
|
|
2647
|
+
trace(message, data) {
|
|
2648
|
+
if (!this.debugEnabled) {
|
|
2649
|
+
return;
|
|
2650
|
+
}
|
|
2651
|
+
if (data === void 0) {
|
|
2652
|
+
console.debug("[le-space/ui]", message);
|
|
2653
|
+
return;
|
|
2654
|
+
}
|
|
2655
|
+
console.debug("[le-space/ui]", message, data);
|
|
2656
|
+
}
|
|
2254
2657
|
patch(patch) {
|
|
2255
2658
|
this.state = {
|
|
2256
2659
|
...this.state,
|
|
@@ -2267,6 +2670,14 @@ var SponsorRelayController = class {
|
|
|
2267
2670
|
...event,
|
|
2268
2671
|
timestamp: Date.now()
|
|
2269
2672
|
};
|
|
2673
|
+
this.trace(`progress:${nextEvent.stage}`, {
|
|
2674
|
+
label: nextEvent.label,
|
|
2675
|
+
progress: nextEvent.progress,
|
|
2676
|
+
status: nextEvent.status,
|
|
2677
|
+
itemHash: nextEvent.itemHash ?? null,
|
|
2678
|
+
detail: nextEvent.detail ?? null,
|
|
2679
|
+
error: nextEvent.error ?? null
|
|
2680
|
+
});
|
|
2270
2681
|
this.patch({
|
|
2271
2682
|
deploymentProgress: nextEvent,
|
|
2272
2683
|
statusText: event.error ?? event.detail ?? event.label,
|
|
@@ -2274,6 +2685,145 @@ var SponsorRelayController = class {
|
|
|
2274
2685
|
});
|
|
2275
2686
|
this.progressEmitter.emit(nextEvent);
|
|
2276
2687
|
}
|
|
2688
|
+
async configureRelayBootstrapRegistration(args) {
|
|
2689
|
+
const profile = relayProfileForManifest(this.state.manifest);
|
|
2690
|
+
if (!profile) return;
|
|
2691
|
+
if (!this.state.wallet.address) {
|
|
2692
|
+
throw new Error("A connected wallet is required to register relay bootstrap addresses.");
|
|
2693
|
+
}
|
|
2694
|
+
if (!args.runtime.hostIpv4) {
|
|
2695
|
+
throw new Error("Relay runtime did not expose a host IPv4 address.");
|
|
2696
|
+
}
|
|
2697
|
+
const mappedPorts2 = args.runtime.mappedPorts ?? {};
|
|
2698
|
+
const setupPort = mappedPorts2["80"]?.host ?? null;
|
|
2699
|
+
if (!setupPort) {
|
|
2700
|
+
throw new Error("Relay runtime did not expose the temporary setup endpoint.");
|
|
2701
|
+
}
|
|
2702
|
+
this.emitProgress({
|
|
2703
|
+
stage: "deployment-confirmed",
|
|
2704
|
+
label: "Configuring relay",
|
|
2705
|
+
progress: 93,
|
|
2706
|
+
status: "info",
|
|
2707
|
+
itemHash: args.itemHash,
|
|
2708
|
+
detail: "Waiting for the guest setup endpoint before collecting relay metadata."
|
|
2709
|
+
});
|
|
2710
|
+
const setupHealth = await waitForSetupEndpoint({
|
|
2711
|
+
hostIpv4: args.runtime.hostIpv4,
|
|
2712
|
+
setupPort,
|
|
2713
|
+
fetch: (url, init) => fetch(url, init),
|
|
2714
|
+
attempts: 15,
|
|
2715
|
+
delayMs: 4e3,
|
|
2716
|
+
httpTimeoutMs: 1e4
|
|
2717
|
+
});
|
|
2718
|
+
if (!setupHealth.ok) {
|
|
2719
|
+
throw new Error(
|
|
2720
|
+
`Relay setup endpoint did not become reachable at http://${args.runtime.hostIpv4}:${setupPort}/health.`
|
|
2721
|
+
);
|
|
2722
|
+
}
|
|
2723
|
+
this.emitProgress({
|
|
2724
|
+
stage: "deployment-confirmed",
|
|
2725
|
+
label: "Applying relay networking",
|
|
2726
|
+
progress: 94,
|
|
2727
|
+
status: "info",
|
|
2728
|
+
itemHash: args.itemHash,
|
|
2729
|
+
detail: "Publishing the host port mapping into the guest relay configuration."
|
|
2730
|
+
});
|
|
2731
|
+
if (profile === "orbitdb-relay-pinner") {
|
|
2732
|
+
const tcpPort = mappedPorts2["9091"]?.host ?? 0;
|
|
2733
|
+
const wsPort = mappedPorts2["9092"]?.host ?? mappedPorts2["443"]?.host ?? 0;
|
|
2734
|
+
if (!tcpPort || !wsPort) {
|
|
2735
|
+
throw new Error("OrbitDB relay runtime is missing required mapped TCP/WS ports.");
|
|
2736
|
+
}
|
|
2737
|
+
await configureOrbitdbRelaySetup2({
|
|
2738
|
+
hostIpv4: args.runtime.hostIpv4,
|
|
2739
|
+
publicIpv6: args.runtime.ipv6,
|
|
2740
|
+
setupPort,
|
|
2741
|
+
tcpPort,
|
|
2742
|
+
wsPort,
|
|
2743
|
+
proxyUrl: args.runtime.proxyUrl ?? void 0,
|
|
2744
|
+
metricsPort: mappedPorts2["9090"]?.host ?? null,
|
|
2745
|
+
metricsHttpsPort: mappedPorts2["443"]?.host ?? null,
|
|
2746
|
+
webrtcPort: mappedPorts2["9093"]?.host ?? null,
|
|
2747
|
+
quicPort: mappedPorts2["9094"]?.host ?? null,
|
|
2748
|
+
fetch: (url, init) => fetch(url, init),
|
|
2749
|
+
timeoutMs: 18e4
|
|
2750
|
+
});
|
|
2751
|
+
} else {
|
|
2752
|
+
await configureUcGoPeer({
|
|
2753
|
+
hostIpv4: args.runtime.hostIpv4,
|
|
2754
|
+
publicIpv6: args.runtime.ipv6,
|
|
2755
|
+
setupPort,
|
|
2756
|
+
tcpPort: mappedPorts2["9095"]?.host ?? null,
|
|
2757
|
+
wsPort: mappedPorts2["9097"]?.host ?? mappedPorts2["9095"]?.host ?? null,
|
|
2758
|
+
udpPort: mappedPorts2["9095"]?.udp === true ? mappedPorts2["9095"]?.host ?? null : null,
|
|
2759
|
+
quicPort: mappedPorts2["9095"]?.udp === true ? mappedPorts2["9095"]?.host ?? null : null,
|
|
2760
|
+
webrtcPort: mappedPorts2["9095"]?.udp === true ? mappedPorts2["9095"]?.host ?? null : null,
|
|
2761
|
+
proxyUrl: args.runtime.proxyUrl ?? void 0,
|
|
2762
|
+
fetch: (url, init) => fetch(url, init),
|
|
2763
|
+
timeoutMs: 18e4
|
|
2764
|
+
});
|
|
2765
|
+
}
|
|
2766
|
+
this.emitProgress({
|
|
2767
|
+
stage: "publishing-bootstrap",
|
|
2768
|
+
label: "Reading relay multiaddrs",
|
|
2769
|
+
progress: 95,
|
|
2770
|
+
status: "info",
|
|
2771
|
+
itemHash: args.itemHash,
|
|
2772
|
+
detail: "Waiting for the relay to report its final public multiaddrs."
|
|
2773
|
+
});
|
|
2774
|
+
const metadataResult = await fetchUcGoPeerMetadata({
|
|
2775
|
+
hostIpv4: args.runtime.hostIpv4,
|
|
2776
|
+
setupPort,
|
|
2777
|
+
fetch: (url, init) => fetch(url, init),
|
|
2778
|
+
attempts: 80,
|
|
2779
|
+
delayMs: 3e3,
|
|
2780
|
+
timeoutMs: 24e4
|
|
2781
|
+
});
|
|
2782
|
+
const metadata = metadataResult && typeof metadataResult === "object" && metadataResult.metadata && typeof metadataResult.metadata === "object" ? metadataResult.metadata : null;
|
|
2783
|
+
const peerId = typeof metadata?.peer_id === "string" ? metadata.peer_id : null;
|
|
2784
|
+
const probeMultiaddrs = Array.isArray(metadata?.probe_multiaddrs) ? metadata.probe_multiaddrs.filter(
|
|
2785
|
+
(entry) => typeof entry === "string"
|
|
2786
|
+
) : [];
|
|
2787
|
+
const browserBootstrapMultiaddrs = Array.isArray(
|
|
2788
|
+
metadata?.browser_bootstrap_multiaddrs
|
|
2789
|
+
) ? metadata.browser_bootstrap_multiaddrs.filter(
|
|
2790
|
+
(entry) => typeof entry === "string"
|
|
2791
|
+
) : [];
|
|
2792
|
+
if (!peerId || probeMultiaddrs.length === 0) {
|
|
2793
|
+
throw new Error("Relay metadata did not include a peer ID and public multiaddrs.");
|
|
2794
|
+
}
|
|
2795
|
+
this.emitProgress({
|
|
2796
|
+
stage: "publishing-bootstrap",
|
|
2797
|
+
label: "Publishing bootstrap registration",
|
|
2798
|
+
progress: 96,
|
|
2799
|
+
status: "info",
|
|
2800
|
+
itemHash: args.itemHash,
|
|
2801
|
+
detail: "Writing the relay bootstrap registration to Aleph."
|
|
2802
|
+
});
|
|
2803
|
+
const publication = await publishRelayBootstrapRegistration({
|
|
2804
|
+
sender: this.state.wallet.address,
|
|
2805
|
+
signer: personalSign,
|
|
2806
|
+
hasher: sha256Hex,
|
|
2807
|
+
fetch: (url, init) => fetch(url, init).then(async (response) => ({
|
|
2808
|
+
ok: response.ok,
|
|
2809
|
+
status: response.status,
|
|
2810
|
+
json: async () => await response.json()
|
|
2811
|
+
})),
|
|
2812
|
+
apiHost: this.client.apiHost,
|
|
2813
|
+
peerId,
|
|
2814
|
+
multiaddrs: probeMultiaddrs,
|
|
2815
|
+
browserMultiaddrs: browserBootstrapMultiaddrs,
|
|
2816
|
+
profile,
|
|
2817
|
+
version: this.state.manifest?.version,
|
|
2818
|
+
sync: true
|
|
2819
|
+
});
|
|
2820
|
+
this.trace("deploy:bootstrap-registration", {
|
|
2821
|
+
itemHash: args.itemHash,
|
|
2822
|
+
peerId,
|
|
2823
|
+
metadata,
|
|
2824
|
+
publication
|
|
2825
|
+
});
|
|
2826
|
+
}
|
|
2277
2827
|
syncLatestDeploymentProgress(instances) {
|
|
2278
2828
|
const itemHash = this.state.lastDeploymentHash;
|
|
2279
2829
|
if (!itemHash) {
|
|
@@ -2285,6 +2835,9 @@ var SponsorRelayController = class {
|
|
|
2285
2835
|
if (!latest) {
|
|
2286
2836
|
return;
|
|
2287
2837
|
}
|
|
2838
|
+
const currentProgress = this.state.deploymentProgress;
|
|
2839
|
+
const currentProgressIsForLatestHash = currentProgress.itemHash === itemHash || currentProgress.itemHash == null && currentProgress.stage !== "idle" && currentProgress.stage !== "error";
|
|
2840
|
+
const keepTerminalSuccess = this.lastRuntimeReadyHash === itemHash || currentProgressIsForLatestHash && currentProgress.stage === "completed" && currentProgress.status === "success";
|
|
2288
2841
|
const status = latest.details.messageStatus;
|
|
2289
2842
|
if (status === "rejected") {
|
|
2290
2843
|
this.emitProgress({
|
|
@@ -2299,6 +2852,14 @@ var SponsorRelayController = class {
|
|
|
2299
2852
|
return;
|
|
2300
2853
|
}
|
|
2301
2854
|
if (status !== "processed") {
|
|
2855
|
+
if (keepTerminalSuccess) {
|
|
2856
|
+
this.trace("progress:retain-completed", {
|
|
2857
|
+
reason: "latest refresh still reports non-processed status",
|
|
2858
|
+
itemHash,
|
|
2859
|
+
status
|
|
2860
|
+
});
|
|
2861
|
+
return;
|
|
2862
|
+
}
|
|
2302
2863
|
const submittedAtMs = instanceTimestampMs(latest.instance);
|
|
2303
2864
|
const pendingTooLong = submittedAtMs != null && Date.now() - submittedAtMs >= DEPLOYMENT_PENDING_WARNING_MS;
|
|
2304
2865
|
this.emitProgress({
|
|
@@ -2312,6 +2873,13 @@ var SponsorRelayController = class {
|
|
|
2312
2873
|
return;
|
|
2313
2874
|
}
|
|
2314
2875
|
if (!hasUsableRuntime(latest.details)) {
|
|
2876
|
+
if (keepTerminalSuccess) {
|
|
2877
|
+
this.trace("progress:retain-completed", {
|
|
2878
|
+
reason: "latest refresh lacks runtime details after completed state",
|
|
2879
|
+
itemHash
|
|
2880
|
+
});
|
|
2881
|
+
return;
|
|
2882
|
+
}
|
|
2315
2883
|
this.emitProgress({
|
|
2316
2884
|
stage: "deployment-confirmed",
|
|
2317
2885
|
label: "Waiting for runtime",
|
|
@@ -2358,8 +2926,42 @@ var SponsorRelayController = class {
|
|
|
2358
2926
|
Date.now() + STALE_INSTANCE_ALLOCATION_COOLDOWN_MS
|
|
2359
2927
|
);
|
|
2360
2928
|
}
|
|
2929
|
+
rememberRuntimeDetails(itemHash, details) {
|
|
2930
|
+
if (!hasUsableRuntime(details)) {
|
|
2931
|
+
return;
|
|
2932
|
+
}
|
|
2933
|
+
this.runtimeDetailsByHash.set(itemHash, {
|
|
2934
|
+
...details,
|
|
2935
|
+
mappedPorts: [...details.mappedPorts]
|
|
2936
|
+
});
|
|
2937
|
+
}
|
|
2938
|
+
mergeRememberedRuntimeDetails(itemHash, details) {
|
|
2939
|
+
const remembered = this.runtimeDetailsByHash.get(itemHash);
|
|
2940
|
+
if (!remembered) {
|
|
2941
|
+
return details;
|
|
2942
|
+
}
|
|
2943
|
+
if (details.messageStatus === "processed" && hasUsableRuntime(details)) {
|
|
2944
|
+
return details;
|
|
2945
|
+
}
|
|
2946
|
+
this.trace("runtime:retain-known-details", {
|
|
2947
|
+
itemHash,
|
|
2948
|
+
currentStatus: details.messageStatus,
|
|
2949
|
+
rememberedStatus: remembered.messageStatus,
|
|
2950
|
+
currentHasRuntime: hasUsableRuntime(details)
|
|
2951
|
+
});
|
|
2952
|
+
return {
|
|
2953
|
+
...details,
|
|
2954
|
+
...remembered,
|
|
2955
|
+
error: details.error ?? remembered.error
|
|
2956
|
+
};
|
|
2957
|
+
}
|
|
2361
2958
|
async init() {
|
|
2959
|
+
this.trace("init:start", {
|
|
2960
|
+
launcherMode: this.props.launcherMode ?? "floating",
|
|
2961
|
+
manifestUrl: this.state.manifestUrl
|
|
2962
|
+
});
|
|
2362
2963
|
this.stopWalletWatch = watchWallet(() => {
|
|
2964
|
+
this.trace("wallet:changed");
|
|
2363
2965
|
void this.refreshWalletDerivedState();
|
|
2364
2966
|
});
|
|
2365
2967
|
await this.refresh();
|
|
@@ -2371,6 +2973,7 @@ var SponsorRelayController = class {
|
|
|
2371
2973
|
}, RELAY_PING_INTERVAL_MS);
|
|
2372
2974
|
await this.refreshRelayPing();
|
|
2373
2975
|
this.patch({ ready: true });
|
|
2976
|
+
this.trace("init:ready");
|
|
2374
2977
|
}
|
|
2375
2978
|
destroy() {
|
|
2376
2979
|
if (this.refreshTimer) clearInterval(this.refreshTimer);
|
|
@@ -2471,6 +3074,11 @@ var SponsorRelayController = class {
|
|
|
2471
3074
|
}
|
|
2472
3075
|
}
|
|
2473
3076
|
async refresh() {
|
|
3077
|
+
this.trace("refresh:start", {
|
|
3078
|
+
wallet: this.state.wallet.address,
|
|
3079
|
+
manifestUrl: this.state.manifestUrl,
|
|
3080
|
+
showInstances: this.state.showInstances
|
|
3081
|
+
});
|
|
2474
3082
|
this.patch({
|
|
2475
3083
|
busy: { refreshing: true },
|
|
2476
3084
|
errorText: null,
|
|
@@ -2496,29 +3104,58 @@ var SponsorRelayController = class {
|
|
|
2496
3104
|
balance = nextBalance;
|
|
2497
3105
|
instances = await Promise.all(
|
|
2498
3106
|
rawInstances.map(async (instance) => {
|
|
2499
|
-
const
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
3107
|
+
const inspected = this.canSkipRuntimeRefresh(instance) ? {
|
|
3108
|
+
details: {
|
|
3109
|
+
messageStatus: String(
|
|
3110
|
+
instance.status ?? (instance.confirmed ? "processed" : "pending")
|
|
3111
|
+
).toLowerCase(),
|
|
3112
|
+
allocationSource: null,
|
|
3113
|
+
crnUrl: null,
|
|
3114
|
+
hostIpv4: null,
|
|
3115
|
+
ipv6: null,
|
|
3116
|
+
vmIpv4: null,
|
|
3117
|
+
webUrl: null,
|
|
3118
|
+
sshCommand: null,
|
|
3119
|
+
mappedPorts: [],
|
|
3120
|
+
execution: null,
|
|
3121
|
+
error: null
|
|
3122
|
+
},
|
|
3123
|
+
lookup: {
|
|
3124
|
+
allocationFound: false,
|
|
3125
|
+
allocationSource: null,
|
|
3126
|
+
crnUrl: null,
|
|
3127
|
+
webUrl: null,
|
|
3128
|
+
executionPayloadFound: false,
|
|
3129
|
+
executionLookupBlocked: false,
|
|
3130
|
+
executionLookupRequestUrl: null,
|
|
3131
|
+
executionLookupVersion: null
|
|
3132
|
+
}
|
|
2513
3133
|
} : await inspectInstanceRuntime({
|
|
2514
3134
|
client: this.client,
|
|
2515
3135
|
instance,
|
|
2516
3136
|
crns
|
|
2517
3137
|
});
|
|
2518
|
-
|
|
3138
|
+
const details = inspected.details;
|
|
3139
|
+
const mergedDetails = this.mergeRememberedRuntimeDetails(
|
|
3140
|
+
instance.item_hash,
|
|
3141
|
+
details
|
|
3142
|
+
);
|
|
3143
|
+
if (this.debugEnabled && instance.item_hash === this.state.lastDeploymentHash) {
|
|
3144
|
+
this.trace("runtime:inspect-result", {
|
|
3145
|
+
itemHash: instance.item_hash,
|
|
3146
|
+
messageStatus: details.messageStatus,
|
|
3147
|
+
hostIpv4: details.hostIpv4,
|
|
3148
|
+
vmIpv4: details.vmIpv4,
|
|
3149
|
+
mappedPorts: details.mappedPorts,
|
|
3150
|
+
error: details.error,
|
|
3151
|
+
lookup: inspected.lookup
|
|
3152
|
+
});
|
|
3153
|
+
}
|
|
3154
|
+
this.rememberRuntimeDetails(instance.item_hash, mergedDetails);
|
|
3155
|
+
this.noteRuntimeRefreshResult(instance, mergedDetails);
|
|
2519
3156
|
return {
|
|
2520
3157
|
instance,
|
|
2521
|
-
details
|
|
3158
|
+
details: mergedDetails
|
|
2522
3159
|
};
|
|
2523
3160
|
})
|
|
2524
3161
|
);
|
|
@@ -2555,9 +3192,15 @@ var SponsorRelayController = class {
|
|
|
2555
3192
|
busy: { refreshing: false },
|
|
2556
3193
|
statusText: "Relay sponsor data ready"
|
|
2557
3194
|
});
|
|
3195
|
+
this.trace("refresh:success", {
|
|
3196
|
+
manifestValid: manifestState.valid,
|
|
3197
|
+
rootfsVerified,
|
|
3198
|
+
instances: instances.length
|
|
3199
|
+
});
|
|
2558
3200
|
this.recomputePricingSummary();
|
|
2559
3201
|
this.syncLatestDeploymentProgress(instances);
|
|
2560
3202
|
} catch (error) {
|
|
3203
|
+
this.trace("refresh:error", error);
|
|
2561
3204
|
this.patch({
|
|
2562
3205
|
busy: { refreshing: false },
|
|
2563
3206
|
errorText: error instanceof Error ? error.message : String(error),
|
|
@@ -2568,8 +3211,17 @@ var SponsorRelayController = class {
|
|
|
2568
3211
|
async refreshRelayPing() {
|
|
2569
3212
|
const relayPing = await pingPeer(this.props.libp2p);
|
|
2570
3213
|
this.patch({ relayPing });
|
|
3214
|
+
this.trace("libp2p:relay-ping", relayPing);
|
|
2571
3215
|
}
|
|
2572
3216
|
async deploy() {
|
|
3217
|
+
this.trace("deploy:start", {
|
|
3218
|
+
wallet: this.state.wallet.address,
|
|
3219
|
+
instanceName: this.state.instanceName,
|
|
3220
|
+
tierId: this.state.tierId,
|
|
3221
|
+
selectedCrn: this.state.selectedCrn?.name ?? null,
|
|
3222
|
+
manifestRootfsItemHash: this.state.manifest?.rootfsItemHash ?? null,
|
|
3223
|
+
requiredPortForwards: this.state.manifest?.requiredPortForwards ?? []
|
|
3224
|
+
});
|
|
2573
3225
|
if (!this.state.wallet.address) {
|
|
2574
3226
|
this.patch({ errorText: "Connect MetaMask before deploying." });
|
|
2575
3227
|
return;
|
|
@@ -2634,6 +3286,8 @@ var SponsorRelayController = class {
|
|
|
2634
3286
|
statusText: `Deployment submitted: ${result.itemHash}`,
|
|
2635
3287
|
lastDeploymentHash: result.itemHash
|
|
2636
3288
|
});
|
|
3289
|
+
this.trace("deploy:broadcasted", result);
|
|
3290
|
+
this.lastRuntimeReadyHash = null;
|
|
2637
3291
|
const inspection = await waitForDeploymentResult2(result.itemHash, {
|
|
2638
3292
|
rootfsRef: this.state.manifest.rootfsItemHash,
|
|
2639
3293
|
apiHost: this.client.apiHost,
|
|
@@ -2679,6 +3333,7 @@ var SponsorRelayController = class {
|
|
|
2679
3333
|
inspection.rejectionReason ?? `Deployment ${result.itemHash} stayed ${inspection.status} on Aleph.`
|
|
2680
3334
|
);
|
|
2681
3335
|
}
|
|
3336
|
+
this.trace("deploy:aleph-processed", inspection);
|
|
2682
3337
|
if ((this.state.manifest.requiredPortForwards?.length ?? 0) > 0) {
|
|
2683
3338
|
this.emitProgress({
|
|
2684
3339
|
stage: "refreshing-instances",
|
|
@@ -2698,8 +3353,18 @@ var SponsorRelayController = class {
|
|
|
2698
3353
|
apiHost: this.client.apiHost,
|
|
2699
3354
|
sync: true
|
|
2700
3355
|
});
|
|
3356
|
+
this.trace("deploy:port-forwards-published", {
|
|
3357
|
+
itemHash: result.itemHash,
|
|
3358
|
+
requiredPortForwards: this.state.manifest.requiredPortForwards
|
|
3359
|
+
});
|
|
2701
3360
|
}
|
|
2702
3361
|
if (this.state.selectedCrn?.address) {
|
|
3362
|
+
this.trace("deploy:notifying-crn", {
|
|
3363
|
+
itemHash: result.itemHash,
|
|
3364
|
+
crnName: this.state.selectedCrn.name,
|
|
3365
|
+
crnHash: this.state.selectedCrn.hash,
|
|
3366
|
+
crnUrl: this.state.selectedCrn.address
|
|
3367
|
+
});
|
|
2703
3368
|
await notifyCrnAllocationWithRetry({
|
|
2704
3369
|
crnUrl: this.state.selectedCrn.address,
|
|
2705
3370
|
itemHash: result.itemHash,
|
|
@@ -2752,6 +3417,25 @@ var SponsorRelayController = class {
|
|
|
2752
3417
|
runtime.diagnostics?.reason ?? "Deployment was processed, but runtime networking never exposed mapped ports."
|
|
2753
3418
|
);
|
|
2754
3419
|
}
|
|
3420
|
+
this.trace("deploy:runtime-ready", runtime);
|
|
3421
|
+
this.lastRuntimeReadyHash = result.itemHash;
|
|
3422
|
+
this.rememberRuntimeDetails(result.itemHash, {
|
|
3423
|
+
messageStatus: "processed",
|
|
3424
|
+
allocationSource: runtime.allocation?.source ?? null,
|
|
3425
|
+
crnUrl: runtime.allocation?.crnUrl ?? runtime.execution?.crnUrl ?? null,
|
|
3426
|
+
hostIpv4: runtime.hostIpv4 ?? null,
|
|
3427
|
+
ipv6: runtime.ipv6 ?? null,
|
|
3428
|
+
vmIpv4: runtime.execution?.networking?.ipv4_ip ?? null,
|
|
3429
|
+
webUrl: runtime.webAccessUrl ?? runtime.proxyUrl ?? runtime.execution?.networking?.proxy_url ?? null,
|
|
3430
|
+
sshCommand: runtime.sshCommand ?? null,
|
|
3431
|
+
mappedPorts: runtime.execution != null ? mappedPorts(runtime.execution) : runtimeMappedPorts(runtime.mappedPorts),
|
|
3432
|
+
execution: runtime.execution ?? null,
|
|
3433
|
+
error: null
|
|
3434
|
+
});
|
|
3435
|
+
await this.configureRelayBootstrapRegistration({
|
|
3436
|
+
itemHash: result.itemHash,
|
|
3437
|
+
runtime
|
|
3438
|
+
});
|
|
2755
3439
|
this.patch({
|
|
2756
3440
|
busy: { deploying: false }
|
|
2757
3441
|
});
|
|
@@ -2765,6 +3449,7 @@ var SponsorRelayController = class {
|
|
|
2765
3449
|
});
|
|
2766
3450
|
await this.refresh();
|
|
2767
3451
|
} catch (error) {
|
|
3452
|
+
this.trace("deploy:error", error);
|
|
2768
3453
|
this.patch({
|
|
2769
3454
|
busy: { deploying: false },
|
|
2770
3455
|
errorText: error instanceof Error ? error.message : String(error),
|
|
@@ -2780,6 +3465,7 @@ var SponsorRelayController = class {
|
|
|
2780
3465
|
}
|
|
2781
3466
|
}
|
|
2782
3467
|
async deleteInstance(instanceHash) {
|
|
3468
|
+
this.trace("delete:start", { instanceHash });
|
|
2783
3469
|
if (!this.state.wallet.address) {
|
|
2784
3470
|
this.patch({ errorText: "Connect MetaMask before deleting instances." });
|
|
2785
3471
|
return;
|
|
@@ -2827,6 +3513,7 @@ var SponsorRelayController = class {
|
|
|
2827
3513
|
detail: "Reloading current deployments."
|
|
2828
3514
|
});
|
|
2829
3515
|
await this.refresh();
|
|
3516
|
+
this.trace("delete:submitted", { instanceHash });
|
|
2830
3517
|
this.emitProgress({
|
|
2831
3518
|
stage: "completed",
|
|
2832
3519
|
label: "Delete completed",
|
|
@@ -2837,6 +3524,7 @@ var SponsorRelayController = class {
|
|
|
2837
3524
|
error: null
|
|
2838
3525
|
});
|
|
2839
3526
|
} catch (error) {
|
|
3527
|
+
this.trace("delete:error", error);
|
|
2840
3528
|
this.patch({
|
|
2841
3529
|
busy: { deletingInstanceHash: null },
|
|
2842
3530
|
errorText: error instanceof Error ? error.message : String(error),
|