@le-space/ui 0.6.1 → 0.6.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 +14 -0
- package/react/index.js +745 -59
- package/shared/index.d.ts +22 -2
- package/shared/index.js +561 -44
- package/svelte/SponsorRelayFab.svelte +83 -12
package/react/index.js
CHANGED
|
@@ -5,6 +5,21 @@ import React from "react";
|
|
|
5
5
|
var DEFAULT_INSTANCE_NAME = "sponsor-relay";
|
|
6
6
|
var DEFAULT_MANIFEST_URL = "./rootfs-manifest.json";
|
|
7
7
|
var DEFAULT_TIER_ID = "tier-1";
|
|
8
|
+
var DEFAULT_UCAN_STORE_PWA_ORIGIN = "https://ucan.nicokrause.com";
|
|
9
|
+
var DEFAULT_UCAN_STORE_SERVICE_ORIGIN = "https://ucan-api.nicokrause.com";
|
|
10
|
+
var DEFAULT_UCAN_STORE_SERVICE_DID = "did:web:ucan-api.nicokrause.com";
|
|
11
|
+
var DEFAULT_UCAN_STORE_ALLOWED_CAPABILITIES = [
|
|
12
|
+
"space/blob/add",
|
|
13
|
+
"space/blob/list",
|
|
14
|
+
"space/index/add",
|
|
15
|
+
"space/index/list",
|
|
16
|
+
"filecoin/offer",
|
|
17
|
+
"upload/add",
|
|
18
|
+
"upload/list",
|
|
19
|
+
"store/add"
|
|
20
|
+
];
|
|
21
|
+
var DEFAULT_UCAN_STORE_USER_DELEGATION_EXPIRATION_SECONDS = "31536000";
|
|
22
|
+
var DEFAULT_UCAN_STORE_MAX_DELEGATION_EXPIRATION_SECONDS = "315360000";
|
|
8
23
|
var ROOTFS_MISSING_STATE = {
|
|
9
24
|
tone: "idle",
|
|
10
25
|
label: "manifest missing",
|
|
@@ -28,7 +43,7 @@ var RECENT_INSTANCE_RUNTIME_GRACE_MS = 10 * 60 * 1e3;
|
|
|
28
43
|
var DEPLOYMENT_PENDING_WARNING_MS = 3 * 60 * 1e3;
|
|
29
44
|
|
|
30
45
|
// src/shared/package-version.ts
|
|
31
|
-
var UI_PACKAGE_VERSION = "0.6.
|
|
46
|
+
var UI_PACKAGE_VERSION = "0.6.3";
|
|
32
47
|
|
|
33
48
|
// src/shared/format.ts
|
|
34
49
|
function shortHash(value, head = 8, tail = 6) {
|
|
@@ -871,7 +886,7 @@ async function fetchInstancePricing(apiHost = DEFAULT_ALEPH_API_HOST, aggregateA
|
|
|
871
886
|
}
|
|
872
887
|
|
|
873
888
|
// ../core/src/constants.ts
|
|
874
|
-
var DEFAULT_ALEPH_CHANNEL = "
|
|
889
|
+
var DEFAULT_ALEPH_CHANNEL = "ALEPH-CLOUDSOLUTIONS";
|
|
875
890
|
|
|
876
891
|
// ../core/src/manifests.ts
|
|
877
892
|
var DEFAULT_ALEPH_API_HOST2 = "https://api.aleph.im";
|
|
@@ -1153,6 +1168,13 @@ function normalizeExecution2(item, crnUrl) {
|
|
|
1153
1168
|
}
|
|
1154
1169
|
|
|
1155
1170
|
// ../core/src/deployment-inspection.ts
|
|
1171
|
+
var TRANSIENT_MESSAGE_LOOKUP_STATUSES = /* @__PURE__ */ new Set([408, 425, 429, 500, 502, 503, 504]);
|
|
1172
|
+
function isTransientMessageLookupError(error) {
|
|
1173
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1174
|
+
const match = message.match(/Message lookup failed: (\d{3})/);
|
|
1175
|
+
if (!match) return false;
|
|
1176
|
+
return TRANSIENT_MESSAGE_LOOKUP_STATUSES.has(Number(match[1]));
|
|
1177
|
+
}
|
|
1156
1178
|
async function fetchMessageEnvelope2(itemHash, options) {
|
|
1157
1179
|
const response = await options.fetch(`${options.apiHost ?? DEFAULT_ALEPH_API_HOST2}/api/v0/messages/${itemHash}`, {
|
|
1158
1180
|
cache: "no-cache"
|
|
@@ -1209,15 +1231,32 @@ async function waitForDeploymentResult2(itemHash, options) {
|
|
|
1209
1231
|
const attempts = Math.max(1, Number(options.attempts ?? 15));
|
|
1210
1232
|
const delayMs = Math.max(0, Number(options.delayMs ?? 2e3));
|
|
1211
1233
|
const sleep2 = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
1212
|
-
let lastResult =
|
|
1213
|
-
|
|
1214
|
-
|
|
1234
|
+
let lastResult = {
|
|
1235
|
+
status: "unknown",
|
|
1236
|
+
errorCode: null,
|
|
1237
|
+
details: null,
|
|
1238
|
+
rejectionReason: null,
|
|
1239
|
+
references: []
|
|
1240
|
+
};
|
|
1241
|
+
for (let attempt = 1; attempt <= attempts; attempt += 1) {
|
|
1242
|
+
try {
|
|
1243
|
+
lastResult = await inspectDeploymentResult2(itemHash, options);
|
|
1244
|
+
} catch (error) {
|
|
1245
|
+
if (!isTransientMessageLookupError(error)) {
|
|
1246
|
+
throw error;
|
|
1247
|
+
}
|
|
1248
|
+
lastResult = {
|
|
1249
|
+
...lastResult,
|
|
1250
|
+
rejectionReason: error instanceof Error ? error.message : String(error)
|
|
1251
|
+
};
|
|
1252
|
+
}
|
|
1253
|
+
options.onAttempt?.(lastResult, attempt, attempts);
|
|
1215
1254
|
if (lastResult.status === "processed" || lastResult.status === "rejected") {
|
|
1216
1255
|
return lastResult;
|
|
1217
1256
|
}
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1257
|
+
if (attempt < attempts) {
|
|
1258
|
+
await sleep2(delayMs);
|
|
1259
|
+
}
|
|
1221
1260
|
}
|
|
1222
1261
|
return lastResult;
|
|
1223
1262
|
}
|
|
@@ -2274,6 +2313,45 @@ async function configureOrbitdbRelaySetup2(args) {
|
|
|
2274
2313
|
clearTimeout(timeout);
|
|
2275
2314
|
}
|
|
2276
2315
|
}
|
|
2316
|
+
async function configureUcanStore(args) {
|
|
2317
|
+
const controller = new AbortController();
|
|
2318
|
+
const timeout = setTimeout(
|
|
2319
|
+
() => controller.abort(),
|
|
2320
|
+
Number(args.timeoutMs ?? 18e4)
|
|
2321
|
+
);
|
|
2322
|
+
const payload = {
|
|
2323
|
+
public_ipv4: args.hostIpv4,
|
|
2324
|
+
public_ipv6: args.publicIpv6 ?? void 0,
|
|
2325
|
+
proxy_url: args.proxyUrl ?? void 0,
|
|
2326
|
+
webauthn_origin: args.webauthnOrigin ?? void 0,
|
|
2327
|
+
webauthn_origin_fallbacks: args.webauthnOriginFallbacks ?? void 0,
|
|
2328
|
+
admin_did: args.adminDid ?? void 0,
|
|
2329
|
+
bootstrap_package: args.bootstrapPackage ?? void 0,
|
|
2330
|
+
no_start: args.noStart === true ? true : void 0
|
|
2331
|
+
};
|
|
2332
|
+
try {
|
|
2333
|
+
const response = await args.fetch(
|
|
2334
|
+
`http://${args.hostIpv4}:${args.setupPort}/configure`,
|
|
2335
|
+
{
|
|
2336
|
+
method: "POST",
|
|
2337
|
+
headers: {
|
|
2338
|
+
"content-type": "application/json"
|
|
2339
|
+
},
|
|
2340
|
+
body: JSON.stringify(payload),
|
|
2341
|
+
signal: controller.signal
|
|
2342
|
+
}
|
|
2343
|
+
);
|
|
2344
|
+
const responsePayload = await response.json().catch(() => null);
|
|
2345
|
+
if (!response.ok) {
|
|
2346
|
+
throw new Error(
|
|
2347
|
+
`Service setup request failed: ${response.status} ${typeof responsePayload === "string" ? responsePayload : JSON.stringify(responsePayload ?? {})}`
|
|
2348
|
+
);
|
|
2349
|
+
}
|
|
2350
|
+
return responsePayload;
|
|
2351
|
+
} finally {
|
|
2352
|
+
clearTimeout(timeout);
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2277
2355
|
async function fetchUcGoPeerMetadata(args) {
|
|
2278
2356
|
const attempts = Math.max(1, Number(args.attempts ?? 60));
|
|
2279
2357
|
const delayMs = Math.max(0, Number(args.delayMs ?? 3e3));
|
|
@@ -2341,7 +2419,7 @@ async function fetchUcGoPeerMetadata(args) {
|
|
|
2341
2419
|
}
|
|
2342
2420
|
}
|
|
2343
2421
|
throw new Error(
|
|
2344
|
-
`
|
|
2422
|
+
`Guest metadata did not become ready after ${attempts} attempts: ${lastError ? lastError : typeof lastPayload === "string" ? lastPayload : JSON.stringify(lastPayload ?? {})}`
|
|
2345
2423
|
);
|
|
2346
2424
|
}
|
|
2347
2425
|
|
|
@@ -3273,7 +3351,130 @@ function createDeploymentProgressEmitter() {
|
|
|
3273
3351
|
};
|
|
3274
3352
|
}
|
|
3275
3353
|
|
|
3354
|
+
// ../shared-types/src/ucan-store-bootstrap.ts
|
|
3355
|
+
function isRecord(value) {
|
|
3356
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
3357
|
+
}
|
|
3358
|
+
function normalizeNonEmptyString(value) {
|
|
3359
|
+
if (typeof value !== "string") return null;
|
|
3360
|
+
const normalized = value.trim();
|
|
3361
|
+
return normalized ? normalized : null;
|
|
3362
|
+
}
|
|
3363
|
+
function normalizeDid(value) {
|
|
3364
|
+
const did = normalizeNonEmptyString(value);
|
|
3365
|
+
return did && did.startsWith("did:") ? did : null;
|
|
3366
|
+
}
|
|
3367
|
+
function normalizeOrigin(value) {
|
|
3368
|
+
const raw = normalizeNonEmptyString(value);
|
|
3369
|
+
if (!raw) return null;
|
|
3370
|
+
try {
|
|
3371
|
+
const parsed = new URL(raw);
|
|
3372
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:" || !parsed.hostname || parsed.pathname && parsed.pathname !== "/" || parsed.search || parsed.hash) {
|
|
3373
|
+
return null;
|
|
3374
|
+
}
|
|
3375
|
+
return parsed.origin;
|
|
3376
|
+
} catch {
|
|
3377
|
+
return null;
|
|
3378
|
+
}
|
|
3379
|
+
}
|
|
3380
|
+
function normalizeExpiration(value) {
|
|
3381
|
+
if (value == null) return void 0;
|
|
3382
|
+
if (value === null) return null;
|
|
3383
|
+
if (!Number.isInteger(value) || Number(value) < 0) return void 0;
|
|
3384
|
+
return Number(value);
|
|
3385
|
+
}
|
|
3386
|
+
function validateUcanStoreBootstrapPackage(value) {
|
|
3387
|
+
if (!isRecord(value)) {
|
|
3388
|
+
return {
|
|
3389
|
+
valid: false,
|
|
3390
|
+
errors: ["Bootstrap package must be a JSON object."],
|
|
3391
|
+
bootstrapPackage: null
|
|
3392
|
+
};
|
|
3393
|
+
}
|
|
3394
|
+
const errors = [];
|
|
3395
|
+
const operatorAddress = normalizeNonEmptyString(value.operatorAddress);
|
|
3396
|
+
if (!operatorAddress || !/^0x[a-fA-F0-9]{40}$/.test(operatorAddress)) {
|
|
3397
|
+
errors.push("operatorAddress must be a 0x-prefixed 20-byte Ethereum address.");
|
|
3398
|
+
}
|
|
3399
|
+
const adminDid = normalizeDid(value.adminDid);
|
|
3400
|
+
if (!adminDid) {
|
|
3401
|
+
errors.push("adminDid must be a non-empty DID string.");
|
|
3402
|
+
}
|
|
3403
|
+
const serviceDidRaw = value.serviceDid;
|
|
3404
|
+
const serviceDid = serviceDidRaw == null || serviceDidRaw === "" ? null : normalizeDid(serviceDidRaw);
|
|
3405
|
+
if (serviceDidRaw != null && serviceDidRaw !== "" && !serviceDid) {
|
|
3406
|
+
errors.push("serviceDid must be empty or a non-empty DID string.");
|
|
3407
|
+
}
|
|
3408
|
+
const spaceDid = normalizeDid(value.spaceDid);
|
|
3409
|
+
if (!spaceDid) {
|
|
3410
|
+
errors.push("spaceDid must be a non-empty DID string.");
|
|
3411
|
+
}
|
|
3412
|
+
const rootDelegationProof = normalizeNonEmptyString(value.rootDelegationProof);
|
|
3413
|
+
if (!rootDelegationProof) {
|
|
3414
|
+
errors.push("rootDelegationProof must be a non-empty proof string.");
|
|
3415
|
+
}
|
|
3416
|
+
const allowedCapabilities = Array.isArray(value.allowedCapabilities) ? value.allowedCapabilities.map((entry) => normalizeNonEmptyString(entry)).filter((entry) => Boolean(entry)) : [];
|
|
3417
|
+
if (allowedCapabilities.length === 0) {
|
|
3418
|
+
errors.push("allowedCapabilities must contain at least one capability string.");
|
|
3419
|
+
}
|
|
3420
|
+
const defaultUserDelegationExpiration = normalizeExpiration(
|
|
3421
|
+
value.defaultUserDelegationExpiration
|
|
3422
|
+
);
|
|
3423
|
+
if (value.defaultUserDelegationExpiration != null && defaultUserDelegationExpiration === void 0) {
|
|
3424
|
+
errors.push(
|
|
3425
|
+
"defaultUserDelegationExpiration must be null or a non-negative integer number of seconds."
|
|
3426
|
+
);
|
|
3427
|
+
}
|
|
3428
|
+
const maxUserDelegationExpiration = normalizeExpiration(
|
|
3429
|
+
value.maxUserDelegationExpiration
|
|
3430
|
+
);
|
|
3431
|
+
if (value.maxUserDelegationExpiration != null && maxUserDelegationExpiration === void 0) {
|
|
3432
|
+
errors.push(
|
|
3433
|
+
"maxUserDelegationExpiration must be null or a non-negative integer number of seconds."
|
|
3434
|
+
);
|
|
3435
|
+
}
|
|
3436
|
+
if (typeof defaultUserDelegationExpiration === "number" && typeof maxUserDelegationExpiration === "number" && defaultUserDelegationExpiration > maxUserDelegationExpiration) {
|
|
3437
|
+
errors.push(
|
|
3438
|
+
"defaultUserDelegationExpiration cannot exceed maxUserDelegationExpiration."
|
|
3439
|
+
);
|
|
3440
|
+
}
|
|
3441
|
+
const pwaOrigin = normalizeOrigin(value.pwaOrigin);
|
|
3442
|
+
if (!pwaOrigin) {
|
|
3443
|
+
errors.push("pwaOrigin must be an http(s) origin without path, query, or hash.");
|
|
3444
|
+
}
|
|
3445
|
+
const serviceOrigin = normalizeOrigin(value.serviceOrigin);
|
|
3446
|
+
if (!serviceOrigin) {
|
|
3447
|
+
errors.push("serviceOrigin must be an http(s) origin without path, query, or hash.");
|
|
3448
|
+
}
|
|
3449
|
+
if (errors.length > 0) {
|
|
3450
|
+
return {
|
|
3451
|
+
valid: false,
|
|
3452
|
+
errors,
|
|
3453
|
+
bootstrapPackage: null
|
|
3454
|
+
};
|
|
3455
|
+
}
|
|
3456
|
+
return {
|
|
3457
|
+
valid: true,
|
|
3458
|
+
errors: [],
|
|
3459
|
+
bootstrapPackage: {
|
|
3460
|
+
operatorAddress,
|
|
3461
|
+
adminDid,
|
|
3462
|
+
serviceDid,
|
|
3463
|
+
spaceDid,
|
|
3464
|
+
rootDelegationProof,
|
|
3465
|
+
allowedCapabilities,
|
|
3466
|
+
defaultUserDelegationExpiration,
|
|
3467
|
+
maxUserDelegationExpiration,
|
|
3468
|
+
pwaOrigin,
|
|
3469
|
+
serviceOrigin
|
|
3470
|
+
}
|
|
3471
|
+
};
|
|
3472
|
+
}
|
|
3473
|
+
|
|
3276
3474
|
// src/shared/controller.ts
|
|
3475
|
+
function deploymentNoun(profile) {
|
|
3476
|
+
return profile === "ucan-store" ? "service" : "relay";
|
|
3477
|
+
}
|
|
3277
3478
|
function asJsonFetch(input, init) {
|
|
3278
3479
|
return fetch(input, init).then(async (response) => ({
|
|
3279
3480
|
ok: response.ok,
|
|
@@ -3281,11 +3482,122 @@ function asJsonFetch(input, init) {
|
|
|
3281
3482
|
json: async () => await response.json()
|
|
3282
3483
|
}));
|
|
3283
3484
|
}
|
|
3284
|
-
function
|
|
3485
|
+
function isConfirmedGuestSetupResult(value) {
|
|
3285
3486
|
return Boolean(
|
|
3286
3487
|
value && typeof value === "object" && "status" in value && value.status === "configured"
|
|
3287
3488
|
);
|
|
3288
3489
|
}
|
|
3490
|
+
function defaultUcanStoreBootstrapInput(props) {
|
|
3491
|
+
return {
|
|
3492
|
+
adminDid: props.ucanStoreBootstrap?.adminDid ?? "",
|
|
3493
|
+
serviceDid: props.ucanStoreBootstrap?.serviceDid ?? DEFAULT_UCAN_STORE_SERVICE_DID,
|
|
3494
|
+
spaceDid: props.ucanStoreBootstrap?.spaceDid ?? "",
|
|
3495
|
+
rootDelegationProof: props.ucanStoreBootstrap?.rootDelegationProof ?? "",
|
|
3496
|
+
allowedCapabilities: props.ucanStoreBootstrap?.allowedCapabilities ?? DEFAULT_UCAN_STORE_ALLOWED_CAPABILITIES.join("\n"),
|
|
3497
|
+
defaultUserDelegationExpiration: props.ucanStoreBootstrap?.defaultUserDelegationExpiration ?? DEFAULT_UCAN_STORE_USER_DELEGATION_EXPIRATION_SECONDS,
|
|
3498
|
+
maxUserDelegationExpiration: props.ucanStoreBootstrap?.maxUserDelegationExpiration ?? DEFAULT_UCAN_STORE_MAX_DELEGATION_EXPIRATION_SECONDS,
|
|
3499
|
+
pwaOrigin: props.ucanStoreBootstrap?.pwaOrigin ?? DEFAULT_UCAN_STORE_PWA_ORIGIN,
|
|
3500
|
+
serviceOrigin: props.ucanStoreBootstrap?.serviceOrigin ?? DEFAULT_UCAN_STORE_SERVICE_ORIGIN
|
|
3501
|
+
};
|
|
3502
|
+
}
|
|
3503
|
+
function currentPageOrigin() {
|
|
3504
|
+
try {
|
|
3505
|
+
const origin = globalThis.location?.origin?.trim();
|
|
3506
|
+
return origin ? origin : null;
|
|
3507
|
+
} catch {
|
|
3508
|
+
return null;
|
|
3509
|
+
}
|
|
3510
|
+
}
|
|
3511
|
+
function parseOptionalExpiration(value) {
|
|
3512
|
+
const normalized = value.trim();
|
|
3513
|
+
if (!normalized) return void 0;
|
|
3514
|
+
const parsed = Number.parseInt(normalized, 10);
|
|
3515
|
+
if (!Number.isInteger(parsed) || parsed < 0) {
|
|
3516
|
+
return null;
|
|
3517
|
+
}
|
|
3518
|
+
return parsed;
|
|
3519
|
+
}
|
|
3520
|
+
function parseAllowedCapabilities(value) {
|
|
3521
|
+
return value.split(/[\n,]/).map((entry) => entry.trim()).filter(Boolean);
|
|
3522
|
+
}
|
|
3523
|
+
function draftUcanStoreBootstrapErrors(args) {
|
|
3524
|
+
const errors = [];
|
|
3525
|
+
const { input } = args;
|
|
3526
|
+
if (!args.operatorAddress) {
|
|
3527
|
+
errors.push("Connect MetaMask before configuring the ucan-store bootstrap package.");
|
|
3528
|
+
}
|
|
3529
|
+
if (!input.adminDid.trim().startsWith("did:")) {
|
|
3530
|
+
errors.push("Admin DID must be a non-empty DID string.");
|
|
3531
|
+
}
|
|
3532
|
+
if (input.serviceDid.trim() && !input.serviceDid.trim().startsWith("did:")) {
|
|
3533
|
+
errors.push("Service DID must be empty or a non-empty DID string.");
|
|
3534
|
+
}
|
|
3535
|
+
if (!input.spaceDid.trim().startsWith("did:")) {
|
|
3536
|
+
errors.push("Space DID must be a non-empty DID string.");
|
|
3537
|
+
}
|
|
3538
|
+
if (!input.rootDelegationProof.trim()) {
|
|
3539
|
+
errors.push("Root delegation proof is required.");
|
|
3540
|
+
}
|
|
3541
|
+
if (parseAllowedCapabilities(input.allowedCapabilities).length === 0) {
|
|
3542
|
+
errors.push("Add at least one allowed capability.");
|
|
3543
|
+
}
|
|
3544
|
+
const defaultExpiration = parseOptionalExpiration(
|
|
3545
|
+
input.defaultUserDelegationExpiration
|
|
3546
|
+
);
|
|
3547
|
+
if (defaultExpiration === null) {
|
|
3548
|
+
errors.push(
|
|
3549
|
+
"Default user delegation expiration must be a non-negative integer number of seconds."
|
|
3550
|
+
);
|
|
3551
|
+
}
|
|
3552
|
+
const maxExpiration = parseOptionalExpiration(
|
|
3553
|
+
input.maxUserDelegationExpiration
|
|
3554
|
+
);
|
|
3555
|
+
if (maxExpiration === null) {
|
|
3556
|
+
errors.push(
|
|
3557
|
+
"Max user delegation expiration must be a non-negative integer number of seconds."
|
|
3558
|
+
);
|
|
3559
|
+
}
|
|
3560
|
+
if (typeof defaultExpiration === "number" && typeof maxExpiration === "number" && defaultExpiration > maxExpiration) {
|
|
3561
|
+
errors.push(
|
|
3562
|
+
"Default user delegation expiration cannot exceed the max user delegation expiration."
|
|
3563
|
+
);
|
|
3564
|
+
}
|
|
3565
|
+
const pwaOrigin = input.pwaOrigin.trim() || currentPageOrigin() || "";
|
|
3566
|
+
if (!pwaOrigin) {
|
|
3567
|
+
errors.push("PWA origin is required for the ucan-store bootstrap package.");
|
|
3568
|
+
}
|
|
3569
|
+
return errors;
|
|
3570
|
+
}
|
|
3571
|
+
function buildUcanStoreBootstrapPackage(args) {
|
|
3572
|
+
const candidate = {
|
|
3573
|
+
operatorAddress: args.operatorAddress,
|
|
3574
|
+
adminDid: args.input.adminDid.trim(),
|
|
3575
|
+
serviceDid: args.input.serviceDid.trim() || null,
|
|
3576
|
+
spaceDid: args.input.spaceDid.trim(),
|
|
3577
|
+
rootDelegationProof: args.input.rootDelegationProof.trim(),
|
|
3578
|
+
allowedCapabilities: parseAllowedCapabilities(args.input.allowedCapabilities),
|
|
3579
|
+
defaultUserDelegationExpiration: parseOptionalExpiration(
|
|
3580
|
+
args.input.defaultUserDelegationExpiration
|
|
3581
|
+
),
|
|
3582
|
+
maxUserDelegationExpiration: parseOptionalExpiration(
|
|
3583
|
+
args.input.maxUserDelegationExpiration
|
|
3584
|
+
),
|
|
3585
|
+
pwaOrigin: args.input.pwaOrigin.trim() || args.pwaOriginFallback?.trim() || currentPageOrigin() || "",
|
|
3586
|
+
serviceOrigin: args.input.serviceOrigin.trim() || args.serviceOriginFallback?.trim() || ""
|
|
3587
|
+
};
|
|
3588
|
+
if (candidate.defaultUserDelegationExpiration === void 0) {
|
|
3589
|
+
delete candidate.defaultUserDelegationExpiration;
|
|
3590
|
+
}
|
|
3591
|
+
if (candidate.maxUserDelegationExpiration === void 0) {
|
|
3592
|
+
delete candidate.maxUserDelegationExpiration;
|
|
3593
|
+
}
|
|
3594
|
+
if (candidate.serviceDid === null) {
|
|
3595
|
+
delete candidate.serviceDid;
|
|
3596
|
+
}
|
|
3597
|
+
return validateUcanStoreBootstrapPackage(
|
|
3598
|
+
candidate
|
|
3599
|
+
);
|
|
3600
|
+
}
|
|
3289
3601
|
function defaultState(props = {}) {
|
|
3290
3602
|
return {
|
|
3291
3603
|
ready: false,
|
|
@@ -3300,6 +3612,7 @@ function defaultState(props = {}) {
|
|
|
3300
3612
|
manifestJson: props.manifestJson ?? "",
|
|
3301
3613
|
sshPublicKey: props.sshPublicKey ?? "",
|
|
3302
3614
|
instanceName: props.instanceName ?? DEFAULT_INSTANCE_NAME,
|
|
3615
|
+
ucanStoreBootstrap: defaultUcanStoreBootstrapInput(props),
|
|
3303
3616
|
tierId: DEFAULT_TIER_ID,
|
|
3304
3617
|
showAdvanced: Boolean(props.manifestJson?.trim() || props.sshPublicKey?.trim()),
|
|
3305
3618
|
showInstances: props.showInstances ?? true,
|
|
@@ -3434,13 +3747,33 @@ async function resolveManifest(args) {
|
|
|
3434
3747
|
if (pasted) return pasted;
|
|
3435
3748
|
return loadRootfsManifest(args.manifestUrl);
|
|
3436
3749
|
}
|
|
3437
|
-
function
|
|
3750
|
+
function deploymentProfileForManifest(manifest) {
|
|
3438
3751
|
if (manifest?.profile === "uc-go-peer") return "uc-go-peer";
|
|
3439
3752
|
if (manifest?.profile === "orbitdb-relay") {
|
|
3440
3753
|
return manifest.profile;
|
|
3441
3754
|
}
|
|
3755
|
+
if (manifest?.profile === "ucan-store") return "ucan-store";
|
|
3756
|
+
return null;
|
|
3757
|
+
}
|
|
3758
|
+
function bootstrapRelayProfileForManifest(manifest) {
|
|
3759
|
+
const profile = deploymentProfileForManifest(manifest);
|
|
3760
|
+
if (profile === "uc-go-peer" || profile === "orbitdb-relay") {
|
|
3761
|
+
return profile;
|
|
3762
|
+
}
|
|
3442
3763
|
return null;
|
|
3443
3764
|
}
|
|
3765
|
+
function supportsBootstrapRegistrationsForManifest(manifest) {
|
|
3766
|
+
return bootstrapRelayProfileForManifest(manifest) != null;
|
|
3767
|
+
}
|
|
3768
|
+
function deploymentReadyLabel(profile) {
|
|
3769
|
+
return profile === "ucan-store" ? "Service ready" : "Relay ready";
|
|
3770
|
+
}
|
|
3771
|
+
function deploymentReadyDetail(profile, fallback) {
|
|
3772
|
+
if (profile === "ucan-store") {
|
|
3773
|
+
return "The upload service runtime is available and the deployment finished successfully.";
|
|
3774
|
+
}
|
|
3775
|
+
return fallback;
|
|
3776
|
+
}
|
|
3444
3777
|
function registrationIdInstanceItemHash(registrationId) {
|
|
3445
3778
|
const normalized = String(registrationId ?? "").trim();
|
|
3446
3779
|
if (!normalized) return null;
|
|
@@ -3689,19 +4022,148 @@ var SponsorRelayController = class {
|
|
|
3689
4022
|
this.progressEmitter.emit(nextEvent);
|
|
3690
4023
|
}
|
|
3691
4024
|
async configureRelayBootstrapRegistration(args) {
|
|
3692
|
-
const
|
|
3693
|
-
|
|
3694
|
-
if (!
|
|
4025
|
+
const deploymentProfile = deploymentProfileForManifest(this.state.manifest);
|
|
4026
|
+
const profile = bootstrapRelayProfileForManifest(this.state.manifest);
|
|
4027
|
+
if (!profile && deploymentProfile !== "ucan-store") return;
|
|
4028
|
+
if (profile && !this.state.wallet.address) {
|
|
3695
4029
|
throw new Error("A connected wallet is required to register relay bootstrap addresses.");
|
|
3696
4030
|
}
|
|
3697
|
-
|
|
3698
|
-
|
|
4031
|
+
const runtimeHostIpv4 = args.runtime.hostIpv4;
|
|
4032
|
+
if (!runtimeHostIpv4) {
|
|
4033
|
+
throw new Error(
|
|
4034
|
+
`${deploymentProfile === "ucan-store" ? "Service" : "Relay"} runtime did not expose a host IPv4 address.`
|
|
4035
|
+
);
|
|
3699
4036
|
}
|
|
3700
4037
|
let runtime = args.runtime;
|
|
3701
4038
|
let mappedPorts2 = runtime.mappedPorts ?? {};
|
|
3702
4039
|
const setupPort = mappedPorts2["80"]?.host ?? null;
|
|
3703
4040
|
if (!setupPort) {
|
|
3704
|
-
throw new Error(
|
|
4041
|
+
throw new Error(
|
|
4042
|
+
`${deploymentProfile === "ucan-store" ? "Service" : "Relay"} runtime did not expose the temporary setup endpoint.`
|
|
4043
|
+
);
|
|
4044
|
+
}
|
|
4045
|
+
if (deploymentProfile === "ucan-store") {
|
|
4046
|
+
const serviceHostIpv4 = runtimeHostIpv4;
|
|
4047
|
+
const serviceProxyUrl = runtime.proxyUrl;
|
|
4048
|
+
if (!serviceProxyUrl) {
|
|
4049
|
+
throw new Error("Service runtime did not expose a proxy URL.");
|
|
4050
|
+
}
|
|
4051
|
+
const walletAddress2 = this.state.wallet.address;
|
|
4052
|
+
if (!walletAddress2) {
|
|
4053
|
+
throw new Error("A connected wallet is required to configure the ucan-store bootstrap package.");
|
|
4054
|
+
}
|
|
4055
|
+
const bootstrapValidation = buildUcanStoreBootstrapPackage({
|
|
4056
|
+
input: this.state.ucanStoreBootstrap,
|
|
4057
|
+
operatorAddress: walletAddress2,
|
|
4058
|
+
serviceOriginFallback: serviceProxyUrl,
|
|
4059
|
+
pwaOriginFallback: currentPageOrigin()
|
|
4060
|
+
});
|
|
4061
|
+
if (!bootstrapValidation.valid || !bootstrapValidation.bootstrapPackage) {
|
|
4062
|
+
throw new Error(
|
|
4063
|
+
bootstrapValidation.errors[0] ?? "The ucan-store bootstrap package is invalid."
|
|
4064
|
+
);
|
|
4065
|
+
}
|
|
4066
|
+
this.emitProgress({
|
|
4067
|
+
stage: "deployment-confirmed",
|
|
4068
|
+
label: "Configuring service",
|
|
4069
|
+
progress: 93,
|
|
4070
|
+
status: "info",
|
|
4071
|
+
itemHash: args.itemHash,
|
|
4072
|
+
detail: "Waiting for the guest setup endpoint before applying the upload service configuration."
|
|
4073
|
+
});
|
|
4074
|
+
const setupHealth = await waitForSetupEndpoint({
|
|
4075
|
+
hostIpv4: serviceHostIpv4,
|
|
4076
|
+
setupPort,
|
|
4077
|
+
fetch: (url, init) => fetch(url, init),
|
|
4078
|
+
attempts: 15,
|
|
4079
|
+
delayMs: 4e3,
|
|
4080
|
+
httpTimeoutMs: 1e4,
|
|
4081
|
+
onAttempt: (result, attempt, attempts) => {
|
|
4082
|
+
this.emitProgress({
|
|
4083
|
+
stage: "deployment-confirmed",
|
|
4084
|
+
label: "Waiting for guest setup",
|
|
4085
|
+
progress: 93,
|
|
4086
|
+
status: result.ok ? "success" : "info",
|
|
4087
|
+
itemHash: args.itemHash,
|
|
4088
|
+
detail: result.ok ? `Setup endpoint ${attempt}/${attempts}: ready at http://${serviceHostIpv4}:${setupPort}/health.` : `Setup endpoint ${attempt}/${attempts}: waiting for http://${serviceHostIpv4}:${setupPort}/health.`
|
|
4089
|
+
});
|
|
4090
|
+
}
|
|
4091
|
+
});
|
|
4092
|
+
if (!setupHealth.ok) {
|
|
4093
|
+
throw new Error(
|
|
4094
|
+
`Service setup endpoint did not become reachable at http://${serviceHostIpv4}:${setupPort}/health.`
|
|
4095
|
+
);
|
|
4096
|
+
}
|
|
4097
|
+
this.emitProgress({
|
|
4098
|
+
stage: "deployment-confirmed",
|
|
4099
|
+
label: "Applying service config",
|
|
4100
|
+
progress: 94,
|
|
4101
|
+
status: "info",
|
|
4102
|
+
itemHash: args.itemHash,
|
|
4103
|
+
detail: "Publishing the public HTTPS origin into the guest upload service configuration."
|
|
4104
|
+
});
|
|
4105
|
+
const configureResult = await configureUcanStore({
|
|
4106
|
+
hostIpv4: serviceHostIpv4,
|
|
4107
|
+
publicIpv6: runtime.ipv6,
|
|
4108
|
+
setupPort,
|
|
4109
|
+
proxyUrl: serviceProxyUrl,
|
|
4110
|
+
webauthnOrigin: serviceProxyUrl,
|
|
4111
|
+
adminDid: bootstrapValidation.bootstrapPackage.adminDid,
|
|
4112
|
+
bootstrapPackage: bootstrapValidation.bootstrapPackage,
|
|
4113
|
+
fetch: (url, init) => fetch(url, init),
|
|
4114
|
+
timeoutMs: 18e4
|
|
4115
|
+
});
|
|
4116
|
+
if (!isConfirmedGuestSetupResult(configureResult)) {
|
|
4117
|
+
throw new Error(
|
|
4118
|
+
`Service guest configuration could not be confirmed at http://${serviceHostIpv4}:${setupPort}/configure.`
|
|
4119
|
+
);
|
|
4120
|
+
}
|
|
4121
|
+
this.emitProgress({
|
|
4122
|
+
stage: "deployment-confirmed",
|
|
4123
|
+
label: "Waiting for service metadata",
|
|
4124
|
+
progress: 95,
|
|
4125
|
+
status: "info",
|
|
4126
|
+
itemHash: args.itemHash,
|
|
4127
|
+
detail: "Waiting for the upload service metadata endpoint to report the public service DID and PWA environment."
|
|
4128
|
+
});
|
|
4129
|
+
const serviceMetadata = await fetchUcGoPeerMetadata({
|
|
4130
|
+
hostIpv4: serviceHostIpv4,
|
|
4131
|
+
setupPort,
|
|
4132
|
+
fetch: (url, init) => fetch(url, init),
|
|
4133
|
+
attempts: 80,
|
|
4134
|
+
delayMs: 3e3,
|
|
4135
|
+
timeoutMs: 24e4,
|
|
4136
|
+
isReady: ({ payload, ok }) => {
|
|
4137
|
+
if (!ok || !payload || typeof payload !== "object") return false;
|
|
4138
|
+
const metadata2 = payload.metadata && typeof payload.metadata === "object" ? payload.metadata : null;
|
|
4139
|
+
const pwaEnv = metadata2?.pwa_env && typeof metadata2.pwa_env === "object" ? metadata2.pwa_env : null;
|
|
4140
|
+
return Boolean(
|
|
4141
|
+
typeof metadata2?.upload_service_did === "string" && metadata2.upload_service_did.length > 0 && typeof pwaEnv?.VITE_UPLOAD_SERVICE_URL === "string" && pwaEnv.VITE_UPLOAD_SERVICE_URL.length > 0
|
|
4142
|
+
);
|
|
4143
|
+
},
|
|
4144
|
+
onAttempt: ({ ready, attempt, attempts, requestUrl }) => {
|
|
4145
|
+
this.emitProgress({
|
|
4146
|
+
stage: "deployment-confirmed",
|
|
4147
|
+
label: ready ? "Service metadata ready" : "Waiting for service metadata",
|
|
4148
|
+
progress: 95,
|
|
4149
|
+
status: ready ? "success" : "info",
|
|
4150
|
+
itemHash: args.itemHash,
|
|
4151
|
+
detail: ready ? `Service metadata ${attempt}/${attempts}: public upload service wiring is ready.` : `Service metadata ${attempt}/${attempts}: waiting for ${requestUrl}.`
|
|
4152
|
+
});
|
|
4153
|
+
}
|
|
4154
|
+
});
|
|
4155
|
+
const metadata = serviceMetadata && typeof serviceMetadata === "object" ? serviceMetadata.metadata ?? null : null;
|
|
4156
|
+
if (!metadata || typeof metadata !== "object" || typeof metadata.upload_service_did !== "string") {
|
|
4157
|
+
throw new Error(
|
|
4158
|
+
"Service metadata did not include the public upload service DID."
|
|
4159
|
+
);
|
|
4160
|
+
}
|
|
4161
|
+
return;
|
|
4162
|
+
}
|
|
4163
|
+
if (!profile) return;
|
|
4164
|
+
const walletAddress = this.state.wallet.address;
|
|
4165
|
+
if (!walletAddress) {
|
|
4166
|
+
throw new Error("A connected wallet is required to register relay bootstrap addresses.");
|
|
3705
4167
|
}
|
|
3706
4168
|
let bootstrapSignalRelayMetadata = null;
|
|
3707
4169
|
if (profile === "orbitdb-relay") {
|
|
@@ -3714,7 +4176,7 @@ var SponsorRelayController = class {
|
|
|
3714
4176
|
detail: "Waiting for the guest setup endpoint before collecting relay metadata."
|
|
3715
4177
|
});
|
|
3716
4178
|
const setupHealth = await waitForSetupEndpoint({
|
|
3717
|
-
hostIpv4:
|
|
4179
|
+
hostIpv4: runtimeHostIpv4,
|
|
3718
4180
|
setupPort,
|
|
3719
4181
|
fetch: (url, init) => fetch(url, init),
|
|
3720
4182
|
attempts: 15,
|
|
@@ -3727,13 +4189,13 @@ var SponsorRelayController = class {
|
|
|
3727
4189
|
progress: 93,
|
|
3728
4190
|
status: result.ok ? "success" : "info",
|
|
3729
4191
|
itemHash: args.itemHash,
|
|
3730
|
-
detail: result.ok ? `Setup endpoint ${attempt}/${attempts}: ready at http://${
|
|
4192
|
+
detail: result.ok ? `Setup endpoint ${attempt}/${attempts}: ready at http://${runtimeHostIpv4}:${setupPort}/health.` : `Setup endpoint ${attempt}/${attempts}: waiting for http://${runtimeHostIpv4}:${setupPort}/health.`
|
|
3731
4193
|
});
|
|
3732
4194
|
}
|
|
3733
4195
|
});
|
|
3734
4196
|
if (!setupHealth.ok) {
|
|
3735
4197
|
throw new Error(
|
|
3736
|
-
`Relay setup endpoint did not become reachable at http://${
|
|
4198
|
+
`Relay setup endpoint did not become reachable at http://${runtimeHostIpv4}:${setupPort}/health.`
|
|
3737
4199
|
);
|
|
3738
4200
|
}
|
|
3739
4201
|
this.emitProgress({
|
|
@@ -3750,7 +4212,7 @@ var SponsorRelayController = class {
|
|
|
3750
4212
|
throw new Error("OrbitDB relay runtime is missing required mapped TCP/WS ports.");
|
|
3751
4213
|
}
|
|
3752
4214
|
const configureResult = await configureOrbitdbRelaySetup2({
|
|
3753
|
-
hostIpv4:
|
|
4215
|
+
hostIpv4: runtimeHostIpv4,
|
|
3754
4216
|
publicIpv6: args.runtime.ipv6,
|
|
3755
4217
|
setupPort,
|
|
3756
4218
|
tcpPort,
|
|
@@ -3763,7 +4225,7 @@ var SponsorRelayController = class {
|
|
|
3763
4225
|
fetch: (url, init) => fetch(url, init),
|
|
3764
4226
|
timeoutMs: 18e4
|
|
3765
4227
|
});
|
|
3766
|
-
if (!
|
|
4228
|
+
if (!isConfirmedGuestSetupResult(configureResult)) {
|
|
3767
4229
|
throw new Error(
|
|
3768
4230
|
`Relay guest configuration could not be confirmed at http://${args.runtime.hostIpv4}:${setupPort}/configure.`
|
|
3769
4231
|
);
|
|
@@ -3821,7 +4283,7 @@ var SponsorRelayController = class {
|
|
|
3821
4283
|
"Relay runtime lost its host IPv4 address while waiting for HTTPS activation."
|
|
3822
4284
|
);
|
|
3823
4285
|
}
|
|
3824
|
-
const
|
|
4286
|
+
const runtimeHostIpv42 = runtime.hostIpv4;
|
|
3825
4287
|
const activeProxyUrl = runtime.webAccess?.active === true ? runtime.proxyUrl ?? null : null;
|
|
3826
4288
|
this.emitProgress({
|
|
3827
4289
|
stage: "deployment-confirmed",
|
|
@@ -3834,13 +4296,13 @@ var SponsorRelayController = class {
|
|
|
3834
4296
|
const record = {
|
|
3835
4297
|
deploymentToken: args.deploymentToken,
|
|
3836
4298
|
profile,
|
|
3837
|
-
ownerAddress:
|
|
4299
|
+
ownerAddress: walletAddress,
|
|
3838
4300
|
instanceItemHash: args.itemHash,
|
|
3839
4301
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3840
4302
|
expiresAt: new Date(Date.now() + 30 * 6e4).toISOString(),
|
|
3841
4303
|
status: "pending",
|
|
3842
4304
|
runtime: {
|
|
3843
|
-
publicIpv4:
|
|
4305
|
+
publicIpv4: runtimeHostIpv42,
|
|
3844
4306
|
publicIpv6: runtime.ipv6 ?? null,
|
|
3845
4307
|
proxyUrl: activeProxyUrl,
|
|
3846
4308
|
mappedPorts: mappedPorts2
|
|
@@ -3854,7 +4316,7 @@ var SponsorRelayController = class {
|
|
|
3854
4316
|
}
|
|
3855
4317
|
};
|
|
3856
4318
|
const bootstrapConfigPublication = await publishVmBootstrapConfig({
|
|
3857
|
-
sender:
|
|
4319
|
+
sender: walletAddress,
|
|
3858
4320
|
record,
|
|
3859
4321
|
signer: personalSign,
|
|
3860
4322
|
hasher: sha256Hex,
|
|
@@ -3881,7 +4343,7 @@ var SponsorRelayController = class {
|
|
|
3881
4343
|
});
|
|
3882
4344
|
const bootstrapConfigSignal = await waitForVmBootstrapConfigSignal({
|
|
3883
4345
|
deploymentToken: args.deploymentToken,
|
|
3884
|
-
ownerAddress:
|
|
4346
|
+
ownerAddress: walletAddress,
|
|
3885
4347
|
instanceItemHash: args.itemHash,
|
|
3886
4348
|
fetch: asJsonFetch,
|
|
3887
4349
|
apiHost: this.client.apiHost,
|
|
@@ -4053,7 +4515,7 @@ var SponsorRelayController = class {
|
|
|
4053
4515
|
detail: "Guest bootstrap registration was delayed. Publishing the relay bootstrap record from the browser."
|
|
4054
4516
|
});
|
|
4055
4517
|
const fallbackPublication = await publishRelayBootstrapRegistration({
|
|
4056
|
-
sender:
|
|
4518
|
+
sender: walletAddress,
|
|
4057
4519
|
signer: personalSign,
|
|
4058
4520
|
hasher: sha256Hex,
|
|
4059
4521
|
fetch: asJsonFetch,
|
|
@@ -4073,7 +4535,7 @@ var SponsorRelayController = class {
|
|
|
4073
4535
|
fallbackPublication
|
|
4074
4536
|
});
|
|
4075
4537
|
const fallbackVisibleRegistration = await waitForRelayBootstrapRegistration({
|
|
4076
|
-
sender:
|
|
4538
|
+
sender: walletAddress,
|
|
4077
4539
|
registrationId,
|
|
4078
4540
|
peerId,
|
|
4079
4541
|
fetch: asJsonFetch,
|
|
@@ -4106,7 +4568,7 @@ var SponsorRelayController = class {
|
|
|
4106
4568
|
if (profile === "uc-go-peer" && args.deploymentToken) {
|
|
4107
4569
|
let cleanupAggregateItemHash = null;
|
|
4108
4570
|
await deleteVmBootstrapConfig({
|
|
4109
|
-
sender:
|
|
4571
|
+
sender: walletAddress,
|
|
4110
4572
|
deploymentToken: args.deploymentToken,
|
|
4111
4573
|
signer: personalSign,
|
|
4112
4574
|
hasher: sha256Hex,
|
|
@@ -4272,17 +4734,35 @@ var SponsorRelayController = class {
|
|
|
4272
4734
|
});
|
|
4273
4735
|
return;
|
|
4274
4736
|
}
|
|
4737
|
+
const currentProfile = deploymentProfileForManifest(this.state.manifest);
|
|
4275
4738
|
const hasConfirmedBootstrapRegistration = this.state.bootstrapRegistrations.some(
|
|
4276
4739
|
(entry) => entry.instanceItemHash === itemHash && entry.confirmed
|
|
4277
4740
|
);
|
|
4741
|
+
if (currentProfile === "ucan-store") {
|
|
4742
|
+
this.emitProgress({
|
|
4743
|
+
stage: "completed",
|
|
4744
|
+
label: deploymentReadyLabel(currentProfile),
|
|
4745
|
+
progress: 100,
|
|
4746
|
+
status: "success",
|
|
4747
|
+
itemHash,
|
|
4748
|
+
detail: deploymentReadyDetail(
|
|
4749
|
+
currentProfile,
|
|
4750
|
+
"Runtime networking is available and the deployment finished successfully."
|
|
4751
|
+
)
|
|
4752
|
+
});
|
|
4753
|
+
return;
|
|
4754
|
+
}
|
|
4278
4755
|
if (hasConfirmedBootstrapRegistration) {
|
|
4279
4756
|
this.emitProgress({
|
|
4280
4757
|
stage: "completed",
|
|
4281
|
-
label:
|
|
4758
|
+
label: deploymentReadyLabel(currentProfile),
|
|
4282
4759
|
progress: 100,
|
|
4283
4760
|
status: "success",
|
|
4284
4761
|
itemHash,
|
|
4285
|
-
detail:
|
|
4762
|
+
detail: deploymentReadyDetail(
|
|
4763
|
+
currentProfile,
|
|
4764
|
+
"Runtime networking is available and the relay bootstrap registration is confirmed on Aleph."
|
|
4765
|
+
)
|
|
4286
4766
|
});
|
|
4287
4767
|
return;
|
|
4288
4768
|
}
|
|
@@ -4292,7 +4772,7 @@ var SponsorRelayController = class {
|
|
|
4292
4772
|
progress: 92,
|
|
4293
4773
|
status: "info",
|
|
4294
4774
|
itemHash,
|
|
4295
|
-
detail:
|
|
4775
|
+
detail: `Deployment processed and runtime networking is available. Finishing ${deploymentNoun(currentProfile)} setup and verification.`
|
|
4296
4776
|
});
|
|
4297
4777
|
}
|
|
4298
4778
|
canSkipRuntimeRefresh(instance) {
|
|
@@ -4405,6 +4885,15 @@ var SponsorRelayController = class {
|
|
|
4405
4885
|
setInstanceName(instanceName) {
|
|
4406
4886
|
this.patch({ instanceName });
|
|
4407
4887
|
}
|
|
4888
|
+
setUcanStoreBootstrapField(field, value) {
|
|
4889
|
+
this.patch({
|
|
4890
|
+
ucanStoreBootstrap: {
|
|
4891
|
+
...this.state.ucanStoreBootstrap,
|
|
4892
|
+
[field]: value
|
|
4893
|
+
},
|
|
4894
|
+
showAdvanced: this.state.showAdvanced || Boolean(value.trim())
|
|
4895
|
+
});
|
|
4896
|
+
}
|
|
4408
4897
|
setTierId(tierId) {
|
|
4409
4898
|
this.patch({ tierId });
|
|
4410
4899
|
this.recomputePricingSummary();
|
|
@@ -4490,6 +4979,7 @@ var SponsorRelayController = class {
|
|
|
4490
4979
|
}
|
|
4491
4980
|
}
|
|
4492
4981
|
async refresh() {
|
|
4982
|
+
const currentProfile = deploymentProfileForManifest(this.state.manifest);
|
|
4493
4983
|
this.trace("refresh:start", {
|
|
4494
4984
|
wallet: this.state.wallet.address,
|
|
4495
4985
|
manifestUrl: this.state.manifestUrl,
|
|
@@ -4498,7 +4988,7 @@ var SponsorRelayController = class {
|
|
|
4498
4988
|
this.patch({
|
|
4499
4989
|
busy: { refreshing: true },
|
|
4500
4990
|
errorText: null,
|
|
4501
|
-
statusText: "Refreshing relay
|
|
4991
|
+
statusText: currentProfile === "ucan-store" ? "Refreshing service deployment data" : "Refreshing relay deployment data"
|
|
4502
4992
|
});
|
|
4503
4993
|
try {
|
|
4504
4994
|
const [pricingSummary, crns] = await Promise.all([
|
|
@@ -4510,6 +5000,8 @@ var SponsorRelayController = class {
|
|
|
4510
5000
|
manifestJson: this.state.manifestJson
|
|
4511
5001
|
}).catch((error) => manifestLoadErrorState(error));
|
|
4512
5002
|
const manifest = manifestState.manifest;
|
|
5003
|
+
const resolvedProfile = deploymentProfileForManifest(manifest);
|
|
5004
|
+
const bootstrapEnabled = supportsBootstrapRegistrationsForManifest(manifest);
|
|
4513
5005
|
let balance = this.state.balance;
|
|
4514
5006
|
let instances = [];
|
|
4515
5007
|
let bootstrapRegistrations = [];
|
|
@@ -4518,10 +5010,10 @@ var SponsorRelayController = class {
|
|
|
4518
5010
|
const [nextBalance, rawInstances, rawBootstrapPosts] = await Promise.all([
|
|
4519
5011
|
this.client.fetchBalance(this.state.wallet.address),
|
|
4520
5012
|
this.state.showInstances ? this.client.fetchInstances(this.state.wallet.address) : Promise.resolve([]),
|
|
4521
|
-
fetchAlephBootstrapPosts({
|
|
5013
|
+
bootstrapEnabled ? fetchAlephBootstrapPosts({
|
|
4522
5014
|
apiHost: this.client.apiHost,
|
|
4523
5015
|
fetch
|
|
4524
|
-
}).catch(() => [])
|
|
5016
|
+
}).catch(() => []) : Promise.resolve([])
|
|
4525
5017
|
]);
|
|
4526
5018
|
balance = nextBalance;
|
|
4527
5019
|
instances = await Promise.all(
|
|
@@ -4651,7 +5143,7 @@ var SponsorRelayController = class {
|
|
|
4651
5143
|
bootstrapRegistrations,
|
|
4652
5144
|
orphanBootstrapRegistrations,
|
|
4653
5145
|
busy: { refreshing: false },
|
|
4654
|
-
statusText: "Relay
|
|
5146
|
+
statusText: resolvedProfile === "ucan-store" ? "Service deployment data ready" : "Relay deployment data ready"
|
|
4655
5147
|
});
|
|
4656
5148
|
this.trace("refresh:success", {
|
|
4657
5149
|
manifestValid: manifestState.valid,
|
|
@@ -4688,6 +5180,16 @@ var SponsorRelayController = class {
|
|
|
4688
5180
|
});
|
|
4689
5181
|
return;
|
|
4690
5182
|
}
|
|
5183
|
+
if (deploymentProfileForManifest(this.state.manifest) === "ucan-store") {
|
|
5184
|
+
const draftErrors = draftUcanStoreBootstrapErrors({
|
|
5185
|
+
input: this.state.ucanStoreBootstrap,
|
|
5186
|
+
operatorAddress: this.state.wallet.address
|
|
5187
|
+
});
|
|
5188
|
+
if (draftErrors.length > 0) {
|
|
5189
|
+
this.patch({ errorText: draftErrors[0] });
|
|
5190
|
+
return;
|
|
5191
|
+
}
|
|
5192
|
+
}
|
|
4691
5193
|
this.patch({
|
|
4692
5194
|
busy: { deploying: true },
|
|
4693
5195
|
errorText: null,
|
|
@@ -4737,7 +5239,7 @@ var SponsorRelayController = class {
|
|
|
4737
5239
|
detail: `Trying ${crnDisplayName}`
|
|
4738
5240
|
});
|
|
4739
5241
|
try {
|
|
4740
|
-
const profile =
|
|
5242
|
+
const profile = deploymentProfileForManifest(this.state.manifest);
|
|
4741
5243
|
attemptProfile = profile;
|
|
4742
5244
|
const sshPublicKey = profile === "uc-go-peer" ? appendDeploymentTokenToSshPublicKey(
|
|
4743
5245
|
this.state.sshPublicKey.trim(),
|
|
@@ -4956,11 +5458,14 @@ var SponsorRelayController = class {
|
|
|
4956
5458
|
this.lastCompletedDeploymentHash = result.itemHash;
|
|
4957
5459
|
this.emitProgress({
|
|
4958
5460
|
stage: "completed",
|
|
4959
|
-
label:
|
|
5461
|
+
label: deploymentReadyLabel(attemptProfile),
|
|
4960
5462
|
progress: 100,
|
|
4961
5463
|
status: "success",
|
|
4962
5464
|
itemHash: result.itemHash,
|
|
4963
|
-
detail:
|
|
5465
|
+
detail: deploymentReadyDetail(
|
|
5466
|
+
attemptProfile,
|
|
5467
|
+
"Relay runtime, setup, metadata, and bootstrap registration are confirmed."
|
|
5468
|
+
)
|
|
4964
5469
|
});
|
|
4965
5470
|
return;
|
|
4966
5471
|
} catch (error) {
|
|
@@ -5034,11 +5539,14 @@ var SponsorRelayController = class {
|
|
|
5034
5539
|
this.lastCompletedDeploymentHash = attemptItemHash;
|
|
5035
5540
|
this.emitProgress({
|
|
5036
5541
|
stage: "completed",
|
|
5037
|
-
label:
|
|
5542
|
+
label: deploymentReadyLabel(attemptProfile),
|
|
5038
5543
|
progress: 100,
|
|
5039
5544
|
status: "success",
|
|
5040
5545
|
itemHash: attemptItemHash,
|
|
5041
|
-
detail:
|
|
5546
|
+
detail: deploymentReadyDetail(
|
|
5547
|
+
attemptProfile,
|
|
5548
|
+
"The relay completed startup after a transient UI polling error. Runtime and bootstrap registration are confirmed."
|
|
5549
|
+
)
|
|
5042
5550
|
});
|
|
5043
5551
|
return;
|
|
5044
5552
|
}
|
|
@@ -5065,11 +5573,14 @@ var SponsorRelayController = class {
|
|
|
5065
5573
|
this.lastCompletedDeploymentHash = attemptItemHash;
|
|
5066
5574
|
this.emitProgress({
|
|
5067
5575
|
stage: "completed",
|
|
5068
|
-
label:
|
|
5576
|
+
label: deploymentReadyLabel(attemptProfile),
|
|
5069
5577
|
progress: 100,
|
|
5070
5578
|
status: "success",
|
|
5071
5579
|
itemHash: attemptItemHash,
|
|
5072
|
-
detail:
|
|
5580
|
+
detail: deploymentReadyDetail(
|
|
5581
|
+
attemptProfile,
|
|
5582
|
+
"The relay completed startup after a transient browser-side polling error. Runtime and bootstrap registration are confirmed."
|
|
5583
|
+
)
|
|
5073
5584
|
});
|
|
5074
5585
|
return;
|
|
5075
5586
|
}
|
|
@@ -5384,7 +5895,8 @@ function useSponsorRelayController(props) {
|
|
|
5384
5895
|
props.schedulerApiHost,
|
|
5385
5896
|
props.showInstances,
|
|
5386
5897
|
props.sshPublicKey,
|
|
5387
|
-
props.twoN6ApiHost
|
|
5898
|
+
props.twoN6ApiHost,
|
|
5899
|
+
props.ucanStoreBootstrap
|
|
5388
5900
|
]
|
|
5389
5901
|
);
|
|
5390
5902
|
useEffect(() => {
|
|
@@ -5518,6 +6030,27 @@ var POLLING_STAGES = /* @__PURE__ */ new Set([
|
|
|
5518
6030
|
"publishing-bootstrap",
|
|
5519
6031
|
"refreshing-instances"
|
|
5520
6032
|
]);
|
|
6033
|
+
function stateDeploymentProfile(state) {
|
|
6034
|
+
return state.manifest?.profile === "ucan-store" ? "ucan-store" : "relay";
|
|
6035
|
+
}
|
|
6036
|
+
function supportsBootstrapUi(state) {
|
|
6037
|
+
return stateDeploymentProfile(state) !== "ucan-store";
|
|
6038
|
+
}
|
|
6039
|
+
function deploymentPanelTitle(state) {
|
|
6040
|
+
return stateDeploymentProfile(state) === "ucan-store" ? "Sponsor Service" : "Sponsor Relay";
|
|
6041
|
+
}
|
|
6042
|
+
function deploymentLauncherLabel(state, compactInlineLabel, launcherMode) {
|
|
6043
|
+
if (launcherMode === "inline" && compactInlineLabel) {
|
|
6044
|
+
return stateDeploymentProfile(state) === "ucan-store" ? "Service" : "Relay";
|
|
6045
|
+
}
|
|
6046
|
+
return deploymentPanelTitle(state);
|
|
6047
|
+
}
|
|
6048
|
+
function deploymentInstanceFallbackLabel(state) {
|
|
6049
|
+
return stateDeploymentProfile(state) === "ucan-store" ? "service" : "relay";
|
|
6050
|
+
}
|
|
6051
|
+
function deploymentButtonLabel(state) {
|
|
6052
|
+
return stateDeploymentProfile(state) === "ucan-store" ? "Deploy Service" : "Deploy Relay";
|
|
6053
|
+
}
|
|
5521
6054
|
function isDeploymentProgressVisible(state) {
|
|
5522
6055
|
const stage = state.deploymentProgress.stage;
|
|
5523
6056
|
if (stage === "idle") {
|
|
@@ -5533,17 +6066,19 @@ function isDeploymentProgressVisible(state) {
|
|
|
5533
6066
|
}
|
|
5534
6067
|
function pollingIndicator(state) {
|
|
5535
6068
|
if (state.busy.refreshing) {
|
|
6069
|
+
const isService2 = stateDeploymentProfile(state) === "ucan-store";
|
|
5536
6070
|
return {
|
|
5537
|
-
label: "Checking relay state",
|
|
5538
|
-
detail: state.statusText || "Refreshing relay
|
|
6071
|
+
label: isService2 ? "Checking deployment state" : "Checking relay state",
|
|
6072
|
+
detail: state.statusText || (isService2 ? "Refreshing service deployment data from Aleph and the selected CRN." : "Refreshing relay deployment data from Aleph and the selected CRN.")
|
|
5539
6073
|
};
|
|
5540
6074
|
}
|
|
5541
6075
|
if (!POLLING_STAGES.has(state.deploymentProgress.stage)) {
|
|
5542
6076
|
return null;
|
|
5543
6077
|
}
|
|
6078
|
+
const isService = stateDeploymentProfile(state) === "ucan-store";
|
|
5544
6079
|
return {
|
|
5545
|
-
label: state.deploymentProgress.label || "Polling relay state",
|
|
5546
|
-
detail: state.deploymentProgress.detail || state.statusText || "Waiting for the next confirmed relay state from Aleph."
|
|
6080
|
+
label: state.deploymentProgress.label || (isService ? "Polling deployment state" : "Polling relay state"),
|
|
6081
|
+
detail: state.deploymentProgress.detail || state.statusText || (isService ? "Waiting for the next confirmed deployment state from Aleph." : "Waiting for the next confirmed relay state from Aleph.")
|
|
5547
6082
|
};
|
|
5548
6083
|
}
|
|
5549
6084
|
function launcherIndicator(state) {
|
|
@@ -5592,7 +6127,7 @@ function launcherIndicator(state) {
|
|
|
5592
6127
|
if (state.busy.refreshing) {
|
|
5593
6128
|
return {
|
|
5594
6129
|
label: "SYNC",
|
|
5595
|
-
detail: "Refreshing relay state",
|
|
6130
|
+
detail: stateDeploymentProfile(state) === "ucan-store" ? "Refreshing deployment state" : "Refreshing relay state",
|
|
5596
6131
|
tone: "info"
|
|
5597
6132
|
};
|
|
5598
6133
|
}
|
|
@@ -5609,6 +6144,7 @@ function SponsorRelayFab(props) {
|
|
|
5609
6144
|
const versionLabel = resolvedVersion.startsWith("v") ? resolvedVersion : `v${resolvedVersion}`;
|
|
5610
6145
|
const launcherMode = props.launcherMode ?? "floating";
|
|
5611
6146
|
const indicator = launcherIndicator(state);
|
|
6147
|
+
const bootstrapUiEnabled = supportsBootstrapUi(state);
|
|
5612
6148
|
const confirmedRegistrationByInstanceHash = new Map(
|
|
5613
6149
|
(state.bootstrapRegistrations ?? []).filter((entry) => entry.confirmed && entry.instanceItemHash).map((entry) => [entry.instanceItemHash, entry])
|
|
5614
6150
|
);
|
|
@@ -5710,7 +6246,8 @@ function SponsorRelayFab(props) {
|
|
|
5710
6246
|
bottom: "11.5rem",
|
|
5711
6247
|
maxHeight: "calc(100vh - 12.5rem)"
|
|
5712
6248
|
};
|
|
5713
|
-
const launcherLabel =
|
|
6249
|
+
const launcherLabel = deploymentLauncherLabel(state, compactInlineLabel, launcherMode);
|
|
6250
|
+
const deployCallToAction = state.wallet.connected ? state.busy.deploying ? "Deploying\u2026" : deploymentButtonLabel(state) : "Connect MetaMask";
|
|
5714
6251
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5715
6252
|
/* @__PURE__ */ jsx("style", { children: `@keyframes leSpaceRelayPulse { 0%, 100% { transform: scale(1); opacity: 0.74; } 50% { transform: scale(1.22); opacity: 1; } }` }),
|
|
5716
6253
|
/* @__PURE__ */ jsxs(
|
|
@@ -5723,7 +6260,7 @@ function SponsorRelayFab(props) {
|
|
|
5723
6260
|
onMouseLeave: () => setHovered(false),
|
|
5724
6261
|
onFocus: () => setHovered(true),
|
|
5725
6262
|
onBlur: () => setHovered(false),
|
|
5726
|
-
title: indicator.detail ??
|
|
6263
|
+
title: indicator.detail ?? deploymentPanelTitle(state),
|
|
5727
6264
|
style: {
|
|
5728
6265
|
position: launcherMode === "floating" ? "fixed" : "relative",
|
|
5729
6266
|
right: launcherMode === "floating" ? "1.4rem" : void 0,
|
|
@@ -5880,7 +6417,7 @@ function SponsorRelayFab(props) {
|
|
|
5880
6417
|
margin: "0.2rem 0 0",
|
|
5881
6418
|
fontFamily: '"Epilogue", sans-serif'
|
|
5882
6419
|
},
|
|
5883
|
-
children:
|
|
6420
|
+
children: deploymentPanelTitle(state)
|
|
5884
6421
|
}
|
|
5885
6422
|
)
|
|
5886
6423
|
] }),
|
|
@@ -6217,7 +6754,156 @@ function SponsorRelayFab(props) {
|
|
|
6217
6754
|
)
|
|
6218
6755
|
]
|
|
6219
6756
|
}
|
|
6220
|
-
)
|
|
6757
|
+
),
|
|
6758
|
+
stateDeploymentProfile(state) === "ucan-store" ? /* @__PURE__ */ jsxs("details", { open: true, children: [
|
|
6759
|
+
/* @__PURE__ */ jsx("summary", { children: "UCAN Store Bootstrap" }),
|
|
6760
|
+
/* @__PURE__ */ jsxs(
|
|
6761
|
+
"div",
|
|
6762
|
+
{
|
|
6763
|
+
style: {
|
|
6764
|
+
display: "grid",
|
|
6765
|
+
gap: "0.75rem",
|
|
6766
|
+
marginTop: "0.65rem"
|
|
6767
|
+
},
|
|
6768
|
+
children: [
|
|
6769
|
+
/* @__PURE__ */ jsx(
|
|
6770
|
+
"input",
|
|
6771
|
+
{
|
|
6772
|
+
style: fieldStyle,
|
|
6773
|
+
value: state.ucanStoreBootstrap.adminDid,
|
|
6774
|
+
onChange: (event) => controller.setUcanStoreBootstrapField(
|
|
6775
|
+
"adminDid",
|
|
6776
|
+
event.currentTarget.value
|
|
6777
|
+
),
|
|
6778
|
+
placeholder: "Admin DID"
|
|
6779
|
+
}
|
|
6780
|
+
),
|
|
6781
|
+
/* @__PURE__ */ jsx(
|
|
6782
|
+
"input",
|
|
6783
|
+
{
|
|
6784
|
+
style: fieldStyle,
|
|
6785
|
+
value: state.ucanStoreBootstrap.serviceDid,
|
|
6786
|
+
onChange: (event) => controller.setUcanStoreBootstrapField(
|
|
6787
|
+
"serviceDid",
|
|
6788
|
+
event.currentTarget.value
|
|
6789
|
+
),
|
|
6790
|
+
placeholder: "Service DID override (optional)"
|
|
6791
|
+
}
|
|
6792
|
+
),
|
|
6793
|
+
/* @__PURE__ */ jsx(
|
|
6794
|
+
"input",
|
|
6795
|
+
{
|
|
6796
|
+
style: fieldStyle,
|
|
6797
|
+
value: state.ucanStoreBootstrap.spaceDid,
|
|
6798
|
+
onChange: (event) => controller.setUcanStoreBootstrapField(
|
|
6799
|
+
"spaceDid",
|
|
6800
|
+
event.currentTarget.value
|
|
6801
|
+
),
|
|
6802
|
+
placeholder: "Space DID"
|
|
6803
|
+
}
|
|
6804
|
+
),
|
|
6805
|
+
/* @__PURE__ */ jsx(
|
|
6806
|
+
"textarea",
|
|
6807
|
+
{
|
|
6808
|
+
style: fieldStyle,
|
|
6809
|
+
rows: 5,
|
|
6810
|
+
value: state.ucanStoreBootstrap.rootDelegationProof,
|
|
6811
|
+
onChange: (event) => controller.setUcanStoreBootstrapField(
|
|
6812
|
+
"rootDelegationProof",
|
|
6813
|
+
event.currentTarget.value
|
|
6814
|
+
),
|
|
6815
|
+
placeholder: "Root delegation proof"
|
|
6816
|
+
}
|
|
6817
|
+
),
|
|
6818
|
+
/* @__PURE__ */ jsx(
|
|
6819
|
+
"textarea",
|
|
6820
|
+
{
|
|
6821
|
+
style: fieldStyle,
|
|
6822
|
+
rows: 4,
|
|
6823
|
+
value: state.ucanStoreBootstrap.allowedCapabilities,
|
|
6824
|
+
onChange: (event) => controller.setUcanStoreBootstrapField(
|
|
6825
|
+
"allowedCapabilities",
|
|
6826
|
+
event.currentTarget.value
|
|
6827
|
+
),
|
|
6828
|
+
placeholder: "Allowed capabilities, one per line or comma-separated\nspace/blob/add\nspace/blob/list"
|
|
6829
|
+
}
|
|
6830
|
+
),
|
|
6831
|
+
/* @__PURE__ */ jsxs(
|
|
6832
|
+
"div",
|
|
6833
|
+
{
|
|
6834
|
+
style: {
|
|
6835
|
+
display: "grid",
|
|
6836
|
+
gap: "0.75rem",
|
|
6837
|
+
gridTemplateColumns: "repeat(auto-fit, minmax(10rem, 1fr))"
|
|
6838
|
+
},
|
|
6839
|
+
children: [
|
|
6840
|
+
/* @__PURE__ */ jsx(
|
|
6841
|
+
"input",
|
|
6842
|
+
{
|
|
6843
|
+
style: fieldStyle,
|
|
6844
|
+
value: state.ucanStoreBootstrap.defaultUserDelegationExpiration,
|
|
6845
|
+
onChange: (event) => controller.setUcanStoreBootstrapField(
|
|
6846
|
+
"defaultUserDelegationExpiration",
|
|
6847
|
+
event.currentTarget.value
|
|
6848
|
+
),
|
|
6849
|
+
placeholder: "Default expiration (seconds)"
|
|
6850
|
+
}
|
|
6851
|
+
),
|
|
6852
|
+
/* @__PURE__ */ jsx(
|
|
6853
|
+
"input",
|
|
6854
|
+
{
|
|
6855
|
+
style: fieldStyle,
|
|
6856
|
+
value: state.ucanStoreBootstrap.maxUserDelegationExpiration,
|
|
6857
|
+
onChange: (event) => controller.setUcanStoreBootstrapField(
|
|
6858
|
+
"maxUserDelegationExpiration",
|
|
6859
|
+
event.currentTarget.value
|
|
6860
|
+
),
|
|
6861
|
+
placeholder: "Max expiration (seconds)"
|
|
6862
|
+
}
|
|
6863
|
+
)
|
|
6864
|
+
]
|
|
6865
|
+
}
|
|
6866
|
+
),
|
|
6867
|
+
/* @__PURE__ */ jsx(
|
|
6868
|
+
"input",
|
|
6869
|
+
{
|
|
6870
|
+
style: fieldStyle,
|
|
6871
|
+
value: state.ucanStoreBootstrap.pwaOrigin,
|
|
6872
|
+
onChange: (event) => controller.setUcanStoreBootstrapField(
|
|
6873
|
+
"pwaOrigin",
|
|
6874
|
+
event.currentTarget.value
|
|
6875
|
+
),
|
|
6876
|
+
placeholder: "PWA origin override (optional, defaults to current page origin)"
|
|
6877
|
+
}
|
|
6878
|
+
),
|
|
6879
|
+
/* @__PURE__ */ jsx(
|
|
6880
|
+
"input",
|
|
6881
|
+
{
|
|
6882
|
+
style: fieldStyle,
|
|
6883
|
+
value: state.ucanStoreBootstrap.serviceOrigin,
|
|
6884
|
+
onChange: (event) => controller.setUcanStoreBootstrapField(
|
|
6885
|
+
"serviceOrigin",
|
|
6886
|
+
event.currentTarget.value
|
|
6887
|
+
),
|
|
6888
|
+
placeholder: "Service origin override (optional, defaults to runtime proxy URL)"
|
|
6889
|
+
}
|
|
6890
|
+
),
|
|
6891
|
+
/* @__PURE__ */ jsx(
|
|
6892
|
+
"div",
|
|
6893
|
+
{
|
|
6894
|
+
style: {
|
|
6895
|
+
color: "#9fb2ca",
|
|
6896
|
+
fontSize: "0.74rem",
|
|
6897
|
+
lineHeight: 1.35,
|
|
6898
|
+
marginTop: "-0.15rem"
|
|
6899
|
+
},
|
|
6900
|
+
children: "Operator address comes from the connected MetaMask account. If you leave service origin empty, `relay-button` will use the runtime proxy URL during guest configuration."
|
|
6901
|
+
}
|
|
6902
|
+
)
|
|
6903
|
+
]
|
|
6904
|
+
}
|
|
6905
|
+
)
|
|
6906
|
+
] }) : null
|
|
6221
6907
|
]
|
|
6222
6908
|
}
|
|
6223
6909
|
)
|
|
@@ -6253,7 +6939,7 @@ function SponsorRelayFab(props) {
|
|
|
6253
6939
|
onClick: () => void (state.wallet.connected ? controller.deploy() : controller.connectWallet()),
|
|
6254
6940
|
disabled: state.wallet.connected ? state.busy.deploying || state.rootfsHealth.tone !== "ok" : state.busy.connectingWallet,
|
|
6255
6941
|
style: { ...primaryButtonStyle, width: "100%", marginTop: "1rem" },
|
|
6256
|
-
children:
|
|
6942
|
+
children: deployCallToAction
|
|
6257
6943
|
}
|
|
6258
6944
|
),
|
|
6259
6945
|
state.lastDeploymentHash ? /* @__PURE__ */ jsxs("p", { children: [
|
|
@@ -6280,8 +6966,8 @@ function SponsorRelayFab(props) {
|
|
|
6280
6966
|
flexWrap: "wrap"
|
|
6281
6967
|
},
|
|
6282
6968
|
children: [
|
|
6283
|
-
(entry.instance.content?.metadata?.name ??
|
|
6284
|
-
confirmedRegistration ? /* @__PURE__ */ jsxs(
|
|
6969
|
+
(entry.instance.content?.metadata?.name ?? deploymentInstanceFallbackLabel(state)) + " \xB7 " + shortHash(entry.instance.item_hash),
|
|
6970
|
+
bootstrapUiEnabled && confirmedRegistration ? /* @__PURE__ */ jsxs(
|
|
6285
6971
|
"span",
|
|
6286
6972
|
{
|
|
6287
6973
|
style: {
|
|
@@ -6329,7 +7015,7 @@ function SponsorRelayFab(props) {
|
|
|
6329
7015
|
"Status: ",
|
|
6330
7016
|
entry.details.messageStatus
|
|
6331
7017
|
] }),
|
|
6332
|
-
confirmedRegistration ? /* @__PURE__ */ jsxs("div", { children: [
|
|
7018
|
+
bootstrapUiEnabled && confirmedRegistration ? /* @__PURE__ */ jsxs("div", { children: [
|
|
6333
7019
|
"Bootstrap registration:",
|
|
6334
7020
|
" ",
|
|
6335
7021
|
shortHash(
|
|
@@ -6381,7 +7067,7 @@ function SponsorRelayFab(props) {
|
|
|
6381
7067
|
)
|
|
6382
7068
|
] }, entry.instance.item_hash);
|
|
6383
7069
|
}),
|
|
6384
|
-
orphanRegistrations.length > 0 ? /* @__PURE__ */ jsxs(
|
|
7070
|
+
bootstrapUiEnabled && orphanRegistrations.length > 0 ? /* @__PURE__ */ jsxs(
|
|
6385
7071
|
"div",
|
|
6386
7072
|
{
|
|
6387
7073
|
style: {
|