@le-space/ui 0.6.1 → 0.6.2
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 +699 -52
- package/shared/index.d.ts +16 -2
- package/shared/index.js +509 -37
- package/svelte/SponsorRelayFab.svelte +83 -12
package/react/index.js
CHANGED
|
@@ -28,7 +28,7 @@ var RECENT_INSTANCE_RUNTIME_GRACE_MS = 10 * 60 * 1e3;
|
|
|
28
28
|
var DEPLOYMENT_PENDING_WARNING_MS = 3 * 60 * 1e3;
|
|
29
29
|
|
|
30
30
|
// src/shared/package-version.ts
|
|
31
|
-
var UI_PACKAGE_VERSION = "0.6.
|
|
31
|
+
var UI_PACKAGE_VERSION = "0.6.2";
|
|
32
32
|
|
|
33
33
|
// src/shared/format.ts
|
|
34
34
|
function shortHash(value, head = 8, tail = 6) {
|
|
@@ -2274,6 +2274,45 @@ async function configureOrbitdbRelaySetup2(args) {
|
|
|
2274
2274
|
clearTimeout(timeout);
|
|
2275
2275
|
}
|
|
2276
2276
|
}
|
|
2277
|
+
async function configureUcanStore(args) {
|
|
2278
|
+
const controller = new AbortController();
|
|
2279
|
+
const timeout = setTimeout(
|
|
2280
|
+
() => controller.abort(),
|
|
2281
|
+
Number(args.timeoutMs ?? 18e4)
|
|
2282
|
+
);
|
|
2283
|
+
const payload = {
|
|
2284
|
+
public_ipv4: args.hostIpv4,
|
|
2285
|
+
public_ipv6: args.publicIpv6 ?? void 0,
|
|
2286
|
+
proxy_url: args.proxyUrl ?? void 0,
|
|
2287
|
+
webauthn_origin: args.webauthnOrigin ?? void 0,
|
|
2288
|
+
webauthn_origin_fallbacks: args.webauthnOriginFallbacks ?? void 0,
|
|
2289
|
+
admin_did: args.adminDid ?? void 0,
|
|
2290
|
+
bootstrap_package: args.bootstrapPackage ?? void 0,
|
|
2291
|
+
no_start: args.noStart === true ? true : void 0
|
|
2292
|
+
};
|
|
2293
|
+
try {
|
|
2294
|
+
const response = await args.fetch(
|
|
2295
|
+
`http://${args.hostIpv4}:${args.setupPort}/configure`,
|
|
2296
|
+
{
|
|
2297
|
+
method: "POST",
|
|
2298
|
+
headers: {
|
|
2299
|
+
"content-type": "application/json"
|
|
2300
|
+
},
|
|
2301
|
+
body: JSON.stringify(payload),
|
|
2302
|
+
signal: controller.signal
|
|
2303
|
+
}
|
|
2304
|
+
);
|
|
2305
|
+
const responsePayload = await response.json().catch(() => null);
|
|
2306
|
+
if (!response.ok) {
|
|
2307
|
+
throw new Error(
|
|
2308
|
+
`Service setup request failed: ${response.status} ${typeof responsePayload === "string" ? responsePayload : JSON.stringify(responsePayload ?? {})}`
|
|
2309
|
+
);
|
|
2310
|
+
}
|
|
2311
|
+
return responsePayload;
|
|
2312
|
+
} finally {
|
|
2313
|
+
clearTimeout(timeout);
|
|
2314
|
+
}
|
|
2315
|
+
}
|
|
2277
2316
|
async function fetchUcGoPeerMetadata(args) {
|
|
2278
2317
|
const attempts = Math.max(1, Number(args.attempts ?? 60));
|
|
2279
2318
|
const delayMs = Math.max(0, Number(args.delayMs ?? 3e3));
|
|
@@ -2341,7 +2380,7 @@ async function fetchUcGoPeerMetadata(args) {
|
|
|
2341
2380
|
}
|
|
2342
2381
|
}
|
|
2343
2382
|
throw new Error(
|
|
2344
|
-
`
|
|
2383
|
+
`Guest metadata did not become ready after ${attempts} attempts: ${lastError ? lastError : typeof lastPayload === "string" ? lastPayload : JSON.stringify(lastPayload ?? {})}`
|
|
2345
2384
|
);
|
|
2346
2385
|
}
|
|
2347
2386
|
|
|
@@ -3273,7 +3312,130 @@ function createDeploymentProgressEmitter() {
|
|
|
3273
3312
|
};
|
|
3274
3313
|
}
|
|
3275
3314
|
|
|
3315
|
+
// ../shared-types/src/ucan-store-bootstrap.ts
|
|
3316
|
+
function isRecord(value) {
|
|
3317
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
3318
|
+
}
|
|
3319
|
+
function normalizeNonEmptyString(value) {
|
|
3320
|
+
if (typeof value !== "string") return null;
|
|
3321
|
+
const normalized = value.trim();
|
|
3322
|
+
return normalized ? normalized : null;
|
|
3323
|
+
}
|
|
3324
|
+
function normalizeDid(value) {
|
|
3325
|
+
const did = normalizeNonEmptyString(value);
|
|
3326
|
+
return did && did.startsWith("did:") ? did : null;
|
|
3327
|
+
}
|
|
3328
|
+
function normalizeOrigin(value) {
|
|
3329
|
+
const raw = normalizeNonEmptyString(value);
|
|
3330
|
+
if (!raw) return null;
|
|
3331
|
+
try {
|
|
3332
|
+
const parsed = new URL(raw);
|
|
3333
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:" || !parsed.hostname || parsed.pathname && parsed.pathname !== "/" || parsed.search || parsed.hash) {
|
|
3334
|
+
return null;
|
|
3335
|
+
}
|
|
3336
|
+
return parsed.origin;
|
|
3337
|
+
} catch {
|
|
3338
|
+
return null;
|
|
3339
|
+
}
|
|
3340
|
+
}
|
|
3341
|
+
function normalizeExpiration(value) {
|
|
3342
|
+
if (value == null) return void 0;
|
|
3343
|
+
if (value === null) return null;
|
|
3344
|
+
if (!Number.isInteger(value) || Number(value) < 0) return void 0;
|
|
3345
|
+
return Number(value);
|
|
3346
|
+
}
|
|
3347
|
+
function validateUcanStoreBootstrapPackage(value) {
|
|
3348
|
+
if (!isRecord(value)) {
|
|
3349
|
+
return {
|
|
3350
|
+
valid: false,
|
|
3351
|
+
errors: ["Bootstrap package must be a JSON object."],
|
|
3352
|
+
bootstrapPackage: null
|
|
3353
|
+
};
|
|
3354
|
+
}
|
|
3355
|
+
const errors = [];
|
|
3356
|
+
const operatorAddress = normalizeNonEmptyString(value.operatorAddress);
|
|
3357
|
+
if (!operatorAddress || !/^0x[a-fA-F0-9]{40}$/.test(operatorAddress)) {
|
|
3358
|
+
errors.push("operatorAddress must be a 0x-prefixed 20-byte Ethereum address.");
|
|
3359
|
+
}
|
|
3360
|
+
const adminDid = normalizeDid(value.adminDid);
|
|
3361
|
+
if (!adminDid) {
|
|
3362
|
+
errors.push("adminDid must be a non-empty DID string.");
|
|
3363
|
+
}
|
|
3364
|
+
const serviceDidRaw = value.serviceDid;
|
|
3365
|
+
const serviceDid = serviceDidRaw == null || serviceDidRaw === "" ? null : normalizeDid(serviceDidRaw);
|
|
3366
|
+
if (serviceDidRaw != null && serviceDidRaw !== "" && !serviceDid) {
|
|
3367
|
+
errors.push("serviceDid must be empty or a non-empty DID string.");
|
|
3368
|
+
}
|
|
3369
|
+
const spaceDid = normalizeDid(value.spaceDid);
|
|
3370
|
+
if (!spaceDid) {
|
|
3371
|
+
errors.push("spaceDid must be a non-empty DID string.");
|
|
3372
|
+
}
|
|
3373
|
+
const rootDelegationProof = normalizeNonEmptyString(value.rootDelegationProof);
|
|
3374
|
+
if (!rootDelegationProof) {
|
|
3375
|
+
errors.push("rootDelegationProof must be a non-empty proof string.");
|
|
3376
|
+
}
|
|
3377
|
+
const allowedCapabilities = Array.isArray(value.allowedCapabilities) ? value.allowedCapabilities.map((entry) => normalizeNonEmptyString(entry)).filter((entry) => Boolean(entry)) : [];
|
|
3378
|
+
if (allowedCapabilities.length === 0) {
|
|
3379
|
+
errors.push("allowedCapabilities must contain at least one capability string.");
|
|
3380
|
+
}
|
|
3381
|
+
const defaultUserDelegationExpiration = normalizeExpiration(
|
|
3382
|
+
value.defaultUserDelegationExpiration
|
|
3383
|
+
);
|
|
3384
|
+
if (value.defaultUserDelegationExpiration != null && defaultUserDelegationExpiration === void 0) {
|
|
3385
|
+
errors.push(
|
|
3386
|
+
"defaultUserDelegationExpiration must be null or a non-negative integer number of seconds."
|
|
3387
|
+
);
|
|
3388
|
+
}
|
|
3389
|
+
const maxUserDelegationExpiration = normalizeExpiration(
|
|
3390
|
+
value.maxUserDelegationExpiration
|
|
3391
|
+
);
|
|
3392
|
+
if (value.maxUserDelegationExpiration != null && maxUserDelegationExpiration === void 0) {
|
|
3393
|
+
errors.push(
|
|
3394
|
+
"maxUserDelegationExpiration must be null or a non-negative integer number of seconds."
|
|
3395
|
+
);
|
|
3396
|
+
}
|
|
3397
|
+
if (typeof defaultUserDelegationExpiration === "number" && typeof maxUserDelegationExpiration === "number" && defaultUserDelegationExpiration > maxUserDelegationExpiration) {
|
|
3398
|
+
errors.push(
|
|
3399
|
+
"defaultUserDelegationExpiration cannot exceed maxUserDelegationExpiration."
|
|
3400
|
+
);
|
|
3401
|
+
}
|
|
3402
|
+
const pwaOrigin = normalizeOrigin(value.pwaOrigin);
|
|
3403
|
+
if (!pwaOrigin) {
|
|
3404
|
+
errors.push("pwaOrigin must be an http(s) origin without path, query, or hash.");
|
|
3405
|
+
}
|
|
3406
|
+
const serviceOrigin = normalizeOrigin(value.serviceOrigin);
|
|
3407
|
+
if (!serviceOrigin) {
|
|
3408
|
+
errors.push("serviceOrigin must be an http(s) origin without path, query, or hash.");
|
|
3409
|
+
}
|
|
3410
|
+
if (errors.length > 0) {
|
|
3411
|
+
return {
|
|
3412
|
+
valid: false,
|
|
3413
|
+
errors,
|
|
3414
|
+
bootstrapPackage: null
|
|
3415
|
+
};
|
|
3416
|
+
}
|
|
3417
|
+
return {
|
|
3418
|
+
valid: true,
|
|
3419
|
+
errors: [],
|
|
3420
|
+
bootstrapPackage: {
|
|
3421
|
+
operatorAddress,
|
|
3422
|
+
adminDid,
|
|
3423
|
+
serviceDid,
|
|
3424
|
+
spaceDid,
|
|
3425
|
+
rootDelegationProof,
|
|
3426
|
+
allowedCapabilities,
|
|
3427
|
+
defaultUserDelegationExpiration,
|
|
3428
|
+
maxUserDelegationExpiration,
|
|
3429
|
+
pwaOrigin,
|
|
3430
|
+
serviceOrigin
|
|
3431
|
+
}
|
|
3432
|
+
};
|
|
3433
|
+
}
|
|
3434
|
+
|
|
3276
3435
|
// src/shared/controller.ts
|
|
3436
|
+
function deploymentNoun(profile) {
|
|
3437
|
+
return profile === "ucan-store" ? "service" : "relay";
|
|
3438
|
+
}
|
|
3277
3439
|
function asJsonFetch(input, init) {
|
|
3278
3440
|
return fetch(input, init).then(async (response) => ({
|
|
3279
3441
|
ok: response.ok,
|
|
@@ -3281,11 +3443,122 @@ function asJsonFetch(input, init) {
|
|
|
3281
3443
|
json: async () => await response.json()
|
|
3282
3444
|
}));
|
|
3283
3445
|
}
|
|
3284
|
-
function
|
|
3446
|
+
function isConfirmedGuestSetupResult(value) {
|
|
3285
3447
|
return Boolean(
|
|
3286
3448
|
value && typeof value === "object" && "status" in value && value.status === "configured"
|
|
3287
3449
|
);
|
|
3288
3450
|
}
|
|
3451
|
+
function defaultUcanStoreBootstrapInput(props) {
|
|
3452
|
+
return {
|
|
3453
|
+
adminDid: props.ucanStoreBootstrap?.adminDid ?? "",
|
|
3454
|
+
serviceDid: props.ucanStoreBootstrap?.serviceDid ?? "",
|
|
3455
|
+
spaceDid: props.ucanStoreBootstrap?.spaceDid ?? "",
|
|
3456
|
+
rootDelegationProof: props.ucanStoreBootstrap?.rootDelegationProof ?? "",
|
|
3457
|
+
allowedCapabilities: props.ucanStoreBootstrap?.allowedCapabilities ?? "",
|
|
3458
|
+
defaultUserDelegationExpiration: props.ucanStoreBootstrap?.defaultUserDelegationExpiration ?? "",
|
|
3459
|
+
maxUserDelegationExpiration: props.ucanStoreBootstrap?.maxUserDelegationExpiration ?? "",
|
|
3460
|
+
pwaOrigin: props.ucanStoreBootstrap?.pwaOrigin ?? "",
|
|
3461
|
+
serviceOrigin: props.ucanStoreBootstrap?.serviceOrigin ?? ""
|
|
3462
|
+
};
|
|
3463
|
+
}
|
|
3464
|
+
function currentPageOrigin() {
|
|
3465
|
+
try {
|
|
3466
|
+
const origin = globalThis.location?.origin?.trim();
|
|
3467
|
+
return origin ? origin : null;
|
|
3468
|
+
} catch {
|
|
3469
|
+
return null;
|
|
3470
|
+
}
|
|
3471
|
+
}
|
|
3472
|
+
function parseOptionalExpiration(value) {
|
|
3473
|
+
const normalized = value.trim();
|
|
3474
|
+
if (!normalized) return void 0;
|
|
3475
|
+
const parsed = Number.parseInt(normalized, 10);
|
|
3476
|
+
if (!Number.isInteger(parsed) || parsed < 0) {
|
|
3477
|
+
return null;
|
|
3478
|
+
}
|
|
3479
|
+
return parsed;
|
|
3480
|
+
}
|
|
3481
|
+
function parseAllowedCapabilities(value) {
|
|
3482
|
+
return value.split(/[\n,]/).map((entry) => entry.trim()).filter(Boolean);
|
|
3483
|
+
}
|
|
3484
|
+
function draftUcanStoreBootstrapErrors(args) {
|
|
3485
|
+
const errors = [];
|
|
3486
|
+
const { input } = args;
|
|
3487
|
+
if (!args.operatorAddress) {
|
|
3488
|
+
errors.push("Connect MetaMask before configuring the ucan-store bootstrap package.");
|
|
3489
|
+
}
|
|
3490
|
+
if (!input.adminDid.trim().startsWith("did:")) {
|
|
3491
|
+
errors.push("Admin DID must be a non-empty DID string.");
|
|
3492
|
+
}
|
|
3493
|
+
if (input.serviceDid.trim() && !input.serviceDid.trim().startsWith("did:")) {
|
|
3494
|
+
errors.push("Service DID must be empty or a non-empty DID string.");
|
|
3495
|
+
}
|
|
3496
|
+
if (!input.spaceDid.trim().startsWith("did:")) {
|
|
3497
|
+
errors.push("Space DID must be a non-empty DID string.");
|
|
3498
|
+
}
|
|
3499
|
+
if (!input.rootDelegationProof.trim()) {
|
|
3500
|
+
errors.push("Root delegation proof is required.");
|
|
3501
|
+
}
|
|
3502
|
+
if (parseAllowedCapabilities(input.allowedCapabilities).length === 0) {
|
|
3503
|
+
errors.push("Add at least one allowed capability.");
|
|
3504
|
+
}
|
|
3505
|
+
const defaultExpiration = parseOptionalExpiration(
|
|
3506
|
+
input.defaultUserDelegationExpiration
|
|
3507
|
+
);
|
|
3508
|
+
if (defaultExpiration === null) {
|
|
3509
|
+
errors.push(
|
|
3510
|
+
"Default user delegation expiration must be a non-negative integer number of seconds."
|
|
3511
|
+
);
|
|
3512
|
+
}
|
|
3513
|
+
const maxExpiration = parseOptionalExpiration(
|
|
3514
|
+
input.maxUserDelegationExpiration
|
|
3515
|
+
);
|
|
3516
|
+
if (maxExpiration === null) {
|
|
3517
|
+
errors.push(
|
|
3518
|
+
"Max user delegation expiration must be a non-negative integer number of seconds."
|
|
3519
|
+
);
|
|
3520
|
+
}
|
|
3521
|
+
if (typeof defaultExpiration === "number" && typeof maxExpiration === "number" && defaultExpiration > maxExpiration) {
|
|
3522
|
+
errors.push(
|
|
3523
|
+
"Default user delegation expiration cannot exceed the max user delegation expiration."
|
|
3524
|
+
);
|
|
3525
|
+
}
|
|
3526
|
+
const pwaOrigin = input.pwaOrigin.trim() || currentPageOrigin() || "";
|
|
3527
|
+
if (!pwaOrigin) {
|
|
3528
|
+
errors.push("PWA origin is required for the ucan-store bootstrap package.");
|
|
3529
|
+
}
|
|
3530
|
+
return errors;
|
|
3531
|
+
}
|
|
3532
|
+
function buildUcanStoreBootstrapPackage(args) {
|
|
3533
|
+
const candidate = {
|
|
3534
|
+
operatorAddress: args.operatorAddress,
|
|
3535
|
+
adminDid: args.input.adminDid.trim(),
|
|
3536
|
+
serviceDid: args.input.serviceDid.trim() || null,
|
|
3537
|
+
spaceDid: args.input.spaceDid.trim(),
|
|
3538
|
+
rootDelegationProof: args.input.rootDelegationProof.trim(),
|
|
3539
|
+
allowedCapabilities: parseAllowedCapabilities(args.input.allowedCapabilities),
|
|
3540
|
+
defaultUserDelegationExpiration: parseOptionalExpiration(
|
|
3541
|
+
args.input.defaultUserDelegationExpiration
|
|
3542
|
+
),
|
|
3543
|
+
maxUserDelegationExpiration: parseOptionalExpiration(
|
|
3544
|
+
args.input.maxUserDelegationExpiration
|
|
3545
|
+
),
|
|
3546
|
+
pwaOrigin: args.input.pwaOrigin.trim() || args.pwaOriginFallback?.trim() || currentPageOrigin() || "",
|
|
3547
|
+
serviceOrigin: args.input.serviceOrigin.trim() || args.serviceOriginFallback?.trim() || ""
|
|
3548
|
+
};
|
|
3549
|
+
if (candidate.defaultUserDelegationExpiration === void 0) {
|
|
3550
|
+
delete candidate.defaultUserDelegationExpiration;
|
|
3551
|
+
}
|
|
3552
|
+
if (candidate.maxUserDelegationExpiration === void 0) {
|
|
3553
|
+
delete candidate.maxUserDelegationExpiration;
|
|
3554
|
+
}
|
|
3555
|
+
if (candidate.serviceDid === null) {
|
|
3556
|
+
delete candidate.serviceDid;
|
|
3557
|
+
}
|
|
3558
|
+
return validateUcanStoreBootstrapPackage(
|
|
3559
|
+
candidate
|
|
3560
|
+
);
|
|
3561
|
+
}
|
|
3289
3562
|
function defaultState(props = {}) {
|
|
3290
3563
|
return {
|
|
3291
3564
|
ready: false,
|
|
@@ -3300,6 +3573,7 @@ function defaultState(props = {}) {
|
|
|
3300
3573
|
manifestJson: props.manifestJson ?? "",
|
|
3301
3574
|
sshPublicKey: props.sshPublicKey ?? "",
|
|
3302
3575
|
instanceName: props.instanceName ?? DEFAULT_INSTANCE_NAME,
|
|
3576
|
+
ucanStoreBootstrap: defaultUcanStoreBootstrapInput(props),
|
|
3303
3577
|
tierId: DEFAULT_TIER_ID,
|
|
3304
3578
|
showAdvanced: Boolean(props.manifestJson?.trim() || props.sshPublicKey?.trim()),
|
|
3305
3579
|
showInstances: props.showInstances ?? true,
|
|
@@ -3434,13 +3708,33 @@ async function resolveManifest(args) {
|
|
|
3434
3708
|
if (pasted) return pasted;
|
|
3435
3709
|
return loadRootfsManifest(args.manifestUrl);
|
|
3436
3710
|
}
|
|
3437
|
-
function
|
|
3711
|
+
function deploymentProfileForManifest(manifest) {
|
|
3438
3712
|
if (manifest?.profile === "uc-go-peer") return "uc-go-peer";
|
|
3439
3713
|
if (manifest?.profile === "orbitdb-relay") {
|
|
3440
3714
|
return manifest.profile;
|
|
3441
3715
|
}
|
|
3716
|
+
if (manifest?.profile === "ucan-store") return "ucan-store";
|
|
3442
3717
|
return null;
|
|
3443
3718
|
}
|
|
3719
|
+
function bootstrapRelayProfileForManifest(manifest) {
|
|
3720
|
+
const profile = deploymentProfileForManifest(manifest);
|
|
3721
|
+
if (profile === "uc-go-peer" || profile === "orbitdb-relay") {
|
|
3722
|
+
return profile;
|
|
3723
|
+
}
|
|
3724
|
+
return null;
|
|
3725
|
+
}
|
|
3726
|
+
function supportsBootstrapRegistrationsForManifest(manifest) {
|
|
3727
|
+
return bootstrapRelayProfileForManifest(manifest) != null;
|
|
3728
|
+
}
|
|
3729
|
+
function deploymentReadyLabel(profile) {
|
|
3730
|
+
return profile === "ucan-store" ? "Service ready" : "Relay ready";
|
|
3731
|
+
}
|
|
3732
|
+
function deploymentReadyDetail(profile, fallback) {
|
|
3733
|
+
if (profile === "ucan-store") {
|
|
3734
|
+
return "The upload service runtime is available and the deployment finished successfully.";
|
|
3735
|
+
}
|
|
3736
|
+
return fallback;
|
|
3737
|
+
}
|
|
3444
3738
|
function registrationIdInstanceItemHash(registrationId) {
|
|
3445
3739
|
const normalized = String(registrationId ?? "").trim();
|
|
3446
3740
|
if (!normalized) return null;
|
|
@@ -3689,19 +3983,148 @@ var SponsorRelayController = class {
|
|
|
3689
3983
|
this.progressEmitter.emit(nextEvent);
|
|
3690
3984
|
}
|
|
3691
3985
|
async configureRelayBootstrapRegistration(args) {
|
|
3692
|
-
const
|
|
3693
|
-
|
|
3694
|
-
if (!
|
|
3986
|
+
const deploymentProfile = deploymentProfileForManifest(this.state.manifest);
|
|
3987
|
+
const profile = bootstrapRelayProfileForManifest(this.state.manifest);
|
|
3988
|
+
if (!profile && deploymentProfile !== "ucan-store") return;
|
|
3989
|
+
if (profile && !this.state.wallet.address) {
|
|
3695
3990
|
throw new Error("A connected wallet is required to register relay bootstrap addresses.");
|
|
3696
3991
|
}
|
|
3697
|
-
|
|
3698
|
-
|
|
3992
|
+
const runtimeHostIpv4 = args.runtime.hostIpv4;
|
|
3993
|
+
if (!runtimeHostIpv4) {
|
|
3994
|
+
throw new Error(
|
|
3995
|
+
`${deploymentProfile === "ucan-store" ? "Service" : "Relay"} runtime did not expose a host IPv4 address.`
|
|
3996
|
+
);
|
|
3699
3997
|
}
|
|
3700
3998
|
let runtime = args.runtime;
|
|
3701
3999
|
let mappedPorts2 = runtime.mappedPorts ?? {};
|
|
3702
4000
|
const setupPort = mappedPorts2["80"]?.host ?? null;
|
|
3703
4001
|
if (!setupPort) {
|
|
3704
|
-
throw new Error(
|
|
4002
|
+
throw new Error(
|
|
4003
|
+
`${deploymentProfile === "ucan-store" ? "Service" : "Relay"} runtime did not expose the temporary setup endpoint.`
|
|
4004
|
+
);
|
|
4005
|
+
}
|
|
4006
|
+
if (deploymentProfile === "ucan-store") {
|
|
4007
|
+
const serviceHostIpv4 = runtimeHostIpv4;
|
|
4008
|
+
const serviceProxyUrl = runtime.proxyUrl;
|
|
4009
|
+
if (!serviceProxyUrl) {
|
|
4010
|
+
throw new Error("Service runtime did not expose a proxy URL.");
|
|
4011
|
+
}
|
|
4012
|
+
const walletAddress2 = this.state.wallet.address;
|
|
4013
|
+
if (!walletAddress2) {
|
|
4014
|
+
throw new Error("A connected wallet is required to configure the ucan-store bootstrap package.");
|
|
4015
|
+
}
|
|
4016
|
+
const bootstrapValidation = buildUcanStoreBootstrapPackage({
|
|
4017
|
+
input: this.state.ucanStoreBootstrap,
|
|
4018
|
+
operatorAddress: walletAddress2,
|
|
4019
|
+
serviceOriginFallback: serviceProxyUrl,
|
|
4020
|
+
pwaOriginFallback: currentPageOrigin()
|
|
4021
|
+
});
|
|
4022
|
+
if (!bootstrapValidation.valid || !bootstrapValidation.bootstrapPackage) {
|
|
4023
|
+
throw new Error(
|
|
4024
|
+
bootstrapValidation.errors[0] ?? "The ucan-store bootstrap package is invalid."
|
|
4025
|
+
);
|
|
4026
|
+
}
|
|
4027
|
+
this.emitProgress({
|
|
4028
|
+
stage: "deployment-confirmed",
|
|
4029
|
+
label: "Configuring service",
|
|
4030
|
+
progress: 93,
|
|
4031
|
+
status: "info",
|
|
4032
|
+
itemHash: args.itemHash,
|
|
4033
|
+
detail: "Waiting for the guest setup endpoint before applying the upload service configuration."
|
|
4034
|
+
});
|
|
4035
|
+
const setupHealth = await waitForSetupEndpoint({
|
|
4036
|
+
hostIpv4: serviceHostIpv4,
|
|
4037
|
+
setupPort,
|
|
4038
|
+
fetch: (url, init) => fetch(url, init),
|
|
4039
|
+
attempts: 15,
|
|
4040
|
+
delayMs: 4e3,
|
|
4041
|
+
httpTimeoutMs: 1e4,
|
|
4042
|
+
onAttempt: (result, attempt, attempts) => {
|
|
4043
|
+
this.emitProgress({
|
|
4044
|
+
stage: "deployment-confirmed",
|
|
4045
|
+
label: "Waiting for guest setup",
|
|
4046
|
+
progress: 93,
|
|
4047
|
+
status: result.ok ? "success" : "info",
|
|
4048
|
+
itemHash: args.itemHash,
|
|
4049
|
+
detail: result.ok ? `Setup endpoint ${attempt}/${attempts}: ready at http://${serviceHostIpv4}:${setupPort}/health.` : `Setup endpoint ${attempt}/${attempts}: waiting for http://${serviceHostIpv4}:${setupPort}/health.`
|
|
4050
|
+
});
|
|
4051
|
+
}
|
|
4052
|
+
});
|
|
4053
|
+
if (!setupHealth.ok) {
|
|
4054
|
+
throw new Error(
|
|
4055
|
+
`Service setup endpoint did not become reachable at http://${serviceHostIpv4}:${setupPort}/health.`
|
|
4056
|
+
);
|
|
4057
|
+
}
|
|
4058
|
+
this.emitProgress({
|
|
4059
|
+
stage: "deployment-confirmed",
|
|
4060
|
+
label: "Applying service config",
|
|
4061
|
+
progress: 94,
|
|
4062
|
+
status: "info",
|
|
4063
|
+
itemHash: args.itemHash,
|
|
4064
|
+
detail: "Publishing the public HTTPS origin into the guest upload service configuration."
|
|
4065
|
+
});
|
|
4066
|
+
const configureResult = await configureUcanStore({
|
|
4067
|
+
hostIpv4: serviceHostIpv4,
|
|
4068
|
+
publicIpv6: runtime.ipv6,
|
|
4069
|
+
setupPort,
|
|
4070
|
+
proxyUrl: serviceProxyUrl,
|
|
4071
|
+
webauthnOrigin: serviceProxyUrl,
|
|
4072
|
+
adminDid: bootstrapValidation.bootstrapPackage.adminDid,
|
|
4073
|
+
bootstrapPackage: bootstrapValidation.bootstrapPackage,
|
|
4074
|
+
fetch: (url, init) => fetch(url, init),
|
|
4075
|
+
timeoutMs: 18e4
|
|
4076
|
+
});
|
|
4077
|
+
if (!isConfirmedGuestSetupResult(configureResult)) {
|
|
4078
|
+
throw new Error(
|
|
4079
|
+
`Service guest configuration could not be confirmed at http://${serviceHostIpv4}:${setupPort}/configure.`
|
|
4080
|
+
);
|
|
4081
|
+
}
|
|
4082
|
+
this.emitProgress({
|
|
4083
|
+
stage: "deployment-confirmed",
|
|
4084
|
+
label: "Waiting for service metadata",
|
|
4085
|
+
progress: 95,
|
|
4086
|
+
status: "info",
|
|
4087
|
+
itemHash: args.itemHash,
|
|
4088
|
+
detail: "Waiting for the upload service metadata endpoint to report the public service DID and PWA environment."
|
|
4089
|
+
});
|
|
4090
|
+
const serviceMetadata = await fetchUcGoPeerMetadata({
|
|
4091
|
+
hostIpv4: serviceHostIpv4,
|
|
4092
|
+
setupPort,
|
|
4093
|
+
fetch: (url, init) => fetch(url, init),
|
|
4094
|
+
attempts: 80,
|
|
4095
|
+
delayMs: 3e3,
|
|
4096
|
+
timeoutMs: 24e4,
|
|
4097
|
+
isReady: ({ payload, ok }) => {
|
|
4098
|
+
if (!ok || !payload || typeof payload !== "object") return false;
|
|
4099
|
+
const metadata2 = payload.metadata && typeof payload.metadata === "object" ? payload.metadata : null;
|
|
4100
|
+
const pwaEnv = metadata2?.pwa_env && typeof metadata2.pwa_env === "object" ? metadata2.pwa_env : null;
|
|
4101
|
+
return Boolean(
|
|
4102
|
+
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
|
|
4103
|
+
);
|
|
4104
|
+
},
|
|
4105
|
+
onAttempt: ({ ready, attempt, attempts, requestUrl }) => {
|
|
4106
|
+
this.emitProgress({
|
|
4107
|
+
stage: "deployment-confirmed",
|
|
4108
|
+
label: ready ? "Service metadata ready" : "Waiting for service metadata",
|
|
4109
|
+
progress: 95,
|
|
4110
|
+
status: ready ? "success" : "info",
|
|
4111
|
+
itemHash: args.itemHash,
|
|
4112
|
+
detail: ready ? `Service metadata ${attempt}/${attempts}: public upload service wiring is ready.` : `Service metadata ${attempt}/${attempts}: waiting for ${requestUrl}.`
|
|
4113
|
+
});
|
|
4114
|
+
}
|
|
4115
|
+
});
|
|
4116
|
+
const metadata = serviceMetadata && typeof serviceMetadata === "object" ? serviceMetadata.metadata ?? null : null;
|
|
4117
|
+
if (!metadata || typeof metadata !== "object" || typeof metadata.upload_service_did !== "string") {
|
|
4118
|
+
throw new Error(
|
|
4119
|
+
"Service metadata did not include the public upload service DID."
|
|
4120
|
+
);
|
|
4121
|
+
}
|
|
4122
|
+
return;
|
|
4123
|
+
}
|
|
4124
|
+
if (!profile) return;
|
|
4125
|
+
const walletAddress = this.state.wallet.address;
|
|
4126
|
+
if (!walletAddress) {
|
|
4127
|
+
throw new Error("A connected wallet is required to register relay bootstrap addresses.");
|
|
3705
4128
|
}
|
|
3706
4129
|
let bootstrapSignalRelayMetadata = null;
|
|
3707
4130
|
if (profile === "orbitdb-relay") {
|
|
@@ -3714,7 +4137,7 @@ var SponsorRelayController = class {
|
|
|
3714
4137
|
detail: "Waiting for the guest setup endpoint before collecting relay metadata."
|
|
3715
4138
|
});
|
|
3716
4139
|
const setupHealth = await waitForSetupEndpoint({
|
|
3717
|
-
hostIpv4:
|
|
4140
|
+
hostIpv4: runtimeHostIpv4,
|
|
3718
4141
|
setupPort,
|
|
3719
4142
|
fetch: (url, init) => fetch(url, init),
|
|
3720
4143
|
attempts: 15,
|
|
@@ -3727,13 +4150,13 @@ var SponsorRelayController = class {
|
|
|
3727
4150
|
progress: 93,
|
|
3728
4151
|
status: result.ok ? "success" : "info",
|
|
3729
4152
|
itemHash: args.itemHash,
|
|
3730
|
-
detail: result.ok ? `Setup endpoint ${attempt}/${attempts}: ready at http://${
|
|
4153
|
+
detail: result.ok ? `Setup endpoint ${attempt}/${attempts}: ready at http://${runtimeHostIpv4}:${setupPort}/health.` : `Setup endpoint ${attempt}/${attempts}: waiting for http://${runtimeHostIpv4}:${setupPort}/health.`
|
|
3731
4154
|
});
|
|
3732
4155
|
}
|
|
3733
4156
|
});
|
|
3734
4157
|
if (!setupHealth.ok) {
|
|
3735
4158
|
throw new Error(
|
|
3736
|
-
`Relay setup endpoint did not become reachable at http://${
|
|
4159
|
+
`Relay setup endpoint did not become reachable at http://${runtimeHostIpv4}:${setupPort}/health.`
|
|
3737
4160
|
);
|
|
3738
4161
|
}
|
|
3739
4162
|
this.emitProgress({
|
|
@@ -3750,7 +4173,7 @@ var SponsorRelayController = class {
|
|
|
3750
4173
|
throw new Error("OrbitDB relay runtime is missing required mapped TCP/WS ports.");
|
|
3751
4174
|
}
|
|
3752
4175
|
const configureResult = await configureOrbitdbRelaySetup2({
|
|
3753
|
-
hostIpv4:
|
|
4176
|
+
hostIpv4: runtimeHostIpv4,
|
|
3754
4177
|
publicIpv6: args.runtime.ipv6,
|
|
3755
4178
|
setupPort,
|
|
3756
4179
|
tcpPort,
|
|
@@ -3763,7 +4186,7 @@ var SponsorRelayController = class {
|
|
|
3763
4186
|
fetch: (url, init) => fetch(url, init),
|
|
3764
4187
|
timeoutMs: 18e4
|
|
3765
4188
|
});
|
|
3766
|
-
if (!
|
|
4189
|
+
if (!isConfirmedGuestSetupResult(configureResult)) {
|
|
3767
4190
|
throw new Error(
|
|
3768
4191
|
`Relay guest configuration could not be confirmed at http://${args.runtime.hostIpv4}:${setupPort}/configure.`
|
|
3769
4192
|
);
|
|
@@ -3821,7 +4244,7 @@ var SponsorRelayController = class {
|
|
|
3821
4244
|
"Relay runtime lost its host IPv4 address while waiting for HTTPS activation."
|
|
3822
4245
|
);
|
|
3823
4246
|
}
|
|
3824
|
-
const
|
|
4247
|
+
const runtimeHostIpv42 = runtime.hostIpv4;
|
|
3825
4248
|
const activeProxyUrl = runtime.webAccess?.active === true ? runtime.proxyUrl ?? null : null;
|
|
3826
4249
|
this.emitProgress({
|
|
3827
4250
|
stage: "deployment-confirmed",
|
|
@@ -3834,13 +4257,13 @@ var SponsorRelayController = class {
|
|
|
3834
4257
|
const record = {
|
|
3835
4258
|
deploymentToken: args.deploymentToken,
|
|
3836
4259
|
profile,
|
|
3837
|
-
ownerAddress:
|
|
4260
|
+
ownerAddress: walletAddress,
|
|
3838
4261
|
instanceItemHash: args.itemHash,
|
|
3839
4262
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3840
4263
|
expiresAt: new Date(Date.now() + 30 * 6e4).toISOString(),
|
|
3841
4264
|
status: "pending",
|
|
3842
4265
|
runtime: {
|
|
3843
|
-
publicIpv4:
|
|
4266
|
+
publicIpv4: runtimeHostIpv42,
|
|
3844
4267
|
publicIpv6: runtime.ipv6 ?? null,
|
|
3845
4268
|
proxyUrl: activeProxyUrl,
|
|
3846
4269
|
mappedPorts: mappedPorts2
|
|
@@ -3854,7 +4277,7 @@ var SponsorRelayController = class {
|
|
|
3854
4277
|
}
|
|
3855
4278
|
};
|
|
3856
4279
|
const bootstrapConfigPublication = await publishVmBootstrapConfig({
|
|
3857
|
-
sender:
|
|
4280
|
+
sender: walletAddress,
|
|
3858
4281
|
record,
|
|
3859
4282
|
signer: personalSign,
|
|
3860
4283
|
hasher: sha256Hex,
|
|
@@ -3881,7 +4304,7 @@ var SponsorRelayController = class {
|
|
|
3881
4304
|
});
|
|
3882
4305
|
const bootstrapConfigSignal = await waitForVmBootstrapConfigSignal({
|
|
3883
4306
|
deploymentToken: args.deploymentToken,
|
|
3884
|
-
ownerAddress:
|
|
4307
|
+
ownerAddress: walletAddress,
|
|
3885
4308
|
instanceItemHash: args.itemHash,
|
|
3886
4309
|
fetch: asJsonFetch,
|
|
3887
4310
|
apiHost: this.client.apiHost,
|
|
@@ -4053,7 +4476,7 @@ var SponsorRelayController = class {
|
|
|
4053
4476
|
detail: "Guest bootstrap registration was delayed. Publishing the relay bootstrap record from the browser."
|
|
4054
4477
|
});
|
|
4055
4478
|
const fallbackPublication = await publishRelayBootstrapRegistration({
|
|
4056
|
-
sender:
|
|
4479
|
+
sender: walletAddress,
|
|
4057
4480
|
signer: personalSign,
|
|
4058
4481
|
hasher: sha256Hex,
|
|
4059
4482
|
fetch: asJsonFetch,
|
|
@@ -4073,7 +4496,7 @@ var SponsorRelayController = class {
|
|
|
4073
4496
|
fallbackPublication
|
|
4074
4497
|
});
|
|
4075
4498
|
const fallbackVisibleRegistration = await waitForRelayBootstrapRegistration({
|
|
4076
|
-
sender:
|
|
4499
|
+
sender: walletAddress,
|
|
4077
4500
|
registrationId,
|
|
4078
4501
|
peerId,
|
|
4079
4502
|
fetch: asJsonFetch,
|
|
@@ -4106,7 +4529,7 @@ var SponsorRelayController = class {
|
|
|
4106
4529
|
if (profile === "uc-go-peer" && args.deploymentToken) {
|
|
4107
4530
|
let cleanupAggregateItemHash = null;
|
|
4108
4531
|
await deleteVmBootstrapConfig({
|
|
4109
|
-
sender:
|
|
4532
|
+
sender: walletAddress,
|
|
4110
4533
|
deploymentToken: args.deploymentToken,
|
|
4111
4534
|
signer: personalSign,
|
|
4112
4535
|
hasher: sha256Hex,
|
|
@@ -4272,17 +4695,35 @@ var SponsorRelayController = class {
|
|
|
4272
4695
|
});
|
|
4273
4696
|
return;
|
|
4274
4697
|
}
|
|
4698
|
+
const currentProfile = deploymentProfileForManifest(this.state.manifest);
|
|
4275
4699
|
const hasConfirmedBootstrapRegistration = this.state.bootstrapRegistrations.some(
|
|
4276
4700
|
(entry) => entry.instanceItemHash === itemHash && entry.confirmed
|
|
4277
4701
|
);
|
|
4702
|
+
if (currentProfile === "ucan-store") {
|
|
4703
|
+
this.emitProgress({
|
|
4704
|
+
stage: "completed",
|
|
4705
|
+
label: deploymentReadyLabel(currentProfile),
|
|
4706
|
+
progress: 100,
|
|
4707
|
+
status: "success",
|
|
4708
|
+
itemHash,
|
|
4709
|
+
detail: deploymentReadyDetail(
|
|
4710
|
+
currentProfile,
|
|
4711
|
+
"Runtime networking is available and the deployment finished successfully."
|
|
4712
|
+
)
|
|
4713
|
+
});
|
|
4714
|
+
return;
|
|
4715
|
+
}
|
|
4278
4716
|
if (hasConfirmedBootstrapRegistration) {
|
|
4279
4717
|
this.emitProgress({
|
|
4280
4718
|
stage: "completed",
|
|
4281
|
-
label:
|
|
4719
|
+
label: deploymentReadyLabel(currentProfile),
|
|
4282
4720
|
progress: 100,
|
|
4283
4721
|
status: "success",
|
|
4284
4722
|
itemHash,
|
|
4285
|
-
detail:
|
|
4723
|
+
detail: deploymentReadyDetail(
|
|
4724
|
+
currentProfile,
|
|
4725
|
+
"Runtime networking is available and the relay bootstrap registration is confirmed on Aleph."
|
|
4726
|
+
)
|
|
4286
4727
|
});
|
|
4287
4728
|
return;
|
|
4288
4729
|
}
|
|
@@ -4292,7 +4733,7 @@ var SponsorRelayController = class {
|
|
|
4292
4733
|
progress: 92,
|
|
4293
4734
|
status: "info",
|
|
4294
4735
|
itemHash,
|
|
4295
|
-
detail:
|
|
4736
|
+
detail: `Deployment processed and runtime networking is available. Finishing ${deploymentNoun(currentProfile)} setup and verification.`
|
|
4296
4737
|
});
|
|
4297
4738
|
}
|
|
4298
4739
|
canSkipRuntimeRefresh(instance) {
|
|
@@ -4405,6 +4846,15 @@ var SponsorRelayController = class {
|
|
|
4405
4846
|
setInstanceName(instanceName) {
|
|
4406
4847
|
this.patch({ instanceName });
|
|
4407
4848
|
}
|
|
4849
|
+
setUcanStoreBootstrapField(field, value) {
|
|
4850
|
+
this.patch({
|
|
4851
|
+
ucanStoreBootstrap: {
|
|
4852
|
+
...this.state.ucanStoreBootstrap,
|
|
4853
|
+
[field]: value
|
|
4854
|
+
},
|
|
4855
|
+
showAdvanced: this.state.showAdvanced || Boolean(value.trim())
|
|
4856
|
+
});
|
|
4857
|
+
}
|
|
4408
4858
|
setTierId(tierId) {
|
|
4409
4859
|
this.patch({ tierId });
|
|
4410
4860
|
this.recomputePricingSummary();
|
|
@@ -4490,6 +4940,7 @@ var SponsorRelayController = class {
|
|
|
4490
4940
|
}
|
|
4491
4941
|
}
|
|
4492
4942
|
async refresh() {
|
|
4943
|
+
const currentProfile = deploymentProfileForManifest(this.state.manifest);
|
|
4493
4944
|
this.trace("refresh:start", {
|
|
4494
4945
|
wallet: this.state.wallet.address,
|
|
4495
4946
|
manifestUrl: this.state.manifestUrl,
|
|
@@ -4498,7 +4949,7 @@ var SponsorRelayController = class {
|
|
|
4498
4949
|
this.patch({
|
|
4499
4950
|
busy: { refreshing: true },
|
|
4500
4951
|
errorText: null,
|
|
4501
|
-
statusText: "Refreshing relay
|
|
4952
|
+
statusText: currentProfile === "ucan-store" ? "Refreshing service deployment data" : "Refreshing relay deployment data"
|
|
4502
4953
|
});
|
|
4503
4954
|
try {
|
|
4504
4955
|
const [pricingSummary, crns] = await Promise.all([
|
|
@@ -4510,6 +4961,8 @@ var SponsorRelayController = class {
|
|
|
4510
4961
|
manifestJson: this.state.manifestJson
|
|
4511
4962
|
}).catch((error) => manifestLoadErrorState(error));
|
|
4512
4963
|
const manifest = manifestState.manifest;
|
|
4964
|
+
const resolvedProfile = deploymentProfileForManifest(manifest);
|
|
4965
|
+
const bootstrapEnabled = supportsBootstrapRegistrationsForManifest(manifest);
|
|
4513
4966
|
let balance = this.state.balance;
|
|
4514
4967
|
let instances = [];
|
|
4515
4968
|
let bootstrapRegistrations = [];
|
|
@@ -4518,10 +4971,10 @@ var SponsorRelayController = class {
|
|
|
4518
4971
|
const [nextBalance, rawInstances, rawBootstrapPosts] = await Promise.all([
|
|
4519
4972
|
this.client.fetchBalance(this.state.wallet.address),
|
|
4520
4973
|
this.state.showInstances ? this.client.fetchInstances(this.state.wallet.address) : Promise.resolve([]),
|
|
4521
|
-
fetchAlephBootstrapPosts({
|
|
4974
|
+
bootstrapEnabled ? fetchAlephBootstrapPosts({
|
|
4522
4975
|
apiHost: this.client.apiHost,
|
|
4523
4976
|
fetch
|
|
4524
|
-
}).catch(() => [])
|
|
4977
|
+
}).catch(() => []) : Promise.resolve([])
|
|
4525
4978
|
]);
|
|
4526
4979
|
balance = nextBalance;
|
|
4527
4980
|
instances = await Promise.all(
|
|
@@ -4651,7 +5104,7 @@ var SponsorRelayController = class {
|
|
|
4651
5104
|
bootstrapRegistrations,
|
|
4652
5105
|
orphanBootstrapRegistrations,
|
|
4653
5106
|
busy: { refreshing: false },
|
|
4654
|
-
statusText: "Relay
|
|
5107
|
+
statusText: resolvedProfile === "ucan-store" ? "Service deployment data ready" : "Relay deployment data ready"
|
|
4655
5108
|
});
|
|
4656
5109
|
this.trace("refresh:success", {
|
|
4657
5110
|
manifestValid: manifestState.valid,
|
|
@@ -4688,6 +5141,16 @@ var SponsorRelayController = class {
|
|
|
4688
5141
|
});
|
|
4689
5142
|
return;
|
|
4690
5143
|
}
|
|
5144
|
+
if (deploymentProfileForManifest(this.state.manifest) === "ucan-store") {
|
|
5145
|
+
const draftErrors = draftUcanStoreBootstrapErrors({
|
|
5146
|
+
input: this.state.ucanStoreBootstrap,
|
|
5147
|
+
operatorAddress: this.state.wallet.address
|
|
5148
|
+
});
|
|
5149
|
+
if (draftErrors.length > 0) {
|
|
5150
|
+
this.patch({ errorText: draftErrors[0] });
|
|
5151
|
+
return;
|
|
5152
|
+
}
|
|
5153
|
+
}
|
|
4691
5154
|
this.patch({
|
|
4692
5155
|
busy: { deploying: true },
|
|
4693
5156
|
errorText: null,
|
|
@@ -4737,7 +5200,7 @@ var SponsorRelayController = class {
|
|
|
4737
5200
|
detail: `Trying ${crnDisplayName}`
|
|
4738
5201
|
});
|
|
4739
5202
|
try {
|
|
4740
|
-
const profile =
|
|
5203
|
+
const profile = deploymentProfileForManifest(this.state.manifest);
|
|
4741
5204
|
attemptProfile = profile;
|
|
4742
5205
|
const sshPublicKey = profile === "uc-go-peer" ? appendDeploymentTokenToSshPublicKey(
|
|
4743
5206
|
this.state.sshPublicKey.trim(),
|
|
@@ -4956,11 +5419,14 @@ var SponsorRelayController = class {
|
|
|
4956
5419
|
this.lastCompletedDeploymentHash = result.itemHash;
|
|
4957
5420
|
this.emitProgress({
|
|
4958
5421
|
stage: "completed",
|
|
4959
|
-
label:
|
|
5422
|
+
label: deploymentReadyLabel(attemptProfile),
|
|
4960
5423
|
progress: 100,
|
|
4961
5424
|
status: "success",
|
|
4962
5425
|
itemHash: result.itemHash,
|
|
4963
|
-
detail:
|
|
5426
|
+
detail: deploymentReadyDetail(
|
|
5427
|
+
attemptProfile,
|
|
5428
|
+
"Relay runtime, setup, metadata, and bootstrap registration are confirmed."
|
|
5429
|
+
)
|
|
4964
5430
|
});
|
|
4965
5431
|
return;
|
|
4966
5432
|
} catch (error) {
|
|
@@ -5034,11 +5500,14 @@ var SponsorRelayController = class {
|
|
|
5034
5500
|
this.lastCompletedDeploymentHash = attemptItemHash;
|
|
5035
5501
|
this.emitProgress({
|
|
5036
5502
|
stage: "completed",
|
|
5037
|
-
label:
|
|
5503
|
+
label: deploymentReadyLabel(attemptProfile),
|
|
5038
5504
|
progress: 100,
|
|
5039
5505
|
status: "success",
|
|
5040
5506
|
itemHash: attemptItemHash,
|
|
5041
|
-
detail:
|
|
5507
|
+
detail: deploymentReadyDetail(
|
|
5508
|
+
attemptProfile,
|
|
5509
|
+
"The relay completed startup after a transient UI polling error. Runtime and bootstrap registration are confirmed."
|
|
5510
|
+
)
|
|
5042
5511
|
});
|
|
5043
5512
|
return;
|
|
5044
5513
|
}
|
|
@@ -5065,11 +5534,14 @@ var SponsorRelayController = class {
|
|
|
5065
5534
|
this.lastCompletedDeploymentHash = attemptItemHash;
|
|
5066
5535
|
this.emitProgress({
|
|
5067
5536
|
stage: "completed",
|
|
5068
|
-
label:
|
|
5537
|
+
label: deploymentReadyLabel(attemptProfile),
|
|
5069
5538
|
progress: 100,
|
|
5070
5539
|
status: "success",
|
|
5071
5540
|
itemHash: attemptItemHash,
|
|
5072
|
-
detail:
|
|
5541
|
+
detail: deploymentReadyDetail(
|
|
5542
|
+
attemptProfile,
|
|
5543
|
+
"The relay completed startup after a transient browser-side polling error. Runtime and bootstrap registration are confirmed."
|
|
5544
|
+
)
|
|
5073
5545
|
});
|
|
5074
5546
|
return;
|
|
5075
5547
|
}
|
|
@@ -5384,7 +5856,8 @@ function useSponsorRelayController(props) {
|
|
|
5384
5856
|
props.schedulerApiHost,
|
|
5385
5857
|
props.showInstances,
|
|
5386
5858
|
props.sshPublicKey,
|
|
5387
|
-
props.twoN6ApiHost
|
|
5859
|
+
props.twoN6ApiHost,
|
|
5860
|
+
props.ucanStoreBootstrap
|
|
5388
5861
|
]
|
|
5389
5862
|
);
|
|
5390
5863
|
useEffect(() => {
|
|
@@ -5518,6 +5991,27 @@ var POLLING_STAGES = /* @__PURE__ */ new Set([
|
|
|
5518
5991
|
"publishing-bootstrap",
|
|
5519
5992
|
"refreshing-instances"
|
|
5520
5993
|
]);
|
|
5994
|
+
function stateDeploymentProfile(state) {
|
|
5995
|
+
return state.manifest?.profile === "ucan-store" ? "ucan-store" : "relay";
|
|
5996
|
+
}
|
|
5997
|
+
function supportsBootstrapUi(state) {
|
|
5998
|
+
return stateDeploymentProfile(state) !== "ucan-store";
|
|
5999
|
+
}
|
|
6000
|
+
function deploymentPanelTitle(state) {
|
|
6001
|
+
return stateDeploymentProfile(state) === "ucan-store" ? "Sponsor Service" : "Sponsor Relay";
|
|
6002
|
+
}
|
|
6003
|
+
function deploymentLauncherLabel(state, compactInlineLabel, launcherMode) {
|
|
6004
|
+
if (launcherMode === "inline" && compactInlineLabel) {
|
|
6005
|
+
return stateDeploymentProfile(state) === "ucan-store" ? "Service" : "Relay";
|
|
6006
|
+
}
|
|
6007
|
+
return deploymentPanelTitle(state);
|
|
6008
|
+
}
|
|
6009
|
+
function deploymentInstanceFallbackLabel(state) {
|
|
6010
|
+
return stateDeploymentProfile(state) === "ucan-store" ? "service" : "relay";
|
|
6011
|
+
}
|
|
6012
|
+
function deploymentButtonLabel(state) {
|
|
6013
|
+
return stateDeploymentProfile(state) === "ucan-store" ? "Deploy Service" : "Deploy Relay";
|
|
6014
|
+
}
|
|
5521
6015
|
function isDeploymentProgressVisible(state) {
|
|
5522
6016
|
const stage = state.deploymentProgress.stage;
|
|
5523
6017
|
if (stage === "idle") {
|
|
@@ -5533,17 +6027,19 @@ function isDeploymentProgressVisible(state) {
|
|
|
5533
6027
|
}
|
|
5534
6028
|
function pollingIndicator(state) {
|
|
5535
6029
|
if (state.busy.refreshing) {
|
|
6030
|
+
const isService2 = stateDeploymentProfile(state) === "ucan-store";
|
|
5536
6031
|
return {
|
|
5537
|
-
label: "Checking relay state",
|
|
5538
|
-
detail: state.statusText || "Refreshing relay
|
|
6032
|
+
label: isService2 ? "Checking deployment state" : "Checking relay state",
|
|
6033
|
+
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
6034
|
};
|
|
5540
6035
|
}
|
|
5541
6036
|
if (!POLLING_STAGES.has(state.deploymentProgress.stage)) {
|
|
5542
6037
|
return null;
|
|
5543
6038
|
}
|
|
6039
|
+
const isService = stateDeploymentProfile(state) === "ucan-store";
|
|
5544
6040
|
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."
|
|
6041
|
+
label: state.deploymentProgress.label || (isService ? "Polling deployment state" : "Polling relay state"),
|
|
6042
|
+
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
6043
|
};
|
|
5548
6044
|
}
|
|
5549
6045
|
function launcherIndicator(state) {
|
|
@@ -5592,7 +6088,7 @@ function launcherIndicator(state) {
|
|
|
5592
6088
|
if (state.busy.refreshing) {
|
|
5593
6089
|
return {
|
|
5594
6090
|
label: "SYNC",
|
|
5595
|
-
detail: "Refreshing relay state",
|
|
6091
|
+
detail: stateDeploymentProfile(state) === "ucan-store" ? "Refreshing deployment state" : "Refreshing relay state",
|
|
5596
6092
|
tone: "info"
|
|
5597
6093
|
};
|
|
5598
6094
|
}
|
|
@@ -5609,6 +6105,7 @@ function SponsorRelayFab(props) {
|
|
|
5609
6105
|
const versionLabel = resolvedVersion.startsWith("v") ? resolvedVersion : `v${resolvedVersion}`;
|
|
5610
6106
|
const launcherMode = props.launcherMode ?? "floating";
|
|
5611
6107
|
const indicator = launcherIndicator(state);
|
|
6108
|
+
const bootstrapUiEnabled = supportsBootstrapUi(state);
|
|
5612
6109
|
const confirmedRegistrationByInstanceHash = new Map(
|
|
5613
6110
|
(state.bootstrapRegistrations ?? []).filter((entry) => entry.confirmed && entry.instanceItemHash).map((entry) => [entry.instanceItemHash, entry])
|
|
5614
6111
|
);
|
|
@@ -5710,7 +6207,8 @@ function SponsorRelayFab(props) {
|
|
|
5710
6207
|
bottom: "11.5rem",
|
|
5711
6208
|
maxHeight: "calc(100vh - 12.5rem)"
|
|
5712
6209
|
};
|
|
5713
|
-
const launcherLabel =
|
|
6210
|
+
const launcherLabel = deploymentLauncherLabel(state, compactInlineLabel, launcherMode);
|
|
6211
|
+
const deployCallToAction = state.wallet.connected ? state.busy.deploying ? "Deploying\u2026" : deploymentButtonLabel(state) : "Connect MetaMask";
|
|
5714
6212
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5715
6213
|
/* @__PURE__ */ jsx("style", { children: `@keyframes leSpaceRelayPulse { 0%, 100% { transform: scale(1); opacity: 0.74; } 50% { transform: scale(1.22); opacity: 1; } }` }),
|
|
5716
6214
|
/* @__PURE__ */ jsxs(
|
|
@@ -5723,7 +6221,7 @@ function SponsorRelayFab(props) {
|
|
|
5723
6221
|
onMouseLeave: () => setHovered(false),
|
|
5724
6222
|
onFocus: () => setHovered(true),
|
|
5725
6223
|
onBlur: () => setHovered(false),
|
|
5726
|
-
title: indicator.detail ??
|
|
6224
|
+
title: indicator.detail ?? deploymentPanelTitle(state),
|
|
5727
6225
|
style: {
|
|
5728
6226
|
position: launcherMode === "floating" ? "fixed" : "relative",
|
|
5729
6227
|
right: launcherMode === "floating" ? "1.4rem" : void 0,
|
|
@@ -5880,7 +6378,7 @@ function SponsorRelayFab(props) {
|
|
|
5880
6378
|
margin: "0.2rem 0 0",
|
|
5881
6379
|
fontFamily: '"Epilogue", sans-serif'
|
|
5882
6380
|
},
|
|
5883
|
-
children:
|
|
6381
|
+
children: deploymentPanelTitle(state)
|
|
5884
6382
|
}
|
|
5885
6383
|
)
|
|
5886
6384
|
] }),
|
|
@@ -6217,7 +6715,156 @@ function SponsorRelayFab(props) {
|
|
|
6217
6715
|
)
|
|
6218
6716
|
]
|
|
6219
6717
|
}
|
|
6220
|
-
)
|
|
6718
|
+
),
|
|
6719
|
+
stateDeploymentProfile(state) === "ucan-store" ? /* @__PURE__ */ jsxs("details", { open: true, children: [
|
|
6720
|
+
/* @__PURE__ */ jsx("summary", { children: "UCAN Store Bootstrap" }),
|
|
6721
|
+
/* @__PURE__ */ jsxs(
|
|
6722
|
+
"div",
|
|
6723
|
+
{
|
|
6724
|
+
style: {
|
|
6725
|
+
display: "grid",
|
|
6726
|
+
gap: "0.75rem",
|
|
6727
|
+
marginTop: "0.65rem"
|
|
6728
|
+
},
|
|
6729
|
+
children: [
|
|
6730
|
+
/* @__PURE__ */ jsx(
|
|
6731
|
+
"input",
|
|
6732
|
+
{
|
|
6733
|
+
style: fieldStyle,
|
|
6734
|
+
value: state.ucanStoreBootstrap.adminDid,
|
|
6735
|
+
onChange: (event) => controller.setUcanStoreBootstrapField(
|
|
6736
|
+
"adminDid",
|
|
6737
|
+
event.currentTarget.value
|
|
6738
|
+
),
|
|
6739
|
+
placeholder: "Admin DID"
|
|
6740
|
+
}
|
|
6741
|
+
),
|
|
6742
|
+
/* @__PURE__ */ jsx(
|
|
6743
|
+
"input",
|
|
6744
|
+
{
|
|
6745
|
+
style: fieldStyle,
|
|
6746
|
+
value: state.ucanStoreBootstrap.serviceDid,
|
|
6747
|
+
onChange: (event) => controller.setUcanStoreBootstrapField(
|
|
6748
|
+
"serviceDid",
|
|
6749
|
+
event.currentTarget.value
|
|
6750
|
+
),
|
|
6751
|
+
placeholder: "Service DID override (optional)"
|
|
6752
|
+
}
|
|
6753
|
+
),
|
|
6754
|
+
/* @__PURE__ */ jsx(
|
|
6755
|
+
"input",
|
|
6756
|
+
{
|
|
6757
|
+
style: fieldStyle,
|
|
6758
|
+
value: state.ucanStoreBootstrap.spaceDid,
|
|
6759
|
+
onChange: (event) => controller.setUcanStoreBootstrapField(
|
|
6760
|
+
"spaceDid",
|
|
6761
|
+
event.currentTarget.value
|
|
6762
|
+
),
|
|
6763
|
+
placeholder: "Space DID"
|
|
6764
|
+
}
|
|
6765
|
+
),
|
|
6766
|
+
/* @__PURE__ */ jsx(
|
|
6767
|
+
"textarea",
|
|
6768
|
+
{
|
|
6769
|
+
style: fieldStyle,
|
|
6770
|
+
rows: 5,
|
|
6771
|
+
value: state.ucanStoreBootstrap.rootDelegationProof,
|
|
6772
|
+
onChange: (event) => controller.setUcanStoreBootstrapField(
|
|
6773
|
+
"rootDelegationProof",
|
|
6774
|
+
event.currentTarget.value
|
|
6775
|
+
),
|
|
6776
|
+
placeholder: "Root delegation proof"
|
|
6777
|
+
}
|
|
6778
|
+
),
|
|
6779
|
+
/* @__PURE__ */ jsx(
|
|
6780
|
+
"textarea",
|
|
6781
|
+
{
|
|
6782
|
+
style: fieldStyle,
|
|
6783
|
+
rows: 4,
|
|
6784
|
+
value: state.ucanStoreBootstrap.allowedCapabilities,
|
|
6785
|
+
onChange: (event) => controller.setUcanStoreBootstrapField(
|
|
6786
|
+
"allowedCapabilities",
|
|
6787
|
+
event.currentTarget.value
|
|
6788
|
+
),
|
|
6789
|
+
placeholder: "Allowed capabilities, one per line or comma-separated\nspace/blob/add\nspace/blob/list"
|
|
6790
|
+
}
|
|
6791
|
+
),
|
|
6792
|
+
/* @__PURE__ */ jsxs(
|
|
6793
|
+
"div",
|
|
6794
|
+
{
|
|
6795
|
+
style: {
|
|
6796
|
+
display: "grid",
|
|
6797
|
+
gap: "0.75rem",
|
|
6798
|
+
gridTemplateColumns: "repeat(auto-fit, minmax(10rem, 1fr))"
|
|
6799
|
+
},
|
|
6800
|
+
children: [
|
|
6801
|
+
/* @__PURE__ */ jsx(
|
|
6802
|
+
"input",
|
|
6803
|
+
{
|
|
6804
|
+
style: fieldStyle,
|
|
6805
|
+
value: state.ucanStoreBootstrap.defaultUserDelegationExpiration,
|
|
6806
|
+
onChange: (event) => controller.setUcanStoreBootstrapField(
|
|
6807
|
+
"defaultUserDelegationExpiration",
|
|
6808
|
+
event.currentTarget.value
|
|
6809
|
+
),
|
|
6810
|
+
placeholder: "Default expiration (seconds)"
|
|
6811
|
+
}
|
|
6812
|
+
),
|
|
6813
|
+
/* @__PURE__ */ jsx(
|
|
6814
|
+
"input",
|
|
6815
|
+
{
|
|
6816
|
+
style: fieldStyle,
|
|
6817
|
+
value: state.ucanStoreBootstrap.maxUserDelegationExpiration,
|
|
6818
|
+
onChange: (event) => controller.setUcanStoreBootstrapField(
|
|
6819
|
+
"maxUserDelegationExpiration",
|
|
6820
|
+
event.currentTarget.value
|
|
6821
|
+
),
|
|
6822
|
+
placeholder: "Max expiration (seconds)"
|
|
6823
|
+
}
|
|
6824
|
+
)
|
|
6825
|
+
]
|
|
6826
|
+
}
|
|
6827
|
+
),
|
|
6828
|
+
/* @__PURE__ */ jsx(
|
|
6829
|
+
"input",
|
|
6830
|
+
{
|
|
6831
|
+
style: fieldStyle,
|
|
6832
|
+
value: state.ucanStoreBootstrap.pwaOrigin,
|
|
6833
|
+
onChange: (event) => controller.setUcanStoreBootstrapField(
|
|
6834
|
+
"pwaOrigin",
|
|
6835
|
+
event.currentTarget.value
|
|
6836
|
+
),
|
|
6837
|
+
placeholder: "PWA origin override (optional, defaults to current page origin)"
|
|
6838
|
+
}
|
|
6839
|
+
),
|
|
6840
|
+
/* @__PURE__ */ jsx(
|
|
6841
|
+
"input",
|
|
6842
|
+
{
|
|
6843
|
+
style: fieldStyle,
|
|
6844
|
+
value: state.ucanStoreBootstrap.serviceOrigin,
|
|
6845
|
+
onChange: (event) => controller.setUcanStoreBootstrapField(
|
|
6846
|
+
"serviceOrigin",
|
|
6847
|
+
event.currentTarget.value
|
|
6848
|
+
),
|
|
6849
|
+
placeholder: "Service origin override (optional, defaults to runtime proxy URL)"
|
|
6850
|
+
}
|
|
6851
|
+
),
|
|
6852
|
+
/* @__PURE__ */ jsx(
|
|
6853
|
+
"div",
|
|
6854
|
+
{
|
|
6855
|
+
style: {
|
|
6856
|
+
color: "#9fb2ca",
|
|
6857
|
+
fontSize: "0.74rem",
|
|
6858
|
+
lineHeight: 1.35,
|
|
6859
|
+
marginTop: "-0.15rem"
|
|
6860
|
+
},
|
|
6861
|
+
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."
|
|
6862
|
+
}
|
|
6863
|
+
)
|
|
6864
|
+
]
|
|
6865
|
+
}
|
|
6866
|
+
)
|
|
6867
|
+
] }) : null
|
|
6221
6868
|
]
|
|
6222
6869
|
}
|
|
6223
6870
|
)
|
|
@@ -6253,7 +6900,7 @@ function SponsorRelayFab(props) {
|
|
|
6253
6900
|
onClick: () => void (state.wallet.connected ? controller.deploy() : controller.connectWallet()),
|
|
6254
6901
|
disabled: state.wallet.connected ? state.busy.deploying || state.rootfsHealth.tone !== "ok" : state.busy.connectingWallet,
|
|
6255
6902
|
style: { ...primaryButtonStyle, width: "100%", marginTop: "1rem" },
|
|
6256
|
-
children:
|
|
6903
|
+
children: deployCallToAction
|
|
6257
6904
|
}
|
|
6258
6905
|
),
|
|
6259
6906
|
state.lastDeploymentHash ? /* @__PURE__ */ jsxs("p", { children: [
|
|
@@ -6280,8 +6927,8 @@ function SponsorRelayFab(props) {
|
|
|
6280
6927
|
flexWrap: "wrap"
|
|
6281
6928
|
},
|
|
6282
6929
|
children: [
|
|
6283
|
-
(entry.instance.content?.metadata?.name ??
|
|
6284
|
-
confirmedRegistration ? /* @__PURE__ */ jsxs(
|
|
6930
|
+
(entry.instance.content?.metadata?.name ?? deploymentInstanceFallbackLabel(state)) + " \xB7 " + shortHash(entry.instance.item_hash),
|
|
6931
|
+
bootstrapUiEnabled && confirmedRegistration ? /* @__PURE__ */ jsxs(
|
|
6285
6932
|
"span",
|
|
6286
6933
|
{
|
|
6287
6934
|
style: {
|
|
@@ -6329,7 +6976,7 @@ function SponsorRelayFab(props) {
|
|
|
6329
6976
|
"Status: ",
|
|
6330
6977
|
entry.details.messageStatus
|
|
6331
6978
|
] }),
|
|
6332
|
-
confirmedRegistration ? /* @__PURE__ */ jsxs("div", { children: [
|
|
6979
|
+
bootstrapUiEnabled && confirmedRegistration ? /* @__PURE__ */ jsxs("div", { children: [
|
|
6333
6980
|
"Bootstrap registration:",
|
|
6334
6981
|
" ",
|
|
6335
6982
|
shortHash(
|
|
@@ -6381,7 +7028,7 @@ function SponsorRelayFab(props) {
|
|
|
6381
7028
|
)
|
|
6382
7029
|
] }, entry.instance.item_hash);
|
|
6383
7030
|
}),
|
|
6384
|
-
orphanRegistrations.length > 0 ? /* @__PURE__ */ jsxs(
|
|
7031
|
+
bootstrapUiEnabled && orphanRegistrations.length > 0 ? /* @__PURE__ */ jsxs(
|
|
6385
7032
|
"div",
|
|
6386
7033
|
{
|
|
6387
7034
|
style: {
|