@le-space/ui 0.3.31 → 0.4.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 +34 -0
- package/react/index.js +451 -492
- package/shared/index.d.ts +38 -2
- package/shared/index.js +269 -443
- package/svelte/SponsorRelayFab.svelte +96 -0
package/react/index.js
CHANGED
|
@@ -10,6 +10,16 @@ var ROOTFS_MISSING_STATE = {
|
|
|
10
10
|
label: "manifest missing",
|
|
11
11
|
detail: "Provide a manifest URL or paste manifest JSON."
|
|
12
12
|
};
|
|
13
|
+
var RELAY_PING_IDLE_STATE = {
|
|
14
|
+
tone: "idle",
|
|
15
|
+
sent: false,
|
|
16
|
+
received: false,
|
|
17
|
+
lastPeerId: null,
|
|
18
|
+
lastLatencyMs: null,
|
|
19
|
+
lastSentAt: null,
|
|
20
|
+
lastReceivedAt: null,
|
|
21
|
+
error: null
|
|
22
|
+
};
|
|
13
23
|
var IDLE_DEPLOYMENT_PROGRESS = {
|
|
14
24
|
stage: "idle",
|
|
15
25
|
label: "Ready",
|
|
@@ -21,6 +31,7 @@ var IDLE_DEPLOYMENT_PROGRESS = {
|
|
|
21
31
|
timestamp: Date.now()
|
|
22
32
|
};
|
|
23
33
|
var REFRESH_INTERVAL_MS = 3e4;
|
|
34
|
+
var RELAY_PING_INTERVAL_MS = 2e4;
|
|
24
35
|
var MANIFEST_SOURCE_REFRESH_DEBOUNCE_MS = 400;
|
|
25
36
|
var INSTANCE_RUNTIME_STALE_REFRESH_MS = 5 * 6e4;
|
|
26
37
|
var STALE_INSTANCE_ALLOCATION_COOLDOWN_MS = 5 * 60 * 1e3;
|
|
@@ -28,7 +39,7 @@ var RECENT_INSTANCE_RUNTIME_GRACE_MS = 10 * 60 * 1e3;
|
|
|
28
39
|
var DEPLOYMENT_PENDING_WARNING_MS = 3 * 60 * 1e3;
|
|
29
40
|
|
|
30
41
|
// src/shared/package-version.ts
|
|
31
|
-
var UI_PACKAGE_VERSION = "0.
|
|
42
|
+
var UI_PACKAGE_VERSION = "0.4.0";
|
|
32
43
|
|
|
33
44
|
// src/shared/format.ts
|
|
34
45
|
function shortHash(value, head = 8, tail = 6) {
|
|
@@ -1237,6 +1248,16 @@ function normalizeBroadcastStatus(httpStatus, responseStatus) {
|
|
|
1237
1248
|
if (httpStatus === 202) return "pending";
|
|
1238
1249
|
return normalizeMessageStatus2(responseStatus);
|
|
1239
1250
|
}
|
|
1251
|
+
function isInvalidMessageFormatResponse2(response, payload) {
|
|
1252
|
+
if (response.status !== 422) return false;
|
|
1253
|
+
const details = payload?.details;
|
|
1254
|
+
if (typeof details === "string" && details.includes("InvalidMessageFormat")) return true;
|
|
1255
|
+
if (details && typeof details === "object") {
|
|
1256
|
+
const detailMessage = details.message;
|
|
1257
|
+
if (typeof detailMessage === "string" && detailMessage.includes("InvalidMessageFormat")) return true;
|
|
1258
|
+
}
|
|
1259
|
+
return false;
|
|
1260
|
+
}
|
|
1240
1261
|
function isRetryableBroadcastFailure(response, payload) {
|
|
1241
1262
|
if (response.status >= 500) return true;
|
|
1242
1263
|
const publicationStatus = payload?.publication_status?.status;
|
|
@@ -1258,22 +1279,25 @@ async function postBroadcastPayload2(body, options) {
|
|
|
1258
1279
|
};
|
|
1259
1280
|
}
|
|
1260
1281
|
async function broadcastAlephMessage2(message, options) {
|
|
1261
|
-
const
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1282
|
+
const attempts = [
|
|
1283
|
+
{ sync: options.sync ?? false, message },
|
|
1284
|
+
{ ...message, sync: options.sync ?? false },
|
|
1285
|
+
{ ...message }
|
|
1286
|
+
];
|
|
1287
|
+
for (let index = 0; index < attempts.length; index += 1) {
|
|
1288
|
+
const result = await postBroadcastPayload2(attempts[index], {
|
|
1265
1289
|
apiHost: options.apiHost,
|
|
1266
1290
|
fetch: options.fetch
|
|
1267
1291
|
});
|
|
1268
1292
|
if (result.httpStatus === 202 || normalizeBroadcastStatus(result.httpStatus, result.response?.message_status) !== "unknown" || result.httpStatus >= 200 && result.httpStatus < 300) {
|
|
1269
1293
|
return result;
|
|
1270
1294
|
}
|
|
1271
|
-
const canRetry = index <
|
|
1295
|
+
const canRetry = index < attempts.length - 1 && (isInvalidMessageFormatResponse2({ status: result.httpStatus }, result.response) || isRetryableBroadcastFailure({ status: result.httpStatus }, result.response));
|
|
1272
1296
|
if (!canRetry) {
|
|
1273
1297
|
throw new Error(`Broadcast failed: ${result.httpStatus} ${JSON.stringify(result.response ?? {})}`);
|
|
1274
1298
|
}
|
|
1275
1299
|
}
|
|
1276
|
-
throw new Error("Broadcast failed:
|
|
1300
|
+
throw new Error("Broadcast failed: no compatible request format was accepted");
|
|
1277
1301
|
}
|
|
1278
1302
|
|
|
1279
1303
|
// ../core/src/forget.ts
|
|
@@ -1878,13 +1902,6 @@ async function waitForVmRuntime(args) {
|
|
|
1878
1902
|
}
|
|
1879
1903
|
|
|
1880
1904
|
// ../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
|
-
}
|
|
1888
1905
|
async function defaultHttpProbe(fetch2, url, timeoutMs = 1e4) {
|
|
1889
1906
|
try {
|
|
1890
1907
|
const controller = new AbortController();
|
|
@@ -2126,59 +2143,6 @@ async function fetchUcGoPeerMetadata(args) {
|
|
|
2126
2143
|
`Relay metadata did not become ready after ${attempts} attempts: ${lastError ? lastError : typeof lastPayload === "string" ? lastPayload : JSON.stringify(lastPayload ?? {})}`
|
|
2127
2144
|
);
|
|
2128
2145
|
}
|
|
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
|
-
}
|
|
2182
2146
|
|
|
2183
2147
|
// ../aleph-bootstrap/src/index.ts
|
|
2184
2148
|
import { recoverMessageAddress } from "viem";
|
|
@@ -2720,16 +2684,6 @@ async function publishRelayBootstrapRegistration(args) {
|
|
|
2720
2684
|
|
|
2721
2685
|
// ../core/src/bootstrap-config.ts
|
|
2722
2686
|
var VM_BOOTSTRAP_CONFIG_AGGREGATE_KEY = "vm-bootstrap-config";
|
|
2723
|
-
var VM_BOOTSTRAP_CONFIG_SIGNAL_REF = "vm-bootstrap-config";
|
|
2724
|
-
var VM_BOOTSTRAP_CONFIG_SIGNAL_POST_TYPE = "vm-bootstrap-config-status";
|
|
2725
|
-
function parseJsonObject(value) {
|
|
2726
|
-
try {
|
|
2727
|
-
const parsed = JSON.parse(value);
|
|
2728
|
-
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
2729
|
-
} catch {
|
|
2730
|
-
return null;
|
|
2731
|
-
}
|
|
2732
|
-
}
|
|
2733
2687
|
async function fetchVmBootstrapConfigAggregate(address, options) {
|
|
2734
2688
|
const requestUrl = new URL(`/api/v0/aggregates/${address}.json`, options.apiHost ?? DEFAULT_ALEPH_API_HOST2);
|
|
2735
2689
|
requestUrl.searchParams.set("keys", VM_BOOTSTRAP_CONFIG_AGGREGATE_KEY);
|
|
@@ -2849,89 +2803,6 @@ async function deleteVmBootstrapConfig(args) {
|
|
|
2849
2803
|
aggregate: content
|
|
2850
2804
|
};
|
|
2851
2805
|
}
|
|
2852
|
-
function normalizeVmBootstrapConfigSignalRecord(value) {
|
|
2853
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
2854
|
-
const candidate = value;
|
|
2855
|
-
const deploymentToken = typeof candidate.deploymentToken === "string" ? candidate.deploymentToken.trim() : "";
|
|
2856
|
-
const status = typeof candidate.status === "string" ? candidate.status.trim() : "";
|
|
2857
|
-
const profile = typeof candidate.profile === "string" ? candidate.profile.trim() : "";
|
|
2858
|
-
const ownerAddress = typeof candidate.ownerAddress === "string" ? candidate.ownerAddress.trim() : "";
|
|
2859
|
-
const instanceItemHash = typeof candidate.instanceItemHash === "string" ? candidate.instanceItemHash.trim() : "";
|
|
2860
|
-
const updatedAt = typeof candidate.updatedAt === "string" ? candidate.updatedAt.trim() : "";
|
|
2861
|
-
if (!deploymentToken || !status || !profile || !ownerAddress || !instanceItemHash || !updatedAt) {
|
|
2862
|
-
return null;
|
|
2863
|
-
}
|
|
2864
|
-
return {
|
|
2865
|
-
deploymentToken,
|
|
2866
|
-
status,
|
|
2867
|
-
profile,
|
|
2868
|
-
ownerAddress,
|
|
2869
|
-
instanceItemHash,
|
|
2870
|
-
updatedAt,
|
|
2871
|
-
publisherAddress: typeof candidate.publisherAddress === "string" && candidate.publisherAddress.trim() ? candidate.publisherAddress.trim() : null,
|
|
2872
|
-
authorization: candidate.authorization,
|
|
2873
|
-
peerId: typeof candidate.peerId === "string" && candidate.peerId.trim() ? candidate.peerId.trim() : null,
|
|
2874
|
-
probeMultiaddrs: Array.isArray(candidate.probeMultiaddrs) ? candidate.probeMultiaddrs.filter(
|
|
2875
|
-
(entry) => typeof entry === "string" && entry.trim().length > 0
|
|
2876
|
-
) : [],
|
|
2877
|
-
browserBootstrapMultiaddrs: Array.isArray(candidate.browserBootstrapMultiaddrs) ? candidate.browserBootstrapMultiaddrs.filter(
|
|
2878
|
-
(entry) => typeof entry === "string" && entry.trim().length > 0
|
|
2879
|
-
) : []
|
|
2880
|
-
};
|
|
2881
|
-
}
|
|
2882
|
-
async function fetchVmBootstrapConfigSignals(args) {
|
|
2883
|
-
const requestUrl = new URL("/api/v0/posts.json", args.apiHost ?? DEFAULT_ALEPH_API_HOST2);
|
|
2884
|
-
requestUrl.searchParams.set("refs", args.ref ?? VM_BOOTSTRAP_CONFIG_SIGNAL_REF);
|
|
2885
|
-
requestUrl.searchParams.set("types", args.postType ?? VM_BOOTSTRAP_CONFIG_SIGNAL_POST_TYPE);
|
|
2886
|
-
requestUrl.searchParams.set("pagination", String(Math.max(1, Number(args.pagination ?? 100))));
|
|
2887
|
-
requestUrl.searchParams.set("page", String(Math.max(1, Number(args.page ?? 1))));
|
|
2888
|
-
requestUrl.searchParams.set("sortOrder", "-1");
|
|
2889
|
-
const response = await args.fetch(requestUrl.toString(), { cache: "no-cache" });
|
|
2890
|
-
if (!response.ok) {
|
|
2891
|
-
throw new Error(`VM bootstrap config signal request failed: ${response.status}`);
|
|
2892
|
-
}
|
|
2893
|
-
const payload = await response.json();
|
|
2894
|
-
const expectedDeploymentToken = args.deploymentToken?.trim() ?? "";
|
|
2895
|
-
const expectedOwnerAddress = args.ownerAddress?.trim().toLowerCase() ?? "";
|
|
2896
|
-
const expectedInstanceItemHash = args.instanceItemHash?.trim() ?? "";
|
|
2897
|
-
return (payload.posts ?? []).map((entry) => {
|
|
2898
|
-
if (!entry || typeof entry !== "object" || Array.isArray(entry)) return null;
|
|
2899
|
-
const parsed = "content" in entry && entry.content && typeof entry.content === "object" && !Array.isArray(entry.content) ? entry.content : "item_content" in entry && typeof entry.item_content === "string" ? parseJsonObject(entry.item_content) : null;
|
|
2900
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
2901
|
-
const content = "deploymentToken" in parsed ? parsed : "content" in parsed && parsed.content && typeof parsed.content === "object" && !Array.isArray(parsed.content) ? parsed.content : null;
|
|
2902
|
-
if (!content || typeof content !== "object" || Array.isArray(content)) return null;
|
|
2903
|
-
return normalizeVmBootstrapConfigSignalRecord(content);
|
|
2904
|
-
}).filter((entry) => {
|
|
2905
|
-
if (!entry) return false;
|
|
2906
|
-
if (expectedDeploymentToken && entry.deploymentToken !== expectedDeploymentToken) return false;
|
|
2907
|
-
if (expectedOwnerAddress && entry.ownerAddress.toLowerCase() !== expectedOwnerAddress) return false;
|
|
2908
|
-
if (expectedInstanceItemHash && entry.instanceItemHash !== expectedInstanceItemHash) return false;
|
|
2909
|
-
return true;
|
|
2910
|
-
});
|
|
2911
|
-
}
|
|
2912
|
-
async function waitForVmBootstrapConfigSignal(args) {
|
|
2913
|
-
const attempts = Math.max(1, Number(args.attempts ?? 24));
|
|
2914
|
-
const delayMs = Math.max(0, Number(args.delayMs ?? 2500));
|
|
2915
|
-
const sleep2 = args.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
2916
|
-
const expectedStatus = args.expectedStatus ?? "applied";
|
|
2917
|
-
for (let attempt = 0; attempt < attempts; attempt += 1) {
|
|
2918
|
-
const signals = await fetchVmBootstrapConfigSignals({
|
|
2919
|
-
deploymentToken: args.deploymentToken,
|
|
2920
|
-
ownerAddress: args.ownerAddress,
|
|
2921
|
-
instanceItemHash: args.instanceItemHash,
|
|
2922
|
-
fetch: args.fetch,
|
|
2923
|
-
apiHost: args.apiHost,
|
|
2924
|
-
ref: args.ref,
|
|
2925
|
-
postType: args.postType
|
|
2926
|
-
}).catch(() => []);
|
|
2927
|
-
const match = signals.find((entry) => entry.status === expectedStatus) ?? null;
|
|
2928
|
-
if (match) return match;
|
|
2929
|
-
if (attempt < attempts - 1) {
|
|
2930
|
-
await sleep2(delayMs);
|
|
2931
|
-
}
|
|
2932
|
-
}
|
|
2933
|
-
return null;
|
|
2934
|
-
}
|
|
2935
2806
|
|
|
2936
2807
|
// ../core/src/bootstrap-reconcile.ts
|
|
2937
2808
|
function createRelayBootstrapRegistrationId(profile, instanceName, itemHash) {
|
|
@@ -3044,7 +2915,8 @@ function defaultState(props = {}) {
|
|
|
3044
2915
|
connectingWallet: false,
|
|
3045
2916
|
refreshing: false,
|
|
3046
2917
|
deploying: false,
|
|
3047
|
-
deletingInstanceHash: null
|
|
2918
|
+
deletingInstanceHash: null,
|
|
2919
|
+
deletingRegistrationHash: null
|
|
3048
2920
|
},
|
|
3049
2921
|
statusText: "Ready",
|
|
3050
2922
|
errorText: null,
|
|
@@ -3070,6 +2942,9 @@ function defaultState(props = {}) {
|
|
|
3070
2942
|
crns: [],
|
|
3071
2943
|
selectedCrn: null,
|
|
3072
2944
|
instances: [],
|
|
2945
|
+
bootstrapRegistrations: [],
|
|
2946
|
+
orphanBootstrapRegistrations: [],
|
|
2947
|
+
relayPing: RELAY_PING_IDLE_STATE,
|
|
3073
2948
|
lastDeploymentHash: null,
|
|
3074
2949
|
deploymentProgress: IDLE_DEPLOYMENT_PROGRESS
|
|
3075
2950
|
};
|
|
@@ -3174,6 +3049,20 @@ function relayProfileForManifest(manifest) {
|
|
|
3174
3049
|
}
|
|
3175
3050
|
return null;
|
|
3176
3051
|
}
|
|
3052
|
+
function registrationIdInstanceItemHash(registrationId) {
|
|
3053
|
+
const normalized = String(registrationId ?? "").trim();
|
|
3054
|
+
if (!normalized) return null;
|
|
3055
|
+
const parts = normalized.split(":").map((part) => part.trim()).filter(Boolean);
|
|
3056
|
+
const candidate = parts.at(-1) ?? "";
|
|
3057
|
+
return /^[0-9a-f]{64}$/i.test(candidate) ? candidate : null;
|
|
3058
|
+
}
|
|
3059
|
+
function relayBootstrapInstanceItemHash(entry) {
|
|
3060
|
+
const authorizedInstanceItemHash = typeof entry?.content?.authorization?.payload?.instanceItemHash === "string" ? entry.content.authorization.payload.instanceItemHash.trim() : "";
|
|
3061
|
+
if (authorizedInstanceItemHash) {
|
|
3062
|
+
return authorizedInstanceItemHash;
|
|
3063
|
+
}
|
|
3064
|
+
return registrationIdInstanceItemHash(entry?.content?.registrationId);
|
|
3065
|
+
}
|
|
3177
3066
|
async function inspectInstanceRuntime(args) {
|
|
3178
3067
|
const details = {
|
|
3179
3068
|
messageStatus: String(
|
|
@@ -3282,12 +3171,61 @@ function compatibleCrnsForTier(crns, state) {
|
|
|
3282
3171
|
);
|
|
3283
3172
|
return filterDeployableCrns(crns, { spec });
|
|
3284
3173
|
}
|
|
3174
|
+
async function pingPeer(libp2p) {
|
|
3175
|
+
if (!libp2p || typeof libp2p !== "object") {
|
|
3176
|
+
return RELAY_PING_IDLE_STATE;
|
|
3177
|
+
}
|
|
3178
|
+
const candidate = libp2p;
|
|
3179
|
+
const peers = candidate.getPeers?.() ?? [];
|
|
3180
|
+
const firstPeer = peers[0];
|
|
3181
|
+
if (!firstPeer) {
|
|
3182
|
+
return {
|
|
3183
|
+
...RELAY_PING_IDLE_STATE,
|
|
3184
|
+
tone: "caution",
|
|
3185
|
+
error: "No connected relay peers available."
|
|
3186
|
+
};
|
|
3187
|
+
}
|
|
3188
|
+
const sentAt = Date.now();
|
|
3189
|
+
try {
|
|
3190
|
+
const pingFn = candidate.services?.ping?.ping?.bind(candidate.services.ping) ?? candidate.ping?.bind(candidate);
|
|
3191
|
+
if (!pingFn) {
|
|
3192
|
+
return {
|
|
3193
|
+
...RELAY_PING_IDLE_STATE,
|
|
3194
|
+
tone: "caution",
|
|
3195
|
+
sent: true,
|
|
3196
|
+
lastPeerId: String(firstPeer),
|
|
3197
|
+
lastSentAt: sentAt,
|
|
3198
|
+
error: "libp2p ping service not available."
|
|
3199
|
+
};
|
|
3200
|
+
}
|
|
3201
|
+
const latency = await pingFn(firstPeer);
|
|
3202
|
+
return {
|
|
3203
|
+
tone: "ok",
|
|
3204
|
+
sent: true,
|
|
3205
|
+
received: true,
|
|
3206
|
+
lastPeerId: String(firstPeer),
|
|
3207
|
+
lastLatencyMs: Number(latency),
|
|
3208
|
+
lastSentAt: sentAt,
|
|
3209
|
+
lastReceivedAt: Date.now(),
|
|
3210
|
+
error: null
|
|
3211
|
+
};
|
|
3212
|
+
} catch (error) {
|
|
3213
|
+
return {
|
|
3214
|
+
tone: "error",
|
|
3215
|
+
sent: true,
|
|
3216
|
+
received: false,
|
|
3217
|
+
lastPeerId: String(firstPeer),
|
|
3218
|
+
lastLatencyMs: null,
|
|
3219
|
+
lastSentAt: sentAt,
|
|
3220
|
+
lastReceivedAt: null,
|
|
3221
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3222
|
+
};
|
|
3223
|
+
}
|
|
3224
|
+
}
|
|
3285
3225
|
var UI_DEPLOY_WAIT_ATTEMPTS = 60;
|
|
3286
3226
|
var UI_DEPLOY_WAIT_DELAY_MS = 5e3;
|
|
3287
3227
|
var UI_RUNTIME_WAIT_ATTEMPTS = 40;
|
|
3288
3228
|
var UI_RUNTIME_WAIT_DELAY_MS = 5e3;
|
|
3289
|
-
var UI_REACHABILITY_VERIFY_ATTEMPTS = 25;
|
|
3290
|
-
var UI_REACHABILITY_VERIFY_DELAY_MS = 3e3;
|
|
3291
3229
|
function hasUsableRuntime(details) {
|
|
3292
3230
|
return Boolean(details.hostIpv4) || Boolean(details.vmIpv4) || details.mappedPorts.length > 0 || Boolean(details.webUrl) || Boolean(details.execution);
|
|
3293
3231
|
}
|
|
@@ -3314,6 +3252,7 @@ var SponsorRelayController = class {
|
|
|
3314
3252
|
subscribers = /* @__PURE__ */ new Set();
|
|
3315
3253
|
client;
|
|
3316
3254
|
refreshTimer = null;
|
|
3255
|
+
pingTimer = null;
|
|
3317
3256
|
manifestRefreshTimer = null;
|
|
3318
3257
|
stopWalletWatch = null;
|
|
3319
3258
|
props;
|
|
@@ -3369,7 +3308,8 @@ var SponsorRelayController = class {
|
|
|
3369
3308
|
...patch,
|
|
3370
3309
|
busy: patch.busy ? { ...this.state.busy, ...patch.busy } : this.state.busy,
|
|
3371
3310
|
wallet: patch.wallet ? { ...this.state.wallet, ...patch.wallet } : this.state.wallet,
|
|
3372
|
-
pricingSummary: patch.pricingSummary ? { ...this.state.pricingSummary, ...patch.pricingSummary } : this.state.pricingSummary
|
|
3311
|
+
pricingSummary: patch.pricingSummary ? { ...this.state.pricingSummary, ...patch.pricingSummary } : this.state.pricingSummary,
|
|
3312
|
+
relayPing: patch.relayPing ? { ...this.state.relayPing, ...patch.relayPing } : this.state.relayPing
|
|
3373
3313
|
};
|
|
3374
3314
|
this.emit();
|
|
3375
3315
|
}
|
|
@@ -3394,21 +3334,19 @@ var SponsorRelayController = class {
|
|
|
3394
3334
|
this.progressEmitter.emit(nextEvent);
|
|
3395
3335
|
}
|
|
3396
3336
|
async configureRelayBootstrapRegistration(args) {
|
|
3397
|
-
let runtime = args.runtime;
|
|
3398
3337
|
const profile = relayProfileForManifest(this.state.manifest);
|
|
3399
3338
|
if (!profile) return;
|
|
3400
3339
|
if (!this.state.wallet.address) {
|
|
3401
3340
|
throw new Error("A connected wallet is required to register relay bootstrap addresses.");
|
|
3402
3341
|
}
|
|
3403
|
-
if (!runtime.hostIpv4) {
|
|
3342
|
+
if (!args.runtime.hostIpv4) {
|
|
3404
3343
|
throw new Error("Relay runtime did not expose a host IPv4 address.");
|
|
3405
3344
|
}
|
|
3406
|
-
|
|
3345
|
+
const mappedPorts2 = args.runtime.mappedPorts ?? {};
|
|
3407
3346
|
const setupPort = mappedPorts2["80"]?.host ?? null;
|
|
3408
3347
|
if (!setupPort) {
|
|
3409
3348
|
throw new Error("Relay runtime did not expose the temporary setup endpoint.");
|
|
3410
3349
|
}
|
|
3411
|
-
let bootstrapSignalRelayMetadata = null;
|
|
3412
3350
|
if (profile === "orbitdb-relay-pinner") {
|
|
3413
3351
|
this.emitProgress({
|
|
3414
3352
|
stage: "deployment-confirmed",
|
|
@@ -3419,7 +3357,7 @@ var SponsorRelayController = class {
|
|
|
3419
3357
|
detail: "Waiting for the guest setup endpoint before collecting relay metadata."
|
|
3420
3358
|
});
|
|
3421
3359
|
const setupHealth = await waitForSetupEndpoint({
|
|
3422
|
-
hostIpv4: runtime.hostIpv4,
|
|
3360
|
+
hostIpv4: args.runtime.hostIpv4,
|
|
3423
3361
|
setupPort,
|
|
3424
3362
|
fetch: (url, init) => fetch(url, init),
|
|
3425
3363
|
attempts: 15,
|
|
@@ -3445,12 +3383,12 @@ var SponsorRelayController = class {
|
|
|
3445
3383
|
throw new Error("OrbitDB relay runtime is missing required mapped TCP/WS ports.");
|
|
3446
3384
|
}
|
|
3447
3385
|
const configureResult = await configureOrbitdbRelaySetup2({
|
|
3448
|
-
hostIpv4: runtime.hostIpv4,
|
|
3449
|
-
publicIpv6: runtime.ipv6,
|
|
3386
|
+
hostIpv4: args.runtime.hostIpv4,
|
|
3387
|
+
publicIpv6: args.runtime.ipv6,
|
|
3450
3388
|
setupPort,
|
|
3451
3389
|
tcpPort,
|
|
3452
3390
|
wsPort,
|
|
3453
|
-
proxyUrl: runtime.proxyUrl ?? void 0,
|
|
3391
|
+
proxyUrl: args.runtime.proxyUrl ?? void 0,
|
|
3454
3392
|
metricsPort: mappedPorts2["9090"]?.host ?? null,
|
|
3455
3393
|
metricsHttpsPort: mappedPorts2["443"]?.host ?? null,
|
|
3456
3394
|
webrtcPort: mappedPorts2["9093"]?.host ?? null,
|
|
@@ -3467,54 +3405,6 @@ var SponsorRelayController = class {
|
|
|
3467
3405
|
if (!args.deploymentToken) {
|
|
3468
3406
|
throw new Error("Missing deployment token for Aleph bootstrap config handoff.");
|
|
3469
3407
|
}
|
|
3470
|
-
if (runtime.proxyUrl && runtime.webAccess?.active !== true) {
|
|
3471
|
-
this.emitProgress({
|
|
3472
|
-
stage: "deployment-confirmed",
|
|
3473
|
-
label: "Waiting for HTTPS route",
|
|
3474
|
-
progress: 93,
|
|
3475
|
-
status: "warning",
|
|
3476
|
-
itemHash: args.itemHash,
|
|
3477
|
-
detail: "The relay received a 2n6 hostname, but it is not active yet. Waiting before handing HTTPS config to the guest."
|
|
3478
|
-
});
|
|
3479
|
-
let latestRuntime = runtime;
|
|
3480
|
-
for (let attempt = 0; attempt < UI_RUNTIME_WAIT_ATTEMPTS; attempt += 1) {
|
|
3481
|
-
if (latestRuntime.webAccess?.active === true) {
|
|
3482
|
-
break;
|
|
3483
|
-
}
|
|
3484
|
-
await new Promise(
|
|
3485
|
-
(resolve) => globalThis.setTimeout(resolve, UI_RUNTIME_WAIT_DELAY_MS)
|
|
3486
|
-
);
|
|
3487
|
-
latestRuntime = await fetchVmRuntime({
|
|
3488
|
-
itemHash: args.itemHash,
|
|
3489
|
-
fetch: (url, init) => fetch(url, init),
|
|
3490
|
-
crnHash: runtime.selectedCrn?.hash ?? runtime.allocation?.crnHash ?? void 0,
|
|
3491
|
-
crns: this.state.crns,
|
|
3492
|
-
crnListUrl: this.props.crnListUrl
|
|
3493
|
-
}).catch(() => latestRuntime);
|
|
3494
|
-
this.emitProgress({
|
|
3495
|
-
stage: "deployment-confirmed",
|
|
3496
|
-
label: "Waiting for HTTPS route",
|
|
3497
|
-
progress: 93,
|
|
3498
|
-
status: latestRuntime.webAccess?.active === true ? "info" : "warning",
|
|
3499
|
-
itemHash: args.itemHash,
|
|
3500
|
-
detail: `2n6 activation ${attempt + 1}/${UI_RUNTIME_WAIT_ATTEMPTS}: ${latestRuntime.webAccess?.active === true ? "active" : "still pending"} for ${latestRuntime.proxyUrl ?? runtime.proxyUrl ?? "reserved proxy URL"}.`
|
|
3501
|
-
});
|
|
3502
|
-
this.trace("deploy:bootstrap-proxy-activation", {
|
|
3503
|
-
itemHash: args.itemHash,
|
|
3504
|
-
attempt: attempt + 1,
|
|
3505
|
-
attempts: UI_RUNTIME_WAIT_ATTEMPTS,
|
|
3506
|
-
active: latestRuntime.webAccess?.active === true,
|
|
3507
|
-
proxyUrl: latestRuntime.proxyUrl ?? null
|
|
3508
|
-
});
|
|
3509
|
-
}
|
|
3510
|
-
runtime = latestRuntime;
|
|
3511
|
-
mappedPorts2 = runtime.mappedPorts ?? mappedPorts2;
|
|
3512
|
-
}
|
|
3513
|
-
if (!runtime.hostIpv4) {
|
|
3514
|
-
throw new Error("Relay runtime lost its host IPv4 address while waiting for HTTPS activation.");
|
|
3515
|
-
}
|
|
3516
|
-
const runtimeHostIpv4 = runtime.hostIpv4;
|
|
3517
|
-
const activeProxyUrl = runtime.webAccess?.active === true ? runtime.proxyUrl ?? null : null;
|
|
3518
3408
|
this.emitProgress({
|
|
3519
3409
|
stage: "deployment-confirmed",
|
|
3520
3410
|
label: "Publishing relay config",
|
|
@@ -3532,9 +3422,9 @@ var SponsorRelayController = class {
|
|
|
3532
3422
|
expiresAt: new Date(Date.now() + 30 * 6e4).toISOString(),
|
|
3533
3423
|
status: "pending",
|
|
3534
3424
|
runtime: {
|
|
3535
|
-
publicIpv4:
|
|
3536
|
-
publicIpv6: runtime.ipv6 ?? null,
|
|
3537
|
-
proxyUrl:
|
|
3425
|
+
publicIpv4: args.runtime.hostIpv4,
|
|
3426
|
+
publicIpv6: args.runtime.ipv6 ?? null,
|
|
3427
|
+
proxyUrl: args.runtime.proxyUrl ?? null,
|
|
3538
3428
|
mappedPorts: mappedPorts2
|
|
3539
3429
|
},
|
|
3540
3430
|
bootstrap: {
|
|
@@ -3563,164 +3453,49 @@ var SponsorRelayController = class {
|
|
|
3563
3453
|
aggregateItemHash: bootstrapConfigPublication.aggregateItemHash,
|
|
3564
3454
|
aggregateStatus: bootstrapConfigPublication.aggregateStatus
|
|
3565
3455
|
});
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
bootstrapConfigSignal
|
|
3587
|
-
});
|
|
3588
|
-
if (!bootstrapConfigSignal) {
|
|
3589
|
-
throw new Error(
|
|
3590
|
-
"The relay VM did not confirm that it applied the Aleph bootstrap config in time."
|
|
3591
|
-
);
|
|
3592
|
-
}
|
|
3593
|
-
bootstrapSignalRelayMetadata = typeof bootstrapConfigSignal.peerId === "string" && bootstrapConfigSignal.peerId.length > 0 && Array.isArray(bootstrapConfigSignal.probeMultiaddrs) && bootstrapConfigSignal.probeMultiaddrs.length > 0 ? {
|
|
3594
|
-
peerId: bootstrapConfigSignal.peerId,
|
|
3595
|
-
probeMultiaddrs: bootstrapConfigSignal.probeMultiaddrs,
|
|
3596
|
-
browserBootstrapMultiaddrs: bootstrapConfigSignal.browserBootstrapMultiaddrs ?? []
|
|
3597
|
-
} : null;
|
|
3598
|
-
if (runtime.proxyUrl && runtime.webAccess?.active !== true) {
|
|
3599
|
-
this.trace("deploy:bootstrap-proxy-fallback", {
|
|
3600
|
-
itemHash: args.itemHash,
|
|
3601
|
-
deploymentToken: args.deploymentToken,
|
|
3602
|
-
proxyUrl: runtime.proxyUrl,
|
|
3603
|
-
bootstrapSignalRelayMetadata
|
|
3604
|
-
});
|
|
3605
|
-
this.emitProgress({
|
|
3606
|
-
stage: "deployment-confirmed",
|
|
3607
|
-
label: "Continuing without HTTPS route",
|
|
3608
|
-
progress: 94,
|
|
3609
|
-
status: "warning",
|
|
3456
|
+
}
|
|
3457
|
+
this.emitProgress({
|
|
3458
|
+
stage: "publishing-bootstrap",
|
|
3459
|
+
label: "Reading relay multiaddrs",
|
|
3460
|
+
progress: 95,
|
|
3461
|
+
status: "info",
|
|
3462
|
+
itemHash: args.itemHash,
|
|
3463
|
+
detail: "Waiting for the relay to report its final public multiaddrs."
|
|
3464
|
+
});
|
|
3465
|
+
const relayMetadata = await fetchRelayMetadataForRuntime({
|
|
3466
|
+
runtime: args.runtime,
|
|
3467
|
+
fetch: (url, init) => fetch(url, init),
|
|
3468
|
+
preferSecureMetadata: profile === "uc-go-peer",
|
|
3469
|
+
attempts: 80,
|
|
3470
|
+
delayMs: 3e3,
|
|
3471
|
+
timeoutMs: 24e4,
|
|
3472
|
+
onAttempt: (result) => {
|
|
3473
|
+
const payload = result.payload && typeof result.payload === "object" ? result.payload : null;
|
|
3474
|
+
const metadata = payload?.metadata && typeof payload.metadata === "object" ? payload.metadata : null;
|
|
3475
|
+
this.trace("deploy:relay-metadata-attempt", {
|
|
3610
3476
|
itemHash: args.itemHash,
|
|
3611
|
-
|
|
3477
|
+
attempt: result.attempt,
|
|
3478
|
+
attempts: result.attempts,
|
|
3479
|
+
requestUrl: result.requestUrl,
|
|
3480
|
+
metadataUrl: result.metadataUrl,
|
|
3481
|
+
hostIpv4: result.hostIpv4,
|
|
3482
|
+
setupPort: result.setupPort,
|
|
3483
|
+
ok: result.ok,
|
|
3484
|
+
status: result.status,
|
|
3485
|
+
ready: result.ready,
|
|
3486
|
+
error: result.error ?? null,
|
|
3487
|
+
payloadStatus: payload && typeof payload.status === "string" ? payload.status : null,
|
|
3488
|
+
peerId: metadata && typeof metadata.peer_id === "string" ? metadata.peer_id : null,
|
|
3489
|
+
probeMultiaddrCount: Array.isArray(metadata?.probe_multiaddrs) ? metadata.probe_multiaddrs.length : 0,
|
|
3490
|
+
browserBootstrapMultiaddrCount: Array.isArray(
|
|
3491
|
+
metadata?.browser_bootstrap_multiaddrs
|
|
3492
|
+
) ? metadata.browser_bootstrap_multiaddrs.length : 0
|
|
3612
3493
|
});
|
|
3613
|
-
runtime = {
|
|
3614
|
-
...runtime,
|
|
3615
|
-
proxyUrl: null,
|
|
3616
|
-
webAccess: runtime.webAccess ? {
|
|
3617
|
-
...runtime.webAccess,
|
|
3618
|
-
active: false
|
|
3619
|
-
} : runtime.webAccess
|
|
3620
|
-
};
|
|
3621
3494
|
}
|
|
3622
|
-
}
|
|
3623
|
-
let relayMetadata = bootstrapSignalRelayMetadata;
|
|
3624
|
-
if (relayMetadata) {
|
|
3625
|
-
this.trace("deploy:relay-metadata-from-bootstrap-signal", {
|
|
3626
|
-
itemHash: args.itemHash,
|
|
3627
|
-
peerId: relayMetadata.peerId,
|
|
3628
|
-
probeMultiaddrCount: relayMetadata.probeMultiaddrs.length,
|
|
3629
|
-
browserBootstrapMultiaddrCount: relayMetadata.browserBootstrapMultiaddrs.length
|
|
3630
|
-
});
|
|
3631
|
-
} else {
|
|
3632
|
-
this.emitProgress({
|
|
3633
|
-
stage: "publishing-bootstrap",
|
|
3634
|
-
label: "Reading relay multiaddrs",
|
|
3635
|
-
progress: 95,
|
|
3636
|
-
status: "info",
|
|
3637
|
-
itemHash: args.itemHash,
|
|
3638
|
-
detail: "Waiting for the relay to report its final public multiaddrs."
|
|
3639
|
-
});
|
|
3640
|
-
relayMetadata = await fetchRelayMetadataForRuntime({
|
|
3641
|
-
runtime,
|
|
3642
|
-
fetch: (url, init) => fetch(url, init),
|
|
3643
|
-
preferSecureMetadata: profile === "uc-go-peer" && Boolean(runtime.proxyUrl),
|
|
3644
|
-
attempts: 80,
|
|
3645
|
-
delayMs: 3e3,
|
|
3646
|
-
timeoutMs: 24e4,
|
|
3647
|
-
onAttempt: (result) => {
|
|
3648
|
-
const payload = result.payload && typeof result.payload === "object" ? result.payload : null;
|
|
3649
|
-
const metadata = payload?.metadata && typeof payload.metadata === "object" ? payload.metadata : null;
|
|
3650
|
-
this.trace("deploy:relay-metadata-attempt", {
|
|
3651
|
-
itemHash: args.itemHash,
|
|
3652
|
-
attempt: result.attempt,
|
|
3653
|
-
attempts: result.attempts,
|
|
3654
|
-
requestUrl: result.requestUrl,
|
|
3655
|
-
metadataUrl: result.metadataUrl,
|
|
3656
|
-
hostIpv4: result.hostIpv4,
|
|
3657
|
-
setupPort: result.setupPort,
|
|
3658
|
-
ok: result.ok,
|
|
3659
|
-
status: result.status,
|
|
3660
|
-
ready: result.ready,
|
|
3661
|
-
error: result.error ?? null,
|
|
3662
|
-
payloadStatus: payload && typeof payload.status === "string" ? payload.status : null,
|
|
3663
|
-
peerId: metadata && typeof metadata.peer_id === "string" ? metadata.peer_id : null,
|
|
3664
|
-
probeMultiaddrCount: Array.isArray(metadata?.probe_multiaddrs) ? metadata.probe_multiaddrs.length : 0,
|
|
3665
|
-
browserBootstrapMultiaddrCount: Array.isArray(
|
|
3666
|
-
metadata?.browser_bootstrap_multiaddrs
|
|
3667
|
-
) ? metadata.browser_bootstrap_multiaddrs.length : 0
|
|
3668
|
-
});
|
|
3669
|
-
}
|
|
3670
|
-
});
|
|
3671
|
-
}
|
|
3495
|
+
});
|
|
3672
3496
|
if (!relayMetadata) {
|
|
3673
3497
|
throw new Error("Relay metadata did not include a peer ID and public multiaddrs.");
|
|
3674
3498
|
}
|
|
3675
|
-
if (profile === "uc-go-peer" && runtime.proxyUrl) {
|
|
3676
|
-
this.emitProgress({
|
|
3677
|
-
stage: "publishing-bootstrap",
|
|
3678
|
-
label: "Verifying reachability",
|
|
3679
|
-
progress: 96,
|
|
3680
|
-
status: "info",
|
|
3681
|
-
itemHash: args.itemHash,
|
|
3682
|
-
detail: "Checking that the secure relay endpoint is reachable before trusting the deployment as ready."
|
|
3683
|
-
});
|
|
3684
|
-
const verificationUrl = (() => {
|
|
3685
|
-
try {
|
|
3686
|
-
return new URL("/bootstrap/metadata", runtime.proxyUrl).toString();
|
|
3687
|
-
} catch {
|
|
3688
|
-
return runtime.proxyUrl ?? "";
|
|
3689
|
-
}
|
|
3690
|
-
})();
|
|
3691
|
-
let verificationResult = null;
|
|
3692
|
-
for (let attempt = 0; attempt < UI_REACHABILITY_VERIFY_ATTEMPTS; attempt += 1) {
|
|
3693
|
-
verificationResult = await verifyUcGoPeerReachability({
|
|
3694
|
-
proxyUrl: verificationUrl,
|
|
3695
|
-
verifyProxyHttp: true,
|
|
3696
|
-
fetch: (url, init) => fetch(url, init),
|
|
3697
|
-
tcpProbe: async () => ({ ok: null })
|
|
3698
|
-
});
|
|
3699
|
-
this.trace("deploy:reachability-verification-attempt", {
|
|
3700
|
-
itemHash: args.itemHash,
|
|
3701
|
-
attempt: attempt + 1,
|
|
3702
|
-
attempts: UI_REACHABILITY_VERIFY_ATTEMPTS,
|
|
3703
|
-
verificationUrl,
|
|
3704
|
-
ok: verificationResult.ok,
|
|
3705
|
-
checks: verificationResult.checks
|
|
3706
|
-
});
|
|
3707
|
-
const proxyHttpCheck2 = verificationResult.checks["https:proxy"];
|
|
3708
|
-
if (verificationResult.ok && proxyHttpCheck2?.ok === true) {
|
|
3709
|
-
break;
|
|
3710
|
-
}
|
|
3711
|
-
if (attempt < UI_REACHABILITY_VERIFY_ATTEMPTS - 1) {
|
|
3712
|
-
await new Promise(
|
|
3713
|
-
(resolve) => globalThis.setTimeout(resolve, UI_REACHABILITY_VERIFY_DELAY_MS)
|
|
3714
|
-
);
|
|
3715
|
-
}
|
|
3716
|
-
}
|
|
3717
|
-
const proxyHttpCheck = verificationResult?.checks["https:proxy"];
|
|
3718
|
-
if (!verificationResult?.ok || proxyHttpCheck?.ok !== true) {
|
|
3719
|
-
throw new Error(
|
|
3720
|
-
proxyHttpCheck?.error ? `Secure relay endpoint did not become reachable in time: ${proxyHttpCheck.error}` : "Secure relay endpoint did not become reachable in time."
|
|
3721
|
-
);
|
|
3722
|
-
}
|
|
3723
|
-
}
|
|
3724
3499
|
const { peerId } = relayMetadata;
|
|
3725
3500
|
const registrationId = createRelayBootstrapRegistrationId(
|
|
3726
3501
|
profile,
|
|
@@ -3838,7 +3613,6 @@ var SponsorRelayController = class {
|
|
|
3838
3613
|
const currentProgress = this.state.deploymentProgress;
|
|
3839
3614
|
const currentProgressIsForLatestHash = currentProgress.itemHash === itemHash || currentProgress.itemHash == null && currentProgress.stage !== "idle" && currentProgress.stage !== "error";
|
|
3840
3615
|
const keepTerminalSuccess = this.lastCompletedDeploymentHash === itemHash || currentProgressIsForLatestHash && currentProgress.stage === "completed" && currentProgress.status === "success";
|
|
3841
|
-
const keepSpecificInFlightProgress = currentProgressIsForLatestHash && currentProgress.stage !== "completed" && currentProgress.stage !== "error" && currentProgress.progress >= 93;
|
|
3842
3616
|
const status = latest.details.messageStatus;
|
|
3843
3617
|
if (status === "rejected") {
|
|
3844
3618
|
this.emitProgress({
|
|
@@ -3881,16 +3655,6 @@ var SponsorRelayController = class {
|
|
|
3881
3655
|
});
|
|
3882
3656
|
return;
|
|
3883
3657
|
}
|
|
3884
|
-
if (keepSpecificInFlightProgress) {
|
|
3885
|
-
this.trace("progress:retain-inflight", {
|
|
3886
|
-
reason: "latest refresh would overwrite a more specific in-flight deployment phase",
|
|
3887
|
-
itemHash,
|
|
3888
|
-
currentStage: currentProgress.stage,
|
|
3889
|
-
currentLabel: currentProgress.label,
|
|
3890
|
-
currentProgress: currentProgress.progress
|
|
3891
|
-
});
|
|
3892
|
-
return;
|
|
3893
|
-
}
|
|
3894
3658
|
this.emitProgress({
|
|
3895
3659
|
stage: "deployment-confirmed",
|
|
3896
3660
|
label: "Waiting for runtime",
|
|
@@ -3901,16 +3665,6 @@ var SponsorRelayController = class {
|
|
|
3901
3665
|
});
|
|
3902
3666
|
return;
|
|
3903
3667
|
}
|
|
3904
|
-
if (keepSpecificInFlightProgress) {
|
|
3905
|
-
this.trace("progress:retain-inflight", {
|
|
3906
|
-
reason: "latest refresh would overwrite a more specific in-flight deployment phase",
|
|
3907
|
-
itemHash,
|
|
3908
|
-
currentStage: currentProgress.stage,
|
|
3909
|
-
currentLabel: currentProgress.label,
|
|
3910
|
-
currentProgress: currentProgress.progress
|
|
3911
|
-
});
|
|
3912
|
-
return;
|
|
3913
|
-
}
|
|
3914
3668
|
this.emitProgress({
|
|
3915
3669
|
stage: "deployment-confirmed",
|
|
3916
3670
|
label: "Runtime ready",
|
|
@@ -3989,11 +3743,16 @@ var SponsorRelayController = class {
|
|
|
3989
3743
|
this.refreshTimer = setInterval(() => {
|
|
3990
3744
|
void this.refresh();
|
|
3991
3745
|
}, REFRESH_INTERVAL_MS);
|
|
3746
|
+
this.pingTimer = setInterval(() => {
|
|
3747
|
+
void this.refreshRelayPing();
|
|
3748
|
+
}, RELAY_PING_INTERVAL_MS);
|
|
3749
|
+
await this.refreshRelayPing();
|
|
3992
3750
|
this.patch({ ready: true });
|
|
3993
3751
|
this.trace("init:ready");
|
|
3994
3752
|
}
|
|
3995
3753
|
destroy() {
|
|
3996
3754
|
if (this.refreshTimer) clearInterval(this.refreshTimer);
|
|
3755
|
+
if (this.pingTimer) clearInterval(this.pingTimer);
|
|
3997
3756
|
if (this.manifestRefreshTimer) clearTimeout(this.manifestRefreshTimer);
|
|
3998
3757
|
this.stopWalletWatch?.();
|
|
3999
3758
|
}
|
|
@@ -4137,10 +3896,16 @@ var SponsorRelayController = class {
|
|
|
4137
3896
|
const manifest = manifestState.manifest;
|
|
4138
3897
|
let balance = this.state.balance;
|
|
4139
3898
|
let instances = [];
|
|
3899
|
+
let bootstrapRegistrations = [];
|
|
3900
|
+
let orphanBootstrapRegistrations = [];
|
|
4140
3901
|
if (this.state.wallet.address) {
|
|
4141
|
-
const [nextBalance, rawInstances] = await Promise.all([
|
|
3902
|
+
const [nextBalance, rawInstances, rawBootstrapPosts] = await Promise.all([
|
|
4142
3903
|
this.client.fetchBalance(this.state.wallet.address),
|
|
4143
|
-
this.state.showInstances ? this.client.fetchInstances(this.state.wallet.address) : Promise.resolve([])
|
|
3904
|
+
this.state.showInstances ? this.client.fetchInstances(this.state.wallet.address) : Promise.resolve([]),
|
|
3905
|
+
fetchAlephBootstrapPosts({
|
|
3906
|
+
apiHost: this.client.apiHost,
|
|
3907
|
+
fetch
|
|
3908
|
+
}).catch(() => [])
|
|
4144
3909
|
]);
|
|
4145
3910
|
balance = nextBalance;
|
|
4146
3911
|
instances = await Promise.all(
|
|
@@ -4200,6 +3965,37 @@ var SponsorRelayController = class {
|
|
|
4200
3965
|
};
|
|
4201
3966
|
})
|
|
4202
3967
|
);
|
|
3968
|
+
const normalizedWalletAddress = this.state.wallet.address.toLowerCase();
|
|
3969
|
+
const activeInstanceHashes = new Set(
|
|
3970
|
+
instances.map((entry) => entry.instance.item_hash)
|
|
3971
|
+
);
|
|
3972
|
+
bootstrapRegistrations = selectCurrentRelayBootstrapPosts(rawBootstrapPosts).filter(
|
|
3973
|
+
(entry) => entry.address?.toLowerCase() === normalizedWalletAddress
|
|
3974
|
+
).map((entry) => {
|
|
3975
|
+
const instanceItemHash = relayBootstrapInstanceItemHash(entry);
|
|
3976
|
+
const messageHash = entry.itemHash ?? entry.hash ?? null;
|
|
3977
|
+
return {
|
|
3978
|
+
messageHash,
|
|
3979
|
+
hash: entry.hash ?? null,
|
|
3980
|
+
itemHash: entry.itemHash ?? null,
|
|
3981
|
+
address: entry.address ?? null,
|
|
3982
|
+
time: entry.time ?? null,
|
|
3983
|
+
instanceItemHash,
|
|
3984
|
+
confirmed: Boolean(
|
|
3985
|
+
instanceItemHash && activeInstanceHashes.has(instanceItemHash)
|
|
3986
|
+
),
|
|
3987
|
+
content: entry.content ? {
|
|
3988
|
+
peerId: entry.content.peerId,
|
|
3989
|
+
registrationId: entry.content.registrationId,
|
|
3990
|
+
multiaddrs: Array.isArray(entry.content.multiaddrs) ? entry.content.multiaddrs : [],
|
|
3991
|
+
browserMultiaddrs: Array.isArray(entry.content.browserMultiaddrs) ? entry.content.browserMultiaddrs : [],
|
|
3992
|
+
updatedAt: entry.content.updatedAt
|
|
3993
|
+
} : null
|
|
3994
|
+
};
|
|
3995
|
+
});
|
|
3996
|
+
orphanBootstrapRegistrations = bootstrapRegistrations.filter(
|
|
3997
|
+
(entry) => !entry.confirmed
|
|
3998
|
+
);
|
|
4203
3999
|
}
|
|
4204
4000
|
let rootfsVerified = false;
|
|
4205
4001
|
let rootfsResolution = null;
|
|
@@ -4230,6 +4026,8 @@ var SponsorRelayController = class {
|
|
|
4230
4026
|
balance,
|
|
4231
4027
|
crns,
|
|
4232
4028
|
instances,
|
|
4029
|
+
bootstrapRegistrations,
|
|
4030
|
+
orphanBootstrapRegistrations,
|
|
4233
4031
|
busy: { refreshing: false },
|
|
4234
4032
|
statusText: "Relay sponsor data ready"
|
|
4235
4033
|
});
|
|
@@ -4249,6 +4047,11 @@ var SponsorRelayController = class {
|
|
|
4249
4047
|
});
|
|
4250
4048
|
}
|
|
4251
4049
|
}
|
|
4050
|
+
async refreshRelayPing() {
|
|
4051
|
+
const relayPing = await pingPeer(this.props.libp2p);
|
|
4052
|
+
this.patch({ relayPing });
|
|
4053
|
+
this.trace("libp2p:relay-ping", relayPing);
|
|
4054
|
+
}
|
|
4252
4055
|
async deploy() {
|
|
4253
4056
|
this.trace("deploy:start", {
|
|
4254
4057
|
wallet: this.state.wallet.address,
|
|
@@ -4541,15 +4344,6 @@ var SponsorRelayController = class {
|
|
|
4541
4344
|
});
|
|
4542
4345
|
if (attemptItemHash) {
|
|
4543
4346
|
if (attemptDeploymentToken) {
|
|
4544
|
-
this.emitProgress({
|
|
4545
|
-
stage: "refreshing-instances",
|
|
4546
|
-
label: "Cleaning up failed attempt",
|
|
4547
|
-
progress: 16,
|
|
4548
|
-
status: "warning",
|
|
4549
|
-
itemHash: attemptItemHash,
|
|
4550
|
-
detail: `Removing bootstrap handoff state for failed deployment on ${attemptLabel}.`,
|
|
4551
|
-
error: lastError.message
|
|
4552
|
-
});
|
|
4553
4347
|
this.trace("deploy:bootstrap-config-cleanup-start", {
|
|
4554
4348
|
itemHash: attemptItemHash,
|
|
4555
4349
|
deploymentToken: attemptDeploymentToken
|
|
@@ -4575,26 +4369,8 @@ var SponsorRelayController = class {
|
|
|
4575
4369
|
deploymentToken: attemptDeploymentToken,
|
|
4576
4370
|
error: cleanupError instanceof Error ? cleanupError.message : String(cleanupError)
|
|
4577
4371
|
});
|
|
4578
|
-
this.emitProgress({
|
|
4579
|
-
stage: "refreshing-instances",
|
|
4580
|
-
label: "Cleanup warning",
|
|
4581
|
-
progress: 16,
|
|
4582
|
-
status: "warning",
|
|
4583
|
-
itemHash: attemptItemHash,
|
|
4584
|
-
detail: `Bootstrap cleanup reported an issue for ${attemptLabel}, but retry cleanup will continue.`,
|
|
4585
|
-
error: cleanupError instanceof Error ? cleanupError.message : String(cleanupError)
|
|
4586
|
-
});
|
|
4587
4372
|
});
|
|
4588
4373
|
}
|
|
4589
|
-
this.emitProgress({
|
|
4590
|
-
stage: "refreshing-instances",
|
|
4591
|
-
label: "Discarding failed deployment",
|
|
4592
|
-
progress: 17,
|
|
4593
|
-
status: "warning",
|
|
4594
|
-
itemHash: attemptItemHash,
|
|
4595
|
-
detail: `Forgetting failed deployment ${attemptItemHash.slice(0, 12)} on ${attemptLabel} before retrying.`,
|
|
4596
|
-
error: lastError.message
|
|
4597
|
-
});
|
|
4598
4374
|
this.trace("deploy:forget-failed-attempt-start", {
|
|
4599
4375
|
itemHash: attemptItemHash,
|
|
4600
4376
|
crnHash: candidateCrn.hash,
|
|
@@ -4617,30 +4393,12 @@ var SponsorRelayController = class {
|
|
|
4617
4393
|
itemHash: attemptItemHash,
|
|
4618
4394
|
error: cleanupError instanceof Error ? cleanupError.message : String(cleanupError)
|
|
4619
4395
|
});
|
|
4620
|
-
this.emitProgress({
|
|
4621
|
-
stage: "refreshing-instances",
|
|
4622
|
-
label: "Cleanup warning",
|
|
4623
|
-
progress: 17,
|
|
4624
|
-
status: "warning",
|
|
4625
|
-
itemHash: attemptItemHash,
|
|
4626
|
-
detail: `Failed deployment cleanup reported an issue for ${attemptLabel}.`,
|
|
4627
|
-
error: cleanupError instanceof Error ? cleanupError.message : String(cleanupError)
|
|
4628
|
-
});
|
|
4629
4396
|
});
|
|
4630
4397
|
this.trace("deploy:forget-failed-attempt-complete", {
|
|
4631
4398
|
itemHash: attemptItemHash,
|
|
4632
4399
|
crnHash: candidateCrn.hash,
|
|
4633
4400
|
crnName: candidateCrn.name
|
|
4634
4401
|
});
|
|
4635
|
-
this.emitProgress({
|
|
4636
|
-
stage: "refreshing-instances",
|
|
4637
|
-
label: "Cleanup complete",
|
|
4638
|
-
progress: 18,
|
|
4639
|
-
status: "info",
|
|
4640
|
-
itemHash: attemptItemHash,
|
|
4641
|
-
detail: `Finished cleaning up failed deployment on ${attemptLabel}.`,
|
|
4642
|
-
error: null
|
|
4643
|
-
});
|
|
4644
4402
|
}
|
|
4645
4403
|
if (candidateIndex < orderedCrns.length - 1) {
|
|
4646
4404
|
this.emitProgress({
|
|
@@ -4739,6 +4497,72 @@ var SponsorRelayController = class {
|
|
|
4739
4497
|
});
|
|
4740
4498
|
}
|
|
4741
4499
|
}
|
|
4500
|
+
async deleteBootstrapRegistration(registrationHash) {
|
|
4501
|
+
this.trace("registration-delete:start", { registrationHash });
|
|
4502
|
+
if (!this.state.wallet.address) {
|
|
4503
|
+
this.patch({
|
|
4504
|
+
errorText: "Connect MetaMask before forgetting registrations."
|
|
4505
|
+
});
|
|
4506
|
+
return;
|
|
4507
|
+
}
|
|
4508
|
+
this.patch({
|
|
4509
|
+
busy: { deletingRegistrationHash: registrationHash },
|
|
4510
|
+
errorText: null,
|
|
4511
|
+
statusText: `Forgetting registration ${registrationHash}`
|
|
4512
|
+
});
|
|
4513
|
+
try {
|
|
4514
|
+
this.emitProgress({
|
|
4515
|
+
stage: "validating",
|
|
4516
|
+
label: "Validating registration cleanup",
|
|
4517
|
+
progress: 6,
|
|
4518
|
+
status: "warning",
|
|
4519
|
+
itemHash: registrationHash,
|
|
4520
|
+
detail: "Preparing Aleph FORGET message for the orphan bootstrap registration."
|
|
4521
|
+
});
|
|
4522
|
+
await forgetAlephMessages({
|
|
4523
|
+
sender: this.state.wallet.address,
|
|
4524
|
+
hashes: [registrationHash],
|
|
4525
|
+
reason: "Deleted orphan relay bootstrap registration from Sponsor Relay panel",
|
|
4526
|
+
signer: personalSign,
|
|
4527
|
+
hasher: sha256Hex,
|
|
4528
|
+
fetch: asJsonFetch,
|
|
4529
|
+
apiHost: this.client.apiHost,
|
|
4530
|
+
onProgress: (event) => {
|
|
4531
|
+
this.emitProgress(event);
|
|
4532
|
+
}
|
|
4533
|
+
});
|
|
4534
|
+
this.patch({
|
|
4535
|
+
busy: { deletingRegistrationHash: null },
|
|
4536
|
+
statusText: `Deletion submitted for ${registrationHash}`
|
|
4537
|
+
});
|
|
4538
|
+
this.emitProgress({
|
|
4539
|
+
stage: "refreshing-instances",
|
|
4540
|
+
label: "Refreshing registrations after delete",
|
|
4541
|
+
progress: 92,
|
|
4542
|
+
status: "info",
|
|
4543
|
+
itemHash: registrationHash,
|
|
4544
|
+
detail: "Reloading deployments and relay bootstrap registrations."
|
|
4545
|
+
});
|
|
4546
|
+
await this.refresh();
|
|
4547
|
+
this.trace("registration-delete:submitted", { registrationHash });
|
|
4548
|
+
this.emitProgress({
|
|
4549
|
+
stage: "completed",
|
|
4550
|
+
label: "Registration cleanup completed",
|
|
4551
|
+
progress: 100,
|
|
4552
|
+
status: "success",
|
|
4553
|
+
itemHash: registrationHash,
|
|
4554
|
+
detail: "Orphan relay bootstrap registration forgotten and state refreshed.",
|
|
4555
|
+
error: null
|
|
4556
|
+
});
|
|
4557
|
+
} catch (error) {
|
|
4558
|
+
this.trace("registration-delete:error", error);
|
|
4559
|
+
this.patch({
|
|
4560
|
+
busy: { deletingRegistrationHash: null },
|
|
4561
|
+
errorText: error instanceof Error ? error.message : String(error),
|
|
4562
|
+
statusText: "Registration cleanup failed"
|
|
4563
|
+
});
|
|
4564
|
+
}
|
|
4565
|
+
}
|
|
4742
4566
|
};
|
|
4743
4567
|
function createSponsorRelayController(props = {}) {
|
|
4744
4568
|
return new SponsorRelayController(props);
|
|
@@ -4765,9 +4589,10 @@ function useSponsorRelayController(props) {
|
|
|
4765
4589
|
);
|
|
4766
4590
|
useEffect(() => {
|
|
4767
4591
|
controller.updateProps({
|
|
4592
|
+
libp2p: props.libp2p,
|
|
4768
4593
|
debug: props.debug
|
|
4769
4594
|
});
|
|
4770
|
-
}, [controller, props.debug]);
|
|
4595
|
+
}, [controller, props.debug, props.libp2p]);
|
|
4771
4596
|
useEffect(() => {
|
|
4772
4597
|
void controller.init();
|
|
4773
4598
|
return () => {
|
|
@@ -4938,6 +4763,10 @@ function SponsorRelayFab(props) {
|
|
|
4938
4763
|
const versionLabel = resolvedVersion.startsWith("v") ? resolvedVersion : `v${resolvedVersion}`;
|
|
4939
4764
|
const launcherMode = props.launcherMode ?? "floating";
|
|
4940
4765
|
const indicator = launcherIndicator(state);
|
|
4766
|
+
const confirmedRegistrationByInstanceHash = new Map(
|
|
4767
|
+
(state.bootstrapRegistrations ?? []).filter((entry) => entry.confirmed && entry.instanceItemHash).map((entry) => [entry.instanceItemHash, entry])
|
|
4768
|
+
);
|
|
4769
|
+
const orphanRegistrations = state.orphanBootstrapRegistrations ?? [];
|
|
4941
4770
|
const [successFlash, setSuccessFlash] = React.useState(false);
|
|
4942
4771
|
const [hovered, setHovered] = React.useState(false);
|
|
4943
4772
|
const launcherRef = React.useRef(null);
|
|
@@ -5576,66 +5405,196 @@ function SponsorRelayFab(props) {
|
|
|
5576
5405
|
"Latest deployment: ",
|
|
5577
5406
|
shortHash(state.lastDeploymentHash)
|
|
5578
5407
|
] }) : null,
|
|
5579
|
-
state.showInstances ? /* @__PURE__ */
|
|
5408
|
+
state.showInstances ? /* @__PURE__ */ jsxs(
|
|
5580
5409
|
"div",
|
|
5581
5410
|
{
|
|
5582
5411
|
style: { marginTop: "1rem", display: "grid", gap: "0.7rem" },
|
|
5583
|
-
children:
|
|
5584
|
-
|
|
5585
|
-
|
|
5412
|
+
children: [
|
|
5413
|
+
state.instances.map((entry) => {
|
|
5414
|
+
const confirmedRegistration = confirmedRegistrationByInstanceHash.get(
|
|
5415
|
+
entry.instance.item_hash
|
|
5416
|
+
) ?? null;
|
|
5417
|
+
return /* @__PURE__ */ jsxs("details", { open: true, children: [
|
|
5418
|
+
/* @__PURE__ */ jsx("summary", { children: /* @__PURE__ */ jsxs(
|
|
5419
|
+
"span",
|
|
5420
|
+
{
|
|
5421
|
+
style: {
|
|
5422
|
+
display: "inline-flex",
|
|
5423
|
+
alignItems: "center",
|
|
5424
|
+
gap: "0.55rem",
|
|
5425
|
+
flexWrap: "wrap"
|
|
5426
|
+
},
|
|
5427
|
+
children: [
|
|
5428
|
+
(entry.instance.content?.metadata?.name ?? "relay") + " \xB7 " + shortHash(entry.instance.item_hash),
|
|
5429
|
+
confirmedRegistration ? /* @__PURE__ */ jsxs(
|
|
5430
|
+
"span",
|
|
5431
|
+
{
|
|
5432
|
+
style: {
|
|
5433
|
+
display: "inline-flex",
|
|
5434
|
+
alignItems: "center",
|
|
5435
|
+
gap: "0.32rem",
|
|
5436
|
+
padding: "0.16rem 0.45rem",
|
|
5437
|
+
borderRadius: "999px",
|
|
5438
|
+
background: "rgba(34, 197, 94, 0.16)",
|
|
5439
|
+
color: "#86efac",
|
|
5440
|
+
fontSize: "0.7rem",
|
|
5441
|
+
fontWeight: 700
|
|
5442
|
+
},
|
|
5443
|
+
children: [
|
|
5444
|
+
/* @__PURE__ */ jsx(
|
|
5445
|
+
"span",
|
|
5446
|
+
{
|
|
5447
|
+
"aria-hidden": "true",
|
|
5448
|
+
style: {
|
|
5449
|
+
width: "0.45rem",
|
|
5450
|
+
height: "0.45rem",
|
|
5451
|
+
borderRadius: "999px",
|
|
5452
|
+
background: "#22c55e",
|
|
5453
|
+
boxShadow: "0 0 0 3px rgba(34, 197, 94, 0.18)"
|
|
5454
|
+
}
|
|
5455
|
+
}
|
|
5456
|
+
),
|
|
5457
|
+
"Registration confirmed"
|
|
5458
|
+
]
|
|
5459
|
+
}
|
|
5460
|
+
) : null
|
|
5461
|
+
]
|
|
5462
|
+
}
|
|
5463
|
+
) }),
|
|
5464
|
+
/* @__PURE__ */ jsxs(
|
|
5465
|
+
"div",
|
|
5466
|
+
{
|
|
5467
|
+
style: {
|
|
5468
|
+
display: "grid",
|
|
5469
|
+
gap: "0.35rem",
|
|
5470
|
+
marginTop: "0.55rem"
|
|
5471
|
+
},
|
|
5472
|
+
children: [
|
|
5473
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
5474
|
+
"Status: ",
|
|
5475
|
+
entry.details.messageStatus
|
|
5476
|
+
] }),
|
|
5477
|
+
confirmedRegistration ? /* @__PURE__ */ jsxs("div", { children: [
|
|
5478
|
+
"Bootstrap registration:",
|
|
5479
|
+
" ",
|
|
5480
|
+
shortHash(
|
|
5481
|
+
confirmedRegistration.messageHash ?? confirmedRegistration.content?.registrationId ?? "confirmed",
|
|
5482
|
+
14,
|
|
5483
|
+
8
|
|
5484
|
+
)
|
|
5485
|
+
] }) : null,
|
|
5486
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
5487
|
+
"Host IPv4: ",
|
|
5488
|
+
entry.details.hostIpv4 ?? "-"
|
|
5489
|
+
] }),
|
|
5490
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
5491
|
+
"IPv6: ",
|
|
5492
|
+
entry.details.ipv6 ?? "-"
|
|
5493
|
+
] }),
|
|
5494
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
5495
|
+
"VM IPv4: ",
|
|
5496
|
+
entry.details.vmIpv4 ?? "-"
|
|
5497
|
+
] }),
|
|
5498
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
5499
|
+
"SSH: ",
|
|
5500
|
+
entry.details.sshCommand ?? "-"
|
|
5501
|
+
] }),
|
|
5502
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
5503
|
+
"Ports: ",
|
|
5504
|
+
joinMappedPorts(entry.details.mappedPorts)
|
|
5505
|
+
] }),
|
|
5506
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
5507
|
+
"Submitted:",
|
|
5508
|
+
" ",
|
|
5509
|
+
formatDateTime(
|
|
5510
|
+
entry.instance.reception_time ?? entry.instance.time
|
|
5511
|
+
)
|
|
5512
|
+
] }),
|
|
5513
|
+
/* @__PURE__ */ jsx(
|
|
5514
|
+
"button",
|
|
5515
|
+
{
|
|
5516
|
+
type: "button",
|
|
5517
|
+
onClick: () => void controller.deleteInstance(
|
|
5518
|
+
entry.instance.item_hash
|
|
5519
|
+
),
|
|
5520
|
+
children: state.busy.deletingInstanceHash === entry.instance.item_hash ? "Deleting\u2026" : "Delete"
|
|
5521
|
+
}
|
|
5522
|
+
)
|
|
5523
|
+
]
|
|
5524
|
+
}
|
|
5525
|
+
)
|
|
5526
|
+
] }, entry.instance.item_hash);
|
|
5527
|
+
}),
|
|
5528
|
+
orphanRegistrations.length > 0 ? /* @__PURE__ */ jsxs(
|
|
5586
5529
|
"div",
|
|
5587
5530
|
{
|
|
5588
5531
|
style: {
|
|
5589
5532
|
display: "grid",
|
|
5590
|
-
gap: "0.
|
|
5591
|
-
|
|
5533
|
+
gap: "0.7rem",
|
|
5534
|
+
padding: "0.85rem",
|
|
5535
|
+
borderRadius: "1rem",
|
|
5536
|
+
border: "1px solid rgba(248, 113, 113, 0.22)",
|
|
5537
|
+
background: "linear-gradient(180deg, rgba(127, 29, 29, 0.18), rgba(69, 10, 10, 0.12))"
|
|
5592
5538
|
},
|
|
5593
5539
|
children: [
|
|
5594
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
5595
|
-
"
|
|
5596
|
-
|
|
5597
|
-
] }),
|
|
5598
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
5599
|
-
"Host IPv4: ",
|
|
5600
|
-
entry.details.hostIpv4 ?? "-"
|
|
5540
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "grid", gap: "0.2rem" }, children: [
|
|
5541
|
+
/* @__PURE__ */ jsx("strong", { children: "Orphan bootstrap registrations" }),
|
|
5542
|
+
/* @__PURE__ */ jsx("small", { style: { color: "#fecaca", lineHeight: 1.35 }, children: "Current-wallet registrations without a matching instance. Forget them directly from here." })
|
|
5601
5543
|
] }),
|
|
5602
|
-
|
|
5603
|
-
|
|
5604
|
-
|
|
5605
|
-
|
|
5606
|
-
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
5544
|
+
orphanRegistrations.map((entry) => {
|
|
5545
|
+
const registrationHash = entry.messageHash ?? entry.hash ?? null;
|
|
5546
|
+
return /* @__PURE__ */ jsxs(
|
|
5547
|
+
"div",
|
|
5548
|
+
{
|
|
5549
|
+
style: {
|
|
5550
|
+
display: "grid",
|
|
5551
|
+
gap: "0.35rem",
|
|
5552
|
+
padding: "0.75rem",
|
|
5553
|
+
borderRadius: "0.9rem",
|
|
5554
|
+
background: "rgba(15, 23, 42, 0.22)",
|
|
5555
|
+
border: "1px solid rgba(255,255,255,0.08)"
|
|
5556
|
+
},
|
|
5557
|
+
children: [
|
|
5558
|
+
/* @__PURE__ */ jsx("div", { style: { fontWeight: 700 }, children: (entry.content?.registrationId ?? "registration") + " \xB7 " + shortHash(registrationHash ?? "unknown") }),
|
|
5559
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
5560
|
+
"Peer: ",
|
|
5561
|
+
entry.content?.peerId ?? "-"
|
|
5562
|
+
] }),
|
|
5563
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
5564
|
+
"Linked instance:",
|
|
5565
|
+
" ",
|
|
5566
|
+
entry.instanceItemHash ? shortHash(entry.instanceItemHash) : "missing"
|
|
5567
|
+
] }),
|
|
5568
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
5569
|
+
"Browser multiaddrs:",
|
|
5570
|
+
" ",
|
|
5571
|
+
String(entry.content?.browserMultiaddrs?.length ?? 0)
|
|
5572
|
+
] }),
|
|
5573
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
5574
|
+
"Updated:",
|
|
5575
|
+
" ",
|
|
5576
|
+
formatDateTime(entry.content?.updatedAt ?? entry.time)
|
|
5577
|
+
] }),
|
|
5578
|
+
/* @__PURE__ */ jsx(
|
|
5579
|
+
"button",
|
|
5580
|
+
{
|
|
5581
|
+
type: "button",
|
|
5582
|
+
disabled: !registrationHash || state.busy.deletingRegistrationHash === registrationHash,
|
|
5583
|
+
onClick: () => registrationHash ? void controller.deleteBootstrapRegistration(
|
|
5584
|
+
registrationHash
|
|
5585
|
+
) : void 0,
|
|
5586
|
+
children: state.busy.deletingRegistrationHash === registrationHash ? "Forgetting\u2026" : "Forget registration"
|
|
5587
|
+
}
|
|
5588
|
+
)
|
|
5589
|
+
]
|
|
5590
|
+
},
|
|
5591
|
+
registrationHash ?? entry.content?.registrationId ?? `orphan-${entry.content?.peerId ?? "unknown"}`
|
|
5592
|
+
);
|
|
5593
|
+
})
|
|
5635
5594
|
]
|
|
5636
5595
|
}
|
|
5637
|
-
)
|
|
5638
|
-
]
|
|
5596
|
+
) : null
|
|
5597
|
+
]
|
|
5639
5598
|
}
|
|
5640
5599
|
) : null
|
|
5641
5600
|
] })
|