fix: prevent My Apps crash when installing apps + add filebrowser to demo
The My Apps page went blank after installing apps because pkg['static-files'].icon was accessed without optional chaining on dynamically installed packages that lack the static-files property. - Make static-files optional in PackageDataEntry type - Add defensive ?.icon access with fallback in Apps.vue and AppDetails.vue - Add filebrowser to mock backend staticDevApps (enables Cloud page in demo) - Expand portMappings and marketplaceMetadata for all marketplace apps - installPackage now uses staticApp() format for consistent data shape Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -356,10 +356,12 @@ INSTALLER_ISO="$WORK_DIR/installer-iso"
|
||||
rm -rf "$INSTALLER_ISO"
|
||||
mkdir -p "$INSTALLER_ISO"
|
||||
cd "$INSTALLER_ISO"
|
||||
(7z x -y "$BASE_ISO" 2>/dev/null || 7za x -y "$BASE_ISO" 2>/dev/null || bsdtar -xf "$BASE_ISO" 2>/dev/null) || {
|
||||
# 7z returns exit code 2 for warnings (symlinks in ISO) — check for key files instead
|
||||
7z x -y "$BASE_ISO" >/dev/null 2>&1 || 7za x -y "$BASE_ISO" >/dev/null 2>&1 || bsdtar -xf "$BASE_ISO" 2>/dev/null || true
|
||||
if [ ! -d "$INSTALLER_ISO/live" ] || [ ! -f "$INSTALLER_ISO/live/vmlinuz" ]; then
|
||||
echo " ❌ Failed to extract ISO. Install p7zip-full: sudo apt install p7zip-full"
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# STEP 3: Add Archipelago components
|
||||
@@ -501,7 +503,8 @@ mkdir -p "$IMAGES_DIR"
|
||||
IMAGES_CAPTURED_FROM_SERVER=0
|
||||
if [ -n "$DEV_SERVER" ] && [ "$DEV_SERVER" != "localhost" ] && [ "$DEV_SERVER" != "127.0.0.1" ]; then
|
||||
echo " Capturing container images from live server ($DEV_SERVER)..."
|
||||
CAPTURE_PATTERNS="bitcoin-ui bitcoin-knots lnd lnd-ui electrs-ui filebrowser mempool mempool-electrs tailscale homeassistant btcpayserver nbxplorer postgres nostr-rs-relay strfry alpine-tor fedimintd gatewayd dwn-server"
|
||||
# Patterns match against `podman images` repository names (not container names)
|
||||
CAPTURE_PATTERNS="bitcoin-ui bitcoinknots lnd lnd-ui electrs-ui filebrowser mempool backend frontend electrs tailscale homeassistant home-assistant btcpayserver nbxplorer postgres alpine-tor nostr-rs-relay strfry fedimintd gatewayd dwn-server grafana uptime-kuma jellyfin vaultwarden searxng mariadb valkey nginx-alpine portainer"
|
||||
REMOTE_TMP="/tmp/archipelago-image-capture-$$"
|
||||
SAVED_LIST=$(ssh "$DEV_SERVER" "mkdir -p $REMOTE_TMP && for p in $CAPTURE_PATTERNS; do img=\$(sudo podman images --format '{{.Repository}}:{{.Tag}}' 2>/dev/null | grep -i \"\$p\" | head -1); [ -n \"\$img\" ] && sudo podman save -o \"$REMOTE_TMP/\$p.tar\" \"\$img\" 2>/dev/null && echo \"\$p\"; done" 2>/dev/null) || true
|
||||
for p in $SAVED_LIST; do
|
||||
@@ -518,26 +521,30 @@ fi
|
||||
|
||||
# Define images to bundle for fallback (when not from server or missing). Includes filebrowser.
|
||||
# bitcoin-ui and lnd-ui are custom and normally captured from server or built separately.
|
||||
# Alpha: core Bitcoin/Lightning stack + essential apps. Others pulled on-demand from Marketplace.
|
||||
CONTAINER_IMAGES="
|
||||
bitcoinknots/bitcoin:29 bitcoin-knots.tar
|
||||
lightninglabs/lnd:v0.18.4-beta lnd.tar
|
||||
ghcr.io/home-assistant/home-assistant:stable homeassistant.tar
|
||||
btcpayserver/btcpayserver:latest btcpayserver.tar
|
||||
docker.io/bitcoinknots/bitcoin:latest bitcoin-knots.tar
|
||||
docker.io/lightninglabs/lnd:v0.18.4-beta lnd.tar
|
||||
docker.io/homeassistant/home-assistant:2024.1 homeassistant.tar
|
||||
docker.io/btcpayserver/btcpayserver:1.13.5 btcpayserver.tar
|
||||
docker.io/nicolasdorier/nbxplorer:2.6.0 nbxplorer.tar
|
||||
docker.io/library/postgres:16 postgres-btcpay.tar
|
||||
mempool/frontend:latest mempool-frontend.tar
|
||||
mempool/backend:v2.5.0 mempool-backend.tar
|
||||
mempool/electrs:latest mempool-electrs.tar
|
||||
docker.io/mariadb:10.11 mariadb-mempool.tar
|
||||
docker.io/library/postgres:15-alpine postgres-btcpay.tar
|
||||
docker.io/mempool/frontend:v2.5.0 mempool-frontend.tar
|
||||
docker.io/mempool/backend:v2.5.0 mempool-backend.tar
|
||||
docker.io/mempool/electrs:latest mempool-electrs.tar
|
||||
docker.io/library/mariadb:10.11 mariadb-mempool.tar
|
||||
docker.io/fedimint/fedimintd:v0.10.0 fedimint.tar
|
||||
docker.io/fedimint/gatewayd:v0.10.0 fedimint-gateway.tar
|
||||
docker.io/filebrowser/filebrowser:latest filebrowser.tar
|
||||
scsibug/nostr-rs-relay:latest nostr-rs-relay.tar
|
||||
hoytech/strfry:latest strfry.tar
|
||||
tailscale/tailscale:latest tailscale.tar
|
||||
docker.io/filebrowser/filebrowser:v2.27.0 filebrowser.tar
|
||||
docker.io/andrius/alpine-tor:latest alpine-tor.tar
|
||||
docker.io/library/nginx:alpine nginx-alpine.tar
|
||||
ghcr.io/tbd54566975/dwn-server:main dwn-server.tar
|
||||
docker.io/grafana/grafana:10.2.0 grafana.tar
|
||||
docker.io/louislam/uptime-kuma:1 uptime-kuma.tar
|
||||
docker.io/vaultwarden/server:1.30.0-alpine vaultwarden.tar
|
||||
docker.io/searxng/searxng:latest searxng.tar
|
||||
docker.io/portainer/portainer-ce:2.19.4 portainer.tar
|
||||
docker.io/tailscale/tailscale:stable tailscale.tar
|
||||
"
|
||||
|
||||
# Pull and save each image (force AMD64 for x86_64 target) only if not already present
|
||||
@@ -722,6 +729,13 @@ FBCSERVICE
|
||||
cp "$WORK_DIR/archipelago-first-boot-containers.service" "$ARCH_DIR/scripts/"
|
||||
fi
|
||||
|
||||
# Bundle E2E test script for post-install validation
|
||||
if [ -f "$SCRIPT_DIR/../scripts/run-e2e-tests.sh" ]; then
|
||||
cp "$SCRIPT_DIR/../scripts/run-e2e-tests.sh" "$ARCH_DIR/scripts/"
|
||||
chmod +x "$ARCH_DIR/scripts/run-e2e-tests.sh"
|
||||
echo " ✅ Bundled E2E test script for post-install validation"
|
||||
fi
|
||||
|
||||
# Bundle docker UI source files for building custom UIs on first boot (fallback if images not captured)
|
||||
DOCKER_UI_DIR="$SCRIPT_DIR/../docker"
|
||||
if [ -d "$DOCKER_UI_DIR" ]; then
|
||||
@@ -992,6 +1006,17 @@ if [ -d "$BOOT_MEDIA/archipelago/container-images" ]; then
|
||||
echo " ✅ Container images staged for first-boot loading"
|
||||
fi
|
||||
|
||||
# Initialize backend data directories for seamless first boot
|
||||
mkdir -p /mnt/target/var/lib/archipelago/tor-config
|
||||
mkdir -p /mnt/target/var/lib/archipelago/identities
|
||||
mkdir -p /mnt/target/var/lib/archipelago/lnd
|
||||
|
||||
# Copy E2E test script for post-install validation
|
||||
if [ -f "$BOOT_MEDIA/archipelago/scripts/run-e2e-tests.sh" ]; then
|
||||
cp "$BOOT_MEDIA/archipelago/scripts/run-e2e-tests.sh" /mnt/target/opt/archipelago/scripts/
|
||||
chmod +x /mnt/target/opt/archipelago/scripts/run-e2e-tests.sh
|
||||
fi
|
||||
|
||||
# Ensure correct ownership (use numeric UID:GID 1000:1000 since we're outside chroot)
|
||||
chown -R 1000:1000 /mnt/target/opt/archipelago 2>/dev/null || true
|
||||
chown -R 1000:1000 /mnt/target/var/lib/archipelago 2>/dev/null || true
|
||||
@@ -1143,6 +1168,8 @@ echo -e "${GREEN}║ Pre-loaded apps (ready to start via Web UI):
|
||||
echo -e "${GREEN}║ • Bitcoin Knots • LND • Home Assistant ║${NC}"
|
||||
echo -e "${GREEN}║ • BTCPay Server • Mempool • Nostr Relays ║${NC}"
|
||||
echo -e "${GREEN}║ ║${NC}"
|
||||
echo -e "${GREEN}║ Validate: bash /opt/archipelago/scripts/run-e2e-tests.sh ║${NC}"
|
||||
echo -e "${GREEN}║ ║${NC}"
|
||||
echo -e "${GREEN}╚═══════════════════════════════════════════════════════════════════╝${NC}"
|
||||
echo ""
|
||||
read -p "Press Enter to reboot..."
|
||||
@@ -1376,37 +1403,88 @@ echo "📦 Step 6: Creating bootable ISO..."
|
||||
|
||||
OUTPUT_ISO="$OUTPUT_DIR/archipelago-installer-x86_64.iso"
|
||||
|
||||
# Get MBR for hybrid boot
|
||||
ISOHDPFX=""
|
||||
for path in \
|
||||
"/usr/local/share/syslinux/isohdpfx.bin" \
|
||||
"/usr/share/syslinux/isohdpfx.bin" \
|
||||
"/opt/homebrew/share/syslinux/isohdpfx.bin" \
|
||||
"$INSTALLER_ISO/isolinux/isohdpfx.bin"; do
|
||||
if [ -f "$path" ]; then
|
||||
ISOHDPFX="$path"
|
||||
# Extract MBR from original Debian Live ISO (most reliable for hybrid boot)
|
||||
# This preserves the exact MBR that makes the ISO work as a USB drive in Balena Etcher
|
||||
echo " Extracting hybrid MBR from original Debian Live ISO..."
|
||||
ISOHDPFX="$WORK_DIR/isohdpfx.bin"
|
||||
dd if="$BASE_ISO" bs=1 count=432 of="$ISOHDPFX" 2>/dev/null
|
||||
|
||||
# Verify we got a valid MBR (should be 432 bytes)
|
||||
ISOHDPFX_SIZE=$(stat -c%s "$ISOHDPFX" 2>/dev/null || stat -f%z "$ISOHDPFX" 2>/dev/null || echo 0)
|
||||
if [ "$ISOHDPFX_SIZE" -ne 432 ]; then
|
||||
echo " ⚠️ MBR extraction unexpected size ($ISOHDPFX_SIZE), trying syslinux paths..."
|
||||
for path in \
|
||||
"/usr/lib/ISOLINUX/isohdpfx.bin" \
|
||||
"/usr/share/syslinux/isohdpfx.bin" \
|
||||
"/usr/local/share/syslinux/isohdpfx.bin"; do
|
||||
if [ -f "$path" ]; then
|
||||
ISOHDPFX="$path"
|
||||
echo " Using $path"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Find the EFI boot image — 7z may extract it to different locations
|
||||
EFI_IMG=""
|
||||
for efi_path in \
|
||||
"$INSTALLER_ISO/boot/grub/efi.img" \
|
||||
"$INSTALLER_ISO/EFI/boot/efi.img" \
|
||||
"$INSTALLER_ISO/efi.img"; do
|
||||
if [ -f "$efi_path" ]; then
|
||||
EFI_IMG="$efi_path"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -z "$ISOHDPFX" ]; then
|
||||
echo " Extracting MBR from isolinux.bin..."
|
||||
dd if="$INSTALLER_ISO/isolinux/isolinux.bin" of="$WORK_DIR/isohdpfx.bin" bs=432 count=1 2>/dev/null
|
||||
ISOHDPFX="$WORK_DIR/isohdpfx.bin"
|
||||
# If no standalone efi.img, check for [BOOT] directory from 7z extraction
|
||||
if [ -z "$EFI_IMG" ] && [ -d "$INSTALLER_ISO/[BOOT]" ]; then
|
||||
# 7z extracts El Torito boot images into [BOOT]/ — the EFI image is usually entry 2
|
||||
for entry in "$INSTALLER_ISO/[BOOT]/"*; do
|
||||
# EFI images are typically > 1MB FAT filesystems
|
||||
if [ -f "$entry" ]; then
|
||||
entry_size=$(stat -c%s "$entry" 2>/dev/null || stat -f%z "$entry" 2>/dev/null || echo 0)
|
||||
if [ "$entry_size" -gt 1048576 ]; then
|
||||
mkdir -p "$INSTALLER_ISO/boot/grub"
|
||||
cp "$entry" "$INSTALLER_ISO/boot/grub/efi.img"
|
||||
EFI_IMG="$INSTALLER_ISO/boot/grub/efi.img"
|
||||
echo " Recovered EFI image from [BOOT] directory"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
xorriso -as mkisofs -o "$OUTPUT_ISO" \
|
||||
-volid "ARCHIPELAGO" \
|
||||
-J -R \
|
||||
-isohybrid-mbr "$ISOHDPFX" \
|
||||
-c isolinux/boot.cat \
|
||||
-b isolinux/isolinux.bin \
|
||||
-no-emul-boot -boot-load-size 4 -boot-info-table \
|
||||
-eltorito-alt-boot \
|
||||
-e boot/grub/efi.img \
|
||||
-no-emul-boot \
|
||||
-isohybrid-gpt-basdat \
|
||||
"$INSTALLER_ISO"
|
||||
if [ -z "$EFI_IMG" ]; then
|
||||
echo " ⚠️ No EFI boot image found — ISO will only support Legacy BIOS boot"
|
||||
xorriso -as mkisofs -o "$OUTPUT_ISO" \
|
||||
-volid "ARCHIPELAGO" \
|
||||
-iso-level 3 \
|
||||
-J -joliet-long -R \
|
||||
-isohybrid-mbr "$ISOHDPFX" \
|
||||
-c isolinux/boot.cat \
|
||||
-b isolinux/isolinux.bin \
|
||||
-no-emul-boot -boot-load-size 4 -boot-info-table \
|
||||
-partition_offset 16 \
|
||||
"$INSTALLER_ISO"
|
||||
else
|
||||
# Make EFI path relative to INSTALLER_ISO for xorriso
|
||||
EFI_REL="${EFI_IMG#$INSTALLER_ISO/}"
|
||||
xorriso -as mkisofs -o "$OUTPUT_ISO" \
|
||||
-volid "ARCHIPELAGO" \
|
||||
-iso-level 3 \
|
||||
-J -joliet-long -R \
|
||||
-isohybrid-mbr "$ISOHDPFX" \
|
||||
-c isolinux/boot.cat \
|
||||
-b isolinux/isolinux.bin \
|
||||
-no-emul-boot -boot-load-size 4 -boot-info-table \
|
||||
-eltorito-alt-boot \
|
||||
-e "$EFI_REL" \
|
||||
-no-emul-boot \
|
||||
-isohybrid-gpt-basdat \
|
||||
-partition_offset 16 \
|
||||
"$INSTALLER_ISO"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "╔════════════════════════════════════════════════════════════════╗"
|
||||
|
||||
Reference in New Issue
Block a user