Compare commits

..
19 changed files with 242 additions and 68 deletions
+14
View File
@@ -1,5 +1,19 @@
# Changelog
## v1.7.73-alpha (2026-05-19)
- Mobile app launches for iframe-blocked apps now open the direct app URL in a new browser tab immediately instead of landing in a broken in-shell webview that requires a second tap.
- Mobile My Apps/Websites tabs now react to route query changes, App Store pages label the mobile view as Discover, mobile filters have safe bottom spacing, and App Store search ignores the current category so searches cover all available apps.
- My Apps search now surfaces matching App Store entries when the app is not installed, making it possible to jump directly from a failed My Apps search to the installable app details.
- NetBird self-host installs now prefer a `100.x` tailnet/CGNAT address for dashboard, management, relay, STUN, and auth redirect origins when one is present; live repair on `100.89.209.89` updated the existing stack from LAN origins to `100.89.209.89` and restored `netbird-server`.
- App-session iframe frames now focus automatically and wrap the iframe in a scroll host so wheel/touch scrolling works in the active right frame without requiring an initial click.
## v1.7.72-alpha (2026-05-19)
- Settings What's New now includes the missing release notes for `v1.7.68-alpha` through `v1.7.71-alpha`, so the modal reflects the current OTA history instead of stopping at `v1.7.67-alpha`.
- The follow-up release carries the NetBird install fix, Gitea icon polish, mobile app-session fallback updates, and rounder app icon masks from `v1.7.71-alpha` with the Settings modal notes included.
- The local Cargo lockfile version metadata is kept in sync with the release bump after the previous release build updated it.
## v1.7.71-alpha (2026-05-19)
- NetBird stack installs now pre-create `/var/lib/archipelago/netbird/data` before binding it into `netbird-server`, fixing the failed install/start path seen on `100.70.96.88` where Podman rejected the missing host directory.
+1 -1
View File
@@ -80,7 +80,7 @@ checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
[[package]]
name = "archipelago"
version = "1.7.70-alpha"
version = "1.7.72-alpha"
dependencies = [
"anyhow",
"archipelago-container",
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "archipelago"
version = "1.7.71-alpha"
version = "1.7.73-alpha"
edition = "2021"
description = "Archipelago Bitcoin Node OS - Native backend"
authors = ["Archipelago Team"]
+16 -1
View File
@@ -1404,7 +1404,9 @@ impl RpcHandler {
.await
.context("Failed to create NetBird data directory")?;
let host_ip = self.config.host_ip.clone();
let host_ip = detect_netbird_public_host_ip()
.await
.unwrap_or_else(|| self.config.host_ip.clone());
let dashboard_origin = format!("http://{}:8087", host_ip);
let mgmt_origin = format!("http://{}:8086", host_ip);
let relay_secret = read_or_generate_b64_secret("netbird-relay-auth-secret").await;
@@ -1544,6 +1546,19 @@ async fn read_or_generate_b64_secret(name: &str) -> String {
secret
}
async fn detect_netbird_public_host_ip() -> Option<String> {
let output = tokio::process::Command::new("hostname")
.args(["-I"])
.output()
.await
.ok()?;
let stdout = String::from_utf8_lossy(&output.stdout);
stdout
.split_whitespace()
.find(|ip| ip.starts_with("100.") && ip.contains('.'))
.map(str::to_string)
}
#[cfg(test)]
mod tests {
use super::{btcpay_stack_app_ids, mempool_stack_app_ids};
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "neode-ui",
"version": "1.7.71-alpha",
"version": "1.7.73-alpha",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "neode-ui",
"version": "1.7.71-alpha",
"version": "1.7.73-alpha",
"dependencies": {
"@types/dompurify": "^3.0.5",
"@vue-leaflet/vue-leaflet": "^0.10.1",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "neode-ui",
"private": true,
"version": "1.7.71-alpha",
"version": "1.7.73-alpha",
"type": "module",
"scripts": {
"start": "./start-dev.sh",
+9
View File
@@ -1659,6 +1659,15 @@ html:has(body.video-background-active)::before {
filter: drop-shadow(0 10px 25px rgba(0, 0, 0, 0.5));
}
.mobile-filter-btn {
bottom: calc(var(--mobile-tab-bar-height, 72px) + var(--safe-area-bottom, env(safe-area-inset-bottom, 0px)) + 12px);
filter: drop-shadow(0 10px 25px rgba(0, 0, 0, 0.5));
}
.mobile-filter-sheet {
padding-bottom: calc(var(--safe-area-bottom, env(safe-area-inset-bottom, 0px)) + 1.5rem);
}
/* ── Cloud Audio Player (mini bar) ──── */
.cloud-audio-player {
+8 -3
View File
@@ -341,9 +341,8 @@ watch(displayMode, (mode) => {
})
onMounted(() => {
// Desktop apps that block iframes open externally. Mobile keeps the user in
// Archipelago and shows the explicit fallback instead of leaving the shell.
if (!isMobile && mustOpenNewTab.value && appUrl.value) {
// Apps that block iframes open externally instead of landing in a broken webview.
if (mustOpenNewTab.value && appUrl.value) {
window.open(appUrl.value, '_blank', 'noopener,noreferrer')
if (isInlinePanel.value) emit('close')
else closeRouteSession()
@@ -532,6 +531,12 @@ onBeforeUnmount(() => {
opacity: 0;
}
.app-session-frame-scroll-host {
overflow: auto;
overscroll-behavior: contain;
-webkit-overflow-scrolling: touch;
}
/* Mobile: full-bleed app sessions — no border, no radius, no shadow */
@media (max-width: 767px) {
.app-session-root {
+56 -1
View File
@@ -106,10 +106,34 @@
</div>
<!-- No Results -->
<div v-if="filteredPackageEntries.length === 0 && searchQuery" class="text-center py-12">
<div v-if="filteredPackageEntries.length === 0 && marketplaceMatches.length === 0 && searchQuery" class="text-center py-12">
<p class="text-white/70">{{ t('apps.noResults', { query: searchQuery }) }}</p>
</div>
<div v-if="marketplaceMatches.length > 0" class="mb-5">
<div class="flex items-center gap-3 mb-3">
<span class="discover-terminal-tag">app store</span>
<h2 class="text-lg font-bold text-white">Available in Discover</h2>
<div class="flex-1 h-px bg-white/10"></div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<button
v-for="app in marketplaceMatches"
:key="app.id"
type="button"
class="glass-card p-4 text-left flex items-center gap-3 hover:bg-orange-500/5 hover:border-orange-500/15 transition-colors"
@click="openMarketplaceResult(app)"
>
<img v-if="app.icon" :src="app.icon" :alt="app.title" class="w-12 h-12 rounded-xl object-cover bg-white/10" />
<div v-else class="w-12 h-12 rounded-xl bg-white/10 flex-shrink-0"></div>
<div class="min-w-0 flex-1">
<p class="font-semibold text-white truncate">{{ app.title }}</p>
<p class="text-xs text-white/50 truncate">Available in App Store</p>
</div>
</button>
</div>
</div>
<!-- Mobile: iPhone-style icon grid -->
<div class="md:hidden">
<AppIconGrid
@@ -236,10 +260,12 @@ import AppCard from './apps/AppCard.vue'
import AppIconGrid from './apps/AppIconGrid.vue'
import AppsUninstallModal from './apps/AppsUninstallModal.vue'
import { useAppsActions } from './apps/useAppsActions'
import { useMarketplaceApp } from '@/composables/useMarketplaceApp'
import {
type AppsTab, filterEntriesForTab, isWebOnlyApp, isWebsitePackage, opensInTab, resolveRuntimeLaunchUrl,
WEB_ONLY_APPS, WEB_ONLY_APP_URLS, buildAllCategories, useCategoriesWithApps,
} from './apps/appsConfig'
import { getCuratedAppList, INSTALLED_ALIASES, type MarketplaceApp } from './marketplace/marketplaceData'
const { t } = useI18n()
const router = useRouter()
@@ -247,6 +273,7 @@ const route = useRoute()
const store = useAppStore()
const serverStore = useServerStore()
const actions = useAppsActions()
const { setCurrentApp } = useMarketplaceApp()
const showSideload = ref(false)
const sideloading = ref(false)
const sideloadError = ref('')
@@ -266,6 +293,10 @@ const activeTab = ref<AppsTab>(
route.query.tab === 'websites' || route.query.tab === 'services' ? 'websites' : 'apps'
)
watch(() => route.query.tab, (tab) => {
activeTab.value = tab === 'websites' || tab === 'services' ? 'websites' : 'apps'
})
// Search (debounced)
const searchQuery = ref('')
const debouncedSearchQuery = ref('')
@@ -309,6 +340,19 @@ const packages = computed(() => {
const categoriesWithApps = useCategoriesWithApps(packages, ALL_CATEGORIES)
const curatedApps = getCuratedAppList()
const marketplaceMatches = computed(() => {
const q = debouncedSearchQuery.value.trim().toLowerCase()
if (!q || activeTab.value !== 'apps') return [] as MarketplaceApp[]
return curatedApps.filter(app => {
if (isInstalledInMyApps(app.id)) return false
return app.title?.toLowerCase().includes(q) ||
app.id.toLowerCase().includes(q) ||
app.author?.toLowerCase().includes(q) ||
(typeof app.description === 'string' && app.description.toLowerCase().includes(q))
}).slice(0, 6)
})
const isLoadingApps = computed(() => !store.hasLoadedInitialData && !connectionError.value)
// Connection error state
@@ -352,6 +396,17 @@ const filteredPackageEntries = computed(() => {
)
})
function isInstalledInMyApps(appId: string): boolean {
if (appId in packages.value) return true
const aliases = INSTALLED_ALIASES[appId]
return aliases ? aliases.some(alias => alias in packages.value) : false
}
function openMarketplaceResult(app: MarketplaceApp) {
setCurrentApp(app)
router.push({ name: 'marketplace-app-detail', params: { id: app.id }, query: { from: 'apps' } }).catch(() => {})
}
// Uninstall modal
const uninstallModal = ref({ show: false, appId: '', appTitle: '' })
+7
View File
@@ -35,6 +35,10 @@
<!-- Mobile: search -->
<div class="md:hidden mb-4">
<div class="flex items-center gap-2 mb-3">
<span class="discover-terminal-tag">discover</span>
<h1 class="text-lg font-bold text-white">App Store</h1>
</div>
<input
v-model="searchQuery"
type="text"
@@ -312,6 +316,9 @@ const categoriesWithApps = computed(() => {
const filteredApps = computed(() => {
let apps = allApps.value
if (selectedCategory.value && selectedCategory.value !== 'all' && !searchQuery.value) {
apps = apps.filter(app => app.category === selectedCategory.value)
}
if (searchQuery.value) {
const query = searchQuery.value.toLowerCase()
apps = apps.filter(app =>
+5 -1
View File
@@ -37,6 +37,10 @@
<!-- Mobile: search (tabs handled by Dashboard.vue header) -->
<div class="md:hidden mb-4">
<div class="flex items-center gap-2 mb-3">
<span class="discover-terminal-tag">discover</span>
<h1 class="text-lg font-bold text-white">App Store</h1>
</div>
<input
v-model="searchQuery"
type="text"
@@ -258,7 +262,7 @@ const categoriesWithApps = computed(() => {
const filteredApps = computed(() => {
let apps = allApps.value
if (selectedCategory.value && selectedCategory.value !== 'all') {
if (selectedCategory.value && selectedCategory.value !== 'all' && !searchQuery.value) {
apps = apps.filter(app => app.category === selectedCategory.value)
}
@@ -9,16 +9,18 @@
</div>
</Transition>
<iframe
v-if="appUrl && !iframeBlocked"
ref="iframeRef"
:key="refreshKey"
:src="appUrl"
class="absolute inset-0 w-full h-full border-0 iframe-scrollbar-hide"
title="App content"
@load="$emit('iframeLoad')"
@error="$emit('iframeError')"
/>
<div v-if="appUrl && !iframeBlocked" class="absolute inset-0 app-session-frame-scroll-host">
<iframe
ref="iframeRef"
:key="refreshKey"
:src="appUrl"
class="w-full h-full border-0 iframe-scrollbar-hide"
title="App content"
tabindex="0"
@load="$emit('iframeLoad')"
@error="$emit('iframeError')"
/>
</div>
<!-- Iframe blocked fallback -->
<Transition name="content-fade">
@@ -69,9 +71,9 @@
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { nextTick, ref, watch } from 'vue'
defineProps<{
const props = defineProps<{
appUrl: string
appId: string
appTitle: string
@@ -91,5 +93,11 @@ defineEmits<{
const iframeRef = ref<HTMLIFrameElement | null>(null)
watch(() => [props.appUrl, props.refreshKey, props.iframeBlocked], async () => {
if (!props.appUrl || props.iframeBlocked) return
await nextTick()
iframeRef.value?.focus({ preventScroll: true })
}, { immediate: true })
defineExpose({ iframeRef })
</script>
@@ -61,7 +61,7 @@ describe('AppIconGrid', () => {
expect(useAppLauncherStore().panelAppId).toBe('lnd')
})
it('opens desktop new-tab apps through app session on mobile', async () => {
it('routes desktop new-tab apps through app session on mobile', async () => {
Object.defineProperty(window, 'innerWidth', {
value: 390,
writable: true,
@@ -78,5 +78,6 @@ describe('AppIconGrid', () => {
await wrapper.get('.app-icon-item').trigger('click')
expect(mockWindowOpen).not.toHaveBeenCalled()
expect(useAppLauncherStore().panelAppId).toBeNull()
})
})
@@ -22,6 +22,7 @@
to="/dashboard/apps?tab=websites"
class="mode-switcher-btn"
:class="{ 'mode-switcher-btn-active': route.query.tab === 'services' || route.query.tab === 'websites' }"
@click.prevent="router.push({ path: '/dashboard/apps', query: { tab: 'websites' } })"
>Websites</RouterLink>
</div>
</div>
+3 -4
View File
@@ -4,8 +4,7 @@
<Teleport to="body">
<button
@click="showFilter = true"
class="md:hidden fixed right-4 z-40 w-14 h-14 rounded-full glass-button flex items-center justify-center shadow-2xl mobile-back-btn"
style="left: auto;"
class="md:hidden fixed right-4 z-[2400] w-14 h-14 rounded-full glass-button flex items-center justify-center shadow-2xl mobile-filter-btn"
>
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z" />
@@ -17,10 +16,10 @@
<Transition name="modal">
<div
v-if="showFilter"
class="fixed inset-0 z-50 flex items-end justify-center md:hidden bg-black/10 backdrop-blur-md"
class="fixed inset-0 z-[3000] flex items-end justify-center md:hidden bg-black/10 backdrop-blur-md"
@click.self="closeFilter"
>
<div ref="filterModalRef" class="glass-card p-6 w-full rounded-t-3xl max-h-[80vh] overflow-y-auto">
<div ref="filterModalRef" class="glass-card p-6 w-full rounded-t-3xl max-h-[80vh] overflow-y-auto mobile-filter-sheet">
<div class="flex items-center justify-between mb-6">
<h2 class="text-2xl font-bold text-white">Filter</h2>
<button @click="closeFilter" class="text-white/60 hover:text-white transition-colors">
@@ -3,8 +3,7 @@
<Teleport to="body">
<button
@click="showModal = true"
class="md:hidden fixed right-4 z-40 w-14 h-14 rounded-full glass-button flex items-center justify-center shadow-2xl mobile-back-btn"
style="left: auto;"
class="md:hidden fixed right-4 z-[2400] w-14 h-14 rounded-full glass-button flex items-center justify-center shadow-2xl mobile-filter-btn"
>
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z" />
@@ -16,10 +15,10 @@
<Transition name="modal">
<div
v-if="showModal"
class="fixed inset-0 z-50 flex items-end justify-center md:hidden bg-black/10 backdrop-blur-md"
class="fixed inset-0 z-[3000] flex items-end justify-center md:hidden bg-black/10 backdrop-blur-md"
@click.self="close()"
>
<div ref="modalRef" class="glass-card p-6 w-full rounded-t-3xl max-h-[80vh] overflow-y-auto">
<div ref="modalRef" class="glass-card p-6 w-full rounded-t-3xl max-h-[80vh] overflow-y-auto mobile-filter-sheet">
<!-- Header -->
<div class="flex items-center justify-between mb-6">
<h2 class="text-2xl font-bold text-white">{{ t('marketplace.filterByCategory') }}</h2>
@@ -180,6 +180,65 @@ init()
</button>
</div>
<div class="overflow-y-auto flex-1 min-h-0 space-y-6 pr-1">
<!-- v1.7.72-alpha -->
<div>
<div class="flex items-center gap-2 mb-3">
<span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.72-alpha</span>
<span class="text-xs text-white/40">May 19, 2026</span>
</div>
<div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
<p>Settings What's New is caught up again. The modal now includes the missing entries for v1.7.68-alpha through v1.7.71-alpha instead of stopping at v1.7.67-alpha.</p>
<p>The release lockfile metadata is also kept in sync with the previous release bump.</p>
</div>
</div>
<!-- v1.7.71-alpha -->
<div>
<div class="flex items-center gap-2 mb-3">
<span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.71-alpha</span>
<span class="text-xs text-white/40">May 19, 2026</span>
</div>
<div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
<p>NetBird stack installs now create the exact persistent data directory before binding it into the server container, fixing the failed install path seen on the test node.</p>
<p>NetBird start and restart actions bring up the control-plane server before the dashboard, so lifecycle actions use the correct dependency order.</p>
<p>App-session fallbacks now return to My Apps under /dashboard, mobile iframe-blocked apps stay inside Archipelago with an explicit fallback, and installed Gitea containers show the packaged Gitea icon with rounder app icon masks.</p>
</div>
</div>
<!-- v1.7.70-alpha -->
<div>
<div class="flex items-center gap-2 mb-3">
<span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.70-alpha</span>
<span class="text-xs text-white/40">May 19, 2026</span>
</div>
<div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
<p>NetBird was corrected from the peer/client daemon image to the self-hosted control-plane stack, with a launchable dashboard on port 8087, management/signal/relay server on 8086, and STUN on UDP 3478.</p>
<p>Local app launches use direct host ports and carry an explicit dashboard return target, so closing an app session goes back to the launching dashboard screen instead of falling through to browser history or a 404.</p>
<p>Mobile launches ignore stale desktop panel state and route into the full app-session webview. The desktop sidebar also keeps top and bottom regions pinned while only the middle navigation scrolls on short screens.</p>
</div>
</div>
<!-- v1.7.69-alpha -->
<div>
<div class="flex items-center gap-2 mb-3">
<span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.69-alpha</span>
<span class="text-xs text-white/40">May 19, 2026</span>
</div>
<div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
<p>App installs now allow up to 10 minutes for slow initial install RPCs, matching large container pulls and preventing apps from disappearing from My Apps while the backend is still pulling or retrying mirrors.</p>
<p>Gitea is now categorized as a known Data app and stays visible during slow registry pulls. Live diagnostics confirmed the Gitea container came up healthy on port 3001 after the frontend had previously timed out too early.</p>
<p>NetBird was added to the catalog as a recommended networking app, and the Archipelago terminal includes nano on new installs and existing-node self-update fallback.</p>
</div>
</div>
<!-- v1.7.68-alpha -->
<div>
<div class="flex items-center gap-2 mb-3">
<span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.68-alpha</span>
<span class="text-xs text-white/40">May 19, 2026</span>
</div>
<div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
<p>BTCPay Server now ships on the official btcpayserver image, fixing the plugin catalog crash caused by newer plugin dependency metadata while preserving existing data and Postgres databases.</p>
<p>BTCPay health checks no longer require curl inside the container, and Nginx Proxy Manager certificate challenge handling now avoids hijacking local API traffic while syncing issued public proxy hosts into host nginx.</p>
<p>System Update confirmation and mirror modals now cover the whole app, app-session close returns to the previous dashboard screen, and mobile app launches stay inside Archipelago's app-session webview.</p>
</div>
</div>
<!-- v1.7.67-alpha -->
<div>
<div class="flex items-center gap-2 mb-3">
+17 -18
View File
@@ -1,30 +1,29 @@
{
"version": "1.7.71-alpha",
"version": "1.7.73-alpha",
"release_date": "2026-05-19",
"changelog": [
"NetBird stack installs now pre-create `/var/lib/archipelago/netbird/data` before binding it into `netbird-server`, fixing the failed install/start path seen on `100.70.96.88` where Podman rejected the missing host directory.",
"NetBird start/restart ordering now starts `netbird-server` before the dashboard container so lifecycle actions bring the control plane up before the UI.",
"App-session invalid IDs and panel-mode fallbacks now return to `/dashboard/apps`, avoiding the stale `/apps` route that could render a 404.",
"Mobile launches for apps that block iframes now stay inside the Archipelago app-session fallback instead of automatically opening an external browser tab.",
"Installed Gitea containers now report the packaged Gitea icon, and app icon masks use a rounder radius on mobile grids, app cards, and detail headers.",
"Validation passed with `npm run type-check`, focused Vitest app-session/app-grid tests, `cargo fmt --all --check --manifest-path core/Cargo.toml`, and `cargo check -p archipelago --manifest-path core/Cargo.toml`."
"Mobile app launches for iframe-blocked apps now open the direct app URL in a new browser tab immediately instead of landing in a broken in-shell webview that requires a second tap.",
"Mobile My Apps/Websites tabs now react to route query changes, App Store pages label the mobile view as Discover, mobile filters have safe bottom spacing, and App Store search ignores the current category so searches cover all available apps.",
"My Apps search now surfaces matching App Store entries when the app is not installed, making it possible to jump directly from a failed My Apps search to the installable app details.",
"NetBird self-host installs now prefer a `100.x` tailnet/CGNAT address for dashboard, management, relay, STUN, and auth redirect origins when one is present; live repair on `100.89.209.89` updated the existing stack from LAN origins to `100.89.209.89` and restored `netbird-server`.",
"App-session iframe frames now focus automatically and wrap the iframe in a scroll host so wheel/touch scrolling works in the active right frame without requiring an initial click."
],
"components": [
{
"name": "archipelago",
"current_version": "1.7.71-alpha",
"new_version": "1.7.71-alpha",
"download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.71-alpha/archipelago",
"sha256": "96895f2034cf9760103813954c9ac5532060498929ebc2dc78a3517adbdbd035",
"size_bytes": 42985824
"current_version": "1.7.73-alpha",
"new_version": "1.7.73-alpha",
"download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.73-alpha/archipelago",
"sha256": "458b510e34c0d69e39294ff05eb56ed89c2eb896b72074ecaea0c2bb52477455",
"size_bytes": 42997664
},
{
"name": "archipelago-frontend-1.7.71-alpha.tar.gz",
"current_version": "1.7.71-alpha",
"new_version": "1.7.71-alpha",
"download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.71-alpha/archipelago-frontend-1.7.71-alpha.tar.gz",
"sha256": "80c185b7ed6831a4bdd5b54ead65f5b7ca21706687cdcd147dc4cdbdc1c1ed7a",
"size_bytes": 166478267
"name": "archipelago-frontend-1.7.73-alpha.tar.gz",
"current_version": "1.7.73-alpha",
"new_version": "1.7.73-alpha",
"download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.73-alpha/archipelago-frontend-1.7.73-alpha.tar.gz",
"sha256": "586ee104787b8c69230f2616dd6256926299907fde53d6dd6f0015b98c5db41b",
"size_bytes": 166488057
}
]
}
+17 -18
View File
@@ -1,30 +1,29 @@
{
"version": "1.7.71-alpha",
"version": "1.7.73-alpha",
"release_date": "2026-05-19",
"changelog": [
"NetBird stack installs now pre-create `/var/lib/archipelago/netbird/data` before binding it into `netbird-server`, fixing the failed install/start path seen on `100.70.96.88` where Podman rejected the missing host directory.",
"NetBird start/restart ordering now starts `netbird-server` before the dashboard container so lifecycle actions bring the control plane up before the UI.",
"App-session invalid IDs and panel-mode fallbacks now return to `/dashboard/apps`, avoiding the stale `/apps` route that could render a 404.",
"Mobile launches for apps that block iframes now stay inside the Archipelago app-session fallback instead of automatically opening an external browser tab.",
"Installed Gitea containers now report the packaged Gitea icon, and app icon masks use a rounder radius on mobile grids, app cards, and detail headers.",
"Validation passed with `npm run type-check`, focused Vitest app-session/app-grid tests, `cargo fmt --all --check --manifest-path core/Cargo.toml`, and `cargo check -p archipelago --manifest-path core/Cargo.toml`."
"Mobile app launches for iframe-blocked apps now open the direct app URL in a new browser tab immediately instead of landing in a broken in-shell webview that requires a second tap.",
"Mobile My Apps/Websites tabs now react to route query changes, App Store pages label the mobile view as Discover, mobile filters have safe bottom spacing, and App Store search ignores the current category so searches cover all available apps.",
"My Apps search now surfaces matching App Store entries when the app is not installed, making it possible to jump directly from a failed My Apps search to the installable app details.",
"NetBird self-host installs now prefer a `100.x` tailnet/CGNAT address for dashboard, management, relay, STUN, and auth redirect origins when one is present; live repair on `100.89.209.89` updated the existing stack from LAN origins to `100.89.209.89` and restored `netbird-server`.",
"App-session iframe frames now focus automatically and wrap the iframe in a scroll host so wheel/touch scrolling works in the active right frame without requiring an initial click."
],
"components": [
{
"name": "archipelago",
"current_version": "1.7.71-alpha",
"new_version": "1.7.71-alpha",
"download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.71-alpha/archipelago",
"sha256": "96895f2034cf9760103813954c9ac5532060498929ebc2dc78a3517adbdbd035",
"size_bytes": 42985824
"current_version": "1.7.73-alpha",
"new_version": "1.7.73-alpha",
"download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.73-alpha/archipelago",
"sha256": "458b510e34c0d69e39294ff05eb56ed89c2eb896b72074ecaea0c2bb52477455",
"size_bytes": 42997664
},
{
"name": "archipelago-frontend-1.7.71-alpha.tar.gz",
"current_version": "1.7.71-alpha",
"new_version": "1.7.71-alpha",
"download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.71-alpha/archipelago-frontend-1.7.71-alpha.tar.gz",
"sha256": "80c185b7ed6831a4bdd5b54ead65f5b7ca21706687cdcd147dc4cdbdc1c1ed7a",
"size_bytes": 166478267
"name": "archipelago-frontend-1.7.73-alpha.tar.gz",
"current_version": "1.7.73-alpha",
"new_version": "1.7.73-alpha",
"download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.73-alpha/archipelago-frontend-1.7.73-alpha.tar.gz",
"sha256": "586ee104787b8c69230f2616dd6256926299907fde53d6dd6f0015b98c5db41b",
"size_bytes": 166488057
}
]
}