@le-space/ui 0.3.0 → 0.3.3
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 +4 -0
- package/react/index.js +496 -55
- package/shared/index.d.ts +7 -1
- package/shared/index.js +397 -14
- package/styles.css +9 -5
- package/svelte/SponsorRelayFab.svelte +67 -18
- package/svelte/components/LauncherButton.svelte +3 -3
- package/svelte/styles/theme.css +9 -5
package/react/index.js
CHANGED
|
@@ -32,6 +32,7 @@ var IDLE_DEPLOYMENT_PROGRESS = {
|
|
|
32
32
|
};
|
|
33
33
|
var REFRESH_INTERVAL_MS = 3e4;
|
|
34
34
|
var RELAY_PING_INTERVAL_MS = 2e4;
|
|
35
|
+
var MANIFEST_SOURCE_REFRESH_DEBOUNCE_MS = 400;
|
|
35
36
|
var INSTANCE_RUNTIME_STALE_REFRESH_MS = 5 * 6e4;
|
|
36
37
|
var STALE_INSTANCE_ALLOCATION_COOLDOWN_MS = 5 * 60 * 1e3;
|
|
37
38
|
var RECENT_INSTANCE_RUNTIME_GRACE_MS = 10 * 60 * 1e3;
|
|
@@ -57,6 +58,12 @@ function formatDateTime(value) {
|
|
|
57
58
|
if (Number.isNaN(date.getTime())) return String(value);
|
|
58
59
|
return date.toLocaleString();
|
|
59
60
|
}
|
|
61
|
+
function formatTierSpecLabel(vcpus, memoryMiB, diskMiB) {
|
|
62
|
+
if (vcpus == null || !Number.isFinite(vcpus) || memoryMiB == null || !Number.isFinite(memoryMiB) || diskMiB == null || !Number.isFinite(diskMiB)) {
|
|
63
|
+
return "-";
|
|
64
|
+
}
|
|
65
|
+
return `(${formatNumber(vcpus, 0)} vCPU \xB7 ${formatNumber(memoryMiB / 1024, 1)} GiB RAM \xB7 ${formatNumber(diskMiB / 1024, 0)} GiB disk)`;
|
|
66
|
+
}
|
|
60
67
|
function buildSshCommand(hostIpv4, mappedPorts2) {
|
|
61
68
|
if (!hostIpv4) return null;
|
|
62
69
|
const sshPort = mappedPorts2.find((entry) => entry.label.startsWith("22/"))?.hostPort ?? 22;
|
|
@@ -402,6 +409,18 @@ function extractReferenceHashes(details) {
|
|
|
402
409
|
if (!Array.isArray(errors)) return [];
|
|
403
410
|
return errors.filter((value) => typeof value === "string");
|
|
404
411
|
}
|
|
412
|
+
function extractInsufficientBalanceMessage(details) {
|
|
413
|
+
if (!details || typeof details !== "object" || !("errors" in details)) return null;
|
|
414
|
+
const errors = details.errors;
|
|
415
|
+
const firstError = Array.isArray(errors) && errors[0] && typeof errors[0] === "object" ? errors[0] : null;
|
|
416
|
+
const accountBalance = typeof firstError?.account_balance === "number" || typeof firstError?.account_balance === "string" ? Number(firstError.account_balance) : Number.NaN;
|
|
417
|
+
const requiredBalance = typeof firstError?.required_balance === "number" || typeof firstError?.required_balance === "string" ? Number(firstError.required_balance) : Number.NaN;
|
|
418
|
+
if (!Number.isFinite(accountBalance) || !Number.isFinite(requiredBalance)) {
|
|
419
|
+
return null;
|
|
420
|
+
}
|
|
421
|
+
const shortfall = requiredBalance - accountBalance;
|
|
422
|
+
return shortfall > 0 ? `insufficient Aleph balance: ${accountBalance.toFixed(3)} available, ${requiredBalance.toFixed(3)} required, ${shortfall.toFixed(3)} short` : `insufficient Aleph balance: ${accountBalance.toFixed(3)} available, ${requiredBalance.toFixed(3)} required`;
|
|
423
|
+
}
|
|
405
424
|
function describeRejectedDeployment(payload, references, rootfsRef) {
|
|
406
425
|
const errorCode = typeof payload.error_code === "number" ? payload.error_code : null;
|
|
407
426
|
const pendingReferences = references.filter((reference) => reference.status === "pending");
|
|
@@ -416,6 +435,10 @@ function describeRejectedDeployment(payload, references, rootfsRef) {
|
|
|
416
435
|
if (missingReferences.length > 0) {
|
|
417
436
|
return `Aleph rejected this deployment because referenced message(s) were not found on Aleph: ${missingReferences.map((reference) => reference.itemHash).join(", ")}.`;
|
|
418
437
|
}
|
|
438
|
+
const insufficientBalanceMessage = extractInsufficientBalanceMessage(payload.details);
|
|
439
|
+
if (insufficientBalanceMessage) {
|
|
440
|
+
return `Aleph rejected this deployment due to ${insufficientBalanceMessage}.`;
|
|
441
|
+
}
|
|
419
442
|
const referencedHashes = extractReferenceHashes(payload.details);
|
|
420
443
|
if (referencedHashes.length > 0) {
|
|
421
444
|
return `Aleph rejected this deployment${errorCode ? ` (error ${errorCode})` : ""}. Referenced message(s): ${referencedHashes.join(", ")}.`;
|
|
@@ -1028,6 +1051,20 @@ function extractReferenceHashes2(details) {
|
|
|
1028
1051
|
if (!Array.isArray(errors)) return [];
|
|
1029
1052
|
return errors.filter((value) => typeof value === "string");
|
|
1030
1053
|
}
|
|
1054
|
+
function extractInsufficientBalanceMessage2(details) {
|
|
1055
|
+
if (!details || typeof details !== "object" || !("errors" in details)) {
|
|
1056
|
+
return null;
|
|
1057
|
+
}
|
|
1058
|
+
const errors = details.errors;
|
|
1059
|
+
const firstError = Array.isArray(errors) && errors[0] && typeof errors[0] === "object" ? errors[0] : null;
|
|
1060
|
+
const accountBalance = typeof firstError?.account_balance === "number" || typeof firstError?.account_balance === "string" ? Number(firstError.account_balance) : Number.NaN;
|
|
1061
|
+
const requiredBalance = typeof firstError?.required_balance === "number" || typeof firstError?.required_balance === "string" ? Number(firstError.required_balance) : Number.NaN;
|
|
1062
|
+
if (!Number.isFinite(accountBalance) || !Number.isFinite(requiredBalance)) {
|
|
1063
|
+
return null;
|
|
1064
|
+
}
|
|
1065
|
+
const shortfall = requiredBalance - accountBalance;
|
|
1066
|
+
return shortfall > 0 ? `insufficient Aleph balance: ${accountBalance.toFixed(3)} available, ${requiredBalance.toFixed(3)} required, ${shortfall.toFixed(3)} short` : `insufficient Aleph balance: ${accountBalance.toFixed(3)} available, ${requiredBalance.toFixed(3)} required`;
|
|
1067
|
+
}
|
|
1031
1068
|
function describeRejectedDeployment2(payload, references, rootfsRef) {
|
|
1032
1069
|
const errorCode = typeof payload.error_code === "number" ? payload.error_code : null;
|
|
1033
1070
|
const pendingReferences = references.filter((reference) => reference.status === "pending");
|
|
@@ -1042,6 +1079,10 @@ function describeRejectedDeployment2(payload, references, rootfsRef) {
|
|
|
1042
1079
|
if (missingReferences.length > 0) {
|
|
1043
1080
|
return `Aleph rejected this deployment because referenced message(s) were not found on Aleph: ${missingReferences.map((reference) => reference.itemHash).join(", ")}.`;
|
|
1044
1081
|
}
|
|
1082
|
+
const insufficientBalanceMessage = extractInsufficientBalanceMessage2(payload.details);
|
|
1083
|
+
if (insufficientBalanceMessage) {
|
|
1084
|
+
return `Aleph rejected this deployment due to ${insufficientBalanceMessage}.`;
|
|
1085
|
+
}
|
|
1045
1086
|
const referencedHashes = extractReferenceHashes2(payload.details);
|
|
1046
1087
|
if (referencedHashes.length > 0) {
|
|
1047
1088
|
return `Aleph rejected this deployment${errorCode ? ` (error ${errorCode})` : ""}. Referenced message(s): ${referencedHashes.join(", ")}.`;
|
|
@@ -1454,6 +1495,14 @@ function buildPaymentQuote(tier, pricing, balance) {
|
|
|
1454
1495
|
label: "credits"
|
|
1455
1496
|
};
|
|
1456
1497
|
}
|
|
1498
|
+
function describeRejectedInstanceBroadcast(response) {
|
|
1499
|
+
const balanceMessage = extractInsufficientBalanceMessage2(response.details);
|
|
1500
|
+
if (balanceMessage) {
|
|
1501
|
+
return `Aleph rejected this deployment due to ${balanceMessage}.`;
|
|
1502
|
+
}
|
|
1503
|
+
const errorCode = typeof response.error_code === "number" ? response.error_code : null;
|
|
1504
|
+
return `Aleph rejected this deployment${errorCode ? ` (error ${errorCode})` : ""}.`;
|
|
1505
|
+
}
|
|
1457
1506
|
function createInstanceContent(args) {
|
|
1458
1507
|
const sshKey = normalizeSshPublicKey(args.sshPublicKey);
|
|
1459
1508
|
if (!sshKey) {
|
|
@@ -1570,9 +1619,9 @@ async function deployInstance(args) {
|
|
|
1570
1619
|
label: status === "processed" ? "Deployment accepted by Aleph" : status === "rejected" ? "Deployment rejected by Aleph" : "Deployment submitted to Aleph",
|
|
1571
1620
|
progress: status === "processed" ? 88 : status === "rejected" ? 100 : 78,
|
|
1572
1621
|
status: status === "processed" ? "success" : status === "rejected" ? "error" : "warning",
|
|
1573
|
-
detail: status === "rejected" ?
|
|
1622
|
+
detail: status === "rejected" ? describeRejectedInstanceBroadcast(response) : null,
|
|
1574
1623
|
itemHash: message.item_hash,
|
|
1575
|
-
error: status === "rejected" ?
|
|
1624
|
+
error: status === "rejected" ? describeRejectedInstanceBroadcast(response) : null,
|
|
1576
1625
|
timestamp: Date.now()
|
|
1577
1626
|
});
|
|
1578
1627
|
return {
|
|
@@ -1581,7 +1630,7 @@ async function deployInstance(args) {
|
|
|
1581
1630
|
status,
|
|
1582
1631
|
message,
|
|
1583
1632
|
response,
|
|
1584
|
-
rejectionReason: status === "rejected" ?
|
|
1633
|
+
rejectionReason: status === "rejected" ? describeRejectedInstanceBroadcast(response) : null
|
|
1585
1634
|
};
|
|
1586
1635
|
}
|
|
1587
1636
|
|
|
@@ -1971,7 +2020,13 @@ async function configureUcGoPeer(args) {
|
|
|
1971
2020
|
ws_port: args.wsPort ?? void 0,
|
|
1972
2021
|
udp_port: args.udpPort ?? void 0,
|
|
1973
2022
|
quic_port: args.quicPort ?? void 0,
|
|
1974
|
-
webrtc_port: args.webrtcPort ?? void 0
|
|
2023
|
+
webrtc_port: args.webrtcPort ?? void 0,
|
|
2024
|
+
bootstrap_publisher_private_key: args.bootstrapPublisherPrivateKey ?? void 0,
|
|
2025
|
+
bootstrap_publisher_libp2p_identity_b64: args.bootstrapPublisherLibp2pIdentityBase64 ?? void 0,
|
|
2026
|
+
bootstrap_owner_private_key: args.bootstrapOwnerPrivateKey ?? void 0,
|
|
2027
|
+
bootstrap_owner_authorization_b64: args.bootstrapOwnerAuthorizationBase64 ?? void 0,
|
|
2028
|
+
bootstrap_registration_id: args.bootstrapRegistrationId ?? void 0,
|
|
2029
|
+
no_start: args.noStart === true ? true : void 0
|
|
1975
2030
|
};
|
|
1976
2031
|
try {
|
|
1977
2032
|
const response = await args.fetch(
|
|
@@ -2011,7 +2066,13 @@ async function configureOrbitdbRelaySetup2(args) {
|
|
|
2011
2066
|
metrics_port: args.metricsPort ?? void 0,
|
|
2012
2067
|
metrics_https_port: args.metricsHttpsPort ?? void 0,
|
|
2013
2068
|
webrtc_port: args.webrtcPort ?? void 0,
|
|
2014
|
-
quic_port: args.quicPort ?? void 0
|
|
2069
|
+
quic_port: args.quicPort ?? void 0,
|
|
2070
|
+
bootstrap_publisher_private_key: args.bootstrapPublisherPrivateKey ?? void 0,
|
|
2071
|
+
bootstrap_publisher_libp2p_identity_hex: args.bootstrapPublisherLibp2pIdentityHex ?? void 0,
|
|
2072
|
+
bootstrap_owner_private_key: args.bootstrapOwnerPrivateKey ?? void 0,
|
|
2073
|
+
bootstrap_owner_authorization_b64: args.bootstrapOwnerAuthorizationBase64 ?? void 0,
|
|
2074
|
+
bootstrap_registration_id: args.bootstrapRegistrationId ?? void 0,
|
|
2075
|
+
no_start: args.noStart === true ? true : void 0
|
|
2015
2076
|
};
|
|
2016
2077
|
try {
|
|
2017
2078
|
const response = await args.fetch(
|
|
@@ -2085,14 +2146,56 @@ async function fetchUcGoPeerMetadata(args) {
|
|
|
2085
2146
|
}
|
|
2086
2147
|
|
|
2087
2148
|
// ../aleph-bootstrap/src/index.ts
|
|
2149
|
+
import { recoverMessageAddress } from "viem";
|
|
2088
2150
|
var DEFAULT_ALEPH_API_HOST3 = "https://api2.aleph.im";
|
|
2089
2151
|
var DEFAULT_ALEPH_BOOTSTRAP_CHANNEL = "simple-todo";
|
|
2090
2152
|
var DEFAULT_ALEPH_BOOTSTRAP_REF = "simple-todo-bootstrap";
|
|
2091
2153
|
var DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE = "relay-bootstrap";
|
|
2092
2154
|
var DEFAULT_BOOTSTRAP_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
2155
|
+
var DEFAULT_BOOTSTRAP_PAGINATION = 50;
|
|
2156
|
+
var RELAY_BOOTSTRAP_SIGNATURE_SCHEME = "personal_sign";
|
|
2157
|
+
function serializeOwnerAuthorizationPayload(payload) {
|
|
2158
|
+
return JSON.stringify({
|
|
2159
|
+
ownerAddress: payload.ownerAddress,
|
|
2160
|
+
publisherAddress: payload.publisherAddress,
|
|
2161
|
+
peerId: payload.peerId,
|
|
2162
|
+
registrationId: payload.registrationId,
|
|
2163
|
+
profile: payload.profile,
|
|
2164
|
+
version: payload.version,
|
|
2165
|
+
instanceItemHash: payload.instanceItemHash,
|
|
2166
|
+
issuedAt: payload.issuedAt,
|
|
2167
|
+
expiresAt: payload.expiresAt
|
|
2168
|
+
});
|
|
2169
|
+
}
|
|
2170
|
+
function serializeRelayProofPayload(payload) {
|
|
2171
|
+
return JSON.stringify({
|
|
2172
|
+
peerId: payload.peerId,
|
|
2173
|
+
multiaddrs: dedupeMultiaddrs(payload.multiaddrs),
|
|
2174
|
+
browserMultiaddrs: payload.browserMultiaddrs ? dedupeMultiaddrs(payload.browserMultiaddrs) : void 0,
|
|
2175
|
+
registrationId: payload.registrationId,
|
|
2176
|
+
profile: payload.profile,
|
|
2177
|
+
version: payload.version,
|
|
2178
|
+
updatedAt: payload.updatedAt
|
|
2179
|
+
});
|
|
2180
|
+
}
|
|
2181
|
+
function asTrimmedString(value) {
|
|
2182
|
+
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
2183
|
+
}
|
|
2184
|
+
function asNumber4(value) {
|
|
2185
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
2186
|
+
if (typeof value === "string" && value.trim()) {
|
|
2187
|
+
const parsed = Number(value);
|
|
2188
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
2189
|
+
}
|
|
2190
|
+
return null;
|
|
2191
|
+
}
|
|
2093
2192
|
function normalizeHost(host) {
|
|
2094
2193
|
return host.trim().toLowerCase();
|
|
2095
2194
|
}
|
|
2195
|
+
function normalizeSignature(signature) {
|
|
2196
|
+
const trimmed = signature.trim();
|
|
2197
|
+
return trimmed.startsWith("0x") ? trimmed : `0x${trimmed}`;
|
|
2198
|
+
}
|
|
2096
2199
|
function splitMultiaddr(addr) {
|
|
2097
2200
|
return addr.split("/").filter(Boolean);
|
|
2098
2201
|
}
|
|
@@ -2163,6 +2266,100 @@ function filterPublicMultiaddrs(addrs, options = {}) {
|
|
|
2163
2266
|
return true;
|
|
2164
2267
|
});
|
|
2165
2268
|
}
|
|
2269
|
+
function normalizeRelayBootstrapContent(value) {
|
|
2270
|
+
if (!value || typeof value !== "object") return null;
|
|
2271
|
+
const content = value;
|
|
2272
|
+
const peerId = asTrimmedString(content.peerId);
|
|
2273
|
+
const updatedAt = asNumber4(content.updatedAt);
|
|
2274
|
+
if (!peerId || updatedAt == null) return null;
|
|
2275
|
+
const multiaddrs = Array.isArray(content.multiaddrs) ? content.multiaddrs.filter((entry) => typeof entry === "string") : [];
|
|
2276
|
+
const browserMultiaddrs = Array.isArray(content.browserMultiaddrs) ? content.browserMultiaddrs.filter((entry) => typeof entry === "string") : void 0;
|
|
2277
|
+
return {
|
|
2278
|
+
peerId,
|
|
2279
|
+
multiaddrs: dedupeMultiaddrs(multiaddrs),
|
|
2280
|
+
browserMultiaddrs: browserMultiaddrs ? dedupeMultiaddrs(browserMultiaddrs) : void 0,
|
|
2281
|
+
registrationId: asTrimmedString(content.registrationId) ?? void 0,
|
|
2282
|
+
profile: asTrimmedString(content.profile) ?? void 0,
|
|
2283
|
+
version: asTrimmedString(content.version) ?? void 0,
|
|
2284
|
+
ownerAddress: asTrimmedString(content.ownerAddress) ?? void 0,
|
|
2285
|
+
publisherAddress: asTrimmedString(content.publisherAddress) ?? void 0,
|
|
2286
|
+
authorization: normalizeRelayBootstrapAuthorizationRecord(content.authorization) ?? void 0,
|
|
2287
|
+
relayProof: normalizeRelayBootstrapProofRecord(content.relayProof) ?? void 0,
|
|
2288
|
+
updatedAt
|
|
2289
|
+
};
|
|
2290
|
+
}
|
|
2291
|
+
function normalizeRelayBootstrapAuthorizationPayload(value) {
|
|
2292
|
+
if (!value || typeof value !== "object") return null;
|
|
2293
|
+
const payload = value;
|
|
2294
|
+
const ownerAddress = asTrimmedString(payload.ownerAddress);
|
|
2295
|
+
const publisherAddress = asTrimmedString(payload.publisherAddress);
|
|
2296
|
+
const peerId = asTrimmedString(payload.peerId);
|
|
2297
|
+
const issuedAt = asNumber4(payload.issuedAt);
|
|
2298
|
+
const expiresAt = asNumber4(payload.expiresAt) ?? void 0;
|
|
2299
|
+
if (!ownerAddress || !publisherAddress || !peerId || issuedAt == null) {
|
|
2300
|
+
return null;
|
|
2301
|
+
}
|
|
2302
|
+
return {
|
|
2303
|
+
ownerAddress,
|
|
2304
|
+
publisherAddress,
|
|
2305
|
+
peerId,
|
|
2306
|
+
registrationId: asTrimmedString(payload.registrationId) ?? void 0,
|
|
2307
|
+
profile: asTrimmedString(payload.profile) ?? void 0,
|
|
2308
|
+
version: asTrimmedString(payload.version) ?? void 0,
|
|
2309
|
+
instanceItemHash: asTrimmedString(payload.instanceItemHash) ?? void 0,
|
|
2310
|
+
issuedAt,
|
|
2311
|
+
expiresAt
|
|
2312
|
+
};
|
|
2313
|
+
}
|
|
2314
|
+
function normalizeRelayBootstrapAuthorizationRecord(value) {
|
|
2315
|
+
if (!value || typeof value !== "object") return null;
|
|
2316
|
+
const record = value;
|
|
2317
|
+
const scheme = asTrimmedString(record.scheme);
|
|
2318
|
+
const signature = asTrimmedString(record.signature);
|
|
2319
|
+
const payload = normalizeRelayBootstrapAuthorizationPayload(record.payload);
|
|
2320
|
+
if (!scheme || !signature || !payload) return null;
|
|
2321
|
+
return { scheme, signature, payload };
|
|
2322
|
+
}
|
|
2323
|
+
function normalizeRelayBootstrapProofPayload(value) {
|
|
2324
|
+
if (!value || typeof value !== "object") return null;
|
|
2325
|
+
const payload = value;
|
|
2326
|
+
const peerId = asTrimmedString(payload.peerId);
|
|
2327
|
+
const updatedAt = asNumber4(payload.updatedAt);
|
|
2328
|
+
if (!peerId || updatedAt == null) return null;
|
|
2329
|
+
const multiaddrs = Array.isArray(payload.multiaddrs) ? payload.multiaddrs.filter((entry) => typeof entry === "string") : [];
|
|
2330
|
+
const browserMultiaddrs = Array.isArray(payload.browserMultiaddrs) ? payload.browserMultiaddrs.filter((entry) => typeof entry === "string") : void 0;
|
|
2331
|
+
return {
|
|
2332
|
+
peerId,
|
|
2333
|
+
multiaddrs: dedupeMultiaddrs(multiaddrs),
|
|
2334
|
+
browserMultiaddrs: browserMultiaddrs ? dedupeMultiaddrs(browserMultiaddrs) : void 0,
|
|
2335
|
+
registrationId: asTrimmedString(payload.registrationId) ?? void 0,
|
|
2336
|
+
profile: asTrimmedString(payload.profile) ?? void 0,
|
|
2337
|
+
version: asTrimmedString(payload.version) ?? void 0,
|
|
2338
|
+
updatedAt
|
|
2339
|
+
};
|
|
2340
|
+
}
|
|
2341
|
+
function normalizeRelayBootstrapProofRecord(value) {
|
|
2342
|
+
if (!value || typeof value !== "object") return null;
|
|
2343
|
+
const record = value;
|
|
2344
|
+
const scheme = asTrimmedString(record.scheme);
|
|
2345
|
+
const signature = asTrimmedString(record.signature);
|
|
2346
|
+
const payload = normalizeRelayBootstrapProofPayload(record.payload);
|
|
2347
|
+
if (!scheme || !signature || !payload) return null;
|
|
2348
|
+
return { scheme, signature, payload };
|
|
2349
|
+
}
|
|
2350
|
+
function normalizeRelayBootstrapPostRecord(value) {
|
|
2351
|
+
if (!value || typeof value !== "object") return null;
|
|
2352
|
+
const entry = value;
|
|
2353
|
+
return {
|
|
2354
|
+
hash: asTrimmedString(entry.hash),
|
|
2355
|
+
itemHash: asTrimmedString(entry.item_hash),
|
|
2356
|
+
address: asTrimmedString(entry.address),
|
|
2357
|
+
ref: asTrimmedString(entry.ref),
|
|
2358
|
+
type: asTrimmedString(entry.type),
|
|
2359
|
+
time: asNumber4(entry.time),
|
|
2360
|
+
content: normalizeRelayBootstrapContent(entry.content)
|
|
2361
|
+
};
|
|
2362
|
+
}
|
|
2166
2363
|
function buildRelayBootstrapPostContent(args) {
|
|
2167
2364
|
const now = args.now ?? Date.now() / 1e3;
|
|
2168
2365
|
const updatedAt = args.now ?? Date.now();
|
|
@@ -2176,8 +2373,13 @@ function buildRelayBootstrapPostContent(args) {
|
|
|
2176
2373
|
browserMultiaddrs: args.browserMultiaddrs ? filterPublicMultiaddrs(args.browserMultiaddrs, {
|
|
2177
2374
|
browserDialableOnly: true
|
|
2178
2375
|
}) : void 0,
|
|
2376
|
+
registrationId: args.registrationId,
|
|
2179
2377
|
profile: args.profile,
|
|
2180
2378
|
version: args.version,
|
|
2379
|
+
ownerAddress: args.ownerAddress,
|
|
2380
|
+
publisherAddress: args.publisherAddress,
|
|
2381
|
+
authorization: args.authorization,
|
|
2382
|
+
relayProof: args.relayProof,
|
|
2181
2383
|
updatedAt: Math.round(updatedAt)
|
|
2182
2384
|
},
|
|
2183
2385
|
time: now
|
|
@@ -2191,10 +2393,15 @@ async function createRelayBootstrapPost(args) {
|
|
|
2191
2393
|
peerId: args.peerId,
|
|
2192
2394
|
multiaddrs: args.multiaddrs,
|
|
2193
2395
|
browserMultiaddrs: args.browserMultiaddrs,
|
|
2396
|
+
registrationId: args.registrationId,
|
|
2194
2397
|
ref: args.ref ?? DEFAULT_ALEPH_BOOTSTRAP_REF,
|
|
2195
2398
|
postType: args.postType ?? DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE,
|
|
2196
2399
|
profile: args.profile,
|
|
2197
2400
|
version: args.version,
|
|
2401
|
+
ownerAddress: args.ownerAddress,
|
|
2402
|
+
publisherAddress: args.publisherAddress,
|
|
2403
|
+
authorization: args.authorization,
|
|
2404
|
+
relayProof: args.relayProof,
|
|
2198
2405
|
now: nowMillis
|
|
2199
2406
|
});
|
|
2200
2407
|
itemContent.time = nowSeconds;
|
|
@@ -2211,19 +2418,130 @@ async function createRelayBootstrapPost(args) {
|
|
|
2211
2418
|
item_hash: itemHash
|
|
2212
2419
|
};
|
|
2213
2420
|
}
|
|
2421
|
+
async function signRelayBootstrapAuthorization(args) {
|
|
2422
|
+
const payload = {
|
|
2423
|
+
ownerAddress: args.ownerAddress,
|
|
2424
|
+
publisherAddress: args.publisherAddress,
|
|
2425
|
+
peerId: args.peerId,
|
|
2426
|
+
registrationId: args.registrationId,
|
|
2427
|
+
profile: args.profile,
|
|
2428
|
+
version: args.version,
|
|
2429
|
+
instanceItemHash: args.instanceItemHash,
|
|
2430
|
+
issuedAt: args.issuedAt ?? Date.now(),
|
|
2431
|
+
expiresAt: args.expiresAt
|
|
2432
|
+
};
|
|
2433
|
+
const serialized = serializeOwnerAuthorizationPayload(payload);
|
|
2434
|
+
const signature = await args.signer(args.ownerAddress, serialized);
|
|
2435
|
+
return {
|
|
2436
|
+
scheme: RELAY_BOOTSTRAP_SIGNATURE_SCHEME,
|
|
2437
|
+
payload,
|
|
2438
|
+
signature: normalizeSignature(signature)
|
|
2439
|
+
};
|
|
2440
|
+
}
|
|
2441
|
+
async function signRelayBootstrapProof(args) {
|
|
2442
|
+
const payload = {
|
|
2443
|
+
peerId: args.peerId,
|
|
2444
|
+
multiaddrs: filterPublicMultiaddrs(args.multiaddrs),
|
|
2445
|
+
browserMultiaddrs: args.browserMultiaddrs ? filterPublicMultiaddrs(args.browserMultiaddrs, {
|
|
2446
|
+
browserDialableOnly: true
|
|
2447
|
+
}) : void 0,
|
|
2448
|
+
registrationId: args.registrationId,
|
|
2449
|
+
profile: args.profile,
|
|
2450
|
+
version: args.version,
|
|
2451
|
+
updatedAt: args.updatedAt ?? Date.now()
|
|
2452
|
+
};
|
|
2453
|
+
const serialized = serializeRelayProofPayload(payload);
|
|
2454
|
+
const signature = await args.signer(args.publisherAddress, serialized);
|
|
2455
|
+
return {
|
|
2456
|
+
scheme: RELAY_BOOTSTRAP_SIGNATURE_SCHEME,
|
|
2457
|
+
payload,
|
|
2458
|
+
signature: normalizeSignature(signature)
|
|
2459
|
+
};
|
|
2460
|
+
}
|
|
2461
|
+
async function fetchAlephBootstrapPosts(options = {}) {
|
|
2462
|
+
const fetchImpl = options.fetch ?? globalThis.fetch?.bind(globalThis);
|
|
2463
|
+
if (typeof fetchImpl !== "function") {
|
|
2464
|
+
throw new Error(
|
|
2465
|
+
"A fetch implementation is required to query Aleph bootstrap posts."
|
|
2466
|
+
);
|
|
2467
|
+
}
|
|
2468
|
+
const url = new URL(
|
|
2469
|
+
"/api/v0/posts.json",
|
|
2470
|
+
options.apiHost ?? DEFAULT_ALEPH_API_HOST3
|
|
2471
|
+
);
|
|
2472
|
+
url.searchParams.set(
|
|
2473
|
+
"channels",
|
|
2474
|
+
options.channel ?? DEFAULT_ALEPH_BOOTSTRAP_CHANNEL
|
|
2475
|
+
);
|
|
2476
|
+
url.searchParams.set("refs", options.ref ?? DEFAULT_ALEPH_BOOTSTRAP_REF);
|
|
2477
|
+
url.searchParams.set(
|
|
2478
|
+
"types",
|
|
2479
|
+
options.postType ?? DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE
|
|
2480
|
+
);
|
|
2481
|
+
url.searchParams.set(
|
|
2482
|
+
"pagination",
|
|
2483
|
+
String(options.pagination ?? DEFAULT_BOOTSTRAP_PAGINATION)
|
|
2484
|
+
);
|
|
2485
|
+
url.searchParams.set("page", String(options.page ?? 1));
|
|
2486
|
+
const response = await fetchImpl(url.toString(), {
|
|
2487
|
+
method: "GET",
|
|
2488
|
+
headers: { accept: "application/json" }
|
|
2489
|
+
});
|
|
2490
|
+
if (!response.ok) {
|
|
2491
|
+
throw new Error(`Aleph bootstrap post lookup failed: ${response.status}`);
|
|
2492
|
+
}
|
|
2493
|
+
const payload = await response.json();
|
|
2494
|
+
return (payload.posts ?? []).map((entry) => normalizeRelayBootstrapPostRecord(entry)).filter((entry) => entry != null);
|
|
2495
|
+
}
|
|
2214
2496
|
|
|
2215
2497
|
// ../core/src/bootstrap-registration.ts
|
|
2216
2498
|
async function publishRelayBootstrapRegistration(args) {
|
|
2499
|
+
const publisherAddress = args.publisherAddress ?? args.sender;
|
|
2500
|
+
const ownerAddress = args.ownerAddress;
|
|
2501
|
+
let ownerAuthorization = args.ownerAuthorization;
|
|
2502
|
+
let relayProof = args.relayProof;
|
|
2503
|
+
if (!ownerAuthorization && ownerAddress && args.ownerSigner) {
|
|
2504
|
+
ownerAuthorization = await signRelayBootstrapAuthorization({
|
|
2505
|
+
ownerAddress,
|
|
2506
|
+
publisherAddress,
|
|
2507
|
+
peerId: args.peerId,
|
|
2508
|
+
registrationId: args.registrationId,
|
|
2509
|
+
profile: args.profile,
|
|
2510
|
+
version: args.version,
|
|
2511
|
+
instanceItemHash: args.instanceItemHash,
|
|
2512
|
+
issuedAt: args.authorizationIssuedAt ?? args.now ?? Date.now(),
|
|
2513
|
+
expiresAt: args.authorizationExpiresAt,
|
|
2514
|
+
signer: args.ownerSigner
|
|
2515
|
+
});
|
|
2516
|
+
}
|
|
2517
|
+
if (!relayProof && args.publisherSigner) {
|
|
2518
|
+
relayProof = await signRelayBootstrapProof({
|
|
2519
|
+
publisherAddress,
|
|
2520
|
+
peerId: args.peerId,
|
|
2521
|
+
multiaddrs: args.multiaddrs,
|
|
2522
|
+
browserMultiaddrs: args.browserMultiaddrs,
|
|
2523
|
+
registrationId: args.registrationId,
|
|
2524
|
+
profile: args.profile,
|
|
2525
|
+
version: args.version,
|
|
2526
|
+
updatedAt: args.now ?? Date.now(),
|
|
2527
|
+
signer: args.publisherSigner
|
|
2528
|
+
});
|
|
2529
|
+
}
|
|
2217
2530
|
const unsigned = await createRelayBootstrapPost({
|
|
2218
2531
|
sender: args.sender,
|
|
2219
2532
|
peerId: args.peerId,
|
|
2220
2533
|
multiaddrs: args.multiaddrs,
|
|
2221
2534
|
browserMultiaddrs: args.browserMultiaddrs,
|
|
2535
|
+
registrationId: args.registrationId,
|
|
2222
2536
|
channel: args.channel,
|
|
2223
2537
|
ref: args.ref,
|
|
2224
2538
|
postType: args.postType,
|
|
2225
2539
|
profile: args.profile,
|
|
2226
2540
|
version: args.version,
|
|
2541
|
+
ownerAddress,
|
|
2542
|
+
publisherAddress,
|
|
2543
|
+
authorization: ownerAuthorization,
|
|
2544
|
+
relayProof,
|
|
2227
2545
|
now: args.now,
|
|
2228
2546
|
hasher: args.hasher
|
|
2229
2547
|
});
|
|
@@ -2242,6 +2560,32 @@ async function publishRelayBootstrapRegistration(args) {
|
|
|
2242
2560
|
sync: args.sync ?? true,
|
|
2243
2561
|
fetch: args.fetch
|
|
2244
2562
|
});
|
|
2563
|
+
let forgottenHashes = [];
|
|
2564
|
+
let forgetResult;
|
|
2565
|
+
if (args.forgetPrevious && args.registrationId) {
|
|
2566
|
+
const previousPosts = await fetchAlephBootstrapPosts({
|
|
2567
|
+
apiHost: args.apiHost ?? DEFAULT_ALEPH_API_HOST3,
|
|
2568
|
+
channel: args.channel,
|
|
2569
|
+
ref: args.ref,
|
|
2570
|
+
postType: args.postType,
|
|
2571
|
+
fetch: args.fetch
|
|
2572
|
+
});
|
|
2573
|
+
forgottenHashes = previousPosts.filter(
|
|
2574
|
+
(post) => post.address?.toLowerCase() === args.sender.toLowerCase() && post.content?.registrationId === args.registrationId && (post.itemHash ?? post.hash) != null && (post.itemHash ?? post.hash) !== unsigned.item_hash
|
|
2575
|
+
).map((post) => post.itemHash ?? post.hash ?? "").filter(Boolean);
|
|
2576
|
+
if (forgottenHashes.length > 0) {
|
|
2577
|
+
forgetResult = await forgetAlephMessages({
|
|
2578
|
+
sender: args.sender,
|
|
2579
|
+
hashes: forgottenHashes,
|
|
2580
|
+
reason: args.forgetPreviousReason ?? `Replace older relay bootstrap records for ${args.registrationId}`,
|
|
2581
|
+
signer: args.signer,
|
|
2582
|
+
hasher: args.hasher,
|
|
2583
|
+
fetch: args.fetch,
|
|
2584
|
+
apiHost: args.apiHost ?? DEFAULT_ALEPH_API_HOST3,
|
|
2585
|
+
sync: args.sync ?? true
|
|
2586
|
+
});
|
|
2587
|
+
}
|
|
2588
|
+
}
|
|
2245
2589
|
return {
|
|
2246
2590
|
status: "published",
|
|
2247
2591
|
itemHash: unsigned.item_hash,
|
|
@@ -2249,7 +2593,9 @@ async function publishRelayBootstrapRegistration(args) {
|
|
|
2249
2593
|
response,
|
|
2250
2594
|
httpStatus,
|
|
2251
2595
|
publishedMultiaddrs: content.content?.multiaddrs ?? [],
|
|
2252
|
-
publishedBrowserMultiaddrs: content.content?.browserMultiaddrs ?? []
|
|
2596
|
+
publishedBrowserMultiaddrs: content.content?.browserMultiaddrs ?? [],
|
|
2597
|
+
forgottenHashes,
|
|
2598
|
+
forgetResult
|
|
2253
2599
|
};
|
|
2254
2600
|
}
|
|
2255
2601
|
|
|
@@ -2288,8 +2634,9 @@ function defaultState(props = {}) {
|
|
|
2288
2634
|
sshPublicKey: props.sshPublicKey ?? "",
|
|
2289
2635
|
instanceName: props.instanceName ?? DEFAULT_INSTANCE_NAME,
|
|
2290
2636
|
tierId: DEFAULT_TIER_ID,
|
|
2637
|
+
showAdvanced: Boolean(props.manifestJson?.trim() || props.sshPublicKey?.trim()),
|
|
2291
2638
|
showInstances: props.showInstances ?? true,
|
|
2292
|
-
showPasteManifest:
|
|
2639
|
+
showPasteManifest: Boolean(props.manifestJson?.trim()),
|
|
2293
2640
|
busy: {
|
|
2294
2641
|
connectingWallet: false,
|
|
2295
2642
|
refreshing: false,
|
|
@@ -2325,6 +2672,14 @@ function defaultState(props = {}) {
|
|
|
2325
2672
|
deploymentProgress: IDLE_DEPLOYMENT_PROGRESS
|
|
2326
2673
|
};
|
|
2327
2674
|
}
|
|
2675
|
+
function manifestLoadErrorState(error) {
|
|
2676
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2677
|
+
return {
|
|
2678
|
+
manifest: null,
|
|
2679
|
+
valid: false,
|
|
2680
|
+
errors: [message]
|
|
2681
|
+
};
|
|
2682
|
+
}
|
|
2328
2683
|
function isDebugEnabled(props) {
|
|
2329
2684
|
if (props.debug) {
|
|
2330
2685
|
return true;
|
|
@@ -2607,6 +2962,7 @@ var SponsorRelayController = class {
|
|
|
2607
2962
|
client;
|
|
2608
2963
|
refreshTimer = null;
|
|
2609
2964
|
pingTimer = null;
|
|
2965
|
+
manifestRefreshTimer = null;
|
|
2610
2966
|
stopWalletWatch = null;
|
|
2611
2967
|
props;
|
|
2612
2968
|
progressEmitter = createDeploymentProgressEmitter();
|
|
@@ -2979,6 +3335,7 @@ var SponsorRelayController = class {
|
|
|
2979
3335
|
destroy() {
|
|
2980
3336
|
if (this.refreshTimer) clearInterval(this.refreshTimer);
|
|
2981
3337
|
if (this.pingTimer) clearInterval(this.pingTimer);
|
|
3338
|
+
if (this.manifestRefreshTimer) clearTimeout(this.manifestRefreshTimer);
|
|
2982
3339
|
this.stopWalletWatch?.();
|
|
2983
3340
|
}
|
|
2984
3341
|
setOpen(open) {
|
|
@@ -2989,15 +3346,27 @@ var SponsorRelayController = class {
|
|
|
2989
3346
|
}
|
|
2990
3347
|
setManifestUrl(manifestUrl) {
|
|
2991
3348
|
this.patch({ manifestUrl });
|
|
3349
|
+
this.queueManifestRefresh();
|
|
2992
3350
|
}
|
|
2993
3351
|
setManifestJson(manifestJson) {
|
|
2994
|
-
this.patch({
|
|
3352
|
+
this.patch({
|
|
3353
|
+
manifestJson,
|
|
3354
|
+
showAdvanced: this.state.showAdvanced || Boolean(manifestJson.trim()),
|
|
3355
|
+
showPasteManifest: this.state.showPasteManifest || Boolean(manifestJson.trim())
|
|
3356
|
+
});
|
|
3357
|
+
this.queueManifestRefresh();
|
|
3358
|
+
}
|
|
3359
|
+
setShowAdvanced(showAdvanced) {
|
|
3360
|
+
this.patch({ showAdvanced });
|
|
2995
3361
|
}
|
|
2996
3362
|
setShowPasteManifest(showPasteManifest) {
|
|
2997
3363
|
this.patch({ showPasteManifest });
|
|
2998
3364
|
}
|
|
2999
3365
|
setSshPublicKey(sshPublicKey) {
|
|
3000
|
-
this.patch({
|
|
3366
|
+
this.patch({
|
|
3367
|
+
sshPublicKey,
|
|
3368
|
+
showAdvanced: this.state.showAdvanced || Boolean(sshPublicKey.trim())
|
|
3369
|
+
});
|
|
3001
3370
|
}
|
|
3002
3371
|
setInstanceName(instanceName) {
|
|
3003
3372
|
this.patch({ instanceName });
|
|
@@ -3033,6 +3402,18 @@ var SponsorRelayController = class {
|
|
|
3033
3402
|
selectedCrn
|
|
3034
3403
|
});
|
|
3035
3404
|
}
|
|
3405
|
+
queueManifestRefresh() {
|
|
3406
|
+
if (!this.state.ready) {
|
|
3407
|
+
return;
|
|
3408
|
+
}
|
|
3409
|
+
if (this.manifestRefreshTimer) {
|
|
3410
|
+
clearTimeout(this.manifestRefreshTimer);
|
|
3411
|
+
}
|
|
3412
|
+
this.manifestRefreshTimer = setTimeout(() => {
|
|
3413
|
+
this.manifestRefreshTimer = null;
|
|
3414
|
+
void this.refresh();
|
|
3415
|
+
}, MANIFEST_SOURCE_REFRESH_DEBOUNCE_MS);
|
|
3416
|
+
}
|
|
3036
3417
|
async connectWallet() {
|
|
3037
3418
|
this.patch({
|
|
3038
3419
|
busy: { connectingWallet: true },
|
|
@@ -3086,15 +3467,15 @@ var SponsorRelayController = class {
|
|
|
3086
3467
|
statusText: "Refreshing relay sponsor data"
|
|
3087
3468
|
});
|
|
3088
3469
|
try {
|
|
3089
|
-
const manifestState = await resolveManifest({
|
|
3090
|
-
manifestUrl: this.state.manifestUrl,
|
|
3091
|
-
manifestJson: this.state.manifestJson
|
|
3092
|
-
});
|
|
3093
|
-
const manifest = manifestState.manifest;
|
|
3094
3470
|
const [pricingSummary, crns] = await Promise.all([
|
|
3095
3471
|
fetchInstancePricing(this.client.apiHost),
|
|
3096
3472
|
this.client.fetchCrns()
|
|
3097
3473
|
]);
|
|
3474
|
+
const manifestState = await resolveManifest({
|
|
3475
|
+
manifestUrl: this.state.manifestUrl,
|
|
3476
|
+
manifestJson: this.state.manifestJson
|
|
3477
|
+
}).catch((error) => manifestLoadErrorState(error));
|
|
3478
|
+
const manifest = manifestState.manifest;
|
|
3098
3479
|
let balance = this.state.balance;
|
|
3099
3480
|
let instances = [];
|
|
3100
3481
|
if (this.state.wallet.address) {
|
|
@@ -3584,11 +3965,11 @@ var basePanelStyle = {
|
|
|
3584
3965
|
zIndex: 9999,
|
|
3585
3966
|
width: "min(28rem, calc(100vw - 2rem))",
|
|
3586
3967
|
overflow: "auto",
|
|
3587
|
-
border: "1px solid rgba(
|
|
3968
|
+
border: "1px solid var(--le-space-sponsor-relay-panel-border, rgba(199, 210, 254, 0.22))",
|
|
3588
3969
|
borderRadius: "1.4rem",
|
|
3589
|
-
background: "rgba(
|
|
3970
|
+
background: "var(--le-space-sponsor-relay-panel-bg, rgba(49, 46, 129, 0.94))",
|
|
3590
3971
|
color: "#f8fafc",
|
|
3591
|
-
boxShadow: "0 28px 80px rgba(
|
|
3972
|
+
boxShadow: "var(--le-space-sponsor-relay-panel-shadow, 0 28px 80px rgba(49, 46, 129, 0.34))",
|
|
3592
3973
|
padding: "1rem",
|
|
3593
3974
|
fontFamily: '"DM Sans", "Inter", sans-serif'
|
|
3594
3975
|
};
|
|
@@ -3603,6 +3984,11 @@ var fieldStyle = {
|
|
|
3603
3984
|
fontSize: "0.98rem",
|
|
3604
3985
|
lineHeight: 1.45
|
|
3605
3986
|
};
|
|
3987
|
+
var themedLauncherBackground = "linear-gradient(135deg, var(--le-space-sponsor-relay-launcher-start, #4f46e5) 0%, var(--le-space-sponsor-relay-launcher-end, #6366f1) 100%)";
|
|
3988
|
+
var themedLauncherBorder = "var(--le-space-sponsor-relay-launcher-border, rgba(199, 210, 254, 0.42))";
|
|
3989
|
+
var themedLauncherBadgeBackground = "var(--le-space-sponsor-relay-launcher-badge-bg, rgba(49, 46, 129, 0.92))";
|
|
3990
|
+
var themedLauncherBadgeBorder = "var(--le-space-sponsor-relay-launcher-badge-border, rgba(191, 219, 254, 0.24))";
|
|
3991
|
+
var themedLauncherDot = "var(--le-space-sponsor-relay-launcher-dot, #f59e0b)";
|
|
3606
3992
|
function progressToneColor(status) {
|
|
3607
3993
|
switch (status) {
|
|
3608
3994
|
case "success":
|
|
@@ -3783,11 +4169,11 @@ function SponsorRelayFab(props) {
|
|
|
3783
4169
|
const progressActive = state.deploymentProgress.stage !== "idle" && state.deploymentProgress.stage !== "completed" && state.deploymentProgress.stage !== "error";
|
|
3784
4170
|
const deploymentProgressVisible = isDeploymentProgressVisible(state);
|
|
3785
4171
|
const pulseScale = progressActive ? 1.03 : hovered ? 1.015 : 1;
|
|
3786
|
-
const pulseShadow = progressActive ? `0 0 0 4px ${progressToneColor(indicator.tone)}22, 0 12px 28px rgba(15, 23, 42, 0.22)` : successFlash ? `0 0 0 5px rgba(55, 214, 122, 0.22), 0 14px 32px rgba(55, 214, 122, 0.22)` : launcherMode === "inline" ? hovered ? "0 14px 30px rgba(79, 70, 229, 0.28)" : "0 10px 24px rgba(99, 102, 241, 0.22)" : void 0;
|
|
3787
|
-
const inlineButtonBackground =
|
|
3788
|
-
const inlineButtonBorder =
|
|
3789
|
-
const inlineBadgeBackground =
|
|
3790
|
-
const inlineBadgeBorder =
|
|
4172
|
+
const pulseShadow = progressActive ? `0 0 0 4px ${progressToneColor(indicator.tone)}22, 0 12px 28px rgba(15, 23, 42, 0.22)` : successFlash ? `0 0 0 5px rgba(55, 214, 122, 0.22), 0 14px 32px rgba(55, 214, 122, 0.22)` : launcherMode === "inline" ? hovered ? "var(--le-space-sponsor-relay-launcher-hover-shadow, 0 14px 30px rgba(79, 70, 229, 0.28))" : "var(--le-space-sponsor-relay-launcher-shadow, 0 10px 24px rgba(99, 102, 241, 0.22))" : void 0;
|
|
4173
|
+
const inlineButtonBackground = themedLauncherBackground;
|
|
4174
|
+
const inlineButtonBorder = `1px solid ${themedLauncherBorder}`;
|
|
4175
|
+
const inlineBadgeBackground = themedLauncherBadgeBackground;
|
|
4176
|
+
const inlineBadgeBorder = `1px solid ${themedLauncherBadgeBorder}`;
|
|
3791
4177
|
const panelStyle = launcherMode === "inline" ? inlinePanelStyle ?? {
|
|
3792
4178
|
...basePanelStyle,
|
|
3793
4179
|
top: "4.75rem",
|
|
@@ -3819,8 +4205,8 @@ function SponsorRelayFab(props) {
|
|
|
3819
4205
|
bottom: launcherMode === "floating" ? "5.8rem" : void 0,
|
|
3820
4206
|
zIndex: launcherMode === "floating" ? 1e4 : "auto",
|
|
3821
4207
|
borderRadius: "999px",
|
|
3822
|
-
border: launcherMode === "floating" ?
|
|
3823
|
-
background: launcherMode === "floating" ?
|
|
4208
|
+
border: launcherMode === "floating" ? `2px solid ${themedLauncherBorder}` : inlineButtonBorder,
|
|
4209
|
+
background: launcherMode === "floating" ? themedLauncherBackground : inlineButtonBackground,
|
|
3824
4210
|
color: "white",
|
|
3825
4211
|
minHeight: launcherMode === "floating" ? void 0 : "2.25rem",
|
|
3826
4212
|
padding: launcherMode === "floating" ? "0.9rem 1.2rem" : "0.42rem 0.56rem 0.42rem 0.76rem",
|
|
@@ -3856,8 +4242,8 @@ function SponsorRelayFab(props) {
|
|
|
3856
4242
|
width: launcherMode === "floating" ? "0.5rem" : "0.42rem",
|
|
3857
4243
|
height: launcherMode === "floating" ? "0.5rem" : "0.42rem",
|
|
3858
4244
|
borderRadius: "999px",
|
|
3859
|
-
background: launcherMode === "floating" ? "rgba(255,255,255,0.96)" :
|
|
3860
|
-
boxShadow: launcherMode === "floating" ? "0 0 0 3px rgba(255,255,255,0.22)" : "0 0 0 3px rgba(245, 158, 11, 0.18)"
|
|
4245
|
+
background: launcherMode === "floating" ? "rgba(255,255,255,0.96)" : themedLauncherDot,
|
|
4246
|
+
boxShadow: launcherMode === "floating" ? "0 0 0 3px rgba(255,255,255,0.22)" : "0 0 0 3px var(--le-space-sponsor-relay-launcher-dot-ring, rgba(245, 158, 11, 0.18))"
|
|
3861
4247
|
}
|
|
3862
4248
|
}
|
|
3863
4249
|
),
|
|
@@ -3916,7 +4302,7 @@ function SponsorRelayFab(props) {
|
|
|
3916
4302
|
position: "fixed",
|
|
3917
4303
|
inset: 0,
|
|
3918
4304
|
zIndex: 9998,
|
|
3919
|
-
background: "radial-gradient(circle at 88% 82%, rgba(
|
|
4305
|
+
background: "radial-gradient(circle at 88% 82%, var(--le-space-sponsor-relay-backdrop-accent, rgba(79, 70, 229, 0.2)), transparent 34%)"
|
|
3920
4306
|
}
|
|
3921
4307
|
}
|
|
3922
4308
|
),
|
|
@@ -4137,15 +4523,6 @@ function SponsorRelayFab(props) {
|
|
|
4137
4523
|
{
|
|
4138
4524
|
style: { display: "grid", gap: "0.75rem", marginTop: "0.9rem" },
|
|
4139
4525
|
children: [
|
|
4140
|
-
/* @__PURE__ */ jsx(
|
|
4141
|
-
"input",
|
|
4142
|
-
{
|
|
4143
|
-
style: fieldStyle,
|
|
4144
|
-
value: state.manifestUrl,
|
|
4145
|
-
onChange: (event) => controller.setManifestUrl(event.currentTarget.value),
|
|
4146
|
-
placeholder: "Manifest URL"
|
|
4147
|
-
}
|
|
4148
|
-
),
|
|
4149
4526
|
/* @__PURE__ */ jsx(
|
|
4150
4527
|
"input",
|
|
4151
4528
|
{
|
|
@@ -4161,31 +4538,95 @@ function SponsorRelayFab(props) {
|
|
|
4161
4538
|
style: fieldStyle,
|
|
4162
4539
|
value: state.pricingSummary.tier?.id ?? state.tierId,
|
|
4163
4540
|
onChange: (event) => controller.setTierId(event.currentTarget.value),
|
|
4164
|
-
children: (state.pricingSummary.pricing?.tiers
|
|
4541
|
+
children: (state.pricingSummary.pricing?.tiers?.length ? state.pricingSummary.pricing.tiers : [{ id: state.tierId, compute_units: 1 }]).map((tier) => {
|
|
4542
|
+
const unit = state.pricingSummary.pricing?.compute_unit;
|
|
4543
|
+
const vcpus = unit ? unit.vcpus * tier.compute_units : null;
|
|
4544
|
+
const memoryMiB = unit ? unit.memory_mib * tier.compute_units : null;
|
|
4545
|
+
const diskMiB = unit ? unit.disk_mib * tier.compute_units : null;
|
|
4546
|
+
return /* @__PURE__ */ jsx("option", { value: tier.id, children: `${tier.id} ${formatTierSpecLabel(vcpus, memoryMiB, diskMiB)}` }, tier.id);
|
|
4547
|
+
})
|
|
4165
4548
|
}
|
|
4166
4549
|
),
|
|
4167
4550
|
/* @__PURE__ */ jsx(
|
|
4168
|
-
"
|
|
4551
|
+
"div",
|
|
4169
4552
|
{
|
|
4170
|
-
style:
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4553
|
+
style: {
|
|
4554
|
+
color: "#9fb2ca",
|
|
4555
|
+
fontSize: "0.74rem",
|
|
4556
|
+
lineHeight: 1.35,
|
|
4557
|
+
marginTop: "-0.15rem"
|
|
4558
|
+
},
|
|
4559
|
+
children: formatTierSpecLabel(
|
|
4560
|
+
state.pricingSummary.vcpus,
|
|
4561
|
+
state.pricingSummary.memoryMiB,
|
|
4562
|
+
state.pricingSummary.diskMiB
|
|
4563
|
+
)
|
|
4175
4564
|
}
|
|
4176
4565
|
),
|
|
4177
|
-
/* @__PURE__ */ jsxs(
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
|
-
|
|
4188
|
-
|
|
4566
|
+
/* @__PURE__ */ jsxs(
|
|
4567
|
+
"details",
|
|
4568
|
+
{
|
|
4569
|
+
open: state.showAdvanced,
|
|
4570
|
+
onToggle: (event) => controller.setShowAdvanced(
|
|
4571
|
+
event.currentTarget.open
|
|
4572
|
+
),
|
|
4573
|
+
children: [
|
|
4574
|
+
/* @__PURE__ */ jsx("summary", { children: "Advanced" }),
|
|
4575
|
+
/* @__PURE__ */ jsxs(
|
|
4576
|
+
"div",
|
|
4577
|
+
{
|
|
4578
|
+
style: {
|
|
4579
|
+
display: "grid",
|
|
4580
|
+
gap: "0.75rem",
|
|
4581
|
+
marginTop: "0.65rem"
|
|
4582
|
+
},
|
|
4583
|
+
children: [
|
|
4584
|
+
/* @__PURE__ */ jsx(
|
|
4585
|
+
"input",
|
|
4586
|
+
{
|
|
4587
|
+
style: fieldStyle,
|
|
4588
|
+
value: state.manifestUrl,
|
|
4589
|
+
onChange: (event) => controller.setManifestUrl(event.currentTarget.value),
|
|
4590
|
+
placeholder: "Manifest URL"
|
|
4591
|
+
}
|
|
4592
|
+
),
|
|
4593
|
+
/* @__PURE__ */ jsx(
|
|
4594
|
+
"textarea",
|
|
4595
|
+
{
|
|
4596
|
+
style: fieldStyle,
|
|
4597
|
+
rows: 3,
|
|
4598
|
+
value: state.sshPublicKey,
|
|
4599
|
+
onChange: (event) => controller.setSshPublicKey(event.currentTarget.value),
|
|
4600
|
+
placeholder: "SSH public key"
|
|
4601
|
+
}
|
|
4602
|
+
),
|
|
4603
|
+
/* @__PURE__ */ jsxs(
|
|
4604
|
+
"details",
|
|
4605
|
+
{
|
|
4606
|
+
open: state.showPasteManifest,
|
|
4607
|
+
onToggle: (event) => controller.setShowPasteManifest(
|
|
4608
|
+
event.currentTarget.open
|
|
4609
|
+
),
|
|
4610
|
+
children: [
|
|
4611
|
+
/* @__PURE__ */ jsx("summary", { children: "Paste Manifest" }),
|
|
4612
|
+
/* @__PURE__ */ jsx(
|
|
4613
|
+
"textarea",
|
|
4614
|
+
{
|
|
4615
|
+
style: { ...fieldStyle, marginTop: "0.65rem" },
|
|
4616
|
+
rows: 7,
|
|
4617
|
+
value: state.manifestJson,
|
|
4618
|
+
onChange: (event) => controller.setManifestJson(event.currentTarget.value)
|
|
4619
|
+
}
|
|
4620
|
+
)
|
|
4621
|
+
]
|
|
4622
|
+
}
|
|
4623
|
+
)
|
|
4624
|
+
]
|
|
4625
|
+
}
|
|
4626
|
+
)
|
|
4627
|
+
]
|
|
4628
|
+
}
|
|
4629
|
+
)
|
|
4189
4630
|
]
|
|
4190
4631
|
}
|
|
4191
4632
|
),
|