clean up tech debt, bump dependencies

This commit is contained in:
Aiden McClelland
2025-08-15 18:32:27 -06:00
parent 7094d1d939
commit d06c443c7d
44 changed files with 120 additions and 126 deletions

View File

@@ -1,3 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type ServiceInterfaceId = string;
export type ServiceInterfaceId = string;

View File

@@ -24,7 +24,6 @@ use crate::util::serde::{display_serializable, HandlerExtSerde, WithIoFormat};
use crate::{ensure_code, Error, ResultExt};
#[derive(Debug, Clone, Default, Deserialize, Serialize, TS)]
#[ts(as = "BTreeMap::<String, Session>")]
pub struct Sessions(pub BTreeMap<InternedString, Session>);
impl Sessions {
pub fn new() -> Self {

View File

@@ -375,7 +375,6 @@ pub struct PackageDataEntry {
pub last_backup: Option<DateTime<Utc>>,
pub current_dependencies: CurrentDependencies,
pub actions: BTreeMap<ActionId, ActionMetadata>,
#[ts(as = "BTreeMap::<String, TaskEntry>")]
pub tasks: BTreeMap<ReplayId, TaskEntry>,
pub service_interfaces: BTreeMap<ServiceInterfaceId, ServiceInterface>,
pub hosts: Hosts,

View File

@@ -92,7 +92,6 @@ impl Public {
},
gateways: OrdMap::new(),
acme: BTreeMap::new(),
domains: BTreeMap::new(),
dns: Default::default(),
},
status_info: ServerStatus {
@@ -195,9 +194,6 @@ pub struct NetworkInfo {
#[serde(default)]
pub acme: BTreeMap<AcmeProvider, AcmeSettings>,
#[serde(default)]
#[ts(as = "BTreeMap::<String, DomainSettings>")]
pub domains: BTreeMap<InternedString, DomainSettings>,
#[serde(default)]
pub dns: DnsSettings,
}
@@ -206,8 +202,7 @@ pub struct NetworkInfo {
#[model = "Model<Self>"]
#[ts(export)]
pub struct DnsSettings {
pub dhcp: Vec<IpAddr>,
#[serde(rename = "static")]
pub dhcp_servers: Vec<IpAddr>,
pub static_servers: Option<Vec<IpAddr>>,
}

View File

@@ -37,7 +37,6 @@ pub struct DepInfo {
#[derive(Clone, Debug, Deserialize, Serialize, HasModel, TS)]
#[serde(rename_all = "camelCase")]
#[model = "Model<Self>"]
#[ts(export)]
pub struct DependencyMetadata {
#[ts(type = "string")]
pub title: InternedString,

View File

@@ -21,11 +21,14 @@ use hickory_server::ServerFuture;
use imbl::OrdMap;
use imbl_value::InternedString;
use models::{GatewayId, PackageId};
use rpc_toolkit::{from_fn_blocking, Context, HandlerArgs, HandlerExt, ParentHandler};
use rpc_toolkit::{
from_fn_async, from_fn_blocking, Context, HandlerArgs, HandlerExt, ParentHandler,
};
use serde::{Deserialize, Serialize};
use tokio::net::{TcpListener, UdpSocket};
use tracing::instrument;
use crate::context::RpcContext;
use crate::db::model::public::NetworkInterfaceInfo;
use crate::net::gateway::NetworkInterfaceWatcher;
use crate::util::serde::{display_serializable, HandlerExtSerde};
@@ -33,23 +36,30 @@ use crate::util::sync::{SyncRwLock, Watch};
use crate::{Error, ErrorKind, ResultExt};
pub fn dns_api<C: Context>() -> ParentHandler<C> {
ParentHandler::new().subcommand(
"query",
from_fn_blocking(query_dns::<C>)
.with_display_serializable()
.with_custom_display_fn(|HandlerArgs { params, .. }, res| {
if let Some(format) = params.format {
return display_serializable(format, res);
}
ParentHandler::new()
.subcommand(
"query",
from_fn_blocking(query_dns::<C>)
.with_display_serializable()
.with_custom_display_fn(|HandlerArgs { params, .. }, res| {
if let Some(format) = params.format {
return display_serializable(format, res);
}
if let Some(ip) = res {
println!("{}", ip)
}
if let Some(ip) = res {
println!("{}", ip)
}
Ok(())
})
.with_about("Test the DNS configuration for a domain"),
)
Ok(())
})
.with_about("Test the DNS configuration for a domain"),
)
.subcommand(
"set-static",
from_fn_async(set_static_dns)
.no_display()
.with_about("Set static DNS servers"),
)
}
#[derive(Deserialize, Serialize, Parser)]
@@ -91,17 +101,17 @@ pub fn query_dns<C: Context>(
.map_err(Error::from)
}
// #[test]
// fn test_dns() {
// assert!(query_dns(
// (),
// QueryDnsParams {
// fqdn: "fakedomain-definitely-not-real.com"
// }
// )
// .unwrap()
// .is_none())
// }
#[derive(Deserialize, Serialize, Parser)]
pub struct SetStaticDnsParams {
pub servers: Option<Vec<IpAddr>>,
}
pub async fn set_static_dns(
ctx: RpcContext,
SetStaticDnsParams { servers }: SetStaticDnsParams,
) -> Result<(), Error> {
todo!()
}
#[derive(Default)]
struct ResolveMap {

View File

@@ -856,7 +856,7 @@ impl NetworkInterfaceController {
db.mutate(|db| {
let net = db.as_public_mut().as_server_info_mut().as_network_mut();
net.as_dns_mut().as_dhcp_mut().ser(&dns)?;
net.as_dns_mut().as_dhcp_servers_mut().ser(&dns)?;
net.as_gateways_mut().ser(info)
})
.await

View File

@@ -51,7 +51,6 @@ pub fn info_api<C: Context>() -> ParentHandler<C, WithIoFormat<Empty>> {
pub struct RegistryInfo {
pub name: Option<String>,
pub icon: Option<DataUrl<'static>>,
#[ts(as = "BTreeMap::<String, Category>")]
pub categories: BTreeMap<InternedString, Category>,
}

View File

@@ -8,8 +8,8 @@ use ts_rs::TS;
use crate::prelude::*;
use crate::registry::asset::RegistryAsset;
use crate::registry::context::RegistryContext;
use crate::sign::commitment::blake3::Blake3Commitment;
use crate::rpc_continuations::Guid;
use crate::sign::commitment::blake3::Blake3Commitment;
#[derive(Debug, Default, Deserialize, Serialize, HasModel, TS)]
#[serde(rename_all = "camelCase")]
@@ -44,11 +44,8 @@ pub struct OsVersionInfo {
#[ts(type = "string")]
pub source_version: VersionRange,
pub authorized: BTreeSet<Guid>,
#[ts(as = "BTreeMap::<String, RegistryAsset::<Blake3Commitment>>")]
pub iso: BTreeMap<InternedString, RegistryAsset<Blake3Commitment>>, // platform (i.e. x86_64-nonfree) -> asset
#[ts(as = "BTreeMap::<String, RegistryAsset::<Blake3Commitment>>")]
pub squashfs: BTreeMap<InternedString, RegistryAsset<Blake3Commitment>>, // platform (i.e. x86_64-nonfree) -> asset
#[ts(as = "BTreeMap::<String, RegistryAsset::<Blake3Commitment>>")]
pub img: BTreeMap<InternedString, RegistryAsset<Blake3Commitment>>, // platform (i.e. raspberrypi) -> asset
}

View File

@@ -12,20 +12,19 @@ use crate::prelude::*;
use crate::registry::asset::RegistryAsset;
use crate::registry::context::RegistryContext;
use crate::registry::device_info::DeviceInfo;
use crate::sign::commitment::merkle_archive::MerkleArchiveCommitment;
use crate::sign::{AnySignature, AnyVerifyingKey};
use crate::rpc_continuations::Guid;
use crate::s9pk::git_hash::GitHash;
use crate::s9pk::manifest::{Alerts, Description, HardwareRequirements};
use crate::s9pk::merkle_archive::source::FileSource;
use crate::s9pk::S9pk;
use crate::sign::commitment::merkle_archive::MerkleArchiveCommitment;
use crate::sign::{AnySignature, AnyVerifyingKey};
#[derive(Debug, Default, Deserialize, Serialize, HasModel, TS)]
#[serde(rename_all = "camelCase")]
#[model = "Model<Self>"]
#[ts(export)]
pub struct PackageIndex {
#[ts(as = "BTreeMap::<String, Category>")]
pub categories: BTreeMap<InternedString, Category>,
pub packages: BTreeMap<PackageId, PackageInfo>,
}

View File

@@ -77,7 +77,7 @@ export async function checkDependencies<
}
const tasksSatisfied = (packageId: DependencyId) =>
Object.entries(infoFor(packageId).result.tasks).filter(
([_, t]) => t.active && t.task.severity === "critical",
([_, t]) => t?.active && t.task.severity === "critical",
).length === 0
const healthCheckSatisfied = (
packageId: DependencyId,
@@ -146,7 +146,7 @@ export async function checkDependencies<
const throwIfTasksNotSatisfied = (packageId: DependencyId) => {
const dep = infoFor(packageId)
const reqs = Object.entries(dep.result.tasks)
.filter(([_, t]) => t.active && t.task.severity === "critical")
.filter(([_, t]) => t?.active && t.task.severity === "critical")
.map(([id, _]) => id)
if (reqs.length) {
throw new Error(

View File

@@ -2,7 +2,10 @@ import * as T from "../types"
import { once } from "../util"
export type RequiredDependenciesOf<Manifest extends T.SDKManifest> = {
[K in keyof Manifest["dependencies"]]: Manifest["dependencies"][K]["optional"] extends false
[K in keyof Manifest["dependencies"]]: Exclude<
Manifest["dependencies"][K],
undefined
>["optional"] extends false
? K
: never
}[keyof Manifest["dependencies"]]

View File

@@ -2,4 +2,4 @@
import type { PackageDataEntry } from "./PackageDataEntry"
import type { PackageId } from "./PackageId"
export type AllPackageData = { [key: PackageId]: PackageDataEntry }
export type AllPackageData = { [key in PackageId]?: PackageDataEntry }

View File

@@ -12,6 +12,6 @@ export type CheckDependenciesResult = {
installedVersion: Version | null
satisfies: Array<Version>
isRunning: boolean
tasks: { [key: ReplayId]: TaskEntry }
healthChecks: { [key: HealthCheckId]: NamedHealthCheckResult }
tasks: { [key in ReplayId]?: TaskEntry }
healthChecks: { [key in HealthCheckId]?: NamedHealthCheckResult }
}

View File

@@ -2,4 +2,4 @@
import type { CurrentDependencyInfo } from "./CurrentDependencyInfo"
import type { PackageId } from "./PackageId"
export type CurrentDependencies = { [key: PackageId]: CurrentDependencyInfo }
export type CurrentDependencies = { [key in PackageId]?: CurrentDependencyInfo }

View File

@@ -2,4 +2,4 @@
import type { DepInfo } from "./DepInfo"
import type { PackageId } from "./PackageId"
export type Dependencies = { [key: PackageId]: DepInfo }
export type Dependencies = { [key in PackageId]?: DepInfo }

View File

@@ -1,3 +1,6 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type DnsSettings = { dhcp: Array<string>; static: Array<string> | null }
export type DnsSettings = {
dhcpServers: Array<string>
staticServers: Array<string> | null
}

View File

@@ -1,7 +0,0 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { PublicDomainConfig } from "./PublicDomainConfig"
export type Domains = {
public: { [key: string]: PublicDomainConfig }
private: Array<string>
}

View File

@@ -10,5 +10,5 @@ export type FullIndex = {
icon: DataUrl | null
package: PackageIndex
os: OsIndex
signers: { [key: Guid]: SignerInfo }
signers: { [key in Guid]?: SignerInfo }
}

View File

@@ -5,6 +5,6 @@ import type { Version } from "./Version"
export type GetPackageResponse = {
categories: string[]
best: { [key: Version]: PackageVersionInfo }
otherVersions?: { [key: Version]: PackageInfoShort }
best: { [key in Version]?: PackageVersionInfo }
otherVersions?: { [key in Version]?: PackageInfoShort }
}

View File

@@ -4,6 +4,6 @@ import type { Version } from "./Version"
export type GetPackageResponseFull = {
categories: string[]
best: { [key: Version]: PackageVersionInfo }
otherVersions: { [key: Version]: PackageVersionInfo }
best: { [key in Version]?: PackageVersionInfo }
otherVersions: { [key in Version]?: PackageVersionInfo }
}

View File

@@ -1,14 +1,15 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { BindInfo } from "./BindInfo"
import type { Domains } from "./Domains"
import type { HostnameInfo } from "./HostnameInfo"
import type { PublicDomainConfig } from "./PublicDomainConfig"
export type Host = {
bindings: { [key: number]: BindInfo }
bindings: { [key in number]?: BindInfo }
onions: string[]
domains: Domains
publicDomains: { [key in string]?: PublicDomainConfig }
privateDomains: Array<string>
/**
* COMPUTED: NetService::update
*/
hostnameInfo: { [key: number]: Array<HostnameInfo> }
hostnameInfo: { [key in number]?: Array<HostnameInfo> }
}

View File

@@ -2,4 +2,4 @@
import type { Host } from "./Host"
import type { HostId } from "./HostId"
export type Hosts = { [key: HostId]: Host }
export type Hosts = { [key in HostId]?: Host }

View File

@@ -7,7 +7,7 @@ export type ImageSource =
dockerBuild: {
workdir?: string
dockerfile?: string
buildArgs?: { [key: string]: BuildArg }
buildArgs?: { [key in string]?: BuildArg }
}
}
| { dockerTag: string }

View File

@@ -15,11 +15,11 @@ export type MainStatus =
| { main: "stopping" }
| {
main: "starting"
health: { [key: HealthCheckId]: NamedHealthCheckResult }
health: { [key in HealthCheckId]?: NamedHealthCheckResult }
}
| {
main: "running"
started: string
health: { [key: HealthCheckId]: NamedHealthCheckResult }
health: { [key in HealthCheckId]?: NamedHealthCheckResult }
}
| { main: "backingUp"; onComplete: StartStop }

View File

@@ -26,7 +26,7 @@ export type Manifest = {
donationUrl: string | null
docsUrl: string | null
description: Description
images: { [key: ImageId]: ImageConfig }
images: { [key in ImageId]?: ImageConfig }
volumes: Array<VolumeId>
alerts: Alerts
dependencies: Dependencies

View File

@@ -2,7 +2,6 @@
import type { AcmeProvider } from "./AcmeProvider"
import type { AcmeSettings } from "./AcmeSettings"
import type { DnsSettings } from "./DnsSettings"
import type { DomainSettings } from "./DomainSettings"
import type { GatewayId } from "./GatewayId"
import type { Host } from "./Host"
import type { NetworkInterfaceInfo } from "./NetworkInterfaceInfo"
@@ -11,8 +10,7 @@ import type { WifiInfo } from "./WifiInfo"
export type NetworkInfo = {
wifi: WifiInfo
host: Host
gateways: { [key: GatewayId]: NetworkInterfaceInfo }
acme: { [key: AcmeProvider]: AcmeSettings }
domains: { [key: string]: DomainSettings }
gateways: { [key in GatewayId]?: NetworkInterfaceInfo }
acme: { [key in AcmeProvider]?: AcmeSettings }
dns: DnsSettings
}

View File

@@ -8,7 +8,7 @@ export type OsVersionInfo = {
releaseNotes: string
sourceVersion: string
authorized: Array<Guid>
iso: { [key: string]: RegistryAsset<Blake3Commitment> }
squashfs: { [key: string]: RegistryAsset<Blake3Commitment> }
img: { [key: string]: RegistryAsset<Blake3Commitment> }
iso: { [key in string]?: RegistryAsset<Blake3Commitment> }
squashfs: { [key in string]?: RegistryAsset<Blake3Commitment> }
img: { [key in string]?: RegistryAsset<Blake3Commitment> }
}

View File

@@ -1,4 +1,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { OsVersionInfo } from "./OsVersionInfo"
export type OsVersionInfoMap = { [key: string]: OsVersionInfo }
export type OsVersionInfoMap = { [key in string]?: OsVersionInfo }

View File

@@ -6,6 +6,7 @@ import type { DataUrl } from "./DataUrl"
import type { Hosts } from "./Hosts"
import type { MainStatus } from "./MainStatus"
import type { PackageState } from "./PackageState"
import type { ReplayId } from "./ReplayId"
import type { ServiceInterface } from "./ServiceInterface"
import type { ServiceInterfaceId } from "./ServiceInterfaceId"
import type { TaskEntry } from "./TaskEntry"
@@ -19,9 +20,9 @@ export type PackageDataEntry = {
icon: DataUrl
lastBackup: string | null
currentDependencies: CurrentDependencies
actions: { [key: ActionId]: ActionMetadata }
tasks: { [key: string]: TaskEntry }
serviceInterfaces: { [key: ServiceInterfaceId]: ServiceInterface }
actions: { [key in ActionId]?: ActionMetadata }
tasks: { [key in ReplayId]?: TaskEntry }
serviceInterfaces: { [key in ServiceInterfaceId]?: ServiceInterface }
hosts: Hosts
storeExposedDependents: string[]
}

View File

@@ -4,6 +4,6 @@ import type { PackageId } from "./PackageId"
import type { PackageInfo } from "./PackageInfo"
export type PackageIndex = {
categories: { [key: string]: Category }
packages: { [key: PackageId]: PackageInfo }
categories: { [key in string]?: Category }
packages: { [key in PackageId]?: PackageInfo }
}

View File

@@ -5,6 +5,6 @@ import type { Version } from "./Version"
export type PackageInfo = {
authorized: Array<Guid>
versions: { [key: Version]: PackageVersionInfo }
versions: { [key in Version]?: PackageVersionInfo }
categories: string[]
}

View File

@@ -23,7 +23,7 @@ export type PackageVersionInfo = {
donationUrl: string | null
docsUrl: string | null
alerts: Alerts
dependencyMetadata: { [key: PackageId]: DependencyMetadata }
dependencyMetadata: { [key in PackageId]?: DependencyMetadata }
osVersion: string
sdkVersion: string | null
hardwareRequirements: HardwareRequirements

View File

@@ -6,5 +6,5 @@ export type RegistryAsset<Commitment> = {
publishedAt: string
url: string
commitment: Commitment
signatures: { [key: AnyVerifyingKey]: AnySignature }
signatures: { [key in AnyVerifyingKey]?: AnySignature }
}

View File

@@ -5,5 +5,5 @@ import type { DataUrl } from "./DataUrl"
export type RegistryInfo = {
name: string | null
icon: DataUrl | null
categories: { [key: string]: Category }
categories: { [key in string]?: Category }
}

View File

@@ -4,7 +4,7 @@ import type { FullProgress } from "./FullProgress"
import type { PackageId } from "./PackageId"
export type ServerStatus = {
backupProgress: { [key: PackageId]: BackupProgress } | null
backupProgress: { [key in PackageId]?: BackupProgress } | null
updated: boolean
updateProgress: FullProgress | null
shuttingDown: boolean

View File

@@ -1,9 +1,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { Session } from "./Session"
export type Sessions = {
[key: string]: {
loggedIn: string
lastActive: string
userAgent: string | null
}
}
export type Sessions = { [key in string]?: Session }

View File

@@ -68,7 +68,6 @@ export { DestroySubcontainerFsParams } from "./DestroySubcontainerFsParams"
export { DeviceFilter } from "./DeviceFilter"
export { DnsSettings } from "./DnsSettings"
export { DomainSettings } from "./DomainSettings"
export { Domains } from "./Domains"
export { Duration } from "./Duration"
export { EchoParams } from "./EchoParams"
export { EditSignerParams } from "./EditSignerParams"

View File

@@ -101,18 +101,20 @@ export class S9pk {
)
}
async dependencyMetadata(): Promise<Record<PackageId, DependencyMetadata>> {
async dependencyMetadata() {
return Object.fromEntries(
await Promise.all(
Object.entries(this.manifest.dependencies).map(async ([id, info]) => [
id,
{
...(await this.dependencyMetadataFor(id)),
icon: await this.dependencyIconFor(id),
description: info.description,
optional: info.optional,
},
]),
Object.entries(this.manifest.dependencies)
.filter(([_, info]) => !!info)
.map(async ([id, info]) => [
id,
{
...(await this.dependencyMetadataFor(id)),
icon: await this.dependencyIconFor(id),
description: info!.description,
optional: info!.optional,
},
]),
),
)
}

View File

@@ -165,7 +165,7 @@ export const filledAddress = (
addressInfo: AddressInfo,
): FilledAddressInfo => {
const toUrl = addressHostToUrl.bind(null, addressInfo)
const hostnames = host.hostnameInfo[addressInfo.internalPort]
const hostnames = host.hostnameInfo[addressInfo.internalPort] ?? []
return {
...addressInfo,

View File

@@ -211,5 +211,5 @@ export class ServiceRoute {
function toHealthCheck(status: T.MainStatus): T.NamedHealthCheckResult[] {
return status.main !== 'running' || isEmptyObject(status.health)
? []
: Object.values(status.health)
: Object.values(status.health).filter(h => !!h)
}

View File

@@ -103,12 +103,14 @@ export class DepErrorService {
// action required
if (
Object.values(pkg.tasks).some(
t =>
t.active &&
t.task.packageId === depId &&
t.task.severity === 'critical',
)
Object.values(pkg.tasks)
.filter(t => !!t)
.some(
t =>
t.active &&
t.task.packageId === depId &&
t.task.severity === 'critical',
)
) {
return {
type: 'actionRequired',

View File

@@ -19,13 +19,13 @@ export class GatewayService {
.pipe(
map(gateways =>
Object.entries(gateways)
.filter(([_, val]) => !!val.ipInfo)
.filter(([_, val]) => !!val?.ipInfo)
.map(
([id, val]) =>
({
...val,
id,
lanIpv4: val.ipInfo?.subnets
lanIpv4: val?.ipInfo?.subnets
.filter(s => !s.includes('::'))
.map(s => s.split('/')[0]),
}) as GatewayPlus,

View File

@@ -25,9 +25,9 @@ export function getInstalledPrimaryStatus({
tasks,
status,
}: T.PackageDataEntry): PrimaryStatus {
return Object.values(tasks).some(
t => t.active && t.task.severity === 'critical',
)
return Object.values(tasks)
.filter(t => !!t)
.some(t => t.active && t.task.severity === 'critical')
? 'actionRequired'
: status.main
}
@@ -37,7 +37,7 @@ function getHealthStatus(status: T.MainStatus): T.HealthStatus | null {
return null
}
const values = Object.values(status.health)
const values = Object.values(status.health).filter(h => !!h)
if (values.some(h => h.result === 'failure')) {
return 'failure'