@le-space/ui 0.4.2 → 0.4.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 +3 -0
- package/react/index.js +214 -11
- package/shared/index.d.ts +4 -1
- package/shared/index.js +214 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@le-space/ui",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
4
4
|
"description": "Floating Aleph sponsor relay UI components for Svelte and React.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
"access": "public"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@le-space/browser": "0.4.
|
|
40
|
-
"@le-space/core": "0.4.
|
|
39
|
+
"@le-space/browser": "0.4.3",
|
|
40
|
+
"@le-space/core": "0.4.3",
|
|
41
41
|
"viem": "^2.38.5"
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|
package/react/index.d.ts
CHANGED
|
@@ -256,6 +256,8 @@ interface CompactBootstrapRegistrationRecord {
|
|
|
256
256
|
registrationId?: string;
|
|
257
257
|
multiaddrs: string[];
|
|
258
258
|
browserMultiaddrs?: string[];
|
|
259
|
+
ownerAddress?: string;
|
|
260
|
+
publisherAddress?: string;
|
|
259
261
|
updatedAt: number;
|
|
260
262
|
} | null;
|
|
261
263
|
}
|
|
@@ -320,6 +322,7 @@ declare class SponsorRelayController {
|
|
|
320
322
|
private patch;
|
|
321
323
|
private emitProgress;
|
|
322
324
|
private configureRelayBootstrapRegistration;
|
|
325
|
+
private cleanupStaleVmBootstrapConfigHistory;
|
|
323
326
|
private syncLatestDeploymentProgress;
|
|
324
327
|
private canSkipRuntimeRefresh;
|
|
325
328
|
private noteRuntimeRefreshResult;
|
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.4.
|
|
31
|
+
var UI_PACKAGE_VERSION = "0.4.3";
|
|
32
32
|
|
|
33
33
|
// src/shared/format.ts
|
|
34
34
|
function shortHash(value, head = 8, tail = 6) {
|
|
@@ -1741,14 +1741,15 @@ function describeRuntimeAvailability(runtime) {
|
|
|
1741
1741
|
const mappedPorts2 = runtime.mappedPorts ?? {};
|
|
1742
1742
|
const hostIpv4 = runtime.hostIpv4 ?? null;
|
|
1743
1743
|
const ipv6 = runtime.ipv6 ?? null;
|
|
1744
|
+
const executionGuestIpv6 = execution?.networking?.ipv6_ip ?? null;
|
|
1744
1745
|
const proxyUrl = runtime.proxyUrl ?? null;
|
|
1745
1746
|
const schedulerSource = runtime.allocation?.source ?? null;
|
|
1746
1747
|
const webAccessActive = runtime.webAccess?.active ?? null;
|
|
1747
1748
|
const mappedPortCount = Object.keys(mappedPorts2).length;
|
|
1748
|
-
if (hostIpv4 && mappedPortCount > 0 && runtime.requirePublicGuestIpv6ForProxy === true && proxyUrl && !isLikelyGlobalIpv6(
|
|
1749
|
+
if (hostIpv4 && mappedPortCount > 0 && runtime.requirePublicGuestIpv6ForProxy === true && proxyUrl && executionGuestIpv6 && !isLikelyGlobalIpv6(executionGuestIpv6)) {
|
|
1749
1750
|
return {
|
|
1750
1751
|
state: "execution-invalid-public-ipv6",
|
|
1751
|
-
reason: `The CRN exposed runtime networking, but the guest IPv6
|
|
1752
|
+
reason: `The CRN exposed runtime networking, but the guest IPv6 (${executionGuestIpv6}) is not globally routable. Proxy-backed HTTPS activation cannot succeed until the CRN reports a public guest IPv6.`,
|
|
1752
1753
|
schedulerSource,
|
|
1753
1754
|
executionSeen: Boolean(execution),
|
|
1754
1755
|
webAccessActive,
|
|
@@ -2698,6 +2699,7 @@ async function publishRelayBootstrapRegistration(args) {
|
|
|
2698
2699
|
var VM_BOOTSTRAP_CONFIG_AGGREGATE_KEY = "vm-bootstrap-config";
|
|
2699
2700
|
var VM_BOOTSTRAP_CONFIG_SIGNAL_REF = "vm-bootstrap-config";
|
|
2700
2701
|
var VM_BOOTSTRAP_CONFIG_SIGNAL_POST_TYPE = "vm-bootstrap-config-status";
|
|
2702
|
+
var VM_BOOTSTRAP_CONFIG_HISTORY_RETENTION_MS = 6 * 60 * 60 * 1e3;
|
|
2701
2703
|
function parseJsonObject(value) {
|
|
2702
2704
|
try {
|
|
2703
2705
|
const parsed = JSON.parse(value);
|
|
@@ -2706,6 +2708,44 @@ function parseJsonObject(value) {
|
|
|
2706
2708
|
return null;
|
|
2707
2709
|
}
|
|
2708
2710
|
}
|
|
2711
|
+
function parseTimestampMs(value) {
|
|
2712
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
2713
|
+
return value > 1e12 ? value : value * 1e3;
|
|
2714
|
+
}
|
|
2715
|
+
if (typeof value === "string" && value.trim()) {
|
|
2716
|
+
const numeric = Number(value);
|
|
2717
|
+
if (Number.isFinite(numeric)) {
|
|
2718
|
+
return numeric > 1e12 ? numeric : numeric * 1e3;
|
|
2719
|
+
}
|
|
2720
|
+
const parsed = Date.parse(value);
|
|
2721
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
2722
|
+
}
|
|
2723
|
+
return null;
|
|
2724
|
+
}
|
|
2725
|
+
function normalizeVmBootstrapConfigRecord(deploymentTokenKey, value, options = {}) {
|
|
2726
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
2727
|
+
const candidate = value;
|
|
2728
|
+
const deploymentToken = typeof candidate.deploymentToken === "string" ? candidate.deploymentToken.trim() : "";
|
|
2729
|
+
const profile = typeof candidate.profile === "string" ? candidate.profile.trim() : "";
|
|
2730
|
+
const ownerAddress = typeof candidate.ownerAddress === "string" ? candidate.ownerAddress.trim() : "";
|
|
2731
|
+
const instanceItemHash = typeof candidate.instanceItemHash === "string" ? candidate.instanceItemHash.trim() : "";
|
|
2732
|
+
const createdAt = typeof candidate.createdAt === "string" ? candidate.createdAt.trim() : "";
|
|
2733
|
+
const expiresAt = typeof candidate.expiresAt === "string" ? candidate.expiresAt.trim() : "";
|
|
2734
|
+
if (!deploymentTokenKey.trim() || !deploymentToken || deploymentToken !== deploymentTokenKey.trim() || !profile || !ownerAddress || !instanceItemHash || !createdAt || !expiresAt) {
|
|
2735
|
+
return null;
|
|
2736
|
+
}
|
|
2737
|
+
const nowMs = Math.max(0, Number(options.nowMs ?? Date.now()));
|
|
2738
|
+
const maxRecordAgeMs = Math.max(
|
|
2739
|
+
6e4,
|
|
2740
|
+
Number(options.maxRecordAgeMs ?? VM_BOOTSTRAP_CONFIG_HISTORY_RETENTION_MS)
|
|
2741
|
+
);
|
|
2742
|
+
const createdAtMs = parseTimestampMs(createdAt);
|
|
2743
|
+
const expiresAtMs = parseTimestampMs(expiresAt);
|
|
2744
|
+
if (createdAtMs == null || expiresAtMs == null) return null;
|
|
2745
|
+
if (expiresAtMs <= nowMs) return null;
|
|
2746
|
+
if (createdAtMs < nowMs - maxRecordAgeMs) return null;
|
|
2747
|
+
return candidate;
|
|
2748
|
+
}
|
|
2709
2749
|
async function fetchVmBootstrapConfigAggregate(address, options) {
|
|
2710
2750
|
const requestUrl = new URL(`/api/v0/aggregates/${address}.json`, options.apiHost ?? DEFAULT_ALEPH_API_HOST2);
|
|
2711
2751
|
requestUrl.searchParams.set("keys", VM_BOOTSTRAP_CONFIG_AGGREGATE_KEY);
|
|
@@ -2719,16 +2759,21 @@ async function fetchVmBootstrapConfigAggregate(address, options) {
|
|
|
2719
2759
|
if (!aggregate || typeof aggregate !== "object" || Array.isArray(aggregate)) return {};
|
|
2720
2760
|
return aggregate;
|
|
2721
2761
|
}
|
|
2722
|
-
function normalizeVmBootstrapConfigAggregate(aggregate) {
|
|
2762
|
+
function normalizeVmBootstrapConfigAggregate(aggregate, options = {}) {
|
|
2723
2763
|
if (!aggregate || typeof aggregate !== "object") return {};
|
|
2724
2764
|
return Object.fromEntries(
|
|
2725
|
-
Object.entries(aggregate).
|
|
2726
|
-
|
|
2727
|
-
|
|
2765
|
+
Object.entries(aggregate).map(([deploymentToken, record]) => [
|
|
2766
|
+
deploymentToken,
|
|
2767
|
+
normalizeVmBootstrapConfigRecord(deploymentToken, record, options)
|
|
2768
|
+
]).filter((entry) => entry[1] != null)
|
|
2728
2769
|
);
|
|
2729
2770
|
}
|
|
2730
2771
|
function createVmBootstrapConfigAggregateContent(args) {
|
|
2731
|
-
const
|
|
2772
|
+
const nowMs = Math.max(0, Number(args.now ?? Date.now() / 1e3) * 1e3);
|
|
2773
|
+
const content = normalizeVmBootstrapConfigAggregate(args.existingAggregate, {
|
|
2774
|
+
nowMs,
|
|
2775
|
+
maxRecordAgeMs: args.maxRecordAgeMs
|
|
2776
|
+
});
|
|
2732
2777
|
content[args.record.deploymentToken] = args.record;
|
|
2733
2778
|
return {
|
|
2734
2779
|
address: args.sender,
|
|
@@ -2773,6 +2818,55 @@ async function publishVmBootstrapConfigAggregate(args) {
|
|
|
2773
2818
|
aggregateStatus
|
|
2774
2819
|
};
|
|
2775
2820
|
}
|
|
2821
|
+
function normalizeAggregateMessageHashRecord(value) {
|
|
2822
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
2823
|
+
const candidate = value;
|
|
2824
|
+
const itemHash = typeof candidate.item_hash === "string" ? candidate.item_hash.trim() : "";
|
|
2825
|
+
if (!itemHash) return null;
|
|
2826
|
+
const content = candidate.content && typeof candidate.content === "object" && !Array.isArray(candidate.content) ? candidate.content : typeof candidate.item_content === "string" ? parseJsonObject(candidate.item_content) : null;
|
|
2827
|
+
if (!content || content.key !== VM_BOOTSTRAP_CONFIG_AGGREGATE_KEY) return null;
|
|
2828
|
+
const timeMs = parseTimestampMs(candidate.time);
|
|
2829
|
+
if (timeMs == null) return null;
|
|
2830
|
+
return { itemHash, timeMs };
|
|
2831
|
+
}
|
|
2832
|
+
async function listStaleVmBootstrapConfigAggregateMessageHashes(args) {
|
|
2833
|
+
const address = args.address.trim();
|
|
2834
|
+
if (!address) return [];
|
|
2835
|
+
const currentAggregateItemHash = args.currentAggregateItemHash?.trim() ?? "";
|
|
2836
|
+
const olderThanMs = Math.max(
|
|
2837
|
+
6e4,
|
|
2838
|
+
Number(args.olderThanMs ?? VM_BOOTSTRAP_CONFIG_HISTORY_RETENTION_MS)
|
|
2839
|
+
);
|
|
2840
|
+
const cutoffMs = Math.max(0, Number(args.nowMs ?? Date.now()) - olderThanMs);
|
|
2841
|
+
const pagination = Math.max(1, Number(args.pagination ?? 100));
|
|
2842
|
+
const maxPages = Math.max(1, Number(args.maxPages ?? 10));
|
|
2843
|
+
const hashes = /* @__PURE__ */ new Set();
|
|
2844
|
+
for (let page = 1; page <= maxPages; page += 1) {
|
|
2845
|
+
const requestUrl = new URL("/api/v0/messages.json", args.apiHost ?? DEFAULT_ALEPH_API_HOST2);
|
|
2846
|
+
requestUrl.searchParams.set("msgType", "AGGREGATE");
|
|
2847
|
+
requestUrl.searchParams.set("addresses", address);
|
|
2848
|
+
requestUrl.searchParams.set("message_statuses", "processed,pending,rejected,removing");
|
|
2849
|
+
requestUrl.searchParams.set("pagination", String(pagination));
|
|
2850
|
+
requestUrl.searchParams.set("page", String(page));
|
|
2851
|
+
requestUrl.searchParams.set("sortOrder", "-1");
|
|
2852
|
+
const response = await args.fetch(requestUrl.toString(), { cache: "no-cache" });
|
|
2853
|
+
if (!response.ok) {
|
|
2854
|
+
throw new Error(`VM bootstrap config aggregate history request failed: ${response.status}`);
|
|
2855
|
+
}
|
|
2856
|
+
const payload = await response.json();
|
|
2857
|
+
const messages = Array.isArray(payload.messages) ? payload.messages : [];
|
|
2858
|
+
if (messages.length === 0) break;
|
|
2859
|
+
for (const message of messages) {
|
|
2860
|
+
const normalized = normalizeAggregateMessageHashRecord(message);
|
|
2861
|
+
if (!normalized) continue;
|
|
2862
|
+
if (normalized.itemHash === currentAggregateItemHash) continue;
|
|
2863
|
+
if (normalized.timeMs > cutoffMs) continue;
|
|
2864
|
+
hashes.add(normalized.itemHash);
|
|
2865
|
+
}
|
|
2866
|
+
if (messages.length < pagination) break;
|
|
2867
|
+
}
|
|
2868
|
+
return [...hashes];
|
|
2869
|
+
}
|
|
2776
2870
|
async function publishVmBootstrapConfig(args) {
|
|
2777
2871
|
const aggregate = await fetchVmBootstrapConfigAggregate(args.sender, {
|
|
2778
2872
|
apiHost: args.apiHost,
|
|
@@ -2781,7 +2875,8 @@ async function publishVmBootstrapConfig(args) {
|
|
|
2781
2875
|
const content = createVmBootstrapConfigAggregateContent({
|
|
2782
2876
|
sender: args.sender,
|
|
2783
2877
|
record: args.record,
|
|
2784
|
-
existingAggregate: aggregate
|
|
2878
|
+
existingAggregate: aggregate,
|
|
2879
|
+
maxRecordAgeMs: VM_BOOTSTRAP_CONFIG_HISTORY_RETENTION_MS
|
|
2785
2880
|
});
|
|
2786
2881
|
const result = await publishVmBootstrapConfigAggregate({
|
|
2787
2882
|
sender: args.sender,
|
|
@@ -2803,7 +2898,9 @@ async function deleteVmBootstrapConfig(args) {
|
|
|
2803
2898
|
apiHost: args.apiHost,
|
|
2804
2899
|
fetch: args.fetch
|
|
2805
2900
|
});
|
|
2806
|
-
const content = normalizeVmBootstrapConfigAggregate(aggregate
|
|
2901
|
+
const content = normalizeVmBootstrapConfigAggregate(aggregate, {
|
|
2902
|
+
maxRecordAgeMs: VM_BOOTSTRAP_CONFIG_HISTORY_RETENTION_MS
|
|
2903
|
+
});
|
|
2807
2904
|
delete content[args.deploymentToken];
|
|
2808
2905
|
const publishResult = await publishVmBootstrapConfigAggregate({
|
|
2809
2906
|
sender: args.sender,
|
|
@@ -3167,6 +3264,22 @@ function relayBootstrapInstanceItemHash(entry) {
|
|
|
3167
3264
|
}
|
|
3168
3265
|
return registrationIdInstanceItemHash(entry?.content?.registrationId);
|
|
3169
3266
|
}
|
|
3267
|
+
function relayBootstrapMatchesCurrentWallet(entry, normalizedWalletAddress, activeInstanceHashes) {
|
|
3268
|
+
const instanceItemHash = relayBootstrapInstanceItemHash(entry);
|
|
3269
|
+
if (instanceItemHash && activeInstanceHashes.has(instanceItemHash)) {
|
|
3270
|
+
return true;
|
|
3271
|
+
}
|
|
3272
|
+
const candidateAddresses = [
|
|
3273
|
+
entry?.address,
|
|
3274
|
+
entry?.content?.ownerAddress,
|
|
3275
|
+
entry?.content?.authorization?.payload?.ownerAddress,
|
|
3276
|
+
entry?.content?.publisherAddress,
|
|
3277
|
+
entry?.content?.authorization?.payload?.publisherAddress
|
|
3278
|
+
];
|
|
3279
|
+
return candidateAddresses.some(
|
|
3280
|
+
(value) => typeof value === "string" && value.trim().toLowerCase() === normalizedWalletAddress
|
|
3281
|
+
);
|
|
3282
|
+
}
|
|
3170
3283
|
async function inspectInstanceRuntime(args) {
|
|
3171
3284
|
const details = {
|
|
3172
3285
|
messageStatus: String(
|
|
@@ -3790,6 +3903,7 @@ var SponsorRelayController = class {
|
|
|
3790
3903
|
}
|
|
3791
3904
|
}
|
|
3792
3905
|
if (profile === "uc-go-peer" && args.deploymentToken) {
|
|
3906
|
+
let cleanupAggregateItemHash = null;
|
|
3793
3907
|
await deleteVmBootstrapConfig({
|
|
3794
3908
|
sender: this.state.wallet.address,
|
|
3795
3909
|
deploymentToken: args.deploymentToken,
|
|
@@ -3798,6 +3912,14 @@ var SponsorRelayController = class {
|
|
|
3798
3912
|
fetch: asJsonFetch,
|
|
3799
3913
|
apiHost: this.client.apiHost,
|
|
3800
3914
|
sync: true
|
|
3915
|
+
}).then((cleanupResult) => {
|
|
3916
|
+
cleanupAggregateItemHash = cleanupResult.aggregateItemHash;
|
|
3917
|
+
this.trace("deploy:bootstrap-config-cleanup-complete", {
|
|
3918
|
+
itemHash: args.itemHash,
|
|
3919
|
+
deploymentToken: args.deploymentToken,
|
|
3920
|
+
aggregateItemHash: cleanupResult.aggregateItemHash,
|
|
3921
|
+
aggregateStatus: cleanupResult.aggregateStatus
|
|
3922
|
+
});
|
|
3801
3923
|
}).catch((error) => {
|
|
3802
3924
|
this.trace("deploy:bootstrap-config-cleanup-error", {
|
|
3803
3925
|
itemHash: args.itemHash,
|
|
@@ -3805,8 +3927,75 @@ var SponsorRelayController = class {
|
|
|
3805
3927
|
error: error instanceof Error ? error.message : String(error)
|
|
3806
3928
|
});
|
|
3807
3929
|
});
|
|
3930
|
+
await this.cleanupStaleVmBootstrapConfigHistory({
|
|
3931
|
+
itemHash: args.itemHash,
|
|
3932
|
+
currentAggregateItemHash: cleanupAggregateItemHash,
|
|
3933
|
+
stage: "publishing-bootstrap",
|
|
3934
|
+
progress: 99
|
|
3935
|
+
});
|
|
3808
3936
|
}
|
|
3809
3937
|
}
|
|
3938
|
+
async cleanupStaleVmBootstrapConfigHistory(args) {
|
|
3939
|
+
if (!this.state.wallet.address || !args.currentAggregateItemHash) {
|
|
3940
|
+
return;
|
|
3941
|
+
}
|
|
3942
|
+
const staleHashes = await listStaleVmBootstrapConfigAggregateMessageHashes({
|
|
3943
|
+
address: this.state.wallet.address,
|
|
3944
|
+
currentAggregateItemHash: args.currentAggregateItemHash,
|
|
3945
|
+
olderThanMs: VM_BOOTSTRAP_CONFIG_HISTORY_RETENTION_MS,
|
|
3946
|
+
fetch: asJsonFetch,
|
|
3947
|
+
apiHost: this.client.apiHost
|
|
3948
|
+
}).catch((error) => {
|
|
3949
|
+
this.trace("deploy:bootstrap-config-history-scan-error", {
|
|
3950
|
+
itemHash: args.itemHash,
|
|
3951
|
+
currentAggregateItemHash: args.currentAggregateItemHash,
|
|
3952
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3953
|
+
});
|
|
3954
|
+
return [];
|
|
3955
|
+
});
|
|
3956
|
+
if (staleHashes.length === 0) {
|
|
3957
|
+
return;
|
|
3958
|
+
}
|
|
3959
|
+
const staleCount = staleHashes.length;
|
|
3960
|
+
this.emitProgress({
|
|
3961
|
+
stage: args.stage,
|
|
3962
|
+
label: "Cleaning up stale handoff history",
|
|
3963
|
+
progress: args.progress,
|
|
3964
|
+
status: "warning",
|
|
3965
|
+
itemHash: args.itemHash,
|
|
3966
|
+
detail: `Forgetting ${staleCount} superseded Aleph handoff aggregate message${staleCount === 1 ? "" : "s"} older than 6 hours. MetaMask may request another cleanup signature.`
|
|
3967
|
+
});
|
|
3968
|
+
this.trace("deploy:bootstrap-config-history-cleanup-start", {
|
|
3969
|
+
itemHash: args.itemHash,
|
|
3970
|
+
currentAggregateItemHash: args.currentAggregateItemHash,
|
|
3971
|
+
staleHashes
|
|
3972
|
+
});
|
|
3973
|
+
await forgetAlephMessages({
|
|
3974
|
+
sender: this.state.wallet.address,
|
|
3975
|
+
hashes: staleHashes,
|
|
3976
|
+
reason: "Prune stale vm-bootstrap-config aggregate history older than 6 hours",
|
|
3977
|
+
signer: personalSign,
|
|
3978
|
+
hasher: sha256Hex,
|
|
3979
|
+
fetch: asJsonFetch,
|
|
3980
|
+
apiHost: this.client.apiHost,
|
|
3981
|
+
sync: true
|
|
3982
|
+
}).then((cleanupResult) => {
|
|
3983
|
+
this.trace("deploy:bootstrap-config-history-cleanup-complete", {
|
|
3984
|
+
itemHash: args.itemHash,
|
|
3985
|
+
currentAggregateItemHash: args.currentAggregateItemHash,
|
|
3986
|
+
staleHashes,
|
|
3987
|
+
forgetItemHash: cleanupResult.itemHash,
|
|
3988
|
+
forgetStatus: cleanupResult.status
|
|
3989
|
+
});
|
|
3990
|
+
}).catch((error) => {
|
|
3991
|
+
this.trace("deploy:bootstrap-config-history-cleanup-error", {
|
|
3992
|
+
itemHash: args.itemHash,
|
|
3993
|
+
currentAggregateItemHash: args.currentAggregateItemHash,
|
|
3994
|
+
staleHashes,
|
|
3995
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3996
|
+
});
|
|
3997
|
+
});
|
|
3998
|
+
}
|
|
3810
3999
|
syncLatestDeploymentProgress(instances) {
|
|
3811
4000
|
const itemHash = this.state.lastDeploymentHash;
|
|
3812
4001
|
if (!itemHash) {
|
|
@@ -4182,7 +4371,11 @@ var SponsorRelayController = class {
|
|
|
4182
4371
|
instances.map((entry) => entry.instance.item_hash)
|
|
4183
4372
|
);
|
|
4184
4373
|
bootstrapRegistrations = selectCurrentRelayBootstrapPosts(rawBootstrapPosts).filter(
|
|
4185
|
-
(entry) =>
|
|
4374
|
+
(entry) => relayBootstrapMatchesCurrentWallet(
|
|
4375
|
+
entry,
|
|
4376
|
+
normalizedWalletAddress,
|
|
4377
|
+
activeInstanceHashes
|
|
4378
|
+
)
|
|
4186
4379
|
).map((entry) => {
|
|
4187
4380
|
const instanceItemHash = relayBootstrapInstanceItemHash(entry);
|
|
4188
4381
|
const messageHash = entry.itemHash ?? entry.hash ?? null;
|
|
@@ -4201,6 +4394,8 @@ var SponsorRelayController = class {
|
|
|
4201
4394
|
registrationId: entry.content.registrationId,
|
|
4202
4395
|
multiaddrs: Array.isArray(entry.content.multiaddrs) ? entry.content.multiaddrs : [],
|
|
4203
4396
|
browserMultiaddrs: Array.isArray(entry.content.browserMultiaddrs) ? entry.content.browserMultiaddrs : [],
|
|
4397
|
+
ownerAddress: typeof entry.content.ownerAddress === "string" ? entry.content.ownerAddress : void 0,
|
|
4398
|
+
publisherAddress: typeof entry.content.publisherAddress === "string" ? entry.content.publisherAddress : void 0,
|
|
4204
4399
|
updatedAt: entry.content.updatedAt
|
|
4205
4400
|
} : null
|
|
4206
4401
|
};
|
|
@@ -4572,6 +4767,7 @@ var SponsorRelayController = class {
|
|
|
4572
4767
|
detail: failedDueToInvalidIpv6 ? `${attemptLabel} exposed runtime networking that cannot support proxy-backed HTTPS. Cleaning up this attempt before retrying another CRN.` : `${attemptLabel} failed: ${lastError.message} Cleaning up this attempt before retrying another CRN.`
|
|
4573
4768
|
});
|
|
4574
4769
|
if (attemptDeploymentToken) {
|
|
4770
|
+
let cleanupAggregateItemHash = null;
|
|
4575
4771
|
this.emitProgress({
|
|
4576
4772
|
stage: "deployment-confirmed",
|
|
4577
4773
|
label: "Cleaning up failed attempt",
|
|
@@ -4593,6 +4789,7 @@ var SponsorRelayController = class {
|
|
|
4593
4789
|
apiHost: this.client.apiHost,
|
|
4594
4790
|
sync: true
|
|
4595
4791
|
}).then((cleanupResult) => {
|
|
4792
|
+
cleanupAggregateItemHash = cleanupResult.aggregateItemHash;
|
|
4596
4793
|
this.trace("deploy:bootstrap-config-cleanup-complete", {
|
|
4597
4794
|
itemHash: attemptItemHash,
|
|
4598
4795
|
deploymentToken: attemptDeploymentToken,
|
|
@@ -4606,6 +4803,12 @@ var SponsorRelayController = class {
|
|
|
4606
4803
|
error: cleanupError instanceof Error ? cleanupError.message : String(cleanupError)
|
|
4607
4804
|
});
|
|
4608
4805
|
});
|
|
4806
|
+
await this.cleanupStaleVmBootstrapConfigHistory({
|
|
4807
|
+
itemHash: attemptItemHash,
|
|
4808
|
+
currentAggregateItemHash: cleanupAggregateItemHash,
|
|
4809
|
+
stage: "deployment-confirmed",
|
|
4810
|
+
progress: 18
|
|
4811
|
+
});
|
|
4609
4812
|
}
|
|
4610
4813
|
this.emitProgress({
|
|
4611
4814
|
stage: "deployment-confirmed",
|
package/shared/index.d.ts
CHANGED
|
@@ -254,6 +254,8 @@ interface CompactBootstrapRegistrationRecord {
|
|
|
254
254
|
registrationId?: string;
|
|
255
255
|
multiaddrs: string[];
|
|
256
256
|
browserMultiaddrs?: string[];
|
|
257
|
+
ownerAddress?: string;
|
|
258
|
+
publisherAddress?: string;
|
|
257
259
|
updatedAt: number;
|
|
258
260
|
} | null;
|
|
259
261
|
}
|
|
@@ -309,7 +311,7 @@ declare const STALE_INSTANCE_ALLOCATION_COOLDOWN_MS: number;
|
|
|
309
311
|
declare const RECENT_INSTANCE_RUNTIME_GRACE_MS: number;
|
|
310
312
|
declare const DEPLOYMENT_PENDING_WARNING_MS: number;
|
|
311
313
|
|
|
312
|
-
declare const UI_PACKAGE_VERSION = "0.4.
|
|
314
|
+
declare const UI_PACKAGE_VERSION = "0.4.3";
|
|
313
315
|
|
|
314
316
|
interface RootfsRequiredPortForward {
|
|
315
317
|
port: number;
|
|
@@ -368,6 +370,7 @@ declare class SponsorRelayController {
|
|
|
368
370
|
private patch;
|
|
369
371
|
private emitProgress;
|
|
370
372
|
private configureRelayBootstrapRegistration;
|
|
373
|
+
private cleanupStaleVmBootstrapConfigHistory;
|
|
371
374
|
private syncLatestDeploymentProgress;
|
|
372
375
|
private canSkipRuntimeRefresh;
|
|
373
376
|
private noteRuntimeRefreshResult;
|
package/shared/index.js
CHANGED
|
@@ -27,7 +27,7 @@ var RECENT_INSTANCE_RUNTIME_GRACE_MS = 10 * 60 * 1e3;
|
|
|
27
27
|
var DEPLOYMENT_PENDING_WARNING_MS = 3 * 60 * 1e3;
|
|
28
28
|
|
|
29
29
|
// src/shared/package-version.ts
|
|
30
|
-
var UI_PACKAGE_VERSION = "0.4.
|
|
30
|
+
var UI_PACKAGE_VERSION = "0.4.3";
|
|
31
31
|
|
|
32
32
|
// src/shared/format.ts
|
|
33
33
|
function shortHash(value, head = 8, tail = 6) {
|
|
@@ -1740,14 +1740,15 @@ function describeRuntimeAvailability(runtime) {
|
|
|
1740
1740
|
const mappedPorts2 = runtime.mappedPorts ?? {};
|
|
1741
1741
|
const hostIpv4 = runtime.hostIpv4 ?? null;
|
|
1742
1742
|
const ipv6 = runtime.ipv6 ?? null;
|
|
1743
|
+
const executionGuestIpv6 = execution?.networking?.ipv6_ip ?? null;
|
|
1743
1744
|
const proxyUrl = runtime.proxyUrl ?? null;
|
|
1744
1745
|
const schedulerSource = runtime.allocation?.source ?? null;
|
|
1745
1746
|
const webAccessActive = runtime.webAccess?.active ?? null;
|
|
1746
1747
|
const mappedPortCount = Object.keys(mappedPorts2).length;
|
|
1747
|
-
if (hostIpv4 && mappedPortCount > 0 && runtime.requirePublicGuestIpv6ForProxy === true && proxyUrl && !isLikelyGlobalIpv6(
|
|
1748
|
+
if (hostIpv4 && mappedPortCount > 0 && runtime.requirePublicGuestIpv6ForProxy === true && proxyUrl && executionGuestIpv6 && !isLikelyGlobalIpv6(executionGuestIpv6)) {
|
|
1748
1749
|
return {
|
|
1749
1750
|
state: "execution-invalid-public-ipv6",
|
|
1750
|
-
reason: `The CRN exposed runtime networking, but the guest IPv6
|
|
1751
|
+
reason: `The CRN exposed runtime networking, but the guest IPv6 (${executionGuestIpv6}) is not globally routable. Proxy-backed HTTPS activation cannot succeed until the CRN reports a public guest IPv6.`,
|
|
1751
1752
|
schedulerSource,
|
|
1752
1753
|
executionSeen: Boolean(execution),
|
|
1753
1754
|
webAccessActive,
|
|
@@ -2697,6 +2698,7 @@ async function publishRelayBootstrapRegistration(args) {
|
|
|
2697
2698
|
var VM_BOOTSTRAP_CONFIG_AGGREGATE_KEY = "vm-bootstrap-config";
|
|
2698
2699
|
var VM_BOOTSTRAP_CONFIG_SIGNAL_REF = "vm-bootstrap-config";
|
|
2699
2700
|
var VM_BOOTSTRAP_CONFIG_SIGNAL_POST_TYPE = "vm-bootstrap-config-status";
|
|
2701
|
+
var VM_BOOTSTRAP_CONFIG_HISTORY_RETENTION_MS = 6 * 60 * 60 * 1e3;
|
|
2700
2702
|
function parseJsonObject(value) {
|
|
2701
2703
|
try {
|
|
2702
2704
|
const parsed = JSON.parse(value);
|
|
@@ -2705,6 +2707,44 @@ function parseJsonObject(value) {
|
|
|
2705
2707
|
return null;
|
|
2706
2708
|
}
|
|
2707
2709
|
}
|
|
2710
|
+
function parseTimestampMs(value) {
|
|
2711
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
2712
|
+
return value > 1e12 ? value : value * 1e3;
|
|
2713
|
+
}
|
|
2714
|
+
if (typeof value === "string" && value.trim()) {
|
|
2715
|
+
const numeric = Number(value);
|
|
2716
|
+
if (Number.isFinite(numeric)) {
|
|
2717
|
+
return numeric > 1e12 ? numeric : numeric * 1e3;
|
|
2718
|
+
}
|
|
2719
|
+
const parsed = Date.parse(value);
|
|
2720
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
2721
|
+
}
|
|
2722
|
+
return null;
|
|
2723
|
+
}
|
|
2724
|
+
function normalizeVmBootstrapConfigRecord(deploymentTokenKey, value, options = {}) {
|
|
2725
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
2726
|
+
const candidate = value;
|
|
2727
|
+
const deploymentToken = typeof candidate.deploymentToken === "string" ? candidate.deploymentToken.trim() : "";
|
|
2728
|
+
const profile = typeof candidate.profile === "string" ? candidate.profile.trim() : "";
|
|
2729
|
+
const ownerAddress = typeof candidate.ownerAddress === "string" ? candidate.ownerAddress.trim() : "";
|
|
2730
|
+
const instanceItemHash = typeof candidate.instanceItemHash === "string" ? candidate.instanceItemHash.trim() : "";
|
|
2731
|
+
const createdAt = typeof candidate.createdAt === "string" ? candidate.createdAt.trim() : "";
|
|
2732
|
+
const expiresAt = typeof candidate.expiresAt === "string" ? candidate.expiresAt.trim() : "";
|
|
2733
|
+
if (!deploymentTokenKey.trim() || !deploymentToken || deploymentToken !== deploymentTokenKey.trim() || !profile || !ownerAddress || !instanceItemHash || !createdAt || !expiresAt) {
|
|
2734
|
+
return null;
|
|
2735
|
+
}
|
|
2736
|
+
const nowMs = Math.max(0, Number(options.nowMs ?? Date.now()));
|
|
2737
|
+
const maxRecordAgeMs = Math.max(
|
|
2738
|
+
6e4,
|
|
2739
|
+
Number(options.maxRecordAgeMs ?? VM_BOOTSTRAP_CONFIG_HISTORY_RETENTION_MS)
|
|
2740
|
+
);
|
|
2741
|
+
const createdAtMs = parseTimestampMs(createdAt);
|
|
2742
|
+
const expiresAtMs = parseTimestampMs(expiresAt);
|
|
2743
|
+
if (createdAtMs == null || expiresAtMs == null) return null;
|
|
2744
|
+
if (expiresAtMs <= nowMs) return null;
|
|
2745
|
+
if (createdAtMs < nowMs - maxRecordAgeMs) return null;
|
|
2746
|
+
return candidate;
|
|
2747
|
+
}
|
|
2708
2748
|
async function fetchVmBootstrapConfigAggregate(address, options) {
|
|
2709
2749
|
const requestUrl = new URL(`/api/v0/aggregates/${address}.json`, options.apiHost ?? DEFAULT_ALEPH_API_HOST2);
|
|
2710
2750
|
requestUrl.searchParams.set("keys", VM_BOOTSTRAP_CONFIG_AGGREGATE_KEY);
|
|
@@ -2718,16 +2758,21 @@ async function fetchVmBootstrapConfigAggregate(address, options) {
|
|
|
2718
2758
|
if (!aggregate || typeof aggregate !== "object" || Array.isArray(aggregate)) return {};
|
|
2719
2759
|
return aggregate;
|
|
2720
2760
|
}
|
|
2721
|
-
function normalizeVmBootstrapConfigAggregate(aggregate) {
|
|
2761
|
+
function normalizeVmBootstrapConfigAggregate(aggregate, options = {}) {
|
|
2722
2762
|
if (!aggregate || typeof aggregate !== "object") return {};
|
|
2723
2763
|
return Object.fromEntries(
|
|
2724
|
-
Object.entries(aggregate).
|
|
2725
|
-
|
|
2726
|
-
|
|
2764
|
+
Object.entries(aggregate).map(([deploymentToken, record]) => [
|
|
2765
|
+
deploymentToken,
|
|
2766
|
+
normalizeVmBootstrapConfigRecord(deploymentToken, record, options)
|
|
2767
|
+
]).filter((entry) => entry[1] != null)
|
|
2727
2768
|
);
|
|
2728
2769
|
}
|
|
2729
2770
|
function createVmBootstrapConfigAggregateContent(args) {
|
|
2730
|
-
const
|
|
2771
|
+
const nowMs = Math.max(0, Number(args.now ?? Date.now() / 1e3) * 1e3);
|
|
2772
|
+
const content = normalizeVmBootstrapConfigAggregate(args.existingAggregate, {
|
|
2773
|
+
nowMs,
|
|
2774
|
+
maxRecordAgeMs: args.maxRecordAgeMs
|
|
2775
|
+
});
|
|
2731
2776
|
content[args.record.deploymentToken] = args.record;
|
|
2732
2777
|
return {
|
|
2733
2778
|
address: args.sender,
|
|
@@ -2772,6 +2817,55 @@ async function publishVmBootstrapConfigAggregate(args) {
|
|
|
2772
2817
|
aggregateStatus
|
|
2773
2818
|
};
|
|
2774
2819
|
}
|
|
2820
|
+
function normalizeAggregateMessageHashRecord(value) {
|
|
2821
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
2822
|
+
const candidate = value;
|
|
2823
|
+
const itemHash = typeof candidate.item_hash === "string" ? candidate.item_hash.trim() : "";
|
|
2824
|
+
if (!itemHash) return null;
|
|
2825
|
+
const content = candidate.content && typeof candidate.content === "object" && !Array.isArray(candidate.content) ? candidate.content : typeof candidate.item_content === "string" ? parseJsonObject(candidate.item_content) : null;
|
|
2826
|
+
if (!content || content.key !== VM_BOOTSTRAP_CONFIG_AGGREGATE_KEY) return null;
|
|
2827
|
+
const timeMs = parseTimestampMs(candidate.time);
|
|
2828
|
+
if (timeMs == null) return null;
|
|
2829
|
+
return { itemHash, timeMs };
|
|
2830
|
+
}
|
|
2831
|
+
async function listStaleVmBootstrapConfigAggregateMessageHashes(args) {
|
|
2832
|
+
const address = args.address.trim();
|
|
2833
|
+
if (!address) return [];
|
|
2834
|
+
const currentAggregateItemHash = args.currentAggregateItemHash?.trim() ?? "";
|
|
2835
|
+
const olderThanMs = Math.max(
|
|
2836
|
+
6e4,
|
|
2837
|
+
Number(args.olderThanMs ?? VM_BOOTSTRAP_CONFIG_HISTORY_RETENTION_MS)
|
|
2838
|
+
);
|
|
2839
|
+
const cutoffMs = Math.max(0, Number(args.nowMs ?? Date.now()) - olderThanMs);
|
|
2840
|
+
const pagination = Math.max(1, Number(args.pagination ?? 100));
|
|
2841
|
+
const maxPages = Math.max(1, Number(args.maxPages ?? 10));
|
|
2842
|
+
const hashes = /* @__PURE__ */ new Set();
|
|
2843
|
+
for (let page = 1; page <= maxPages; page += 1) {
|
|
2844
|
+
const requestUrl = new URL("/api/v0/messages.json", args.apiHost ?? DEFAULT_ALEPH_API_HOST2);
|
|
2845
|
+
requestUrl.searchParams.set("msgType", "AGGREGATE");
|
|
2846
|
+
requestUrl.searchParams.set("addresses", address);
|
|
2847
|
+
requestUrl.searchParams.set("message_statuses", "processed,pending,rejected,removing");
|
|
2848
|
+
requestUrl.searchParams.set("pagination", String(pagination));
|
|
2849
|
+
requestUrl.searchParams.set("page", String(page));
|
|
2850
|
+
requestUrl.searchParams.set("sortOrder", "-1");
|
|
2851
|
+
const response = await args.fetch(requestUrl.toString(), { cache: "no-cache" });
|
|
2852
|
+
if (!response.ok) {
|
|
2853
|
+
throw new Error(`VM bootstrap config aggregate history request failed: ${response.status}`);
|
|
2854
|
+
}
|
|
2855
|
+
const payload = await response.json();
|
|
2856
|
+
const messages = Array.isArray(payload.messages) ? payload.messages : [];
|
|
2857
|
+
if (messages.length === 0) break;
|
|
2858
|
+
for (const message of messages) {
|
|
2859
|
+
const normalized = normalizeAggregateMessageHashRecord(message);
|
|
2860
|
+
if (!normalized) continue;
|
|
2861
|
+
if (normalized.itemHash === currentAggregateItemHash) continue;
|
|
2862
|
+
if (normalized.timeMs > cutoffMs) continue;
|
|
2863
|
+
hashes.add(normalized.itemHash);
|
|
2864
|
+
}
|
|
2865
|
+
if (messages.length < pagination) break;
|
|
2866
|
+
}
|
|
2867
|
+
return [...hashes];
|
|
2868
|
+
}
|
|
2775
2869
|
async function publishVmBootstrapConfig(args) {
|
|
2776
2870
|
const aggregate = await fetchVmBootstrapConfigAggregate(args.sender, {
|
|
2777
2871
|
apiHost: args.apiHost,
|
|
@@ -2780,7 +2874,8 @@ async function publishVmBootstrapConfig(args) {
|
|
|
2780
2874
|
const content = createVmBootstrapConfigAggregateContent({
|
|
2781
2875
|
sender: args.sender,
|
|
2782
2876
|
record: args.record,
|
|
2783
|
-
existingAggregate: aggregate
|
|
2877
|
+
existingAggregate: aggregate,
|
|
2878
|
+
maxRecordAgeMs: VM_BOOTSTRAP_CONFIG_HISTORY_RETENTION_MS
|
|
2784
2879
|
});
|
|
2785
2880
|
const result = await publishVmBootstrapConfigAggregate({
|
|
2786
2881
|
sender: args.sender,
|
|
@@ -2802,7 +2897,9 @@ async function deleteVmBootstrapConfig(args) {
|
|
|
2802
2897
|
apiHost: args.apiHost,
|
|
2803
2898
|
fetch: args.fetch
|
|
2804
2899
|
});
|
|
2805
|
-
const content = normalizeVmBootstrapConfigAggregate(aggregate
|
|
2900
|
+
const content = normalizeVmBootstrapConfigAggregate(aggregate, {
|
|
2901
|
+
maxRecordAgeMs: VM_BOOTSTRAP_CONFIG_HISTORY_RETENTION_MS
|
|
2902
|
+
});
|
|
2806
2903
|
delete content[args.deploymentToken];
|
|
2807
2904
|
const publishResult = await publishVmBootstrapConfigAggregate({
|
|
2808
2905
|
sender: args.sender,
|
|
@@ -3166,6 +3263,22 @@ function relayBootstrapInstanceItemHash(entry) {
|
|
|
3166
3263
|
}
|
|
3167
3264
|
return registrationIdInstanceItemHash(entry?.content?.registrationId);
|
|
3168
3265
|
}
|
|
3266
|
+
function relayBootstrapMatchesCurrentWallet(entry, normalizedWalletAddress, activeInstanceHashes) {
|
|
3267
|
+
const instanceItemHash = relayBootstrapInstanceItemHash(entry);
|
|
3268
|
+
if (instanceItemHash && activeInstanceHashes.has(instanceItemHash)) {
|
|
3269
|
+
return true;
|
|
3270
|
+
}
|
|
3271
|
+
const candidateAddresses = [
|
|
3272
|
+
entry?.address,
|
|
3273
|
+
entry?.content?.ownerAddress,
|
|
3274
|
+
entry?.content?.authorization?.payload?.ownerAddress,
|
|
3275
|
+
entry?.content?.publisherAddress,
|
|
3276
|
+
entry?.content?.authorization?.payload?.publisherAddress
|
|
3277
|
+
];
|
|
3278
|
+
return candidateAddresses.some(
|
|
3279
|
+
(value) => typeof value === "string" && value.trim().toLowerCase() === normalizedWalletAddress
|
|
3280
|
+
);
|
|
3281
|
+
}
|
|
3169
3282
|
async function inspectInstanceRuntime(args) {
|
|
3170
3283
|
const details = {
|
|
3171
3284
|
messageStatus: String(
|
|
@@ -3789,6 +3902,7 @@ var SponsorRelayController = class {
|
|
|
3789
3902
|
}
|
|
3790
3903
|
}
|
|
3791
3904
|
if (profile === "uc-go-peer" && args.deploymentToken) {
|
|
3905
|
+
let cleanupAggregateItemHash = null;
|
|
3792
3906
|
await deleteVmBootstrapConfig({
|
|
3793
3907
|
sender: this.state.wallet.address,
|
|
3794
3908
|
deploymentToken: args.deploymentToken,
|
|
@@ -3797,6 +3911,14 @@ var SponsorRelayController = class {
|
|
|
3797
3911
|
fetch: asJsonFetch,
|
|
3798
3912
|
apiHost: this.client.apiHost,
|
|
3799
3913
|
sync: true
|
|
3914
|
+
}).then((cleanupResult) => {
|
|
3915
|
+
cleanupAggregateItemHash = cleanupResult.aggregateItemHash;
|
|
3916
|
+
this.trace("deploy:bootstrap-config-cleanup-complete", {
|
|
3917
|
+
itemHash: args.itemHash,
|
|
3918
|
+
deploymentToken: args.deploymentToken,
|
|
3919
|
+
aggregateItemHash: cleanupResult.aggregateItemHash,
|
|
3920
|
+
aggregateStatus: cleanupResult.aggregateStatus
|
|
3921
|
+
});
|
|
3800
3922
|
}).catch((error) => {
|
|
3801
3923
|
this.trace("deploy:bootstrap-config-cleanup-error", {
|
|
3802
3924
|
itemHash: args.itemHash,
|
|
@@ -3804,8 +3926,75 @@ var SponsorRelayController = class {
|
|
|
3804
3926
|
error: error instanceof Error ? error.message : String(error)
|
|
3805
3927
|
});
|
|
3806
3928
|
});
|
|
3929
|
+
await this.cleanupStaleVmBootstrapConfigHistory({
|
|
3930
|
+
itemHash: args.itemHash,
|
|
3931
|
+
currentAggregateItemHash: cleanupAggregateItemHash,
|
|
3932
|
+
stage: "publishing-bootstrap",
|
|
3933
|
+
progress: 99
|
|
3934
|
+
});
|
|
3807
3935
|
}
|
|
3808
3936
|
}
|
|
3937
|
+
async cleanupStaleVmBootstrapConfigHistory(args) {
|
|
3938
|
+
if (!this.state.wallet.address || !args.currentAggregateItemHash) {
|
|
3939
|
+
return;
|
|
3940
|
+
}
|
|
3941
|
+
const staleHashes = await listStaleVmBootstrapConfigAggregateMessageHashes({
|
|
3942
|
+
address: this.state.wallet.address,
|
|
3943
|
+
currentAggregateItemHash: args.currentAggregateItemHash,
|
|
3944
|
+
olderThanMs: VM_BOOTSTRAP_CONFIG_HISTORY_RETENTION_MS,
|
|
3945
|
+
fetch: asJsonFetch,
|
|
3946
|
+
apiHost: this.client.apiHost
|
|
3947
|
+
}).catch((error) => {
|
|
3948
|
+
this.trace("deploy:bootstrap-config-history-scan-error", {
|
|
3949
|
+
itemHash: args.itemHash,
|
|
3950
|
+
currentAggregateItemHash: args.currentAggregateItemHash,
|
|
3951
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3952
|
+
});
|
|
3953
|
+
return [];
|
|
3954
|
+
});
|
|
3955
|
+
if (staleHashes.length === 0) {
|
|
3956
|
+
return;
|
|
3957
|
+
}
|
|
3958
|
+
const staleCount = staleHashes.length;
|
|
3959
|
+
this.emitProgress({
|
|
3960
|
+
stage: args.stage,
|
|
3961
|
+
label: "Cleaning up stale handoff history",
|
|
3962
|
+
progress: args.progress,
|
|
3963
|
+
status: "warning",
|
|
3964
|
+
itemHash: args.itemHash,
|
|
3965
|
+
detail: `Forgetting ${staleCount} superseded Aleph handoff aggregate message${staleCount === 1 ? "" : "s"} older than 6 hours. MetaMask may request another cleanup signature.`
|
|
3966
|
+
});
|
|
3967
|
+
this.trace("deploy:bootstrap-config-history-cleanup-start", {
|
|
3968
|
+
itemHash: args.itemHash,
|
|
3969
|
+
currentAggregateItemHash: args.currentAggregateItemHash,
|
|
3970
|
+
staleHashes
|
|
3971
|
+
});
|
|
3972
|
+
await forgetAlephMessages({
|
|
3973
|
+
sender: this.state.wallet.address,
|
|
3974
|
+
hashes: staleHashes,
|
|
3975
|
+
reason: "Prune stale vm-bootstrap-config aggregate history older than 6 hours",
|
|
3976
|
+
signer: personalSign,
|
|
3977
|
+
hasher: sha256Hex,
|
|
3978
|
+
fetch: asJsonFetch,
|
|
3979
|
+
apiHost: this.client.apiHost,
|
|
3980
|
+
sync: true
|
|
3981
|
+
}).then((cleanupResult) => {
|
|
3982
|
+
this.trace("deploy:bootstrap-config-history-cleanup-complete", {
|
|
3983
|
+
itemHash: args.itemHash,
|
|
3984
|
+
currentAggregateItemHash: args.currentAggregateItemHash,
|
|
3985
|
+
staleHashes,
|
|
3986
|
+
forgetItemHash: cleanupResult.itemHash,
|
|
3987
|
+
forgetStatus: cleanupResult.status
|
|
3988
|
+
});
|
|
3989
|
+
}).catch((error) => {
|
|
3990
|
+
this.trace("deploy:bootstrap-config-history-cleanup-error", {
|
|
3991
|
+
itemHash: args.itemHash,
|
|
3992
|
+
currentAggregateItemHash: args.currentAggregateItemHash,
|
|
3993
|
+
staleHashes,
|
|
3994
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3995
|
+
});
|
|
3996
|
+
});
|
|
3997
|
+
}
|
|
3809
3998
|
syncLatestDeploymentProgress(instances) {
|
|
3810
3999
|
const itemHash = this.state.lastDeploymentHash;
|
|
3811
4000
|
if (!itemHash) {
|
|
@@ -4181,7 +4370,11 @@ var SponsorRelayController = class {
|
|
|
4181
4370
|
instances.map((entry) => entry.instance.item_hash)
|
|
4182
4371
|
);
|
|
4183
4372
|
bootstrapRegistrations = selectCurrentRelayBootstrapPosts(rawBootstrapPosts).filter(
|
|
4184
|
-
(entry) =>
|
|
4373
|
+
(entry) => relayBootstrapMatchesCurrentWallet(
|
|
4374
|
+
entry,
|
|
4375
|
+
normalizedWalletAddress,
|
|
4376
|
+
activeInstanceHashes
|
|
4377
|
+
)
|
|
4185
4378
|
).map((entry) => {
|
|
4186
4379
|
const instanceItemHash = relayBootstrapInstanceItemHash(entry);
|
|
4187
4380
|
const messageHash = entry.itemHash ?? entry.hash ?? null;
|
|
@@ -4200,6 +4393,8 @@ var SponsorRelayController = class {
|
|
|
4200
4393
|
registrationId: entry.content.registrationId,
|
|
4201
4394
|
multiaddrs: Array.isArray(entry.content.multiaddrs) ? entry.content.multiaddrs : [],
|
|
4202
4395
|
browserMultiaddrs: Array.isArray(entry.content.browserMultiaddrs) ? entry.content.browserMultiaddrs : [],
|
|
4396
|
+
ownerAddress: typeof entry.content.ownerAddress === "string" ? entry.content.ownerAddress : void 0,
|
|
4397
|
+
publisherAddress: typeof entry.content.publisherAddress === "string" ? entry.content.publisherAddress : void 0,
|
|
4203
4398
|
updatedAt: entry.content.updatedAt
|
|
4204
4399
|
} : null
|
|
4205
4400
|
};
|
|
@@ -4571,6 +4766,7 @@ var SponsorRelayController = class {
|
|
|
4571
4766
|
detail: failedDueToInvalidIpv6 ? `${attemptLabel} exposed runtime networking that cannot support proxy-backed HTTPS. Cleaning up this attempt before retrying another CRN.` : `${attemptLabel} failed: ${lastError.message} Cleaning up this attempt before retrying another CRN.`
|
|
4572
4767
|
});
|
|
4573
4768
|
if (attemptDeploymentToken) {
|
|
4769
|
+
let cleanupAggregateItemHash = null;
|
|
4574
4770
|
this.emitProgress({
|
|
4575
4771
|
stage: "deployment-confirmed",
|
|
4576
4772
|
label: "Cleaning up failed attempt",
|
|
@@ -4592,6 +4788,7 @@ var SponsorRelayController = class {
|
|
|
4592
4788
|
apiHost: this.client.apiHost,
|
|
4593
4789
|
sync: true
|
|
4594
4790
|
}).then((cleanupResult) => {
|
|
4791
|
+
cleanupAggregateItemHash = cleanupResult.aggregateItemHash;
|
|
4595
4792
|
this.trace("deploy:bootstrap-config-cleanup-complete", {
|
|
4596
4793
|
itemHash: attemptItemHash,
|
|
4597
4794
|
deploymentToken: attemptDeploymentToken,
|
|
@@ -4605,6 +4802,12 @@ var SponsorRelayController = class {
|
|
|
4605
4802
|
error: cleanupError instanceof Error ? cleanupError.message : String(cleanupError)
|
|
4606
4803
|
});
|
|
4607
4804
|
});
|
|
4805
|
+
await this.cleanupStaleVmBootstrapConfigHistory({
|
|
4806
|
+
itemHash: attemptItemHash,
|
|
4807
|
+
currentAggregateItemHash: cleanupAggregateItemHash,
|
|
4808
|
+
stage: "deployment-confirmed",
|
|
4809
|
+
progress: 18
|
|
4810
|
+
});
|
|
4608
4811
|
}
|
|
4609
4812
|
this.emitProgress({
|
|
4610
4813
|
stage: "deployment-confirmed",
|