@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/shared/index.js
CHANGED
|
@@ -2,6 +2,21 @@
|
|
|
2
2
|
var DEFAULT_INSTANCE_NAME = "sponsor-relay";
|
|
3
3
|
var DEFAULT_MANIFEST_URL = "./rootfs-manifest.json";
|
|
4
4
|
var DEFAULT_TIER_ID = "tier-1";
|
|
5
|
+
var DEFAULT_UCAN_STORE_PWA_ORIGIN = "https://ucan.nicokrause.com";
|
|
6
|
+
var DEFAULT_UCAN_STORE_SERVICE_ORIGIN = "https://ucan-api.nicokrause.com";
|
|
7
|
+
var DEFAULT_UCAN_STORE_SERVICE_DID = "did:web:ucan-api.nicokrause.com";
|
|
8
|
+
var DEFAULT_UCAN_STORE_ALLOWED_CAPABILITIES = [
|
|
9
|
+
"space/blob/add",
|
|
10
|
+
"space/blob/list",
|
|
11
|
+
"space/index/add",
|
|
12
|
+
"space/index/list",
|
|
13
|
+
"filecoin/offer",
|
|
14
|
+
"upload/add",
|
|
15
|
+
"upload/list",
|
|
16
|
+
"store/add"
|
|
17
|
+
];
|
|
18
|
+
var DEFAULT_UCAN_STORE_USER_DELEGATION_EXPIRATION_SECONDS = "31536000";
|
|
19
|
+
var DEFAULT_UCAN_STORE_MAX_DELEGATION_EXPIRATION_SECONDS = "315360000";
|
|
5
20
|
var ROOTFS_MISSING_STATE = {
|
|
6
21
|
tone: "idle",
|
|
7
22
|
label: "manifest missing",
|
|
@@ -27,7 +42,7 @@ var RECENT_INSTANCE_RUNTIME_GRACE_MS = 10 * 60 * 1e3;
|
|
|
27
42
|
var DEPLOYMENT_PENDING_WARNING_MS = 3 * 60 * 1e3;
|
|
28
43
|
|
|
29
44
|
// src/shared/package-version.ts
|
|
30
|
-
var UI_PACKAGE_VERSION = "0.6.
|
|
45
|
+
var UI_PACKAGE_VERSION = "0.6.3";
|
|
31
46
|
|
|
32
47
|
// src/shared/format.ts
|
|
33
48
|
function shortHash(value, head = 8, tail = 6) {
|
|
@@ -870,7 +885,7 @@ async function fetchInstancePricing(apiHost = DEFAULT_ALEPH_API_HOST, aggregateA
|
|
|
870
885
|
}
|
|
871
886
|
|
|
872
887
|
// ../core/src/constants.ts
|
|
873
|
-
var DEFAULT_ALEPH_CHANNEL = "
|
|
888
|
+
var DEFAULT_ALEPH_CHANNEL = "ALEPH-CLOUDSOLUTIONS";
|
|
874
889
|
|
|
875
890
|
// ../core/src/manifests.ts
|
|
876
891
|
var DEFAULT_ALEPH_API_HOST2 = "https://api.aleph.im";
|
|
@@ -1152,6 +1167,13 @@ function normalizeExecution2(item, crnUrl) {
|
|
|
1152
1167
|
}
|
|
1153
1168
|
|
|
1154
1169
|
// ../core/src/deployment-inspection.ts
|
|
1170
|
+
var TRANSIENT_MESSAGE_LOOKUP_STATUSES = /* @__PURE__ */ new Set([408, 425, 429, 500, 502, 503, 504]);
|
|
1171
|
+
function isTransientMessageLookupError(error) {
|
|
1172
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1173
|
+
const match = message.match(/Message lookup failed: (\d{3})/);
|
|
1174
|
+
if (!match) return false;
|
|
1175
|
+
return TRANSIENT_MESSAGE_LOOKUP_STATUSES.has(Number(match[1]));
|
|
1176
|
+
}
|
|
1155
1177
|
async function fetchMessageEnvelope2(itemHash, options) {
|
|
1156
1178
|
const response = await options.fetch(`${options.apiHost ?? DEFAULT_ALEPH_API_HOST2}/api/v0/messages/${itemHash}`, {
|
|
1157
1179
|
cache: "no-cache"
|
|
@@ -1208,15 +1230,32 @@ async function waitForDeploymentResult2(itemHash, options) {
|
|
|
1208
1230
|
const attempts = Math.max(1, Number(options.attempts ?? 15));
|
|
1209
1231
|
const delayMs = Math.max(0, Number(options.delayMs ?? 2e3));
|
|
1210
1232
|
const sleep2 = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
1211
|
-
let lastResult =
|
|
1212
|
-
|
|
1213
|
-
|
|
1233
|
+
let lastResult = {
|
|
1234
|
+
status: "unknown",
|
|
1235
|
+
errorCode: null,
|
|
1236
|
+
details: null,
|
|
1237
|
+
rejectionReason: null,
|
|
1238
|
+
references: []
|
|
1239
|
+
};
|
|
1240
|
+
for (let attempt = 1; attempt <= attempts; attempt += 1) {
|
|
1241
|
+
try {
|
|
1242
|
+
lastResult = await inspectDeploymentResult2(itemHash, options);
|
|
1243
|
+
} catch (error) {
|
|
1244
|
+
if (!isTransientMessageLookupError(error)) {
|
|
1245
|
+
throw error;
|
|
1246
|
+
}
|
|
1247
|
+
lastResult = {
|
|
1248
|
+
...lastResult,
|
|
1249
|
+
rejectionReason: error instanceof Error ? error.message : String(error)
|
|
1250
|
+
};
|
|
1251
|
+
}
|
|
1252
|
+
options.onAttempt?.(lastResult, attempt, attempts);
|
|
1214
1253
|
if (lastResult.status === "processed" || lastResult.status === "rejected") {
|
|
1215
1254
|
return lastResult;
|
|
1216
1255
|
}
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1256
|
+
if (attempt < attempts) {
|
|
1257
|
+
await sleep2(delayMs);
|
|
1258
|
+
}
|
|
1220
1259
|
}
|
|
1221
1260
|
return lastResult;
|
|
1222
1261
|
}
|
|
@@ -2273,6 +2312,45 @@ async function configureOrbitdbRelaySetup2(args) {
|
|
|
2273
2312
|
clearTimeout(timeout);
|
|
2274
2313
|
}
|
|
2275
2314
|
}
|
|
2315
|
+
async function configureUcanStore(args) {
|
|
2316
|
+
const controller = new AbortController();
|
|
2317
|
+
const timeout = setTimeout(
|
|
2318
|
+
() => controller.abort(),
|
|
2319
|
+
Number(args.timeoutMs ?? 18e4)
|
|
2320
|
+
);
|
|
2321
|
+
const payload = {
|
|
2322
|
+
public_ipv4: args.hostIpv4,
|
|
2323
|
+
public_ipv6: args.publicIpv6 ?? void 0,
|
|
2324
|
+
proxy_url: args.proxyUrl ?? void 0,
|
|
2325
|
+
webauthn_origin: args.webauthnOrigin ?? void 0,
|
|
2326
|
+
webauthn_origin_fallbacks: args.webauthnOriginFallbacks ?? void 0,
|
|
2327
|
+
admin_did: args.adminDid ?? void 0,
|
|
2328
|
+
bootstrap_package: args.bootstrapPackage ?? void 0,
|
|
2329
|
+
no_start: args.noStart === true ? true : void 0
|
|
2330
|
+
};
|
|
2331
|
+
try {
|
|
2332
|
+
const response = await args.fetch(
|
|
2333
|
+
`http://${args.hostIpv4}:${args.setupPort}/configure`,
|
|
2334
|
+
{
|
|
2335
|
+
method: "POST",
|
|
2336
|
+
headers: {
|
|
2337
|
+
"content-type": "application/json"
|
|
2338
|
+
},
|
|
2339
|
+
body: JSON.stringify(payload),
|
|
2340
|
+
signal: controller.signal
|
|
2341
|
+
}
|
|
2342
|
+
);
|
|
2343
|
+
const responsePayload = await response.json().catch(() => null);
|
|
2344
|
+
if (!response.ok) {
|
|
2345
|
+
throw new Error(
|
|
2346
|
+
`Service setup request failed: ${response.status} ${typeof responsePayload === "string" ? responsePayload : JSON.stringify(responsePayload ?? {})}`
|
|
2347
|
+
);
|
|
2348
|
+
}
|
|
2349
|
+
return responsePayload;
|
|
2350
|
+
} finally {
|
|
2351
|
+
clearTimeout(timeout);
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2276
2354
|
async function fetchUcGoPeerMetadata(args) {
|
|
2277
2355
|
const attempts = Math.max(1, Number(args.attempts ?? 60));
|
|
2278
2356
|
const delayMs = Math.max(0, Number(args.delayMs ?? 3e3));
|
|
@@ -2340,7 +2418,7 @@ async function fetchUcGoPeerMetadata(args) {
|
|
|
2340
2418
|
}
|
|
2341
2419
|
}
|
|
2342
2420
|
throw new Error(
|
|
2343
|
-
`
|
|
2421
|
+
`Guest metadata did not become ready after ${attempts} attempts: ${lastError ? lastError : typeof lastPayload === "string" ? lastPayload : JSON.stringify(lastPayload ?? {})}`
|
|
2344
2422
|
);
|
|
2345
2423
|
}
|
|
2346
2424
|
|
|
@@ -3272,7 +3350,130 @@ function createDeploymentProgressEmitter() {
|
|
|
3272
3350
|
};
|
|
3273
3351
|
}
|
|
3274
3352
|
|
|
3353
|
+
// ../shared-types/src/ucan-store-bootstrap.ts
|
|
3354
|
+
function isRecord(value) {
|
|
3355
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
3356
|
+
}
|
|
3357
|
+
function normalizeNonEmptyString(value) {
|
|
3358
|
+
if (typeof value !== "string") return null;
|
|
3359
|
+
const normalized = value.trim();
|
|
3360
|
+
return normalized ? normalized : null;
|
|
3361
|
+
}
|
|
3362
|
+
function normalizeDid(value) {
|
|
3363
|
+
const did = normalizeNonEmptyString(value);
|
|
3364
|
+
return did && did.startsWith("did:") ? did : null;
|
|
3365
|
+
}
|
|
3366
|
+
function normalizeOrigin(value) {
|
|
3367
|
+
const raw = normalizeNonEmptyString(value);
|
|
3368
|
+
if (!raw) return null;
|
|
3369
|
+
try {
|
|
3370
|
+
const parsed = new URL(raw);
|
|
3371
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:" || !parsed.hostname || parsed.pathname && parsed.pathname !== "/" || parsed.search || parsed.hash) {
|
|
3372
|
+
return null;
|
|
3373
|
+
}
|
|
3374
|
+
return parsed.origin;
|
|
3375
|
+
} catch {
|
|
3376
|
+
return null;
|
|
3377
|
+
}
|
|
3378
|
+
}
|
|
3379
|
+
function normalizeExpiration(value) {
|
|
3380
|
+
if (value == null) return void 0;
|
|
3381
|
+
if (value === null) return null;
|
|
3382
|
+
if (!Number.isInteger(value) || Number(value) < 0) return void 0;
|
|
3383
|
+
return Number(value);
|
|
3384
|
+
}
|
|
3385
|
+
function validateUcanStoreBootstrapPackage(value) {
|
|
3386
|
+
if (!isRecord(value)) {
|
|
3387
|
+
return {
|
|
3388
|
+
valid: false,
|
|
3389
|
+
errors: ["Bootstrap package must be a JSON object."],
|
|
3390
|
+
bootstrapPackage: null
|
|
3391
|
+
};
|
|
3392
|
+
}
|
|
3393
|
+
const errors = [];
|
|
3394
|
+
const operatorAddress = normalizeNonEmptyString(value.operatorAddress);
|
|
3395
|
+
if (!operatorAddress || !/^0x[a-fA-F0-9]{40}$/.test(operatorAddress)) {
|
|
3396
|
+
errors.push("operatorAddress must be a 0x-prefixed 20-byte Ethereum address.");
|
|
3397
|
+
}
|
|
3398
|
+
const adminDid = normalizeDid(value.adminDid);
|
|
3399
|
+
if (!adminDid) {
|
|
3400
|
+
errors.push("adminDid must be a non-empty DID string.");
|
|
3401
|
+
}
|
|
3402
|
+
const serviceDidRaw = value.serviceDid;
|
|
3403
|
+
const serviceDid = serviceDidRaw == null || serviceDidRaw === "" ? null : normalizeDid(serviceDidRaw);
|
|
3404
|
+
if (serviceDidRaw != null && serviceDidRaw !== "" && !serviceDid) {
|
|
3405
|
+
errors.push("serviceDid must be empty or a non-empty DID string.");
|
|
3406
|
+
}
|
|
3407
|
+
const spaceDid = normalizeDid(value.spaceDid);
|
|
3408
|
+
if (!spaceDid) {
|
|
3409
|
+
errors.push("spaceDid must be a non-empty DID string.");
|
|
3410
|
+
}
|
|
3411
|
+
const rootDelegationProof = normalizeNonEmptyString(value.rootDelegationProof);
|
|
3412
|
+
if (!rootDelegationProof) {
|
|
3413
|
+
errors.push("rootDelegationProof must be a non-empty proof string.");
|
|
3414
|
+
}
|
|
3415
|
+
const allowedCapabilities = Array.isArray(value.allowedCapabilities) ? value.allowedCapabilities.map((entry) => normalizeNonEmptyString(entry)).filter((entry) => Boolean(entry)) : [];
|
|
3416
|
+
if (allowedCapabilities.length === 0) {
|
|
3417
|
+
errors.push("allowedCapabilities must contain at least one capability string.");
|
|
3418
|
+
}
|
|
3419
|
+
const defaultUserDelegationExpiration = normalizeExpiration(
|
|
3420
|
+
value.defaultUserDelegationExpiration
|
|
3421
|
+
);
|
|
3422
|
+
if (value.defaultUserDelegationExpiration != null && defaultUserDelegationExpiration === void 0) {
|
|
3423
|
+
errors.push(
|
|
3424
|
+
"defaultUserDelegationExpiration must be null or a non-negative integer number of seconds."
|
|
3425
|
+
);
|
|
3426
|
+
}
|
|
3427
|
+
const maxUserDelegationExpiration = normalizeExpiration(
|
|
3428
|
+
value.maxUserDelegationExpiration
|
|
3429
|
+
);
|
|
3430
|
+
if (value.maxUserDelegationExpiration != null && maxUserDelegationExpiration === void 0) {
|
|
3431
|
+
errors.push(
|
|
3432
|
+
"maxUserDelegationExpiration must be null or a non-negative integer number of seconds."
|
|
3433
|
+
);
|
|
3434
|
+
}
|
|
3435
|
+
if (typeof defaultUserDelegationExpiration === "number" && typeof maxUserDelegationExpiration === "number" && defaultUserDelegationExpiration > maxUserDelegationExpiration) {
|
|
3436
|
+
errors.push(
|
|
3437
|
+
"defaultUserDelegationExpiration cannot exceed maxUserDelegationExpiration."
|
|
3438
|
+
);
|
|
3439
|
+
}
|
|
3440
|
+
const pwaOrigin = normalizeOrigin(value.pwaOrigin);
|
|
3441
|
+
if (!pwaOrigin) {
|
|
3442
|
+
errors.push("pwaOrigin must be an http(s) origin without path, query, or hash.");
|
|
3443
|
+
}
|
|
3444
|
+
const serviceOrigin = normalizeOrigin(value.serviceOrigin);
|
|
3445
|
+
if (!serviceOrigin) {
|
|
3446
|
+
errors.push("serviceOrigin must be an http(s) origin without path, query, or hash.");
|
|
3447
|
+
}
|
|
3448
|
+
if (errors.length > 0) {
|
|
3449
|
+
return {
|
|
3450
|
+
valid: false,
|
|
3451
|
+
errors,
|
|
3452
|
+
bootstrapPackage: null
|
|
3453
|
+
};
|
|
3454
|
+
}
|
|
3455
|
+
return {
|
|
3456
|
+
valid: true,
|
|
3457
|
+
errors: [],
|
|
3458
|
+
bootstrapPackage: {
|
|
3459
|
+
operatorAddress,
|
|
3460
|
+
adminDid,
|
|
3461
|
+
serviceDid,
|
|
3462
|
+
spaceDid,
|
|
3463
|
+
rootDelegationProof,
|
|
3464
|
+
allowedCapabilities,
|
|
3465
|
+
defaultUserDelegationExpiration,
|
|
3466
|
+
maxUserDelegationExpiration,
|
|
3467
|
+
pwaOrigin,
|
|
3468
|
+
serviceOrigin
|
|
3469
|
+
}
|
|
3470
|
+
};
|
|
3471
|
+
}
|
|
3472
|
+
|
|
3275
3473
|
// src/shared/controller.ts
|
|
3474
|
+
function deploymentNoun(profile) {
|
|
3475
|
+
return profile === "ucan-store" ? "service" : "relay";
|
|
3476
|
+
}
|
|
3276
3477
|
function asJsonFetch(input, init) {
|
|
3277
3478
|
return fetch(input, init).then(async (response) => ({
|
|
3278
3479
|
ok: response.ok,
|
|
@@ -3280,11 +3481,122 @@ function asJsonFetch(input, init) {
|
|
|
3280
3481
|
json: async () => await response.json()
|
|
3281
3482
|
}));
|
|
3282
3483
|
}
|
|
3283
|
-
function
|
|
3484
|
+
function isConfirmedGuestSetupResult(value) {
|
|
3284
3485
|
return Boolean(
|
|
3285
3486
|
value && typeof value === "object" && "status" in value && value.status === "configured"
|
|
3286
3487
|
);
|
|
3287
3488
|
}
|
|
3489
|
+
function defaultUcanStoreBootstrapInput(props) {
|
|
3490
|
+
return {
|
|
3491
|
+
adminDid: props.ucanStoreBootstrap?.adminDid ?? "",
|
|
3492
|
+
serviceDid: props.ucanStoreBootstrap?.serviceDid ?? DEFAULT_UCAN_STORE_SERVICE_DID,
|
|
3493
|
+
spaceDid: props.ucanStoreBootstrap?.spaceDid ?? "",
|
|
3494
|
+
rootDelegationProof: props.ucanStoreBootstrap?.rootDelegationProof ?? "",
|
|
3495
|
+
allowedCapabilities: props.ucanStoreBootstrap?.allowedCapabilities ?? DEFAULT_UCAN_STORE_ALLOWED_CAPABILITIES.join("\n"),
|
|
3496
|
+
defaultUserDelegationExpiration: props.ucanStoreBootstrap?.defaultUserDelegationExpiration ?? DEFAULT_UCAN_STORE_USER_DELEGATION_EXPIRATION_SECONDS,
|
|
3497
|
+
maxUserDelegationExpiration: props.ucanStoreBootstrap?.maxUserDelegationExpiration ?? DEFAULT_UCAN_STORE_MAX_DELEGATION_EXPIRATION_SECONDS,
|
|
3498
|
+
pwaOrigin: props.ucanStoreBootstrap?.pwaOrigin ?? DEFAULT_UCAN_STORE_PWA_ORIGIN,
|
|
3499
|
+
serviceOrigin: props.ucanStoreBootstrap?.serviceOrigin ?? DEFAULT_UCAN_STORE_SERVICE_ORIGIN
|
|
3500
|
+
};
|
|
3501
|
+
}
|
|
3502
|
+
function currentPageOrigin() {
|
|
3503
|
+
try {
|
|
3504
|
+
const origin = globalThis.location?.origin?.trim();
|
|
3505
|
+
return origin ? origin : null;
|
|
3506
|
+
} catch {
|
|
3507
|
+
return null;
|
|
3508
|
+
}
|
|
3509
|
+
}
|
|
3510
|
+
function parseOptionalExpiration(value) {
|
|
3511
|
+
const normalized = value.trim();
|
|
3512
|
+
if (!normalized) return void 0;
|
|
3513
|
+
const parsed = Number.parseInt(normalized, 10);
|
|
3514
|
+
if (!Number.isInteger(parsed) || parsed < 0) {
|
|
3515
|
+
return null;
|
|
3516
|
+
}
|
|
3517
|
+
return parsed;
|
|
3518
|
+
}
|
|
3519
|
+
function parseAllowedCapabilities(value) {
|
|
3520
|
+
return value.split(/[\n,]/).map((entry) => entry.trim()).filter(Boolean);
|
|
3521
|
+
}
|
|
3522
|
+
function draftUcanStoreBootstrapErrors(args) {
|
|
3523
|
+
const errors = [];
|
|
3524
|
+
const { input } = args;
|
|
3525
|
+
if (!args.operatorAddress) {
|
|
3526
|
+
errors.push("Connect MetaMask before configuring the ucan-store bootstrap package.");
|
|
3527
|
+
}
|
|
3528
|
+
if (!input.adminDid.trim().startsWith("did:")) {
|
|
3529
|
+
errors.push("Admin DID must be a non-empty DID string.");
|
|
3530
|
+
}
|
|
3531
|
+
if (input.serviceDid.trim() && !input.serviceDid.trim().startsWith("did:")) {
|
|
3532
|
+
errors.push("Service DID must be empty or a non-empty DID string.");
|
|
3533
|
+
}
|
|
3534
|
+
if (!input.spaceDid.trim().startsWith("did:")) {
|
|
3535
|
+
errors.push("Space DID must be a non-empty DID string.");
|
|
3536
|
+
}
|
|
3537
|
+
if (!input.rootDelegationProof.trim()) {
|
|
3538
|
+
errors.push("Root delegation proof is required.");
|
|
3539
|
+
}
|
|
3540
|
+
if (parseAllowedCapabilities(input.allowedCapabilities).length === 0) {
|
|
3541
|
+
errors.push("Add at least one allowed capability.");
|
|
3542
|
+
}
|
|
3543
|
+
const defaultExpiration = parseOptionalExpiration(
|
|
3544
|
+
input.defaultUserDelegationExpiration
|
|
3545
|
+
);
|
|
3546
|
+
if (defaultExpiration === null) {
|
|
3547
|
+
errors.push(
|
|
3548
|
+
"Default user delegation expiration must be a non-negative integer number of seconds."
|
|
3549
|
+
);
|
|
3550
|
+
}
|
|
3551
|
+
const maxExpiration = parseOptionalExpiration(
|
|
3552
|
+
input.maxUserDelegationExpiration
|
|
3553
|
+
);
|
|
3554
|
+
if (maxExpiration === null) {
|
|
3555
|
+
errors.push(
|
|
3556
|
+
"Max user delegation expiration must be a non-negative integer number of seconds."
|
|
3557
|
+
);
|
|
3558
|
+
}
|
|
3559
|
+
if (typeof defaultExpiration === "number" && typeof maxExpiration === "number" && defaultExpiration > maxExpiration) {
|
|
3560
|
+
errors.push(
|
|
3561
|
+
"Default user delegation expiration cannot exceed the max user delegation expiration."
|
|
3562
|
+
);
|
|
3563
|
+
}
|
|
3564
|
+
const pwaOrigin = input.pwaOrigin.trim() || currentPageOrigin() || "";
|
|
3565
|
+
if (!pwaOrigin) {
|
|
3566
|
+
errors.push("PWA origin is required for the ucan-store bootstrap package.");
|
|
3567
|
+
}
|
|
3568
|
+
return errors;
|
|
3569
|
+
}
|
|
3570
|
+
function buildUcanStoreBootstrapPackage(args) {
|
|
3571
|
+
const candidate = {
|
|
3572
|
+
operatorAddress: args.operatorAddress,
|
|
3573
|
+
adminDid: args.input.adminDid.trim(),
|
|
3574
|
+
serviceDid: args.input.serviceDid.trim() || null,
|
|
3575
|
+
spaceDid: args.input.spaceDid.trim(),
|
|
3576
|
+
rootDelegationProof: args.input.rootDelegationProof.trim(),
|
|
3577
|
+
allowedCapabilities: parseAllowedCapabilities(args.input.allowedCapabilities),
|
|
3578
|
+
defaultUserDelegationExpiration: parseOptionalExpiration(
|
|
3579
|
+
args.input.defaultUserDelegationExpiration
|
|
3580
|
+
),
|
|
3581
|
+
maxUserDelegationExpiration: parseOptionalExpiration(
|
|
3582
|
+
args.input.maxUserDelegationExpiration
|
|
3583
|
+
),
|
|
3584
|
+
pwaOrigin: args.input.pwaOrigin.trim() || args.pwaOriginFallback?.trim() || currentPageOrigin() || "",
|
|
3585
|
+
serviceOrigin: args.input.serviceOrigin.trim() || args.serviceOriginFallback?.trim() || ""
|
|
3586
|
+
};
|
|
3587
|
+
if (candidate.defaultUserDelegationExpiration === void 0) {
|
|
3588
|
+
delete candidate.defaultUserDelegationExpiration;
|
|
3589
|
+
}
|
|
3590
|
+
if (candidate.maxUserDelegationExpiration === void 0) {
|
|
3591
|
+
delete candidate.maxUserDelegationExpiration;
|
|
3592
|
+
}
|
|
3593
|
+
if (candidate.serviceDid === null) {
|
|
3594
|
+
delete candidate.serviceDid;
|
|
3595
|
+
}
|
|
3596
|
+
return validateUcanStoreBootstrapPackage(
|
|
3597
|
+
candidate
|
|
3598
|
+
);
|
|
3599
|
+
}
|
|
3288
3600
|
function defaultState(props = {}) {
|
|
3289
3601
|
return {
|
|
3290
3602
|
ready: false,
|
|
@@ -3299,6 +3611,7 @@ function defaultState(props = {}) {
|
|
|
3299
3611
|
manifestJson: props.manifestJson ?? "",
|
|
3300
3612
|
sshPublicKey: props.sshPublicKey ?? "",
|
|
3301
3613
|
instanceName: props.instanceName ?? DEFAULT_INSTANCE_NAME,
|
|
3614
|
+
ucanStoreBootstrap: defaultUcanStoreBootstrapInput(props),
|
|
3302
3615
|
tierId: DEFAULT_TIER_ID,
|
|
3303
3616
|
showAdvanced: Boolean(props.manifestJson?.trim() || props.sshPublicKey?.trim()),
|
|
3304
3617
|
showInstances: props.showInstances ?? true,
|
|
@@ -3433,13 +3746,33 @@ async function resolveManifest(args) {
|
|
|
3433
3746
|
if (pasted) return pasted;
|
|
3434
3747
|
return loadRootfsManifest(args.manifestUrl);
|
|
3435
3748
|
}
|
|
3436
|
-
function
|
|
3749
|
+
function deploymentProfileForManifest(manifest) {
|
|
3437
3750
|
if (manifest?.profile === "uc-go-peer") return "uc-go-peer";
|
|
3438
3751
|
if (manifest?.profile === "orbitdb-relay") {
|
|
3439
3752
|
return manifest.profile;
|
|
3440
3753
|
}
|
|
3754
|
+
if (manifest?.profile === "ucan-store") return "ucan-store";
|
|
3441
3755
|
return null;
|
|
3442
3756
|
}
|
|
3757
|
+
function bootstrapRelayProfileForManifest(manifest) {
|
|
3758
|
+
const profile = deploymentProfileForManifest(manifest);
|
|
3759
|
+
if (profile === "uc-go-peer" || profile === "orbitdb-relay") {
|
|
3760
|
+
return profile;
|
|
3761
|
+
}
|
|
3762
|
+
return null;
|
|
3763
|
+
}
|
|
3764
|
+
function supportsBootstrapRegistrationsForManifest(manifest) {
|
|
3765
|
+
return bootstrapRelayProfileForManifest(manifest) != null;
|
|
3766
|
+
}
|
|
3767
|
+
function deploymentReadyLabel(profile) {
|
|
3768
|
+
return profile === "ucan-store" ? "Service ready" : "Relay ready";
|
|
3769
|
+
}
|
|
3770
|
+
function deploymentReadyDetail(profile, fallback) {
|
|
3771
|
+
if (profile === "ucan-store") {
|
|
3772
|
+
return "The upload service runtime is available and the deployment finished successfully.";
|
|
3773
|
+
}
|
|
3774
|
+
return fallback;
|
|
3775
|
+
}
|
|
3443
3776
|
function registrationIdInstanceItemHash(registrationId) {
|
|
3444
3777
|
const normalized = String(registrationId ?? "").trim();
|
|
3445
3778
|
if (!normalized) return null;
|
|
@@ -3688,19 +4021,148 @@ var SponsorRelayController = class {
|
|
|
3688
4021
|
this.progressEmitter.emit(nextEvent);
|
|
3689
4022
|
}
|
|
3690
4023
|
async configureRelayBootstrapRegistration(args) {
|
|
3691
|
-
const
|
|
3692
|
-
|
|
3693
|
-
if (!
|
|
4024
|
+
const deploymentProfile = deploymentProfileForManifest(this.state.manifest);
|
|
4025
|
+
const profile = bootstrapRelayProfileForManifest(this.state.manifest);
|
|
4026
|
+
if (!profile && deploymentProfile !== "ucan-store") return;
|
|
4027
|
+
if (profile && !this.state.wallet.address) {
|
|
3694
4028
|
throw new Error("A connected wallet is required to register relay bootstrap addresses.");
|
|
3695
4029
|
}
|
|
3696
|
-
|
|
3697
|
-
|
|
4030
|
+
const runtimeHostIpv4 = args.runtime.hostIpv4;
|
|
4031
|
+
if (!runtimeHostIpv4) {
|
|
4032
|
+
throw new Error(
|
|
4033
|
+
`${deploymentProfile === "ucan-store" ? "Service" : "Relay"} runtime did not expose a host IPv4 address.`
|
|
4034
|
+
);
|
|
3698
4035
|
}
|
|
3699
4036
|
let runtime = args.runtime;
|
|
3700
4037
|
let mappedPorts2 = runtime.mappedPorts ?? {};
|
|
3701
4038
|
const setupPort = mappedPorts2["80"]?.host ?? null;
|
|
3702
4039
|
if (!setupPort) {
|
|
3703
|
-
throw new Error(
|
|
4040
|
+
throw new Error(
|
|
4041
|
+
`${deploymentProfile === "ucan-store" ? "Service" : "Relay"} runtime did not expose the temporary setup endpoint.`
|
|
4042
|
+
);
|
|
4043
|
+
}
|
|
4044
|
+
if (deploymentProfile === "ucan-store") {
|
|
4045
|
+
const serviceHostIpv4 = runtimeHostIpv4;
|
|
4046
|
+
const serviceProxyUrl = runtime.proxyUrl;
|
|
4047
|
+
if (!serviceProxyUrl) {
|
|
4048
|
+
throw new Error("Service runtime did not expose a proxy URL.");
|
|
4049
|
+
}
|
|
4050
|
+
const walletAddress2 = this.state.wallet.address;
|
|
4051
|
+
if (!walletAddress2) {
|
|
4052
|
+
throw new Error("A connected wallet is required to configure the ucan-store bootstrap package.");
|
|
4053
|
+
}
|
|
4054
|
+
const bootstrapValidation = buildUcanStoreBootstrapPackage({
|
|
4055
|
+
input: this.state.ucanStoreBootstrap,
|
|
4056
|
+
operatorAddress: walletAddress2,
|
|
4057
|
+
serviceOriginFallback: serviceProxyUrl,
|
|
4058
|
+
pwaOriginFallback: currentPageOrigin()
|
|
4059
|
+
});
|
|
4060
|
+
if (!bootstrapValidation.valid || !bootstrapValidation.bootstrapPackage) {
|
|
4061
|
+
throw new Error(
|
|
4062
|
+
bootstrapValidation.errors[0] ?? "The ucan-store bootstrap package is invalid."
|
|
4063
|
+
);
|
|
4064
|
+
}
|
|
4065
|
+
this.emitProgress({
|
|
4066
|
+
stage: "deployment-confirmed",
|
|
4067
|
+
label: "Configuring service",
|
|
4068
|
+
progress: 93,
|
|
4069
|
+
status: "info",
|
|
4070
|
+
itemHash: args.itemHash,
|
|
4071
|
+
detail: "Waiting for the guest setup endpoint before applying the upload service configuration."
|
|
4072
|
+
});
|
|
4073
|
+
const setupHealth = await waitForSetupEndpoint({
|
|
4074
|
+
hostIpv4: serviceHostIpv4,
|
|
4075
|
+
setupPort,
|
|
4076
|
+
fetch: (url, init) => fetch(url, init),
|
|
4077
|
+
attempts: 15,
|
|
4078
|
+
delayMs: 4e3,
|
|
4079
|
+
httpTimeoutMs: 1e4,
|
|
4080
|
+
onAttempt: (result, attempt, attempts) => {
|
|
4081
|
+
this.emitProgress({
|
|
4082
|
+
stage: "deployment-confirmed",
|
|
4083
|
+
label: "Waiting for guest setup",
|
|
4084
|
+
progress: 93,
|
|
4085
|
+
status: result.ok ? "success" : "info",
|
|
4086
|
+
itemHash: args.itemHash,
|
|
4087
|
+
detail: result.ok ? `Setup endpoint ${attempt}/${attempts}: ready at http://${serviceHostIpv4}:${setupPort}/health.` : `Setup endpoint ${attempt}/${attempts}: waiting for http://${serviceHostIpv4}:${setupPort}/health.`
|
|
4088
|
+
});
|
|
4089
|
+
}
|
|
4090
|
+
});
|
|
4091
|
+
if (!setupHealth.ok) {
|
|
4092
|
+
throw new Error(
|
|
4093
|
+
`Service setup endpoint did not become reachable at http://${serviceHostIpv4}:${setupPort}/health.`
|
|
4094
|
+
);
|
|
4095
|
+
}
|
|
4096
|
+
this.emitProgress({
|
|
4097
|
+
stage: "deployment-confirmed",
|
|
4098
|
+
label: "Applying service config",
|
|
4099
|
+
progress: 94,
|
|
4100
|
+
status: "info",
|
|
4101
|
+
itemHash: args.itemHash,
|
|
4102
|
+
detail: "Publishing the public HTTPS origin into the guest upload service configuration."
|
|
4103
|
+
});
|
|
4104
|
+
const configureResult = await configureUcanStore({
|
|
4105
|
+
hostIpv4: serviceHostIpv4,
|
|
4106
|
+
publicIpv6: runtime.ipv6,
|
|
4107
|
+
setupPort,
|
|
4108
|
+
proxyUrl: serviceProxyUrl,
|
|
4109
|
+
webauthnOrigin: serviceProxyUrl,
|
|
4110
|
+
adminDid: bootstrapValidation.bootstrapPackage.adminDid,
|
|
4111
|
+
bootstrapPackage: bootstrapValidation.bootstrapPackage,
|
|
4112
|
+
fetch: (url, init) => fetch(url, init),
|
|
4113
|
+
timeoutMs: 18e4
|
|
4114
|
+
});
|
|
4115
|
+
if (!isConfirmedGuestSetupResult(configureResult)) {
|
|
4116
|
+
throw new Error(
|
|
4117
|
+
`Service guest configuration could not be confirmed at http://${serviceHostIpv4}:${setupPort}/configure.`
|
|
4118
|
+
);
|
|
4119
|
+
}
|
|
4120
|
+
this.emitProgress({
|
|
4121
|
+
stage: "deployment-confirmed",
|
|
4122
|
+
label: "Waiting for service metadata",
|
|
4123
|
+
progress: 95,
|
|
4124
|
+
status: "info",
|
|
4125
|
+
itemHash: args.itemHash,
|
|
4126
|
+
detail: "Waiting for the upload service metadata endpoint to report the public service DID and PWA environment."
|
|
4127
|
+
});
|
|
4128
|
+
const serviceMetadata = await fetchUcGoPeerMetadata({
|
|
4129
|
+
hostIpv4: serviceHostIpv4,
|
|
4130
|
+
setupPort,
|
|
4131
|
+
fetch: (url, init) => fetch(url, init),
|
|
4132
|
+
attempts: 80,
|
|
4133
|
+
delayMs: 3e3,
|
|
4134
|
+
timeoutMs: 24e4,
|
|
4135
|
+
isReady: ({ payload, ok }) => {
|
|
4136
|
+
if (!ok || !payload || typeof payload !== "object") return false;
|
|
4137
|
+
const metadata2 = payload.metadata && typeof payload.metadata === "object" ? payload.metadata : null;
|
|
4138
|
+
const pwaEnv = metadata2?.pwa_env && typeof metadata2.pwa_env === "object" ? metadata2.pwa_env : null;
|
|
4139
|
+
return Boolean(
|
|
4140
|
+
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
|
|
4141
|
+
);
|
|
4142
|
+
},
|
|
4143
|
+
onAttempt: ({ ready, attempt, attempts, requestUrl }) => {
|
|
4144
|
+
this.emitProgress({
|
|
4145
|
+
stage: "deployment-confirmed",
|
|
4146
|
+
label: ready ? "Service metadata ready" : "Waiting for service metadata",
|
|
4147
|
+
progress: 95,
|
|
4148
|
+
status: ready ? "success" : "info",
|
|
4149
|
+
itemHash: args.itemHash,
|
|
4150
|
+
detail: ready ? `Service metadata ${attempt}/${attempts}: public upload service wiring is ready.` : `Service metadata ${attempt}/${attempts}: waiting for ${requestUrl}.`
|
|
4151
|
+
});
|
|
4152
|
+
}
|
|
4153
|
+
});
|
|
4154
|
+
const metadata = serviceMetadata && typeof serviceMetadata === "object" ? serviceMetadata.metadata ?? null : null;
|
|
4155
|
+
if (!metadata || typeof metadata !== "object" || typeof metadata.upload_service_did !== "string") {
|
|
4156
|
+
throw new Error(
|
|
4157
|
+
"Service metadata did not include the public upload service DID."
|
|
4158
|
+
);
|
|
4159
|
+
}
|
|
4160
|
+
return;
|
|
4161
|
+
}
|
|
4162
|
+
if (!profile) return;
|
|
4163
|
+
const walletAddress = this.state.wallet.address;
|
|
4164
|
+
if (!walletAddress) {
|
|
4165
|
+
throw new Error("A connected wallet is required to register relay bootstrap addresses.");
|
|
3704
4166
|
}
|
|
3705
4167
|
let bootstrapSignalRelayMetadata = null;
|
|
3706
4168
|
if (profile === "orbitdb-relay") {
|
|
@@ -3713,7 +4175,7 @@ var SponsorRelayController = class {
|
|
|
3713
4175
|
detail: "Waiting for the guest setup endpoint before collecting relay metadata."
|
|
3714
4176
|
});
|
|
3715
4177
|
const setupHealth = await waitForSetupEndpoint({
|
|
3716
|
-
hostIpv4:
|
|
4178
|
+
hostIpv4: runtimeHostIpv4,
|
|
3717
4179
|
setupPort,
|
|
3718
4180
|
fetch: (url, init) => fetch(url, init),
|
|
3719
4181
|
attempts: 15,
|
|
@@ -3726,13 +4188,13 @@ var SponsorRelayController = class {
|
|
|
3726
4188
|
progress: 93,
|
|
3727
4189
|
status: result.ok ? "success" : "info",
|
|
3728
4190
|
itemHash: args.itemHash,
|
|
3729
|
-
detail: result.ok ? `Setup endpoint ${attempt}/${attempts}: ready at http://${
|
|
4191
|
+
detail: result.ok ? `Setup endpoint ${attempt}/${attempts}: ready at http://${runtimeHostIpv4}:${setupPort}/health.` : `Setup endpoint ${attempt}/${attempts}: waiting for http://${runtimeHostIpv4}:${setupPort}/health.`
|
|
3730
4192
|
});
|
|
3731
4193
|
}
|
|
3732
4194
|
});
|
|
3733
4195
|
if (!setupHealth.ok) {
|
|
3734
4196
|
throw new Error(
|
|
3735
|
-
`Relay setup endpoint did not become reachable at http://${
|
|
4197
|
+
`Relay setup endpoint did not become reachable at http://${runtimeHostIpv4}:${setupPort}/health.`
|
|
3736
4198
|
);
|
|
3737
4199
|
}
|
|
3738
4200
|
this.emitProgress({
|
|
@@ -3749,7 +4211,7 @@ var SponsorRelayController = class {
|
|
|
3749
4211
|
throw new Error("OrbitDB relay runtime is missing required mapped TCP/WS ports.");
|
|
3750
4212
|
}
|
|
3751
4213
|
const configureResult = await configureOrbitdbRelaySetup2({
|
|
3752
|
-
hostIpv4:
|
|
4214
|
+
hostIpv4: runtimeHostIpv4,
|
|
3753
4215
|
publicIpv6: args.runtime.ipv6,
|
|
3754
4216
|
setupPort,
|
|
3755
4217
|
tcpPort,
|
|
@@ -3762,7 +4224,7 @@ var SponsorRelayController = class {
|
|
|
3762
4224
|
fetch: (url, init) => fetch(url, init),
|
|
3763
4225
|
timeoutMs: 18e4
|
|
3764
4226
|
});
|
|
3765
|
-
if (!
|
|
4227
|
+
if (!isConfirmedGuestSetupResult(configureResult)) {
|
|
3766
4228
|
throw new Error(
|
|
3767
4229
|
`Relay guest configuration could not be confirmed at http://${args.runtime.hostIpv4}:${setupPort}/configure.`
|
|
3768
4230
|
);
|
|
@@ -3820,7 +4282,7 @@ var SponsorRelayController = class {
|
|
|
3820
4282
|
"Relay runtime lost its host IPv4 address while waiting for HTTPS activation."
|
|
3821
4283
|
);
|
|
3822
4284
|
}
|
|
3823
|
-
const
|
|
4285
|
+
const runtimeHostIpv42 = runtime.hostIpv4;
|
|
3824
4286
|
const activeProxyUrl = runtime.webAccess?.active === true ? runtime.proxyUrl ?? null : null;
|
|
3825
4287
|
this.emitProgress({
|
|
3826
4288
|
stage: "deployment-confirmed",
|
|
@@ -3833,13 +4295,13 @@ var SponsorRelayController = class {
|
|
|
3833
4295
|
const record = {
|
|
3834
4296
|
deploymentToken: args.deploymentToken,
|
|
3835
4297
|
profile,
|
|
3836
|
-
ownerAddress:
|
|
4298
|
+
ownerAddress: walletAddress,
|
|
3837
4299
|
instanceItemHash: args.itemHash,
|
|
3838
4300
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3839
4301
|
expiresAt: new Date(Date.now() + 30 * 6e4).toISOString(),
|
|
3840
4302
|
status: "pending",
|
|
3841
4303
|
runtime: {
|
|
3842
|
-
publicIpv4:
|
|
4304
|
+
publicIpv4: runtimeHostIpv42,
|
|
3843
4305
|
publicIpv6: runtime.ipv6 ?? null,
|
|
3844
4306
|
proxyUrl: activeProxyUrl,
|
|
3845
4307
|
mappedPorts: mappedPorts2
|
|
@@ -3853,7 +4315,7 @@ var SponsorRelayController = class {
|
|
|
3853
4315
|
}
|
|
3854
4316
|
};
|
|
3855
4317
|
const bootstrapConfigPublication = await publishVmBootstrapConfig({
|
|
3856
|
-
sender:
|
|
4318
|
+
sender: walletAddress,
|
|
3857
4319
|
record,
|
|
3858
4320
|
signer: personalSign,
|
|
3859
4321
|
hasher: sha256Hex,
|
|
@@ -3880,7 +4342,7 @@ var SponsorRelayController = class {
|
|
|
3880
4342
|
});
|
|
3881
4343
|
const bootstrapConfigSignal = await waitForVmBootstrapConfigSignal({
|
|
3882
4344
|
deploymentToken: args.deploymentToken,
|
|
3883
|
-
ownerAddress:
|
|
4345
|
+
ownerAddress: walletAddress,
|
|
3884
4346
|
instanceItemHash: args.itemHash,
|
|
3885
4347
|
fetch: asJsonFetch,
|
|
3886
4348
|
apiHost: this.client.apiHost,
|
|
@@ -4052,7 +4514,7 @@ var SponsorRelayController = class {
|
|
|
4052
4514
|
detail: "Guest bootstrap registration was delayed. Publishing the relay bootstrap record from the browser."
|
|
4053
4515
|
});
|
|
4054
4516
|
const fallbackPublication = await publishRelayBootstrapRegistration({
|
|
4055
|
-
sender:
|
|
4517
|
+
sender: walletAddress,
|
|
4056
4518
|
signer: personalSign,
|
|
4057
4519
|
hasher: sha256Hex,
|
|
4058
4520
|
fetch: asJsonFetch,
|
|
@@ -4072,7 +4534,7 @@ var SponsorRelayController = class {
|
|
|
4072
4534
|
fallbackPublication
|
|
4073
4535
|
});
|
|
4074
4536
|
const fallbackVisibleRegistration = await waitForRelayBootstrapRegistration({
|
|
4075
|
-
sender:
|
|
4537
|
+
sender: walletAddress,
|
|
4076
4538
|
registrationId,
|
|
4077
4539
|
peerId,
|
|
4078
4540
|
fetch: asJsonFetch,
|
|
@@ -4105,7 +4567,7 @@ var SponsorRelayController = class {
|
|
|
4105
4567
|
if (profile === "uc-go-peer" && args.deploymentToken) {
|
|
4106
4568
|
let cleanupAggregateItemHash = null;
|
|
4107
4569
|
await deleteVmBootstrapConfig({
|
|
4108
|
-
sender:
|
|
4570
|
+
sender: walletAddress,
|
|
4109
4571
|
deploymentToken: args.deploymentToken,
|
|
4110
4572
|
signer: personalSign,
|
|
4111
4573
|
hasher: sha256Hex,
|
|
@@ -4271,17 +4733,35 @@ var SponsorRelayController = class {
|
|
|
4271
4733
|
});
|
|
4272
4734
|
return;
|
|
4273
4735
|
}
|
|
4736
|
+
const currentProfile = deploymentProfileForManifest(this.state.manifest);
|
|
4274
4737
|
const hasConfirmedBootstrapRegistration = this.state.bootstrapRegistrations.some(
|
|
4275
4738
|
(entry) => entry.instanceItemHash === itemHash && entry.confirmed
|
|
4276
4739
|
);
|
|
4740
|
+
if (currentProfile === "ucan-store") {
|
|
4741
|
+
this.emitProgress({
|
|
4742
|
+
stage: "completed",
|
|
4743
|
+
label: deploymentReadyLabel(currentProfile),
|
|
4744
|
+
progress: 100,
|
|
4745
|
+
status: "success",
|
|
4746
|
+
itemHash,
|
|
4747
|
+
detail: deploymentReadyDetail(
|
|
4748
|
+
currentProfile,
|
|
4749
|
+
"Runtime networking is available and the deployment finished successfully."
|
|
4750
|
+
)
|
|
4751
|
+
});
|
|
4752
|
+
return;
|
|
4753
|
+
}
|
|
4277
4754
|
if (hasConfirmedBootstrapRegistration) {
|
|
4278
4755
|
this.emitProgress({
|
|
4279
4756
|
stage: "completed",
|
|
4280
|
-
label:
|
|
4757
|
+
label: deploymentReadyLabel(currentProfile),
|
|
4281
4758
|
progress: 100,
|
|
4282
4759
|
status: "success",
|
|
4283
4760
|
itemHash,
|
|
4284
|
-
detail:
|
|
4761
|
+
detail: deploymentReadyDetail(
|
|
4762
|
+
currentProfile,
|
|
4763
|
+
"Runtime networking is available and the relay bootstrap registration is confirmed on Aleph."
|
|
4764
|
+
)
|
|
4285
4765
|
});
|
|
4286
4766
|
return;
|
|
4287
4767
|
}
|
|
@@ -4291,7 +4771,7 @@ var SponsorRelayController = class {
|
|
|
4291
4771
|
progress: 92,
|
|
4292
4772
|
status: "info",
|
|
4293
4773
|
itemHash,
|
|
4294
|
-
detail:
|
|
4774
|
+
detail: `Deployment processed and runtime networking is available. Finishing ${deploymentNoun(currentProfile)} setup and verification.`
|
|
4295
4775
|
});
|
|
4296
4776
|
}
|
|
4297
4777
|
canSkipRuntimeRefresh(instance) {
|
|
@@ -4404,6 +4884,15 @@ var SponsorRelayController = class {
|
|
|
4404
4884
|
setInstanceName(instanceName) {
|
|
4405
4885
|
this.patch({ instanceName });
|
|
4406
4886
|
}
|
|
4887
|
+
setUcanStoreBootstrapField(field, value) {
|
|
4888
|
+
this.patch({
|
|
4889
|
+
ucanStoreBootstrap: {
|
|
4890
|
+
...this.state.ucanStoreBootstrap,
|
|
4891
|
+
[field]: value
|
|
4892
|
+
},
|
|
4893
|
+
showAdvanced: this.state.showAdvanced || Boolean(value.trim())
|
|
4894
|
+
});
|
|
4895
|
+
}
|
|
4407
4896
|
setTierId(tierId) {
|
|
4408
4897
|
this.patch({ tierId });
|
|
4409
4898
|
this.recomputePricingSummary();
|
|
@@ -4489,6 +4978,7 @@ var SponsorRelayController = class {
|
|
|
4489
4978
|
}
|
|
4490
4979
|
}
|
|
4491
4980
|
async refresh() {
|
|
4981
|
+
const currentProfile = deploymentProfileForManifest(this.state.manifest);
|
|
4492
4982
|
this.trace("refresh:start", {
|
|
4493
4983
|
wallet: this.state.wallet.address,
|
|
4494
4984
|
manifestUrl: this.state.manifestUrl,
|
|
@@ -4497,7 +4987,7 @@ var SponsorRelayController = class {
|
|
|
4497
4987
|
this.patch({
|
|
4498
4988
|
busy: { refreshing: true },
|
|
4499
4989
|
errorText: null,
|
|
4500
|
-
statusText: "Refreshing relay
|
|
4990
|
+
statusText: currentProfile === "ucan-store" ? "Refreshing service deployment data" : "Refreshing relay deployment data"
|
|
4501
4991
|
});
|
|
4502
4992
|
try {
|
|
4503
4993
|
const [pricingSummary, crns] = await Promise.all([
|
|
@@ -4509,6 +4999,8 @@ var SponsorRelayController = class {
|
|
|
4509
4999
|
manifestJson: this.state.manifestJson
|
|
4510
5000
|
}).catch((error) => manifestLoadErrorState(error));
|
|
4511
5001
|
const manifest = manifestState.manifest;
|
|
5002
|
+
const resolvedProfile = deploymentProfileForManifest(manifest);
|
|
5003
|
+
const bootstrapEnabled = supportsBootstrapRegistrationsForManifest(manifest);
|
|
4512
5004
|
let balance = this.state.balance;
|
|
4513
5005
|
let instances = [];
|
|
4514
5006
|
let bootstrapRegistrations = [];
|
|
@@ -4517,10 +5009,10 @@ var SponsorRelayController = class {
|
|
|
4517
5009
|
const [nextBalance, rawInstances, rawBootstrapPosts] = await Promise.all([
|
|
4518
5010
|
this.client.fetchBalance(this.state.wallet.address),
|
|
4519
5011
|
this.state.showInstances ? this.client.fetchInstances(this.state.wallet.address) : Promise.resolve([]),
|
|
4520
|
-
fetchAlephBootstrapPosts({
|
|
5012
|
+
bootstrapEnabled ? fetchAlephBootstrapPosts({
|
|
4521
5013
|
apiHost: this.client.apiHost,
|
|
4522
5014
|
fetch
|
|
4523
|
-
}).catch(() => [])
|
|
5015
|
+
}).catch(() => []) : Promise.resolve([])
|
|
4524
5016
|
]);
|
|
4525
5017
|
balance = nextBalance;
|
|
4526
5018
|
instances = await Promise.all(
|
|
@@ -4650,7 +5142,7 @@ var SponsorRelayController = class {
|
|
|
4650
5142
|
bootstrapRegistrations,
|
|
4651
5143
|
orphanBootstrapRegistrations,
|
|
4652
5144
|
busy: { refreshing: false },
|
|
4653
|
-
statusText: "Relay
|
|
5145
|
+
statusText: resolvedProfile === "ucan-store" ? "Service deployment data ready" : "Relay deployment data ready"
|
|
4654
5146
|
});
|
|
4655
5147
|
this.trace("refresh:success", {
|
|
4656
5148
|
manifestValid: manifestState.valid,
|
|
@@ -4687,6 +5179,16 @@ var SponsorRelayController = class {
|
|
|
4687
5179
|
});
|
|
4688
5180
|
return;
|
|
4689
5181
|
}
|
|
5182
|
+
if (deploymentProfileForManifest(this.state.manifest) === "ucan-store") {
|
|
5183
|
+
const draftErrors = draftUcanStoreBootstrapErrors({
|
|
5184
|
+
input: this.state.ucanStoreBootstrap,
|
|
5185
|
+
operatorAddress: this.state.wallet.address
|
|
5186
|
+
});
|
|
5187
|
+
if (draftErrors.length > 0) {
|
|
5188
|
+
this.patch({ errorText: draftErrors[0] });
|
|
5189
|
+
return;
|
|
5190
|
+
}
|
|
5191
|
+
}
|
|
4690
5192
|
this.patch({
|
|
4691
5193
|
busy: { deploying: true },
|
|
4692
5194
|
errorText: null,
|
|
@@ -4736,7 +5238,7 @@ var SponsorRelayController = class {
|
|
|
4736
5238
|
detail: `Trying ${crnDisplayName}`
|
|
4737
5239
|
});
|
|
4738
5240
|
try {
|
|
4739
|
-
const profile =
|
|
5241
|
+
const profile = deploymentProfileForManifest(this.state.manifest);
|
|
4740
5242
|
attemptProfile = profile;
|
|
4741
5243
|
const sshPublicKey = profile === "uc-go-peer" ? appendDeploymentTokenToSshPublicKey(
|
|
4742
5244
|
this.state.sshPublicKey.trim(),
|
|
@@ -4955,11 +5457,14 @@ var SponsorRelayController = class {
|
|
|
4955
5457
|
this.lastCompletedDeploymentHash = result.itemHash;
|
|
4956
5458
|
this.emitProgress({
|
|
4957
5459
|
stage: "completed",
|
|
4958
|
-
label:
|
|
5460
|
+
label: deploymentReadyLabel(attemptProfile),
|
|
4959
5461
|
progress: 100,
|
|
4960
5462
|
status: "success",
|
|
4961
5463
|
itemHash: result.itemHash,
|
|
4962
|
-
detail:
|
|
5464
|
+
detail: deploymentReadyDetail(
|
|
5465
|
+
attemptProfile,
|
|
5466
|
+
"Relay runtime, setup, metadata, and bootstrap registration are confirmed."
|
|
5467
|
+
)
|
|
4963
5468
|
});
|
|
4964
5469
|
return;
|
|
4965
5470
|
} catch (error) {
|
|
@@ -5033,11 +5538,14 @@ var SponsorRelayController = class {
|
|
|
5033
5538
|
this.lastCompletedDeploymentHash = attemptItemHash;
|
|
5034
5539
|
this.emitProgress({
|
|
5035
5540
|
stage: "completed",
|
|
5036
|
-
label:
|
|
5541
|
+
label: deploymentReadyLabel(attemptProfile),
|
|
5037
5542
|
progress: 100,
|
|
5038
5543
|
status: "success",
|
|
5039
5544
|
itemHash: attemptItemHash,
|
|
5040
|
-
detail:
|
|
5545
|
+
detail: deploymentReadyDetail(
|
|
5546
|
+
attemptProfile,
|
|
5547
|
+
"The relay completed startup after a transient UI polling error. Runtime and bootstrap registration are confirmed."
|
|
5548
|
+
)
|
|
5041
5549
|
});
|
|
5042
5550
|
return;
|
|
5043
5551
|
}
|
|
@@ -5064,11 +5572,14 @@ var SponsorRelayController = class {
|
|
|
5064
5572
|
this.lastCompletedDeploymentHash = attemptItemHash;
|
|
5065
5573
|
this.emitProgress({
|
|
5066
5574
|
stage: "completed",
|
|
5067
|
-
label:
|
|
5575
|
+
label: deploymentReadyLabel(attemptProfile),
|
|
5068
5576
|
progress: 100,
|
|
5069
5577
|
status: "success",
|
|
5070
5578
|
itemHash: attemptItemHash,
|
|
5071
|
-
detail:
|
|
5579
|
+
detail: deploymentReadyDetail(
|
|
5580
|
+
attemptProfile,
|
|
5581
|
+
"The relay completed startup after a transient browser-side polling error. Runtime and bootstrap registration are confirmed."
|
|
5582
|
+
)
|
|
5072
5583
|
});
|
|
5073
5584
|
return;
|
|
5074
5585
|
}
|
|
@@ -5370,6 +5881,12 @@ export {
|
|
|
5370
5881
|
DEFAULT_INSTANCE_NAME,
|
|
5371
5882
|
DEFAULT_MANIFEST_URL,
|
|
5372
5883
|
DEFAULT_TIER_ID,
|
|
5884
|
+
DEFAULT_UCAN_STORE_ALLOWED_CAPABILITIES,
|
|
5885
|
+
DEFAULT_UCAN_STORE_MAX_DELEGATION_EXPIRATION_SECONDS,
|
|
5886
|
+
DEFAULT_UCAN_STORE_PWA_ORIGIN,
|
|
5887
|
+
DEFAULT_UCAN_STORE_SERVICE_DID,
|
|
5888
|
+
DEFAULT_UCAN_STORE_SERVICE_ORIGIN,
|
|
5889
|
+
DEFAULT_UCAN_STORE_USER_DELEGATION_EXPIRATION_SECONDS,
|
|
5373
5890
|
DEPLOYMENT_PENDING_WARNING_MS,
|
|
5374
5891
|
IDLE_DEPLOYMENT_PROGRESS,
|
|
5375
5892
|
INSTANCE_RUNTIME_PENDING_REFRESH_MS,
|