fix: harden node upgrades and prepare 1.9.0-alpha
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { signedCatalogToApps } from '../curatedApps'
|
||||
import { normalizeStoreApps } from '../../apps/serviceNames'
|
||||
|
||||
describe('one App Store card per product', () => {
|
||||
it('keeps Cuprate and NetBird components out and prefers canonical BTCPay metadata', () => {
|
||||
const entries = {
|
||||
btcpay: { version: '2.4.3' },
|
||||
'btcpay-server': { version: '2.4.3', manifest: { app: { name: 'BTCPay Server', category: 'commerce', metadata: { icon: '/btcpay.svg' } } } },
|
||||
cuprate: { version: '0.1' }, 'cuprate-ui': { version: '1.7' },
|
||||
netbird: { version: '2.38' }, 'netbird-dashboard': { version: '2.38' }, 'netbird-server': { version: '0.71' },
|
||||
}
|
||||
for (const apps of [entries, Object.fromEntries(Object.entries(entries).reverse())]) {
|
||||
const result = signedCatalogToApps({ apps })
|
||||
expect(result.map(x => x.id).sort()).toEqual(['btcpay-server', 'cuprate', 'netbird'])
|
||||
expect(result.find(x => x.id === 'btcpay-server')).toMatchObject({ title: 'BTCPay Server', category: 'commerce', icon: '/btcpay.svg', version: '2.4.3' })
|
||||
}
|
||||
})
|
||||
it('normalizes persisted/community entries repeatedly without hiding independent services', () => {
|
||||
const stale = ['cuprate-ui', 'netbird-server', 'netbird-dashboard', 'btcpay', 'btcpay-server', 'angor-indexer', 'angor-relay', 'electrumx'].map(id => ({ id }))
|
||||
const result = normalizeStoreApps(stale)
|
||||
expect(result.map(x => x.id)).toEqual(['btcpay-server', 'angor-indexer', 'angor-relay', 'electrumx'])
|
||||
expect(normalizeStoreApps(result)).toEqual(result)
|
||||
expect(normalizeStoreApps([{ id: 'btcpay' }])).toEqual([{ id: 'btcpay-server' }])
|
||||
})
|
||||
})
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { MarketplaceApp } from './types'
|
||||
import { isStoreListedApp } from '../apps/serviceNames'
|
||||
import { isStoreListedApp, normalizeStoreApps } from '../apps/serviceNames'
|
||||
|
||||
const R = 'source.archipelago-foundation.org/lfg2025'
|
||||
|
||||
@@ -98,7 +98,7 @@ export function signedCatalogToApps(catalog: SignedAppCatalog): MarketplaceApp[]
|
||||
source: 'signed-catalog',
|
||||
})
|
||||
}
|
||||
return out
|
||||
return normalizeStoreApps(out)
|
||||
}
|
||||
|
||||
/** The daemon-verified signed catalog, kept for synchronous port-auth lookups
|
||||
@@ -192,7 +192,7 @@ const CATALOG_URLS = [
|
||||
* Caches for 1 hour. Returns null only if ALL sources fail. */
|
||||
export async function fetchAppCatalog(): Promise<AppCatalog | null> {
|
||||
// Return cache if fresh
|
||||
if (cachedCatalog && Date.now() - catalogFetchedAt < CATALOG_TTL) return cachedCatalog
|
||||
if (cachedCatalog && Date.now() - catalogFetchedAt < CATALOG_TTL) return { ...cachedCatalog, apps: normalizeStoreApps(cachedCatalog.apps) }
|
||||
|
||||
// The daemon-verified signed catalog first (release-root signature checked
|
||||
// server-side): it is what makes a newly published app appear without a
|
||||
@@ -239,16 +239,16 @@ export async function fetchAppCatalog(): Promise<AppCatalog | null> {
|
||||
// apps); signed entries fill version/image gaps and append brand-new apps.
|
||||
const byId = new Map<string, MarketplaceApp>()
|
||||
for (const app of signedApps) byId.set(app.id, app)
|
||||
for (const app of community?.apps ?? []) {
|
||||
for (const app of normalizeStoreApps(community?.apps ?? [])) {
|
||||
const existing = byId.get(app.id)
|
||||
byId.set(app.id, existing ? { ...app, version: app.version || existing.version, dockerImage: app.dockerImage || existing.dockerImage } : app)
|
||||
byId.set(app.id, existing ? { ...app, version: existing.version || app.version, dockerImage: existing.dockerImage || app.dockerImage } : app)
|
||||
}
|
||||
const merged: AppCatalog = {
|
||||
version: community?.version ?? 1,
|
||||
registry: community?.registry ?? R,
|
||||
featured: signedFeatured ?? community?.featured,
|
||||
storefront: signedStorefront ?? community?.storefront,
|
||||
apps: [...byId.values()],
|
||||
apps: normalizeStoreApps([...byId.values()]),
|
||||
}
|
||||
cachedCatalog = merged
|
||||
catalogFetchedAt = Date.now()
|
||||
@@ -261,6 +261,7 @@ export async function fetchAppCatalog(): Promise<AppCatalog | null> {
|
||||
const stored = localStorage.getItem('archy_catalog')
|
||||
if (stored) {
|
||||
cachedCatalog = JSON.parse(stored) as AppCatalog
|
||||
cachedCatalog.apps = normalizeStoreApps(cachedCatalog.apps)
|
||||
catalogFetchedAt = Date.now() - CATALOG_TTL + 5 * 60 * 1000 // re-check in 5 min
|
||||
return cachedCatalog
|
||||
}
|
||||
@@ -314,6 +315,7 @@ export const INSTALLED_ALIASES: Record<string, string[]> = {
|
||||
mempool: ['mempool', 'mempool-web', 'archy-mempool-web'],
|
||||
bitcoin: ['bitcoin-knots'],
|
||||
btcpay: ['btcpay-server'],
|
||||
'btcpay-server': ['btcpay-server', 'btcpay', 'btcpayserver'],
|
||||
immich: ['immich-server', 'immich-app', 'immich_server'],
|
||||
nextcloud: ['nextcloud-aio', 'nextcloud-server'],
|
||||
fedimint: ['fedimint-gateway'],
|
||||
|
||||
Reference in New Issue
Block a user