diff --git a/Makefile b/Makefile index 48a28c388..f19b40b47 100644 --- a/Makefile +++ b/Makefile @@ -174,8 +174,8 @@ container-runtime/node_modules: container-runtime/package.json container-runtime touch container-runtime/node_modules core/startos/bindings: $(shell git ls-files core) $(ENVIRONMENT_FILE) $(PLATFORM_FILE) + rm -rf core/startos/bindings (cd core/ && cargo test) - touch core/startos/bindings sdk/lib/test: $(shell git ls-files sdk) core/startos/bindings (cd sdk && make test) diff --git a/core/startos/bindings/BindOptionsSecure.ts b/core/models/bindings/ServiceInterfaceId.ts similarity index 68% rename from core/startos/bindings/BindOptionsSecure.ts rename to core/models/bindings/ServiceInterfaceId.ts index c7b1b69af..87edd8694 100644 --- a/core/startos/bindings/BindOptionsSecure.ts +++ b/core/models/bindings/ServiceInterfaceId.ts @@ -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 BindOptionsSecure = { ssl: boolean, }; \ No newline at end of file +export type ServiceInterfaceId = string; \ No newline at end of file diff --git a/core/models/src/id/mod.rs b/core/models/src/id/mod.rs index 239479ed7..11644c71d 100644 --- a/core/models/src/id/mod.rs +++ b/core/models/src/id/mod.rs @@ -6,21 +6,21 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; use yasi::InternedString; mod action; -mod address; mod health_check; mod host; mod image; mod invalid_id; mod package; +mod service_interface; mod volume; pub use action::ActionId; -pub use address::AddressId; pub use health_check::HealthCheckId; pub use host::HostId; pub use image::ImageId; pub use invalid_id::InvalidId; pub use package::{PackageId, SYSTEM_PACKAGE_ID}; +pub use service_interface::ServiceInterfaceId; pub use volume::VolumeId; lazy_static::lazy_static! { diff --git a/core/models/src/id/address.rs b/core/models/src/id/service_interface.rs similarity index 67% rename from core/models/src/id/address.rs rename to core/models/src/id/service_interface.rs index 1bd670525..25aec0aba 100644 --- a/core/models/src/id/address.rs +++ b/core/models/src/id/service_interface.rs @@ -1,46 +1,48 @@ use std::path::Path; use serde::{Deserialize, Deserializer, Serialize}; +use ts_rs::TS; use crate::Id; -#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)] -pub struct AddressId(Id); -impl From for AddressId { +#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, TS)] +#[ts(export, type = "string")] +pub struct ServiceInterfaceId(Id); +impl From for ServiceInterfaceId { fn from(id: Id) -> Self { Self(id) } } -impl std::fmt::Display for AddressId { +impl std::fmt::Display for ServiceInterfaceId { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", &self.0) } } -impl std::ops::Deref for AddressId { +impl std::ops::Deref for ServiceInterfaceId { type Target = str; fn deref(&self) -> &Self::Target { &*self.0 } } -impl AsRef for AddressId { +impl AsRef for ServiceInterfaceId { fn as_ref(&self) -> &str { self.0.as_ref() } } -impl<'de> Deserialize<'de> for AddressId { +impl<'de> Deserialize<'de> for ServiceInterfaceId { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { - Ok(AddressId(Deserialize::deserialize(deserializer)?)) + Ok(ServiceInterfaceId(Deserialize::deserialize(deserializer)?)) } } -impl AsRef for AddressId { +impl AsRef for ServiceInterfaceId { fn as_ref(&self) -> &Path { self.0.as_ref().as_ref() } } -impl<'q> sqlx::Encode<'q, sqlx::Postgres> for AddressId { +impl<'q> sqlx::Encode<'q, sqlx::Postgres> for ServiceInterfaceId { fn encode_by_ref( &self, buf: &mut >::ArgumentBuffer, @@ -48,7 +50,7 @@ impl<'q> sqlx::Encode<'q, sqlx::Postgres> for AddressId { <&str as sqlx::Encode<'q, sqlx::Postgres>>::encode_by_ref(&&**self, buf) } } -impl sqlx::Type for AddressId { +impl sqlx::Type for ServiceInterfaceId { fn type_info() -> sqlx::postgres::PgTypeInfo { <&str as sqlx::Type>::type_info() } diff --git a/core/startos/bindings/BindKind.ts b/core/startos/bindings/ActionId.ts similarity index 67% rename from core/startos/bindings/BindKind.ts rename to core/startos/bindings/ActionId.ts index e026fb081..7c05d2b3c 100644 --- a/core/startos/bindings/BindKind.ts +++ b/core/startos/bindings/ActionId.ts @@ -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 BindKind = "static" | "single" | "multi"; \ No newline at end of file +export type ActionId = string; \ No newline at end of file diff --git a/core/startos/bindings/ActionMetadata.ts b/core/startos/bindings/ActionMetadata.ts index 91af02b7b..e787190c8 100644 --- a/core/startos/bindings/ActionMetadata.ts +++ b/core/startos/bindings/ActionMetadata.ts @@ -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 { AllowedStatuses } from "./AllowedStatuses"; -export type ActionMetadata = { name: string, description: string, warning: string | null, disabled: boolean, input: {[key: string]: any}, allowedStatuses: AllowedStatuses, group: string | null, }; \ No newline at end of file +export type ActionMetadata = { name: string, description: string, warning: string | null, input: any, disabled: boolean, allowedStatuses: AllowedStatuses, group: string | null, }; \ No newline at end of file diff --git a/core/startos/bindings/AddSslOptions.ts b/core/startos/bindings/AddSslOptions.ts index 97035853d..fcf2d63d4 100644 --- a/core/startos/bindings/AddSslOptions.ts +++ b/core/startos/bindings/AddSslOptions.ts @@ -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 { AlpnInfo } from "./AlpnInfo"; -export type AddSslOptions = { scheme: string, preferredExternalPort: number, alpn: AlpnInfo, }; \ No newline at end of file +export type AddSslOptions = { scheme: string | null, preferredExternalPort: number, alpn: AlpnInfo, }; \ No newline at end of file diff --git a/core/startos/bindings/AddressInfo.ts b/core/startos/bindings/AddressInfo.ts index b253ab823..6bc42c0e9 100644 --- a/core/startos/bindings/AddressInfo.ts +++ b/core/startos/bindings/AddressInfo.ts @@ -1,4 +1,5 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { BindOptions } from "./BindOptions"; +import type { HostId } from "./HostId"; -export type AddressInfo = { username: string | null, hostId: string, bindOptions: BindOptions, suffix: string, }; \ No newline at end of file +export type AddressInfo = { username: string | null, hostId: HostId, bindOptions: BindOptions, suffix: string, }; \ No newline at end of file diff --git a/core/startos/bindings/BindOptions.ts b/core/startos/bindings/BindOptions.ts index dc8b1e5b5..9043c5f57 100644 --- a/core/startos/bindings/BindOptions.ts +++ b/core/startos/bindings/BindOptions.ts @@ -1,4 +1,5 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { AddSslOptions } from "./AddSslOptions"; +import type { Security } from "./Security"; -export type BindOptions = { scheme: string, preferredExternalPort: number, addSsl: AddSslOptions | null, secure: boolean, ssl: boolean, }; \ No newline at end of file +export type BindOptions = { scheme: string | null, preferredExternalPort: number, addSsl: AddSslOptions | null, secure: Security | null, }; \ No newline at end of file diff --git a/core/startos/bindings/BindParams.ts b/core/startos/bindings/BindParams.ts index 319666538..07a8033bc 100644 --- a/core/startos/bindings/BindParams.ts +++ b/core/startos/bindings/BindParams.ts @@ -1,6 +1,7 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { AddSslOptions } from "./AddSslOptions"; -import type { BindKind } from "./BindKind"; -import type { BindOptionsSecure } from "./BindOptionsSecure"; +import type { HostId } from "./HostId"; +import type { HostKind } from "./HostKind"; +import type { Security } from "./Security"; -export type BindParams = { kind: BindKind, id: string, internalPort: number, scheme: string, preferredExternalPort: number, addSsl: AddSslOptions | null, secure: BindOptionsSecure | null, }; \ No newline at end of file +export type BindParams = { kind: HostKind, id: HostId, internalPort: number, scheme: string | null, preferredExternalPort: number, addSsl: AddSslOptions | null, secure: Security | null, }; \ No newline at end of file diff --git a/core/startos/bindings/CurrentDependencyInfo.ts b/core/startos/bindings/CurrentDependencyInfo.ts index ad8d3cf36..a253afa38 100644 --- a/core/startos/bindings/CurrentDependencyInfo.ts +++ b/core/startos/bindings/CurrentDependencyInfo.ts @@ -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 { DataUrl } from "./DataUrl"; -export type CurrentDependencyInfo = { title: string, icon: DataUrl, registry: string, versionSpec: string, } & ({ "kind": "exists" } | { "kind": "running", healthChecks: string[], }); \ No newline at end of file +export type CurrentDependencyInfo = { title: string, icon: DataUrl, registryUrl: string, versionSpec: string, } & ({ "kind": "exists" } | { "kind": "running", healthChecks: string[], }); \ No newline at end of file diff --git a/core/startos/bindings/DependencyRequirement.ts b/core/startos/bindings/DependencyRequirement.ts index f6ff4aa54..40b78b473 100644 --- a/core/startos/bindings/DependencyRequirement.ts +++ b/core/startos/bindings/DependencyRequirement.ts @@ -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 DependencyRequirement = { "kind": "running", id: string, healthChecks: string[], versionSpec: string, registry: string, } | { "kind": "exists", id: string, versionSpec: string, registry: string, }; \ No newline at end of file +export type DependencyRequirement = { "kind": "running", id: string, healthChecks: string[], versionSpec: string, registryUrl: string, } | { "kind": "exists", id: string, versionSpec: string, registryUrl: string, }; \ No newline at end of file diff --git a/core/startos/bindings/ExportedHostInfo.ts b/core/startos/bindings/ExportedHostInfo.ts new file mode 100644 index 000000000..c4d36bd61 --- /dev/null +++ b/core/startos/bindings/ExportedHostInfo.ts @@ -0,0 +1,6 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { ExportedHostnameInfo } from "./ExportedHostnameInfo"; +import type { HostId } from "./HostId"; +import type { HostKind } from "./HostKind"; + +export type ExportedHostInfo = { id: HostId, kind: HostKind, hostnames: Array, }; \ No newline at end of file diff --git a/core/startos/bindings/ExportedHostnameInfo.ts b/core/startos/bindings/ExportedHostnameInfo.ts new file mode 100644 index 000000000..086fd95b1 --- /dev/null +++ b/core/startos/bindings/ExportedHostnameInfo.ts @@ -0,0 +1,5 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { ExportedIpHostname } from "./ExportedIpHostname"; +import type { ExportedOnionHostname } from "./ExportedOnionHostname"; + +export type ExportedHostnameInfo = { "kind": "ip", networkInterfaceId: string, public: boolean, hostname: ExportedIpHostname, } | { "kind": "onion", hostname: ExportedOnionHostname, }; \ No newline at end of file diff --git a/core/startos/bindings/ExportedIpHostname.ts b/core/startos/bindings/ExportedIpHostname.ts new file mode 100644 index 000000000..7d012fecc --- /dev/null +++ b/core/startos/bindings/ExportedIpHostname.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type ExportedIpHostname = { "kind": "ipv4", value: string, port: number | null, sslPort: number | null, } | { "kind": "ipv6", value: string, port: number | null, sslPort: number | null, } | { "kind": "local", value: string, port: number | null, sslPort: number | null, } | { "kind": "domain", domain: string, subdomain: string | null, port: number | null, sslPort: number | null, }; \ No newline at end of file diff --git a/core/startos/bindings/ExportedOnionHostname.ts b/core/startos/bindings/ExportedOnionHostname.ts new file mode 100644 index 000000000..82fee09e3 --- /dev/null +++ b/core/startos/bindings/ExportedOnionHostname.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type ExportedOnionHostname = { value: string, port: number | null, sslPort: number | null, }; \ No newline at end of file diff --git a/core/startos/bindings/HealthCheckResult.ts b/core/startos/bindings/HealthCheckResult.ts index eaba169f1..a539fc805 100644 --- a/core/startos/bindings/HealthCheckResult.ts +++ b/core/startos/bindings/HealthCheckResult.ts @@ -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 HealthCheckResult = { "result": "success" } | { "result": "disabled" } | { "result": "starting" } | { "result": "loading", message: string, } | { "result": "failure", error: string, }; \ No newline at end of file +export type HealthCheckResult = { name: string, } & ({ "result": "success", message: string, } | { "result": "disabled" } | { "result": "starting" } | { "result": "loading", message: string, } | { "result": "failure", message: string, }); \ No newline at end of file diff --git a/core/startos/bindings/PackageDataEntry.ts b/core/startos/bindings/PackageDataEntry.ts index 100e38ba7..7abb7503a 100644 --- a/core/startos/bindings/PackageDataEntry.ts +++ b/core/startos/bindings/PackageDataEntry.ts @@ -1,8 +1,12 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { ActionId } from "./ActionId"; +import type { ActionMetadata } from "./ActionMetadata"; import type { CurrentDependencies } from "./CurrentDependencies"; import type { DataUrl } from "./DataUrl"; import type { HostInfo } from "./HostInfo"; import type { PackageState } from "./PackageState"; +import type { ServiceInterfaceId } from "./ServiceInterfaceId"; +import type { ServiceInterfaceWithHostInfo } from "./ServiceInterfaceWithHostInfo"; import type { Status } from "./Status"; -export type PackageDataEntry = { stateInfo: PackageState, status: Status, marketplaceUrl: string | null, developerKey: string, icon: DataUrl, lastBackup: string | null, currentDependencies: CurrentDependencies, hosts: HostInfo, storeExposedDependents: string[], }; \ No newline at end of file +export type PackageDataEntry = { stateInfo: PackageState, status: Status, marketplaceUrl: string | null, developerKey: string, icon: DataUrl, lastBackup: string | null, currentDependencies: CurrentDependencies, actions: { [key: ActionId]: ActionMetadata }, serviceInterfaces: { [key: ServiceInterfaceId]: ServiceInterfaceWithHostInfo }, hosts: HostInfo, storeExposedDependents: string[], }; \ No newline at end of file diff --git a/core/startos/bindings/Progress.ts b/core/startos/bindings/Progress.ts index d522dee5a..acddd8582 100644 --- a/core/startos/bindings/Progress.ts +++ b/core/startos/bindings/Progress.ts @@ -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 Progress = boolean | { done: bigint, total: bigint | null, }; \ No newline at end of file +export type Progress = boolean | { done: number, total: number | null, }; \ No newline at end of file diff --git a/core/startos/bindings/ConnectionAddresses.ts b/core/startos/bindings/Security.ts similarity index 56% rename from core/startos/bindings/ConnectionAddresses.ts rename to core/startos/bindings/Security.ts index 503bfb418..390b6a91f 100644 --- a/core/startos/bindings/ConnectionAddresses.ts +++ b/core/startos/bindings/Security.ts @@ -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 ConnectionAddresses = { tor: Array, clearnet: Array, }; \ No newline at end of file +export type Security = { ssl: boolean, }; \ No newline at end of file diff --git a/core/startos/bindings/ServerInfo.ts b/core/startos/bindings/ServerInfo.ts index ee8e55157..97cd77888 100644 --- a/core/startos/bindings/ServerInfo.ts +++ b/core/startos/bindings/ServerInfo.ts @@ -1,5 +1,4 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { ConnectionAddresses } from "./ConnectionAddresses"; import type { Governor } from "./Governor"; import type { IpInfo } from "./IpInfo"; import type { ServerStatus } from "./ServerStatus"; @@ -13,4 +12,4 @@ lastWifiRegion: string | null, eosVersionCompat: string, lanAddress: string, oni /** * for backwards compatibility */ -torAddress: string, ipInfo: { [key: string]: IpInfo }, statusInfo: ServerStatus, wifi: WifiInfo, unreadNotificationCount: bigint, connectionAddresses: ConnectionAddresses, passwordHash: string, pubkey: string, caFingerprint: string, ntpSynced: boolean, zram: boolean, governor: Governor | null, }; \ No newline at end of file +torAddress: string, ipInfo: { [key: string]: IpInfo }, statusInfo: ServerStatus, wifi: WifiInfo, unreadNotificationCount: number, passwordHash: string, pubkey: string, caFingerprint: string, ntpSynced: boolean, zram: boolean, governor: Governor | null, }; \ No newline at end of file diff --git a/core/startos/bindings/ServiceInterface.ts b/core/startos/bindings/ServiceInterface.ts new file mode 100644 index 000000000..2d484d749 --- /dev/null +++ b/core/startos/bindings/ServiceInterface.ts @@ -0,0 +1,6 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { AddressInfo } from "./AddressInfo"; +import type { ServiceInterfaceId } from "./ServiceInterfaceId"; +import type { ServiceInterfaceType } from "./ServiceInterfaceType"; + +export type ServiceInterface = { id: ServiceInterfaceId, name: string, description: string, hasPrimary: boolean, disabled: boolean, masked: boolean, addressInfo: AddressInfo, type: ServiceInterfaceType, }; \ No newline at end of file diff --git a/core/startos/bindings/HealthCheckString.ts b/core/startos/bindings/ServiceInterfaceId.ts similarity index 54% rename from core/startos/bindings/HealthCheckString.ts rename to core/startos/bindings/ServiceInterfaceId.ts index efe9f42bd..87edd8694 100644 --- a/core/startos/bindings/HealthCheckString.ts +++ b/core/startos/bindings/ServiceInterfaceId.ts @@ -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 HealthCheckString = "passing" | "disabled" | "starting" | "warning" | "failure"; \ No newline at end of file +export type ServiceInterfaceId = string; \ No newline at end of file diff --git a/core/startos/bindings/ServiceInterfaceWithHostInfo.ts b/core/startos/bindings/ServiceInterfaceWithHostInfo.ts new file mode 100644 index 000000000..449c5b29d --- /dev/null +++ b/core/startos/bindings/ServiceInterfaceWithHostInfo.ts @@ -0,0 +1,7 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { AddressInfo } from "./AddressInfo"; +import type { ExportedHostInfo } from "./ExportedHostInfo"; +import type { ServiceInterfaceId } from "./ServiceInterfaceId"; +import type { ServiceInterfaceType } from "./ServiceInterfaceType"; + +export type ServiceInterfaceWithHostInfo = { hostInfo: ExportedHostInfo, id: ServiceInterfaceId, name: string, description: string, hasPrimary: boolean, disabled: boolean, masked: boolean, addressInfo: AddressInfo, type: ServiceInterfaceType, }; \ No newline at end of file diff --git a/core/startos/bindings/SetHealth.ts b/core/startos/bindings/SetHealth.ts index 321b5c97b..cc8193863 100644 --- a/core/startos/bindings/SetHealth.ts +++ b/core/startos/bindings/SetHealth.ts @@ -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 { HealthCheckString } from "./HealthCheckString"; +import type { HealthCheckId } from "./HealthCheckId"; -export type SetHealth = { name: string, status: HealthCheckString, message: string | null, }; \ No newline at end of file +export type SetHealth = { id: HealthCheckId, name: string, } & ({ "result": "success", message: string, } | { "result": "disabled" } | { "result": "starting" } | { "result": "loading", message: string, } | { "result": "failure", message: string, }); \ No newline at end of file diff --git a/core/startos/bindings/UpdateProgress.ts b/core/startos/bindings/UpdateProgress.ts index ad9750196..ef6473f37 100644 --- a/core/startos/bindings/UpdateProgress.ts +++ b/core/startos/bindings/UpdateProgress.ts @@ -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 UpdateProgress = { size: bigint | null, downloaded: bigint, }; \ No newline at end of file +export type UpdateProgress = { size: number | null, downloaded: number, }; \ No newline at end of file diff --git a/core/startos/src/db/model/package.rs b/core/startos/src/db/model/package.rs index 0c82bf80c..83a35d086 100644 --- a/core/startos/src/db/model/package.rs +++ b/core/startos/src/db/model/package.rs @@ -3,7 +3,7 @@ use std::collections::{BTreeMap, BTreeSet}; use chrono::{DateTime, Utc}; use emver::VersionRange; use imbl_value::InternedString; -use models::{ActionId, DataUrl, HealthCheckId, HostId, PackageId}; +use models::{ActionId, DataUrl, HealthCheckId, HostId, PackageId, ServiceInterfaceId}; use patch_db::json_ptr::JsonPointer; use patch_db::HasModel; use reqwest::Url; @@ -11,6 +11,7 @@ use serde::{Deserialize, Serialize}; use ts_rs::TS; use crate::net::host::HostInfo; +use crate::net::service_interface::ServiceInterfaceWithHostInfo; use crate::prelude::*; use crate::progress::FullProgress; use crate::s9pk::manifest::Manifest; @@ -306,14 +307,14 @@ pub enum AllowedStatuses { #[serde(rename_all = "camelCase")] #[model = "Model"] pub struct ActionMetadata { - name: String, - description: String, - warning: Option, + pub name: String, + pub description: String, + pub warning: Option, #[ts(type = "any")] - input: Value, - disabled: bool, - allowedStatuses: AllowedStatuses, - group: Option, + pub input: Value, + pub disabled: bool, + pub allowed_statuses: AllowedStatuses, + pub group: Option, } #[derive(Debug, Deserialize, Serialize, HasModel, TS)] @@ -331,10 +332,11 @@ pub struct PackageDataEntry { #[ts(type = "string | null")] pub last_backup: Option>, pub current_dependencies: CurrentDependencies, + pub actions: BTreeMap, + pub service_interfaces: BTreeMap, pub hosts: HostInfo, #[ts(type = "string[]")] pub store_exposed_dependents: Vec, - pub exposed_actions: BTreeMap, } impl AsRef for PackageDataEntry { fn as_ref(&self) -> &PackageDataEntry { @@ -375,7 +377,7 @@ pub struct CurrentDependencyInfo { pub title: String, pub icon: DataUrl<'static>, #[ts(type = "string")] - pub registry: Url, + pub registry_url: Url, #[ts(type = "string")] pub version_spec: VersionRange, } diff --git a/core/startos/src/db/model/public.rs b/core/startos/src/db/model/public.rs index ea8a3ac3d..d1eec5443 100644 --- a/core/startos/src/db/model/public.rs +++ b/core/startos/src/db/model/public.rs @@ -66,10 +66,6 @@ impl Public { selected: None, }, unread_notification_count: 0, - connection_addresses: ConnectionAddresses { - tor: Vec::new(), - clearnet: Vec::new(), - }, password_hash: account.password.clone(), pubkey: ssh_key::PublicKey::from(&account.ssh_key) .to_openssh() @@ -136,8 +132,8 @@ pub struct ServerInfo { #[serde(default)] pub status_info: ServerStatus, pub wifi: WifiInfo, + #[ts(type = "number")] pub unread_notification_count: u64, - pub connection_addresses: ConnectionAddresses, pub password_hash: String, pub pubkey: String, pub ca_fingerprint: String, @@ -199,7 +195,9 @@ pub struct ServerStatus { #[model = "Model"] #[ts(export)] pub struct UpdateProgress { + #[ts(type = "number | null")] pub size: Option, + #[ts(type = "number")] pub downloaded: u64, } @@ -221,11 +219,3 @@ pub struct ServerSpecs { pub disk: String, pub memory: String, } - -#[derive(Debug, Deserialize, Serialize, TS)] -#[serde(rename_all = "camelCase")] -#[ts(export)] -pub struct ConnectionAddresses { - pub tor: Vec, - pub clearnet: Vec, -} diff --git a/core/startos/src/net/host/binding.rs b/core/startos/src/net/host/binding.rs index aa689b717..8301821f5 100644 --- a/core/startos/src/net/host/binding.rs +++ b/core/startos/src/net/host/binding.rs @@ -16,7 +16,7 @@ pub struct BindInfo { impl BindInfo { pub fn new(available_ports: &mut AvailablePorts, options: BindOptions) -> Result { let mut assigned_lan_port = None; - if options.add_ssl.is_some() || options.secure { + if options.add_ssl.is_some() || options.secure.is_some() { assigned_lan_port = Some(available_ports.alloc()?); } Ok(Self { @@ -33,7 +33,7 @@ impl BindInfo { mut assigned_lan_port, .. } = self; - if options.add_ssl.is_some() || options.secure { + if options.add_ssl.is_some() || options.secure.is_some() { assigned_lan_port = if let Some(port) = assigned_lan_port.take() { Some(port) } else { @@ -51,24 +51,30 @@ impl BindInfo { } } -#[derive(Debug, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, TS)] +#[ts(export)] +#[serde(rename_all = "camelCase")] +pub struct Security { + pub ssl: bool, +} + +#[derive(Clone, Debug, Deserialize, Serialize, TS)] #[serde(rename_all = "camelCase")] #[ts(export)] pub struct BindOptions { - #[ts(type = "string")] - pub scheme: InternedString, + #[ts(type = "string | null")] + pub scheme: Option, pub preferred_external_port: u16, pub add_ssl: Option, - pub secure: bool, - pub ssl: bool, + pub secure: Option, } #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, TS)] #[serde(rename_all = "camelCase")] #[ts(export)] pub struct AddSslOptions { - #[ts(type = "string")] - pub scheme: InternedString, + #[ts(type = "string | null")] + pub scheme: Option, pub preferred_external_port: u16, // #[serde(default)] // pub add_x_forwarded_headers: bool, // TODO diff --git a/core/startos/src/net/host/mod.rs b/core/startos/src/net/host/mod.rs index 086840bd8..2d50df15a 100644 --- a/core/startos/src/net/host/mod.rs +++ b/core/startos/src/net/host/mod.rs @@ -39,7 +39,7 @@ impl Host { } } -#[derive(Debug, Deserialize, Serialize, TS)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize, TS)] #[serde(rename_all = "camelCase")] #[ts(export)] pub enum HostKind { diff --git a/core/startos/src/net/mod.rs b/core/startos/src/net/mod.rs index f6e5ddee5..aaf019e66 100644 --- a/core/startos/src/net/mod.rs +++ b/core/startos/src/net/mod.rs @@ -7,6 +7,7 @@ pub mod host; pub mod keys; pub mod mdns; pub mod net_controller; +pub mod service_interface; pub mod ssl; pub mod static_server; pub mod tor; diff --git a/core/startos/src/net/net_controller.rs b/core/startos/src/net/net_controller.rs index c9338cdff..a4c9ea507 100644 --- a/core/startos/src/net/net_controller.rs +++ b/core/startos/src/net/net_controller.rs @@ -247,7 +247,7 @@ impl NetService { None, external, (self.ip, *port).into(), - if bind.options.ssl { + if bind.options.secure.as_ref().map_or(false, |s| s.ssl) { Ok(()) } else { Err(ssl.alpn.clone()) diff --git a/core/startos/src/net/service_interface.rs b/core/startos/src/net/service_interface.rs new file mode 100644 index 000000000..9a4659cfd --- /dev/null +++ b/core/startos/src/net/service_interface.rs @@ -0,0 +1,115 @@ +use std::net::{Ipv4Addr, Ipv6Addr}; + +use models::{HostId, ServiceInterfaceId}; +use serde::{Deserialize, Serialize}; +use ts_rs::TS; + +use crate::net::host::binding::BindOptions; +use crate::net::host::HostKind; +use crate::prelude::*; + +#[derive(Clone, Debug, Deserialize, Serialize, TS)] +#[ts(export)] +#[serde(rename_all = "camelCase")] +pub struct ServiceInterfaceWithHostInfo { + #[serde(flatten)] + pub service_interface: ServiceInterface, + pub host_info: ExportedHostInfo, +} + +#[derive(Clone, Debug, Deserialize, Serialize, TS)] +#[ts(export)] +#[serde(rename_all = "camelCase")] +pub struct ExportedHostInfo { + pub id: HostId, + pub kind: HostKind, + pub hostnames: Vec, +} + +#[derive(Clone, Debug, Deserialize, Serialize, TS)] +#[ts(export)] +#[serde(rename_all = "camelCase")] +#[serde(rename_all_fields = "camelCase")] +#[serde(tag = "kind")] +pub enum ExportedHostnameInfo { + Ip { + network_interface_id: String, + public: bool, + hostname: ExportedIpHostname, + }, + Onion { + hostname: ExportedOnionHostname, + }, +} + +#[derive(Clone, Debug, Deserialize, Serialize, TS)] +#[ts(export)] +#[serde(rename_all = "camelCase")] +pub struct ExportedOnionHostname { + pub value: String, + pub port: Option, + pub ssl_port: Option, +} + +#[derive(Clone, Debug, Deserialize, Serialize, TS)] +#[ts(export)] +#[serde(rename_all = "camelCase")] +#[serde(rename_all_fields = "camelCase")] +#[serde(tag = "kind")] +pub enum ExportedIpHostname { + Ipv4 { + value: Ipv4Addr, + port: Option, + ssl_port: Option, + }, + Ipv6 { + value: Ipv6Addr, + port: Option, + ssl_port: Option, + }, + Local { + value: String, + port: Option, + ssl_port: Option, + }, + Domain { + domain: String, + subdomain: Option, + port: Option, + ssl_port: Option, + }, +} + +#[derive(Clone, Debug, Deserialize, Serialize, TS)] +#[ts(export)] +#[serde(rename_all = "camelCase")] +pub struct ServiceInterface { + pub id: ServiceInterfaceId, + pub name: String, + pub description: String, + pub has_primary: bool, + pub disabled: bool, + pub masked: bool, + pub address_info: AddressInfo, + #[serde(rename = "type")] + pub interface_type: ServiceInterfaceType, +} + +#[derive(Clone, Debug, Deserialize, Serialize, TS)] +#[ts(export)] +#[serde(rename_all = "camelCase")] +pub enum ServiceInterfaceType { + Ui, + P2p, + Api, +} + +#[derive(Clone, Debug, Deserialize, Serialize, TS)] +#[ts(export)] +#[serde(rename_all = "camelCase")] +pub struct AddressInfo { + pub username: Option, + pub host_id: HostId, + pub bind_options: BindOptions, + pub suffix: String, +} diff --git a/core/startos/src/progress.rs b/core/startos/src/progress.rs index 0acdca111..eec637575 100644 --- a/core/startos/src/progress.rs +++ b/core/startos/src/progress.rs @@ -24,7 +24,12 @@ lazy_static::lazy_static! { #[serde(untagged)] pub enum Progress { Complete(bool), - Progress { done: u64, total: Option }, + Progress { + #[ts(type = "number")] + done: u64, + #[ts(type = "number | null")] + total: Option, + }, } impl Progress { pub fn new() -> Self { diff --git a/core/startos/src/service/service_effect_handler.rs b/core/startos/src/service/service_effect_handler.rs index 7bd1c0ab8..4041cbb98 100644 --- a/core/startos/src/service/service_effect_handler.rs +++ b/core/startos/src/service/service_effect_handler.rs @@ -11,7 +11,7 @@ use clap::Parser; use emver::VersionRange; use imbl::OrdMap; use imbl_value::{json, InternedString}; -use models::{ActionId, HealthCheckId, ImageId, PackageId, VolumeId}; +use models::{ActionId, HealthCheckId, HostId, ImageId, PackageId, VolumeId}; use patch_db::json_ptr::JsonPointer; use rpc_toolkit::{from_fn, from_fn_async, AnyContext, Context, Empty, HandlerExt, ParentHandler}; use serde::{Deserialize, Serialize}; @@ -25,11 +25,13 @@ use crate::db::model::package::{ use crate::disk::mount::filesystem::idmapped::IdMapped; use crate::disk::mount::filesystem::loop_dev::LoopDev; use crate::disk::mount::filesystem::overlayfs::OverlayGuard; +use crate::net::host::binding::BindOptions; +use crate::net::host::HostKind; use crate::prelude::*; use crate::s9pk::rpc::SKIP_ENV; use crate::service::cli::ContainerCliContext; use crate::service::ServiceActorSeed; -use crate::status::health_check::{HealthCheckResult, HealthCheckString}; +use crate::status::health_check::HealthCheckResult; use crate::status::MainStatus; use crate::util::clap::FromStrParser; use crate::util::{new_guid, Invoke}; @@ -185,21 +187,7 @@ struct GetServicePortForwardParams { package_id: Option, internal_port: u32, } -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, TS)] -#[ts(export)] -#[serde(rename_all = "camelCase")] -struct BindOptionsSecure { - ssl: bool, -} -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, TS)] -#[ts(export)] -#[serde(rename_all = "camelCase")] -struct BindOptions { - scheme: Option, - preferred_external_port: u32, - add_ssl: Option, - secure: Option, -} + #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, TS)] #[ts(export)] #[serde(rename_all = "camelCase")] @@ -379,7 +367,7 @@ async fn export_action(context: EffectContext, data: ExportActionParams) -> Resu .as_package_data_mut() .as_idx_mut(&package_id) .or_not_found(&package_id)? - .as_exposed_actions_mut(); + .as_actions_mut(); let mut value = model.de()?; value .insert(data.id, data.metadata) @@ -402,7 +390,7 @@ async fn remove_action(context: EffectContext, data: RemoveActionParams) -> Resu .as_package_data_mut() .as_idx_mut(&package_id) .or_not_found(&package_id)? - .as_exposed_actions_mut(); + .as_actions_mut(); let mut value = model.de()?; value.remove(&data.id).map(|_| ()).unwrap_or_default(); model.ser(&value) @@ -447,35 +435,16 @@ async fn get_host_info( async fn clear_bindings(context: EffectContext, _: Empty) -> Result { todo!() } -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, TS)] -#[serde(rename_all = "camelCase")] -#[ts(export)] -enum BindKind { - Static, - Single, - Multi, -} -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, TS)] -#[serde(rename_all = "camelCase")] -#[ts(export)] - -struct AddSslOptions { - scheme: Option, - preferred_external_port: u32, - add_x_forwarded_headers: Option, -} #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, TS)] #[serde(rename_all = "camelCase")] #[ts(export)] struct BindParams { - kind: BindKind, - id: String, - internal_port: u32, - scheme: String, - preferred_external_port: u32, - add_ssl: Option, - secure: Option, + kind: HostKind, + id: HostId, + internal_port: u16, + #[serde(flatten)] + options: BindOptions, } async fn bind(_: AnyContext, BindParams { .. }: BindParams) -> Result { todo!() @@ -918,19 +887,14 @@ async fn set_main_status(context: EffectContext, params: SetMainStatus) -> Resul #[serde(rename_all = "camelCase")] #[ts(export)] struct SetHealth { - #[ts(type = "string")] - name: HealthCheckId, - status: HealthCheckString, - message: Option, + id: HealthCheckId, + #[serde(flatten)] + result: HealthCheckResult, } async fn set_health( context: EffectContext, - SetHealth { - name, - status, - message, - }: SetHealth, + SetHealth { id, result }: SetHealth, ) -> Result { let context = context.deref()?; @@ -939,43 +903,22 @@ async fn set_health( .ctx .db .mutate(move |db| { - let mut main = db - .as_public() - .as_package_data() - .as_idx(package_id) - .or_not_found(package_id)? - .as_status() - .as_main() - .de()?; - match &mut main { - &mut MainStatus::Running { ref mut health, .. } - | &mut MainStatus::BackingUp { ref mut health, .. } => { - health.remove(&name); - - health.insert( - name, - match status { - HealthCheckString::Disabled => HealthCheckResult::Disabled, - HealthCheckString::Passing => HealthCheckResult::Success, - HealthCheckString::Starting => HealthCheckResult::Starting, - HealthCheckString::Warning => HealthCheckResult::Loading { - message: message.unwrap_or_default(), - }, - HealthCheckString::Failure => HealthCheckResult::Failure { - error: message.unwrap_or_default(), - }, - }, - ); - } - _ => return Ok(()), - }; db.as_public_mut() .as_package_data_mut() .as_idx_mut(package_id) .or_not_found(package_id)? .as_status_mut() .as_main_mut() - .ser(&main) + .mutate(|main| { + match main { + &mut MainStatus::Running { ref mut health, .. } + | &mut MainStatus::BackingUp { ref mut health, .. } => { + health.insert(id, result); + } + _ => (), + } + Ok(()) + }) }) .await?; Ok(json!(())) @@ -1100,7 +1043,7 @@ enum DependencyRequirement { #[ts(type = "string")] version_spec: VersionRange, #[ts(type = "string")] - registry: Url, + registry_url: Url, }, #[serde(rename_all = "camelCase")] Exists { @@ -1109,7 +1052,7 @@ enum DependencyRequirement { #[ts(type = "string")] version_spec: VersionRange, #[ts(type = "string")] - registry: Url, + registry_url: Url, }, } // filebrowser:exists,bitcoind:running:foo+bar+baz @@ -1119,7 +1062,7 @@ impl FromStr for DependencyRequirement { match s.split_once(':') { Some((id, "e")) | Some((id, "exists")) => Ok(Self::Exists { id: id.parse()?, - registry: "".parse()?, // TODO + registry_url: "".parse()?, // TODO version_spec: "*".parse()?, // TODO }), Some((id, rest)) => { @@ -1143,14 +1086,14 @@ impl FromStr for DependencyRequirement { Ok(Self::Running { id: id.parse()?, health_checks, - registry: "".parse()?, // TODO + registry_url: "".parse()?, // TODO version_spec: "*".parse()?, // TODO }) } None => Ok(Self::Running { id: s.parse()?, health_checks: BTreeSet::new(), - registry: "".parse()?, // TODO + registry_url: "".parse()?, // TODO version_spec: "*".parse()?, // TODO }), } @@ -1186,13 +1129,13 @@ async fn set_dependencies( .map(|dependency| match dependency { DependencyRequirement::Exists { id, - registry, + registry_url, version_spec, } => ( id, CurrentDependencyInfo { kind: CurrentDependencyKind::Exists, - registry, + registry_url, version_spec, icon: todo!(), title: todo!(), @@ -1201,13 +1144,13 @@ async fn set_dependencies( DependencyRequirement::Running { id, health_checks, - registry, + registry_url, version_spec, } => ( id, CurrentDependencyInfo { kind: CurrentDependencyKind::Running { health_checks }, - registry, + registry_url, version_spec, icon: todo!(), title: todo!(), diff --git a/core/startos/src/service/service_map.rs b/core/startos/src/service/service_map.rs index 1eebfced6..934497eb9 100644 --- a/core/startos/src/service/service_map.rs +++ b/core/startos/src/service/service_map.rs @@ -172,6 +172,8 @@ impl ServiceMap { icon, last_backup: None, current_dependencies: Default::default(), + actions: Default::default(), + service_interfaces: Default::default(), hosts: Default::default(), store_exposed_dependents: Default::default(), }, diff --git a/core/startos/src/status/health_check.rs b/core/startos/src/status/health_check.rs index c2af46490..8629976a0 100644 --- a/core/startos/src/status/health_check.rs +++ b/core/startos/src/status/health_check.rs @@ -2,35 +2,35 @@ pub use models::HealthCheckId; use serde::{Deserialize, Serialize}; use ts_rs::TS; +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, TS)] +#[serde(rename_all = "camelCase")] +pub struct HealthCheckResult { + pub name: String, + #[serde(flatten)] + pub kind: HealthCheckResultKind, +} + #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, TS)] #[serde(rename_all = "camelCase")] #[serde(tag = "result")] -pub enum HealthCheckResult { - Success, +pub enum HealthCheckResultKind { + Success { message: String }, Disabled, Starting, Loading { message: String }, - Failure { error: String }, + Failure { message: String }, } impl std::fmt::Display for HealthCheckResult { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - HealthCheckResult::Success => write!(f, "Succeeded"), - HealthCheckResult::Disabled => write!(f, "Disabled"), - HealthCheckResult::Starting => write!(f, "Starting"), - HealthCheckResult::Loading { message } => write!(f, "Loading ({})", message), - HealthCheckResult::Failure { error } => write!(f, "Failed ({})", error), + let name = &self.name; + match &self.kind { + HealthCheckResultKind::Success { message } => { + write!(f, "{name}: Succeeded ({message})") + } + HealthCheckResultKind::Disabled => write!(f, "{name}: Disabled"), + HealthCheckResultKind::Starting => write!(f, "{name}: Starting"), + HealthCheckResultKind::Loading { message } => write!(f, "{name}: Loading ({message})"), + HealthCheckResultKind::Failure { message } => write!(f, "{name}: Failed ({message})"), } } } - -#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, ts_rs::TS)] -#[serde(rename_all = "camelCase")] -#[ts(export)] -pub enum HealthCheckString { - Passing, - Disabled, - Starting, - Warning, - Failure, -} diff --git a/sdk/lib/Dependency.ts b/sdk/lib/Dependency.ts index 71cc05890..1e70629da 100644 --- a/sdk/lib/Dependency.ts +++ b/sdk/lib/Dependency.ts @@ -6,13 +6,13 @@ export class Dependency { | { type: "running" versionSpec: Checker - url: string + registryUrl: string healthChecks: string[] } | { type: "exists" versionSpec: Checker - url: string + registryUrl: string }, ) {} } diff --git a/sdk/lib/interfaces/Host.ts b/sdk/lib/interfaces/Host.ts index 250f42075..de54f7dc0 100644 --- a/sdk/lib/interfaces/Host.ts +++ b/sdk/lib/interfaces/Host.ts @@ -1,71 +1,58 @@ import { object, string } from "ts-matches" import { Effects } from "../types" import { Origin } from "./Origin" +import { AddSslOptions } from "../../../core/startos/bindings/AddSslOptions" +import { Security } from "../../../core/startos/bindings/Security" +import { BindOptions } from "../../../core/startos/bindings/BindOptions" +import { AlpnInfo } from "../../../core/startos/bindings/AlpnInfo" + +export { AddSslOptions, Security, BindOptions } const knownProtocols = { http: { - secure: false, - ssl: false, + secure: null, defaultPort: 80, withSsl: "https", + alpn: { specified: ["http/1.1"] } as AlpnInfo, }, https: { - secure: true, - ssl: true, + secure: { ssl: true }, defaultPort: 443, }, ws: { - secure: false, - ssl: false, + secure: null, defaultPort: 80, withSsl: "wss", + alpn: { specified: ["http/1.1"] } as AlpnInfo, }, wss: { - secure: true, - ssl: true, + secure: { ssl: true }, defaultPort: 443, }, ssh: { - secure: true, - ssl: false, + secure: { ssl: false }, defaultPort: 22, }, bitcoin: { - secure: true, - ssl: false, + secure: { ssl: false }, defaultPort: 8333, }, lightning: { - secure: true, - ssl: true, + secure: { ssl: true }, defaultPort: 9735, }, grpc: { - secure: true, - ssl: true, + secure: { ssl: true }, defaultPort: 50051, }, dns: { - secure: true, - ssl: false, + secure: { ssl: false }, defaultPort: 53, }, } as const export type Scheme = string | null -type AddSslOptions = { - scheme: Scheme - preferredExternalPort: number - addXForwardedHeaders: boolean | null /** default: false */ -} -type Security = { ssl: boolean } -export type BindOptions = { - scheme: Scheme - preferredExternalPort: number - addSsl: AddSslOptions | null - secure: Security | null -} type KnownProtocols = typeof knownProtocols type ProtocolsWithSslVariants = { [K in keyof KnownProtocols]: KnownProtocols[K] extends { @@ -177,9 +164,10 @@ export class Host { if ("noAddSsl" in options && options.noAddSsl) return null if ("withSsl" in protoInfo && protoInfo.withSsl) return { - addXForwardedHeaders: null, + // addXForwardedHeaders: null, preferredExternalPort: knownProtocols[protoInfo.withSsl].defaultPort, scheme: protoInfo.withSsl, + alpn: protoInfo.alpn, ...("addSsl" in options ? options.addSsl : null), } return null diff --git a/sdk/lib/test/startosTypeValidation.test.ts b/sdk/lib/test/startosTypeValidation.test.ts index f2e86de74..5fa3f74b3 100644 --- a/sdk/lib/test/startosTypeValidation.test.ts +++ b/sdk/lib/test/startosTypeValidation.test.ts @@ -9,7 +9,6 @@ import { ParamsMaybePackageId } from "../../../core/startos/bindings/ParamsMaybe import { SetConfigured } from "../../../core/startos/bindings/SetConfigured" import { SetHealth } from "../../../core/startos/bindings/SetHealth" import { ExposeForDependentsParams } from "../../../core/startos/bindings/ExposeForDependentsParams" -import { ExposeUiParams } from "../../../core/startos/bindings/ExposeUiParams" import { GetSslCertificateParams } from "../../../core/startos/bindings/GetSslCertificateParams" import { GetSslKeyParams } from "../../../core/startos/bindings/GetSslKeyParams" import { GetServiceInterfaceParams } from "../../../core/startos/bindings/GetServiceInterfaceParams" @@ -24,7 +23,6 @@ import { ExportActionParams } from "../../../core/startos/bindings/ExportActionP import { RemoveActionParams } from "../../../core/startos/bindings/RemoveActionParams" import { ReverseProxyParams } from "../../../core/startos/bindings/ReverseProxyParams" import { MountParams } from "../../../core/startos/bindings/MountParams" -import { ExposedUI } from "../../../core/startos/bindings/ExposedUI" function typeEquality(_a: ExpectedType) {} describe("startosTypeValidation ", () => { test(`checking the params match`, () => { diff --git a/sdk/lib/types.ts b/sdk/lib/types.ts index fa77d2c02..daa7ffe43 100644 --- a/sdk/lib/types.ts +++ b/sdk/lib/types.ts @@ -1,5 +1,6 @@ export * as configTypes from "./config/configTypes" -import { AddSslOptions } from "../../core/startos/bindings/AddSslOptions" +import { HealthCheckId } from "../../core/startos/bindings/HealthCheckId" +import { HealthCheckResult } from "../../core/startos/bindings/HealthCheckResult" import { MainEffects, ServiceInterfaceType, Signals } from "./StartSdk" import { InputSpec } from "./config/configTypes" import { DependenciesReceipt } from "./config/setupConfig" @@ -324,16 +325,13 @@ export type Effects = { /** Removes all network bindings */ clearBindings(): Promise /** Creates a host connected to the specified port with the provided options */ - bind(options: { - kind: "static" | "single" | "multi" - id: string - internalPort: number - - scheme: Scheme - preferredExternalPort: number - addSsl: AddSslOptions | null - secure: { ssl: boolean } | null - }): Promise + bind( + options: { + kind: "static" | "single" | "multi" + id: string + internalPort: number + } & BindOptions, + ): Promise /** Retrieves the current hostname(s) associated with a host id */ // getHostInfo(options: { // kind: "static" | "single" @@ -479,11 +477,11 @@ export type Effects = { algorithm: "ecdsa" | "ed25519" | null }) => Promise - setHealth(o: { - name: string - status: HealthStatus - message: string | null - }): Promise + setHealth( + o: HealthCheckResult & { + id: HealthCheckId + }, + ): Promise /** Set the dependencies of what the service needs, usually ran during the set config as a best practice */ setDependencies(options: { @@ -590,7 +588,7 @@ export type KnownError = export type Dependency = { id: PackageId versionSpec: string - url: string + registryUrl: string } & ({ kind: "exists" } | { kind: "running"; healthChecks: string[] }) export type Dependencies = Array diff --git a/web/projects/marketplace/src/types.ts b/web/projects/marketplace/src/types.ts index 7f69c3747..bc7c70f80 100644 --- a/web/projects/marketplace/src/types.ts +++ b/web/projects/marketplace/src/types.ts @@ -1,4 +1,5 @@ import { Url } from '@start9labs/shared' +import { Manifest } from '../../../../core/startos/bindings/Manifest' export type StoreURL = string export type StoreName = string @@ -41,35 +42,6 @@ export interface DependencyMetadata { hidden: boolean } -export interface Manifest { - id: string - title: string - version: string - gitHash?: string - description: { - short: string - long: string - } - replaces?: string[] - releaseNotes: string - license: string // name of license - wrapperRepo: Url - upstreamRepo: Url - supportSite: Url - marketingSite: Url - donationUrl: Url | null - alerts: { - install: string | null - uninstall: string | null - restore: string | null - start: string | null - stop: string | null - } - dependencies: Record - osVersion: string - hasConfig: boolean -} - export interface Dependency { description: string | null optional: boolean diff --git a/web/projects/ui/src/app/app/menu/menu.component.ts b/web/projects/ui/src/app/app/menu/menu.component.ts index d44781a41..7a7eb5d29 100644 --- a/web/projects/ui/src/app/app/menu/menu.component.ts +++ b/web/projects/ui/src/app/app/menu/menu.component.ts @@ -18,7 +18,7 @@ import { } from 'rxjs' import { AbstractMarketplaceService } from '@start9labs/marketplace' import { MarketplaceService } from 'src/app/services/marketplace.service' -import { DataModel, PackageState } from 'src/app/services/patch-db/data-model' +import { DataModel } from 'src/app/services/patch-db/data-model' import { SplitPaneTracker } from 'src/app/services/split-pane.service' import { Emver, THEME } from '@start9labs/shared' import { ConnectionService } from 'src/app/services/connection.service' @@ -77,12 +77,10 @@ export class MenuComponent { filter(([prev, curr]) => Object.values(prev).some( p => - [ - PackageState.Installing, - PackageState.Updating, - PackageState.Restoring, - ].includes(p.stateInfo.state) && - [PackageState.Installed, PackageState.Removing].includes( + ['installing', 'updating', 'restoring'].includes( + p.stateInfo.state, + ) && + ['installed', 'removing'].includes( curr[getManifest(p).id].stateInfo.state, ), ), diff --git a/web/projects/ui/src/app/modals/backup-select/backup-select.page.ts b/web/projects/ui/src/app/modals/backup-select/backup-select.page.ts index 861e4c29f..2b6934c39 100644 --- a/web/projects/ui/src/app/modals/backup-select/backup-select.page.ts +++ b/web/projects/ui/src/app/modals/backup-select/backup-select.page.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core' import { ModalController } from '@ionic/angular' import { map, take } from 'rxjs/operators' -import { DataModel, PackageState } from 'src/app/services/patch-db/data-model' +import { DataModel } from 'src/app/services/patch-db/data-model' import { PatchDB } from 'patch-db-client' import { firstValueFrom } from 'rxjs' import { getManifest } from 'src/app/util/get-package-data' @@ -38,7 +38,7 @@ export class BackupSelectPage { id, title, icon: pkg.icon, - disabled: pkg.stateInfo.state !== PackageState.Installed, + disabled: pkg.stateInfo.state !== 'installed', checked: false, } }) diff --git a/web/projects/ui/src/app/pages/apps-routes/app-actions/app-actions.page.ts b/web/projects/ui/src/app/pages/apps-routes/app-actions/app-actions.page.ts index c836b6206..62038e78b 100644 --- a/web/projects/ui/src/app/pages/apps-routes/app-actions/app-actions.page.ts +++ b/web/projects/ui/src/app/pages/apps-routes/app-actions/app-actions.page.ts @@ -11,8 +11,6 @@ import { PatchDB } from 'patch-db-client' import { DataModel, PackageDataEntry, - PackageMainStatus, - Status, } from 'src/app/services/patch-db/data-model' import { GenericFormPage } from 'src/app/modals/generic-form/generic-form.page' import { isEmptyObject, ErrorToastService, getPkgId } from '@start9labs/shared' @@ -20,6 +18,7 @@ import { ActionSuccessPage } from 'src/app/modals/action-success/action-success. import { hasCurrentDeps } from 'src/app/util/has-deps' import { getAllPackages, getManifest } from 'src/app/util/get-package-data' import { ActionMetadata } from '@start9labs/start-sdk/cjs/sdk/lib/types' +import { Status } from '../../../../../../../../core/startos/bindings/Status' @Component({ selector: 'app-actions', diff --git a/web/projects/ui/src/app/pages/apps-routes/app-interfaces/app-interfaces.page.ts b/web/projects/ui/src/app/pages/apps-routes/app-interfaces/app-interfaces.page.ts index c390e122c..5f7227464 100644 --- a/web/projects/ui/src/app/pages/apps-routes/app-interfaces/app-interfaces.page.ts +++ b/web/projects/ui/src/app/pages/apps-routes/app-interfaces/app-interfaces.page.ts @@ -8,9 +8,8 @@ import { PatchDB } from 'patch-db-client' import { QRComponent } from 'src/app/components/qr/qr.component' import { map } from 'rxjs' import { types as T } from '@start9labs/start-sdk' - -type ServiceInterface = T.ServiceInterface -type ServiceInterfaceWithHostInfo = T.ServiceInterfaceWithHostInfo +import { ServiceInterface } from '../../../../../../../../core/startos/bindings/ServiceInterface' +import { ServiceInterfaceWithHostInfo } from '../../../../../../../../core/startos/bindings/ServiceInterfaceWithHostInfo' type MappedInterface = ServiceInterface & { addresses: MappedAddress[] @@ -109,12 +108,10 @@ function getAddresses( const username = addressInfo.username ? addressInfo.username + '@' : '' const suffix = addressInfo.suffix || '' - const hostnames = - host.kind === 'multi' - ? host.hostnames - : host.hostname + const hostnames = host.kind === 'multi' ? host.hostnames : [] // TODO: non-multi + /* host.hostname ? [host.hostname] - : [] + : [] */ const addresses: MappedAddress[] = [] diff --git a/web/projects/ui/src/app/pages/apps-routes/app-list/app-list-pkg/app-list-pkg.component.ts b/web/projects/ui/src/app/pages/apps-routes/app-list/app-list-pkg/app-list-pkg.component.ts index 04d05a1d8..b1c62618d 100644 --- a/web/projects/ui/src/app/pages/apps-routes/app-list/app-list-pkg/app-list-pkg.component.ts +++ b/web/projects/ui/src/app/pages/apps-routes/app-list/app-list-pkg/app-list-pkg.component.ts @@ -1,11 +1,8 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core' -import { - MainStatus, - PackageDataEntry, - PackageMainStatus, -} from 'src/app/services/patch-db/data-model' +import { PackageDataEntry } from 'src/app/services/patch-db/data-model' import { PkgInfo } from 'src/app/util/get-package-info' import { UiLauncherService } from 'src/app/services/ui-launcher.service' +import { MainStatus } from '../../../../../../../../../core/startos/bindings/MainStatus' @Component({ selector: 'app-list-pkg', @@ -21,13 +18,13 @@ export class AppListPkgComponent { get pkgMainStatus(): MainStatus { return ( this.pkg.entry.status.main || { - status: PackageMainStatus.Stopped, + status: 'stopped', } ) } get sigtermTimeout(): string | null { - return this.pkgMainStatus.status === PackageMainStatus.Stopping + return this.pkgMainStatus.status === 'stopping' ? this.pkgMainStatus.timeout : null } diff --git a/web/projects/ui/src/app/pages/apps-routes/app-properties/app-properties.page.ts b/web/projects/ui/src/app/pages/apps-routes/app-properties/app-properties.page.ts index e3b4508a7..d9b6bbc3e 100644 --- a/web/projects/ui/src/app/pages/apps-routes/app-properties/app-properties.page.ts +++ b/web/projects/ui/src/app/pages/apps-routes/app-properties/app-properties.page.ts @@ -11,10 +11,7 @@ import { import { PackageProperties } from 'src/app/util/properties.util' import { QRComponent } from 'src/app/components/qr/qr.component' import { PatchDB } from 'patch-db-client' -import { - DataModel, - PackageMainStatus, -} from 'src/app/services/patch-db/data-model' +import { DataModel } from 'src/app/services/patch-db/data-model' import { ErrorToastService, getPkgId, @@ -42,7 +39,7 @@ export class AppPropertiesPage { stopped$ = this.patch .watch$('packageData', this.pkgId, 'status', 'main', 'status') - .pipe(map(status => status === PackageMainStatus.Stopped)) + .pipe(map(status => status === 'stopped')) @ViewChild(IonBackButtonDelegate, { static: false }) backButton?: IonBackButtonDelegate diff --git a/web/projects/ui/src/app/pages/apps-routes/app-show/app-show.page.ts b/web/projects/ui/src/app/pages/apps-routes/app-show/app-show.page.ts index 0c32c0ba2..52404aea3 100644 --- a/web/projects/ui/src/app/pages/apps-routes/app-show/app-show.page.ts +++ b/web/projects/ui/src/app/pages/apps-routes/app-show/app-show.page.ts @@ -26,7 +26,7 @@ import { isRestoring, isUpdating, } from 'src/app/util/get-package-data' -import { Manifest } from '@start9labs/marketplace' +import { Manifest } from '../../../../../../../../core/startos/bindings/Manifest' export interface DependencyInfo { id: string diff --git a/web/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-additional/app-show-additional.component.ts b/web/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-additional/app-show-additional.component.ts index 26281bb80..b639b216f 100644 --- a/web/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-additional/app-show-additional.component.ts +++ b/web/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-additional/app-show-additional.component.ts @@ -3,7 +3,7 @@ import { ModalController, ToastController } from '@ionic/angular' import { copyToClipboard, MarkdownComponent } from '@start9labs/shared' import { from } from 'rxjs' import { ApiService } from 'src/app/services/api/embassy-api.service' -import { Manifest } from '@start9labs/marketplace' +import { Manifest } from '../../../../../../../../../../core/startos/bindings/Manifest' @Component({ selector: 'app-show-additional', diff --git a/web/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-health-checks/app-show-health-checks.component.ts b/web/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-health-checks/app-show-health-checks.component.ts index 5ecdf9a0f..ccf46a6e8 100644 --- a/web/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-health-checks/app-show-health-checks.component.ts +++ b/web/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-health-checks/app-show-health-checks.component.ts @@ -1,11 +1,6 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core' import { ConnectionService } from 'src/app/services/connection.service' -import { - HealthCheckResult, - HealthResult, - MainStatus, -} from 'src/app/services/patch-db/data-model' -import { Manifest } from '@start9labs/marketplace' +import { HealthCheckResult } from '../../../../../../../../../../core/startos/bindings/HealthCheckResult' @Component({ selector: 'app-show-health-checks', @@ -21,12 +16,12 @@ export class AppShowHealthChecksComponent { constructor(private readonly connectionService: ConnectionService) {} - isLoading(result: HealthResult): boolean { - return result === HealthResult.Starting || result === HealthResult.Loading + isLoading(result: HealthCheckResult['result']): boolean { + return result === 'starting' || result === 'loading' } - isReady(result: HealthResult): boolean { - return result !== HealthResult.Failure && result !== HealthResult.Loading + isReady(result: HealthCheckResult['result']): boolean { + return result !== 'failure' && result !== 'loading' } asIsOrder() { diff --git a/web/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-progress/app-show-progress.component.ts b/web/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-progress/app-show-progress.component.ts index ab5c8e416..474b62f62 100644 --- a/web/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-progress/app-show-progress.component.ts +++ b/web/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-progress/app-show-progress.component.ts @@ -1,5 +1,5 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core' -import { FullProgress } from 'src/app/services/patch-db/data-model' +import { FullProgress } from '../../../../../../../../../../core/startos/bindings/FullProgress' @Component({ selector: 'app-show-progress', diff --git a/web/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-status/app-show-status.component.ts b/web/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-status/app-show-status.component.ts index 2a1c47af7..d67ce2941 100644 --- a/web/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-status/app-show-status.component.ts +++ b/web/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-status/app-show-status.component.ts @@ -8,8 +8,6 @@ import { import { DataModel, PackageDataEntry, - PackageMainStatus, - Status, } from 'src/app/services/patch-db/data-model' import { ErrorToastService } from '@start9labs/shared' import { AlertController, LoadingController } from '@ionic/angular' @@ -22,8 +20,9 @@ import { getManifest, getAllPackages, } from 'src/app/util/get-package-data' -import { Manifest } from '@start9labs/marketplace' import { PatchDB } from 'patch-db-client' +import { Status } from '../../../../../../../../../../core/startos/bindings/Status' +import { Manifest } from '../../../../../../../../../../core/startos/bindings/Manifest' @Component({ selector: 'app-show-status', @@ -84,7 +83,7 @@ export class AppShowStatusComponent { } get sigtermTimeout(): string | null { - return this.pkgStatus?.main.status === PackageMainStatus.Stopping + return this.pkgStatus?.main.status === 'stopping' ? this.pkgStatus.main.timeout : null } diff --git a/web/projects/ui/src/app/pages/apps-routes/app-show/pipes/health-color.pipe.ts b/web/projects/ui/src/app/pages/apps-routes/app-show/pipes/health-color.pipe.ts index a274aa8c0..a676c28f7 100644 --- a/web/projects/ui/src/app/pages/apps-routes/app-show/pipes/health-color.pipe.ts +++ b/web/projects/ui/src/app/pages/apps-routes/app-show/pipes/health-color.pipe.ts @@ -1,20 +1,20 @@ import { Pipe, PipeTransform } from '@angular/core' -import { HealthResult } from 'src/app/services/patch-db/data-model' +import { HealthCheckResult } from '../../../../../../../../../core/startos/bindings/HealthCheckResult' @Pipe({ name: 'healthColor', }) export class HealthColorPipe implements PipeTransform { - transform(val: HealthResult): string { + transform(val: HealthCheckResult['result']): string { switch (val) { - case HealthResult.Success: + case 'success': return 'success' - case HealthResult.Failure: + case 'failure': return 'warning' - case HealthResult.Disabled: + case 'disabled': return 'dark' - case HealthResult.Starting: - case HealthResult.Loading: + case 'starting': + case 'loading': return 'primary' } } diff --git a/web/projects/ui/src/app/pages/apps-routes/app-show/pipes/to-buttons.pipe.ts b/web/projects/ui/src/app/pages/apps-routes/app-show/pipes/to-buttons.pipe.ts index f26addee9..c51b4cac7 100644 --- a/web/projects/ui/src/app/pages/apps-routes/app-show/pipes/to-buttons.pipe.ts +++ b/web/projects/ui/src/app/pages/apps-routes/app-show/pipes/to-buttons.pipe.ts @@ -11,7 +11,7 @@ import { ModalService } from 'src/app/services/modal.service' import { ApiService } from 'src/app/services/api/embassy-api.service' import { from, map, Observable } from 'rxjs' import { PatchDB } from 'patch-db-client' -import { Manifest } from '@start9labs/marketplace' +import { Manifest } from '../../../../../../../../../core/startos/bindings/Manifest' export interface Button { title: string diff --git a/web/projects/ui/src/app/pages/apps-routes/app-show/pipes/to-health-checks.pipe.ts b/web/projects/ui/src/app/pages/apps-routes/app-show/pipes/to-health-checks.pipe.ts index 98265152b..63c31263a 100644 --- a/web/projects/ui/src/app/pages/apps-routes/app-show/pipes/to-health-checks.pipe.ts +++ b/web/projects/ui/src/app/pages/apps-routes/app-show/pipes/to-health-checks.pipe.ts @@ -1,14 +1,11 @@ import { Pipe, PipeTransform } from '@angular/core' -import { - DataModel, - HealthCheckResult, - PackageMainStatus, -} from 'src/app/services/patch-db/data-model' +import { DataModel } from 'src/app/services/patch-db/data-model' import { isEmptyObject } from '@start9labs/shared' import { map, startWith } from 'rxjs/operators' import { PatchDB } from 'patch-db-client' import { Observable } from 'rxjs' -import { Manifest } from '@start9labs/marketplace' +import { HealthCheckResult } from '../../../../../../../../../core/startos/bindings/HealthCheckResult' +import { Manifest } from '../../../../../../../../../core/startos/bindings/Manifest' @Pipe({ name: 'toHealthChecks', @@ -21,8 +18,7 @@ export class ToHealthChecksPipe implements PipeTransform { ): Observable | null> { return this.patch.watch$('packageData', manifest.id, 'status', 'main').pipe( map(main => { - return main.status === PackageMainStatus.Running && - !isEmptyObject(main.health) + return main.status === 'running' && !isEmptyObject(main.health) ? main.health : null }), diff --git a/web/projects/ui/src/app/pages/marketplace-routes/marketplace-show/marketplace-show-controls/marketplace-show-controls.component.ts b/web/projects/ui/src/app/pages/marketplace-routes/marketplace-show/marketplace-show-controls/marketplace-show-controls.component.ts index 10717cc19..a2e94aee0 100644 --- a/web/projects/ui/src/app/pages/marketplace-routes/marketplace-show/marketplace-show-controls/marketplace-show-controls.component.ts +++ b/web/projects/ui/src/app/pages/marketplace-routes/marketplace-show/marketplace-show-controls/marketplace-show-controls.component.ts @@ -7,7 +7,6 @@ import { import { AlertController, LoadingController } from '@ionic/angular' import { AbstractMarketplaceService, - Manifest, MarketplacePkg, } from '@start9labs/marketplace' import { diff --git a/web/projects/ui/src/app/pages/server-routes/server-backup/backing-up/backing-up.component.html b/web/projects/ui/src/app/pages/server-routes/server-backup/backing-up/backing-up.component.html index 7dcf4d793..d70291de9 100644 --- a/web/projects/ui/src/app/pages/server-routes/server-backup/backing-up/backing-up.component.html +++ b/web/projects/ui/src/app/pages/server-routes/server-backup/backing-up/backing-up.component.html @@ -35,7 +35,7 @@ > diff --git a/web/projects/ui/src/app/pages/server-routes/server-backup/backing-up/backing-up.component.ts b/web/projects/ui/src/app/pages/server-routes/server-backup/backing-up/backing-up.component.ts index 31d3bce1e..4a5d8951d 100644 --- a/web/projects/ui/src/app/pages/server-routes/server-backup/backing-up/backing-up.component.ts +++ b/web/projects/ui/src/app/pages/server-routes/server-backup/backing-up/backing-up.component.ts @@ -6,11 +6,9 @@ import { } from '@angular/core' import { PatchDB } from 'patch-db-client' import { take } from 'rxjs/operators' -import { - DataModel, - PackageMainStatus, -} from 'src/app/services/patch-db/data-model' +import { DataModel } from 'src/app/services/patch-db/data-model' import { Observable } from 'rxjs' +import { MainStatus } from '../../../../../../../../../core/startos/bindings/MainStatus' @Component({ selector: 'backing-up', @@ -32,7 +30,7 @@ export class BackingUpComponent { name: 'pkgMainStatus', }) export class PkgMainStatusPipe implements PipeTransform { - transform(pkgId: string): Observable { + transform(pkgId: string): Observable { return this.patch.watch$('packageData', pkgId, 'status', 'main', 'status') } diff --git a/web/projects/ui/src/app/pages/server-routes/sideload/sideload.page.ts b/web/projects/ui/src/app/pages/server-routes/sideload/sideload.page.ts index b834d084c..242b94172 100644 --- a/web/projects/ui/src/app/pages/server-routes/sideload/sideload.page.ts +++ b/web/projects/ui/src/app/pages/server-routes/sideload/sideload.page.ts @@ -4,7 +4,7 @@ import { ApiService } from 'src/app/services/api/embassy-api.service' import { ConfigService } from 'src/app/services/config.service' import cbor from 'cbor' import { ErrorToastService } from '@start9labs/shared' -import { Manifest } from '@start9labs/marketplace' +import { Manifest } from '../../../../../../../../core/startos/bindings/Manifest' interface Positions { [key: string]: [bigint, bigint] // [position, length] diff --git a/web/projects/ui/src/app/pages/updates/updates.page.ts b/web/projects/ui/src/app/pages/updates/updates.page.ts index 11d627cb5..a77dcb34f 100644 --- a/web/projects/ui/src/app/pages/updates/updates.page.ts +++ b/web/projects/ui/src/app/pages/updates/updates.page.ts @@ -10,7 +10,6 @@ import { MarketplaceService } from 'src/app/services/marketplace.service' import { AbstractMarketplaceService, Marketplace, - Manifest, MarketplacePkg, StoreIdentity, } from '@start9labs/marketplace' @@ -25,6 +24,7 @@ import { isUpdating, } from 'src/app/util/get-package-data' import { dryUpdate } from 'src/app/util/dry-update' +import { Manifest } from '../../../../../../../core/startos/bindings/Manifest' interface UpdatesData { hosts: StoreIdentity[] diff --git a/web/projects/ui/src/app/pipes/install-progress/install-progress.pipe.ts b/web/projects/ui/src/app/pipes/install-progress/install-progress.pipe.ts index 93e826bf7..7d6a646d0 100644 --- a/web/projects/ui/src/app/pipes/install-progress/install-progress.pipe.ts +++ b/web/projects/ui/src/app/pipes/install-progress/install-progress.pipe.ts @@ -1,5 +1,5 @@ import { Pipe, PipeTransform } from '@angular/core' -import { Progress } from 'src/app/services/patch-db/data-model' +import { Progress } from '../../../../../../../core/startos/bindings/Progress' @Pipe({ name: 'installingProgressString', diff --git a/web/projects/ui/src/app/pipes/launchable/launchable.pipe.ts b/web/projects/ui/src/app/pipes/launchable/launchable.pipe.ts index 668328820..d99e69c87 100644 --- a/web/projects/ui/src/app/pipes/launchable/launchable.pipe.ts +++ b/web/projects/ui/src/app/pipes/launchable/launchable.pipe.ts @@ -1,9 +1,7 @@ import { Pipe, PipeTransform } from '@angular/core' -import { - PackageMainStatus, - PackageState, -} from 'src/app/services/patch-db/data-model' import { ConfigService } from '../../services/config.service' +import { PackageState } from '../../../../../../../core/startos/bindings/PackageState' +import { MainStatus } from '../../../../../../../core/startos/bindings/MainStatus' @Pipe({ name: 'isLaunchable', @@ -11,7 +9,10 @@ import { ConfigService } from '../../services/config.service' export class LaunchablePipe implements PipeTransform { constructor(private configService: ConfigService) {} - transform(state: PackageState, status: PackageMainStatus): boolean { + transform( + state: PackageState['state'], + status: MainStatus['status'], + ): boolean { return this.configService.isLaunchable(state, status) } } diff --git a/web/projects/ui/src/app/pipes/ui/ui.pipe.ts b/web/projects/ui/src/app/pipes/ui/ui.pipe.ts index a6bbb52be..49ad380ad 100644 --- a/web/projects/ui/src/app/pipes/ui/ui.pipe.ts +++ b/web/projects/ui/src/app/pipes/ui/ui.pipe.ts @@ -2,7 +2,7 @@ import { Pipe, PipeTransform } from '@angular/core' import { PackageDataEntry } from '../../services/patch-db/data-model' import { hasUi } from '../../services/config.service' import { getManifest } from 'src/app/util/get-package-data' -import { Manifest } from '@start9labs/marketplace' +import { Manifest } from '../../../../../../../core/startos/bindings/Manifest' @Pipe({ name: 'hasUi', diff --git a/web/projects/ui/src/app/services/api/api.fixures.ts b/web/projects/ui/src/app/services/api/api.fixures.ts index 77c0a684c..4ceaff1f9 100644 --- a/web/projects/ui/src/app/services/api/api.fixures.ts +++ b/web/projects/ui/src/app/services/api/api.fixures.ts @@ -1,21 +1,16 @@ import { InstalledState, PackageDataEntry, - PackageMainStatus, - PackageState, - ServerStatusInfo, } from 'src/app/services/patch-db/data-model' import { Metric, NotificationLevel, RR, ServerNotifications } from './api.types' import { BTC_ICON, LND_ICON, PROXY_ICON } from './api-icons' -import { - DependencyMetadata, - Manifest, - MarketplacePkg, -} from '@start9labs/marketplace' +import { DependencyMetadata, MarketplacePkg } from '@start9labs/marketplace' import { Log } from '@start9labs/shared' +import { ServerStatus } from '../../../../../../../core/startos/bindings/ServerStatus' +import { Manifest } from '../../../../../../../core/startos/bindings/Manifest' export module Mock { - export const ServerUpdated: ServerStatusInfo = { + export const ServerUpdated: ServerStatus = { backupProgress: null, updateProgress: null, updated: true, @@ -75,16 +70,26 @@ export module Mock { osVersion: '0.2.12', dependencies: {}, hasConfig: true, + images: ['main'], + assets: [], + volumes: ['main'], + hardwareRequirements: { + device: {}, + arch: null, + ram: null, + }, } export const MockManifestLnd: Manifest = { id: 'lnd', title: 'Lightning Network Daemon', version: '0.11.1', + gitHash: 'abcdefgh', description: { short: 'A bolt spec compliant client.', long: 'More info about LND. More info about LND. More info about LND.', }, + replaces: ['banks', 'governments'], releaseNotes: 'Dual funded channels!', license: 'MIT', wrapperRepo: 'https://github.com/start9labs/lnd-wrapper', @@ -113,6 +118,14 @@ export module Mock { }, }, hasConfig: true, + images: ['main'], + assets: [], + volumes: ['main'], + hardwareRequirements: { + device: {}, + arch: null, + ram: null, + }, } export const MockManifestBitcoinProxy: Manifest = { @@ -145,7 +158,16 @@ export module Mock { optional: false, }, }, + replaces: [], hasConfig: false, + images: ['main'], + assets: [], + volumes: ['main'], + hardwareRequirements: { + device: {}, + arch: null, + ram: null, + }, } export const BitcoinDep: DependencyMetadata = { @@ -1376,7 +1398,7 @@ export module Mock { export const bitcoind: PackageDataEntry = { stateInfo: { - state: PackageState.Installed, + state: 'installed', manifest: MockManifestBitcoind, }, icon: '/assets/img/service-icons/bitcoind.svg', @@ -1384,7 +1406,7 @@ export module Mock { status: { configured: true, main: { - status: PackageMainStatus.Running, + status: 'running', started: new Date().toISOString(), health: {}, }, @@ -1408,9 +1430,10 @@ export module Mock { scheme: 'http', preferredExternalPort: 80, addSsl: { - addXForwardedHeaders: false, + // addXForwardedHeaders: false, preferredExternalPort: 443, scheme: 'https', + alpn: { specified: ['http/1.1', 'h2'] }, }, secure: null, }, @@ -1480,9 +1503,10 @@ export module Mock { scheme: 'http', preferredExternalPort: 80, addSsl: { - addXForwardedHeaders: false, + // addXForwardedHeaders: false, preferredExternalPort: 443, scheme: 'https', + alpn: { specified: ['http/1.1'] }, }, secure: null, }, @@ -1608,13 +1632,15 @@ export module Mock { }, }, currentDependencies: {}, + hosts: {}, + storeExposedDependents: [], marketplaceUrl: 'https://registry.start9.com/', developerKey: 'developer-key', } export const bitcoinProxy: PackageDataEntry = { stateInfo: { - state: PackageState.Installed, + state: 'installed', manifest: MockManifestBitcoinProxy, }, icon: '/assets/img/service-icons/btc-rpc-proxy.png', @@ -1622,7 +1648,7 @@ export module Mock { status: { configured: false, main: { - status: PackageMainStatus.Stopped, + status: 'stopped', }, dependencyConfigErrors: {}, }, @@ -1643,9 +1669,10 @@ export module Mock { scheme: 'http', preferredExternalPort: 80, addSsl: { - addXForwardedHeaders: false, + // addXForwardedHeaders: false, preferredExternalPort: 443, scheme: 'https', + alpn: { specified: ['http/1.1', 'h2'] }, }, secure: { ssl: true, @@ -1745,13 +1772,15 @@ export module Mock { healthChecks: [], }, }, + hosts: {}, + storeExposedDependents: [], marketplaceUrl: 'https://registry.start9.com/', developerKey: 'developer-key', } export const lnd: PackageDataEntry = { stateInfo: { - state: PackageState.Installed, + state: 'installed', manifest: MockManifestLnd, }, icon: '/assets/img/service-icons/lnd.png', @@ -1759,7 +1788,7 @@ export module Mock { status: { configured: true, main: { - status: PackageMainStatus.Stopped, + status: 'stopped', }, dependencyConfigErrors: { 'btc-rpc-proxy': 'Username not found', @@ -1993,9 +2022,10 @@ export module Mock { kind: 'exists', registryUrl: 'https://community-registry.start9.com', versionSpec: '>2.0.0', // @TODO - healthChecks: [], }, }, + hosts: {}, + storeExposedDependents: [], marketplaceUrl: 'https://registry.start9.com/', developerKey: 'developer-key', } diff --git a/web/projects/ui/src/app/services/api/api.types.ts b/web/projects/ui/src/app/services/api/api.types.ts index 0bab23a5a..43edea08e 100644 --- a/web/projects/ui/src/app/services/api/api.types.ts +++ b/web/projects/ui/src/app/services/api/api.types.ts @@ -1,12 +1,11 @@ import { Dump, Revision } from 'patch-db-client' -import { Manifest, MarketplacePkg, StoreInfo } from '@start9labs/marketplace' +import { MarketplacePkg, StoreInfo } from '@start9labs/marketplace' import { PackagePropertiesVersioned } from 'src/app/util/properties.util' import { ConfigSpec } from 'src/app/pkg-config/config-types' -import { - DataModel, - HealthCheckResult, -} from 'src/app/services/patch-db/data-model' +import { DataModel } from 'src/app/services/patch-db/data-model' import { StartOSDiskInfo, LogsRes, ServerLogsReq } from '@start9labs/shared' +import { HealthCheckResult } from '../../../../../../../core/startos/bindings/HealthCheckResult' +import { Manifest } from '../../../../../../../core/startos/bindings/Manifest' export module RR { // DB diff --git a/web/projects/ui/src/app/services/api/embassy-mock-api.service.ts b/web/projects/ui/src/app/services/api/embassy-mock-api.service.ts index 5f9b1b3bc..5cbc841ef 100644 --- a/web/projects/ui/src/app/services/api/embassy-mock-api.service.ts +++ b/web/projects/ui/src/app/services/api/embassy-mock-api.service.ts @@ -10,12 +10,8 @@ import { } from 'patch-db-client' import { DataModel, - FullProgress, InstallingState, PackageDataEntry, - PackageMainStatus, - PackageState, - ServerStatus, StateInfo, UpdatingState, } from 'src/app/services/patch-db/data-model' @@ -41,6 +37,8 @@ import { WebSocketSubjectConfig } from 'rxjs/webSocket' import { AuthService } from '../auth.service' import { ConnectionService } from '../connection.service' import { StoreInfo } from '@start9labs/marketplace' +import { FullProgress } from '../../../../../../../core/startos/bindings/FullProgress' +import { ServerStatus } from '../../../../../../../core/startos/bindings/ServerStatus' const PROGRESS: FullProgress = { overall: { @@ -576,7 +574,7 @@ export class MockApiService extends ApiService { { op: PatchOp.REPLACE, path: appPath, - value: PackageMainStatus.BackingUp, + value: 'backingUp', }, ] this.mockRevision(appPatch) @@ -586,7 +584,7 @@ export class MockApiService extends ApiService { this.mockRevision([ { ...appPatch[0], - value: PackageMainStatus.Stopped, + value: 'stopped', }, ]) this.mockRevision([ @@ -692,7 +690,7 @@ export class MockApiService extends ApiService { // state: PackageState.Installing, // if updating - state: PackageState.Updating, + state: 'updating', manifest: mockPatchData.packageData[params.id].stateInfo.manifest!, // both @@ -757,7 +755,7 @@ export class MockApiService extends ApiService { value: { ...Mock.LocalPkgs[id], stateInfo: { - state: PackageState.Restoring, + state: 'restoring', installingInfo: { newManifest: Mock.LocalPkgs[id].stateInfo.manifest!, progress: PROGRESS, @@ -789,7 +787,7 @@ export class MockApiService extends ApiService { { op: PatchOp.REPLACE, path: path + '/status', - value: PackageMainStatus.Running, + value: 'running', }, { op: PatchOp.REPLACE, @@ -849,7 +847,7 @@ export class MockApiService extends ApiService { { op: PatchOp.REPLACE, path: path + '/status', - value: PackageMainStatus.Starting, + value: 'starting', }, ] @@ -870,7 +868,7 @@ export class MockApiService extends ApiService { { op: PatchOp.REPLACE, path: path + '/status', - value: PackageMainStatus.Starting, + value: 'starting', }, { op: PatchOp.ADD, @@ -886,7 +884,7 @@ export class MockApiService extends ApiService { { op: PatchOp.REPLACE, path: path + '/status', - value: PackageMainStatus.Running, + value: 'running', }, { op: PatchOp.REMOVE, @@ -923,7 +921,7 @@ export class MockApiService extends ApiService { { op: PatchOp.REPLACE, path: path + '/status', - value: PackageMainStatus.Restarting, + value: 'restarting', }, { op: PatchOp.REPLACE, @@ -947,7 +945,7 @@ export class MockApiService extends ApiService { op: PatchOp.REPLACE, path: path, value: { - status: PackageMainStatus.Stopped, + status: 'stopped', }, }, ] @@ -959,7 +957,7 @@ export class MockApiService extends ApiService { op: PatchOp.REPLACE, path: path, value: { - status: PackageMainStatus.Stopping, + status: 'stopping', timeout: '35s', }, }, @@ -989,7 +987,7 @@ export class MockApiService extends ApiService { { op: PatchOp.REPLACE, path: `/packageData/${params.id}/stateInfo/state`, - value: PackageState.Removing, + value: 'removing', }, ] @@ -1105,7 +1103,7 @@ export class MockApiService extends ApiService { op: PatchOp.REPLACE, path: `/packageData/${id}/stateInfo`, value: { - state: PackageState.Installed, + state: 'installed', manifest: Mock.LocalPkgs[id].stateInfo.manifest, }, }, @@ -1149,11 +1147,11 @@ export class MockApiService extends ApiService { this.mockRevision(patch2) setTimeout(async () => { - const patch3: Operation[] = [ + const patch3: Operation[] = [ { op: PatchOp.REPLACE, - path: '/serverInfo/status', - value: ServerStatus.Updated, + path: '/serverInfo/statusInfo/updated', + value: true, }, { op: PatchOp.REMOVE, @@ -1167,7 +1165,7 @@ export class MockApiService extends ApiService { { op: PatchOp.REPLACE, path: '/serverInfo/status', - value: ServerStatus.Running, + value: 'running', }, ] this.mockRevision(patch4) diff --git a/web/projects/ui/src/app/services/api/mock-patch.ts b/web/projects/ui/src/app/services/api/mock-patch.ts index 00b57d2cc..3a8365b67 100644 --- a/web/projects/ui/src/app/services/api/mock-patch.ts +++ b/web/projects/ui/src/app/services/api/mock-patch.ts @@ -1,9 +1,4 @@ -import { - DataModel, - HealthResult, - PackageMainStatus, - PackageState, -} from 'src/app/services/patch-db/data-model' +import { DataModel } from 'src/app/services/patch-db/data-model' import { Mock } from './api.fixures' import { BUILT_IN_WIDGETS } from '../../pages/widgets/built-in/widgets' @@ -39,6 +34,8 @@ export const mockPatchData: DataModel = { ackInstructions: {}, }, serverInfo: { + arch: 'x86_64', + onionAddress: 'myveryownspecialtoraddress', id: 'abcdefgh', version: '0.3.5.1', lastBackup: new Date(new Date().valueOf() - 604800001).toISOString(), @@ -47,11 +44,15 @@ export const mockPatchData: DataModel = { ipInfo: { eth0: { ipv4: '10.0.0.1', + ipv4Range: '10.0.0.1/24', ipv6: null, + ipv6Range: null, }, wlan0: { ipv4: '10.0.90.12', + ipv4Range: '10.0.90.12/24', ipv6: 'FE80:CD00:0000:0CDE:1257:0000:211E:729CD', + ipv6Range: 'FE80:CD00:0000:0CDE:1257:0000:211E:729CD/64', }, }, lastWifiRegion: null, @@ -72,11 +73,18 @@ export const mockPatchData: DataModel = { caFingerprint: 'SHA-256: 63 2B 11 99 44 40 17 DF 37 FC C3 DF 0F 3D 15', ntpSynced: false, platform: 'x86_64-nonfree', + zram: true, + governor: 'performance', + wifi: { + ssids: [], + selected: null, + connected: null, + }, }, packageData: { bitcoind: { stateInfo: { - state: PackageState.Installed, + state: 'installed', manifest: { ...Mock.MockManifestBitcoind, version: '0.20.0', @@ -87,31 +95,31 @@ export const mockPatchData: DataModel = { status: { configured: true, main: { - status: PackageMainStatus.Running, + status: 'running', started: '2021-06-14T20:49:17.774Z', health: { 'ephemeral-health-check': { name: 'Ephemeral Health Check', - result: HealthResult.Starting, + result: 'starting', }, 'chain-state': { name: 'Chain State', - result: HealthResult.Loading, + result: 'loading', message: 'Bitcoin is syncing from genesis', }, 'p2p-interface': { name: 'P2P', - result: HealthResult.Success, + result: 'success', message: 'Health check successful', }, 'rpc-interface': { name: 'RPC', - result: HealthResult.Failure, + result: 'failure', message: 'RPC interface unreachable.', }, 'unnecessary-health-check': { name: 'Unnecessary Health Check', - result: HealthResult.Disabled, + result: 'disabled', }, }, }, @@ -135,9 +143,10 @@ export const mockPatchData: DataModel = { scheme: 'http', preferredExternalPort: 80, addSsl: { - addXForwardedHeaders: false, + // addXForwardedHeaders: false, preferredExternalPort: 443, scheme: 'https', + alpn: { specified: ['http/1.1', 'h2'] }, }, secure: null, }, @@ -207,9 +216,10 @@ export const mockPatchData: DataModel = { scheme: 'http', preferredExternalPort: 80, addSsl: { - addXForwardedHeaders: false, + // addXForwardedHeaders: false, preferredExternalPort: 443, scheme: 'https', + alpn: { specified: ['http/1.1'] }, }, secure: null, }, @@ -335,12 +345,14 @@ export const mockPatchData: DataModel = { }, }, currentDependencies: {}, + hosts: {}, + storeExposedDependents: [], marketplaceUrl: 'https://registry.start9.com/', developerKey: 'developer-key', }, lnd: { stateInfo: { - state: PackageState.Installed, + state: 'installed', manifest: { ...Mock.MockManifestLnd, version: '0.11.0', @@ -351,7 +363,7 @@ export const mockPatchData: DataModel = { status: { configured: true, main: { - status: PackageMainStatus.Stopped, + status: 'stopped', }, dependencyConfigErrors: { 'btc-rpc-proxy': 'This is a config unsatisfied error', @@ -586,6 +598,8 @@ export const mockPatchData: DataModel = { healthChecks: [], }, }, + hosts: {}, + storeExposedDependents: [], marketplaceUrl: 'https://registry.start9.com/', developerKey: 'developer-key', }, diff --git a/web/projects/ui/src/app/services/config.service.ts b/web/projects/ui/src/app/services/config.service.ts index 2bae31e63..eb53dd385 100644 --- a/web/projects/ui/src/app/services/config.service.ts +++ b/web/projects/ui/src/app/services/config.service.ts @@ -2,14 +2,12 @@ import { DOCUMENT } from '@angular/common' import { Inject, Injectable } from '@angular/core' import { WorkspaceConfig } from '@start9labs/shared' import { types } from '@start9labs/start-sdk' -import { - PackageDataEntry, - PackageMainStatus, - PackageState, -} from 'src/app/services/patch-db/data-model' - -type HostnameInfoIp = types.HostnameInfoIp -type HostnameInfoOnion = types.HostnameInfoOnion +import { PackageDataEntry } from 'src/app/services/patch-db/data-model' +import { PackageState } from '../../../../../../core/startos/bindings/PackageState' +import { MainStatus } from '../../../../../../core/startos/bindings/MainStatus' +import { ExportedOnionHostname } from '../../../../../../core/startos/bindings/ExportedOnionHostname' +import { ExportedIpHostname } from '../../../../../../core/startos/bindings/ExportedIpHostname' +import { ExportedHostnameInfo } from '../../../../../../core/startos/bindings/ExportedHostnameInfo' const { gitHash, @@ -56,10 +54,11 @@ export class ConfigService { return window.isSecureContext || this.isTor() } - isLaunchable(state: PackageState, status: PackageMainStatus): boolean { - return ( - state === PackageState.Installed && status === PackageMainStatus.Running - ) + isLaunchable( + state: PackageState['state'], + status: MainStatus['status'], + ): boolean { + return state === 'installed' && status === 'running' } /** ${scheme}://${username}@${host}:${externalPort}${suffix} */ @@ -76,31 +75,28 @@ export class ConfigService { const url = new URL(`${scheme}://${username}placeholder${suffix}`) if (host.kind === 'multi') { - const onionHostname = host.hostnames.find( - (h: any) => h.kind === 'onion', - ) as HostnameInfoOnion + const onionHostname = host.hostnames.find(h => h.kind === 'onion') + ?.hostname as ExportedOnionHostname if (this.isTor() && onionHostname) { - url.hostname = onionHostname.hostname.value + url.hostname = onionHostname.value } else { - const ipHostname = host.hostnames.find( - (h: any) => h.kind === 'ip', - ) as HostnameInfoIp + const ipHostname = host.hostnames.find(h => h.kind === 'ip') + ?.hostname as ExportedIpHostname if (!ipHostname) return '' url.hostname = this.hostname - url.port = String( - ipHostname.hostname.sslPort || ipHostname.hostname.port, - ) + url.port = String(ipHostname.sslPort || ipHostname.port) } } else { - const hostname = host.hostname + throw new Error('unimplemented') + const hostname = {} as ExportedHostnameInfo // host.hostname if (!hostname) return '' if (this.isTor() && hostname.kind === 'onion') { - url.hostname = hostname.hostname.value + url.hostname = (hostname.hostname as ExportedOnionHostname).value } else { url.hostname = this.hostname url.port = String(hostname.hostname.sslPort || hostname.hostname.port) diff --git a/web/projects/ui/src/app/services/dep-error.service.ts b/web/projects/ui/src/app/services/dep-error.service.ts index 1991f7bec..fe145055b 100644 --- a/web/projects/ui/src/app/services/dep-error.service.ts +++ b/web/projects/ui/src/app/services/dep-error.service.ts @@ -4,11 +4,8 @@ import { distinctUntilChanged, map, shareReplay } from 'rxjs/operators' import { PatchDB } from 'patch-db-client' import { DataModel, - HealthResult, InstalledState, PackageDataEntry, - PackageMainStatus, - PackageState, } from './patch-db/data-model' import * as deepEqual from 'fast-deep-equal' import { isInstalled } from '../util/get-package-data' @@ -79,7 +76,7 @@ export class DepErrorService { const dep = pkgs[depId] // not installed - if (!dep || dep.stateInfo.state !== PackageState.Installed) { + if (!dep || dep.stateInfo.state !== 'installed') { return { type: DependencyErrorType.NotInstalled, } @@ -107,19 +104,18 @@ export class DepErrorService { const depStatus = dep.status.main.status // not running - if ( - depStatus !== PackageMainStatus.Running && - depStatus !== PackageMainStatus.Starting - ) { + if (depStatus !== 'running' && depStatus !== 'starting') { return { type: DependencyErrorType.NotRunning, } } + const currentDep = pkg.currentDependencies[depId] + // health check failure - if (depStatus === PackageMainStatus.Running) { - for (let id of pkg.currentDependencies[depId].healthChecks) { - if (dep.status.main.health[id]?.result !== HealthResult.Success) { + if (depStatus === 'running' && currentDep.kind === 'running') { + for (let id of currentDep.healthChecks) { + if (dep.status.main.health[id]?.result !== 'success') { return { type: DependencyErrorType.HealthChecksFailed, } diff --git a/web/projects/ui/src/app/services/marketplace.service.ts b/web/projects/ui/src/app/services/marketplace.service.ts index ac9d4a8f4..30055df56 100644 --- a/web/projects/ui/src/app/services/marketplace.service.ts +++ b/web/projects/ui/src/app/services/marketplace.service.ts @@ -19,7 +19,11 @@ import { } from 'rxjs' import { RR } from 'src/app/services/api/api.types' import { ApiService } from 'src/app/services/api/embassy-api.service' -import { DataModel, UIStore } from 'src/app/services/patch-db/data-model' +import { + DataModel, + UIMarketplaceData, + UIStore, +} from 'src/app/services/patch-db/data-model' import { PatchDB } from 'patch-db-client' import { catchError, @@ -41,7 +45,7 @@ export class MarketplaceService implements AbstractMarketplaceService { private readonly knownHosts$: Observable = this.patch .watch$('ui', 'marketplace', 'knownHosts') .pipe( - map(hosts => { + map((hosts: UIMarketplaceData['knownHosts']) => { const { start9, community } = this.config.marketplace let arr = [ toStoreIdentity(start9, hosts[start9]), diff --git a/web/projects/ui/src/app/services/patch-db/data-model.ts b/web/projects/ui/src/app/services/patch-db/data-model.ts index 29761e300..b2446892e 100644 --- a/web/projects/ui/src/app/services/patch-db/data-model.ts +++ b/web/projects/ui/src/app/services/patch-db/data-model.ts @@ -1,13 +1,15 @@ import { Url } from '@start9labs/shared' -import { Manifest } from '@start9labs/marketplace' import { types } from '@start9labs/start-sdk' import { ActionMetadata } from '@start9labs/start-sdk/cjs/sdk/lib/types' +import { Public } from '../../../../../../../core/startos/bindings/Public' +import { PackageDataEntry as PDE } from '../../../../../../../core/startos/bindings/PackageDataEntry' +import { FullProgress } from '../../../../../../../core/startos/bindings/FullProgress' +import { Manifest } from '../../../../../../../core/startos/bindings/Manifest' type ServiceInterfaceWithHostInfo = types.ServiceInterfaceWithHostInfo -export interface DataModel { - serverInfo: ServerInfo - packageData: { [id: string]: PackageDataEntry } +export type DataModel = Public & { ui: UIData + packageData: Record } export interface UIData { @@ -50,197 +52,31 @@ export interface UIStore { name?: string } -export interface ServerInfo { - id: string - version: string - lastBackup: string | null - lanAddress: Url - torAddress: Url - ipInfo: IpInfo - lastWifiRegion: string | null - unreadNotificationCount: number - statusInfo: ServerStatusInfo - eosVersionCompat: string - passwordHash: string - hostname: string - pubkey: string - caFingerprint: string - ntpSynced: boolean - platform: string -} - -export interface IpInfo { - [iface: string]: { - ipv4: string | null - ipv6: string | null - } -} - -export interface ServerStatusInfo { - backupProgress: null | { - [packageId: string]: { - complete: boolean - } - } - updated: boolean - updateProgress: { size: number | null; downloaded: number } | null - restarting: boolean - shuttingDown: boolean -} - -export enum ServerStatus { - Running = 'running', - Updated = 'updated', - BackingUp = 'backing-up', -} - -export type PackageDataEntry = { +export type PackageDataEntry = PDE & { stateInfo: T - icon: Url - status: Status - actions: Record - lastBackup: string | null - currentDependencies: Record - serviceInterfaces: Record - marketplaceUrl: string | null - developerKey: string } export type StateInfo = InstalledState | InstallingState | UpdatingState export type InstalledState = { - state: PackageState.Installed | PackageState.Removing + state: 'installed' | 'removing' manifest: Manifest installingInfo?: undefined } export type InstallingState = { - state: PackageState.Installing | PackageState.Restoring + state: 'installing' | 'restoring' installingInfo: InstallingInfo manifest?: undefined } export type UpdatingState = { - state: PackageState.Updating + state: 'updating' installingInfo: InstallingInfo manifest: Manifest } -export enum PackageState { - Installing = 'installing', - Installed = 'installed', - Updating = 'updating', - Removing = 'removing', - Restoring = 'restoring', -} - -export interface CurrentDependencyInfo { - title: string - icon: string - kind: 'exists' | 'running' - registryUrl: string - versionSpec: string - healthChecks: string[] // array of health check IDs -} - -export interface Status { - configured: boolean - main: MainStatus - dependencyConfigErrors: { [id: string]: string | null } -} - -export type MainStatus = - | MainStatusStopped - | MainStatusStopping - | MainStatusStarting - | MainStatusRunning - | MainStatusBackingUp - | MainStatusRestarting - -export interface MainStatusStopped { - status: PackageMainStatus.Stopped -} - -export interface MainStatusStopping { - status: PackageMainStatus.Stopping - timeout: string -} - -export interface MainStatusStarting { - status: PackageMainStatus.Starting - restarting: boolean -} - -export interface MainStatusRunning { - status: PackageMainStatus.Running - started: string // UTC date string - health: Record -} - -export interface MainStatusBackingUp { - status: PackageMainStatus.BackingUp - started: string | null // UTC date string -} - -export interface MainStatusRestarting { - status: PackageMainStatus.Restarting -} - -export enum PackageMainStatus { - Starting = 'starting', - Running = 'running', - Stopping = 'stopping', - Stopped = 'stopped', - BackingUp = 'backing-up', - Restarting = 'restarting', -} - -export type HealthCheckResult = { name: string } & ( - | HealthCheckResultStarting - | HealthCheckResultLoading - | HealthCheckResultDisabled - | HealthCheckResultSuccess - | HealthCheckResultFailure -) - -export enum HealthResult { - Starting = 'starting', - Loading = 'loading', - Disabled = 'disabled', - Success = 'success', - Failure = 'failure', -} - -export interface HealthCheckResultStarting { - result: HealthResult.Starting -} - -export interface HealthCheckResultDisabled { - result: HealthResult.Disabled -} - -export interface HealthCheckResultSuccess { - result: HealthResult.Success - message: string -} - -export interface HealthCheckResultLoading { - result: HealthResult.Loading - message: string -} - -export interface HealthCheckResultFailure { - result: HealthResult.Failure - message: string -} - export type InstallingInfo = { progress: FullProgress newManifest: Manifest } - -export type FullProgress = { - overall: Progress - phases: { name: string; progress: Progress }[] -} -export type Progress = boolean | { done: number; total: number | null } // false means indeterminate. true means complete diff --git a/web/projects/ui/src/app/services/pkg-status-rendering.service.ts b/web/projects/ui/src/app/services/pkg-status-rendering.service.ts index 7e1f52b49..d95a5ccdc 100644 --- a/web/projects/ui/src/app/services/pkg-status-rendering.service.ts +++ b/web/projects/ui/src/app/services/pkg-status-rendering.service.ts @@ -1,12 +1,7 @@ import { isEmptyObject } from '@start9labs/shared' -import { - MainStatusStarting, - PackageDataEntry, - PackageMainStatus, - PackageState, - Status, -} from 'src/app/services/patch-db/data-model' +import { PackageDataEntry } from 'src/app/services/patch-db/data-model' import { PkgDependencyErrors } from './dep-error.service' +import { Status } from '../../../../../../core/startos/bindings/Status' export interface PackageStatus { primary: PrimaryStatus @@ -22,7 +17,7 @@ export function renderPkgStatus( let dependency: DependencyStatus | null = null let health: HealthStatus | null = null - if (pkg.stateInfo.state === PackageState.Installed) { + if (pkg.stateInfo.state === 'installed') { primary = getPrimaryStatus(pkg.status) dependency = getDependencyStatus(depErrors) health = getHealthStatus(pkg.status) @@ -36,7 +31,7 @@ export function renderPkgStatus( function getPrimaryStatus(status: Status): PrimaryStatus { if (!status.configured) { return PrimaryStatus.NeedsConfig - } else if ((status.main as MainStatusStarting).restarting) { + } else if (status.main.status === 'restarting') { return PrimaryStatus.Restarting } else { return status.main.status as any as PrimaryStatus @@ -50,7 +45,7 @@ function getDependencyStatus(depErrors: PkgDependencyErrors): DependencyStatus { } function getHealthStatus(status: Status): HealthStatus | null { - if (status.main.status !== PackageMainStatus.Running || !status.main.health) { + if (status.main.status !== 'running' || !status.main.health) { return null } diff --git a/web/projects/ui/src/app/util/get-package-data.ts b/web/projects/ui/src/app/util/get-package-data.ts index 244324501..08fbdd2df 100644 --- a/web/projects/ui/src/app/util/get-package-data.ts +++ b/web/projects/ui/src/app/util/get-package-data.ts @@ -4,11 +4,10 @@ import { InstalledState, InstallingState, PackageDataEntry, - PackageState, UpdatingState, } from 'src/app/services/patch-db/data-model' import { firstValueFrom } from 'rxjs' -import { Manifest } from '@start9labs/marketplace' +import { Manifest } from '../../../../../../core/startos/bindings/Manifest' export async function getPackage( patch: PatchDB, @@ -32,29 +31,29 @@ export function getManifest(pkg: PackageDataEntry): Manifest { export function isInstalled( pkg: PackageDataEntry, ): pkg is PackageDataEntry { - return pkg.stateInfo.state === PackageState.Installed + return pkg.stateInfo.state === 'installed' } export function isRemoving( pkg: PackageDataEntry, ): pkg is PackageDataEntry { - return pkg.stateInfo.state === PackageState.Removing + return pkg.stateInfo.state === 'removing' } export function isInstalling( pkg: PackageDataEntry, ): pkg is PackageDataEntry { - return pkg.stateInfo.state === PackageState.Installing + return pkg.stateInfo.state === 'installing' } export function isRestoring( pkg: PackageDataEntry, ): pkg is PackageDataEntry { - return pkg.stateInfo.state === PackageState.Restoring + return pkg.stateInfo.state === 'restoring' } export function isUpdating( pkg: PackageDataEntry, ): pkg is PackageDataEntry { - return pkg.stateInfo.state === PackageState.Updating + return pkg.stateInfo.state === 'updating' } diff --git a/web/projects/ui/src/app/util/get-server-info.ts b/web/projects/ui/src/app/util/get-server-info.ts index 08eecd451..ba4bf0dbf 100644 --- a/web/projects/ui/src/app/util/get-server-info.ts +++ b/web/projects/ui/src/app/util/get-server-info.ts @@ -1,6 +1,7 @@ import { PatchDB } from 'patch-db-client' -import { DataModel, ServerInfo } from 'src/app/services/patch-db/data-model' +import { DataModel } from 'src/app/services/patch-db/data-model' import { firstValueFrom } from 'rxjs' +import { ServerInfo } from '../../../../../../core/startos/bindings/ServerInfo' export async function getServerInfo( patch: PatchDB,