Compare commits

...

2 Commits

Author SHA1 Message Date
archipelago
853d51ae14 chore: release v1.7.81-alpha 2026-05-21 21:44:14 -04:00
archipelago
a578834462 fix(apps): repair saleor storefront startup 2026-05-21 21:33:51 -04:00
7 changed files with 178 additions and 114 deletions

View File

@ -1,5 +1,12 @@
# Changelog # Changelog
## v1.7.81-alpha (2026-05-21)
- Saleor storefront installs now use the prebuilt registry image instead of building the Next.js app on-device, avoiding Podman build failures during stack installation.
- Existing Saleor stacks are repaired on adoption by recreating missing storefront containers, forcing the storefront app to bind `0.0.0.0:3000`, and resolving nginx upstreams dynamically after container restarts.
- The shipped Saleor storefront image now includes public assets and omits Vercel-only Speed Insights injection, fixing broken static asset responses and the local `/_vercel/speed-insights/script.js` browser warning.
- Validation passed with `cargo fmt --all --check --manifest-path core/Cargo.toml`, `cargo check -p archipelago --manifest-path core/Cargo.toml`, and live checks on `100.114.134.21` for `9011` storefront, static assets, and proxied GraphQL.
## v1.7.80-alpha (2026-05-21) ## v1.7.80-alpha (2026-05-21)
- Saleor storefront proxying now falls back to the direct request scheme when no forwarded protocol header is present, fixing direct `http://node:9011` launches that could generate an invalid same-origin GraphQL URL. - Saleor storefront proxying now falls back to the direct request scheme when no forwarded protocol header is present, fixing direct `http://node:9011` launches that could generate an invalid same-origin GraphQL URL.

View File

@ -1,6 +1,6 @@
[package] [package]
name = "archipelago" name = "archipelago"
version = "1.7.80-alpha" version = "1.7.81-alpha"
edition = "2021" edition = "2021"
description = "Archipelago Bitcoin Node OS - Native backend" description = "Archipelago Bitcoin Node OS - Native backend"
authors = ["Archipelago Team"] authors = ["Archipelago Team"]

View File

