refactor: rename manifest metadata fields and improve error display

Rename wrapperRepo→packageRepo, marketingSite→marketingUrl,
docsUrl→docsUrls (array), remove supportSite. Add display_src/display_dbg
helpers to Error. Fix DepInfo description type to LocaleString. Update
web UI, SDK bindings, tests, and fixtures to match. Clean up cli_attach
error handling and remove dead commented code.
This commit is contained in:
Aiden McClelland
2026-02-17 18:40:50 -07:00
parent 313b2df540
commit 4cae00cb33
16 changed files with 142 additions and 173 deletions

View File

@@ -45,7 +45,7 @@ impl TS for DepInfo {
"DepInfo".into() "DepInfo".into()
} }
fn inline() -> String { fn inline() -> String {
"{ description: string | null, optional: boolean } & MetadataSrc".into() "{ description: LocaleString | null, optional: boolean } & MetadataSrc".into()
} }
fn inline_flattened() -> String { fn inline_flattened() -> String {
Self::inline() Self::inline()
@@ -54,7 +54,8 @@ impl TS for DepInfo {
where where
Self: 'static, Self: 'static,
{ {
v.visit::<MetadataSrc>() v.visit::<MetadataSrc>();
v.visit::<LocaleString>();
} }
fn output_path() -> Option<&'static std::path::Path> { fn output_path() -> Option<&'static std::path::Path> {
Some(Path::new("DepInfo.ts")) Some(Path::new("DepInfo.ts"))

View File

@@ -3,6 +3,7 @@ use std::fmt::{Debug, Display};
use axum::http::StatusCode; use axum::http::StatusCode;
use axum::http::uri::InvalidUri; use axum::http::uri::InvalidUri;
use color_eyre::eyre::eyre; use color_eyre::eyre::eyre;
use imbl_value::InternedString;
use num_enum::TryFromPrimitive; use num_enum::TryFromPrimitive;
use patch_db::Value; use patch_db::Value;
use rpc_toolkit::reqwest; use rpc_toolkit::reqwest;
@@ -204,17 +205,12 @@ pub struct Error {
impl Display for Error { impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}: {:#}", &self.kind.as_str(), self.source) write!(f, "{}: {}", &self.kind.as_str(), self.display_src())
} }
} }
impl Debug for Error { impl Debug for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!( write!(f, "{}: {}", &self.kind.as_str(), self.display_dbg())
f,
"{}: {:?}",
&self.kind.as_str(),
self.debug.as_ref().unwrap_or(&self.source)
)
} }
} }
impl Error { impl Error {
@@ -235,8 +231,13 @@ impl Error {
} }
pub fn clone_output(&self) -> Self { pub fn clone_output(&self) -> Self {
Error { Error {
source: eyre!("{}", self.source), source: eyre!("{:#}", self.source),
debug: self.debug.as_ref().map(|e| eyre!("{e}")), debug: Some(
self.debug
.as_ref()
.map(|e| eyre!("{e}"))
.unwrap_or_else(|| eyre!("{:?}", self.source)),
),
kind: self.kind, kind: self.kind,
info: self.info.clone(), info: self.info.clone(),
task: None, task: None,
@@ -257,6 +258,30 @@ impl Error {
self.task.take(); self.task.take();
self self
} }
pub fn display_src(&self) -> impl Display {
struct D<'a>(&'a Error);
impl<'a> Display for D<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:#}", self.0.source)
}
}
D(self)
}
pub fn display_dbg(&self) -> impl Display {
struct D<'a>(&'a Error);
impl<'a> Display for D<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(debug) = &self.0.debug {
write!(f, "{}", debug)
} else {
write!(f, "{:?}", self.0.source)
}
}
}
D(self)
}
} }
impl axum::response::IntoResponse for Error { impl axum::response::IntoResponse for Error {
fn into_response(self) -> axum::response::Response { fn into_response(self) -> axum::response::Response {
@@ -433,9 +458,11 @@ impl Debug for ErrorData {
impl std::error::Error for ErrorData {} impl std::error::Error for ErrorData {}
impl From<Error> for ErrorData { impl From<Error> for ErrorData {
fn from(value: Error) -> Self { fn from(value: Error) -> Self {
let details = value.display_src().to_string();
let debug = value.display_dbg().to_string();
Self { Self {
details: value.to_string(), details,
debug: format!("{:?}", value), debug,
info: value.info, info: value.info,
} }
} }
@@ -623,13 +650,10 @@ impl<T> ResultExt<T, Error> for Result<T, Error> {
fn with_ctx<F: FnOnce(&Error) -> (ErrorKind, D), D: Display>(self, f: F) -> Result<T, Error> { fn with_ctx<F: FnOnce(&Error) -> (ErrorKind, D), D: Display>(self, f: F) -> Result<T, Error> {
self.map_err(|e| { self.map_err(|e| {
let (kind, ctx) = f(&e); let (kind, ctx) = f(&e);
let ctx = InternedString::from_display(&ctx);
let source = e.source; let source = e.source;
let with_ctx = format!("{ctx}: {source}"); let source = source.wrap_err(ctx.clone());
let source = source.wrap_err(with_ctx); let debug = e.debug.map(|e| e.wrap_err(ctx));
let debug = e.debug.map(|e| {
let with_ctx = format!("{ctx}: {e}");
e.wrap_err(with_ctx)
});
Error { Error {
kind, kind,
source, source,

View File

@@ -206,9 +206,7 @@ impl TryFrom<ManifestV1> for Manifest {
license: value.license.into(), license: value.license.into(),
package_repo: value.wrapper_repo, package_repo: value.wrapper_repo,
upstream_repo: value.upstream_repo, upstream_repo: value.upstream_repo,
marketing_url: Some( marketing_url: Some(value.marketing_site.unwrap_or_else(|| default_url.clone())),
value.marketing_site.unwrap_or_else(|| default_url.clone()),
),
donation_url: value.donation_url, donation_url: value.donation_url,
docs_urls: Vec::new(), docs_urls: Vec::new(),
description: value.description, description: value.description,

View File

@@ -16,7 +16,7 @@ use futures::{FutureExt, SinkExt, StreamExt, TryStreamExt};
use imbl_value::{InternedString, json}; use imbl_value::{InternedString, json};
use itertools::Itertools; use itertools::Itertools;
use nix::sys::signal::Signal; use nix::sys::signal::Signal;
use persistent_container::{PersistentContainer, Subcontainer}; use persistent_container::PersistentContainer;
use rpc_toolkit::HandlerArgs; use rpc_toolkit::HandlerArgs;
use rpc_toolkit::yajrc::RpcError; use rpc_toolkit::yajrc::RpcError;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -1195,10 +1195,12 @@ pub async fn cli_attach(
{ {
Ok(a) => a, Ok(a) => a,
Err(e) => { Err(e) => {
if e.kind != ErrorKind::InvalidRequest {
return Err(e);
}
let prompt = e.to_string(); let prompt = e.to_string();
let options: Vec<SubcontainerInfo> = from_value(e.info)?; let options: Vec<SubcontainerInfo> = from_value(e.info)?;
let choice = choose(&prompt, &options).await?; let choice = choose(&prompt, &options).await?;
println!();
params["subcontainer"] = to_value(&choice.id)?; params["subcontainer"] = to_value(&choice.id)?;
context context
.call_remote::<RpcContext>(&method, params.clone()) .call_remote::<RpcContext>(&method, params.clone())
@@ -1208,6 +1210,7 @@ pub async fn cli_attach(
)?; )?;
let mut ws = context.ws_continuation(guid).await?; let mut ws = context.ws_continuation(guid).await?;
print!("\r");
let (kill, thread_kill) = tokio::sync::oneshot::channel(); let (kill, thread_kill) = tokio::sync::oneshot::channel();
let (thread_send, recv) = tokio::sync::mpsc::channel(4 * CAP_1_KiB); let (thread_send, recv) = tokio::sync::mpsc::channel(4 * CAP_1_KiB);
let stdin_thread: NonDetachingJoinHandle<()> = tokio::task::spawn_blocking(move || { let stdin_thread: NonDetachingJoinHandle<()> = tokio::task::spawn_blocking(move || {
@@ -1236,18 +1239,6 @@ pub async fn cli_attach(
let mut stderr = Some(stderr); let mut stderr = Some(stderr);
loop { loop {
futures::select_biased! { futures::select_biased! {
// signal = tokio:: => {
// let exit = exit?;
// if current_out != "exit" {
// ws.send(Message::Text("exit".into()))
// .await
// .with_kind(ErrorKind::Network)?;
// current_out = "exit";
// }
// ws.send(Message::Binary(
// i32::to_be_bytes(exit.into_raw()).to_vec()
// )).await.with_kind(ErrorKind::Network)?;
// }
input = stdin.as_mut().map_or( input = stdin.as_mut().map_or(
futures::future::Either::Left(futures::future::pending()), futures::future::Either::Left(futures::future::pending()),
|s| futures::future::Either::Right(s.recv()) |s| futures::future::Either::Right(s.recv())

View File

@@ -0,0 +1,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { GatewayId } from './GatewayId'
export type CheckDnsParams = { gateway: GatewayId }

View File

@@ -1,7 +1,8 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { LocaleString } from './LocaleString'
import type { MetadataSrc } from './MetadataSrc' import type { MetadataSrc } from './MetadataSrc'
export type DepInfo = { export type DepInfo = {
description: string | null description: LocaleString | null
optional: boolean optional: boolean
} & MetadataSrc } & MetadataSrc

View File

@@ -13,27 +13,26 @@ import type { VolumeId } from './VolumeId'
export type Manifest = { export type Manifest = {
id: PackageId id: PackageId
title: string
version: Version version: Version
satisfies: Array<Version> satisfies: Array<Version>
releaseNotes: LocaleString
canMigrateTo: string canMigrateTo: string
canMigrateFrom: string canMigrateFrom: string
license: string
wrapperRepo: string
upstreamRepo: string
supportSite: string
marketingSite: string
donationUrl: string | null
docsUrl: string | null
description: Description
images: { [key: ImageId]: ImageConfig } images: { [key: ImageId]: ImageConfig }
volumes: Array<VolumeId> volumes: Array<VolumeId>
alerts: Alerts
dependencies: Dependencies dependencies: Dependencies
hardwareRequirements: HardwareRequirements hardwareRequirements: HardwareRequirements
hardwareAcceleration: boolean title: string
description: Description
releaseNotes: LocaleString
gitHash: GitHash | null gitHash: GitHash | null
license: string
packageRepo: string
upstreamRepo: string
marketingUrl: string
donationUrl: string | null
docsUrls: string[]
alerts: Alerts
osVersion: string osVersion: string
sdkVersion: string | null sdkVersion: string | null
hardwareAcceleration: boolean
} }

View File

@@ -11,22 +11,21 @@ import type { PackageId } from './PackageId'
import type { RegistryAsset } from './RegistryAsset' import type { RegistryAsset } from './RegistryAsset'
export type PackageVersionInfo = { export type PackageVersionInfo = {
icon: DataUrl
dependencyMetadata: { [key: PackageId]: DependencyMetadata }
sourceVersion: string | null sourceVersion: string | null
s9pks: Array<[HardwareRequirements, RegistryAsset<MerkleArchiveCommitment>]> s9pks: Array<[HardwareRequirements, RegistryAsset<MerkleArchiveCommitment>]>
title: string title: string
icon: DataUrl
description: Description description: Description
releaseNotes: LocaleString releaseNotes: LocaleString
gitHash: GitHash | null gitHash: GitHash | null
license: string license: string
wrapperRepo: string packageRepo: string
upstreamRepo: string upstreamRepo: string
supportSite: string marketingUrl: string
marketingSite: string
donationUrl: string | null donationUrl: string | null
docsUrl: string | null docsUrls: string[]
alerts: Alerts alerts: Alerts
dependencyMetadata: { [key: PackageId]: DependencyMetadata }
osVersion: string osVersion: string
sdkVersion: string | null sdkVersion: string | null
hardwareAcceleration: boolean hardwareAcceleration: boolean

View File

@@ -56,6 +56,7 @@ export { Category } from './Category'
export { Celsius } from './Celsius' export { Celsius } from './Celsius'
export { CheckDependenciesParam } from './CheckDependenciesParam' export { CheckDependenciesParam } from './CheckDependenciesParam'
export { CheckDependenciesResult } from './CheckDependenciesResult' export { CheckDependenciesResult } from './CheckDependenciesResult'
export { CheckDnsParams } from './CheckDnsParams'
export { CheckPortParams } from './CheckPortParams' export { CheckPortParams } from './CheckPortParams'
export { CheckPortRes } from './CheckPortRes' export { CheckPortRes } from './CheckPortRes'
export { CifsAddParams } from './CifsAddParams' export { CifsAddParams } from './CifsAddParams'

View File

@@ -21,22 +21,17 @@ export type SDKManifest = {
* URL of the StartOS package repository * URL of the StartOS package repository
* @example `https://github.com/Start9Labs/nextcloud-startos` * @example `https://github.com/Start9Labs/nextcloud-startos`
*/ */
readonly wrapperRepo: string readonly packageRepo: string
/** /**
* URL of the upstream service repository * URL of the upstream service repository
* @example `https://github.com/nextcloud/docker` * @example `https://github.com/nextcloud/docker`
*/ */
readonly upstreamRepo: string readonly upstreamRepo: string
/**
* URL where users can get help using the upstream service
* @example `https://github.com/nextcloud/docker/issues`
*/
readonly supportSite: string
/** /**
* URL where users can learn more about the upstream service * URL where users can learn more about the upstream service
* @example `https://nextcloud.com` * @example `https://nextcloud.com`
*/ */
readonly marketingSite: string readonly marketingUrl: string
/** /**
* (optional) URL where users can donate to the upstream project * (optional) URL where users can donate to the upstream project
* @example `https://nextcloud.com/contribute/` * @example `https://nextcloud.com/contribute/`
@@ -45,7 +40,7 @@ export type SDKManifest = {
/** /**
* URL where users can find instructions on how to use the service * URL where users can find instructions on how to use the service
*/ */
readonly docsUrl: string readonly docsUrls: string[]
readonly description: { readonly description: {
/** Short description to display on the marketplace list page. Max length 80 chars. */ /** Short description to display on the marketplace list page. Max length 80 chars. */
readonly short: T.LocaleString readonly short: T.LocaleString

View File

@@ -393,12 +393,11 @@ describe('values', () => {
id: 'testOutput', id: 'testOutput',
title: '', title: '',
license: '', license: '',
wrapperRepo: '', packageRepo: '',
upstreamRepo: '', upstreamRepo: '',
supportSite: '', marketingUrl: '',
marketingSite: '',
donationUrl: null, donationUrl: null,
docsUrl: '', docsUrls: [],
description: { description: {
short: '', short: '',
long: '', long: '',

View File

@@ -9,12 +9,11 @@ export const sdk = StartSdk.of()
id: 'testOutput', id: 'testOutput',
title: '', title: '',
license: '', license: '',
wrapperRepo: '', packageRepo: '',
upstreamRepo: '', upstreamRepo: '',
supportSite: '', marketingUrl: '',
marketingSite: '',
donationUrl: null, donationUrl: null,
docsUrl: '', docsUrls: [],
description: { description: {
short: '', short: '',
long: '', long: '',

View File

@@ -23,7 +23,7 @@ import { MarketplaceLinkComponent } from './link.component'
class="item-pointer" class="item-pointer"
/> />
<marketplace-link <marketplace-link
[url]="pkg().wrapperRepo" [url]="pkg().packageRepo"
label="StartOS package" label="StartOS package"
icon="@tui.external-link" icon="@tui.external-link"
class="item-pointer" class="item-pointer"
@@ -37,12 +37,12 @@ import { MarketplaceLinkComponent } from './link.component'
<h2 class="additional-detail-title">{{ 'Links' | i18n }}</h2> <h2 class="additional-detail-title">{{ 'Links' | i18n }}</h2>
<div class="detail-container"> <div class="detail-container">
<marketplace-link <marketplace-link
[url]="pkg().marketingSite" [url]="pkg().marketingUrl"
label="Marketing" label="Marketing"
icon="@tui.external-link" icon="@tui.external-link"
class="item-pointer" class="item-pointer"
/> />
@if (pkg().docsUrl; as docsUrl) { @for (docsUrl of pkg().docsUrls; track $index) {
<marketplace-link <marketplace-link
[url]="docsUrl" [url]="docsUrl"
label="Documentation" label="Documentation"
@@ -50,12 +50,6 @@ import { MarketplaceLinkComponent } from './link.component'
class="item-pointer" class="item-pointer"
/> />
} }
<marketplace-link
[url]="pkg().supportSite"
label="Support"
icon="@tui.external-link"
class="item-pointer"
/>
@if (pkg().donationUrl; as donationUrl) { @if (pkg().donationUrl; as donationUrl) {
<marketplace-link <marketplace-link
[url]="donationUrl" [url]="donationUrl"

View File

@@ -125,24 +125,20 @@ export default class ServiceAboutRoute {
}, },
{ {
name: 'StartOS package', name: 'StartOS package',
value: manifest.wrapperRepo, value: manifest.packageRepo,
}, },
], ],
}, },
{ {
header: 'Links', header: 'Links',
items: [ items: [
{ ...manifest.docsUrls.map(docsUrl => ({
name: 'Documentation', name: 'Documentation',
value: manifest.docsUrl || NOT_PROVIDED, value: docsUrl,
}, })),
{
name: 'Support',
value: manifest.supportSite || NOT_PROVIDED,
},
{ {
name: 'Marketing', name: 'Marketing',
value: manifest.marketingSite || NOT_PROVIDED, value: manifest.marketingUrl || NOT_PROVIDED,
}, },
{ {
name: 'Donations', name: 'Donations',

View File

@@ -45,37 +45,19 @@ import { getManifest } from 'src/app/utils/get-package-data'
</header> </header>
<nav> <nav>
@for (item of nav; track $index) { @for (item of nav; track $index) {
@if (item.title === 'Documentation') { <a
<a tuiCell
tuiCell tuiAppearance="action-grayscale"
tuiAppearance="action-grayscale" routerLinkActive="active"
[href]="manifest()?.docsUrl" [routerLinkActiveOptions]="{ exact: true }"
target="_blank" [routerLink]="item.title === 'dashboard' ? './' : item.title"
noreferrer >
> <tui-icon [icon]="item.icon" />
<tui-icon [icon]="item.icon" /> <span tuiTitle>{{ item.title | i18n }}</span>
<span tuiTitle> @if (item.title === 'dashboard') {
<span> <a routerLink="interface" routerLinkActive="active"></a>
{{ item.title | i18n }} }
</span> </a>
</span>
<tui-icon icon="@tui.external-link" [style.font-size.rem]="1" />
</a>
} @else {
<a
tuiCell
tuiAppearance="action-grayscale"
routerLinkActive="active"
[routerLinkActiveOptions]="{ exact: true }"
[routerLink]="item.title === 'dashboard' ? './' : item.title"
>
<tui-icon [icon]="item.icon" />
<span tuiTitle>{{ item.title | i18n }}</span>
@if (item.title === 'dashboard') {
<a routerLink="interface" routerLinkActive="active"></a>
}
</a>
}
} }
</nav> </nav>
</aside> </aside>
@@ -209,7 +191,6 @@ export class ServiceOutletComponent {
{ title: 'actions', icon: '@tui.file-terminal' }, { title: 'actions', icon: '@tui.file-terminal' },
{ title: 'logs', icon: '@tui.logs' }, { title: 'logs', icon: '@tui.logs' },
{ title: 'about', icon: '@tui.info' }, { title: 'about', icon: '@tui.info' },
{ title: 'Documentation', icon: '@tui.book-open-text' },
] ]
protected readonly service = toSignal( protected readonly service = toSignal(

View File

@@ -231,12 +231,11 @@ export namespace Mock {
}, },
releaseNotes: 'Taproot, Schnorr, and more.', releaseNotes: 'Taproot, Schnorr, and more.',
license: 'MIT', license: 'MIT',
wrapperRepo: 'https://github.com/start9labs/bitcoind-wrapper', packageRepo: 'https://github.com/start9labs/bitcoind-wrapper',
upstreamRepo: 'https://github.com/bitcoin/bitcoin', upstreamRepo: 'https://github.com/bitcoin/bitcoin',
supportSite: 'https://bitcoin.org', marketingUrl: 'https://bitcoin.org',
marketingSite: 'https://bitcoin.org',
donationUrl: 'https://start9.com', donationUrl: 'https://start9.com',
docsUrl: 'https://docs.start9.com', docsUrls: ['https://docs.start9.com'],
alerts: { alerts: {
install: 'Bitcoin can take over a week to sync.', install: 'Bitcoin can take over a week to sync.',
uninstall: uninstall:
@@ -279,12 +278,11 @@ export namespace Mock {
}, },
releaseNotes: 'Dual funded channels!', releaseNotes: 'Dual funded channels!',
license: 'MIT', license: 'MIT',
wrapperRepo: 'https://github.com/start9labs/lnd-wrapper', packageRepo: 'https://github.com/start9labs/lnd-wrapper',
upstreamRepo: 'https://github.com/lightningnetwork/lnd', upstreamRepo: 'https://github.com/lightningnetwork/lnd',
supportSite: 'https://lightning.engineering/', marketingUrl: 'https://lightning.engineering/',
marketingSite: 'https://lightning.engineering/',
donationUrl: null, donationUrl: null,
docsUrl: 'https://docs.start9.com', docsUrls: ['https://docs.start9.com'],
alerts: { alerts: {
install: null, install: null,
uninstall: null, uninstall: null,
@@ -339,12 +337,11 @@ export namespace Mock {
}, },
releaseNotes: 'Even better support for Bitcoin and wallets!', releaseNotes: 'Even better support for Bitcoin and wallets!',
license: 'MIT', license: 'MIT',
wrapperRepo: 'https://github.com/start9labs/btc-rpc-proxy-wrapper', packageRepo: 'https://github.com/start9labs/btc-rpc-proxy-wrapper',
upstreamRepo: 'https://github.com/Kixunil/btc-rpc-proxy', upstreamRepo: 'https://github.com/Kixunil/btc-rpc-proxy',
supportSite: '', marketingUrl: '',
marketingSite: '',
donationUrl: 'https://start9.com', donationUrl: 'https://start9.com',
docsUrl: 'https://docs.start9.com', docsUrls: ['https://docs.start9.com'],
alerts: { alerts: {
install: 'Testing install alert', install: 'Testing install alert',
uninstall: null, uninstall: null,
@@ -402,11 +399,10 @@ export namespace Mock {
title: 'Bitcoin Core', title: 'Bitcoin Core',
description: mockDescription, description: mockDescription,
license: 'mit', license: 'mit',
wrapperRepo: 'https://github.com/start9labs/bitcoind-startos', packageRepo: 'https://github.com/start9labs/bitcoind-startos',
upstreamRepo: 'https://github.com/bitcoin/bitcoin', upstreamRepo: 'https://github.com/bitcoin/bitcoin',
supportSite: 'https://bitcoin.org', marketingUrl: 'https://bitcoin.org',
marketingSite: 'https://bitcoin.org', docsUrls: ['https://bitcoin.org'],
docsUrl: 'https://bitcoin.org',
releaseNotes: 'Even better support for Bitcoin and wallets!', releaseNotes: 'Even better support for Bitcoin and wallets!',
osVersion: '0.3.6', osVersion: '0.3.6',
sdkVersion: '0.4.0-beta.48', sdkVersion: '0.4.0-beta.48',
@@ -444,11 +440,10 @@ export namespace Mock {
long: 'Bitcoin Knots is a combined Bitcoin node and wallet. Not only is it easy to use, but it also ensures bitcoins you receive are both real bitcoins and really yours.', long: 'Bitcoin Knots is a combined Bitcoin node and wallet. Not only is it easy to use, but it also ensures bitcoins you receive are both real bitcoins and really yours.',
}, },
license: 'mit', license: 'mit',
wrapperRepo: 'https://github.com/start9labs/bitcoinknots-startos', packageRepo: 'https://github.com/start9labs/bitcoinknots-startos',
upstreamRepo: 'https://github.com/bitcoinknots/bitcoin', upstreamRepo: 'https://github.com/bitcoinknots/bitcoin',
supportSite: 'https://bitcoinknots.org', marketingUrl: 'https://bitcoinknots.org',
marketingSite: 'https://bitcoinknots.org', docsUrls: ['https://bitcoinknots.org'],
docsUrl: 'https://bitcoinknots.org',
releaseNotes: 'Even better support for Bitcoin and wallets!', releaseNotes: 'Even better support for Bitcoin and wallets!',
osVersion: '0.3.6', osVersion: '0.3.6',
sdkVersion: '0.4.0-beta.48', sdkVersion: '0.4.0-beta.48',
@@ -496,11 +491,10 @@ export namespace Mock {
title: 'Bitcoin Core', title: 'Bitcoin Core',
description: mockDescription, description: mockDescription,
license: 'mit', license: 'mit',
wrapperRepo: 'https://github.com/start9labs/bitcoind-startos', packageRepo: 'https://github.com/start9labs/bitcoind-startos',
upstreamRepo: 'https://github.com/bitcoin/bitcoin', upstreamRepo: 'https://github.com/bitcoin/bitcoin',
supportSite: 'https://bitcoin.org', marketingUrl: 'https://bitcoin.org',
marketingSite: 'https://bitcoin.org', docsUrls: ['https://bitcoin.org'],
docsUrl: 'https://bitcoin.org',
releaseNotes: 'Even better support for Bitcoin and wallets!', releaseNotes: 'Even better support for Bitcoin and wallets!',
osVersion: '0.3.6', osVersion: '0.3.6',
sdkVersion: '0.4.0-beta.48', sdkVersion: '0.4.0-beta.48',
@@ -538,11 +532,10 @@ export namespace Mock {
long: 'Bitcoin Knots is a combined Bitcoin node and wallet. Not only is it easy to use, but it also ensures bitcoins you receive are both real bitcoins and really yours.', long: 'Bitcoin Knots is a combined Bitcoin node and wallet. Not only is it easy to use, but it also ensures bitcoins you receive are both real bitcoins and really yours.',
}, },
license: 'mit', license: 'mit',
wrapperRepo: 'https://github.com/start9labs/bitcoinknots-startos', packageRepo: 'https://github.com/start9labs/bitcoinknots-startos',
upstreamRepo: 'https://github.com/bitcoinknots/bitcoin', upstreamRepo: 'https://github.com/bitcoinknots/bitcoin',
supportSite: 'https://bitcoinknots.org', marketingUrl: 'https://bitcoinknots.org',
marketingSite: 'https://bitcoinknots.org', docsUrls: ['https://bitcoinknots.org'],
docsUrl: 'https://bitcoinknots.org',
releaseNotes: 'Even better support for Bitcoin and wallets!', releaseNotes: 'Even better support for Bitcoin and wallets!',
osVersion: '0.3.6', osVersion: '0.3.6',
sdkVersion: '0.4.0-beta.48', sdkVersion: '0.4.0-beta.48',
@@ -592,11 +585,10 @@ export namespace Mock {
title: 'LND', title: 'LND',
description: mockDescription, description: mockDescription,
license: 'mit', license: 'mit',
wrapperRepo: 'https://github.com/start9labs/lnd-startos', packageRepo: 'https://github.com/start9labs/lnd-startos',
upstreamRepo: 'https://github.com/lightningnetwork/lnd', upstreamRepo: 'https://github.com/lightningnetwork/lnd',
supportSite: 'https://lightning.engineering/slack.html', marketingUrl: 'https://lightning.engineering/',
marketingSite: 'https://lightning.engineering/', docsUrls: ['https://lightning.engineering/'],
docsUrl: 'https://lightning.engineering/',
releaseNotes: 'Upstream release to 0.17.5', releaseNotes: 'Upstream release to 0.17.5',
osVersion: '0.3.6', osVersion: '0.3.6',
sdkVersion: '0.4.0-beta.48', sdkVersion: '0.4.0-beta.48',
@@ -647,11 +639,10 @@ export namespace Mock {
title: 'LND', title: 'LND',
description: mockDescription, description: mockDescription,
license: 'mit', license: 'mit',
wrapperRepo: 'https://github.com/start9labs/lnd-startos', packageRepo: 'https://github.com/start9labs/lnd-startos',
upstreamRepo: 'https://github.com/lightningnetwork/lnd', upstreamRepo: 'https://github.com/lightningnetwork/lnd',
supportSite: 'https://lightning.engineering/slack.html', marketingUrl: 'https://lightning.engineering/',
marketingSite: 'https://lightning.engineering/', docsUrls: ['https://lightning.engineering/'],
docsUrl: 'https://lightning.engineering/',
releaseNotes: 'Upstream release to 0.17.4', releaseNotes: 'Upstream release to 0.17.4',
osVersion: '0.3.6', osVersion: '0.3.6',
sdkVersion: '0.4.0-beta.48', sdkVersion: '0.4.0-beta.48',
@@ -706,11 +697,10 @@ export namespace Mock {
title: 'Bitcoin Core', title: 'Bitcoin Core',
description: mockDescription, description: mockDescription,
license: 'mit', license: 'mit',
wrapperRepo: 'https://github.com/start9labs/bitcoind-startos', packageRepo: 'https://github.com/start9labs/bitcoind-startos',
upstreamRepo: 'https://github.com/bitcoin/bitcoin', upstreamRepo: 'https://github.com/bitcoin/bitcoin',
supportSite: 'https://bitcoin.org', marketingUrl: 'https://bitcoin.org',
marketingSite: 'https://bitcoin.org', docsUrls: ['https://bitcoin.org'],
docsUrl: 'https://bitcoin.org',
releaseNotes: 'Even better support for Bitcoin and wallets!', releaseNotes: 'Even better support for Bitcoin and wallets!',
osVersion: '0.3.6', osVersion: '0.3.6',
sdkVersion: '0.4.0-beta.48', sdkVersion: '0.4.0-beta.48',
@@ -748,11 +738,10 @@ export namespace Mock {
long: 'Bitcoin Knots is a combined Bitcoin node and wallet. Not only is it easy to use, but it also ensures bitcoins you receive are both real bitcoins and really yours.', long: 'Bitcoin Knots is a combined Bitcoin node and wallet. Not only is it easy to use, but it also ensures bitcoins you receive are both real bitcoins and really yours.',
}, },
license: 'mit', license: 'mit',
wrapperRepo: 'https://github.com/start9labs/bitcoinknots-startos', packageRepo: 'https://github.com/start9labs/bitcoinknots-startos',
upstreamRepo: 'https://github.com/bitcoinknots/bitcoin', upstreamRepo: 'https://github.com/bitcoinknots/bitcoin',
supportSite: 'https://bitcoinknots.org', marketingUrl: 'https://bitcoinknots.org',
marketingSite: 'https://bitcoinknots.org', docsUrls: [],
docsUrl: 'https://bitcoinknots.org',
releaseNotes: 'Even better support for Bitcoin and wallets!', releaseNotes: 'Even better support for Bitcoin and wallets!',
osVersion: '0.3.6', osVersion: '0.3.6',
sdkVersion: '0.4.0-beta.48', sdkVersion: '0.4.0-beta.48',
@@ -800,11 +789,10 @@ export namespace Mock {
title: 'LND', title: 'LND',
description: mockDescription, description: mockDescription,
license: 'mit', license: 'mit',
wrapperRepo: 'https://github.com/start9labs/lnd-startos', packageRepo: 'https://github.com/start9labs/lnd-startos',
upstreamRepo: 'https://github.com/lightningnetwork/lnd', upstreamRepo: 'https://github.com/lightningnetwork/lnd',
supportSite: 'https://lightning.engineering/slack.html', marketingUrl: 'https://lightning.engineering/',
marketingSite: 'https://lightning.engineering/', docsUrls: [],
docsUrl: 'https://lightning.engineering/',
releaseNotes: 'Upstream release and minor fixes.', releaseNotes: 'Upstream release and minor fixes.',
osVersion: '0.3.6', osVersion: '0.3.6',
sdkVersion: '0.4.0-beta.48', sdkVersion: '0.4.0-beta.48',
@@ -855,11 +843,10 @@ export namespace Mock {
title: 'Bitcoin Proxy', title: 'Bitcoin Proxy',
description: mockDescription, description: mockDescription,
license: 'mit', license: 'mit',
wrapperRepo: 'https://github.com/Start9Labs/btc-rpc-proxy-wrappers', packageRepo: 'https://github.com/Start9Labs/btc-rpc-proxy-wrappers',
upstreamRepo: 'https://github.com/Kixunil/btc-rpc-proxy', upstreamRepo: 'https://github.com/Kixunil/btc-rpc-proxy',
supportSite: 'https://github.com/Kixunil/btc-rpc-proxy/issues', docsUrls: [],
docsUrl: 'https://github.com/Kixunil/btc-rpc-proxy', marketingUrl: '',
marketingSite: '',
releaseNotes: 'Upstream release and minor fixes.', releaseNotes: 'Upstream release and minor fixes.',
osVersion: '0.3.6', osVersion: '0.3.6',
sdkVersion: '0.4.0-beta.48', sdkVersion: '0.4.0-beta.48',