Feature/fe new registry (#2647)

* bugfixes

* update fe types

* implement new registry types in marketplace and ui

* fix marketplace types to have default params

* add alt implementation toggle

* merge cleanup

* more cleanup and notes

* fix build

* cleanup sync with next/minor

* add exver JS parser

* parse ValidExVer to string

* update types to interface

* add VersionRange and comparative functions

* Parse ExtendedVersion from string

* add conjunction, disjunction, and inversion logic

* consider flavor in satisfiedBy fn

* consider prerelease for ordering

* add compare fn for sorting

* rename fns for consistency

* refactoring

* update compare fn to return null if flavors don't match

* begin simplifying dependencies

* under construction

* wip

* add dependency metadata to CurrentDependencyInfo

* ditch inheritance for recursive VersionRange constructor. Recursive 'satisfiedBy' fn wip

* preprocess manifest

* misc fixes

* use sdk version as osVersion in manifest

* chore: Change the type to just validate and not generate all solutions.

* add publishedAt

* fix pegjs exports

* integrate exver into sdk

* misc fixes

* complete satisfiedBy fn

* refactor - use greaterThanOrEqual and lessThanOrEqual fns

* fix tests

* update dependency details

* update types

* remove interim types

* rename alt implementation to flavor

* cleanup os update

* format exver.ts

* add s9pk parsing endpoints

* fix build

* update to exver

* exver and bug fixes

* update static endpoints + cleanup

* cleanup

* update static proxy verification

* make mocks more robust; fix dep icon fallback; cleanup

* refactor alert versions and update fixtures

* registry bugfixes

* misc fixes

* cleanup unused

* convert patchdb ui seed to camelCase

* update otherVersions type

* change otherVersions: null to 'none'

* refactor and complete feature

* improve static endpoints

* fix install params

* mask systemd-networkd-wait-online

* fix static file fetching

* include non-matching versions in otherVersions

* convert release notes to modal and clean up displayExver

* alert for no other versions

* Fix ack-instructions casing

* fix indeterminate loader on service install

---------

Co-authored-by: Aiden McClelland <me@drbonez.dev>
Co-authored-by: Shadowy Super Coder <musashidisciple@proton.me>
Co-authored-by: Aiden McClelland <3732071+dr-bonez@users.noreply.github.com>
Co-authored-by: J H <dragondef@gmail.com>
Co-authored-by: Matt Hill <mattnine@protonmail.com>
This commit is contained in:
Lucy
2024-07-22 20:48:12 -04:00
committed by GitHub
parent 0fbb18b315
commit a535fc17c3
196 changed files with 7002 additions and 2162 deletions

View File

@@ -1,11 +1,11 @@
import { Injectable } from '@angular/core'
import { Inject, Injectable } from '@angular/core'
import {
MarketplacePkg,
AbstractMarketplaceService,
StoreData,
Marketplace,
StoreInfo,
StoreIdentity,
MarketplacePkg,
GetPackageRes,
} from '@start9labs/marketplace'
import {
BehaviorSubject,
@@ -37,8 +37,9 @@ import {
tap,
} from 'rxjs/operators'
import { ConfigService } from './config.service'
import { sameUrl } from '@start9labs/shared'
import { Exver, sameUrl } from '@start9labs/shared'
import { ClientStorageService } from './client-storage.service'
import { ExtendedVersion, T } from '@start9labs/start-sdk'
@Injectable()
export class MarketplaceService implements AbstractMarketplaceService {
@@ -93,11 +94,9 @@ export class MarketplaceService implements AbstractMarketplaceService {
mergeMap(({ url, name }) =>
this.fetchStore$(url).pipe(
tap(data => {
if (data?.info) this.updateStoreName(url, name, data.info.name)
}),
map<StoreData | null, [string, StoreData | null]>(data => {
return [url, data]
if (data?.info.name) this.updateStoreName(url, name, data.info.name)
}),
map<StoreData | null, [string, StoreData | null]>(data => [url, data]),
startWith<[string, StoreData | null]>([url, null]),
),
),
@@ -148,6 +147,7 @@ export class MarketplaceService implements AbstractMarketplaceService {
private readonly patch: PatchDB<DataModel>,
private readonly config: ConfigService,
private readonly clientStorageService: ClientStorageService,
private readonly exver: Exver,
) {}
getKnownHosts$(filtered = false): Observable<StoreIdentity[]> {
@@ -170,28 +170,29 @@ export class MarketplaceService implements AbstractMarketplaceService {
getPackage$(
id: string,
version: string,
optionalUrl?: string,
version: string | null,
flavor: string | null,
registryUrl?: string,
): Observable<MarketplacePkg> {
return this.patch.watch$('ui', 'marketplace').pipe(
switchMap(uiMarketplace => {
const url = optionalUrl || uiMarketplace.selectedUrl
return this.selectedHost$.pipe(
switchMap(selected =>
this.marketplace$.pipe(
switchMap(m => {
const url = registryUrl || selected.url
if (version !== '*' || !uiMarketplace.knownHosts[url]) {
return this.fetchPackage$(id, version, url)
}
const pkg = m[url]?.packages.find(
p =>
p.id === id &&
p.flavor === flavor &&
(!version || this.exver.compareExver(p.version, version) === 0),
)
return this.marketplace$.pipe(
map(m => m[url]),
filter(Boolean),
take(1),
map(
store =>
store.packages.find(p => p.manifest.id === id) ||
({} as MarketplacePkg),
),
)
}),
return !!pkg
? of(pkg)
: this.fetchPackage$(url, id, version, flavor)
}),
),
),
)
}
@@ -210,56 +211,22 @@ export class MarketplaceService implements AbstractMarketplaceService {
): Promise<void> {
const params: RR.InstallPackageReq = {
id,
versionSpec: `=${version}`,
version,
registry: url,
}
await this.api.installPackage(params)
}
fetchInfo$(url: string): Observable<StoreInfo> {
return this.patch.watch$('serverInfo').pipe(
take(1),
switchMap(serverInfo => {
const qp: RR.GetMarketplaceInfoReq = { serverId: serverInfo.id }
return this.api.marketplaceProxy<RR.GetMarketplaceInfoRes>(
'/package/v0/info',
qp,
url,
)
}),
)
fetchInfo$(url: string): Observable<T.RegistryInfo> {
return from(this.api.getRegistryInfo(url))
}
fetchReleaseNotes$(
id: string,
url?: string,
): Observable<Record<string, string>> {
return this.selectedHost$.pipe(
switchMap(m => {
return from(
this.api.marketplaceProxy<Record<string, string>>(
`/package/v0/release-notes/${id}`,
{},
url || m.url,
),
)
}),
)
}
fetchStatic$(id: string, type: string, url?: string): Observable<string> {
return this.selectedHost$.pipe(
switchMap(m => {
return from(
this.api.marketplaceProxy<string>(
`/package/v0/${type}/${id}`,
{},
url || m.url,
),
)
}),
)
fetchStatic$(
pkg: MarketplacePkg,
type: 'LICENSE.md' | 'instructions.md',
): Observable<string> {
return from(this.api.getStaticProxy(pkg, type))
}
private fetchStore$(url: string): Observable<StoreData | null> {
@@ -273,33 +240,57 @@ export class MarketplaceService implements AbstractMarketplaceService {
)
}
private fetchPackages$(
url: string,
params: Omit<RR.GetMarketplacePackagesReq, 'page' | 'per-page'> = {},
): Observable<MarketplacePkg[]> {
const qp: RR.GetMarketplacePackagesReq = {
...params,
page: 1,
perPage: 100,
}
if (qp.ids) qp.ids = JSON.stringify(qp.ids)
return from(
this.api.marketplaceProxy<RR.GetMarketplacePackagesRes>(
'/package/v0/index',
qp,
url,
),
private fetchPackages$(url: string): Observable<MarketplacePkg[]> {
return from(this.api.getRegistryPackages(url)).pipe(
map(packages => {
return Object.entries(packages).flatMap(([id, pkgInfo]) =>
Object.keys(pkgInfo.best).map(version =>
this.convertToMarketplacePkg(
id,
version,
this.exver.getFlavor(version),
pkgInfo,
),
),
)
}),
)
}
private fetchPackage$(
convertToMarketplacePkg(
id: string,
version: string,
version: string | null,
flavor: string | null,
pkgInfo: GetPackageRes,
): MarketplacePkg {
version =
version ||
Object.keys(pkgInfo.best).find(v => this.exver.getFlavor(v) === flavor) ||
null
return !version || !pkgInfo.best[version]
? ({} as MarketplacePkg)
: {
id,
version,
flavor,
...pkgInfo,
...pkgInfo.best[version],
}
}
private fetchPackage$(
url: string,
id: string,
version: string | null,
flavor: string | null,
): Observable<MarketplacePkg> {
return this.fetchPackages$(url, { ids: [{ id, version }] }).pipe(
map(pkgs => pkgs[0] || {}),
return from(
this.api.getRegistryPackage(url, id, version ? `=${version}` : null),
).pipe(
map(pkgInfo =>
this.convertToMarketplacePkg(id, version, flavor, pkgInfo),
),
)
}