@ -76,6 +76,10 @@ async fn adopt_stack_if_exists(
async fn repair_stack_before_adopt(stack_name: &str) { async fn repair_stack_before_adopt(stack_name: &str) {
match stack_name { match stack_name {
"saleor" => {
repair_saleor_network_aliases().await;
let _ = start_saleor_storefront_containers().await;
}
"btcpay" | "btcpay-server" => { "btcpay" | "btcpay-server" => {
let _ = tokio::process::Command::new("sudo") let _ = tokio::process::Command::new("sudo")
.args([ .args([
@ -99,7 +103,6 @@ async fn repair_stack_before_adopt(stack_name: &str) {
} }
"indeedhub" => repair_indeedhub_network_aliases().await, "indeedhub" => repair_indeedhub_network_aliases().await,
"netbird" => repair_netbird_unified_origin().await, "netbird" => repair_netbird_unified_origin().await,
"saleor" => repair_saleor_network_aliases().await,
_ => {} _ => {}
} }
} }
@ -275,6 +278,53 @@ async fn repair_saleor_network_aliases() {
} }
} }
async fn start_saleor_storefront_containers() -> Result<()> {
let names = podman_container_names().await?;
if !names.iter().any(|name| name == "saleor-storefront-app") {
pull_image_with_retry(SALEOR_STOREFRONT_IMAGE).await?;
let mut storefront_cmd = saleor_storefront_app_command();
run_required_stack_command("saleor", "create storefront app", &mut storefront_cmd).await?;
} else {
let _ = tokio::process::Command::new("podman")
.args(["start", "saleor-storefront-app"])
.output()
.await;
}
write_saleor_storefront_proxy_config().await?;
if !names.iter().any(|name| name == "saleor-storefront") {
let mut proxy_cmd = saleor_storefront_proxy_command();
run_required_stack_command("saleor", "create storefront proxy", &mut proxy_cmd).await?;
} else {
let _ = tokio::process::Command::new("podman")
.args(["start", "saleor-storefront"])
.output()
.await;
}
wait_for_stack_containers(
"saleor",
&["saleor-storefront-app", "saleor-storefront"],
60,
)
.await
}
async fn podman_container_names() -> Result<Vec<String>> {
let output = tokio::process::Command::new("podman")
.args(["ps", "-a", "--format", "{{.Names}}"])
.output()
.await
.context("Failed to list containers")?;
Ok(String::from_utf8_lossy(&output.stdout)
.lines()
.map(str::trim)
.filter(|name| !name.is_empty())
.map(ToOwned::to_owned)
.collect())
}
async fn run_required_stack_command( async fn run_required_stack_command(
stack_name: &str, stack_name: &str,
label: &str, label: &str,
@ -447,9 +497,7 @@ const NETBIRD_SERVER_IMAGE: &str = "docker.io/netbirdio/netbird-server:0.71.2";
const NETBIRD_PROXY_IMAGE: &str = "docker.io/library/nginx:1.27-alpine"; const NETBIRD_PROXY_IMAGE: &str = "docker.io/library/nginx:1.27-alpine";
const SALEOR_API_IMAGE: &str = "ghcr.io/saleor/saleor:3.23"; const SALEOR_API_IMAGE: &str = "ghcr.io/saleor/saleor:3.23";
const SALEOR_DASHBOARD_IMAGE: &str = "ghcr.io/saleor/saleor-dashboard:3.23"; const SALEOR_DASHBOARD_IMAGE: &str = "ghcr.io/saleor/saleor-dashboard:3.23";
const SALEOR_STOREFRONT_IMAGE: &str = "localhost/archipelago/saleor-storefront:6eb0b97"; const SALEOR_STOREFRONT_IMAGE: &str = "146.59.87.168:3000/lfg2025/saleor-storefront:6eb0b97";
const SALEOR_STOREFRONT_CONTEXT: &str =
"https://github.com/saleor/storefront.git#6eb0b97b25bd4344d8139515a1cabf763d703b39";
const SALEOR_POSTGRES_IMAGE: &str = "docker.io/library/postgres:15-alpine"; const SALEOR_POSTGRES_IMAGE: &str = "docker.io/library/postgres:15-alpine";
const SALEOR_VALKEY_IMAGE: &str = "docker.io/valkey/valkey:8.1-alpine"; const SALEOR_VALKEY_IMAGE: &str = "docker.io/valkey/valkey:8.1-alpine";
const SALEOR_JAEGER_IMAGE: &str = "docker.io/jaegertracing/jaeger:latest"; const SALEOR_JAEGER_IMAGE: &str = "docker.io/jaegertracing/jaeger:latest";
@ -457,6 +505,14 @@ const SALEOR_MAILPIT_IMAGE: &str = "docker.io/axllent/mailpit:latest";
/// Pull an image with retry and exponential backoff (3 attempts). /// Pull an image with retry and exponential backoff (3 attempts).
async fn pull_image_with_retry(image: &str) -> Result<()> { async fn pull_image_with_retry(image: &str) -> Result<()> {
let exists = tokio::process::Command::new("podman")
.args(["image", "exists", image])
.status()
.await;
if matches!(exists, Ok(status) if status.success()) {
return Ok(());
}
const MAX_ATTEMPTS: u32 = 3; const MAX_ATTEMPTS: u32 = 3;
const BACKOFF_SECS: [u64; 3] = [5, 15, 45]; const BACKOFF_SECS: [u64; 3] = [5, 15, 45];
@ -501,6 +557,73 @@ async fn pull_image_with_retry(image: &str) -> Result<()> {
unreachable!() unreachable!()
} }
fn saleor_storefront_app_command() -> tokio::process::Command {
let mut cmd = tokio::process::Command::new("podman");
cmd.args([
"run",
"-d",
"--name",
"saleor-storefront-app",
"--network",
"saleor-net",
"--network-alias",
"storefront-app",
"--restart=unless-stopped",
"--cap-drop=ALL",
"--cap-add=CHOWN",
"--cap-add=DAC_OVERRIDE",
"--cap-add=FOWNER",
"--cap-add=SETGID",
"--cap-add=SETUID",
"--security-opt=no-new-privileges:true",
"--memory=512m",
"--pids-limit=2048",
"-e",
"NEXT_PUBLIC_SALEOR_API_URL=http://api:8000/graphql/",
"-e",
"NEXT_PUBLIC_STOREFRONT_URL=http://localhost:9011",
"-e",
"NEXT_PUBLIC_DEFAULT_CHANNEL=default-channel",
"-e",
"HOSTNAME=0.0.0.0",
"-e",
"PORT=3000",
SALEOR_STOREFRONT_IMAGE,
]);
cmd
}
fn saleor_storefront_proxy_command() -> tokio::process::Command {
let mut cmd = tokio::process::Command::new("podman");
cmd.args([
"run",
"-d",
"--name",
"saleor-storefront",
"--network",
"saleor-net",
"--network-alias",
"storefront",
"--restart=unless-stopped",
"--cap-drop=ALL",
"--cap-add=CHOWN",
"--cap-add=DAC_OVERRIDE",
"--cap-add=FOWNER",
"--cap-add=NET_BIND_SERVICE",
"--cap-add=SETGID",
"--cap-add=SETUID",
"--security-opt=no-new-privileges:true",
"--memory=128m",
"--pids-limit=1024",
"-p",
"9011:80",
"-v",
"/var/lib/archipelago/saleor-storefront/nginx.conf:/etc/nginx/conf.d/default.conf:ro",
NETBIRD_PROXY_IMAGE,
]);
cmd
}
impl RpcHandler { impl RpcHandler {
/// Install Immich stack (postgres + redis + server). /// Install Immich stack (postgres + redis + server).
pub(super) async fn install_immich_stack(&self) -> Result<serde_json::Value> { pub(super) async fn install_immich_stack(&self) -> Result<serde_json::Value> {
@ -1678,6 +1801,7 @@ impl RpcHandler {
SALEOR_VALKEY_IMAGE, SALEOR_VALKEY_IMAGE,
SALEOR_API_IMAGE, SALEOR_API_IMAGE,
SALEOR_DASHBOARD_IMAGE, SALEOR_DASHBOARD_IMAGE,
SALEOR_STOREFRONT_IMAGE,
SALEOR_JAEGER_IMAGE, SALEOR_JAEGER_IMAGE,
SALEOR_MAILPIT_IMAGE, SALEOR_MAILPIT_IMAGE,
]; ];
@ -1754,7 +1878,6 @@ impl RpcHandler {
let dashboard_origin = format!("http://{}:9010", host_ip); let dashboard_origin = format!("http://{}:9010", host_ip);
let dashboard_url = format!("{}/", dashboard_origin); let dashboard_url = format!("{}/", dashboard_origin);
let api_url = format!("http://{}:8000/graphql/", host_ip); let api_url = format!("http://{}:8000/graphql/", host_ip);
let internal_api_url = "http://api:8000/graphql/";
let storefront_origin = format!("http://{}:9011", host_ip); let storefront_origin = format!("http://{}:9011", host_ip);
let allowed_hosts = format!("localhost,127.0.0.1,api,saleor-api,{}", host_ip); let allowed_hosts = format!("localhost,127.0.0.1,api,saleor-api,{}", host_ip);
let allowed_client_hosts = format!( let allowed_client_hosts = format!(
@ -2079,82 +2202,11 @@ user.save()
]); ]);
run_required_stack_command("saleor", "create dashboard", &mut dashboard_cmd).await?; run_required_stack_command("saleor", "create dashboard", &mut dashboard_cmd).await?;
let mut storefront_build_cmd = tokio::process::Command::new("podman"); let mut storefront_cmd = saleor_storefront_app_command();
storefront_build_cmd.args([
"build",
"--network",
"saleor-net",
"--pull=always",
"-t",
SALEOR_STOREFRONT_IMAGE,
"--build-arg",
&format!("NEXT_PUBLIC_SALEOR_API_URL={}", internal_api_url),
"--build-arg",
&format!("NEXT_PUBLIC_STOREFRONT_URL={}", storefront_origin),
"--build-arg",
"NEXT_PUBLIC_DEFAULT_CHANNEL=default-channel",
SALEOR_STOREFRONT_CONTEXT,
]);
run_required_stack_command("saleor", "build storefront", &mut storefront_build_cmd).await?;
let mut storefront_cmd = tokio::process::Command::new("podman");
storefront_cmd.args([
"run",
"-d",
"--name",
"saleor-storefront-app",
"--network",
"saleor-net",
"--network-alias",
"storefront-app",
"--restart=unless-stopped",
"--cap-drop=ALL",
"--cap-add=CHOWN",
"--cap-add=DAC_OVERRIDE",
"--cap-add=FOWNER",
"--cap-add=SETGID",
"--cap-add=SETUID",
"--security-opt=no-new-privileges:true",
"--memory=512m",
"--pids-limit=2048",
"-e",
&format!("NEXT_PUBLIC_SALEOR_API_URL={}", internal_api_url),
"-e",
&format!("NEXT_PUBLIC_STOREFRONT_URL={}", storefront_origin),
"-e",
"NEXT_PUBLIC_DEFAULT_CHANNEL=default-channel",
SALEOR_STOREFRONT_IMAGE,
]);
run_required_stack_command("saleor", "create storefront app", &mut storefront_cmd).await?; run_required_stack_command("saleor", "create storefront app", &mut storefront_cmd).await?;
write_saleor_storefront_proxy_config().await?; write_saleor_storefront_proxy_config().await?;
let mut storefront_proxy_cmd = tokio::process::Command::new("podman"); let mut storefront_proxy_cmd = saleor_storefront_proxy_command();
storefront_proxy_cmd.args([
"run",
"-d",
"--name",
"saleor-storefront",
"--network",
"saleor-net",
"--network-alias",
"storefront",
"--restart=unless-stopped",
"--cap-drop=ALL",
"--cap-add=CHOWN",
"--cap-add=DAC_OVERRIDE",
"--cap-add=FOWNER",
"--cap-add=NET_BIND_SERVICE",
"--cap-add=SETGID",
"--cap-add=SETUID",
"--security-opt=no-new-privileges:true",
"--memory=128m",
"--pids-limit=1024",
"-p",
"9011:80",
"-v",
"/var/lib/archipelago/saleor-storefront/nginx.conf:/etc/nginx/conf.d/default.conf:ro",
NETBIRD_PROXY_IMAGE,
]);
run_required_stack_command( run_required_stack_command(
"saleor", "saleor",
"create storefront proxy", "create storefront proxy",
@ -2242,6 +2294,7 @@ async fn write_saleor_storefront_proxy_config() -> Result<()> {
server { server {
listen 80; listen 80;
server_name _; server_name _;
resolver 10.89.4.1 valid=10s ipv6=off;
proxy_http_version 1.1; proxy_http_version 1.1;
proxy_set_header Host $host; proxy_set_header Host $host;
@ -2250,13 +2303,15 @@ server {
proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Proto $scheme;
location ^~ /graphql/ { location ^~ /graphql/ {
proxy_pass http://api:8000/graphql/; set $saleor_api http://api:8000/graphql/;
proxy_pass $saleor_api;
proxy_set_header Host api; proxy_set_header Host api;
proxy_set_header Origin ""; proxy_set_header Origin "";
} }
location / { location / {
proxy_pass http://storefront-app:3000; set $saleor_storefront_app http://storefront-app:3000;
proxy_pass $saleor_storefront_app;
proxy_set_header Upgrade $http_upgrade; proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade"; proxy_set_header Connection "upgrade";
proxy_set_header Accept-Encoding ""; proxy_set_header Accept-Encoding "";

View File

@ -1,12 +1,12 @@
{ {
"name": "neode-ui", "name": "neode-ui",
"version": "1.7.80-alpha", "version": "1.7.81-alpha",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "neode-ui", "name": "neode-ui",
"version": "1.7.80-alpha", "version": "1.7.81-alpha",
"dependencies": { "dependencies": {
"@types/dompurify": "^3.0.5", "@types/dompurify": "^3.0.5",
"@vue-leaflet/vue-leaflet": "^0.10.1", "@vue-leaflet/vue-leaflet": "^0.10.1",

View File

@ -1,7 +1,7 @@
{ {
"name": "neode-ui", "name": "neode-ui",
"private": true, "private": true,
"version": "1.7.80-alpha", "version": "1.7.81-alpha",
"type": "module", "type": "module",
"scripts": { "scripts": {
"start": "./start-dev.sh", "start": "./start-dev.sh",

View File

@ -1,27 +1,28 @@
{ {
"version": "1.7.80-alpha", "version": "1.7.81-alpha",
"release_date": "2026-05-21", "release_date": "2026-05-21",
"changelog": [ "changelog": [
"Saleor storefront proxying now falls back to the direct request scheme when no forwarded protocol header is present, fixing direct `http://node:9011` launches that could generate an invalid same-origin GraphQL URL.", "Saleor storefront installs now use the prebuilt registry image instead of building the Next.js app on-device, avoiding Podman build failures during stack installation.",
"The Saleor storefront release path keeps public proxy support intact by still honoring forwarded HTTPS headers for Nginx Proxy Manager domains while repairing local/direct port launches.", "Existing Saleor stacks are repaired on adoption by recreating missing storefront containers, forcing the storefront app to bind `0.0.0.0:3000`, and resolving nginx upstreams dynamically after container restarts.",
"Validation passed with `cargo fmt --check` and `cargo check` for the Archipelago backend before release staging." "The shipped Saleor storefront image now includes public assets and omits Vercel-only Speed Insights injection, fixing broken static asset responses and the local `/_vercel/speed-insights/script.js` browser warning.",
"Validation passed with `cargo fmt --all --check --manifest-path core/Cargo.toml`, `cargo check -p archipelago --manifest-path core/Cargo.toml`, and live checks on `100.114.134.21` for `9011` storefront, static assets, and proxied GraphQL."
], ],
"components": [ "components": [
{ {
"name": "archipelago", "name": "archipelago",
"current_version": "1.7.80-alpha", "current_version": "1.7.81-alpha",
"new_version": "1.7.80-alpha", "new_version": "1.7.81-alpha",
"download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.80-alpha/archipelago", "download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.81-alpha/archipelago",
"sha256": "6e2d796e9395b578944991970b7f07d27b4185d3aae2beb0af10e47d212f5ea7", "sha256": "82ba94b4e4494a4a67506e3516c34e0f874630efae2d673c70852da9f94144e7",
"size_bytes": 43071632 "size_bytes": 43109024
}, },
{ {
"name": "archipelago-frontend-1.7.80-alpha.tar.gz", "name": "archipelago-frontend-1.7.81-alpha.tar.gz",
"current_version": "1.7.80-alpha", "current_version": "1.7.81-alpha",
"new_version": "1.7.80-alpha", "new_version": "1.7.81-alpha",
"download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.80-alpha/archipelago-frontend-1.7.80-alpha.tar.gz", "download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.81-alpha/archipelago-frontend-1.7.81-alpha.tar.gz",
"sha256": "65a75fbe732635ebc658eba1f6d36a7e158de3b88ef49db0a23202d0564e30c0", "sha256": "69ec4df6c1f77cbbacc6ea8dc8e2e40cbb50cf61b032825c7de520c72960afba",
"size_bytes": 166481159 "size_bytes": 166484929
} }
] ]
} }

View File

@ -1,27 +1,28 @@
{ {
"version": "1.7.80-alpha", "version": "1.7.81-alpha",
"release_date": "2026-05-21", "release_date": "2026-05-21",
"changelog": [ "changelog": [
"Saleor storefront proxying now falls back to the direct request scheme when no forwarded protocol header is present, fixing direct `http://node:9011` launches that could generate an invalid same-origin GraphQL URL.", "Saleor storefront installs now use the prebuilt registry image instead of building the Next.js app on-device, avoiding Podman build failures during stack installation.",
"The Saleor storefront release path keeps public proxy support intact by still honoring forwarded HTTPS headers for Nginx Proxy Manager domains while repairing local/direct port launches.", "Existing Saleor stacks are repaired on adoption by recreating missing storefront containers, forcing the storefront app to bind `0.0.0.0:3000`, and resolving nginx upstreams dynamically after container restarts.",
"Validation passed with `cargo fmt --check` and `cargo check` for the Archipelago backend before release staging." "The shipped Saleor storefront image now includes public assets and omits Vercel-only Speed Insights injection, fixing broken static asset responses and the local `/_vercel/speed-insights/script.js` browser warning.",
"Validation passed with `cargo fmt --all --check --manifest-path core/Cargo.toml`, `cargo check -p archipelago --manifest-path core/Cargo.toml`, and live checks on `100.114.134.21` for `9011` storefront, static assets, and proxied GraphQL."
], ],
"components": [ "components": [
{ {
"name": "archipelago", "name": "archipelago",
"current_version": "1.7.80-alpha", "current_version": "1.7.81-alpha",
"new_version": "1.7.80-alpha", "new_version": "1.7.81-alpha",
"download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.80-alpha/archipelago", "download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.81-alpha/archipelago",
"sha256": "6e2d796e9395b578944991970b7f07d27b4185d3aae2beb0af10e47d212f5ea7", "sha256": "82ba94b4e4494a4a67506e3516c34e0f874630efae2d673c70852da9f94144e7",
"size_bytes": 43071632 "size_bytes": 43109024
}, },
{ {
"name": "archipelago-frontend-1.7.80-alpha.tar.gz", "name": "archipelago-frontend-1.7.81-alpha.tar.gz",
"current_version": "1.7.80-alpha", "current_version": "1.7.81-alpha",
"new_version": "1.7.80-alpha", "new_version": "1.7.81-alpha",
"download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.80-alpha/archipelago-frontend-1.7.80-alpha.tar.gz", "download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.81-alpha/archipelago-frontend-1.7.81-alpha.tar.gz",
"sha256": "65a75fbe732635ebc658eba1f6d36a7e158de3b88ef49db0a23202d0564e30c0", "sha256": "69ec4df6c1f77cbbacc6ea8dc8e2e40cbb50cf61b032825c7de520c72960afba",
"size_bytes": 166481159 "size_bytes": 166484929
} }
] ]
} }