fix: harden node upgrades and prepare 1.9.0-alpha

This commit is contained in:
archipelago
2026-10-05 12:43:49 -04:00
parent 138a541d01
commit daac47cac4
129 changed files with 9910 additions and 794 deletions
@@ -89,11 +89,25 @@ describe('appsConfig service filtering', () => {
const entries: Array<[string, PackageDataEntry]> = [
['cuprate', makePkg('cuprate', 'Cuprate', 'money')],
['archy-cuprate-ui', makePkg('archy-cuprate-ui', 'Cuprate UI companion', 'money')],
['cuprate-ui', makePkg('cuprate-ui', 'Cuprate UI', 'money')],
]
expect(filterEntriesForTab(entries, 'apps', 'all').map(([id]) => id)).toEqual(['cuprate'])
expect(filterEntriesForTab(entries, 'services', 'all').map(([id]) => id)).toEqual([])
})
it('groups NetBird parts and BTCPay aliases without hiding a legacy-only installation', () => {
const entries: Array<[string, PackageDataEntry]> = [
['netbird', makePkg('netbird', 'NetBird', 'networking')],
['netbird-dashboard', makePkg('netbird-dashboard', 'NetBird Dashboard', 'networking')],
['netbird-server', makePkg('netbird-server', 'NetBird Server', 'networking')],
['btcpay', makePkg('btcpay', 'BTCPay', 'money')],
['btcpay-server', makePkg('btcpay-server', 'BTCPay Server', 'commerce')],
]
expect(filterEntriesForTab(entries, 'apps', 'all').map(([id]) => id)).toEqual(['netbird', 'btcpay-server'])
expect(filterEntriesForTab(entries, 'services', 'all')).toEqual([])
expect(filterEntriesForTab([entries[3]!], 'apps', 'all').map(([id]) => id)).toEqual(['btcpay'])
})
it('falls back to packaged app icon when static icon token is not a path', () => {
const pkg = makePkg('gitea', 'Gitea', 'dev')
pkg['static-files']!.icon = 'git-branch'
+4 -2
View File
@@ -35,7 +35,7 @@ const INTERNAL_TOOLING_NAMES = new Set([
// Cuprate's dashboard is bundled as a companion of the primary cuprate
// package; showing the generated container as a second Services entry
// defeats the one-app presentation.
'archy-cuprate-ui',
'archy-cuprate-ui', 'cuprate-ui', 'netbird-dashboard', 'netbird-server',
])
export function isInternalToolingPackage(id: string, pkg?: PackageDataEntry): boolean {
@@ -54,7 +54,7 @@ export function isServicePackage(id: string, pkg?: PackageDataEntry): boolean {
// Known app -> category mappings (matches App Store categorisation)
export const APP_CATEGORY_MAP: Record<string, string> = {
'bitcoin-core': 'money', 'bitcoin-knots': 'money', 'bitcoin-ui': 'money', 'cuprate': 'money', 'cuprate-ui': 'money', 'electrumx': 'money', 'electrs': 'money',
'lnd': 'money', 'mempool': 'money', 'mempool-web': 'money', 'btcpay-server': 'commerce',
'lnd': 'money', 'mempool': 'money', 'mempool-web': 'money', 'btcpay-server': 'commerce', 'btcpay': 'commerce', 'btcpayserver': 'commerce',
'fedimint': 'money', 'fedimint-gateway': 'money',
'indeedhub': 'media', 'jellyfin': 'media', 'photoprism': 'media', 'immich': 'media',
'nextcloud': 'data', 'vaultwarden': 'data', 'filebrowser': 'data', 'cryptpad': 'data',
@@ -115,11 +115,13 @@ export function filterEntriesForTab(
selectedCategory: string,
): Array<[string, PackageDataEntry]> {
const hasMempool = entries.some(([id]) => id === 'mempool')
const hasBtcpay = entries.some(([id]) => id === 'btcpay-server')
return entries.filter(([id, pkg]) => {
// Older daemons can retain the frontend manifest alias during a restart.
// Keep one tile while the updated scanner converges; a legacy-only node
// must still be able to see and operate its sole Mempool entry.
if (hasMempool && ['mempool-web', 'mempool-frontend', 'archy-mempool-web'].includes(id)) return false
if (hasBtcpay && ['btcpay', 'btcpayserver'].includes(id)) return false
if (isInternalToolingPackage(id, pkg)) return false
const wantsWebsites = activeTab === 'websites' || activeTab === 'services'
const isWebsite = isWebsitePackage(id, pkg)
+13
View File
@@ -29,6 +29,7 @@ export const SERVICE_NAMES = new Set([
'mysql-mempool', 'mempool-api', 'archy-mempool-web',
'archy-bitcoin-ui', 'archy-lnd-ui', 'archy-electrs-ui',
'bitcoin-ui', 'lnd-ui', 'electrs-ui',
'cuprate-ui', 'netbird-dashboard', 'netbird-server',
'indeedhub-postgres', 'indeedhub-redis', 'indeedhub-minio',
'indeedhub-api', 'indeedhub-ffmpeg',
'indeedhub-relay', 'indeedhub-build_api_1', 'indeedhub-build_ffmpeg-worker_1',
@@ -64,3 +65,15 @@ export function isServiceContainer(id: string): boolean {
export function isStoreListedApp(id: string): boolean {
return !isServiceContainer(id) && !NODE_INTERNAL_IDS.has(id)
}
/** Normalize every catalog source, including persisted caches from older UIs. */
export function normalizeStoreApps<T extends { id: string }>(apps: readonly T[]): T[] {
const result = new Map<string, T>()
for (const app of apps) {
if (!isStoreListedApp(app.id)) continue
const id = ['btcpay', 'btcpayserver'].includes(app.id) ? 'btcpay-server' : app.id
// Prefer the real app's metadata to a legacy image-pin-only alias.
if (!result.has(id) || app.id === id) result.set(id, { ...app, id })
}
return [...result.values()]
}