@le-space/ui 0.6.37 → 0.6.39

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@le-space/ui",
3
- "version": "0.6.37",
3
+ "version": "0.6.39",
4
4
  "description": "Floating Aleph Relay Button UI components for Svelte and React.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -44,8 +44,8 @@
44
44
  "url": "https://github.com/NiKrause/relay-button/issues"
45
45
  },
46
46
  "dependencies": {
47
- "@le-space/browser": "0.6.37",
48
- "@le-space/core": "0.6.37",
47
+ "@le-space/browser": "0.6.39",
48
+ "@le-space/core": "0.6.39",
49
49
  "viem": "^2.53.1"
50
50
  },
51
51
  "peerDependencies": {
package/react/index.d.ts CHANGED
@@ -346,6 +346,7 @@ declare class SponsorRelayController {
346
346
  private patch;
347
347
  private emitProgress;
348
348
  private configureRelayBootstrapRegistration;
349
+ private probeRelayReachableOverProxy;
349
350
  private cleanupStaleVmBootstrapConfigHistory;
350
351
  private syncLatestDeploymentProgress;
351
352
  private canSkipRuntimeRefresh;
package/react/index.js CHANGED
@@ -43,7 +43,7 @@ var RECENT_INSTANCE_RUNTIME_GRACE_MS = 10 * 60 * 1e3;
43
43
  var DEPLOYMENT_PENDING_WARNING_MS = 3 * 60 * 1e3;
44
44
 
45
45
  // src/shared/package-version.ts
46
- var UI_PACKAGE_VERSION = "0.6.37";
46
+ var UI_PACKAGE_VERSION = "0.6.39";
47
47
 
48
48
  // src/shared/format.ts
49
49
  function shortHash(value, head = 8, tail = 6) {
@@ -4545,7 +4545,13 @@ var SponsorRelayController = class {
4545
4545
  instanceItemHash: args.itemHash,
4546
4546
  fetch: asJsonFetch,
4547
4547
  apiHost: this.client.apiHost,
4548
- attempts: 40,
4548
+ // The guest publishes this signal only after its describe step has a
4549
+ // browser-dialable address, which waits on AutoTLS for up to ~240 s.
4550
+ // Wait comfortably longer than that (100 × 3 s = 300 s) so the complete
4551
+ // signal arrives instead of timing out — a timeout here drops into the
4552
+ // recovery path, which used to poll the guest over plain HTTP (mixed
4553
+ // content on an HTTPS origin).
4554
+ attempts: 100,
4549
4555
  delayMs: 3e3
4550
4556
  });
4551
4557
  this.trace("deploy:bootstrap-config-signal-visible", {
@@ -4597,6 +4603,12 @@ var SponsorRelayController = class {
4597
4603
  browserBootstrapMultiaddrCount: relayMetadata.browserBootstrapMultiaddrs.length
4598
4604
  });
4599
4605
  } else {
4606
+ const canReadMetadataSecurely = profile === "uc-go-peer" && Boolean(runtime.proxyUrl);
4607
+ if (usesBootstrapConfigAggregate(this.state.manifest) && !canReadMetadataSecurely) {
4608
+ throw new Error(
4609
+ "The relay applied its bootstrap config but the acknowledgement did not carry its final multiaddrs, and this image exposes no HTTPS metadata endpoint. Reading them over plain HTTP would be blocked as mixed content on an HTTPS origin, so the deployment cannot be completed."
4610
+ );
4611
+ }
4600
4612
  this.emitProgress({
4601
4613
  stage: "publishing-bootstrap",
4602
4614
  label: "Waiting for secure relay metadata",
@@ -4608,7 +4620,7 @@ var SponsorRelayController = class {
4608
4620
  relayMetadata = await fetchRelayMetadataForRuntime({
4609
4621
  runtime,
4610
4622
  fetch: (url, init) => fetch(url, init),
4611
- preferSecureMetadata: profile === "uc-go-peer" && Boolean(runtime.proxyUrl),
4623
+ preferSecureMetadata: canReadMetadataSecurely,
4612
4624
  attempts: 80,
4613
4625
  delayMs: 3e3,
4614
4626
  timeoutMs: 24e4,
@@ -4775,6 +4787,27 @@ var SponsorRelayController = class {
4775
4787
  );
4776
4788
  }
4777
4789
  }
4790
+ if (profile === "orbitdb-relay") {
4791
+ const proxyHostname = (() => {
4792
+ try {
4793
+ return runtime.proxyUrl ? new URL(runtime.proxyUrl).hostname : null;
4794
+ } catch {
4795
+ return null;
4796
+ }
4797
+ })();
4798
+ if (proxyHostname) {
4799
+ const reachable = await this.probeRelayReachableOverProxy({
4800
+ proxyHostname,
4801
+ peerId,
4802
+ itemHash: args.itemHash
4803
+ });
4804
+ if (!reachable) {
4805
+ throw new Error(
4806
+ `Relay ${peerId} never became reachable over its HTTPS proxy (https://${proxyHostname}/health) within the readiness window \u2014 the CRN's proxy is not forwarding to the relay. Failing this attempt so another host can be tried.`
4807
+ );
4808
+ }
4809
+ }
4810
+ }
4778
4811
  if (profile === "uc-go-peer" && args.deploymentToken) {
4779
4812
  let cleanupAggregateItemHash = null;
4780
4813
  await deleteVmBootstrapConfig({
@@ -4808,6 +4841,49 @@ var SponsorRelayController = class {
4808
4841
  });
4809
4842
  }
4810
4843
  }
4844
+ async probeRelayReachableOverProxy(args) {
4845
+ const healthUrl = `https://${args.proxyHostname}/health`;
4846
+ const attempts = 30;
4847
+ const delayMs = 4e3;
4848
+ for (let attempt = 1; attempt <= attempts; attempt += 1) {
4849
+ try {
4850
+ const abort = new AbortController();
4851
+ const timeout = globalThis.setTimeout(() => abort.abort(), 1e4);
4852
+ const response = await fetch(healthUrl, {
4853
+ cache: "no-cache",
4854
+ signal: abort.signal
4855
+ });
4856
+ globalThis.clearTimeout(timeout);
4857
+ if (response.ok) {
4858
+ const payload = await response.json().catch(() => null);
4859
+ if (typeof payload?.peerId === "string" && payload.peerId === args.peerId) {
4860
+ this.emitProgress({
4861
+ stage: "publishing-bootstrap",
4862
+ label: "Relay reachable over HTTPS",
4863
+ progress: 98,
4864
+ status: "success",
4865
+ itemHash: args.itemHash,
4866
+ detail: `Relay answered on ${healthUrl} with its peer id (attempt ${attempt}/${attempts}).`
4867
+ });
4868
+ return true;
4869
+ }
4870
+ }
4871
+ } catch {
4872
+ }
4873
+ this.emitProgress({
4874
+ stage: "publishing-bootstrap",
4875
+ label: "Waiting for relay to be reachable",
4876
+ progress: 98,
4877
+ status: "warning",
4878
+ itemHash: args.itemHash,
4879
+ detail: `Relay not yet reachable over ${healthUrl} (attempt ${attempt}/${attempts}).`
4880
+ });
4881
+ if (attempt < attempts) {
4882
+ await new Promise((resolve) => globalThis.setTimeout(resolve, delayMs));
4883
+ }
4884
+ }
4885
+ return false;
4886
+ }
4811
4887
  async cleanupStaleVmBootstrapConfigHistory(args) {
4812
4888
  if (!this.state.wallet.address || !args.currentAggregateItemHash) {
4813
4889
  return;
@@ -5710,11 +5786,13 @@ var SponsorRelayController = class {
5710
5786
  crnListUrl: this.props.crnListUrl,
5711
5787
  requirePublicGuestIpv6ForProxy: true
5712
5788
  });
5713
- if (latestRuntime.diagnostics?.state === "ready") {
5789
+ const canReconcileMetadataSecurely = attemptProfile === "uc-go-peer" && Boolean(latestRuntime.proxyUrl);
5790
+ const mayReadMetadata = canReconcileMetadataSecurely || !usesBootstrapConfigAggregate(this.state.manifest);
5791
+ if (latestRuntime.diagnostics?.state === "ready" && mayReadMetadata) {
5714
5792
  const reconciledRelayMetadata = await fetchRelayMetadataForRuntime({
5715
5793
  runtime: latestRuntime,
5716
5794
  fetch: (url, init) => fetch(url, init),
5717
- preferSecureMetadata: attemptProfile === "uc-go-peer" && Boolean(latestRuntime.proxyUrl),
5795
+ preferSecureMetadata: canReconcileMetadataSecurely,
5718
5796
  attempts: 3,
5719
5797
  delayMs: 1e3,
5720
5798
  timeoutMs: 15e3
package/shared/index.d.ts CHANGED
@@ -341,7 +341,7 @@ declare const STALE_INSTANCE_ALLOCATION_COOLDOWN_MS: number;
341
341
  declare const RECENT_INSTANCE_RUNTIME_GRACE_MS: number;
342
342
  declare const DEPLOYMENT_PENDING_WARNING_MS: number;
343
343
 
344
- declare const UI_PACKAGE_VERSION = "0.6.37";
344
+ declare const UI_PACKAGE_VERSION = "0.6.39";
345
345
 
346
346
  interface RootfsRequiredPortForward {
347
347
  port: number;
@@ -405,6 +405,7 @@ declare class SponsorRelayController {
405
405
  private patch;
406
406
  private emitProgress;
407
407
  private configureRelayBootstrapRegistration;
408
+ private probeRelayReachableOverProxy;
408
409
  private cleanupStaleVmBootstrapConfigHistory;
409
410
  private syncLatestDeploymentProgress;
410
411
  private canSkipRuntimeRefresh;
package/shared/index.js CHANGED
@@ -42,7 +42,7 @@ var RECENT_INSTANCE_RUNTIME_GRACE_MS = 10 * 60 * 1e3;
42
42
  var DEPLOYMENT_PENDING_WARNING_MS = 3 * 60 * 1e3;
43
43
 
44
44
  // src/shared/package-version.ts
45
- var UI_PACKAGE_VERSION = "0.6.37";
45
+ var UI_PACKAGE_VERSION = "0.6.39";
46
46
 
47
47
  // src/shared/format.ts
48
48
  function shortHash(value, head = 8, tail = 6) {
@@ -4544,7 +4544,13 @@ var SponsorRelayController = class {
4544
4544
  instanceItemHash: args.itemHash,
4545
4545
  fetch: asJsonFetch,
4546
4546
  apiHost: this.client.apiHost,
4547
- attempts: 40,
4547
+ // The guest publishes this signal only after its describe step has a
4548
+ // browser-dialable address, which waits on AutoTLS for up to ~240 s.
4549
+ // Wait comfortably longer than that (100 × 3 s = 300 s) so the complete
4550
+ // signal arrives instead of timing out — a timeout here drops into the
4551
+ // recovery path, which used to poll the guest over plain HTTP (mixed
4552
+ // content on an HTTPS origin).
4553
+ attempts: 100,
4548
4554
  delayMs: 3e3
4549
4555
  });
4550
4556
  this.trace("deploy:bootstrap-config-signal-visible", {
@@ -4596,6 +4602,12 @@ var SponsorRelayController = class {
4596
4602
  browserBootstrapMultiaddrCount: relayMetadata.browserBootstrapMultiaddrs.length
4597
4603
  });
4598
4604
  } else {
4605
+ const canReadMetadataSecurely = profile === "uc-go-peer" && Boolean(runtime.proxyUrl);
4606
+ if (usesBootstrapConfigAggregate(this.state.manifest) && !canReadMetadataSecurely) {
4607
+ throw new Error(
4608
+ "The relay applied its bootstrap config but the acknowledgement did not carry its final multiaddrs, and this image exposes no HTTPS metadata endpoint. Reading them over plain HTTP would be blocked as mixed content on an HTTPS origin, so the deployment cannot be completed."
4609
+ );
4610
+ }
4599
4611
  this.emitProgress({
4600
4612
  stage: "publishing-bootstrap",
4601
4613
  label: "Waiting for secure relay metadata",
@@ -4607,7 +4619,7 @@ var SponsorRelayController = class {
4607
4619
  relayMetadata = await fetchRelayMetadataForRuntime({
4608
4620
  runtime,
4609
4621
  fetch: (url, init) => fetch(url, init),
4610
- preferSecureMetadata: profile === "uc-go-peer" && Boolean(runtime.proxyUrl),
4622
+ preferSecureMetadata: canReadMetadataSecurely,
4611
4623
  attempts: 80,
4612
4624
  delayMs: 3e3,
4613
4625
  timeoutMs: 24e4,
@@ -4774,6 +4786,27 @@ var SponsorRelayController = class {
4774
4786
  );
4775
4787
  }
4776
4788
  }
4789
+ if (profile === "orbitdb-relay") {
4790
+ const proxyHostname = (() => {
4791
+ try {
4792
+ return runtime.proxyUrl ? new URL(runtime.proxyUrl).hostname : null;
4793
+ } catch {
4794
+ return null;
4795
+ }
4796
+ })();
4797
+ if (proxyHostname) {
4798
+ const reachable = await this.probeRelayReachableOverProxy({
4799
+ proxyHostname,
4800
+ peerId,
4801
+ itemHash: args.itemHash
4802
+ });
4803
+ if (!reachable) {
4804
+ throw new Error(
4805
+ `Relay ${peerId} never became reachable over its HTTPS proxy (https://${proxyHostname}/health) within the readiness window \u2014 the CRN's proxy is not forwarding to the relay. Failing this attempt so another host can be tried.`
4806
+ );
4807
+ }
4808
+ }
4809
+ }
4777
4810
  if (profile === "uc-go-peer" && args.deploymentToken) {
4778
4811
  let cleanupAggregateItemHash = null;
4779
4812
  await deleteVmBootstrapConfig({
@@ -4807,6 +4840,49 @@ var SponsorRelayController = class {
4807
4840
  });
4808
4841
  }
4809
4842
  }
4843
+ async probeRelayReachableOverProxy(args) {
4844
+ const healthUrl = `https://${args.proxyHostname}/health`;
4845
+ const attempts = 30;
4846
+ const delayMs = 4e3;
4847
+ for (let attempt = 1; attempt <= attempts; attempt += 1) {
4848
+ try {
4849
+ const abort = new AbortController();
4850
+ const timeout = globalThis.setTimeout(() => abort.abort(), 1e4);
4851
+ const response = await fetch(healthUrl, {
4852
+ cache: "no-cache",
4853
+ signal: abort.signal
4854
+ });
4855
+ globalThis.clearTimeout(timeout);
4856
+ if (response.ok) {
4857
+ const payload = await response.json().catch(() => null);
4858
+ if (typeof payload?.peerId === "string" && payload.peerId === args.peerId) {
4859
+ this.emitProgress({
4860
+ stage: "publishing-bootstrap",
4861
+ label: "Relay reachable over HTTPS",
4862
+ progress: 98,
4863
+ status: "success",
4864
+ itemHash: args.itemHash,
4865
+ detail: `Relay answered on ${healthUrl} with its peer id (attempt ${attempt}/${attempts}).`
4866
+ });
4867
+ return true;
4868
+ }
4869
+ }
4870
+ } catch {
4871
+ }
4872
+ this.emitProgress({
4873
+ stage: "publishing-bootstrap",
4874
+ label: "Waiting for relay to be reachable",
4875
+ progress: 98,
4876
+ status: "warning",
4877
+ itemHash: args.itemHash,
4878
+ detail: `Relay not yet reachable over ${healthUrl} (attempt ${attempt}/${attempts}).`
4879
+ });
4880
+ if (attempt < attempts) {
4881
+ await new Promise((resolve) => globalThis.setTimeout(resolve, delayMs));
4882
+ }
4883
+ }
4884
+ return false;
4885
+ }
4810
4886
  async cleanupStaleVmBootstrapConfigHistory(args) {
4811
4887
  if (!this.state.wallet.address || !args.currentAggregateItemHash) {
4812
4888
  return;
@@ -5709,11 +5785,13 @@ var SponsorRelayController = class {
5709
5785
  crnListUrl: this.props.crnListUrl,
5710
5786
  requirePublicGuestIpv6ForProxy: true
5711
5787
  });
5712
- if (latestRuntime.diagnostics?.state === "ready") {
5788
+ const canReconcileMetadataSecurely = attemptProfile === "uc-go-peer" && Boolean(latestRuntime.proxyUrl);
5789
+ const mayReadMetadata = canReconcileMetadataSecurely || !usesBootstrapConfigAggregate(this.state.manifest);
5790
+ if (latestRuntime.diagnostics?.state === "ready" && mayReadMetadata) {
5713
5791
  const reconciledRelayMetadata = await fetchRelayMetadataForRuntime({
5714
5792
  runtime: latestRuntime,
5715
5793
  fetch: (url, init) => fetch(url, init),
5716
- preferSecureMetadata: attemptProfile === "uc-go-peer" && Boolean(latestRuntime.proxyUrl),
5794
+ preferSecureMetadata: canReconcileMetadataSecurely,
5717
5795
  attempts: 3,
5718
5796
  delayMs: 1e3,
5719
5797
  timeoutMs: 15e3