diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 000000000..967978a54 --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,101 @@ +# Architecture + +StartOS is an open-source Linux distribution for running personal servers. It manages discovery, installation, network configuration, backups, and health monitoring of self-hosted services. + +## Tech Stack + +- Backend: Rust (async/Tokio, Axum web framework) +- Frontend: Angular 20 + TypeScript + TaigaUI +- Container runtime: Node.js/TypeScript with LXC +- Database/State: Patch-DB (git submodule) - storage layer with reactive frontend sync +- API: JSON-RPC via rpc-toolkit (see `core/rpc-toolkit.md`) +- Auth: Password + session cookie, public/private key signatures, local authcookie (see `core/src/middleware/auth/`) + +## Project Structure + +```bash +/ +├── assets/ # Screenshots for README +├── build/ # Auxiliary files and scripts for deployed images +├── container-runtime/ # Node.js program managing package containers +├── core/ # Rust backend: API, daemon (startd), CLI (start-cli) +├── debian/ # Debian package maintainer scripts +├── image-recipe/ # Scripts for building StartOS images +├── patch-db/ # (submodule) Diff-based data store for frontend sync +├── sdk/ # TypeScript SDK for building StartOS packages +└── web/ # Web UIs (Angular) +``` + +## Components + +- **`core/`** — Rust backend daemon. Produces a single binary `startbox` that is symlinked as `startd` (main daemon), `start-cli` (CLI), `start-container` (runs inside LXC containers), `registrybox` (package registry), and `tunnelbox` (VPN/tunnel). Handles all backend logic: RPC API, service lifecycle, networking (DNS, ACME, WiFi, Tor, WireGuard), backups, and database state management. See [core/ARCHITECTURE.md](core/ARCHITECTURE.md). + +- **`web/`** — Angular 20 + TypeScript workspace using Taiga UI. Contains three applications (admin UI, setup wizard, VPN management) and two shared libraries (common components/services, marketplace). Communicates with the backend exclusively via JSON-RPC. See [web/ARCHITECTURE.md](web/ARCHITECTURE.md). + +- **`container-runtime/`** — Node.js runtime that runs inside each service's LXC container. Loads the service's JavaScript from its S9PK package and manages subcontainers. Communicates with the host daemon via JSON-RPC over Unix socket. See [container-runtime/CLAUDE.md](container-runtime/CLAUDE.md). + +- **`sdk/`** — TypeScript SDK for packaging services for StartOS (`@start9labs/start-sdk`). Split into `base/` (core types, ABI definitions, effects interface, consumed by web as `@start9labs/start-sdk-base`) and `package/` (full SDK for service developers, consumed by container-runtime as `@start9labs/start-sdk`). + +- **`patch-db/`** — Git submodule providing diff-based state synchronization. Uses CBOR encoding. Backend mutations produce diffs that are pushed to the frontend via WebSocket, enabling reactive UI updates without polling. See [patch-db repo](https://github.com/Start9Labs/patch-db). + +## Build Pipeline + +Components have a strict dependency chain. Changes flow in one direction: + +``` +Rust (core/) + → cargo test exports ts-rs types to core/bindings/ + → rsync copies to sdk/base/lib/osBindings/ + → SDK build produces baseDist/ and dist/ + → web/ consumes baseDist/ (via @start9labs/start-sdk-base) + → container-runtime/ consumes dist/ (via @start9labs/start-sdk) +``` + +Key make targets along this chain: + +| Step | Command | What it does | +|---|---|---| +| 1 | `cargo check -p start-os` | Verify Rust compiles | +| 2 | `make ts-bindings` | Export ts-rs types → rsync to SDK | +| 3 | `cd sdk && make baseDist dist` | Build SDK packages | +| 4 | `cd web && npm run check` | Type-check Angular projects | +| 5 | `cd container-runtime && npm run check` | Type-check runtime | + +**Important**: Editing `sdk/base/lib/osBindings/*.ts` alone is NOT sufficient — you must rebuild the SDK bundle (step 3) before web/container-runtime can see the changes. + +## Cross-Layer Verification + +When making changes across multiple layers (Rust, SDK, web, container-runtime), verify in this order: + +1. **Rust**: `cargo check -p start-os` — verifies core compiles +2. **TS bindings**: `make ts-bindings` — regenerates TypeScript types from Rust `#[ts(export)]` structs + - Runs `./core/build/build-ts.sh` to export ts-rs types to `core/bindings/` + - Syncs `core/bindings/` → `sdk/base/lib/osBindings/` via rsync + - If you manually edit files in `sdk/base/lib/osBindings/`, you must still rebuild the SDK (step 3) +3. **SDK bundle**: `cd sdk && make baseDist dist` — compiles SDK source into packages + - `baseDist/` is consumed by `/web` (via `@start9labs/start-sdk-base`) + - `dist/` is consumed by `/container-runtime` (via `@start9labs/start-sdk`) + - Web and container-runtime reference the **built** SDK, not source files +4. **Web type check**: `cd web && npm run check` — type-checks all Angular projects +5. **Container runtime type check**: `cd container-runtime && npm run check` — type-checks the runtime + +## Data Flow: Backend to Frontend + +StartOS uses Patch-DB for reactive state synchronization: + +1. The backend mutates state via `db.mutate()`, producing CBOR diffs +2. Diffs are pushed to the frontend over a persistent WebSocket connection +3. The frontend applies diffs to its local state copy and notifies observers +4. Components watch specific database paths via `PatchDB.watch$()`, receiving updates reactively + +This means the UI is always eventually consistent with the backend — after any mutating API call, the frontend waits for the corresponding PatchDB diff before resolving, so the UI reflects the result immediately. + +## Further Reading + +- [core/ARCHITECTURE.md](core/ARCHITECTURE.md) — Rust backend architecture +- [web/ARCHITECTURE.md](web/ARCHITECTURE.md) — Angular frontend architecture +- [container-runtime/CLAUDE.md](container-runtime/CLAUDE.md) — Container runtime details +- [core/rpc-toolkit.md](core/rpc-toolkit.md) — JSON-RPC handler patterns +- [core/s9pk-structure.md](core/s9pk-structure.md) — S9PK package format +- [docs/exver.md](docs/exver.md) — Extended versioning format +- [docs/VERSION_BUMP.md](docs/VERSION_BUMP.md) — Version bumping guide diff --git a/CLAUDE.md b/CLAUDE.md index 9bcc227ec..1b51c4b04 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -2,17 +2,11 @@ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. -## Project Overview +## Architecture -StartOS is an open-source Linux distribution for running personal servers. It manages discovery, installation, network configuration, backups, and health monitoring of self-hosted services. +See [ARCHITECTURE.md](ARCHITECTURE.md) for the full system architecture, component map, build pipeline, and cross-layer verification order. -**Tech Stack:** -- Backend: Rust (async/Tokio, Axum web framework) -- Frontend: Angular 20 + TypeScript + TaigaUI -- Container runtime: Node.js/TypeScript with LXC -- Database/State: Patch-DB (git submodule) - storage layer with reactive frontend sync -- API: JSON-RPC via rpc-toolkit (see `core/rpc-toolkit.md`) -- Auth: Password + session cookie, public/private key signatures, local authcookie (see `core/src/middleware/auth/`) +Each major component has its own `CLAUDE.md` with detailed guidance: `core/`, `web/`, `container-runtime/`, `sdk/`. ## Build & Development @@ -29,33 +23,11 @@ make update-startbox REMOTE=start9@ # Fastest iteration (binary + UI) make test-core # Run Rust tests ``` -### Verifying code changes +## Operating Rules -When making changes across multiple layers (Rust, SDK, web, container-runtime), verify in this order: - -1. **Rust**: `cargo check -p start-os` — verifies core compiles -2. **TS bindings**: `make ts-bindings` — regenerates TypeScript types from Rust `#[ts(export)]` structs - - Runs `./core/build/build-ts.sh` to export ts-rs types to `core/bindings/` - - Syncs `core/bindings/` → `sdk/base/lib/osBindings/` via rsync - - If you manually edit files in `sdk/base/lib/osBindings/`, you must still rebuild the SDK (step 3) -3. **SDK bundle**: `cd sdk && make baseDist dist` — compiles SDK source into packages - - `baseDist/` is consumed by `/web` (via `@start9labs/start-sdk-base`) - - `dist/` is consumed by `/container-runtime` (via `@start9labs/start-sdk`) - - Web and container-runtime reference the **built** SDK, not source files -4. **Web type check**: `cd web && npm run check` — type-checks all Angular projects -5. **Container runtime type check**: `cd container-runtime && npm run check` — type-checks the runtime - -**Important**: Editing `sdk/base/lib/osBindings/*.ts` alone is NOT sufficient — you must rebuild the SDK bundle (step 3) before web/container-runtime can see the changes. - -## Architecture - -Each major component has its own `CLAUDE.md` with detailed guidance. - -- **`core/`** — Rust backend daemon (startbox, start-cli, start-container, registrybox, tunnelbox) -- **`web/`** — Angular frontend workspace (admin UI, setup wizard, marketplace, shared library) -- **`container-runtime/`** — Node.js runtime managing service containers via JSON-RPC -- **`sdk/`** — TypeScript SDK for packaging services (`@start9labs/start-sdk`) -- **`patch-db/`** — Git submodule providing diff-based state synchronization +- Always verify cross-layer changes using the order described in [ARCHITECTURE.md](ARCHITECTURE.md#cross-layer-verification) +- Check component-level CLAUDE.md files for component-specific conventions +- Follow existing patterns before inventing new ones ## Supplementary Documentation diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a1ad06d2a..739568e40 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,27 +6,7 @@ This guide is for contributing to the StartOS. If you are interested in packagin - [Matrix](https://matrix.to/#/#dev-startos:matrix.start9labs.com) -## Project Structure - -```bash -/ -├── assets/ # Screenshots for README -├── build/ # Auxiliary files and scripts for deployed images -├── container-runtime/ # Node.js program managing package containers -├── core/ # Rust backend: API, daemon (startd), CLI (start-cli) -├── debian/ # Debian package maintainer scripts -├── image-recipe/ # Scripts for building StartOS images -├── patch-db/ # (submodule) Diff-based data store for frontend sync -├── sdk/ # TypeScript SDK for building StartOS packages -└── web/ # Web UIs (Angular) -``` - -See component READMEs for details: - -- [`core`](core/README.md) -- [`web`](web/README.md) -- [`build`](build/README.md) -- [`patch-db`](https://github.com/Start9Labs/patch-db) +For project structure and system architecture, see [ARCHITECTURE.md](ARCHITECTURE.md). ## Environment Setup diff --git a/core/ARCHITECTURE.md b/core/ARCHITECTURE.md new file mode 100644 index 000000000..701416f12 --- /dev/null +++ b/core/ARCHITECTURE.md @@ -0,0 +1,69 @@ +# Core Architecture + +The Rust backend daemon for StartOS. + +## Binaries + +The crate produces a single binary `startbox` that is symlinked under different names for different behavior: + +- `startbox` / `startd` — Main daemon +- `start-cli` — CLI interface +- `start-container` — Runs inside LXC containers; communicates with host and manages subcontainers +- `registrybox` — Registry daemon +- `tunnelbox` — VPN/tunnel daemon + +## Crate Structure + +- `startos` — Core library that supports building `startbox` +- `helpers` — Utility functions used across both `startos` and `js-engine` +- `models` — Types shared across `startos`, `js-engine`, and `helpers` + +## Key Modules + +- `src/context/` — Context types (RpcContext, CliContext, InitContext, DiagnosticContext) +- `src/service/` — Service lifecycle management with actor pattern (`service_actor.rs`) +- `src/db/model/` — Patch-DB models (`public.rs` synced to frontend, `private.rs` backend-only) +- `src/net/` — Networking (DNS, ACME, WiFi, Tor via Arti, WireGuard) +- `src/s9pk/` — S9PK package format (merkle archive) +- `src/registry/` — Package registry management + +## RPC Pattern + +The API is JSON-RPC (not REST). All endpoints are RPC methods organized in a hierarchical command structure using [rpc-toolkit](https://github.com/Start9Labs/rpc-toolkit). Handlers are registered in a tree of `ParentHandler` nodes, with four handler types: `from_fn_async` (standard), `from_fn_async_local` (non-Send), `from_fn` (sync), and `from_fn_blocking` (blocking). Metadata like `.with_about()` drives middleware and documentation. + +See [rpc-toolkit.md](rpc-toolkit.md) for full handler patterns and configuration. + +## Patch-DB Patterns + +Patch-DB provides diff-based state synchronization. Changes to `db/model/public.rs` automatically sync to the frontend. + +**Key patterns:** +- `db.peek().await` — Get a read-only snapshot of the database state +- `db.mutate(|db| { ... }).await` — Apply mutations atomically, returns `MutateResult` +- `#[derive(HasModel)]` — Derive macro for types stored in the database, generates typed accessors + +**Generated accessor types** (from `HasModel` derive): +- `as_field()` — Immutable reference: `&Model` +- `as_field_mut()` — Mutable reference: `&mut Model` +- `into_field()` — Owned value: `Model` + +**`Model` APIs** (from `db/prelude.rs`): +- `.de()` — Deserialize to `T` +- `.ser(&value)` — Serialize from `T` +- `.mutate(|v| ...)` — Deserialize, mutate, reserialize +- For maps: `.keys()`, `.as_idx(&key)`, `.as_idx_mut(&key)`, `.insert()`, `.remove()`, `.contains_key()` + +## i18n + +See [i18n-patterns.md](i18n-patterns.md) for internationalization key conventions and the `t!()` macro. + +## Rust Utilities & Patterns + +See [core-rust-patterns.md](core-rust-patterns.md) for common utilities (Invoke trait, Guard pattern, mount guards, Apply trait, etc.). + +## Related Documentation + +- [rpc-toolkit.md](rpc-toolkit.md) — JSON-RPC handler patterns +- [i18n-patterns.md](i18n-patterns.md) — Internationalization conventions +- [core-rust-patterns.md](core-rust-patterns.md) — Common Rust utilities +- [s9pk-structure.md](s9pk-structure.md) — S9PK package format diff --git a/core/CLAUDE.md b/core/CLAUDE.md index acd9e00fc..b68febba9 100644 --- a/core/CLAUDE.md +++ b/core/CLAUDE.md @@ -2,51 +2,24 @@ The Rust backend daemon for StartOS. -## Binaries +## Architecture -- `startbox` — Main daemon (runs as `startd`) -- `start-cli` — CLI interface -- `start-container` — Runs inside LXC containers; communicates with host and manages subcontainers -- `registrybox` — Registry daemon -- `tunnelbox` — VPN/tunnel daemon +See [ARCHITECTURE.md](ARCHITECTURE.md) for binaries, modules, Patch-DB patterns, and related documentation. -## Key Modules +See [CONTRIBUTING.md](CONTRIBUTING.md) for how to add RPC endpoints, TS-exported types, and i18n keys. -- `src/context/` — Context types (RpcContext, CliContext, InitContext, DiagnosticContext) -- `src/service/` — Service lifecycle management with actor pattern (`service_actor.rs`) -- `src/db/model/` — Patch-DB models (`public.rs` synced to frontend, `private.rs` backend-only) -- `src/net/` — Networking (DNS, ACME, WiFi, Tor via Arti, WireGuard) -- `src/s9pk/` — S9PK package format (merkle archive) -- `src/registry/` — Package registry management +## Quick Reference -## RPC Pattern +```bash +cargo check -p start-os # Type check +make test-core # Run tests +make ts-bindings # Regenerate TS types after changing #[ts(export)] structs +cd sdk && make baseDist dist # Rebuild SDK after ts-bindings +``` -See `rpc-toolkit.md` for JSON-RPC handler patterns and configuration. +## Operating Rules -## Patch-DB Patterns - -Patch-DB provides diff-based state synchronization. Changes to `db/model/public.rs` automatically sync to the frontend. - -**Key patterns:** -- `db.peek().await` — Get a read-only snapshot of the database state -- `db.mutate(|db| { ... }).await` — Apply mutations atomically, returns `MutateResult` -- `#[derive(HasModel)]` — Derive macro for types stored in the database, generates typed accessors - -**Generated accessor types** (from `HasModel` derive): -- `as_field()` — Immutable reference: `&Model` -- `as_field_mut()` — Mutable reference: `&mut Model` -- `into_field()` — Owned value: `Model` - -**`Model` APIs** (from `db/prelude.rs`): -- `.de()` — Deserialize to `T` -- `.ser(&value)` — Serialize from `T` -- `.mutate(|v| ...)` — Deserialize, mutate, reserialize -- For maps: `.keys()`, `.as_idx(&key)`, `.as_idx_mut(&key)`, `.insert()`, `.remove()`, `.contains_key()` - -## i18n - -See `i18n-patterns.md` for internationalization key conventions and the `t!()` macro. - -## Rust Utilities & Patterns - -See `core-rust-patterns.md` for common utilities (Invoke trait, Guard pattern, mount guards, Apply trait, etc.). +- Always run `cargo check -p start-os` after modifying Rust code +- When adding RPC endpoints, follow the patterns in [rpc-toolkit.md](rpc-toolkit.md) +- When modifying `#[ts(export)]` types, regenerate bindings and rebuild the SDK (see [ARCHITECTURE.md](../ARCHITECTURE.md#build-pipeline)) +- When adding i18n keys, add all 5 locales in `core/locales/i18n.yaml` (see [i18n-patterns.md](i18n-patterns.md)) diff --git a/core/CONTRIBUTING.md b/core/CONTRIBUTING.md new file mode 100644 index 000000000..63abdafc8 --- /dev/null +++ b/core/CONTRIBUTING.md @@ -0,0 +1,49 @@ +# Contributing to Core + +For general environment setup, cloning, and build system, see the root [CONTRIBUTING.md](../CONTRIBUTING.md). + +## Prerequisites + +- [Rust](https://rustup.rs) (nightly for formatting) +- [rust-analyzer](https://rust-analyzer.github.io/) recommended +- [Docker](https://docs.docker.com/get-docker/) (for cross-compilation via `rust-zig-builder` container) + +## Common Commands + +```bash +cargo check -p start-os # Type check +cargo test --features=test # Run tests (or: make test-core) +make format # Format with nightly rustfmt +cd core && cargo test --features=test # Run a specific test +``` + +## Adding a New RPC Endpoint + +1. Define a params struct with `#[derive(Deserialize, Serialize)]` +2. Choose a handler type (`from_fn_async` for most cases) +3. Write the handler function: `async fn my_handler(ctx: RpcContext, params: MyParams) -> Result` +4. Register it in the appropriate `ParentHandler` tree +5. If params/response should be available in TypeScript, add `#[derive(TS)]` and `#[ts(export)]` + +See [rpc-toolkit.md](rpc-toolkit.md) for full handler patterns and all four handler types. + +## Adding TS-Exported Types + +When a Rust type needs to be available in TypeScript (for the web frontend or SDK): + +1. Add `ts_rs::TS` to the derive list and `#[ts(export)]` to the struct/enum +2. Use `#[serde(rename_all = "camelCase")]` for JS-friendly field names +3. For types that don't implement TS (like `DateTime`, `exver::Version`), use `#[ts(type = "string")]` overrides +4. For `u64` fields that should be JS `number` (not `bigint`), use `#[ts(type = "number")]` +5. Run `make ts-bindings` to regenerate — files appear in `core/bindings/` then sync to `sdk/base/lib/osBindings/` +6. Rebuild the SDK: `cd sdk && make baseDist dist` + +## Adding i18n Keys + +1. Add the key to `core/locales/i18n.yaml` with all 5 language translations +2. Use the `t!("your.key.name")` macro in Rust code +3. Follow existing namespace conventions — match the module path where the key is used +4. Use kebab-case for multi-word segments +5. Translations are validated at compile time + +See [i18n-patterns.md](i18n-patterns.md) for full conventions. diff --git a/core/README.md b/core/README.md index 1a66748f6..c4f97a2c3 100644 --- a/core/README.md +++ b/core/README.md @@ -22,9 +22,7 @@ several different names for different behavior: - `start-sdk`: This is a CLI tool that aids in building and packaging services you wish to deploy to StartOS -## Questions +## Documentation -If you have questions about how various pieces of the backend system work. Open -an issue and tag the following people - -- dr-bonez +- [ARCHITECTURE.md](ARCHITECTURE.md) — Backend architecture, modules, and patterns +- [CONTRIBUTING.md](CONTRIBUTING.md) — How to contribute to core diff --git a/core/src/action.rs b/core/src/action.rs index 1bd1986a2..2d3e888ce 100644 --- a/core/src/action.rs +++ b/core/src/action.rs @@ -271,6 +271,7 @@ pub fn display_action_result( } #[derive(Deserialize, Serialize, TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] pub struct RunActionParams { pub package_id: PackageId, @@ -362,6 +363,7 @@ pub async fn run_action( } #[derive(Deserialize, Serialize, Parser, TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] #[command(rename_all = "kebab-case")] pub struct ClearTaskParams { diff --git a/core/src/auth.rs b/core/src/auth.rs index f145149a8..402d5d9c2 100644 --- a/core/src/auth.rs +++ b/core/src/auth.rs @@ -418,6 +418,7 @@ impl AsLogoutSessionId for KillSessionId { } #[derive(Deserialize, Serialize, Parser, TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] #[command(rename_all = "kebab-case")] pub struct KillParams { @@ -435,6 +436,7 @@ pub async fn kill( } #[derive(Deserialize, Serialize, Parser, TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] #[command(rename_all = "kebab-case")] pub struct ResetPasswordParams { diff --git a/core/src/backup/backup_bulk.rs b/core/src/backup/backup_bulk.rs index 6a2d10dfd..0f48252fa 100644 --- a/core/src/backup/backup_bulk.rs +++ b/core/src/backup/backup_bulk.rs @@ -30,6 +30,7 @@ use crate::util::serde::IoFormat; use crate::version::VersionT; #[derive(Deserialize, Serialize, Parser, TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] #[command(rename_all = "kebab-case")] pub struct BackupParams { diff --git a/core/src/backup/mod.rs b/core/src/backup/mod.rs index 3e231afe2..ce2e72f3d 100644 --- a/core/src/backup/mod.rs +++ b/core/src/backup/mod.rs @@ -2,6 +2,7 @@ use std::collections::BTreeMap; use rpc_toolkit::{Context, HandlerExt, ParentHandler, from_fn_async}; use serde::{Deserialize, Serialize}; +use ts_rs::TS; use crate::PackageId; use crate::context::CliContext; @@ -13,19 +14,22 @@ pub mod os; pub mod restore; pub mod target; -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize, Serialize, TS)] +#[ts(export)] pub struct BackupReport { server: ServerBackupReport, packages: BTreeMap, } -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize, Serialize, TS)] +#[ts(export)] pub struct ServerBackupReport { attempted: bool, error: Option, } -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize, Serialize, TS)] +#[ts(export)] pub struct PackageBackupReport { pub error: Option, } diff --git a/core/src/backup/restore.rs b/core/src/backup/restore.rs index 6f5d78eac..6e8292275 100644 --- a/core/src/backup/restore.rs +++ b/core/src/backup/restore.rs @@ -30,6 +30,7 @@ use crate::{PLATFORM, PackageId}; #[derive(Deserialize, Serialize, Parser, TS)] #[serde(rename_all = "camelCase")] #[command(rename_all = "kebab-case")] +#[ts(export)] pub struct RestorePackageParams { #[arg(help = "help.arg.package-ids")] pub ids: Vec, diff --git a/core/src/backup/target/cifs.rs b/core/src/backup/target/cifs.rs index 0c22536a5..e8a938fea 100644 --- a/core/src/backup/target/cifs.rs +++ b/core/src/backup/target/cifs.rs @@ -36,7 +36,8 @@ impl Map for CifsTargets { } } -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize, Serialize, TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] pub struct CifsBackupTarget { hostname: String, @@ -72,9 +73,10 @@ pub fn cifs() -> ParentHandler { } #[derive(Deserialize, Serialize, Parser, TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] #[command(rename_all = "kebab-case")] -pub struct AddParams { +pub struct CifsAddParams { #[arg(help = "help.arg.cifs-hostname")] pub hostname: String, #[arg(help = "help.arg.cifs-path")] @@ -87,12 +89,12 @@ pub struct AddParams { pub async fn add( ctx: RpcContext, - AddParams { + CifsAddParams { hostname, path, username, password, - }: AddParams, + }: CifsAddParams, ) -> Result, Error> { let cifs = Cifs { hostname, @@ -131,9 +133,10 @@ pub async fn add( } #[derive(Deserialize, Serialize, Parser, TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] #[command(rename_all = "kebab-case")] -pub struct UpdateParams { +pub struct CifsUpdateParams { #[arg(help = "help.arg.backup-target-id")] pub id: BackupTargetId, #[arg(help = "help.arg.cifs-hostname")] @@ -148,13 +151,13 @@ pub struct UpdateParams { pub async fn update( ctx: RpcContext, - UpdateParams { + CifsUpdateParams { id, hostname, path, username, password, - }: UpdateParams, + }: CifsUpdateParams, ) -> Result, Error> { let id = if let BackupTargetId::Cifs { id } = id { id @@ -207,14 +210,15 @@ pub async fn update( } #[derive(Deserialize, Serialize, Parser, TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] #[command(rename_all = "kebab-case")] -pub struct RemoveParams { +pub struct CifsRemoveParams { #[arg(help = "help.arg.backup-target-id")] pub id: BackupTargetId, } -pub async fn remove(ctx: RpcContext, RemoveParams { id }: RemoveParams) -> Result<(), Error> { +pub async fn remove(ctx: RpcContext, CifsRemoveParams { id }: CifsRemoveParams) -> Result<(), Error> { let id = if let BackupTargetId::Cifs { id } = id { id } else { diff --git a/core/src/backup/target/mod.rs b/core/src/backup/target/mod.rs index a5956eb65..86a006cdd 100644 --- a/core/src/backup/target/mod.rs +++ b/core/src/backup/target/mod.rs @@ -34,7 +34,8 @@ use crate::util::{FromStrParser, VersionString}; pub mod cifs; -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize, Serialize, TS)] +#[ts(export)] #[serde(tag = "type")] #[serde(rename_all = "camelCase")] pub enum BackupTarget { @@ -49,7 +50,7 @@ pub enum BackupTarget { } #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, TS)] -#[ts(type = "string")] +#[ts(export, type = "string")] pub enum BackupTargetId { Disk { logicalname: PathBuf }, Cifs { id: u32 }, @@ -111,6 +112,7 @@ impl Serialize for BackupTargetId { } #[derive(Debug, Deserialize, Serialize, TS)] +#[ts(export)] #[serde(tag = "type")] #[serde(rename_all = "camelCase")] pub enum BackupTargetFS { @@ -210,20 +212,26 @@ pub async fn list(ctx: RpcContext) -> Result>, pub package_backups: BTreeMap, } -#[derive(Clone, Debug, Deserialize, Serialize)] +#[derive(Clone, Debug, Deserialize, Serialize, TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] pub struct PackageBackupInfo { pub title: InternedString, pub version: VersionString, + #[ts(type = "string")] pub os_version: Version, + #[ts(type = "string")] pub timestamp: DateTime, } @@ -265,6 +273,7 @@ fn display_backup_info(params: WithIoFormat, info: BackupInfo) -> Re } #[derive(Deserialize, Serialize, Parser, TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] #[command(rename_all = "kebab-case")] pub struct InfoParams { @@ -387,6 +396,7 @@ pub async fn mount( } #[derive(Deserialize, Serialize, Parser, TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] #[command(rename_all = "kebab-case")] pub struct UmountParams { diff --git a/core/src/control.rs b/core/src/control.rs index f5d39d288..63b4ea889 100644 --- a/core/src/control.rs +++ b/core/src/control.rs @@ -8,6 +8,7 @@ use crate::prelude::*; use crate::{Error, PackageId}; #[derive(Deserialize, Serialize, Parser, TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] #[command(rename_all = "kebab-case")] pub struct ControlParams { diff --git a/core/src/disk/util.rs b/core/src/disk/util.rs index fff4264a5..25dff7bf1 100644 --- a/core/src/disk/util.rs +++ b/core/src/disk/util.rs @@ -43,22 +43,28 @@ pub struct DiskInfo { pub guid: Option, } -#[derive(Clone, Debug, Deserialize, Serialize)] +#[derive(Clone, Debug, Deserialize, Serialize, ts_rs::TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] pub struct PartitionInfo { pub logicalname: PathBuf, pub label: Option, + #[ts(type = "number")] pub capacity: u64, + #[ts(type = "number | null")] pub used: Option, pub start_os: BTreeMap, pub guid: Option, } -#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[derive(Clone, Debug, Default, Deserialize, Serialize, ts_rs::TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] pub struct StartOsRecoveryInfo { pub hostname: Hostname, + #[ts(type = "string")] pub version: exver::Version, + #[ts(type = "string")] pub timestamp: DateTime, pub password_hash: Option, pub wrapped_key: Option, diff --git a/core/src/hostname.rs b/core/src/hostname.rs index 5c88bdcec..91c10f06c 100644 --- a/core/src/hostname.rs +++ b/core/src/hostname.rs @@ -6,7 +6,8 @@ use tracing::instrument; use crate::util::Invoke; use crate::{Error, ErrorKind}; -#[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize)] +#[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize, ts_rs::TS)] +#[ts(type = "string")] pub struct Hostname(pub InternedString); lazy_static::lazy_static! { diff --git a/core/src/install/mod.rs b/core/src/install/mod.rs index 9267be2d5..80687c0c2 100644 --- a/core/src/install/mod.rs +++ b/core/src/install/mod.rs @@ -177,6 +177,7 @@ pub async fn install( } #[derive(Deserialize, Serialize, TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] pub struct SideloadParams { #[ts(skip)] @@ -185,6 +186,7 @@ pub struct SideloadParams { } #[derive(Deserialize, Serialize, TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] pub struct SideloadResponse { pub upload: Guid, @@ -284,6 +286,7 @@ pub async fn sideload( } #[derive(Debug, Clone, Deserialize, Serialize, Parser, TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] #[command(rename_all = "kebab-case")] pub struct CancelInstallParams { @@ -521,6 +524,7 @@ pub async fn cli_install( } #[derive(Deserialize, Serialize, Parser, TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] #[command(rename_all = "kebab-case")] pub struct UninstallParams { diff --git a/core/src/logs.rs b/core/src/logs.rs index 737907bb1..7c72415f5 100644 --- a/core/src/logs.rs +++ b/core/src/logs.rs @@ -24,6 +24,7 @@ use tokio::process::{Child, Command}; use tokio_stream::wrappers::LinesStream; use tokio_tungstenite::tungstenite::Message; use tracing::instrument; +use ts_rs::TS; use crate::PackageId; use crate::context::{CliContext, RpcContext}; @@ -109,23 +110,28 @@ async fn ws_handler( } } -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] pub struct LogResponse { + #[ts(as = "Vec")] pub entries: Reversible, start_cursor: Option, end_cursor: Option, } -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] pub struct LogFollowResponse { start_cursor: Option, guid: Guid, } -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] pub struct LogEntry { + #[ts(type = "string")] timestamp: DateTime, message: String, boot_id: String, @@ -321,14 +327,17 @@ impl From for String { } } -#[derive(Deserialize, Serialize, Parser)] +#[derive(Deserialize, Serialize, Parser, TS)] +#[ts(export, concrete(Extra = Empty), bound = "")] #[serde(rename_all = "camelCase")] #[command(rename_all = "kebab-case")] pub struct LogsParams { #[command(flatten)] #[serde(flatten)] + #[ts(skip)] extra: Extra, #[arg(short = 'l', long = "limit", help = "help.arg.log-limit")] + #[ts(optional)] limit: Option, #[arg( short = 'c', @@ -336,9 +345,11 @@ pub struct LogsParams { conflicts_with = "follow", help = "help.arg.log-cursor" )] + #[ts(optional)] cursor: Option, #[arg(short = 'b', long = "boot", help = "help.arg.log-boot")] #[serde(default)] + #[ts(optional, type = "number | string")] boot: Option, #[arg( short = 'B', diff --git a/core/src/net/acme.rs b/core/src/net/acme.rs index 8054715af..056e77e4f 100644 --- a/core/src/net/acme.rs +++ b/core/src/net/acme.rs @@ -461,7 +461,8 @@ impl ValueParserFactory for AcmeProvider { } } -#[derive(Deserialize, Serialize, Parser)] +#[derive(Deserialize, Serialize, Parser, TS)] +#[ts(export)] pub struct InitAcmeParams { #[arg(long, help = "help.arg.acme-provider")] pub provider: AcmeProvider, @@ -486,7 +487,8 @@ pub async fn init( Ok(()) } -#[derive(Deserialize, Serialize, Parser)] +#[derive(Deserialize, Serialize, Parser, TS)] +#[ts(export)] pub struct RemoveAcmeParams { #[arg(long, help = "help.arg.acme-provider")] pub provider: AcmeProvider, diff --git a/core/src/net/dns.rs b/core/src/net/dns.rs index cb435624d..187eae9ca 100644 --- a/core/src/net/dns.rs +++ b/core/src/net/dns.rs @@ -25,6 +25,7 @@ use serde::{Deserialize, Serialize}; use tokio::net::{TcpListener, UdpSocket}; use tokio::sync::RwLock; use tracing::instrument; +use ts_rs::TS; use crate::context::{CliContext, RpcContext}; use crate::db::model::Database; @@ -93,7 +94,8 @@ pub fn dns_api() -> ParentHandler { ) } -#[derive(Deserialize, Serialize, Parser)] +#[derive(Deserialize, Serialize, Parser, TS)] +#[ts(export)] pub struct QueryDnsParams { #[arg(help = "help.arg.fqdn")] pub fqdn: InternedString, @@ -133,7 +135,8 @@ pub fn query_dns( .map_err(Error::from) } -#[derive(Deserialize, Serialize, Parser)] +#[derive(Deserialize, Serialize, Parser, TS)] +#[ts(export)] pub struct SetStaticDnsParams { #[arg(help = "help.arg.dns-servers")] pub servers: Option>, diff --git a/core/src/net/gateway.rs b/core/src/net/gateway.rs index cb4e2ba6b..81a749d18 100644 --- a/core/src/net/gateway.rs +++ b/core/src/net/gateway.rs @@ -119,6 +119,7 @@ async fn list_interfaces( } #[derive(Debug, Clone, Deserialize, Serialize, Parser, TS)] +#[ts(export)] struct ForgetGatewayParams { #[arg(help = "help.arg.gateway-id")] gateway: GatewayId, @@ -132,6 +133,7 @@ async fn forget_iface( } #[derive(Debug, Clone, Deserialize, Serialize, Parser, TS)] +#[ts(export)] struct RenameGatewayParams { #[arg(help = "help.arg.gateway-id")] id: GatewayId, diff --git a/core/src/net/host/address.rs b/core/src/net/host/address.rs index 8adfb5095..b2e30ce33 100644 --- a/core/src/net/host/address.rs +++ b/core/src/net/host/address.rs @@ -25,6 +25,7 @@ pub struct HostAddress { } #[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[ts(export)] pub struct PublicDomainConfig { pub gateway: GatewayId, pub acme: Option, @@ -158,7 +159,8 @@ pub fn address_api() ) } -#[derive(Deserialize, Serialize, Parser)] +#[derive(Deserialize, Serialize, Parser, TS)] +#[ts(export)] pub struct AddPublicDomainParams { #[arg(help = "help.arg.fqdn")] pub fqdn: InternedString, @@ -211,7 +213,8 @@ pub async fn add_public_domain( .with_kind(ErrorKind::Unknown)? } -#[derive(Deserialize, Serialize, Parser)] +#[derive(Deserialize, Serialize, Parser, TS)] +#[ts(export)] pub struct RemoveDomainParams { #[arg(help = "help.arg.fqdn")] pub fqdn: InternedString, @@ -239,7 +242,8 @@ pub async fn remove_public_domain( Ok(()) } -#[derive(Deserialize, Serialize, Parser)] +#[derive(Deserialize, Serialize, Parser, TS)] +#[ts(export)] pub struct AddPrivateDomainParams { #[arg(help = "help.arg.fqdn")] pub fqdn: InternedString, diff --git a/core/src/net/wifi.rs b/core/src/net/wifi.rs index 046ad612f..9feb1bd59 100644 --- a/core/src/net/wifi.rs +++ b/core/src/net/wifi.rs @@ -85,6 +85,7 @@ pub fn wifi() -> ParentHandler { } #[derive(Deserialize, Serialize, Parser, TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] #[command(rename_all = "kebab-case")] pub struct SetWifiEnabledParams { @@ -150,16 +151,17 @@ pub fn country() -> ParentHandler { } #[derive(Deserialize, Serialize, Parser, TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] #[command(rename_all = "kebab-case")] -pub struct AddParams { +pub struct WifiAddParams { #[arg(help = "help.arg.wifi-ssid")] ssid: String, #[arg(help = "help.arg.wifi-password")] password: String, } #[instrument(skip_all)] -pub async fn add(ctx: RpcContext, AddParams { ssid, password }: AddParams) -> Result<(), Error> { +pub async fn add(ctx: RpcContext, WifiAddParams { ssid, password }: WifiAddParams) -> Result<(), Error> { let wifi_manager = ctx.wifi_manager.clone(); if !ssid.is_ascii() { return Err(Error::new( @@ -229,15 +231,16 @@ pub async fn add(ctx: RpcContext, AddParams { ssid, password }: AddParams) -> Re Ok(()) } #[derive(Deserialize, Serialize, Parser, TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] #[command(rename_all = "kebab-case")] -pub struct SsidParams { +pub struct WifiSsidParams { #[arg(help = "help.arg.wifi-ssid")] ssid: String, } #[instrument(skip_all)] -pub async fn connect(ctx: RpcContext, SsidParams { ssid }: SsidParams) -> Result<(), Error> { +pub async fn connect(ctx: RpcContext, WifiSsidParams { ssid }: WifiSsidParams) -> Result<(), Error> { let wifi_manager = ctx.wifi_manager.clone(); if !ssid.is_ascii() { return Err(Error::new( @@ -311,7 +314,7 @@ pub async fn connect(ctx: RpcContext, SsidParams { ssid }: SsidParams) -> Result } #[instrument(skip_all)] -pub async fn remove(ctx: RpcContext, SsidParams { ssid }: SsidParams) -> Result<(), Error> { +pub async fn remove(ctx: RpcContext, WifiSsidParams { ssid }: WifiSsidParams) -> Result<(), Error> { let wifi_manager = ctx.wifi_manager.clone(); if !ssid.is_ascii() { return Err(Error::new( @@ -359,11 +362,13 @@ pub async fn remove(ctx: RpcContext, SsidParams { ssid }: SsidParams) -> Result< .result?; Ok(()) } -#[derive(serde::Serialize, serde::Deserialize)] +#[derive(serde::Serialize, serde::Deserialize, TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] pub struct WifiListInfo { ssids: HashMap, connected: Option, + #[ts(type = "string | null")] country: Option, ethernet: bool, available_wifi: Vec, @@ -374,7 +379,8 @@ pub struct WifiListInfoLow { strength: SignalStrength, security: Vec, } -#[derive(serde::Serialize, serde::Deserialize)] +#[derive(serde::Serialize, serde::Deserialize, TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] pub struct WifiListOut { ssid: Ssid, @@ -560,6 +566,7 @@ pub async fn get_available(ctx: RpcContext, _: Empty) -> Result } #[derive(Deserialize, Serialize, Parser, TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] #[command(rename_all = "kebab-case")] pub struct SetCountryParams { @@ -605,7 +612,7 @@ pub struct NetworkId(String); /// Ssid are the names of the wifis, usually human readable. #[derive( - Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize, + Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize, TS, )] pub struct Ssid(String); @@ -622,6 +629,7 @@ pub struct Ssid(String); Hash, serde::Serialize, serde::Deserialize, + TS, )] pub struct SignalStrength(u8); diff --git a/core/src/notifications.rs b/core/src/notifications.rs index 1d6c147ba..2e5ca39ac 100644 --- a/core/src/notifications.rs +++ b/core/src/notifications.rs @@ -75,6 +75,7 @@ pub fn notification() -> ParentHandler { } #[derive(Deserialize, Serialize, Parser, TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] #[command(rename_all = "kebab-case")] pub struct ListNotificationParams { @@ -140,6 +141,7 @@ pub async fn list( } #[derive(Deserialize, Serialize, Parser, TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] #[command(rename_all = "kebab-case")] pub struct ModifyNotificationParams { @@ -175,6 +177,7 @@ pub async fn remove( } #[derive(Deserialize, Serialize, Parser, TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] #[command(rename_all = "kebab-case")] pub struct ModifyNotificationBeforeParams { @@ -326,6 +329,7 @@ pub async fn create( } #[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] pub enum NotificationLevel { Success, @@ -396,26 +400,31 @@ impl Map for Notifications { } } -#[derive(Debug, Serialize, Deserialize, HasModel)] +#[derive(Debug, Serialize, Deserialize, HasModel, TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] #[model = "Model"] pub struct Notification { pub package_id: Option, + #[ts(type = "string")] pub created_at: DateTime, pub code: u32, pub level: NotificationLevel, pub title: String, pub message: String, + #[ts(type = "any")] pub data: Value, #[serde(default = "const_true")] pub seen: bool, } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] pub struct NotificationWithId { id: u32, #[serde(flatten)] + #[ts(flatten)] notification: Notification, } diff --git a/core/src/service/effects/action.rs b/core/src/service/effects/action.rs index adb6f2d74..d157eafe5 100644 --- a/core/src/service/effects/action.rs +++ b/core/src/service/effects/action.rs @@ -151,7 +151,7 @@ async fn get_action_input( #[derive(Debug, Clone, Serialize, Deserialize, TS, Parser)] #[serde(rename_all = "camelCase")] -#[ts(export)] +#[ts(export, rename = "EffectsRunActionParams")] pub struct RunActionParams { #[serde(default)] #[ts(skip)] diff --git a/core/src/service/mod.rs b/core/src/service/mod.rs index 81aae3229..cc977cdfb 100644 --- a/core/src/service/mod.rs +++ b/core/src/service/mod.rs @@ -701,6 +701,7 @@ struct ServiceActorSeed { } #[derive(Deserialize, Serialize, Parser, TS)] +#[ts(export)] pub struct RebuildParams { #[arg(help = "help.arg.package-id")] pub id: PackageId, diff --git a/core/src/ssh.rs b/core/src/ssh.rs index 7d8b073b4..a29bd76f8 100644 --- a/core/src/ssh.rs +++ b/core/src/ssh.rs @@ -58,7 +58,8 @@ impl ValueParserFactory for SshPubKey { } } -#[derive(serde::Serialize, serde::Deserialize)] +#[derive(serde::Serialize, serde::Deserialize, TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] pub struct SshKeyResponse { pub alg: String, @@ -115,15 +116,16 @@ pub fn ssh() -> ParentHandler { } #[derive(Deserialize, Serialize, Parser, TS)] +#[ts(export)] #[serde(rename_all = "camelCase")] #[command(rename_all = "kebab-case")] -pub struct AddParams { +pub struct SshAddParams { #[arg(help = "help.arg.ssh-public-key")] key: SshPubKey, } #[instrument(skip_all)] -pub async fn add(ctx: RpcContext, AddParams { key }: AddParams) -> Result { +pub async fn add(ctx: RpcContext, SshAddParams { key }: SshAddParams) -> Result { let mut key = WithTimeData::new(key); let fingerprint = InternedString::intern(key.0.fingerprint_md5()); let (keys, res) = ctx @@ -150,9 +152,10 @@ pub async fn add(ctx: RpcContext, AddParams { key }: AddParams) -> Result Result<(), Error> { let keys = ctx .db diff --git a/core/src/system/mod.rs b/core/src/system/mod.rs index 3fe43797a..f6234f78e 100644 --- a/core/src/system/mod.rs +++ b/core/src/system/mod.rs @@ -191,7 +191,9 @@ pub async fn governor( Ok(GovernorInfo { current, available }) } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, TS)] +#[ts(export)] +#[serde(rename_all = "camelCase")] pub struct TimeInfo { now: String, uptime: u64, @@ -331,6 +333,7 @@ pub struct MetricLeaf { } #[derive(Clone, Copy, Debug, PartialEq, PartialOrd, TS)] +#[ts(type = "{ value: string, unit: string }")] pub struct Celsius(f64); impl fmt::Display for Celsius { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -359,6 +362,7 @@ impl<'de> Deserialize<'de> for Celsius { } } #[derive(Clone, Debug, PartialEq, PartialOrd, TS)] +#[ts(type = "{ value: string, unit: string }")] pub struct Percentage(f64); impl Serialize for Percentage { fn serialize(&self, serializer: S) -> Result @@ -385,6 +389,7 @@ impl<'de> Deserialize<'de> for Percentage { } #[derive(Clone, Debug, TS)] +#[ts(type = "{ value: string, unit: string }")] pub struct MebiBytes(pub f64); impl Serialize for MebiBytes { fn serialize(&self, serializer: S) -> Result @@ -411,6 +416,7 @@ impl<'de> Deserialize<'de> for MebiBytes { } #[derive(Clone, Debug, PartialEq, PartialOrd, TS)] +#[ts(type = "{ value: string, unit: string }")] pub struct GigaBytes(f64); impl Serialize for GigaBytes { fn serialize(&self, serializer: S) -> Result @@ -490,6 +496,7 @@ pub async fn metrics(ctx: RpcContext) -> Result { #[derive(Deserialize, Serialize, Clone, Debug, TS)] #[serde(rename_all = "camelCase")] +#[ts(export)] pub struct MetricsFollowResponse { pub guid: Guid, pub metrics: Metrics, @@ -1211,6 +1218,7 @@ pub async fn set_keyboard(ctx: RpcContext, options: KeyboardOptions) -> Result<( } #[derive(Debug, Clone, Deserialize, Serialize, TS, Parser)] +#[ts(export)] #[serde(rename_all = "camelCase")] pub struct SetLanguageParams { #[arg(help = "help.arg.language-code")] diff --git a/sdk/base/lib/osBindings/AddPrivateDomainParams.ts b/sdk/base/lib/osBindings/AddPrivateDomainParams.ts new file mode 100644 index 000000000..5eb1f3e50 --- /dev/null +++ b/sdk/base/lib/osBindings/AddPrivateDomainParams.ts @@ -0,0 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { GatewayId } from './GatewayId' + +export type AddPrivateDomainParams = { fqdn: string; gateway: GatewayId } diff --git a/sdk/base/lib/osBindings/AddPublicDomainParams.ts b/sdk/base/lib/osBindings/AddPublicDomainParams.ts new file mode 100644 index 000000000..3d7ddbdc1 --- /dev/null +++ b/sdk/base/lib/osBindings/AddPublicDomainParams.ts @@ -0,0 +1,9 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { AcmeProvider } from './AcmeProvider' +import type { GatewayId } from './GatewayId' + +export type AddPublicDomainParams = { + fqdn: string + acme: AcmeProvider | null + gateway: GatewayId +} diff --git a/sdk/base/lib/osBindings/BackupInfo.ts b/sdk/base/lib/osBindings/BackupInfo.ts new file mode 100644 index 000000000..bc36fecb1 --- /dev/null +++ b/sdk/base/lib/osBindings/BackupInfo.ts @@ -0,0 +1,9 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { PackageBackupInfo } from './PackageBackupInfo' +import type { PackageId } from './PackageId' + +export type BackupInfo = { + version: string + timestamp: string | null + packageBackups: { [key: PackageId]: PackageBackupInfo } +} diff --git a/sdk/base/lib/osBindings/BackupParams.ts b/sdk/base/lib/osBindings/BackupParams.ts new file mode 100644 index 000000000..921f4ec22 --- /dev/null +++ b/sdk/base/lib/osBindings/BackupParams.ts @@ -0,0 +1,11 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { BackupTargetId } from './BackupTargetId' +import type { PackageId } from './PackageId' +import type { PasswordType } from './PasswordType' + +export type BackupParams = { + targetId: BackupTargetId + oldPassword: PasswordType | null + packageIds: Array | null + password: PasswordType +} diff --git a/sdk/base/lib/osBindings/BackupReport.ts b/sdk/base/lib/osBindings/BackupReport.ts new file mode 100644 index 000000000..9cc3f0576 --- /dev/null +++ b/sdk/base/lib/osBindings/BackupReport.ts @@ -0,0 +1,9 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { PackageBackupReport } from './PackageBackupReport' +import type { PackageId } from './PackageId' +import type { ServerBackupReport } from './ServerBackupReport' + +export type BackupReport = { + server: ServerBackupReport + packages: { [key: PackageId]: PackageBackupReport } +} diff --git a/sdk/base/lib/osBindings/BackupTarget.ts b/sdk/base/lib/osBindings/BackupTarget.ts new file mode 100644 index 000000000..886222570 --- /dev/null +++ b/sdk/base/lib/osBindings/BackupTarget.ts @@ -0,0 +1,17 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { CifsBackupTarget } from './CifsBackupTarget' +import type { StartOsRecoveryInfo } from './StartOsRecoveryInfo' + +export type BackupTarget = + | { + type: 'disk' + vendor: string | null + model: string | null + logicalname: string + label: string | null + capacity: number + used: number | null + startOs: { [key: string]: StartOsRecoveryInfo } + guid: string | null + } + | ({ type: 'cifs' } & CifsBackupTarget) diff --git a/sdk/base/lib/osBindings/BackupTargetId.ts b/sdk/base/lib/osBindings/BackupTargetId.ts new file mode 100644 index 000000000..927dd2e1b --- /dev/null +++ b/sdk/base/lib/osBindings/BackupTargetId.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 BackupTargetId = string diff --git a/sdk/base/lib/osBindings/CancelInstallParams.ts b/sdk/base/lib/osBindings/CancelInstallParams.ts new file mode 100644 index 000000000..28f73d5d7 --- /dev/null +++ b/sdk/base/lib/osBindings/CancelInstallParams.ts @@ -0,0 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { PackageId } from './PackageId' + +export type CancelInstallParams = { id: PackageId } diff --git a/sdk/base/lib/osBindings/Celsius.ts b/sdk/base/lib/osBindings/Celsius.ts index 298f97f5e..24b3380df 100644 --- a/sdk/base/lib/osBindings/Celsius.ts +++ b/sdk/base/lib/osBindings/Celsius.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 Celsius = number +export type Celsius = { value: string; unit: string } diff --git a/sdk/base/lib/osBindings/CifsAddParams.ts b/sdk/base/lib/osBindings/CifsAddParams.ts new file mode 100644 index 000000000..dad0b6bb9 --- /dev/null +++ b/sdk/base/lib/osBindings/CifsAddParams.ts @@ -0,0 +1,8 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type CifsAddParams = { + hostname: string + path: string + username: string + password: string | null +} diff --git a/sdk/base/lib/osBindings/CifsBackupTarget.ts b/sdk/base/lib/osBindings/CifsBackupTarget.ts new file mode 100644 index 000000000..9620e6b52 --- /dev/null +++ b/sdk/base/lib/osBindings/CifsBackupTarget.ts @@ -0,0 +1,10 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { StartOsRecoveryInfo } from './StartOsRecoveryInfo' + +export type CifsBackupTarget = { + hostname: string + path: string + username: string + mountable: boolean + startOs: { [key: string]: StartOsRecoveryInfo } +} diff --git a/sdk/base/lib/osBindings/CifsRemoveParams.ts b/sdk/base/lib/osBindings/CifsRemoveParams.ts new file mode 100644 index 000000000..161a24d80 --- /dev/null +++ b/sdk/base/lib/osBindings/CifsRemoveParams.ts @@ -0,0 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { BackupTargetId } from './BackupTargetId' + +export type CifsRemoveParams = { id: BackupTargetId } diff --git a/sdk/base/lib/osBindings/CifsUpdateParams.ts b/sdk/base/lib/osBindings/CifsUpdateParams.ts new file mode 100644 index 000000000..8529ee51d --- /dev/null +++ b/sdk/base/lib/osBindings/CifsUpdateParams.ts @@ -0,0 +1,10 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { BackupTargetId } from './BackupTargetId' + +export type CifsUpdateParams = { + id: BackupTargetId + hostname: string + path: string + username: string + password: string | null +} diff --git a/sdk/base/lib/osBindings/ClearTaskParams.ts b/sdk/base/lib/osBindings/ClearTaskParams.ts new file mode 100644 index 000000000..6bdc3ae91 --- /dev/null +++ b/sdk/base/lib/osBindings/ClearTaskParams.ts @@ -0,0 +1,9 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { PackageId } from './PackageId' +import type { ReplayId } from './ReplayId' + +export type ClearTaskParams = { + packageId: PackageId + replayId: ReplayId + force: boolean +} diff --git a/sdk/base/lib/osBindings/ControlParams.ts b/sdk/base/lib/osBindings/ControlParams.ts new file mode 100644 index 000000000..7f1a77a0f --- /dev/null +++ b/sdk/base/lib/osBindings/ControlParams.ts @@ -0,0 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { PackageId } from './PackageId' + +export type ControlParams = { id: PackageId } diff --git a/sdk/base/lib/osBindings/EffectsRunActionParams.ts b/sdk/base/lib/osBindings/EffectsRunActionParams.ts new file mode 100644 index 000000000..eb93655ad --- /dev/null +++ b/sdk/base/lib/osBindings/EffectsRunActionParams.ts @@ -0,0 +1,9 @@ +// 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 { PackageId } from './PackageId' + +export type EffectsRunActionParams = { + packageId?: PackageId + actionId: ActionId + input: any +} diff --git a/sdk/base/lib/osBindings/ForgetGatewayParams.ts b/sdk/base/lib/osBindings/ForgetGatewayParams.ts new file mode 100644 index 000000000..ce453bdb2 --- /dev/null +++ b/sdk/base/lib/osBindings/ForgetGatewayParams.ts @@ -0,0 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { GatewayId } from './GatewayId' + +export type ForgetGatewayParams = { gateway: GatewayId } diff --git a/sdk/base/lib/osBindings/GigaBytes.ts b/sdk/base/lib/osBindings/GigaBytes.ts index 9e5e4ed7b..cb2250230 100644 --- a/sdk/base/lib/osBindings/GigaBytes.ts +++ b/sdk/base/lib/osBindings/GigaBytes.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 GigaBytes = number +export type GigaBytes = { value: string; unit: string } diff --git a/sdk/base/lib/osBindings/Host.ts b/sdk/base/lib/osBindings/Host.ts index 3a655acb2..da048ff5f 100644 --- a/sdk/base/lib/osBindings/Host.ts +++ b/sdk/base/lib/osBindings/Host.ts @@ -1,10 +1,15 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { Bindings } from './Bindings' import type { GatewayId } from './GatewayId' +import type { PortForward } from './PortForward' import type { PublicDomainConfig } from './PublicDomainConfig' export type Host = { bindings: Bindings publicDomains: { [key: string]: PublicDomainConfig } privateDomains: { [key: string]: Array } + /** + * COMPUTED: port forwarding rules needed on gateways for public addresses to work. + */ + portForwards: Array } diff --git a/sdk/base/lib/osBindings/Hostname.ts b/sdk/base/lib/osBindings/Hostname.ts new file mode 100644 index 000000000..228fccca7 --- /dev/null +++ b/sdk/base/lib/osBindings/Hostname.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 Hostname = string diff --git a/sdk/base/lib/osBindings/InfoParams.ts b/sdk/base/lib/osBindings/InfoParams.ts new file mode 100644 index 000000000..4e4aa388e --- /dev/null +++ b/sdk/base/lib/osBindings/InfoParams.ts @@ -0,0 +1,8 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { BackupTargetId } from './BackupTargetId' + +export type InfoParams = { + targetId: BackupTargetId + serverId: string + password: string +} diff --git a/sdk/base/lib/osBindings/InitAcmeParams.ts b/sdk/base/lib/osBindings/InitAcmeParams.ts new file mode 100644 index 000000000..38a90e91e --- /dev/null +++ b/sdk/base/lib/osBindings/InitAcmeParams.ts @@ -0,0 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { AcmeProvider } from './AcmeProvider' + +export type InitAcmeParams = { provider: AcmeProvider; contact: Array } diff --git a/sdk/base/lib/osBindings/KillParams.ts b/sdk/base/lib/osBindings/KillParams.ts new file mode 100644 index 000000000..fb0342f24 --- /dev/null +++ b/sdk/base/lib/osBindings/KillParams.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 KillParams = { ids: Array } diff --git a/sdk/base/lib/osBindings/ListNotificationParams.ts b/sdk/base/lib/osBindings/ListNotificationParams.ts new file mode 100644 index 000000000..814b97fc6 --- /dev/null +++ b/sdk/base/lib/osBindings/ListNotificationParams.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. + +export type ListNotificationParams = { + before: number | null + limit: number | null +} diff --git a/sdk/base/lib/osBindings/LogEntry.ts b/sdk/base/lib/osBindings/LogEntry.ts new file mode 100644 index 000000000..b036b428d --- /dev/null +++ b/sdk/base/lib/osBindings/LogEntry.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 LogEntry = { timestamp: string; message: string; bootId: string } diff --git a/sdk/base/lib/osBindings/LogFollowResponse.ts b/sdk/base/lib/osBindings/LogFollowResponse.ts new file mode 100644 index 000000000..503cf414b --- /dev/null +++ b/sdk/base/lib/osBindings/LogFollowResponse.ts @@ -0,0 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { Guid } from './Guid' + +export type LogFollowResponse = { startCursor: string | null; guid: Guid } diff --git a/sdk/base/lib/osBindings/LogResponse.ts b/sdk/base/lib/osBindings/LogResponse.ts new file mode 100644 index 000000000..be282cc8f --- /dev/null +++ b/sdk/base/lib/osBindings/LogResponse.ts @@ -0,0 +1,8 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { LogEntry } from './LogEntry' + +export type LogResponse = { + entries: Array + startCursor: string | null + endCursor: string | null +} diff --git a/sdk/base/lib/osBindings/LogsParams.ts b/sdk/base/lib/osBindings/LogsParams.ts new file mode 100644 index 000000000..529ac06fd --- /dev/null +++ b/sdk/base/lib/osBindings/LogsParams.ts @@ -0,0 +1,8 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type LogsParams = { + limit?: number + cursor?: string + boot?: number | string + before: boolean +} diff --git a/sdk/base/lib/osBindings/MebiBytes.ts b/sdk/base/lib/osBindings/MebiBytes.ts index c10760d23..499aa88e9 100644 --- a/sdk/base/lib/osBindings/MebiBytes.ts +++ b/sdk/base/lib/osBindings/MebiBytes.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 MebiBytes = number +export type MebiBytes = { value: string; unit: string } diff --git a/sdk/base/lib/osBindings/MetricsFollowResponse.ts b/sdk/base/lib/osBindings/MetricsFollowResponse.ts new file mode 100644 index 000000000..f93ca65b6 --- /dev/null +++ b/sdk/base/lib/osBindings/MetricsFollowResponse.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 { Guid } from './Guid' +import type { Metrics } from './Metrics' + +export type MetricsFollowResponse = { guid: Guid; metrics: Metrics } diff --git a/sdk/base/lib/osBindings/ModifyNotificationBeforeParams.ts b/sdk/base/lib/osBindings/ModifyNotificationBeforeParams.ts new file mode 100644 index 000000000..a153b5101 --- /dev/null +++ b/sdk/base/lib/osBindings/ModifyNotificationBeforeParams.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 ModifyNotificationBeforeParams = { before: number } diff --git a/sdk/base/lib/osBindings/ModifyNotificationParams.ts b/sdk/base/lib/osBindings/ModifyNotificationParams.ts new file mode 100644 index 000000000..5e14a76b1 --- /dev/null +++ b/sdk/base/lib/osBindings/ModifyNotificationParams.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 ModifyNotificationParams = { ids: number[] } diff --git a/sdk/base/lib/osBindings/Notification.ts b/sdk/base/lib/osBindings/Notification.ts new file mode 100644 index 000000000..5a4f8c3b8 --- /dev/null +++ b/sdk/base/lib/osBindings/Notification.ts @@ -0,0 +1,14 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { NotificationLevel } from './NotificationLevel' +import type { PackageId } from './PackageId' + +export type Notification = { + packageId: PackageId | null + createdAt: string + code: number + level: NotificationLevel + title: string + message: string + data: any + seen: boolean +} diff --git a/sdk/base/lib/osBindings/NotificationLevel.ts b/sdk/base/lib/osBindings/NotificationLevel.ts new file mode 100644 index 000000000..71110829d --- /dev/null +++ b/sdk/base/lib/osBindings/NotificationLevel.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 NotificationLevel = 'success' | 'info' | 'warning' | 'error' diff --git a/sdk/base/lib/osBindings/NotificationWithId.ts b/sdk/base/lib/osBindings/NotificationWithId.ts new file mode 100644 index 000000000..f61c98079 --- /dev/null +++ b/sdk/base/lib/osBindings/NotificationWithId.ts @@ -0,0 +1,15 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { NotificationLevel } from './NotificationLevel' +import type { PackageId } from './PackageId' + +export type NotificationWithId = { + id: number + packageId: PackageId | null + createdAt: string + code: number + level: NotificationLevel + title: string + message: string + data: any + seen: boolean +} diff --git a/sdk/base/lib/osBindings/PackageBackupInfo.ts b/sdk/base/lib/osBindings/PackageBackupInfo.ts new file mode 100644 index 000000000..51fc7464d --- /dev/null +++ b/sdk/base/lib/osBindings/PackageBackupInfo.ts @@ -0,0 +1,9 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { Version } from './Version' + +export type PackageBackupInfo = { + title: string + version: Version + osVersion: string + timestamp: string +} diff --git a/sdk/base/lib/osBindings/PackageBackupReport.ts b/sdk/base/lib/osBindings/PackageBackupReport.ts new file mode 100644 index 000000000..067655b5f --- /dev/null +++ b/sdk/base/lib/osBindings/PackageBackupReport.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 PackageBackupReport = { error: string | null } diff --git a/sdk/base/lib/osBindings/PartitionInfo.ts b/sdk/base/lib/osBindings/PartitionInfo.ts new file mode 100644 index 000000000..777199c3b --- /dev/null +++ b/sdk/base/lib/osBindings/PartitionInfo.ts @@ -0,0 +1,11 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { StartOsRecoveryInfo } from './StartOsRecoveryInfo' + +export type PartitionInfo = { + logicalname: string + label: string | null + capacity: number + used: number | null + startOs: { [key: string]: StartOsRecoveryInfo } + guid: string | null +} diff --git a/sdk/base/lib/osBindings/Percentage.ts b/sdk/base/lib/osBindings/Percentage.ts index aff21db40..35e7746e4 100644 --- a/sdk/base/lib/osBindings/Percentage.ts +++ b/sdk/base/lib/osBindings/Percentage.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 Percentage = number +export type Percentage = { value: string; unit: string } diff --git a/sdk/base/lib/osBindings/PortForward.ts b/sdk/base/lib/osBindings/PortForward.ts new file mode 100644 index 000000000..c400acdfb --- /dev/null +++ b/sdk/base/lib/osBindings/PortForward.ts @@ -0,0 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { GatewayId } from './GatewayId' + +export type PortForward = { src: string; dst: string; gateway: GatewayId } diff --git a/sdk/base/lib/osBindings/QueryDnsParams.ts b/sdk/base/lib/osBindings/QueryDnsParams.ts new file mode 100644 index 000000000..a232d1cdd --- /dev/null +++ b/sdk/base/lib/osBindings/QueryDnsParams.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 QueryDnsParams = { fqdn: string } diff --git a/sdk/base/lib/osBindings/RebuildParams.ts b/sdk/base/lib/osBindings/RebuildParams.ts new file mode 100644 index 000000000..2a530ab1f --- /dev/null +++ b/sdk/base/lib/osBindings/RebuildParams.ts @@ -0,0 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { PackageId } from './PackageId' + +export type RebuildParams = { id: PackageId } diff --git a/sdk/base/lib/osBindings/RemoveAcmeParams.ts b/sdk/base/lib/osBindings/RemoveAcmeParams.ts new file mode 100644 index 000000000..36d1d1946 --- /dev/null +++ b/sdk/base/lib/osBindings/RemoveAcmeParams.ts @@ -0,0 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { AcmeProvider } from './AcmeProvider' + +export type RemoveAcmeParams = { provider: AcmeProvider } diff --git a/sdk/base/lib/osBindings/RemoveDomainParams.ts b/sdk/base/lib/osBindings/RemoveDomainParams.ts new file mode 100644 index 000000000..91ccf235f --- /dev/null +++ b/sdk/base/lib/osBindings/RemoveDomainParams.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 RemoveDomainParams = { fqdn: string } diff --git a/sdk/base/lib/osBindings/RenameGatewayParams.ts b/sdk/base/lib/osBindings/RenameGatewayParams.ts new file mode 100644 index 000000000..625870299 --- /dev/null +++ b/sdk/base/lib/osBindings/RenameGatewayParams.ts @@ -0,0 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { GatewayId } from './GatewayId' + +export type RenameGatewayParams = { id: GatewayId; name: string } diff --git a/sdk/base/lib/osBindings/ResetPasswordParams.ts b/sdk/base/lib/osBindings/ResetPasswordParams.ts new file mode 100644 index 000000000..750e84a45 --- /dev/null +++ b/sdk/base/lib/osBindings/ResetPasswordParams.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 { PasswordType } from './PasswordType' + +export type ResetPasswordParams = { + oldPassword: PasswordType | null + newPassword: PasswordType | null +} diff --git a/sdk/base/lib/osBindings/RestorePackageParams.ts b/sdk/base/lib/osBindings/RestorePackageParams.ts new file mode 100644 index 000000000..545d3e7ec --- /dev/null +++ b/sdk/base/lib/osBindings/RestorePackageParams.ts @@ -0,0 +1,9 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { BackupTargetId } from './BackupTargetId' +import type { PackageId } from './PackageId' + +export type RestorePackageParams = { + ids: Array + targetId: BackupTargetId + password: string +} diff --git a/sdk/base/lib/osBindings/RunActionParams.ts b/sdk/base/lib/osBindings/RunActionParams.ts index 7dabffce6..66550838e 100644 --- a/sdk/base/lib/osBindings/RunActionParams.ts +++ b/sdk/base/lib/osBindings/RunActionParams.ts @@ -1,9 +1,11 @@ // 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 { Guid } from './Guid' import type { PackageId } from './PackageId' export type RunActionParams = { - packageId?: PackageId + packageId: PackageId + eventId: Guid | null actionId: ActionId - input: any + input?: any } diff --git a/sdk/base/lib/osBindings/ServerBackupReport.ts b/sdk/base/lib/osBindings/ServerBackupReport.ts new file mode 100644 index 000000000..8b8a4d5c6 --- /dev/null +++ b/sdk/base/lib/osBindings/ServerBackupReport.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 ServerBackupReport = { attempted: boolean; error: string | null } diff --git a/sdk/base/lib/osBindings/SetCountryParams.ts b/sdk/base/lib/osBindings/SetCountryParams.ts new file mode 100644 index 000000000..0bd6fc337 --- /dev/null +++ b/sdk/base/lib/osBindings/SetCountryParams.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 SetCountryParams = { country: string } diff --git a/sdk/base/lib/osBindings/SetLanguageParams.ts b/sdk/base/lib/osBindings/SetLanguageParams.ts new file mode 100644 index 000000000..7ed420ee6 --- /dev/null +++ b/sdk/base/lib/osBindings/SetLanguageParams.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 SetLanguageParams = { language: string } diff --git a/sdk/base/lib/osBindings/SetStaticDnsParams.ts b/sdk/base/lib/osBindings/SetStaticDnsParams.ts new file mode 100644 index 000000000..df87b13e1 --- /dev/null +++ b/sdk/base/lib/osBindings/SetStaticDnsParams.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 SetStaticDnsParams = { servers: Array | null } diff --git a/sdk/base/lib/osBindings/SetWifiEnabledParams.ts b/sdk/base/lib/osBindings/SetWifiEnabledParams.ts new file mode 100644 index 000000000..3382e08f2 --- /dev/null +++ b/sdk/base/lib/osBindings/SetWifiEnabledParams.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 SetWifiEnabledParams = { enabled: boolean } diff --git a/sdk/base/lib/osBindings/SideloadParams.ts b/sdk/base/lib/osBindings/SideloadParams.ts new file mode 100644 index 000000000..d7f67746a --- /dev/null +++ b/sdk/base/lib/osBindings/SideloadParams.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 SideloadParams = {} diff --git a/sdk/base/lib/osBindings/SideloadResponse.ts b/sdk/base/lib/osBindings/SideloadResponse.ts new file mode 100644 index 000000000..21f304615 --- /dev/null +++ b/sdk/base/lib/osBindings/SideloadResponse.ts @@ -0,0 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { Guid } from './Guid' + +export type SideloadResponse = { upload: Guid; progress: Guid } diff --git a/sdk/base/lib/osBindings/SignalStrength.ts b/sdk/base/lib/osBindings/SignalStrength.ts new file mode 100644 index 000000000..b7f72309d --- /dev/null +++ b/sdk/base/lib/osBindings/SignalStrength.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. + +/** + * So a signal strength is a number between 0-100, I want the null option to be 0 since there is no signal + */ +export type SignalStrength = number diff --git a/sdk/base/lib/osBindings/SshAddParams.ts b/sdk/base/lib/osBindings/SshAddParams.ts new file mode 100644 index 000000000..a5abbbc3b --- /dev/null +++ b/sdk/base/lib/osBindings/SshAddParams.ts @@ -0,0 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { SshPubKey } from './SshPubKey' + +export type SshAddParams = { key: SshPubKey } diff --git a/sdk/base/lib/osBindings/SshDeleteParams.ts b/sdk/base/lib/osBindings/SshDeleteParams.ts new file mode 100644 index 000000000..fe08546a0 --- /dev/null +++ b/sdk/base/lib/osBindings/SshDeleteParams.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 SshDeleteParams = { fingerprint: string } diff --git a/sdk/base/lib/osBindings/SshKeyResponse.ts b/sdk/base/lib/osBindings/SshKeyResponse.ts new file mode 100644 index 000000000..30d66aa4c --- /dev/null +++ b/sdk/base/lib/osBindings/SshKeyResponse.ts @@ -0,0 +1,8 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type SshKeyResponse = { + alg: string + fingerprint: string + hostname: string + createdAt: string +} diff --git a/sdk/base/lib/osBindings/SshPubKey.ts b/sdk/base/lib/osBindings/SshPubKey.ts new file mode 100644 index 000000000..cbfcae75f --- /dev/null +++ b/sdk/base/lib/osBindings/SshPubKey.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 SshPubKey = string diff --git a/sdk/base/lib/osBindings/Ssid.ts b/sdk/base/lib/osBindings/Ssid.ts new file mode 100644 index 000000000..17bf88f78 --- /dev/null +++ b/sdk/base/lib/osBindings/Ssid.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. + +/** + * Ssid are the names of the wifis, usually human readable. + */ +export type Ssid = string diff --git a/sdk/base/lib/osBindings/StartOsRecoveryInfo.ts b/sdk/base/lib/osBindings/StartOsRecoveryInfo.ts new file mode 100644 index 000000000..0409fa2c4 --- /dev/null +++ b/sdk/base/lib/osBindings/StartOsRecoveryInfo.ts @@ -0,0 +1,10 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { Hostname } from './Hostname' + +export type StartOsRecoveryInfo = { + hostname: Hostname + version: string + timestamp: string + passwordHash: string | null + wrappedKey: string | null +} diff --git a/sdk/base/lib/osBindings/TimeInfo.ts b/sdk/base/lib/osBindings/TimeInfo.ts new file mode 100644 index 000000000..e5429f14e --- /dev/null +++ b/sdk/base/lib/osBindings/TimeInfo.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 TimeInfo = { now: string; uptime: bigint } diff --git a/sdk/base/lib/osBindings/UmountParams.ts b/sdk/base/lib/osBindings/UmountParams.ts new file mode 100644 index 000000000..2923332a7 --- /dev/null +++ b/sdk/base/lib/osBindings/UmountParams.ts @@ -0,0 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { BackupTargetId } from './BackupTargetId' + +export type UmountParams = { targetId: BackupTargetId | null } diff --git a/sdk/base/lib/osBindings/UninstallParams.ts b/sdk/base/lib/osBindings/UninstallParams.ts new file mode 100644 index 000000000..7cc2100aa --- /dev/null +++ b/sdk/base/lib/osBindings/UninstallParams.ts @@ -0,0 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { PackageId } from './PackageId' + +export type UninstallParams = { id: PackageId; soft: boolean; force: boolean } diff --git a/sdk/base/lib/osBindings/WifiAddParams.ts b/sdk/base/lib/osBindings/WifiAddParams.ts new file mode 100644 index 000000000..1dd729b35 --- /dev/null +++ b/sdk/base/lib/osBindings/WifiAddParams.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 WifiAddParams = { ssid: string; password: string } diff --git a/sdk/base/lib/osBindings/WifiListInfo.ts b/sdk/base/lib/osBindings/WifiListInfo.ts new file mode 100644 index 000000000..b1575d40b --- /dev/null +++ b/sdk/base/lib/osBindings/WifiListInfo.ts @@ -0,0 +1,12 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { SignalStrength } from './SignalStrength' +import type { Ssid } from './Ssid' +import type { WifiListOut } from './WifiListOut' + +export type WifiListInfo = { + ssids: { [key: Ssid]: SignalStrength } + connected: Ssid | null + country: string | null + ethernet: boolean + availableWifi: Array +} diff --git a/sdk/base/lib/osBindings/WifiListOut.ts b/sdk/base/lib/osBindings/WifiListOut.ts new file mode 100644 index 000000000..ed5612a0f --- /dev/null +++ b/sdk/base/lib/osBindings/WifiListOut.ts @@ -0,0 +1,9 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { SignalStrength } from './SignalStrength' +import type { Ssid } from './Ssid' + +export type WifiListOut = { + ssid: Ssid + strength: SignalStrength + security: Array +} diff --git a/sdk/base/lib/osBindings/WifiSsidParams.ts b/sdk/base/lib/osBindings/WifiSsidParams.ts new file mode 100644 index 000000000..6dc0a7467 --- /dev/null +++ b/sdk/base/lib/osBindings/WifiSsidParams.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 WifiSsidParams = { ssid: string } diff --git a/sdk/base/lib/osBindings/index.ts b/sdk/base/lib/osBindings/index.ts index 013118267..ae49292ff 100644 --- a/sdk/base/lib/osBindings/index.ts +++ b/sdk/base/lib/osBindings/index.ts @@ -17,6 +17,8 @@ export { AddMirrorParams } from './AddMirrorParams' export { AddPackageParams } from './AddPackageParams' export { AddPackageSignerParams } from './AddPackageSignerParams' export { AddPackageToCategoryParams } from './AddPackageToCategoryParams' +export { AddPrivateDomainParams } from './AddPrivateDomainParams' +export { AddPublicDomainParams } from './AddPublicDomainParams' export { AddressInfo } from './AddressInfo' export { AddSslOptions } from './AddSslOptions' export { AddTunnelParams } from './AddTunnelParams' @@ -31,8 +33,13 @@ export { AnySigningKey } from './AnySigningKey' export { AnyVerifyingKey } from './AnyVerifyingKey' export { ApiState } from './ApiState' export { AttachParams } from './AttachParams' +export { BackupInfo } from './BackupInfo' +export { BackupParams } from './BackupParams' export { BackupProgress } from './BackupProgress' +export { BackupReport } from './BackupReport' export { BackupTargetFS } from './BackupTargetFS' +export { BackupTargetId } from './BackupTargetId' +export { BackupTarget } from './BackupTarget' export { Base64 } from './Base64' export { BindId } from './BindId' export { BindInfo } from './BindInfo' @@ -44,18 +51,25 @@ export { Blake3Commitment } from './Blake3Commitment' export { BlockDev } from './BlockDev' export { BuildArg } from './BuildArg' export { CallbackId } from './CallbackId' +export { CancelInstallParams } from './CancelInstallParams' export { Category } from './Category' export { Celsius } from './Celsius' export { CheckDependenciesParam } from './CheckDependenciesParam' export { CheckDependenciesResult } from './CheckDependenciesResult' +export { CifsAddParams } from './CifsAddParams' +export { CifsBackupTarget } from './CifsBackupTarget' +export { CifsRemoveParams } from './CifsRemoveParams' export { Cifs } from './Cifs' +export { CifsUpdateParams } from './CifsUpdateParams' export { ClearActionsParams } from './ClearActionsParams' export { ClearBindingsParams } from './ClearBindingsParams' export { ClearCallbacksParams } from './ClearCallbacksParams' export { ClearServiceInterfacesParams } from './ClearServiceInterfacesParams' +export { ClearTaskParams } from './ClearTaskParams' export { ClearTasksParams } from './ClearTasksParams' export { CliSetIconParams } from './CliSetIconParams' export { ContactInfo } from './ContactInfo' +export { ControlParams } from './ControlParams' export { CreateSubcontainerFsParams } from './CreateSubcontainerFsParams' export { CreateTaskParams } from './CreateTaskParams' export { CurrentDependencies } from './CurrentDependencies' @@ -75,12 +89,14 @@ export { DomainSettings } from './DomainSettings' export { Duration } from './Duration' export { EchoParams } from './EchoParams' export { EditSignerParams } from './EditSignerParams' +export { EffectsRunActionParams } from './EffectsRunActionParams' export { EncryptedWire } from './EncryptedWire' export { ErrorData } from './ErrorData' export { EventId } from './EventId' export { ExportActionParams } from './ExportActionParams' export { ExportServiceInterfaceParams } from './ExportServiceInterfaceParams' export { FileType } from './FileType' +export { ForgetGatewayParams } from './ForgetGatewayParams' export { FullIndex } from './FullIndex' export { FullProgress } from './FullProgress' export { GatewayId } from './GatewayId' @@ -110,6 +126,7 @@ export { HealthCheckId } from './HealthCheckId' export { HostId } from './HostId' export { HostnameInfo } from './HostnameInfo' export { HostnameMetadata } from './HostnameMetadata' +export { Hostname } from './Hostname' export { Hosts } from './Hosts' export { Host } from './Host' export { IdMap } from './IdMap' @@ -117,6 +134,8 @@ export { ImageConfig } from './ImageConfig' export { ImageId } from './ImageId' export { ImageMetadata } from './ImageMetadata' export { ImageSource } from './ImageSource' +export { InfoParams } from './InfoParams' +export { InitAcmeParams } from './InitAcmeParams' export { InitProgressRes } from './InitProgressRes' export { InstalledState } from './InstalledState' export { InstalledVersionParams } from './InstalledVersionParams' @@ -125,11 +144,17 @@ export { InstallingState } from './InstallingState' export { InstallParams } from './InstallParams' export { IpInfo } from './IpInfo' export { KeyboardOptions } from './KeyboardOptions' +export { KillParams } from './KillParams' +export { ListNotificationParams } from './ListNotificationParams' export { ListPackageSignersParams } from './ListPackageSignersParams' export { ListServiceInterfacesParams } from './ListServiceInterfacesParams' export { ListVersionSignersParams } from './ListVersionSignersParams' export { LocaleString } from './LocaleString' +export { LogEntry } from './LogEntry' +export { LogFollowResponse } from './LogFollowResponse' export { LoginParams } from './LoginParams' +export { LogResponse } from './LogResponse' +export { LogsParams } from './LogsParams' export { LshwDevice } from './LshwDevice' export { LshwDisplay } from './LshwDisplay' export { LshwProcessor } from './LshwProcessor' @@ -141,9 +166,12 @@ export { MetadataSrc } from './MetadataSrc' export { Metadata } from './Metadata' export { MetricsCpu } from './MetricsCpu' export { MetricsDisk } from './MetricsDisk' +export { MetricsFollowResponse } from './MetricsFollowResponse' export { MetricsGeneral } from './MetricsGeneral' export { MetricsMemory } from './MetricsMemory' export { Metrics } from './Metrics' +export { ModifyNotificationBeforeParams } from './ModifyNotificationBeforeParams' +export { ModifyNotificationParams } from './ModifyNotificationParams' export { MountParams } from './MountParams' export { MountTarget } from './MountTarget' export { NamedHealthCheckResult } from './NamedHealthCheckResult' @@ -152,9 +180,14 @@ export { NetInfo } from './NetInfo' export { NetworkInfo } from './NetworkInfo' export { NetworkInterfaceInfo } from './NetworkInterfaceInfo' export { NetworkInterfaceType } from './NetworkInterfaceType' +export { NotificationLevel } from './NotificationLevel' +export { Notification } from './Notification' +export { NotificationWithId } from './NotificationWithId' export { OsIndex } from './OsIndex' export { OsVersionInfoMap } from './OsVersionInfoMap' export { OsVersionInfo } from './OsVersionInfo' +export { PackageBackupInfo } from './PackageBackupInfo' +export { PackageBackupReport } from './PackageBackupReport' export { PackageDataEntry } from './PackageDataEntry' export { PackageDetailLevel } from './PackageDetailLevel' export { PackageId } from './PackageId' @@ -163,30 +196,40 @@ export { PackageInfoShort } from './PackageInfoShort' export { PackageInfo } from './PackageInfo' export { PackageState } from './PackageState' export { PackageVersionInfo } from './PackageVersionInfo' +export { PartitionInfo } from './PartitionInfo' export { PasswordType } from './PasswordType' export { PathOrUrl } from './PathOrUrl' export { Pem } from './Pem' export { Percentage } from './Percentage' +export { PortForward } from './PortForward' export { Progress } from './Progress' export { ProgressUnits } from './ProgressUnits' export { PublicDomainConfig } from './PublicDomainConfig' export { Public } from './Public' +export { QueryDnsParams } from './QueryDnsParams' +export { RebuildParams } from './RebuildParams' export { RecoverySource } from './RecoverySource' export { RegistryAsset } from './RegistryAsset' export { RegistryInfo } from './RegistryInfo' +export { RemoveAcmeParams } from './RemoveAcmeParams' export { RemoveAdminParams } from './RemoveAdminParams' export { RemoveAssetParams } from './RemoveAssetParams' export { RemoveCategoryParams } from './RemoveCategoryParams' +export { RemoveDomainParams } from './RemoveDomainParams' export { RemoveMirrorParams } from './RemoveMirrorParams' export { RemovePackageFromCategoryParams } from './RemovePackageFromCategoryParams' export { RemovePackageParams } from './RemovePackageParams' export { RemovePackageSignerParams } from './RemovePackageSignerParams' export { RemoveTunnelParams } from './RemoveTunnelParams' export { RemoveVersionParams } from './RemoveVersionParams' +export { RenameGatewayParams } from './RenameGatewayParams' export { ReplayId } from './ReplayId' export { RequestCommitment } from './RequestCommitment' +export { ResetPasswordParams } from './ResetPasswordParams' +export { RestorePackageParams } from './RestorePackageParams' export { RunActionParams } from './RunActionParams' export { Security } from './Security' +export { ServerBackupReport } from './ServerBackupReport' export { ServerInfo } from './ServerInfo' export { ServerSpecs } from './ServerSpecs' export { ServerStatus } from './ServerStatus' @@ -196,21 +239,34 @@ export { ServiceInterfaceType } from './ServiceInterfaceType' export { SessionList } from './SessionList' export { Sessions } from './Sessions' export { Session } from './Session' +export { SetCountryParams } from './SetCountryParams' export { SetDataVersionParams } from './SetDataVersionParams' export { SetDependenciesParams } from './SetDependenciesParams' export { SetHealth } from './SetHealth' export { SetIconParams } from './SetIconParams' +export { SetLanguageParams } from './SetLanguageParams' export { SetMainStatusStatus } from './SetMainStatusStatus' export { SetMainStatus } from './SetMainStatus' export { SetNameParams } from './SetNameParams' +export { SetStaticDnsParams } from './SetStaticDnsParams' export { SetupExecuteParams } from './SetupExecuteParams' export { SetupInfo } from './SetupInfo' export { SetupProgress } from './SetupProgress' export { SetupResult } from './SetupResult' export { SetupStatusRes } from './SetupStatusRes' +export { SetWifiEnabledParams } from './SetWifiEnabledParams' +export { SideloadParams } from './SideloadParams' +export { SideloadResponse } from './SideloadResponse' +export { SignalStrength } from './SignalStrength' export { SignAssetParams } from './SignAssetParams' export { SignerInfo } from './SignerInfo' export { SmtpValue } from './SmtpValue' +export { SshAddParams } from './SshAddParams' +export { SshDeleteParams } from './SshDeleteParams' +export { SshKeyResponse } from './SshKeyResponse' +export { SshPubKey } from './SshPubKey' +export { Ssid } from './Ssid' +export { StartOsRecoveryInfo } from './StartOsRecoveryInfo' export { StartStop } from './StartStop' export { StatusInfo } from './StatusInfo' export { TaskCondition } from './TaskCondition' @@ -220,9 +276,16 @@ export { TaskSeverity } from './TaskSeverity' export { TaskTrigger } from './TaskTrigger' export { Task } from './Task' export { TestSmtpParams } from './TestSmtpParams' +export { TimeInfo } from './TimeInfo' +export { UmountParams } from './UmountParams' +export { UninstallParams } from './UninstallParams' export { UpdatingState } from './UpdatingState' export { VerifyCifsParams } from './VerifyCifsParams' export { VersionSignerParams } from './VersionSignerParams' export { Version } from './Version' export { VolumeId } from './VolumeId' +export { WifiAddParams } from './WifiAddParams' export { WifiInfo } from './WifiInfo' +export { WifiListInfo } from './WifiListInfo' +export { WifiListOut } from './WifiListOut' +export { WifiSsidParams } from './WifiSsidParams' diff --git a/sdk/base/lib/osBindings/tunnel/AnyVerifyingKey.ts b/sdk/base/lib/osBindings/tunnel/AnyVerifyingKey.ts index 58a45aaa7..eb9973e82 100644 --- a/sdk/base/lib/osBindings/tunnel/AnyVerifyingKey.ts +++ b/sdk/base/lib/osBindings/tunnel/AnyVerifyingKey.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 AnyVerifyingKey = string +export type AnyVerifyingKey = string; diff --git a/sdk/base/lib/osBindings/tunnel/Base64.ts b/sdk/base/lib/osBindings/tunnel/Base64.ts index 597227fc9..4b19ad7bf 100644 --- a/sdk/base/lib/osBindings/tunnel/Base64.ts +++ b/sdk/base/lib/osBindings/tunnel/Base64.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 Base64 = string +export type Base64 = string; diff --git a/sdk/base/lib/osBindings/tunnel/Pem.ts b/sdk/base/lib/osBindings/tunnel/Pem.ts index 1ec1cd375..f9cfaea8e 100644 --- a/sdk/base/lib/osBindings/tunnel/Pem.ts +++ b/sdk/base/lib/osBindings/tunnel/Pem.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 Pem = string +export type Pem = string; diff --git a/sdk/base/lib/osBindings/tunnel/PortForwards.ts b/sdk/base/lib/osBindings/tunnel/PortForwards.ts index aa9991452..792c6b0c7 100644 --- a/sdk/base/lib/osBindings/tunnel/PortForwards.ts +++ b/sdk/base/lib/osBindings/tunnel/PortForwards.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 PortForwards = { [key: string]: string } +export type PortForwards = { [key: string]: string }; diff --git a/sdk/base/lib/osBindings/tunnel/Session.ts b/sdk/base/lib/osBindings/tunnel/Session.ts index 36ebd2766..cd538f564 100644 --- a/sdk/base/lib/osBindings/tunnel/Session.ts +++ b/sdk/base/lib/osBindings/tunnel/Session.ts @@ -1,7 +1,3 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -export type Session = { - loggedIn: string - lastActive: string - userAgent: string | null -} +export type Session = { loggedIn: string, lastActive: string, userAgent: string | null, }; diff --git a/sdk/base/lib/osBindings/tunnel/Sessions.ts b/sdk/base/lib/osBindings/tunnel/Sessions.ts index 340315855..f6dfcfff7 100644 --- a/sdk/base/lib/osBindings/tunnel/Sessions.ts +++ b/sdk/base/lib/osBindings/tunnel/Sessions.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 { Session } from './Session' +import type { Session } from "./Session"; -export type Sessions = { [key: string]: Session } +export type Sessions = { [key: string]: Session }; diff --git a/sdk/base/lib/osBindings/tunnel/SignerInfo.ts b/sdk/base/lib/osBindings/tunnel/SignerInfo.ts index 76cbdafce..50f34b9e3 100644 --- a/sdk/base/lib/osBindings/tunnel/SignerInfo.ts +++ b/sdk/base/lib/osBindings/tunnel/SignerInfo.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 SignerInfo = { name: string } +export type SignerInfo = { name: string, }; diff --git a/sdk/base/lib/osBindings/tunnel/TunnelCertData.ts b/sdk/base/lib/osBindings/tunnel/TunnelCertData.ts index 8a28ef25c..7fd7d31ef 100644 --- a/sdk/base/lib/osBindings/tunnel/TunnelCertData.ts +++ b/sdk/base/lib/osBindings/tunnel/TunnelCertData.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 { Pem } from './Pem' +import type { Pem } from "./Pem"; -export type TunnelCertData = { key: Pem; cert: Pem } +export type TunnelCertData = { key: Pem, cert: Pem, }; diff --git a/sdk/base/lib/osBindings/tunnel/TunnelDatabase.ts b/sdk/base/lib/osBindings/tunnel/TunnelDatabase.ts index 2f484b5b7..4333d29b6 100644 --- a/sdk/base/lib/osBindings/tunnel/TunnelDatabase.ts +++ b/sdk/base/lib/osBindings/tunnel/TunnelDatabase.ts @@ -1,17 +1,9 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { AnyVerifyingKey } from './AnyVerifyingKey' -import type { PortForwards } from './PortForwards' -import type { Sessions } from './Sessions' -import type { SignerInfo } from './SignerInfo' -import type { WebserverInfo } from './WebserverInfo' -import type { WgServer } from './WgServer' +import type { AnyVerifyingKey } from "./AnyVerifyingKey"; +import type { PortForwards } from "./PortForwards"; +import type { Sessions } from "./Sessions"; +import type { SignerInfo } from "./SignerInfo"; +import type { WebserverInfo } from "./WebserverInfo"; +import type { WgServer } from "./WgServer"; -export type TunnelDatabase = { - webserver: WebserverInfo - sessions: Sessions - password: string | null - authPubkeys: { [key: AnyVerifyingKey]: SignerInfo } - gateways: { [key: AnyVerifyingKey]: SignerInfo } - wg: WgServer - portForwards: PortForwards -} +export type TunnelDatabase = { webserver: WebserverInfo, sessions: Sessions, password: string | null, authPubkeys: { [key: AnyVerifyingKey]: SignerInfo }, gateways: { [key: AnyVerifyingKey]: SignerInfo }, wg: WgServer, portForwards: PortForwards, }; diff --git a/sdk/base/lib/osBindings/tunnel/WebserverInfo.ts b/sdk/base/lib/osBindings/tunnel/WebserverInfo.ts index c5a48ace0..76c0862f4 100644 --- a/sdk/base/lib/osBindings/tunnel/WebserverInfo.ts +++ b/sdk/base/lib/osBindings/tunnel/WebserverInfo.ts @@ -1,8 +1,4 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { TunnelCertData } from './TunnelCertData' +import type { TunnelCertData } from "./TunnelCertData"; -export type WebserverInfo = { - enabled: boolean - listen: string | null - certificate: TunnelCertData | null -} +export type WebserverInfo = { enabled: boolean, listen: string | null, certificate: TunnelCertData | null, }; diff --git a/sdk/base/lib/osBindings/tunnel/WgConfig.ts b/sdk/base/lib/osBindings/tunnel/WgConfig.ts index 4ca18e900..06c27e55b 100644 --- a/sdk/base/lib/osBindings/tunnel/WgConfig.ts +++ b/sdk/base/lib/osBindings/tunnel/WgConfig.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 { Base64 } from './Base64' +import type { Base64 } from "./Base64"; -export type WgConfig = { name: string; key: Base64; psk: Base64 } +export type WgConfig = { name: string, key: Base64, psk: Base64, }; diff --git a/sdk/base/lib/osBindings/tunnel/WgServer.ts b/sdk/base/lib/osBindings/tunnel/WgServer.ts index c6bbb7c9c..f60edf8f3 100644 --- a/sdk/base/lib/osBindings/tunnel/WgServer.ts +++ b/sdk/base/lib/osBindings/tunnel/WgServer.ts @@ -1,5 +1,5 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { Base64 } from './Base64' -import type { WgSubnetMap } from './WgSubnetMap' +import type { Base64 } from "./Base64"; +import type { WgSubnetMap } from "./WgSubnetMap"; -export type WgServer = { port: number; key: Base64; subnets: WgSubnetMap } +export type WgServer = { port: number, key: Base64, subnets: WgSubnetMap, }; diff --git a/sdk/base/lib/osBindings/tunnel/WgSubnetClients.ts b/sdk/base/lib/osBindings/tunnel/WgSubnetClients.ts index 023c51ca5..ad83d5b64 100644 --- a/sdk/base/lib/osBindings/tunnel/WgSubnetClients.ts +++ b/sdk/base/lib/osBindings/tunnel/WgSubnetClients.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 { WgConfig } from './WgConfig' +import type { WgConfig } from "./WgConfig"; -export type WgSubnetClients = { [key: string]: WgConfig } +export type WgSubnetClients = { [key: string]: WgConfig }; diff --git a/sdk/base/lib/osBindings/tunnel/WgSubnetConfig.ts b/sdk/base/lib/osBindings/tunnel/WgSubnetConfig.ts index 37c9af3a1..1606c928f 100644 --- a/sdk/base/lib/osBindings/tunnel/WgSubnetConfig.ts +++ b/sdk/base/lib/osBindings/tunnel/WgSubnetConfig.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 { WgSubnetClients } from './WgSubnetClients' +import type { WgSubnetClients } from "./WgSubnetClients"; -export type WgSubnetConfig = { name: string; clients: WgSubnetClients } +export type WgSubnetConfig = { name: string, clients: WgSubnetClients, }; diff --git a/sdk/base/lib/osBindings/tunnel/WgSubnetMap.ts b/sdk/base/lib/osBindings/tunnel/WgSubnetMap.ts index 8347dcf84..5cf96c79c 100644 --- a/sdk/base/lib/osBindings/tunnel/WgSubnetMap.ts +++ b/sdk/base/lib/osBindings/tunnel/WgSubnetMap.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 { WgSubnetConfig } from './WgSubnetConfig' +import type { WgSubnetConfig } from "./WgSubnetConfig"; -export type WgSubnetMap = { [key: string]: WgSubnetConfig } +export type WgSubnetMap = { [key: string]: WgSubnetConfig }; diff --git a/sdk/base/lib/test/startosTypeValidation.test.ts b/sdk/base/lib/test/startosTypeValidation.test.ts index bcb9f6abb..eede4d669 100644 --- a/sdk/base/lib/test/startosTypeValidation.test.ts +++ b/sdk/base/lib/test/startosTypeValidation.test.ts @@ -10,7 +10,7 @@ import { GetContainerIpParams, GetStatusParams, CreateTaskParams, - RunActionParams, + EffectsRunActionParams, SetDataVersionParams, SetMainStatus, GetServiceManifestParams, @@ -56,7 +56,7 @@ describe('startosTypeValidation ', () => { clear: {} as ClearActionsParams, export: {} as ExportActionParams, getInput: {} as GetActionInputParams, - run: {} as RunActionParams, + run: {} as EffectsRunActionParams, createTask: {} as CreateTaskParams, clearTasks: {} as ClearTasksParams, }, diff --git a/web/ARCHITECTURE.md b/web/ARCHITECTURE.md new file mode 100644 index 000000000..c8cc8becb --- /dev/null +++ b/web/ARCHITECTURE.md @@ -0,0 +1,89 @@ +# Web Architecture + +Angular 20 + TypeScript workspace using [Taiga UI](https://taiga-ui.dev/) component library. + +## API Layer (JSON-RPC) + +All backend communication uses JSON-RPC, not REST. + +- **`HttpService`** (`shared/src/services/http.service.ts`) — Low-level HTTP wrapper. Sends JSON-RPC POST requests via `rpcRequest()`. +- **`ApiService`** (`ui/src/app/services/api/embassy-api.service.ts`) — Abstract class defining 100+ RPC methods. Two implementations: + - `LiveApiService` — Production, calls the real backend + - `MockApiService` — Development with mocks +- **`api.types.ts`** (`ui/src/app/services/api/api.types.ts`) — Namespace `RR` with all request/response type pairs. + +**Calling an RPC endpoint from a component:** + +```typescript +private readonly api = inject(ApiService) + +async doSomething() { + await this.api.someMethod({ param: value }) +} +``` + +The live API handles `x-patch-sequence` headers — after a mutating call, it waits for the PatchDB WebSocket to catch up before resolving. This ensures the UI always reflects the result of the call. + +## PatchDB (Reactive State) + +The backend pushes state diffs to the frontend via WebSocket. This is the primary way components get data. + +- **`PatchDbSource`** (`ui/src/app/services/patch-db/patch-db-source.ts`) — Establishes a WebSocket subscription when authenticated. Buffers updates every 250ms. +- **`DataModel`** (`ui/src/app/services/patch-db/data-model.ts`) — TypeScript type for the full database shape (`ui`, `serverInfo`, `packageData`). +- **`PatchDB`** — Injected service. Use `watch$()` to observe specific paths. + +**Watching data in a component:** + +```typescript +private readonly patch = inject>(PatchDB) + +// Watch a specific path — returns Observable, convert to Signal with toSignal() +readonly name = toSignal(this.patch.watch$('ui', 'name')) +readonly status = toSignal(this.patch.watch$('serverInfo', 'statusInfo')) +readonly packages = toSignal(this.patch.watch$('packageData')) +``` + +**In templates:** `{{ name() }}` — signals are called as functions. + +## WebSockets + +Three WebSocket use cases, all opened via `api.openWebsocket$(guid)`: + +1. **PatchDB** — Continuous state patches (managed by `PatchDbSource`) +2. **Logs** — Streamed via `followServerLogs` / `followPackageLogs`, buffered every 1s +3. **Metrics** — Real-time server metrics via `followServerMetrics` + +## Navigation & Routing + +- **Main app** (`ui/src/app/routing.module.ts`) — NgModule-based with guards (`AuthGuard`, `UnauthGuard`, `stateNot()`), lazy loading via `loadChildren`, `PreloadAllModules`. +- **Portal routes** (`ui/src/app/routes/portal/portal.routes.ts`) — Modern array-based routes with `loadChildren` and `loadComponent`. +- **Setup wizard** (`setup-wizard/src/app/app.routes.ts`) — Standalone `loadComponent()` per step. +- Route config uses `bindToComponentInputs: true` — route params bind directly to component `@Input()`. + +## Forms + +Two patterns: + +1. **Dynamic (spec-driven)** — `FormService` (`ui/src/app/services/form.service.ts`) generates `FormGroup` from IST (Input Specification Type) schemas. Supports text, textarea, number, color, datetime, object, list, union, toggle, select, multiselect, file. Used for service configuration forms. + +2. **Manual** — Standard Angular `FormGroup`/`FormControl` with validators. Used for login, setup wizard, system settings. + +Form controls live in `ui/src/app/routes/portal/components/form/controls/` — each extends a base `Control` class and uses Taiga input components. + +**Dialog-based forms** use `PolymorpheusComponent` + `TuiDialogContext` for modal rendering. + +## i18n + +- **`i18nPipe`** (`shared/src/i18n/i18n.pipe.ts`) — Translates English keys to the active language. +- **Dictionaries** live in `shared/src/i18n/dictionaries/` (en, es, de, fr, pl). +- Usage in templates: `{{ 'Some English Text' | i18n }}` + +## Services & State + +Services often extend `Observable` and expose reactive streams via DI: + +- **`ConnectionService`** — Combines network status + WebSocket readiness +- **`StateService`** — Polls server availability, manages app state (`running`, `initializing`, etc.) +- **`AuthService`** — Tracks `isVerified$`, triggers PatchDB start/stop +- **`PatchMonitorService`** — Starts/stops PatchDB based on auth state +- **`PatchDataService`** — Watches entire DB, updates localStorage bootstrap diff --git a/web/CLAUDE.md b/web/CLAUDE.md index 9f920d3c3..0e33fb3ee 100644 --- a/web/CLAUDE.md +++ b/web/CLAUDE.md @@ -37,98 +37,16 @@ WebFetch url=https://taiga-ui.dev/llms-full.txt prompt="How to use TuiTextfield When implementing something with Taiga, **also check existing code in this project** for local patterns and conventions — Taiga usage here may have project-specific wrappers or style choices. -## Architecture Overview +## Architecture -### API Layer (JSON-RPC) - -All backend communication uses JSON-RPC, not REST. - -- **`HttpService`** (`shared/src/services/http.service.ts`) — Low-level HTTP wrapper. Sends JSON-RPC POST requests via `rpcRequest()`. -- **`ApiService`** (`ui/src/app/services/api/embassy-api.service.ts`) — Abstract class defining 100+ RPC methods. Two implementations: - - `LiveApiService` — Production, calls the real backend - - `MockApiService` — Development with mocks -- **`api.types.ts`** (`ui/src/app/services/api/api.types.ts`) — Namespace `RR` with all request/response type pairs. - -**Calling an RPC endpoint from a component:** -```typescript -private readonly api = inject(ApiService) - -async doSomething() { - await this.api.someMethod({ param: value }) -} -``` - -The live API handles `x-patch-sequence` headers — after a mutating call, it waits for the PatchDB WebSocket to catch up before resolving. This ensures the UI always reflects the result of the call. - -### PatchDB (Reactive State) - -The backend pushes state diffs to the frontend via WebSocket. This is the primary way components get data. - -- **`PatchDbSource`** (`ui/src/app/services/patch-db/patch-db-source.ts`) — Establishes a WebSocket subscription when authenticated. Buffers updates every 250ms. -- **`DataModel`** (`ui/src/app/services/patch-db/data-model.ts`) — TypeScript type for the full database shape (`ui`, `serverInfo`, `packageData`). -- **`PatchDB`** — Injected service. Use `watch$()` to observe specific paths. - -**Watching data in a component:** -```typescript -private readonly patch = inject>(PatchDB) - -// Watch a specific path — returns Observable, convert to Signal with toSignal() -readonly name = toSignal(this.patch.watch$('ui', 'name')) -readonly status = toSignal(this.patch.watch$('serverInfo', 'statusInfo')) -readonly packages = toSignal(this.patch.watch$('packageData')) -``` - -**In templates:** `{{ name() }}` — signals are called as functions. - -### WebSockets - -Three WebSocket use cases, all opened via `api.openWebsocket$(guid)`: - -1. **PatchDB** — Continuous state patches (managed by `PatchDbSource`) -2. **Logs** — Streamed via `followServerLogs` / `followPackageLogs`, buffered every 1s -3. **Metrics** — Real-time server metrics via `followServerMetrics` - -### Navigation & Routing - -- **Main app** (`ui/src/app/routing.module.ts`) — NgModule-based with guards (`AuthGuard`, `UnauthGuard`, `stateNot()`), lazy loading via `loadChildren`, `PreloadAllModules`. -- **Portal routes** (`ui/src/app/routes/portal/portal.routes.ts`) — Modern array-based routes with `loadChildren` and `loadComponent`. -- **Setup wizard** (`setup-wizard/src/app/app.routes.ts`) — Standalone `loadComponent()` per step. -- Route config uses `bindToComponentInputs: true` — route params bind directly to component `@Input()`. - -### Forms - -Two patterns: - -1. **Dynamic (spec-driven)** — `FormService` (`ui/src/app/services/form.service.ts`) generates `FormGroup` from IST (Input Specification Type) schemas. Supports text, textarea, number, color, datetime, object, list, union, toggle, select, multiselect, file. Used for service configuration forms. - -2. **Manual** — Standard Angular `FormGroup`/`FormControl` with validators. Used for login, setup wizard, system settings. - -Form controls live in `ui/src/app/routes/portal/components/form/controls/` — each extends a base `Control` class and uses Taiga input components. - -**Dialog-based forms** use `PolymorpheusComponent` + `TuiDialogContext` for modal rendering. - -### i18n - -- **`i18nPipe`** (`shared/src/i18n/i18n.pipe.ts`) — Translates English keys to the active language. -- **Dictionaries** live in `shared/src/i18n/dictionaries/` (en, es, de, fr, pl). -- Usage in templates: `{{ 'Some English Text' | i18n }}` - -### Services & State - -Services often extend `Observable` and expose reactive streams via DI: - -- **`ConnectionService`** — Combines network status + WebSocket readiness -- **`StateService`** — Polls server availability, manages app state (`running`, `initializing`, etc.) -- **`AuthService`** — Tracks `isVerified$`, triggers PatchDB start/stop -- **`PatchMonitorService`** — Starts/stops PatchDB based on auth state -- **`PatchDataService`** — Watches entire DB, updates localStorage bootstrap +See [ARCHITECTURE.md](ARCHITECTURE.md) for the web architecture: API layer, PatchDB state, WebSockets, routing, forms, i18n, and services. ## Component Conventions - **Standalone components** preferred (no NgModule). Use `imports` array in `@Component`. - **`export default class`** for route components (enables direct `loadComponent` import). - **`inject()`** function for DI (not constructor injection). -- **`signal()`** and `computed()`** for local reactive state. +- **`signal()`** and `computed()`\*\* for local reactive state. - **`toSignal()`** to convert Observables (e.g., PatchDB watches) to signals. - **`ChangeDetectionStrategy.OnPush`** on almost all components. - **`takeUntilDestroyed(inject(DestroyRef))`** for subscription cleanup. @@ -136,6 +54,7 @@ Services often extend `Observable` and expose reactive streams via DI: ## Common Taiga Patterns ### Textfield + Select (dropdown) + ```html @@ -145,12 +64,15 @@ Services often extend `Observable` and expose reactive streams via DI: ``` + Provider to remove the X clear button: + ```typescript providers: [tuiTextfieldOptionsProvider({ cleaner: signal(false) })] ``` ### Buttons + ```html @@ -158,6 +80,7 @@ providers: [tuiTextfieldOptionsProvider({ cleaner: signal(false) })] ``` ### Dialogs + ```typescript // Confirmation this.dialog.openConfirm({ label: 'Warning', data: { content: '...', yes: 'Confirm', no: 'Cancel' } }) @@ -167,17 +90,20 @@ this.dialog.openComponent(new PolymorpheusComponent(MyComponent, injector), { la ``` ### Toggle + ```html ``` ### Errors & Tooltips + ```html ``` ### Layout + ```html diff --git a/web/package-lock.json b/web/package-lock.json index bc8bf06e4..cc14bb785 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -867,6 +867,7 @@ "integrity": "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", @@ -8041,6 +8042,7 @@ "integrity": "sha512-SL0JY3DaxylDuo/MecFeiC+7pedM0zia33zl0vcjgwcq1q1FWWF1To9EIauPbl8GbMCU0R2e0uJ8bZunhYKD2g==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "cli-truncate": "^4.0.0", "colorette": "^2.0.20", @@ -11910,6 +11912,7 @@ "integrity": "sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", @@ -12217,24 +12220,6 @@ "dev": true, "license": "ISC" }, - "node_modules/yaml": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", - "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true, - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } - }, "node_modules/yargs": { "version": "18.0.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", diff --git a/web/projects/setup-wizard/src/app/services/api.service.ts b/web/projects/setup-wizard/src/app/services/api.service.ts index b11aa86a5..733b2be60 100644 --- a/web/projects/setup-wizard/src/app/services/api.service.ts +++ b/web/projects/setup-wizard/src/app/services/api.service.ts @@ -1,7 +1,6 @@ import * as jose from 'node-jose' import { DiskInfo, - FollowLogsRes, FullKeyboard, SetLanguageParams, StartOSDiskInfo, @@ -49,7 +48,7 @@ export abstract class ApiService { abstract shutdown(): Promise // setup.shutdown // Logs & Progress - abstract initFollowLogs(): Promise // setup.logs.follow + abstract initFollowLogs(): Promise // setup.logs.follow abstract openWebsocket$(guid: string): Observable // Restart (for error recovery) diff --git a/web/projects/setup-wizard/src/app/services/live-api.service.ts b/web/projects/setup-wizard/src/app/services/live-api.service.ts index 42c306d50..6504cf544 100644 --- a/web/projects/setup-wizard/src/app/services/live-api.service.ts +++ b/web/projects/setup-wizard/src/app/services/live-api.service.ts @@ -2,7 +2,6 @@ import { Inject, Injectable, DOCUMENT } from '@angular/core' import { DiskInfo, encodeBase64, - FollowLogsRes, FullKeyboard, HttpService, isRpcError, @@ -124,7 +123,7 @@ export class LiveApiService extends ApiService { } async initFollowLogs() { - return this.rpcRequest({ + return this.rpcRequest({ method: 'setup.logs.follow', params: {}, }) diff --git a/web/projects/setup-wizard/src/app/services/mock-api.service.ts b/web/projects/setup-wizard/src/app/services/mock-api.service.ts index b94f9fda3..ff2c57a14 100644 --- a/web/projects/setup-wizard/src/app/services/mock-api.service.ts +++ b/web/projects/setup-wizard/src/app/services/mock-api.service.ts @@ -2,7 +2,6 @@ import { Injectable } from '@angular/core' import { DiskInfo, encodeBase64, - FollowLogsRes, FullKeyboard, pauseFor, SetLanguageParams, @@ -166,7 +165,7 @@ export class MockApiService extends ApiService { } } - async initFollowLogs(): Promise { + async initFollowLogs(): Promise { await pauseFor(500) return { startCursor: 'fakestartcursor', diff --git a/web/projects/shared/src/services/setup-logs.service.ts b/web/projects/shared/src/services/setup-logs.service.ts index 412930369..4b91c69af 100644 --- a/web/projects/shared/src/services/setup-logs.service.ts +++ b/web/projects/shared/src/services/setup-logs.service.ts @@ -12,13 +12,13 @@ import { switchMap, timer, } from 'rxjs' -import { FollowLogsReq, FollowLogsRes, Log } from '../types/api' +import { T } from '@start9labs/start-sdk' import { Constructor } from '../types/constructor' import { convertAnsi } from '../util/convert-ansi' interface Api { - initFollowLogs: (params: FollowLogsReq) => Promise - openWebsocket$: (guid: string) => Observable + initFollowLogs: (params: {}) => Promise + openWebsocket$: (guid: string) => Observable } export function provideSetupLogsService( diff --git a/web/projects/shared/src/types/api.ts b/web/projects/shared/src/types/api.ts index 5a621d489..2a938533f 100644 --- a/web/projects/shared/src/types/api.ts +++ b/web/projects/shared/src/types/api.ts @@ -1,27 +1,3 @@ -export type FollowLogsReq = {} -export type FollowLogsRes = { - startCursor: string - guid: string -} - -export type FetchLogsReq = { - before: boolean - cursor?: string - limit?: number -} - -export type FetchLogsRes = { - entries: Log[] - startCursor?: string - endCursor?: string -} - -export interface Log { - timestamp: string - message: string - bootId: string -} - export type DiskListResponse = DiskInfo[] export interface DiskInfo { diff --git a/web/projects/shared/src/util/convert-ansi.ts b/web/projects/shared/src/util/convert-ansi.ts index f38a97a39..9b598beea 100644 --- a/web/projects/shared/src/util/convert-ansi.ts +++ b/web/projects/shared/src/util/convert-ansi.ts @@ -1,4 +1,4 @@ -import { Log } from '../types/api' +import { T } from '@start9labs/start-sdk' import { toLocalIsoString } from './to-local-iso-string' import Convert from 'ansi-to-html' @@ -8,7 +8,7 @@ const CONVERT = new Convert({ escapeXML: true, }) -export function convertAnsi(entries: readonly Log[]): string { +export function convertAnsi(entries: readonly T.LogEntry[]): string { return entries .map( ({ timestamp, message }) => diff --git a/web/projects/ui/src/app/components/backup-report.component.ts b/web/projects/ui/src/app/components/backup-report.component.ts index 84aaaf141..ffb629ba1 100644 --- a/web/projects/ui/src/app/components/backup-report.component.ts +++ b/web/projects/ui/src/app/components/backup-report.component.ts @@ -12,7 +12,7 @@ import { TuiCell } from '@taiga-ui/layout' import { injectContext, PolymorpheusComponent } from '@taiga-ui/polymorpheus' import { PatchDB } from 'patch-db-client' import { map } from 'rxjs' -import { BackupReport } from 'src/app/services/api/api.types' +import { T } from '@start9labs/start-sdk' import { getManifest } from '../utils/get-package-data' import { DataModel } from '../services/patch-db/data-model' @@ -60,7 +60,7 @@ export class BackupsReportModal { readonly data = injectContext< - TuiDialogContext + TuiDialogContext >().data readonly pkgTitles = toSignal( diff --git a/web/projects/ui/src/app/routes/diagnostic/logs.component.ts b/web/projects/ui/src/app/routes/diagnostic/logs.component.ts index 8682d48dc..7ba7b8e06 100644 --- a/web/projects/ui/src/app/routes/diagnostic/logs.component.ts +++ b/web/projects/ui/src/app/routes/diagnostic/logs.component.ts @@ -69,7 +69,7 @@ export default class LogsPage implements OnInit { private readonly api = inject(ApiService) private readonly errorService = inject(ErrorService) - startCursor?: string + startCursor?: string | null loading = false logs: string[] = [] scrollTop = 0 @@ -98,7 +98,7 @@ export default class LogsPage implements OnInit { try { const response = await this.api.diagnosticGetLogs({ - cursor: this.startCursor, + cursor: this.startCursor ?? undefined, before: !!this.startCursor, limit: 200, }) diff --git a/web/projects/ui/src/app/routes/portal/components/interfaces/addresses/addresses.component.ts b/web/projects/ui/src/app/routes/portal/components/interfaces/addresses/addresses.component.ts index a1804c53f..18ebfed59 100644 --- a/web/projects/ui/src/app/routes/portal/components/interfaces/addresses/addresses.component.ts +++ b/web/projects/ui/src/app/routes/portal/components/interfaces/addresses/addresses.component.ts @@ -216,17 +216,19 @@ export class InterfaceAddressesComponent { private async savePrivateDomain(fqdn: string): Promise { const iface = this.value() + const gatewayId = this.gatewayGroup().gatewayId const loader = this.loader.open('Saving').subscribe() try { if (this.packageId()) { await this.api.pkgAddPrivateDomain({ fqdn, + gateway: gatewayId, package: this.packageId(), host: iface?.addressInfo.hostId || '', }) } else { - await this.api.osUiAddPrivateDomain({ fqdn }) + await this.api.osUiAddPrivateDomain({ fqdn, gateway: gatewayId }) } return true } catch (e: any) { diff --git a/web/projects/ui/src/app/routes/portal/components/logs/logs-download.directive.ts b/web/projects/ui/src/app/routes/portal/components/logs/logs-download.directive.ts index 997f1283b..addabce0f 100644 --- a/web/projects/ui/src/app/routes/portal/components/logs/logs-download.directive.ts +++ b/web/projects/ui/src/app/routes/portal/components/logs/logs-download.directive.ts @@ -3,10 +3,9 @@ import { convertAnsi, DownloadHTMLService, ErrorService, - FetchLogsReq, - FetchLogsRes, LoadingService, } from '@start9labs/shared' +import { T } from '@start9labs/start-sdk' import { LogsComponent } from './logs.component' @Directive({ @@ -19,7 +18,7 @@ export class LogsDownloadDirective { private readonly downloadHtml = inject(DownloadHTMLService) @Input({ required: true }) - logsDownload!: (params: FetchLogsReq) => Promise + logsDownload!: (params: T.LogsParams) => Promise @HostListener('click') async download() { diff --git a/web/projects/ui/src/app/routes/portal/components/logs/logs-fetch.directive.ts b/web/projects/ui/src/app/routes/portal/components/logs/logs-fetch.directive.ts index 04a7c718a..99fd09f86 100644 --- a/web/projects/ui/src/app/routes/portal/components/logs/logs-fetch.directive.ts +++ b/web/projects/ui/src/app/routes/portal/components/logs/logs-fetch.directive.ts @@ -18,7 +18,7 @@ export class LogsFetchDirective { switchMap(() => from( this.component.fetchLogs({ - cursor: this.component.startCursor, + cursor: this.component.startCursor ?? undefined, before: true, limit: 400, }), diff --git a/web/projects/ui/src/app/routes/portal/components/logs/logs.component.ts b/web/projects/ui/src/app/routes/portal/components/logs/logs.component.ts index ee700cbda..4cde692b2 100644 --- a/web/projects/ui/src/app/routes/portal/components/logs/logs.component.ts +++ b/web/projects/ui/src/app/routes/portal/components/logs/logs.component.ts @@ -5,11 +5,12 @@ import { WaIntersectionObserver, } from '@ng-web-apis/intersection-observer' import { WaMutationObserver } from '@ng-web-apis/mutation-observer' -import { FetchLogsReq, FetchLogsRes, i18nPipe } from '@start9labs/shared' +import { i18nPipe } from '@start9labs/shared' +import { T } from '@start9labs/start-sdk' import { TuiButton, TuiLoader, TuiScrollbar } from '@taiga-ui/core' import { NgDompurifyPipe } from '@taiga-ui/dompurify' import { BehaviorSubject } from 'rxjs' -import { RR } from 'src/app/services/api/api.types' +import { FollowServerLogsReq } from 'src/app/services/api/api.types' import { LogsDownloadDirective } from './logs-download.directive' import { LogsFetchDirective } from './logs-fetch.directive' import { LogsPipe } from './logs.pipe' @@ -41,17 +42,17 @@ export class LogsComponent { private readonly scrollbar?: ElementRef @Input({ required: true }) followLogs!: ( - params: RR.FollowServerLogsReq, - ) => Promise + params: FollowServerLogsReq, + ) => Promise @Input({ required: true }) fetchLogs!: ( - params: FetchLogsReq, - ) => Promise + params: T.LogsParams, + ) => Promise @Input({ required: true }) context!: string scrollTop = 0 - startCursor?: string + startCursor?: string | null scroll = true loading = false previous: readonly string[] = [] diff --git a/web/projects/ui/src/app/routes/portal/components/logs/logs.pipe.ts b/web/projects/ui/src/app/routes/portal/components/logs/logs.pipe.ts index b8c3ad8da..233579826 100644 --- a/web/projects/ui/src/app/routes/portal/components/logs/logs.pipe.ts +++ b/web/projects/ui/src/app/routes/portal/components/logs/logs.pipe.ts @@ -1,10 +1,6 @@ import { inject, Pipe, PipeTransform } from '@angular/core' -import { - convertAnsi, - i18nPipe, - Log, - toLocalIsoString, -} from '@start9labs/shared' +import { convertAnsi, i18nPipe, toLocalIsoString } from '@start9labs/shared' +import { T } from '@start9labs/start-sdk' import { bufferTime, catchError, @@ -25,7 +21,7 @@ import { take, tap, } from 'rxjs' -import { RR } from 'src/app/services/api/api.types' +import { FollowServerLogsReq } from 'src/app/services/api/api.types' import { ApiService } from 'src/app/services/api/embassy-api.service' import { ConnectionService } from 'src/app/services/connection.service' import { LogsComponent } from './logs.component' @@ -40,9 +36,7 @@ export class LogsPipe implements PipeTransform { private readonly i18n = inject(i18nPipe) transform( - followLogs: ( - params: RR.FollowServerLogsReq, - ) => Promise, + followLogs: (params: FollowServerLogsReq) => Promise, ): Observable { return merge( this.logs.status$.pipe( @@ -53,7 +47,7 @@ export class LogsPipe implements PipeTransform { defer(() => followLogs(this.options)).pipe( tap(r => this.logs.setCursor(r.startCursor)), switchMap(r => - this.api.openWebsocket$(r.guid, { + this.api.openWebsocket$(r.guid, { openObserver: { next: () => this.logs.status$.next('connected'), }, diff --git a/web/projects/ui/src/app/routes/portal/routes/backups/components/targets.component.ts b/web/projects/ui/src/app/routes/portal/routes/backups/components/targets.component.ts index 33423f4bd..75fe0b257 100644 --- a/web/projects/ui/src/app/routes/portal/routes/backups/components/targets.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/backups/components/targets.component.ts @@ -15,7 +15,7 @@ import { } from '@taiga-ui/core' import { TuiConfirmData, TUI_CONFIRM, TuiSkeleton } from '@taiga-ui/kit' import { filter, map, Subject, switchMap } from 'rxjs' -import { BackupTarget } from 'src/app/services/api/api.types' +import { T } from '@start9labs/start-sdk' import { GetBackupIconPipe } from '../pipes/get-backup-icon.pipe' @Component({ @@ -140,7 +140,7 @@ export class BackupsTargetsComponent { readonly delete$ = new Subject() @Input() - backupsTargets: Record | null = null + backupsTargets: Record | null = null @Output() readonly update = new EventEmitter() diff --git a/web/projects/ui/src/app/routes/portal/routes/backups/modals/edit.component.ts b/web/projects/ui/src/app/routes/portal/routes/backups/modals/edit.component.ts index fc55acf35..ef86c11da 100644 --- a/web/projects/ui/src/app/routes/portal/routes/backups/modals/edit.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/backups/modals/edit.component.ts @@ -11,7 +11,8 @@ import { import { TuiBadge, TuiSwitch } from '@taiga-ui/kit' import { injectContext, PolymorpheusComponent } from '@taiga-ui/polymorpheus' import { from, map } from 'rxjs' -import { BackupJob, BackupTarget } from 'src/app/services/api/api.types' +import { T } from '@start9labs/start-sdk' +import { BackupJob } from 'src/app/services/api/api.types' import { ApiService } from 'src/app/services/api/embassy-api.service' import { ToHumanCronPipe } from '../pipes/to-human-cron.pipe' import { BackupJobBuilder } from '../utils/job-builder' @@ -149,7 +150,7 @@ export class BackupsEditModal { selectTarget() { this.dialogs - .open(TARGET, TARGET_CREATE) + .open(TARGET, TARGET_CREATE) .subscribe(({ id }) => { this.job.targetId = id }) diff --git a/web/projects/ui/src/app/routes/portal/routes/backups/modals/recover.component.ts b/web/projects/ui/src/app/routes/portal/routes/backups/modals/recover.component.ts index 96e237d44..11beba750 100644 --- a/web/projects/ui/src/app/routes/portal/routes/backups/modals/recover.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/backups/modals/recover.component.ts @@ -8,7 +8,7 @@ import { TuiBlock, TuiCheckbox } from '@taiga-ui/kit' import { injectContext, PolymorpheusComponent } from '@taiga-ui/polymorpheus' import { PatchDB } from 'patch-db-client' import { take } from 'rxjs' -import { PackageBackupInfo } from 'src/app/services/api/api.types' +import { T } from '@start9labs/start-sdk' import { ApiService } from 'src/app/services/api/embassy-api.service' import { DataModel } from 'src/app/services/patch-db/data-model' import { ToOptionsPipe } from '../pipes/to-options.pipe' @@ -98,7 +98,7 @@ export class BackupsRecoverModal { } } - get backups(): Record { + get backups(): Record { return this.context.data.backupInfo.packageBackups } @@ -110,13 +110,12 @@ export class BackupsRecoverModal { const ids = options.filter(({ checked }) => !!checked).map(({ id }) => id) const loader = this.loader.open('Initializing').subscribe() - const { targetId, serverId, password } = this.context.data + const { targetId, password } = this.context.data try { await this.api.restorePackages({ ids, targetId, - serverId, password, }) diff --git a/web/projects/ui/src/app/routes/portal/routes/backups/modals/target.component.ts b/web/projects/ui/src/app/routes/portal/routes/backups/modals/target.component.ts index f39d9b51d..b6db19285 100644 --- a/web/projects/ui/src/app/routes/portal/routes/backups/modals/target.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/backups/modals/target.component.ts @@ -6,7 +6,7 @@ import { signal, } from '@angular/core' import { ErrorService, Exver } from '@start9labs/shared' -import { Version } from '@start9labs/start-sdk' +import { T, Version } from '@start9labs/start-sdk' import { TuiButton, TuiDialogContext, @@ -19,7 +19,6 @@ import { import { TuiCell } from '@taiga-ui/layout' import { injectContext, PolymorpheusComponent } from '@taiga-ui/polymorpheus' import { PatchDB } from 'patch-db-client' -import { BackupTarget } from 'src/app/services/api/api.types' import { ApiService } from 'src/app/services/api/embassy-api.service' import { DataModel } from 'src/app/services/patch-db/data-model' import { getServerInfo } from 'src/app/utils/get-server-info' @@ -81,7 +80,7 @@ export class BackupsTargetModal { readonly context = injectContext< - TuiDialogContext + TuiDialogContext >() readonly loading = signal(true) @@ -91,7 +90,7 @@ export class BackupsTargetModal { : 'Loading Backup Sources' serverId = '' - targets: Record = {} + targets: Record = {} async ngOnInit() { try { @@ -104,14 +103,14 @@ export class BackupsTargetModal { } } - isDisabled(target: BackupTarget): boolean { + isDisabled(target: T.BackupTarget): boolean { return ( !target.mountable || (this.context.data.type === 'restore' && !this.hasBackup(target)) ) } - hasBackup(target: BackupTarget): boolean { + hasBackup(target: T.BackupTarget): boolean { return ( target.startOs?.[this.serverId] && Version.parse(target.startOs[this.serverId].version).compare( @@ -127,7 +126,7 @@ export class BackupsTargetModal { .subscribe() } - select(target: BackupTarget, id: string) { + select(target: T.BackupTarget, id: string) { this.context.completeWith({ ...target, id }) } } diff --git a/web/projects/ui/src/app/routes/portal/routes/backups/modals/targets.component.ts b/web/projects/ui/src/app/routes/portal/routes/backups/modals/targets.component.ts index 07f96b917..a0fd73bfa 100644 --- a/web/projects/ui/src/app/routes/portal/routes/backups/modals/targets.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/backups/modals/targets.component.ts @@ -3,8 +3,8 @@ import { ErrorService, LoadingService } from '@start9labs/shared' import { TuiButton, TuiLink, TuiNotification } from '@taiga-ui/core' import { PolymorpheusComponent } from '@taiga-ui/polymorpheus' import { FormComponent } from 'src/app/routes/portal/components/form.component' +import { T } from '@start9labs/start-sdk' import { - BackupTarget, BackupTargetType, RR, UnknownDisk, @@ -188,7 +188,7 @@ export class BackupsTargetsModal implements OnInit { } private async add( - type: BackupTargetType, + type: T.BackupTargetType, value: | RR.AddCifsBackupTargetReq | RR.AddCloudBackupTargetReq @@ -204,7 +204,7 @@ export class BackupsTargetsModal implements OnInit { } private async update( - type: BackupTargetType, + type: T.BackupTargetType, value: | RR.UpdateCifsBackupTargetReq | RR.UpdateCloudBackupTargetReq @@ -220,13 +220,13 @@ export class BackupsTargetsModal implements OnInit { } private setTargets( - saved: Record = this.targets()?.saved || {}, + saved: Record = this.targets()?.saved || {}, unknownDisks: UnknownDisk[] = this.targets()?.unknownDisks || [], ) { this.targets.set({ unknownDisks, saved }) } - private async getSpec(target: BackupTarget) { + private async getSpec(target: T.BackupTarget) { switch (target.type) { case 'cifs': return await configBuilderToSpec(cifsSpec) diff --git a/web/projects/ui/src/app/routes/portal/routes/backups/pipes/get-display-info.pipe.ts b/web/projects/ui/src/app/routes/portal/routes/backups/pipes/get-display-info.pipe.ts index c1f2ae345..83a718bc3 100644 --- a/web/projects/ui/src/app/routes/portal/routes/backups/pipes/get-display-info.pipe.ts +++ b/web/projects/ui/src/app/routes/portal/routes/backups/pipes/get-display-info.pipe.ts @@ -1,5 +1,5 @@ import { Pipe, PipeTransform } from '@angular/core' -import { BackupTarget } from 'src/app/services/api/api.types' +import { T } from '@start9labs/start-sdk' import { DisplayInfo } from '../types/display-info' import { GetBackupIconPipe } from './get-backup-icon.pipe' @@ -9,7 +9,7 @@ import { GetBackupIconPipe } from './get-backup-icon.pipe' export class GetDisplayInfoPipe implements PipeTransform { readonly icon = new GetBackupIconPipe() - transform(target: BackupTarget): DisplayInfo { + transform(target: T.BackupTarget): DisplayInfo { const result = { name: target.name, path: `Path: ${target.path}`, diff --git a/web/projects/ui/src/app/routes/portal/routes/backups/pipes/has-error.pipe.ts b/web/projects/ui/src/app/routes/portal/routes/backups/pipes/has-error.pipe.ts index 32bc938e7..15cc3d516 100644 --- a/web/projects/ui/src/app/routes/portal/routes/backups/pipes/has-error.pipe.ts +++ b/web/projects/ui/src/app/routes/portal/routes/backups/pipes/has-error.pipe.ts @@ -1,11 +1,11 @@ import { Pipe, PipeTransform } from '@angular/core' -import { BackupReport } from 'src/app/services/api/api.types' +import { T } from '@start9labs/start-sdk' @Pipe({ name: 'hasError', }) export class HasErrorPipe implements PipeTransform { - transform(report: BackupReport): boolean { + transform(report: T.BackupReport): boolean { return ( !!report.server.error || !!Object.values(report.packages).find(({ error }) => error) diff --git a/web/projects/ui/src/app/routes/portal/routes/backups/pipes/to-options.pipe.ts b/web/projects/ui/src/app/routes/portal/routes/backups/pipes/to-options.pipe.ts index b33e8b678..2d1796b74 100644 --- a/web/projects/ui/src/app/routes/portal/routes/backups/pipes/to-options.pipe.ts +++ b/web/projects/ui/src/app/routes/portal/routes/backups/pipes/to-options.pipe.ts @@ -1,10 +1,9 @@ import { inject, Pipe, PipeTransform } from '@angular/core' import { map, Observable } from 'rxjs' -import { PackageBackupInfo } from 'src/app/services/api/api.types' +import { T, Version } from '@start9labs/start-sdk' import { ConfigService } from 'src/app/services/config.service' import { PackageDataEntry } from 'src/app/services/patch-db/data-model' import { RecoverOption } from '../types/recover-option' -import { Version } from '@start9labs/start-sdk' @Pipe({ name: 'toOptions', @@ -14,7 +13,7 @@ export class ToOptionsPipe implements PipeTransform { transform( packageData$: Observable>, - packageBackups: Record = {}, + packageBackups: Record = {}, ): Observable { return packageData$.pipe( map(packageData => diff --git a/web/projects/ui/src/app/routes/portal/routes/backups/services/create.service.ts b/web/projects/ui/src/app/routes/portal/routes/backups/services/create.service.ts index 8561552e7..74a85dee7 100644 --- a/web/projects/ui/src/app/routes/portal/routes/backups/services/create.service.ts +++ b/web/projects/ui/src/app/routes/portal/routes/backups/services/create.service.ts @@ -2,7 +2,7 @@ import { inject, Injectable } from '@angular/core' import { LoadingService } from '@start9labs/shared' import { TuiDialogOptions, TuiDialogService } from '@taiga-ui/core' import { from, switchMap } from 'rxjs' -import { BackupTarget } from 'src/app/services/api/api.types' +import { T } from '@start9labs/start-sdk' import { ApiService } from 'src/app/services/api/embassy-api.service' import { TARGET, TARGET_CREATE } from '../modals/target.component' import { BACKUP, BACKUP_OPTIONS } from '../modals/backup.component' @@ -17,7 +17,7 @@ export class BackupsCreateService { readonly handle = () => { this.dialogs - .open(TARGET, TARGET_CREATE) + .open(TARGET, TARGET_CREATE) .pipe( switchMap(({ id }) => this.dialogs diff --git a/web/projects/ui/src/app/routes/portal/routes/backups/services/restore.service.ts b/web/projects/ui/src/app/routes/portal/routes/backups/services/restore.service.ts index 8dfde95aa..4d1c7a4dc 100644 --- a/web/projects/ui/src/app/routes/portal/routes/backups/services/restore.service.ts +++ b/web/projects/ui/src/app/routes/portal/routes/backups/services/restore.service.ts @@ -22,7 +22,7 @@ import { PROMPT, PromptOptions, } from 'src/app/routes/portal/modals/prompt.component' -import { BackupTarget } from 'src/app/services/api/api.types' +import { T } from '@start9labs/start-sdk' import { ApiService } from 'src/app/services/api/embassy-api.service' import { RECOVER } from '../modals/recover.component' import { SERVERS } from '../modals/servers.component' @@ -41,7 +41,7 @@ export class BackupsRestoreService { readonly handle = () => { this.dialogs - .open(TARGET, TARGET_RESTORE) + .open(TARGET, TARGET_RESTORE) .pipe( switchMap(target => this.dialogs diff --git a/web/projects/ui/src/app/routes/portal/routes/backups/types/recover-data.ts b/web/projects/ui/src/app/routes/portal/routes/backups/types/recover-data.ts index 71103a0c3..2063555bc 100644 --- a/web/projects/ui/src/app/routes/portal/routes/backups/types/recover-data.ts +++ b/web/projects/ui/src/app/routes/portal/routes/backups/types/recover-data.ts @@ -1,8 +1,8 @@ -import { BackupInfo } from 'src/app/services/api/api.types' +import { T } from '@start9labs/start-sdk' export interface RecoverData { targetId: string serverId: string - backupInfo: BackupInfo + backupInfo: T.BackupInfo password: string } diff --git a/web/projects/ui/src/app/routes/portal/routes/backups/types/recover-option.ts b/web/projects/ui/src/app/routes/portal/routes/backups/types/recover-option.ts index 89ba8557b..75cb0fc29 100644 --- a/web/projects/ui/src/app/routes/portal/routes/backups/types/recover-option.ts +++ b/web/projects/ui/src/app/routes/portal/routes/backups/types/recover-option.ts @@ -1,6 +1,6 @@ -import { PackageBackupInfo } from 'src/app/services/api/api.types' +import { T } from '@start9labs/start-sdk' -export interface RecoverOption extends PackageBackupInfo { +export interface RecoverOption extends T.PackageBackupInfo { id: string checked: boolean installed: boolean diff --git a/web/projects/ui/src/app/routes/portal/routes/backups/utils/job-builder.ts b/web/projects/ui/src/app/routes/portal/routes/backups/utils/job-builder.ts index 78e99b03c..dac07545d 100644 --- a/web/projects/ui/src/app/routes/portal/routes/backups/utils/job-builder.ts +++ b/web/projects/ui/src/app/routes/portal/routes/backups/utils/job-builder.ts @@ -1,4 +1,5 @@ -import { BackupJob, BackupTarget, RR } from 'src/app/services/api/api.types' +import { T } from '@start9labs/start-sdk' +import { BackupJob, RR } from 'src/app/services/api/api.types' export class BackupJobBuilder { name: string diff --git a/web/projects/ui/src/app/routes/portal/routes/logs/routes/kernel.component.ts b/web/projects/ui/src/app/routes/portal/routes/logs/routes/kernel.component.ts index c4509dc28..a78666946 100644 --- a/web/projects/ui/src/app/routes/portal/routes/logs/routes/kernel.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/logs/routes/kernel.component.ts @@ -1,7 +1,8 @@ import { ChangeDetectionStrategy, Component, inject } from '@angular/core' import { i18nPipe } from '@start9labs/shared' +import { T } from '@start9labs/start-sdk' import { LogsComponent } from 'src/app/routes/portal/components/logs/logs.component' -import { RR } from 'src/app/services/api/api.types' +import { FollowServerLogsReq } from 'src/app/services/api/api.types' import { ApiService } from 'src/app/services/api/embassy-api.service' import { LogsHeaderComponent } from '../components/header.component' @@ -24,9 +25,9 @@ import { LogsHeaderComponent } from '../components/header.component' export default class SystemKernelComponent { private readonly api = inject(ApiService) - protected readonly follow = (params: RR.FollowServerLogsReq) => + protected readonly follow = (params: FollowServerLogsReq) => this.api.followKernelLogs(params) - protected readonly fetch = (params: RR.GetServerLogsReq) => + protected readonly fetch = (params: T.LogsParams) => this.api.getKernelLogs(params) } diff --git a/web/projects/ui/src/app/routes/portal/routes/logs/routes/os.component.ts b/web/projects/ui/src/app/routes/portal/routes/logs/routes/os.component.ts index 37d270c35..b5cebb3e6 100644 --- a/web/projects/ui/src/app/routes/portal/routes/logs/routes/os.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/logs/routes/os.component.ts @@ -1,8 +1,9 @@ import { ChangeDetectionStrategy, Component, inject } from '@angular/core' import { i18nPipe } from '@start9labs/shared' +import { T } from '@start9labs/start-sdk' import { LogsComponent } from 'src/app/routes/portal/components/logs/logs.component' import { LogsHeaderComponent } from 'src/app/routes/portal/routes/logs/components/header.component' -import { RR } from 'src/app/services/api/api.types' +import { FollowServerLogsReq } from 'src/app/services/api/api.types' import { ApiService } from 'src/app/services/api/embassy-api.service' @Component({ @@ -24,9 +25,9 @@ import { ApiService } from 'src/app/services/api/embassy-api.service' export default class SystemOSComponent { private readonly api = inject(ApiService) - protected readonly follow = (params: RR.FollowServerLogsReq) => + protected readonly follow = (params: FollowServerLogsReq) => this.api.followServerLogs(params) - protected readonly fetch = (params: RR.GetServerLogsReq) => + protected readonly fetch = (params: T.LogsParams) => this.api.getServerLogs(params) } diff --git a/web/projects/ui/src/app/routes/portal/routes/metrics/cpu.component.ts b/web/projects/ui/src/app/routes/portal/routes/metrics/cpu.component.ts index 13ff85603..11ca3a6d1 100644 --- a/web/projects/ui/src/app/routes/portal/routes/metrics/cpu.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/metrics/cpu.component.ts @@ -4,7 +4,7 @@ import { computed, input, } from '@angular/core' -import { ServerMetrics } from 'src/app/services/api/api.types' +import { T } from '@start9labs/start-sdk' import { DataComponent } from './data.component' import { i18nKey } from '@start9labs/shared' @@ -86,7 +86,7 @@ const LABELS: Record = { imports: [DataComponent], }) export class CpuComponent { - readonly value = input() + readonly value = input() readonly transform = computed( (value = this.value()?.percentageUsed?.value || '0') => diff --git a/web/projects/ui/src/app/routes/portal/routes/metrics/data.component.ts b/web/projects/ui/src/app/routes/portal/routes/metrics/data.component.ts index a2aacc1cc..7a6b0c988 100644 --- a/web/projects/ui/src/app/routes/portal/routes/metrics/data.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/metrics/data.component.ts @@ -6,7 +6,7 @@ import { } from '@angular/core' import { TuiTitle } from '@taiga-ui/core' import { TuiCell } from '@taiga-ui/layout' -import { ServerMetrics } from 'src/app/services/api/api.types' +import { T } from '@start9labs/start-sdk' import { ValuePipe } from './value.pipe' import { i18nKey, i18nPipe } from '@start9labs/shared' @@ -43,8 +43,8 @@ import { i18nKey, i18nPipe } from '@start9labs/shared' changeDetection: ChangeDetectionStrategy.OnPush, imports: [TuiCell, TuiTitle, ValuePipe, i18nPipe], }) -export class DataComponent { - readonly labels = input.required>() - readonly value = input() - readonly keys = computed(() => Object.keys(this.labels()) as Array) +export class DataComponent { + readonly labels = input.required>() + readonly value = input() + readonly keys = computed(() => Object.keys(this.labels()) as Array) } diff --git a/web/projects/ui/src/app/routes/portal/routes/metrics/memory.component.ts b/web/projects/ui/src/app/routes/portal/routes/metrics/memory.component.ts index 382ecd0df..2e35215c8 100644 --- a/web/projects/ui/src/app/routes/portal/routes/metrics/memory.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/metrics/memory.component.ts @@ -5,7 +5,7 @@ import { input, } from '@angular/core' import { TuiProgress } from '@taiga-ui/kit' -import { ServerMetrics } from 'src/app/services/api/api.types' +import { T } from '@start9labs/start-sdk' import { DataComponent } from './data.component' import { ValuePipe } from './value.pipe' import { i18nKey } from '@start9labs/shared' @@ -40,7 +40,7 @@ const LABELS: Record = { imports: [DataComponent, TuiProgress, ValuePipe], }) export class MemoryComponent { - readonly value = input() + readonly value = input() readonly used = computed( (value = this.value()?.percentageUsed.value || '0') => diff --git a/web/projects/ui/src/app/routes/portal/routes/metrics/metrics.service.ts b/web/projects/ui/src/app/routes/portal/routes/metrics/metrics.service.ts index dfc0c33a7..fd7a43655 100644 --- a/web/projects/ui/src/app/routes/portal/routes/metrics/metrics.service.ts +++ b/web/projects/ui/src/app/routes/portal/routes/metrics/metrics.service.ts @@ -13,14 +13,14 @@ import { take, tap, } from 'rxjs' -import { ServerMetrics } from 'src/app/services/api/api.types' +import { T } from '@start9labs/start-sdk' import { ApiService } from 'src/app/services/api/embassy-api.service' import { ConnectionService } from 'src/app/services/connection.service' @Injectable({ providedIn: 'root', }) -export class MetricsService extends Observable { +export class MetricsService extends Observable { private readonly connection = inject(ConnectionService) private readonly api = inject(ApiService) @@ -28,7 +28,7 @@ export class MetricsService extends Observable { this.api.followServerMetrics({}), ).pipe( switchMap(({ guid, metrics }) => - this.api.openWebsocket$(guid).pipe(startWith(metrics)), + this.api.openWebsocket$(guid).pipe(startWith(metrics)), ), catchError(() => this.connection.pipe(filter(Boolean), take(1), ignoreElements()), diff --git a/web/projects/ui/src/app/routes/portal/routes/metrics/storage.component.ts b/web/projects/ui/src/app/routes/portal/routes/metrics/storage.component.ts index a761553dc..2849dc342 100644 --- a/web/projects/ui/src/app/routes/portal/routes/metrics/storage.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/metrics/storage.component.ts @@ -5,7 +5,7 @@ import { input, } from '@angular/core' import { TuiProgress } from '@taiga-ui/kit' -import { ServerMetrics } from 'src/app/services/api/api.types' +import { T } from '@start9labs/start-sdk' import { DataComponent } from './data.component' import { i18nKey } from '@start9labs/shared' @@ -41,7 +41,7 @@ const LABELS: Record = { imports: [TuiProgress, DataComponent], }) export class StorageComponent { - readonly value = input() + readonly value = input() readonly used = computed( ( diff --git a/web/projects/ui/src/app/routes/portal/routes/notifications/notifications.component.ts b/web/projects/ui/src/app/routes/portal/routes/notifications/notifications.component.ts index c112eff8e..b343c077f 100644 --- a/web/projects/ui/src/app/routes/portal/routes/notifications/notifications.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/notifications/notifications.component.ts @@ -17,11 +17,8 @@ import { import { TuiButton } from '@taiga-ui/core' import { filter } from 'rxjs' import { distinctUntilChanged, skip } from 'rxjs/operators' -import { - RR, - ServerNotification, - ServerNotifications, -} from 'src/app/services/api/api.types' +import { T } from '@start9labs/start-sdk' +import { ServerNotification } from 'src/app/services/api/api.types' import { ApiService } from 'src/app/services/api/embassy-api.service' import { BadgeService } from 'src/app/services/badge.service' import { NotificationService } from 'src/app/services/notification.service' @@ -66,7 +63,7 @@ export default class NotificationsComponent implements OnInit { readonly service = inject(NotificationService) readonly api = inject(ApiService) readonly errorService = inject(ErrorService) - readonly notifications = signal(null) + readonly notifications = signal(null) protected readonly table = viewChild< NotificationsTableComponent> @@ -92,7 +89,7 @@ export default class NotificationsComponent implements OnInit { }) } - async getMore(params: RR.GetNotificationsReq) { + async getMore(params: T.ListNotificationParams) { try { this.notifications.set(null) this.notifications.set(await this.api.getNotifications(params)) @@ -101,7 +98,7 @@ export default class NotificationsComponent implements OnInit { } } - async remove(all: ServerNotifications) { + async remove(all: T.NotificationWithId[]) { const ids = this.table() ?.selected() @@ -119,7 +116,7 @@ export default class NotificationsComponent implements OnInit { } private init() { - this.getMore({}).then(() => { + this.getMore({ before: null, limit: null }).then(() => { const latest = this.notifications()?.at(0) if (latest) { this.service.markSeenAll(latest.id) diff --git a/web/projects/ui/src/app/routes/portal/routes/services/components/task.component.ts b/web/projects/ui/src/app/routes/portal/routes/services/components/task.component.ts index 5f9f91767..1d445c856 100644 --- a/web/projects/ui/src/app/routes/portal/routes/services/components/task.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/services/components/task.component.ts @@ -144,7 +144,7 @@ export class ServiceTaskComponent { .subscribe(async () => { const loader = this.loader.open().subscribe() try { - await this.api.clearTask({ packageId, replayId }) + await this.api.clearTask({ packageId, replayId, force: false }) } catch (e: any) { this.errorService.handleError(e) } finally { diff --git a/web/projects/ui/src/app/routes/portal/routes/services/modals/action-success/types.ts b/web/projects/ui/src/app/routes/portal/routes/services/modals/action-success/types.ts index efc515195..f8fa355e2 100644 --- a/web/projects/ui/src/app/routes/portal/routes/services/modals/action-success/types.ts +++ b/web/projects/ui/src/app/routes/portal/routes/services/modals/action-success/types.ts @@ -1,6 +1,6 @@ -import { RR } from 'src/app/services/api/api.types' +import { ActionRes } from 'src/app/services/api/api.types' -type ActionResponse = NonNullable +type ActionResponse = NonNullable type ActionResult = NonNullable export type ActionResponseWithResult = ActionResponse & { result: ActionResult } export type SingleResult = ActionResult & { type: 'single' } diff --git a/web/projects/ui/src/app/routes/portal/routes/services/routes/logs.component.ts b/web/projects/ui/src/app/routes/portal/routes/services/routes/logs.component.ts index 6172b9576..90fbfac1c 100644 --- a/web/projects/ui/src/app/routes/portal/routes/services/routes/logs.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/services/routes/logs.component.ts @@ -1,7 +1,8 @@ import { ChangeDetectionStrategy, Component, inject } from '@angular/core' import { getPkgId } from '@start9labs/shared' +import { T } from '@start9labs/start-sdk' import { LogsComponent } from 'src/app/routes/portal/components/logs/logs.component' -import { RR } from 'src/app/services/api/api.types' +import { FollowServerLogsReq } from 'src/app/services/api/api.types' import { ApiService } from 'src/app/services/api/embassy-api.service' @Component({ @@ -24,9 +25,9 @@ export default class ServiceLogsRoute { readonly id = getPkgId() - readonly follow = async (params: RR.FollowServerLogsReq) => + readonly follow = async (params: FollowServerLogsReq) => this.api.followPackageLogs({ id: this.id, ...params }) - readonly fetch = async (params: RR.GetServerLogsReq) => + readonly fetch = async (params: T.LogsParams) => this.api.getPackageLogs({ id: this.id, ...params }) } diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/backups/backup.service.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/backups/backup.service.ts index 4e36dc59c..71ed62a7a 100644 --- a/web/projects/ui/src/app/routes/portal/routes/system/routes/backups/backup.service.ts +++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/backups/backup.service.ts @@ -1,8 +1,7 @@ import { inject, Injectable, signal } from '@angular/core' import { ErrorService, getErrorMessage } from '@start9labs/shared' -import { Version } from '@start9labs/start-sdk' +import { T, Version } from '@start9labs/start-sdk' import { - BackupTarget, CifsBackupTarget, DiskBackupTarget, } from 'src/app/services/api/api.types' @@ -61,13 +60,13 @@ export class BackupService { } } - hasAnyBackup({ startOs }: BackupTarget): boolean { + hasAnyBackup({ startOs }: T.BackupTarget): boolean { return Object.values(startOs).some( s => Version.parse(s.version).compare(Version.parse('0.3.6')) !== 'less', ) } - hasThisBackup({ startOs }: BackupTarget, id: string): boolean { + hasThisBackup({ startOs }: T.BackupTarget, id: string): boolean { const item = startOs[id] return ( diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/backups/backup.types.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/backups/backup.types.ts index 38d8ff65a..75de9104e 100644 --- a/web/projects/ui/src/app/routes/portal/routes/system/routes/backups/backup.types.ts +++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/backups/backup.types.ts @@ -1,9 +1,8 @@ +import { T } from '@start9labs/start-sdk' import { TuiDialogContext } from '@taiga-ui/core' import { - BackupInfo, CifsBackupTarget, DiskBackupTarget, - PackageBackupInfo, } from 'src/app/services/api/api.types' import { MappedBackupTarget } from './backup.service' @@ -12,7 +11,7 @@ export type BackupContext = TuiDialogContext< MappedBackupTarget > -export interface RecoverOption extends PackageBackupInfo { +export interface RecoverOption extends T.PackageBackupInfo { id: string checked: boolean installed: boolean @@ -22,6 +21,6 @@ export interface RecoverOption extends PackageBackupInfo { export interface RecoverData { targetId: string serverId: string - backupInfo: BackupInfo + backupInfo: T.BackupInfo password: string } diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/backups/network.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/backups/network.component.ts index ef1b61114..2e874d8d0 100644 --- a/web/projects/ui/src/app/routes/portal/routes/system/routes/backups/network.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/backups/network.component.ts @@ -11,14 +11,14 @@ import { i18nPipe, LoadingService, } from '@start9labs/shared' -import { ISB } from '@start9labs/start-sdk' +import { ISB, T } from '@start9labs/start-sdk' import { TuiButton, TuiIcon } from '@taiga-ui/core' import { TuiTooltip } from '@taiga-ui/kit' import { filter } from 'rxjs' import { FormComponent } from 'src/app/routes/portal/components/form.component' import { PlaceholderComponent } from 'src/app/routes/portal/components/placeholder.component' import { TableComponent } from 'src/app/routes/portal/components/table.component' -import { CifsBackupTarget, RR } from 'src/app/services/api/api.types' +import { CifsBackupTarget } from 'src/app/services/api/api.types' import { ApiService } from 'src/app/services/api/embassy-api.service' import { FormDialogService } from 'src/app/services/form-dialog.service' import { configBuilderToSpec } from 'src/app/utils/configBuilderToSpec' @@ -211,7 +211,7 @@ export class BackupNetworkComponent { buttons: [ { text: this.i18n.transform('Connect'), - handler: (value: RR.AddBackupTargetReq) => this.addTarget(value), + handler: (value: T.CifsAddParams) => this.addTarget(value), }, ], }, @@ -226,7 +226,7 @@ export class BackupNetworkComponent { buttons: [ { text: this.i18n.transform('Connect'), - handler: async (value: RR.AddBackupTargetReq) => { + handler: async (value: T.CifsAddParams) => { const loader = this.loader .open('Testing connectivity to shared folder') .subscribe() @@ -272,7 +272,7 @@ export class BackupNetworkComponent { }) } - private async addTarget(v: RR.AddBackupTargetReq): Promise { + private async addTarget(v: T.CifsAddParams): Promise { const loader = this.loader .open('Testing connectivity to shared folder') .subscribe() diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/backups/recover.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/backups/recover.component.ts index df937a1e1..c98464756 100644 --- a/web/projects/ui/src/app/routes/portal/routes/system/routes/backups/recover.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/backups/recover.component.ts @@ -148,8 +148,8 @@ export class BackupsRecoverComponent { async restore(options: RecoverOption[]): Promise { const ids = options.filter(({ checked }) => !!checked).map(({ id }) => id) - const { targetId, serverId, password } = this.context.data - const params = { ids, targetId, serverId, password } + const { targetId, password } = this.context.data + const params = { ids, targetId, password } const loader = this.loader.open('Initializing').subscribe() try { diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/email/email.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/email/email.component.ts index 8d6777beb..114f487d6 100644 --- a/web/projects/ui/src/app/routes/portal/routes/system/routes/email/email.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/email/email.component.ts @@ -181,7 +181,11 @@ export default class SystemEmailComponent { `${this.i18n.transform('A test email has been sent to')} ${this.testAddress}. ${this.i18n.transform('Check your spam folder and mark as not spam.')}` as i18nKey try { - await this.api.testSmtp({ to: this.testAddress, ...value }) + await this.api.testSmtp({ + ...value, + password: value.password || '', + to: this.testAddress, + }) this.dialog .openAlert(success, { label: 'Success', size: 's' }) .subscribe() diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/gateways/gateways.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/gateways/gateways.component.ts index 254e40f54..6c5484d6f 100644 --- a/web/projects/ui/src/app/routes/portal/routes/system/routes/gateways/gateways.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/gateways/gateways.component.ts @@ -134,6 +134,7 @@ export default class GatewaysComponent { input.config.selection === 'paste' ? input.config.value.file : await (input.config.value.file as any as File).text(), + type: null, // @TODO Aiden why is attr here? setAsDefaultOutbound: input.setAsDefaultOutbound, }) return true diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/sessions/sessions.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/sessions/sessions.component.ts index 35977c2c4..7ff4d0026 100644 --- a/web/projects/ui/src/app/routes/portal/routes/system/routes/sessions/sessions.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/sessions/sessions.component.ts @@ -7,9 +7,9 @@ import { } from '@angular/core' import { RouterLink } from '@angular/router' import { ErrorService, i18nPipe, LoadingService } from '@start9labs/shared' +import { T } from '@start9labs/start-sdk' import { TuiButton } from '@taiga-ui/core' import { from, map, merge, Observable, Subject } from 'rxjs' -import { Session } from 'src/app/services/api/api.types' import { ApiService } from 'src/app/services/api/embassy-api.service' import { TitleDirective } from 'src/app/services/title.service' import { SessionsTableComponent } from './table.component' @@ -72,7 +72,7 @@ export default class SystemSessionsComponent { readonly current$ = this.sessions$.pipe( map(s => { - const current = s.sessions[s.current] + const current = s.current ? s.sessions[s.current] : undefined return current ? [current] : [] }), @@ -115,6 +115,6 @@ export default class SystemSessionsComponent { } } -interface SessionWithId extends Session { +interface SessionWithId extends T.Session { id: string } diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/sessions/table.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/sessions/table.component.ts index 32f467eb9..ed7eb92bf 100644 --- a/web/projects/ui/src/app/routes/portal/routes/system/routes/sessions/table.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/sessions/table.component.ts @@ -11,7 +11,7 @@ import { FormsModule } from '@angular/forms' import { TuiIcon } from '@taiga-ui/core' import { TuiCheckbox, TuiFade, TuiSkeleton } from '@taiga-ui/kit' import { TableComponent } from 'src/app/routes/portal/components/table.component' -import { Session } from 'src/app/services/api/api.types' +import { T } from '@start9labs/start-sdk' import { PlatformInfoPipe } from './platform-info.pipe' import { i18nPipe } from '@start9labs/shared' @@ -165,11 +165,11 @@ import { i18nPipe } from '@start9labs/shared' i18nPipe, ], }) -export class SessionsTableComponent implements OnChanges { - readonly sessions = input(null) +export class SessionsTableComponent implements OnChanges { + readonly sessions = input(null) readonly single = input(false) - readonly selected = signal([]) + readonly selected = signal([]) readonly all = computed( () => !!this.selected()?.length && @@ -180,7 +180,7 @@ export class SessionsTableComponent implements OnChanges { this.selected.set([]) } - onToggle(session: T) { + onToggle(session: S) { if (this.selected().includes(session)) { this.selected.update(selected => selected.filter(s => s !== session)) } else { diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/ssh/ssh.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/ssh/ssh.component.ts index 853258973..565916acc 100644 --- a/web/projects/ui/src/app/routes/portal/routes/system/routes/ssh/ssh.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/ssh/ssh.component.ts @@ -13,11 +13,10 @@ import { i18nPipe, LoadingService, } from '@start9labs/shared' -import { ISB } from '@start9labs/start-sdk' +import { ISB, T } from '@start9labs/start-sdk' import { TuiButton, TuiHint } from '@taiga-ui/core' import { filter, from, merge, Subject } from 'rxjs' import { FormComponent } from 'src/app/routes/portal/components/form.component' -import { SSHKey } from 'src/app/services/api/api.types' import { ApiService } from 'src/app/services/api/embassy-api.service' import { FormDialogService } from 'src/app/services/form-dialog.service' import { TitleDirective } from 'src/app/services/title.service' @@ -101,13 +100,13 @@ export default class SystemSSHComponent { private readonly i18n = inject(i18nPipe) private readonly dialogs = inject(DialogService) - private readonly local$ = new Subject() + private readonly local$ = new Subject() readonly keys$ = merge(from(this.api.getSshKeys({})), this.local$) - protected tableKeys = viewChild>('table') + protected tableKeys = viewChild>('table') - async add(all: readonly SSHKey[]) { + async add(all: readonly T.SshKeyResponse[]) { const spec = ISB.InputSpec.of({ key: ISB.Value.text({ name: this.i18n.transform('Public Key'), @@ -150,7 +149,7 @@ export default class SystemSSHComponent { }) } - remove(all: readonly SSHKey[]) { + remove(all: readonly T.SshKeyResponse[]) { this.dialogs .openConfirm({ label: 'Are you sure?', size: 's' }) .pipe(filter(Boolean)) diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/ssh/table.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/ssh/table.component.ts index b6723c245..d7c09ed2d 100644 --- a/web/projects/ui/src/app/routes/portal/routes/system/routes/ssh/table.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/ssh/table.component.ts @@ -11,7 +11,7 @@ import { FormsModule } from '@angular/forms' import { i18nPipe } from '@start9labs/shared' import { TuiCheckbox, TuiFade, TuiSkeleton } from '@taiga-ui/kit' import { TableComponent } from 'src/app/routes/portal/components/table.component' -import { SSHKey } from 'src/app/services/api/api.types' +import { T } from '@start9labs/start-sdk' @Component({ selector: '[keys]', @@ -151,10 +151,12 @@ import { SSHKey } from 'src/app/services/api/api.types' i18nPipe, ], }) -export class SSHTableComponent implements OnChanges { - readonly keys = input(null) +export class SSHTableComponent< + K extends T.SshKeyResponse, +> implements OnChanges { + readonly keys = input(null) - readonly selected = signal([]) + readonly selected = signal([]) readonly all = computed( () => !!this.selected()?.length && @@ -165,7 +167,7 @@ export class SSHTableComponent implements OnChanges { this.selected.set([]) } - onToggle(key: T) { + onToggle(key: K) { if (this.selected().includes(key)) { this.selected.update(selected => selected.filter(s => s !== key)) } else { diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/wifi/utils.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/wifi/utils.ts index 8f3fadd2e..7ada0635f 100644 --- a/web/projects/ui/src/app/routes/portal/routes/system/routes/wifi/utils.ts +++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/wifi/utils.ts @@ -1,12 +1,11 @@ -import { AvailableWifi } from 'src/app/services/api/api.types' -import { RR } from 'src/app/services/api/api.types' +import { T } from '@start9labs/start-sdk' export interface WiFiForm { ssid: string password: string } -export interface Wifi extends AvailableWifi { +export interface Wifi extends T.WifiListOut { readonly connected?: boolean } @@ -15,7 +14,7 @@ export interface WifiData { available: readonly Wifi[] } -export function parseWifi(res: RR.GetWifiRes): WifiData { +export function parseWifi(res: T.WifiListInfo): WifiData { return { available: res.availableWifi, known: Object.entries(res.ssids).map(([ssid, strength]) => ({ diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/wifi/wifi.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/wifi/wifi.component.ts index 056bdbedd..a2c0dffe8 100644 --- a/web/projects/ui/src/app/routes/portal/routes/system/routes/wifi/wifi.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/wifi/wifi.component.ts @@ -148,7 +148,7 @@ export default class SystemWifiComponent { .subscribe() try { - await this.api.enableWifi({ enable }) + await this.api.enableWifi({ enabled: enable }) } catch (e: any) { this.errorService.handleError(e) } finally { @@ -187,9 +187,8 @@ export default class SystemWifiComponent { await this.api.addWifi({ ssid, password, - priority: 0, - connect: true, }) + await this.api.connectWifi({ ssid }) } else { await this.api.connectWifi({ ssid }) } @@ -263,8 +262,6 @@ export default class SystemWifiComponent { await this.api.addWifi({ ssid, password, - priority: 0, - connect: false, }) wifi.known = wifi.known.concat({ ssid, diff --git a/web/projects/ui/src/app/services/action.service.ts b/web/projects/ui/src/app/services/action.service.ts index f5b4b6340..439635590 100644 --- a/web/projects/ui/src/app/services/action.service.ts +++ b/web/projects/ui/src/app/services/action.service.ts @@ -64,9 +64,9 @@ export class ActionService { try { const res = await this.api.runAction({ packageId, - eventId, actionId, input: input ?? null, + eventId, }) if (!res) return 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 dae769a7e..6fbe16920 100644 --- a/web/projects/ui/src/app/services/api/api.fixures.ts +++ b/web/projects/ui/src/app/services/api/api.fixures.ts @@ -2,9 +2,8 @@ import { InstalledState, PackageDataEntry, } from 'src/app/services/patch-db/data-model' -import { RR, ServerMetrics, ServerNotifications } from './api.types' +import { ActionRes } from './api.types' import { BTC_ICON, LND_ICON, PROXY_ICON, REGISTRY_ICON } from './api-icons' -import { Log } from '@start9labs/shared' import { configBuilderToSpec } from 'src/app/utils/configBuilderToSpec' import { T, ISB, IST } from '@start9labs/start-sdk' import { GetPackagesRes } from '@start9labs/marketplace' @@ -30,7 +29,7 @@ export namespace Mock { shuttingDown: false, } - export const RegistryOSUpdate: RR.CheckOsUpdateRes = { + export const RegistryOSUpdate: T.OsVersionInfoMap = { '0.4.1': { headline: 'v0.4.1', releaseNotes: 'Testing some release notes', @@ -899,7 +898,7 @@ export namespace Mock { }, } - export const Notifications: ServerNotifications = [ + export const Notifications: T.NotificationWithId[] = [ { id: 1, packageId: null, @@ -974,7 +973,7 @@ export namespace Mock { }, ] - export function getMetrics(): ServerMetrics { + export function getMetrics(): T.Metrics { return { general: { temperature: { @@ -1055,7 +1054,7 @@ export namespace Mock { } } - export const ServerLogs: Log[] = [ + export const ServerLogs: T.LogEntry[] = [ { timestamp: '2022-07-28T03:52:54.808769Z', message: '****** START *****', @@ -1079,7 +1078,7 @@ export namespace Mock { }, ] - export const Sessions: RR.GetSessionsRes = { + export const Sessions: T.SessionList = { current: 'b7b1a9cef4284f00af9e9dda6e676177', sessions: { '9513226517c54ddd8107d6d7b9d8aed7': { @@ -1101,7 +1100,7 @@ export namespace Mock { }, } - export const SshKeys: RR.GetSSHKeysRes = [ + export const SshKeys: T.SshKeyResponse[] = [ { createdAt: new Date().toISOString(), alg: 'ed25519', @@ -1116,14 +1115,14 @@ export namespace Mock { }, ] - export const SshKey: RR.AddSSHKeyRes = { + export const SshKey: T.SshKeyResponse = { createdAt: new Date().toISOString(), alg: 'ed25519', hostname: 'Lucy Key', fingerprint: '44:44:7e:78:61:b4:bf:g2:de:24:15:96:4e:d4:15:53', } - export const Wifi: RR.GetWifiRes = { + export const Wifi: T.WifiListInfo = { ethernet: true, ssids: { Goosers: 50, @@ -1150,7 +1149,7 @@ export namespace Mock { ], } - export const BackupTargets: RR.GetBackupTargetsRes = { + export const BackupTargets: { [id: string]: T.BackupTarget } = { hsbdjhasbasda: { type: 'cifs', hostname: 'smb://192.169.10.0', @@ -1195,6 +1194,7 @@ export namespace Mock { used: 100000000000, model: null, vendor: 'SSK', + guid: null, startOs: { '1234-5678-9876-5432': { hostname: 'adjective-noun', @@ -1338,7 +1338,7 @@ export namespace Mock { // }, // ] - export const BackupInfo: RR.GetBackupInfoRes = { + export const BackupInfo: T.BackupInfo = { version: '0.3.6', timestamp: new Date().toISOString(), packageBackups: { @@ -1357,7 +1357,7 @@ export namespace Mock { }, } - export const ActionResMessage: RR.ActionRes = { + export const ActionResMessage: ActionRes = { version: '1', title: 'New Password', message: @@ -1365,7 +1365,7 @@ export namespace Mock { result: null, } - export const ActionResSingle: RR.ActionRes = { + export const ActionResSingle: ActionRes = { version: '1', title: 'New Password', message: @@ -1379,7 +1379,7 @@ export namespace Mock { }, } - export const ActionResGroup: RR.ActionRes = { + export const ActionResGroup: ActionRes = { version: '1', title: 'Properties', message: @@ -2180,6 +2180,7 @@ export namespace Mock { }, publicDomains: {}, privateDomains: {}, + portForwards: [], }, bcdefgh: { bindings: { @@ -2203,6 +2204,7 @@ export namespace Mock { }, publicDomains: {}, privateDomains: {}, + portForwards: [], }, cdefghi: { bindings: { @@ -2226,6 +2228,7 @@ export namespace Mock { }, publicDomains: {}, privateDomains: {}, + portForwards: [], }, }, storeExposedDependents: [], 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 9e682d5e5..815364b93 100644 --- a/web/projects/ui/src/app/services/api/api.types.ts +++ b/web/projects/ui/src/app/services/api/api.types.ts @@ -1,521 +1,99 @@ -import { Dump } from 'patch-db-client' -import { DataModel } from 'src/app/services/patch-db/data-model' -import { - FetchLogsReq, - FetchLogsRes, - FullKeyboard, - SetLanguageParams, - StartOSDiskInfo, -} from '@start9labs/shared' import { IST, T } from '@start9labs/start-sdk' import { WebSocketSubjectConfig } from 'rxjs/webSocket' -import { - GetPackageReq, - GetPackageRes, - GetPackagesReq, - GetPackagesRes, -} from '@start9labs/marketplace' +import { GetPackageReq, GetPackagesReq } from '@start9labs/marketplace' -export namespace RR { - // websocket +// websocket - export type WebsocketConfig = Omit, 'url'> +export type WebsocketConfig = Omit, 'url'> - // state +// state - export type EchoReq = { message: string } // server.echo - export type EchoRes = string +export type ServerState = 'initializing' | 'error' | 'running' - export type ServerState = 'initializing' | 'error' | 'running' +// diagnostic - // DB - - export type SubscribePatchReq = {} - export type SubscribePatchRes = { - dump: Dump - guid: string - } - - export type SetDBValueReq = { pointer: string; value: T } // db.put.ui - export type SetDBValueRes = null - - // auth - - export type LoginReq = { - password: string - ephemeral?: boolean - } // auth.login - unauthed - export type loginRes = null - - export type LogoutReq = {} // auth.logout - export type LogoutRes = null - - export type ResetPasswordReq = { - oldPassword: string - newPassword: string - } // auth.reset-password - export type ResetPasswordRes = null - - // diagnostic - - export type DiagnosticErrorRes = { - code: number - message: string - data: { details: string } - } - - // init - - export type InitFollowProgressRes = { - progress: T.FullProgress - guid: string - } - - // server - - export type GetSystemTimeReq = {} // server.time - export type GetSystemTimeRes = { - now: string - uptime: number // seconds - } - - export type GetServerLogsReq = FetchLogsReq // server.logs & server.kernel-logs - export type GetServerLogsRes = FetchLogsRes - - export type FollowServerLogsReq = { - limit?: number // (optional) default is 50. Ignored if cursor provided - boot?: number | string | null // (optional) number is offset (0: current, -1 prev, +1 first), string is a specific boot id, null is all. Default is undefined - cursor?: string // the last known log. Websocket will return all logs since this log - } // server.logs.follow & server.kernel-logs.follow - export type FollowServerLogsRes = { - startCursor: string - guid: string - } - - export type FollowServerMetricsReq = {} // server.metrics.follow - export type FollowServerMetricsRes = { - guid: string - metrics: ServerMetrics - } - - export type UpdateServerReq = { registry: string; targetVersion: string } // server.update - export type UpdateServerRes = 'updating' | 'no-updates' - - export type RestartServerReq = {} // server.restart - export type RestartServerRes = null - - export type ShutdownServerReq = {} // server.shutdown - export type ShutdownServerRes = null - - export type DiskRepairReq = {} // server.disk.repair - export type DiskRepairRes = null - - export type SetDnsReq = { - servers: string[] | null - } // net.dns.set-static - export type SetDnsRes = null - - export type QueryDnsReq = { - fqdn: string - } // net.dns.query - export type QueryDnsRes = string | null - - export type TestPortForwardReq = { - gateway: string - port: number - } // net.port-forward.test - export type TestPortForwardRes = boolean - - export type SetKeyboardReq = FullKeyboard // server.set-keyboard - export type SetKeyboardRes = null - - export type SetLanguageReq = SetLanguageParams // server.set-language - export type SetLanguageRes = null - - // smtp - - export type SetSMTPReq = T.SmtpValue // server.set-smtp - export type SetSMTPRes = null - - export type ClearSMTPReq = {} // server.clear-smtp - export type ClearSMTPRes = null - - export type TestSMTPReq = SetSMTPReq & { to: string } // server.test-smtp - export type TestSMTPRes = null - - // sessions - - export type GetSessionsReq = {} // sessions.list - export type GetSessionsRes = { - current: string - sessions: { [hash: string]: Session } - } - - export type KillSessionsReq = { ids: string[] } // sessions.kill - export type KillSessionsRes = null - - // notification - - export type GetNotificationsReq = { - before?: number - limit?: number - } // notification.list - export type GetNotificationsRes = ServerNotification[] - - export type DeleteNotificationsReq = { ids: number[] } // notification.remove - export type DeleteNotificationsRes = null - - export type MarkSeenNotificationReq = DeleteNotificationsReq // notification.mark-seen - export type MarkSeenNotificationRes = null - - export type MarkSeenAllNotificationsReq = { before: number } // notification.mark-seen-before - export type MarkSeenAllNotificationsRes = null - - export type MarkUnseenNotificationReq = DeleteNotificationsReq // notification.mark-unseen - export type MarkUnseenNotificationRes = null - - // wifi - - export type GetWifiReq = {} - export type GetWifiRes = { - ssids: { - [ssid: string]: number - } - connected: string | null - country: string | null - ethernet: boolean - availableWifi: AvailableWifi[] - } - - export type AddWifiReq = { - // wifi.add - ssid: string - password: string - priority: number - connect: boolean - } - export type AddWifiRes = null - - export type EnabledWifiReq = { enable: boolean } // wifi.set-enabled - export type EnabledWifiRes = null - - export type SetWifiCountryReq = { country: string } // wifi.country.set - export type SetWifiCountryRes = null - - export type ConnectWifiReq = { ssid: string } // wifi.connect - export type ConnectWifiRes = null - - export type DeleteWifiReq = { ssid: string } // wifi.remove - export type DeleteWifiRes = null - - // ssh - - export type GetSSHKeysReq = {} // ssh.list - export type GetSSHKeysRes = SSHKey[] - - export type AddSSHKeyReq = { key: string } // ssh.add - export type AddSSHKeyRes = SSHKey - - export type DeleteSSHKeyReq = { fingerprint: string } // ssh.remove - export type DeleteSSHKeyRes = null - - // backup - - export type GetBackupTargetsReq = {} // backup.target.list - export type GetBackupTargetsRes = { [id: string]: BackupTarget } - - export type AddBackupTargetReq = { - // backup.target.cifs.add - hostname: string - path: string - username: string - password: string | null - } - export type AddBackupTargetRes = { [id: string]: CifsBackupTarget } - - export type UpdateBackupTargetReq = AddBackupTargetReq & { id: string } // backup.target.cifs.update - export type UpdateBackupTargetRes = AddBackupTargetRes - - export type RemoveBackupTargetReq = { id: string } // backup.target.cifs.remove - export type RemoveBackupTargetRes = null - - export type GetBackupInfoReq = { - // backup.target.info - targetId: string - serverId: string - password: string - } - export type GetBackupInfoRes = BackupInfo - - export type CreateBackupReq = { - // backup.create - targetId: string - packageIds: string[] - oldPassword: string | null - password: string - } - export type CreateBackupRes = null - - // network - - export type GatewayType = 'inbound-outbound' | 'outbound-only' - - export type AddTunnelReq = { - name: string - config: string // file contents - setAsDefaultOutbound?: boolean - } // net.tunnel.add - export type AddTunnelRes = { - id: string - } - - export type UpdateTunnelReq = { - id: string - name: string - } // net.gateway.set-name - export type UpdateTunnelRes = null - - export type RemoveTunnelReq = { id: string } // net.tunnel.remove - export type RemoveTunnelRes = null - - // Set default outbound gateway - export type SetDefaultOutboundReq = { gateway: string | null } // net.gateway.set-default-outbound - export type SetDefaultOutboundRes = null - - // Set service outbound gateway - export type SetServiceOutboundReq = { - packageId: string - gateway: string | null - } // package.set-outbound-gateway - export type SetServiceOutboundRes = null - - export type InitAcmeReq = { - provider: string - contact: string[] - } - export type InitAcmeRes = null - - export type RemoveAcmeReq = { - provider: string - } - export type RemoveAcmeRes = null - - export type ServerBindingSetAddressEnabledReq = { - // server.host.binding.set-address-enabled - internalPort: 80 - address: string // JSON-serialized HostnameInfo - enabled: boolean | null // null = reset to default - } - export type ServerBindingSetAddressEnabledRes = null - - export type OsUiAddPublicDomainReq = { - // server.host.address.domain.public.add - fqdn: string // FQDN - gateway: T.GatewayId - acme: string | null // URL. null means local Root CA - } - export type OsUiAddPublicDomainRes = QueryDnsRes - - export type OsUiRemovePublicDomainReq = { - // server.host.address.domain.public.remove - fqdn: string // FQDN - } - export type OsUiRemovePublicDomainRes = null - - export type OsUiAddPrivateDomainReq = { - // server.host.address.domain.private.add - fqdn: string // FQDN - } - export type OsUiAddPrivateDomainRes = null - - export type OsUiRemovePrivateDomainReq = { - // server.host.address.domain.private.remove - fqdn: string // FQDN - } - export type OsUiRemovePrivateDomainRes = null - - export type PkgBindingSetAddressEnabledReq = Omit< - ServerBindingSetAddressEnabledReq, - 'internalPort' - > & { - // package.host.binding.set-address-enabled - internalPort: number - package: T.PackageId // string - host: T.HostId // string - } - export type PkgBindingSetAddressEnabledRes = null - - export type PkgAddPublicDomainReq = OsUiAddPublicDomainReq & { - // package.host.address.domain.public.add - package: T.PackageId // string - host: T.HostId // string - } - export type PkgAddPublicDomainRes = OsUiAddPublicDomainRes - - export type PkgRemovePublicDomainReq = OsUiRemovePublicDomainReq & { - // package.host.address.domain.public.remove - package: T.PackageId // string - host: T.HostId // string - } - export type PkgRemovePublicDomainRes = OsUiRemovePublicDomainRes - - export type PkgAddPrivateDomainReq = OsUiAddPrivateDomainReq & { - // package.host.address.domain.private.add - package: T.PackageId // string - host: T.HostId // string - } - export type PkgAddPrivateDomainRes = OsUiAddPrivateDomainRes - - export type PkgRemovePrivateDomainReq = PkgAddPrivateDomainReq - export type PkgRemovePrivateDomainRes = OsUiRemovePrivateDomainRes - - export type GetPackageLogsReq = FetchLogsReq & { id: string } // package.logs - export type GetPackageLogsRes = FetchLogsRes - - export type FollowPackageLogsReq = FollowServerLogsReq & { id: string } // package.logs.follow - export type FollowPackageLogsRes = FollowServerLogsRes - - export type InstallPackageReq = T.InstallParams - export type InstallPackageRes = null - - export type CancelInstallPackageReq = { id: string } - export type CancelInstallPackageRes = null - - export type GetActionInputReq = { packageId: string; actionId: string } // package.action.get-input - export type GetActionInputRes = { - eventId: string - spec: IST.InputSpec - value: object | null - } - - export type ActionReq = { - packageId: string - eventId: string | null - actionId: string - input: object | null - } // package.action.run - export type ActionRes = (T.ActionResult & { version: '1' }) | null - - export type ClearTaskReq = { - packageId: string - replayId: string - } // package.action.clear-task - export type ClearTaskRes = null - - export type RestorePackagesReq = { - // package.backup.restore - ids: string[] - targetId: string - serverId: string - password: string - } - export type RestorePackagesRes = null - - export type StartPackageReq = { id: string } // package.start - export type StartPackageRes = null - - export type RestartPackageReq = { id: string } // package.restart - export type RestartPackageRes = null - - export type StopPackageReq = { id: string } // package.stop - export type StopPackageRes = null - - export type RebuildPackageReq = { id: string } // package.rebuild - export type RebuildPackageRes = null - - export type UninstallPackageReq = { - id: string - force: boolean - soft: boolean - } // package.uninstall - export type UninstallPackageRes = null - - export type SideloadPackageReq = { - manifest: T.Manifest - icon: string // base64 - } - export type SideloadPackageRes = { - upload: string - progress: string // guid - } - - // registry - - /** these are returned in ASCENDING order. the newest available version will be the LAST in the object */ - export type CheckOsUpdateReq = { registry: string; serverId: string } - export type CheckOsUpdateRes = { [version: string]: T.OsVersionInfo } - - export type GetRegistryInfoReq = { registry: string } - export type GetRegistryInfoRes = T.RegistryInfo - - export type GetRegistryPackageReq = GetPackageReq & { registry: string } - export type GetRegistryPackageRes = GetPackageRes - - export type GetRegistryPackagesReq = GetPackagesReq & { registry: string } - export type GetRegistryPackagesRes = GetPackagesRes +export type DiagnosticErrorRes = { + code: number + message: string + data: { details: string } } -interface MetricData { - value: string - unit: string +// logs + +export type FollowServerLogsReq = Omit + +// bindings + +export type ServerBindingSetAddressEnabledReq = { + // server.host.binding.set-address-enabled + internalPort: 80 + address: string // JSON-serialized HostnameInfo + enabled: boolean | null // null = reset to default } -export type ServerMetrics = { - general: { - temperature: MetricData | null - } - memory: { - total: MetricData - percentageUsed: MetricData - used: MetricData - available: MetricData - zramTotal: MetricData - zramUsed: MetricData - zramAvailable: MetricData - } - cpu: { - percentageUsed: MetricData - idle: MetricData - userSpace: MetricData - kernelSpace: MetricData - wait: MetricData - } - disk: { - capacity: MetricData - percentageUsed: MetricData - used: MetricData - available: MetricData - } +export type PkgBindingSetAddressEnabledReq = Omit< + ServerBindingSetAddressEnabledReq, + 'internalPort' +> & { + // package.host.binding.set-address-enabled + internalPort: number + package: T.PackageId // string + host: T.HostId // string } -export type Session = { - loggedIn: string - lastActive: string - userAgent: string +// package domains + +export type PkgAddPublicDomainReq = T.AddPublicDomainParams & { + // package.host.address.domain.public.add + package: T.PackageId // string + host: T.HostId // string } -export type BackupTarget = DiskBackupTarget | CifsBackupTarget - -export interface DiskBackupTarget { - type: 'disk' - vendor: string | null - model: string | null - logicalname: string | null - label: string | null - capacity: number - used: number | null - startOs: Record +export type PkgRemovePublicDomainReq = T.RemoveDomainParams & { + // package.host.address.domain.public.remove + package: T.PackageId // string + host: T.HostId // string } -export interface CifsBackupTarget { - type: 'cifs' - hostname: string - path: string - username: string - mountable: boolean - startOs: Record +export type PkgAddPrivateDomainReq = T.AddPrivateDomainParams & { + // package.host.address.domain.private.add + package: T.PackageId // string + host: T.HostId // string } +export type PkgRemovePrivateDomainReq = T.RemoveDomainParams & { + // package.host.address.domain.private.remove + package: T.PackageId // string + host: T.HostId // string +} + +// package logs + +export type GetPackageLogsReq = T.LogsParams & { id: string } // package.logs + +export type FollowPackageLogsReq = FollowServerLogsReq & { id: string } // package.logs.follow + +// actions + +export type GetActionInputRes = { + eventId: string + spec: IST.InputSpec + value: object | null +} + +export type ActionRes = (T.ActionResult & { version: '1' }) | null + +// registry + +export type GetRegistryPackageReq = GetPackageReq & { registry: string } + +export type GetRegistryPackagesReq = GetPackagesReq & { registry: string } + +// backup + +export type DiskBackupTarget = Extract +export type CifsBackupTarget = T.CifsBackupTarget & { type: 'cifs' } + export type RecoverySource = DiskRecoverySource | CifsRecoverySource export interface DiskRecoverySource { @@ -531,74 +109,28 @@ export interface CifsRecoverySource { password: string } -export type BackupInfo = { - version: string - timestamp: string - packageBackups: { - [id: string]: PackageBackupInfo - } -} +// notifications -export type PackageBackupInfo = { - title: string - version: string - osVersion: string - timestamp: string -} - -export type ServerSpecs = { - [key: string]: string | number -} - -export type SSHKey = { - createdAt: string - alg: string - hostname: string - fingerprint: string -} - -export type ServerNotifications = ServerNotification[] - -export type ServerNotification = { +export type ServerNotification = { id: number packageId: string | null createdAt: string - code: T - level: NotificationLevel + code: N + level: T.NotificationLevel title: string message: string - data: NotificationData + data: NotificationData seen: boolean } -export type NotificationLevel = 'success' | 'info' | 'warning' | 'error' - -export type NotificationData = T extends 0 +export type NotificationData = N extends 0 ? null - : T extends 1 - ? BackupReport - : T extends 2 + : N extends 1 + ? T.BackupReport + : N extends 2 ? string : any -export type BackupReport = { - server: { - attempted: boolean - error: string | null - } - packages: { - [id: string]: { - error: string | null - } - } -} - -export type AvailableWifi = { - ssid: string - strength: number - security: string[] -} - declare global { type Stringified = string & { [P in keyof T]: T[P] @@ -614,10 +146,6 @@ declare global { } } -export type Encrypted = { - encrypted: string -} - // @TODO 041 // export namespace RR041 { diff --git a/web/projects/ui/src/app/services/api/embassy-api.service.ts b/web/projects/ui/src/app/services/api/embassy-api.service.ts index 643d23536..1e224b3a8 100644 --- a/web/projects/ui/src/app/services/api/embassy-api.service.ts +++ b/web/projects/ui/src/app/services/api/embassy-api.service.ts @@ -1,5 +1,28 @@ -import { RR } from './api.types' +import { FullKeyboard, SetLanguageParams } from '@start9labs/shared' +import { T } from '@start9labs/start-sdk' +import { GetPackageRes, GetPackagesRes } from '@start9labs/marketplace' +import { Dump } from 'patch-db-client' import { WebSocketSubject } from 'rxjs/webSocket' +import { DataModel } from '../patch-db/data-model' +import { + ActionRes, + CifsBackupTarget, + DiagnosticErrorRes, + FollowPackageLogsReq, + FollowServerLogsReq, + GetActionInputRes, + GetPackageLogsReq, + GetRegistryPackageReq, + GetRegistryPackagesReq, + PkgAddPrivateDomainReq, + PkgAddPublicDomainReq, + PkgBindingSetAddressEnabledReq, + PkgRemovePrivateDomainReq, + PkgRemovePublicDomainReq, + ServerBindingSetAddressEnabledReq, + ServerState, + WebsocketConfig, +} from './api.types' export abstract class ApiService { // http @@ -17,226 +40,206 @@ export abstract class ApiService { abstract openWebsocket$( guid: string, - config?: RR.WebsocketConfig, + config?: WebsocketConfig, ): WebSocketSubject // state - abstract echo(params: RR.EchoReq, url: string): Promise + abstract echo(params: T.EchoParams, url: string): Promise - abstract getState(): Promise + abstract getState(): Promise // db - abstract subscribeToPatchDB( - params: RR.SubscribePatchReq, - ): Promise + abstract subscribeToPatchDB(params: {}): Promise<{ + dump: Dump + guid: string + }> abstract setDbValue( pathArr: Array, value: T, - ): Promise + ): Promise // auth - abstract login(params: RR.LoginReq): Promise + abstract login(params: T.LoginParams): Promise - abstract logout(params: RR.LogoutReq): Promise + abstract logout(params: {}): Promise - abstract getSessions(params: RR.GetSessionsReq): Promise + abstract getSessions(params: {}): Promise - abstract killSessions(params: RR.KillSessionsReq): Promise + abstract killSessions(params: T.KillParams): Promise - abstract resetPassword( - params: RR.ResetPasswordReq, - ): Promise + abstract resetPassword(params: T.ResetPasswordParams): Promise // diagnostic - abstract diagnosticGetError(): Promise + abstract diagnosticGetError(): Promise abstract diagnosticRestart(): Promise abstract diagnosticForgetDrive(): Promise abstract diagnosticRepairDisk(): Promise - abstract diagnosticGetLogs( - params: RR.GetServerLogsReq, - ): Promise + abstract diagnosticGetLogs(params: T.LogsParams): Promise // init - abstract initFollowProgress(): Promise + abstract initFollowProgress(): Promise abstract initFollowLogs( - params: RR.FollowServerLogsReq, - ): Promise + params: FollowServerLogsReq, + ): Promise // server - abstract getSystemTime( - params: RR.GetSystemTimeReq, - ): Promise + abstract getSystemTime(params: {}): Promise - abstract getServerLogs( - params: RR.GetServerLogsReq, - ): Promise + abstract getServerLogs(params: T.LogsParams): Promise - abstract getKernelLogs( - params: RR.GetServerLogsReq, - ): Promise + abstract getKernelLogs(params: T.LogsParams): Promise abstract followServerLogs( - params: RR.FollowServerLogsReq, - ): Promise + params: FollowServerLogsReq, + ): Promise abstract followKernelLogs( - params: RR.FollowServerLogsReq, - ): Promise + params: FollowServerLogsReq, + ): Promise - abstract followServerMetrics( - params: RR.FollowServerMetricsReq, - ): Promise + abstract followServerMetrics(params: {}): Promise - abstract updateServer(params: RR.UpdateServerReq): Promise + abstract updateServer(params: { + registry: string + targetVersion: string + }): Promise<'updating' | 'no-updates'> - abstract restartServer( - params: RR.RestartServerReq, - ): Promise + abstract restartServer(params: {}): Promise - abstract shutdownServer( - params: RR.ShutdownServerReq, - ): Promise + abstract shutdownServer(params: {}): Promise - abstract repairDisk(params: RR.DiskRepairReq): Promise + abstract repairDisk(params: {}): Promise abstract toggleKiosk(enable: boolean): Promise - abstract setKeyboard(params: RR.SetKeyboardReq): Promise + abstract setKeyboard(params: FullKeyboard): Promise - abstract setLanguage(params: RR.SetLanguageReq): Promise + abstract setLanguage(params: SetLanguageParams): Promise - abstract setDns(params: RR.SetDnsReq): Promise + abstract setDns(params: T.SetStaticDnsParams): Promise - abstract queryDns(params: RR.QueryDnsReq): Promise + abstract queryDns(params: T.QueryDnsParams): Promise - abstract testPortForward( - params: RR.TestPortForwardReq, - ): Promise + abstract testPortForward(params: { + gateway: string + port: number + }): Promise // smtp - abstract setSmtp(params: RR.SetSMTPReq): Promise + abstract setSmtp(params: T.SmtpValue): Promise - abstract clearSmtp(params: RR.ClearSMTPReq): Promise + abstract clearSmtp(params: {}): Promise - abstract testSmtp(params: RR.TestSMTPReq): Promise + abstract testSmtp(params: T.TestSmtpParams): Promise // marketplace URLs - abstract checkOSUpdate( - params: RR.CheckOsUpdateReq, - ): Promise + abstract checkOSUpdate(params: { + registry: string + serverId: string + }): Promise - abstract getRegistryInfo( - params: RR.GetRegistryInfoReq, - ): Promise + abstract getRegistryInfo(params: { + registry: string + }): Promise abstract getRegistryPackage( - params: RR.GetRegistryPackageReq, - ): Promise + params: GetRegistryPackageReq, + ): Promise abstract getRegistryPackages( - params: RR.GetRegistryPackagesReq, - ): Promise + params: GetRegistryPackagesReq, + ): Promise // notification abstract getNotifications( - params: RR.GetNotificationsReq, - ): Promise + params: T.ListNotificationParams, + ): Promise abstract markSeenNotifications( - params: RR.MarkSeenNotificationReq, - ): Promise + params: T.ModifyNotificationParams, + ): Promise abstract markSeenAllNotifications( - params: RR.MarkSeenAllNotificationsReq, - ): Promise + params: T.ModifyNotificationBeforeParams, + ): Promise abstract markUnseenNotifications( - params: RR.DeleteNotificationsReq, - ): Promise + params: T.ModifyNotificationParams, + ): Promise abstract deleteNotifications( - params: RR.DeleteNotificationsReq, - ): Promise + params: T.ModifyNotificationParams, + ): Promise // ** proxies ** - abstract addTunnel(params: RR.AddTunnelReq): Promise + abstract addTunnel(params: T.AddTunnelParams): Promise<{ id: string }> - abstract updateTunnel(params: RR.UpdateTunnelReq): Promise + abstract updateTunnel(params: T.RenameGatewayParams): Promise - abstract removeTunnel(params: RR.RemoveTunnelReq): Promise + abstract removeTunnel(params: T.RemoveTunnelParams): Promise - abstract setDefaultOutbound( - params: RR.SetDefaultOutboundReq, - ): Promise + abstract setDefaultOutbound(params: { gateway: string | null }): Promise - abstract setServiceOutbound( - params: RR.SetServiceOutboundReq, - ): Promise + abstract setServiceOutbound(params: { + packageId: string + gateway: string | null + }): Promise // ** domains ** // wifi - abstract enableWifi(params: RR.EnabledWifiReq): Promise + abstract enableWifi(params: T.SetWifiEnabledParams): Promise - abstract setWifiCountry( - params: RR.SetWifiCountryReq, - ): Promise + abstract setWifiCountry(params: T.SetCountryParams): Promise - abstract getWifi( - params: RR.GetWifiReq, - timeout: number, - ): Promise + abstract getWifi(params: {}, timeout: number): Promise - abstract addWifi(params: RR.AddWifiReq): Promise + abstract addWifi(params: T.WifiAddParams): Promise - abstract connectWifi(params: RR.ConnectWifiReq): Promise + abstract connectWifi(params: T.WifiSsidParams): Promise - abstract deleteWifi(params: RR.DeleteWifiReq): Promise + abstract deleteWifi(params: T.WifiSsidParams): Promise // ssh - abstract getSshKeys(params: RR.GetSSHKeysReq): Promise + abstract getSshKeys(params: {}): Promise - abstract addSshKey(params: RR.AddSSHKeyReq): Promise + abstract addSshKey(params: T.SshAddParams): Promise - abstract deleteSshKey(params: RR.DeleteSSHKeyReq): Promise + abstract deleteSshKey(params: T.SshDeleteParams): Promise // backup - abstract getBackupTargets( - params: RR.GetBackupTargetsReq, - ): Promise + abstract getBackupTargets(params: {}): Promise<{ + [id: string]: T.BackupTarget + }> abstract addBackupTarget( - params: RR.AddBackupTargetReq, - ): Promise + params: T.CifsAddParams, + ): Promise<{ [id: string]: CifsBackupTarget }> abstract updateBackupTarget( - params: RR.UpdateBackupTargetReq, - ): Promise + params: T.CifsUpdateParams, + ): Promise<{ [id: string]: CifsBackupTarget }> - abstract removeBackupTarget( - params: RR.RemoveBackupTargetReq, - ): Promise + abstract removeBackupTarget(params: T.CifsRemoveParams): Promise - abstract getBackupInfo( - params: RR.GetBackupInfoReq, - ): Promise + abstract getBackupInfo(params: T.InfoParams): Promise - abstract createBackup(params: RR.CreateBackupReq): Promise + abstract createBackup(params: T.BackupParams): Promise // @TODO 041 @@ -288,51 +291,37 @@ export abstract class ApiService { // package - abstract getPackageLogs( - params: RR.GetPackageLogsReq, - ): Promise + abstract getPackageLogs(params: GetPackageLogsReq): Promise abstract followPackageLogs( - params: RR.FollowPackageLogsReq, - ): Promise + params: FollowPackageLogsReq, + ): Promise - abstract installPackage( - params: RR.InstallPackageReq, - ): Promise + abstract installPackage(params: T.InstallParams): Promise - abstract cancelInstallPackage( - params: RR.CancelInstallPackageReq, - ): Promise + abstract cancelInstallPackage(params: T.CancelInstallParams): Promise abstract getActionInput( - params: RR.GetActionInputReq, - ): Promise + params: T.GetActionInputParams, + ): Promise - abstract runAction(params: RR.ActionReq): Promise + abstract runAction(params: T.RunActionParams): Promise - abstract clearTask(params: RR.ClearTaskReq): Promise + abstract clearTask(params: T.ClearTaskParams): Promise - abstract restorePackages( - params: RR.RestorePackagesReq, - ): Promise + abstract restorePackages(params: T.RestorePackageParams): Promise - abstract startPackage(params: RR.StartPackageReq): Promise + abstract startPackage(params: T.ControlParams): Promise - abstract restartPackage( - params: RR.RestartPackageReq, - ): Promise + abstract restartPackage(params: T.ControlParams): Promise - abstract stopPackage(params: RR.StopPackageReq): Promise + abstract stopPackage(params: T.ControlParams): Promise - abstract rebuildPackage( - params: RR.RebuildPackageReq, - ): Promise + abstract rebuildPackage(params: T.RebuildParams): Promise - abstract uninstallPackage( - params: RR.UninstallPackageReq, - ): Promise + abstract uninstallPackage(params: T.UninstallParams): Promise - abstract sideloadPackage(): Promise + abstract sideloadPackage(): Promise // @TODO 041 @@ -342,47 +331,39 @@ export abstract class ApiService { // params: RR.SetServiceOutboundTunnelReq, // ): Promise - abstract initAcme(params: RR.InitAcmeReq): Promise + abstract initAcme(params: T.InitAcmeParams): Promise - abstract removeAcme(params: RR.RemoveAcmeReq): Promise + abstract removeAcme(params: T.RemoveAcmeParams): Promise abstract serverBindingSetAddressEnabled( - params: RR.ServerBindingSetAddressEnabledReq, - ): Promise + params: ServerBindingSetAddressEnabledReq, + ): Promise abstract osUiAddPublicDomain( - params: RR.OsUiAddPublicDomainReq, - ): Promise + params: T.AddPublicDomainParams, + ): Promise - abstract osUiRemovePublicDomain( - params: RR.OsUiRemovePublicDomainReq, - ): Promise + abstract osUiRemovePublicDomain(params: T.RemoveDomainParams): Promise - abstract osUiAddPrivateDomain( - params: RR.OsUiAddPrivateDomainReq, - ): Promise + abstract osUiAddPrivateDomain(params: T.AddPrivateDomainParams): Promise - abstract osUiRemovePrivateDomain( - params: RR.OsUiRemovePrivateDomainReq, - ): Promise + abstract osUiRemovePrivateDomain(params: T.RemoveDomainParams): Promise abstract pkgBindingSetAddressEnabled( - params: RR.PkgBindingSetAddressEnabledReq, - ): Promise + params: PkgBindingSetAddressEnabledReq, + ): Promise abstract pkgAddPublicDomain( - params: RR.PkgAddPublicDomainReq, - ): Promise + params: PkgAddPublicDomainReq, + ): Promise abstract pkgRemovePublicDomain( - params: RR.PkgRemovePublicDomainReq, - ): Promise + params: PkgRemovePublicDomainReq, + ): Promise - abstract pkgAddPrivateDomain( - params: RR.PkgAddPrivateDomainReq, - ): Promise + abstract pkgAddPrivateDomain(params: PkgAddPrivateDomainReq): Promise abstract pkgRemovePrivateDomain( - params: RR.PkgRemovePrivateDomainReq, - ): Promise + params: PkgRemovePrivateDomainReq, + ): Promise } diff --git a/web/projects/ui/src/app/services/api/embassy-live-api.service.ts b/web/projects/ui/src/app/services/api/embassy-live-api.service.ts index 50af00bb7..bf37e0010 100644 --- a/web/projects/ui/src/app/services/api/embassy-live-api.service.ts +++ b/web/projects/ui/src/app/services/api/embassy-live-api.service.ts @@ -1,19 +1,41 @@ import { DOCUMENT, Inject, Injectable } from '@angular/core' import { blake3 } from '@noble/hashes/blake3' import { + FullKeyboard, HttpOptions, HttpService, isRpcError, RpcError, RPCOptions, + SetLanguageParams, } from '@start9labs/shared' +import { T } from '@start9labs/start-sdk' +import { GetPackageRes, GetPackagesRes } from '@start9labs/marketplace' import { Dump, pathFromArray } from 'patch-db-client' import { filter, firstValueFrom, Observable } from 'rxjs' import { webSocket, WebSocketSubject } from 'rxjs/webSocket' import { PATCH_CACHE } from 'src/app/services/patch-db/patch-db-source' import { AuthService } from '../auth.service' import { DataModel } from '../patch-db/data-model' -import { RR } from './api.types' +import { + ActionRes, + CifsBackupTarget, + DiagnosticErrorRes, + FollowPackageLogsReq, + FollowServerLogsReq, + GetActionInputRes, + GetPackageLogsReq, + GetRegistryPackageReq, + GetRegistryPackagesReq, + PkgAddPrivateDomainReq, + PkgAddPublicDomainReq, + PkgBindingSetAddressEnabledReq, + PkgRemovePrivateDomainReq, + PkgRemovePublicDomainReq, + ServerBindingSetAddressEnabledReq, + ServerState, + WebsocketConfig, +} from './api.types' import { ApiService } from './embassy-api.service' @Injectable() @@ -65,7 +87,7 @@ export class LiveApiService extends ApiService { openWebsocket$( guid: string, - config: RR.WebsocketConfig = {}, + config: WebsocketConfig = {}, ): WebSocketSubject { const { location } = this.document.defaultView! const protocol = location.protocol === 'http:' ? 'ws' : 'wss' @@ -79,59 +101,58 @@ export class LiveApiService extends ApiService { // state - async echo(params: RR.EchoReq, url: string): Promise { + async echo(params: T.EchoParams, url: string): Promise { return this.rpcRequest({ method: 'echo', params }, url) } - async getState(): Promise { + async getState(): Promise { return this.rpcRequest({ method: 'state', params: {}, timeout: 10000 }) } // db - async subscribeToPatchDB( - params: RR.SubscribePatchReq, - ): Promise { + async subscribeToPatchDB(params: {}): Promise<{ + dump: Dump + guid: string + }> { return this.rpcRequest({ method: 'db.subscribe', params }) } async setDbValue( pathArr: Array, value: T, - ): Promise { + ): Promise { const pointer = pathFromArray(pathArr) - const params: RR.SetDBValueReq = { pointer, value } + const params = { pointer, value } return this.rpcRequest({ method: 'db.put.ui', params }) } // auth - async login(params: RR.LoginReq): Promise { + async login(params: T.LoginParams): Promise { return this.rpcRequest({ method: 'auth.login', params }) } - async logout(params: RR.LogoutReq): Promise { + async logout(params: {}): Promise { return this.rpcRequest({ method: 'auth.logout', params }) } - async getSessions(params: RR.GetSessionsReq): Promise { + async getSessions(params: {}): Promise { return this.rpcRequest({ method: 'auth.session.list', params }) } - async killSessions(params: RR.KillSessionsReq): Promise { + async killSessions(params: T.KillParams): Promise { return this.rpcRequest({ method: 'auth.session.kill', params }) } - async resetPassword( - params: RR.ResetPasswordReq, - ): Promise { + async resetPassword(params: T.ResetPasswordParams): Promise { return this.rpcRequest({ method: 'auth.reset-password', params }) } // diagnostic - async diagnosticGetError(): Promise { - return this.rpcRequest({ + async diagnosticGetError(): Promise { + return this.rpcRequest({ method: 'diagnostic.error', params: {}, }) @@ -158,10 +179,8 @@ export class LiveApiService extends ApiService { }) } - async diagnosticGetLogs( - params: RR.GetServerLogsReq, - ): Promise { - return this.rpcRequest({ + async diagnosticGetLogs(params: T.LogsParams): Promise { + return this.rpcRequest({ method: 'diagnostic.logs', params, }) @@ -169,71 +188,62 @@ export class LiveApiService extends ApiService { // init - async initFollowProgress(): Promise { + async initFollowProgress(): Promise { return this.rpcRequest({ method: 'init.subscribe', params: {} }) } async initFollowLogs( - params: RR.FollowServerLogsReq, - ): Promise { + params: FollowServerLogsReq, + ): Promise { return this.rpcRequest({ method: 'init.logs.follow', params }) } // server - async getSystemTime( - params: RR.GetSystemTimeReq, - ): Promise { + async getSystemTime(params: {}): Promise { return this.rpcRequest({ method: 'server.time', params }) } - async getServerLogs( - params: RR.GetServerLogsReq, - ): Promise { + async getServerLogs(params: T.LogsParams): Promise { return this.rpcRequest({ method: 'server.logs', params }) } - async getKernelLogs( - params: RR.GetServerLogsReq, - ): Promise { + async getKernelLogs(params: T.LogsParams): Promise { return this.rpcRequest({ method: 'server.kernel-logs', params }) } async followServerLogs( - params: RR.FollowServerLogsReq, - ): Promise { + params: FollowServerLogsReq, + ): Promise { return this.rpcRequest({ method: 'server.logs.follow', params }) } async followKernelLogs( - params: RR.FollowServerLogsReq, - ): Promise { + params: FollowServerLogsReq, + ): Promise { return this.rpcRequest({ method: 'server.kernel-logs.follow', params }) } - async followServerMetrics( - params: RR.FollowServerMetricsReq, - ): Promise { + async followServerMetrics(params: {}): Promise { return this.rpcRequest({ method: 'server.metrics.follow', params }) } - async updateServer(params: RR.UpdateServerReq): Promise { + async updateServer(params: { + registry: string + targetVersion: string + }): Promise<'updating' | 'no-updates'> { return this.rpcRequest({ method: 'server.update', params }) } - async restartServer( - params: RR.RestartServerReq, - ): Promise { + async restartServer(params: {}): Promise { return this.rpcRequest({ method: 'server.restart', params }) } - async shutdownServer( - params: RR.ShutdownServerReq, - ): Promise { + async shutdownServer(params: {}): Promise { return this.rpcRequest({ method: 'server.shutdown', params }) } - async repairDisk(params: RR.RestartServerReq): Promise { + async repairDisk(params: {}): Promise { return this.rpcRequest({ method: 'disk.repair', params }) } @@ -244,51 +254,51 @@ export class LiveApiService extends ApiService { }) } - async setKeyboard(params: RR.SetKeyboardReq): Promise { + async setKeyboard(params: FullKeyboard): Promise { return this.rpcRequest({ method: 'server.set-keyboard', params }) } - async setLanguage(params: RR.SetLanguageReq): Promise { + async setLanguage(params: SetLanguageParams): Promise { return this.rpcRequest({ method: 'server.set-language', params }) } - async setDns(params: RR.SetDnsReq): Promise { + async setDns(params: T.SetStaticDnsParams): Promise { return this.rpcRequest({ method: 'net.dns.set-static', params, }) } - async queryDns(params: RR.QueryDnsReq): Promise { + async queryDns(params: T.QueryDnsParams): Promise { return this.rpcRequest({ method: 'net.dns.query', params, }) } - async testPortForward( - params: RR.TestPortForwardReq, - ): Promise { + async testPortForward(params: { + gateway: string + port: number + }): Promise { return this.rpcRequest({ - method: 'net.port-forward.test', + method: 'net.gateway.check-port', params, }) } // marketplace URLs - async checkOSUpdate( - params: RR.CheckOsUpdateReq, - ): Promise { + async checkOSUpdate(params: { + registry: string + serverId: string + }): Promise { return this.rpcRequest({ method: 'registry.os.version.get', params, }) } - async getRegistryInfo( - params: RR.GetRegistryInfoReq, - ): Promise { + async getRegistryInfo(params: { registry: string }): Promise { return this.rpcRequest({ method: 'registry.info', params, @@ -296,8 +306,8 @@ export class LiveApiService extends ApiService { } async getRegistryPackage( - params: RR.GetRegistryPackageReq, - ): Promise { + params: GetRegistryPackageReq, + ): Promise { return this.rpcRequest({ method: 'registry.package.get', params, @@ -305,8 +315,8 @@ export class LiveApiService extends ApiService { } async getRegistryPackages( - params: RR.GetRegistryPackagesReq, - ): Promise { + params: GetRegistryPackagesReq, + ): Promise { return this.rpcRequest({ method: 'registry.package.get', params, @@ -316,26 +326,24 @@ export class LiveApiService extends ApiService { // notification async getNotifications( - params: RR.GetNotificationsReq, - ): Promise { + params: T.ListNotificationParams, + ): Promise { return this.rpcRequest({ method: 'notification.list', params }) } - async deleteNotifications( - params: RR.DeleteNotificationsReq, - ): Promise { + async deleteNotifications(params: T.ModifyNotificationParams): Promise { return this.rpcRequest({ method: 'notification.remove', params }) } async markSeenNotifications( - params: RR.MarkSeenNotificationReq, - ): Promise { + params: T.ModifyNotificationParams, + ): Promise { return this.rpcRequest({ method: 'notification.mark-seen', params }) } async markSeenAllNotifications( - params: RR.MarkSeenAllNotificationsReq, - ): Promise { + params: T.ModifyNotificationBeforeParams, + ): Promise { return this.rpcRequest({ method: 'notification.mark-seen-before', params, @@ -343,133 +351,123 @@ export class LiveApiService extends ApiService { } async markUnseenNotifications( - params: RR.MarkUnseenNotificationReq, - ): Promise { + params: T.ModifyNotificationParams, + ): Promise { return this.rpcRequest({ method: 'notification.mark-unseen', params }) } // proxies - async addTunnel(params: RR.AddTunnelReq): Promise { + async addTunnel(params: T.AddTunnelParams): Promise<{ id: string }> { return this.rpcRequest({ method: 'net.tunnel.add', params }) } - async updateTunnel(params: RR.UpdateTunnelReq): Promise { + async updateTunnel(params: T.RenameGatewayParams): Promise { return this.rpcRequest({ method: 'net.gateway.set-name', params }) } - async removeTunnel(params: RR.RemoveTunnelReq): Promise { + async removeTunnel(params: T.RemoveTunnelParams): Promise { return this.rpcRequest({ method: 'net.tunnel.remove', params }) } - async setDefaultOutbound( - params: RR.SetDefaultOutboundReq, - ): Promise { + async setDefaultOutbound(params: { gateway: string | null }): Promise { return this.rpcRequest({ method: 'net.gateway.set-default-outbound', params, }) } - async setServiceOutbound( - params: RR.SetServiceOutboundReq, - ): Promise { + async setServiceOutbound(params: { + packageId: string + gateway: string | null + }): Promise { return this.rpcRequest({ method: 'package.set-outbound-gateway', params }) } // wifi - async enableWifi(params: RR.EnabledWifiReq): Promise { + async enableWifi(params: T.SetWifiEnabledParams): Promise { return this.rpcRequest({ method: 'wifi.enable', params }) } - async getWifi( - params: RR.GetWifiReq, - timeout?: number, - ): Promise { + async getWifi(params: {}, timeout?: number): Promise { return this.rpcRequest({ method: 'wifi.get', params, timeout }) } - async setWifiCountry( - params: RR.SetWifiCountryReq, - ): Promise { + async setWifiCountry(params: T.SetCountryParams): Promise { return this.rpcRequest({ method: 'wifi.country.set', params }) } - async addWifi(params: RR.AddWifiReq): Promise { + async addWifi(params: T.WifiAddParams): Promise { return this.rpcRequest({ method: 'wifi.add', params }) } - async connectWifi(params: RR.ConnectWifiReq): Promise { + async connectWifi(params: T.WifiSsidParams): Promise { return this.rpcRequest({ method: 'wifi.connect', params }) } - async deleteWifi(params: RR.DeleteWifiReq): Promise { + async deleteWifi(params: T.WifiSsidParams): Promise { return this.rpcRequest({ method: 'wifi.remove', params }) } // smtp - async setSmtp(params: RR.SetSMTPReq): Promise { + async setSmtp(params: T.SmtpValue): Promise { return this.rpcRequest({ method: 'server.set-smtp', params }) } - async clearSmtp(params: RR.ClearSMTPReq): Promise { + async clearSmtp(params: {}): Promise { return this.rpcRequest({ method: 'server.clear-smtp', params }) } - async testSmtp(params: RR.TestSMTPReq): Promise { + async testSmtp(params: T.TestSmtpParams): Promise { return this.rpcRequest({ method: 'server.test-smtp', params }) } // ssh - async getSshKeys(params: RR.GetSSHKeysReq): Promise { + async getSshKeys(params: {}): Promise { return this.rpcRequest({ method: 'ssh.list', params }) } - async addSshKey(params: RR.AddSSHKeyReq): Promise { + async addSshKey(params: T.SshAddParams): Promise { return this.rpcRequest({ method: 'ssh.add', params }) } - async deleteSshKey(params: RR.DeleteSSHKeyReq): Promise { + async deleteSshKey(params: T.SshDeleteParams): Promise { return this.rpcRequest({ method: 'ssh.remove', params }) } // backup - async getBackupTargets( - params: RR.GetBackupTargetsReq, - ): Promise { + async getBackupTargets(params: {}): Promise<{ + [id: string]: T.BackupTarget + }> { return this.rpcRequest({ method: 'backup.target.list', params }) } async addBackupTarget( - params: RR.AddBackupTargetReq, - ): Promise { + params: T.CifsAddParams, + ): Promise<{ [id: string]: CifsBackupTarget }> { params.path = params.path.replace('/\\/g', '/') return this.rpcRequest({ method: 'backup.target.cifs.add', params }) } async updateBackupTarget( - params: RR.UpdateBackupTargetReq, - ): Promise { + params: T.CifsUpdateParams, + ): Promise<{ [id: string]: CifsBackupTarget }> { return this.rpcRequest({ method: 'backup.target.cifs.update', params }) } - async removeBackupTarget( - params: RR.RemoveBackupTargetReq, - ): Promise { + async removeBackupTarget(params: T.CifsRemoveParams): Promise { return this.rpcRequest({ method: 'backup.target.cifs.remove', params }) } - async getBackupInfo( - params: RR.GetBackupInfoReq, - ): Promise { + async getBackupInfo(params: T.InfoParams): Promise { return this.rpcRequest({ method: 'backup.target.info', params }) } - async createBackup(params: RR.CreateBackupReq): Promise { + async createBackup(params: T.BackupParams): Promise { return this.rpcRequest({ method: 'backup.create', params }) } @@ -532,77 +530,63 @@ export class LiveApiService extends ApiService { // package - async getPackageLogs( - params: RR.GetPackageLogsReq, - ): Promise { + async getPackageLogs(params: GetPackageLogsReq): Promise { return this.rpcRequest({ method: 'package.logs', params }) } async followPackageLogs( - params: RR.FollowPackageLogsReq, - ): Promise { + params: FollowPackageLogsReq, + ): Promise { return this.rpcRequest({ method: 'package.logs.follow', params }) } - async installPackage( - params: RR.InstallPackageReq, - ): Promise { + async installPackage(params: T.InstallParams): Promise { return this.rpcRequest({ method: 'package.install', params }) } - async cancelInstallPackage( - params: RR.CancelInstallPackageReq, - ): Promise { + async cancelInstallPackage(params: T.CancelInstallParams): Promise { return this.rpcRequest({ method: 'package.cancel-install', params }) } async getActionInput( - params: RR.GetActionInputReq, - ): Promise { + params: T.GetActionInputParams, + ): Promise { return this.rpcRequest({ method: 'package.action.get-input', params }) } - async runAction(params: RR.ActionReq): Promise { + async runAction(params: T.RunActionParams): Promise { return this.rpcRequest({ method: 'package.action.run', params }) } - async clearTask(params: RR.ClearTaskReq): Promise { + async clearTask(params: T.ClearTaskParams): Promise { return this.rpcRequest({ method: 'package.action.clear-task', params }) } - async restorePackages( - params: RR.RestorePackagesReq, - ): Promise { + async restorePackages(params: T.RestorePackageParams): Promise { return this.rpcRequest({ method: 'package.backup.restore', params }) } - async startPackage(params: RR.StartPackageReq): Promise { + async startPackage(params: T.ControlParams): Promise { return this.rpcRequest({ method: 'package.start', params }) } - async restartPackage( - params: RR.RestartPackageReq, - ): Promise { + async restartPackage(params: T.ControlParams): Promise { return this.rpcRequest({ method: 'package.restart', params }) } - async stopPackage(params: RR.StopPackageReq): Promise { + async stopPackage(params: T.ControlParams): Promise { return this.rpcRequest({ method: 'package.stop', params }) } - async rebuildPackage( - params: RR.RebuildPackageReq, - ): Promise { + async rebuildPackage(params: T.RebuildParams): Promise { return this.rpcRequest({ method: 'package.rebuild', params }) } - async uninstallPackage( - params: RR.UninstallPackageReq, - ): Promise { + async uninstallPackage(params: T.UninstallParams): Promise { return this.rpcRequest({ method: 'package.uninstall', params }) } - async sideloadPackage(): Promise { + async sideloadPackage(): Promise { return this.rpcRequest({ method: 'package.sideload', params: {}, @@ -615,14 +599,14 @@ export class LiveApiService extends ApiService { // return this.rpcRequest({ method: 'package.proxy.set-outbound', params }) // } - async removeAcme(params: RR.RemoveAcmeReq): Promise { + async removeAcme(params: T.RemoveAcmeParams): Promise { return this.rpcRequest({ method: 'net.acme.remove', params, }) } - async initAcme(params: RR.InitAcmeReq): Promise { + async initAcme(params: T.InitAcmeParams): Promise { return this.rpcRequest({ method: 'net.acme.init', params, @@ -630,8 +614,8 @@ export class LiveApiService extends ApiService { } async serverBindingSetAddressEnabled( - params: RR.ServerBindingSetAddressEnabledReq, - ): Promise { + params: ServerBindingSetAddressEnabledReq, + ): Promise { return this.rpcRequest({ method: 'server.host.binding.set-address-enabled', params, @@ -639,35 +623,29 @@ export class LiveApiService extends ApiService { } async osUiAddPublicDomain( - params: RR.OsUiAddPublicDomainReq, - ): Promise { + params: T.AddPublicDomainParams, + ): Promise { return this.rpcRequest({ method: 'server.host.address.domain.public.add', params, }) } - async osUiRemovePublicDomain( - params: RR.OsUiRemovePublicDomainReq, - ): Promise { + async osUiRemovePublicDomain(params: T.RemoveDomainParams): Promise { return this.rpcRequest({ method: 'server.host.address.domain.public.remove', params, }) } - async osUiAddPrivateDomain( - params: RR.OsUiAddPrivateDomainReq, - ): Promise { + async osUiAddPrivateDomain(params: T.AddPrivateDomainParams): Promise { return this.rpcRequest({ method: 'server.host.address.domain.private.add', params, }) } - async osUiRemovePrivateDomain( - params: RR.OsUiRemovePrivateDomainReq, - ): Promise { + async osUiRemovePrivateDomain(params: T.RemoveDomainParams): Promise { return this.rpcRequest({ method: 'server.host.address.domain.private.remove', params, @@ -675,8 +653,8 @@ export class LiveApiService extends ApiService { } async pkgBindingSetAddressEnabled( - params: RR.PkgBindingSetAddressEnabledReq, - ): Promise { + params: PkgBindingSetAddressEnabledReq, + ): Promise { return this.rpcRequest({ method: 'package.host.binding.set-address-enabled', params, @@ -684,26 +662,22 @@ export class LiveApiService extends ApiService { } async pkgAddPublicDomain( - params: RR.PkgAddPublicDomainReq, - ): Promise { + params: PkgAddPublicDomainReq, + ): Promise { return this.rpcRequest({ method: 'package.host.address.domain.public.add', params, }) } - async pkgRemovePublicDomain( - params: RR.PkgRemovePublicDomainReq, - ): Promise { + async pkgRemovePublicDomain(params: PkgRemovePublicDomainReq): Promise { return this.rpcRequest({ method: 'package.host.address.domain.public.remove', params, }) } - async pkgAddPrivateDomain( - params: RR.PkgAddPrivateDomainReq, - ): Promise { + async pkgAddPrivateDomain(params: PkgAddPrivateDomainReq): Promise { return this.rpcRequest({ method: 'package.host.address.domain.private.add', params, @@ -711,8 +685,8 @@ export class LiveApiService extends ApiService { } async pkgRemovePrivateDomain( - params: RR.PkgRemovePrivateDomainReq, - ): Promise { + params: PkgRemovePrivateDomainReq, + ): Promise { return this.rpcRequest({ method: 'package.host.address.domain.private.remove', params, 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 f5d27493b..1fa4cb828 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 @@ -1,8 +1,14 @@ import { Injectable } from '@angular/core' -import { pauseFor, Log, RPCErrorDetails } from '@start9labs/shared' +import { + FullKeyboard, + pauseFor, + RPCErrorDetails, + SetLanguageParams, +} from '@start9labs/shared' import { ApiService } from './embassy-api.service' import { AddOperation, + Dump, Operation, PatchOp, pathFromArray, @@ -11,12 +17,32 @@ import { Revision, } from 'patch-db-client' import { + DataModel, InstallingState, PackageDataEntry, StateInfo, UpdatingState, } from 'src/app/services/patch-db/data-model' -import { CifsBackupTarget, RR } from './api.types' +import { GetPackageRes, GetPackagesRes } from '@start9labs/marketplace' +import { + ActionRes, + CifsBackupTarget, + DiagnosticErrorRes, + FollowPackageLogsReq, + FollowServerLogsReq, + GetActionInputRes, + GetPackageLogsReq, + GetRegistryPackageReq, + GetRegistryPackagesReq, + PkgAddPrivateDomainReq, + PkgAddPublicDomainReq, + PkgBindingSetAddressEnabledReq, + PkgRemovePrivateDomainReq, + PkgRemovePublicDomainReq, + ServerBindingSetAddressEnabledReq, + ServerState, + WebsocketConfig, +} from './api.types' import { Mock } from './api.fixures' import { from, interval, map, shareReplay, startWith, Subject, tap } from 'rxjs' import { mockPatchData } from './mock-patch' @@ -86,7 +112,7 @@ export class MockApiService extends ApiService { openWebsocket$( guid: string, - config: RR.WebsocketConfig = {}, + config: WebsocketConfig = {}, ): WebSocketSubject { if (guid === 'db-guid') { return this.mockWsSource$.pipe( @@ -121,7 +147,7 @@ export class MockApiService extends ApiService { // state - async echo(params: RR.EchoReq, url: string): Promise { + async echo(params: T.EchoParams, url: string): Promise { if (url) { const num = Math.floor(Math.random() * 10) + 1 if (num > 8) return params.message @@ -132,7 +158,7 @@ export class MockApiService extends ApiService { } private stateIndex = 0 - async getState(): Promise { + async getState(): Promise { await pauseFor(1000) this.stateIndex++ @@ -142,9 +168,10 @@ export class MockApiService extends ApiService { // db - async subscribeToPatchDB( - params: RR.SubscribePatchReq, - ): Promise { + async subscribeToPatchDB(params: {}): Promise<{ + dump: Dump + guid: string + }> { await pauseFor(2000) return { dump: { id: 1, value: mockPatchData }, @@ -155,9 +182,9 @@ export class MockApiService extends ApiService { async setDbValue( pathArr: Array, value: T, - ): Promise { + ): Promise { const pointer = pathFromArray(pathArr) - const params: RR.SetDBValueReq = { pointer, value } + const params = { pointer, value } await pauseFor(2000) const patch = [ { @@ -173,29 +200,27 @@ export class MockApiService extends ApiService { // auth - async login(params: RR.LoginReq): Promise { + async login(params: T.LoginParams): Promise { await pauseFor(2000) return null } - async logout(params: RR.LogoutReq): Promise { + async logout(params: {}): Promise { await pauseFor(2000) return null } - async getSessions(params: RR.GetSessionsReq): Promise { + async getSessions(params: {}): Promise { await pauseFor(2000) return Mock.Sessions } - async killSessions(params: RR.KillSessionsReq): Promise { + async killSessions(params: T.KillParams): Promise { await pauseFor(2000) return null } - async resetPassword( - params: RR.ResetPasswordReq, - ): Promise { + async resetPassword(params: T.ResetPasswordParams): Promise { await pauseFor(2000) return null } @@ -211,7 +236,7 @@ export class MockApiService extends ApiService { } } - async diagnosticGetError(): Promise { + async diagnosticGetError(): Promise { await pauseFor(1000) return { code: 15, @@ -232,15 +257,13 @@ export class MockApiService extends ApiService { await pauseFor(1000) } - async diagnosticGetLogs( - params: RR.GetServerLogsReq, - ): Promise { + async diagnosticGetLogs(params: T.LogsParams): Promise { return this.getServerLogs(params) } // init - async initFollowProgress(): Promise { + async initFollowProgress(): Promise { await pauseFor(250) return { progress: PROGRESS, @@ -248,7 +271,7 @@ export class MockApiService extends ApiService { } } - async initFollowLogs(): Promise { + async initFollowLogs(): Promise { await pauseFor(2000) return { startCursor: 'start-cursor', @@ -258,19 +281,15 @@ export class MockApiService extends ApiService { // server - async getSystemTime( - params: RR.GetSystemTimeReq, - ): Promise { + async getSystemTime(params: {}): Promise { await pauseFor(2000) return { now: new Date().toUTCString(), - uptime: 1234567, + uptime: 1234567n, } } - async getServerLogs( - params: RR.GetServerLogsReq, - ): Promise { + async getServerLogs(params: T.LogsParams): Promise { await pauseFor(2000) const entries = this.randomLogs(params.limit) @@ -281,9 +300,7 @@ export class MockApiService extends ApiService { } } - async getKernelLogs( - params: RR.GetServerLogsReq, - ): Promise { + async getKernelLogs(params: T.LogsParams): Promise { await pauseFor(2000) const entries = this.randomLogs(params.limit) @@ -295,8 +312,8 @@ export class MockApiService extends ApiService { } async followServerLogs( - params: RR.FollowServerLogsReq, - ): Promise { + params: FollowServerLogsReq, + ): Promise { await pauseFor(2000) return { startCursor: 'start-cursor', @@ -305,8 +322,8 @@ export class MockApiService extends ApiService { } async followKernelLogs( - params: RR.FollowServerLogsReq, - ): Promise { + params: FollowServerLogsReq, + ): Promise { await pauseFor(2000) return { startCursor: 'start-cursor', @@ -314,7 +331,7 @@ export class MockApiService extends ApiService { } } - private randomLogs(limit = 1): Log[] { + private randomLogs(limit = 1): T.LogEntry[] { const arrLength = Math.ceil(limit / Mock.ServerLogs.length) const logs = new Array(arrLength) .fill(Mock.ServerLogs) @@ -323,9 +340,7 @@ export class MockApiService extends ApiService { return logs } - async followServerMetrics( - params: RR.FollowServerMetricsReq, - ): Promise { + async followServerMetrics(params: {}): Promise { await pauseFor(2000) return { guid: 'metrics-guid', @@ -333,7 +348,10 @@ export class MockApiService extends ApiService { } } - async updateServer(params?: RR.UpdateServerReq): Promise { + async updateServer(params?: { + registry: string + targetVersion: string + }): Promise<'updating' | 'no-updates'> { await pauseFor(2000) const initialProgress = { size: null, @@ -356,9 +374,7 @@ export class MockApiService extends ApiService { return 'updating' } - async restartServer( - params: RR.RestartServerReq, - ): Promise { + async restartServer(params: {}): Promise { await pauseFor(2000) const patch = [ @@ -384,9 +400,7 @@ export class MockApiService extends ApiService { return null } - async shutdownServer( - params: RR.ShutdownServerReq, - ): Promise { + async shutdownServer(params: {}): Promise { await pauseFor(2000) const patch = [ @@ -412,7 +426,7 @@ export class MockApiService extends ApiService { return null } - async repairDisk(params: RR.RestartServerReq): Promise { + async repairDisk(params: {}): Promise { await pauseFor(2000) return null } @@ -432,7 +446,7 @@ export class MockApiService extends ApiService { return null } - async setKeyboard(params: RR.SetKeyboardReq): Promise { + async setKeyboard(params: FullKeyboard): Promise { await pauseFor(1000) const patch = [ @@ -447,7 +461,7 @@ export class MockApiService extends ApiService { return null } - async setLanguage(params: RR.SetLanguageReq): Promise { + async setLanguage(params: SetLanguageParams): Promise { await pauseFor(1000) const patch = [ @@ -462,7 +476,7 @@ export class MockApiService extends ApiService { return null } - async setDns(params: RR.SetDnsReq): Promise { + async setDns(params: T.SetStaticDnsParams): Promise { await pauseFor(2000) const patch: ReplaceOperation[] = [ @@ -477,15 +491,16 @@ export class MockApiService extends ApiService { return null } - async queryDns(params: RR.QueryDnsReq): Promise { + async queryDns(params: T.QueryDnsParams): Promise { await pauseFor(2000) return null } - async testPortForward( - params: RR.TestPortForwardReq, - ): Promise { + async testPortForward(params: { + gateway: string + port: number + }): Promise { await pauseFor(2000) return false @@ -493,23 +508,22 @@ export class MockApiService extends ApiService { // marketplace URLs - async checkOSUpdate( - params: RR.CheckOsUpdateReq, - ): Promise { + async checkOSUpdate(params: { + registry: string + serverId: string + }): Promise { await pauseFor(2000) return Mock.RegistryOSUpdate } - async getRegistryInfo( - params: RR.GetRegistryInfoReq, - ): Promise { + async getRegistryInfo(params: { registry: string }): Promise { await pauseFor(2000) return Mock.RegistryInfo } async getRegistryPackage( - params: RR.GetRegistryPackageReq, - ): Promise { + params: GetRegistryPackageReq, + ): Promise { await pauseFor(2000) const { targetVersion, id } = params @@ -522,8 +536,8 @@ export class MockApiService extends ApiService { } async getRegistryPackages( - params: RR.GetRegistryPackagesReq, - ): Promise { + params: GetRegistryPackagesReq, + ): Promise { await pauseFor(2000) return Mock.RegistryPackages } @@ -531,37 +545,35 @@ export class MockApiService extends ApiService { // notification async getNotifications( - params: RR.GetNotificationsReq, - ): Promise { + params: T.ListNotificationParams, + ): Promise { await pauseFor(2000) return Mock.Notifications } - async deleteNotifications( - params: RR.DeleteNotificationsReq, - ): Promise { + async deleteNotifications(params: T.ModifyNotificationParams): Promise { await pauseFor(2000) return null } async markSeenNotifications( - params: RR.MarkSeenNotificationReq, - ): Promise { + params: T.ModifyNotificationParams, + ): Promise { await pauseFor(2000) return null } async markSeenAllNotifications( - params: RR.MarkSeenAllNotificationsReq, - ): Promise { + params: T.ModifyNotificationBeforeParams, + ): Promise { await pauseFor(2000) return null } async markUnseenNotifications( - params: RR.MarkUnseenNotificationReq, - ): Promise { + params: T.ModifyNotificationParams, + ): Promise { await pauseFor(2000) return null } @@ -569,7 +581,7 @@ export class MockApiService extends ApiService { // proxies private proxyId = 0 - async addTunnel(params: RR.AddTunnelReq): Promise { + async addTunnel(params: T.AddTunnelParams): Promise<{ id: string }> { await pauseFor(2000) const id = `wg${this.proxyId++}` @@ -609,7 +621,7 @@ export class MockApiService extends ApiService { return { id } } - async updateTunnel(params: RR.UpdateTunnelReq): Promise { + async updateTunnel(params: T.RenameGatewayParams): Promise { await pauseFor(2000) const patch: ReplaceOperation[] = [ @@ -624,7 +636,7 @@ export class MockApiService extends ApiService { return null } - async removeTunnel(params: RR.RemoveTunnelReq): Promise { + async removeTunnel(params: T.RemoveTunnelParams): Promise { await pauseFor(2000) const patch: RemoveOperation[] = [ { @@ -637,9 +649,7 @@ export class MockApiService extends ApiService { return null } - async setDefaultOutbound( - params: RR.SetDefaultOutboundReq, - ): Promise { + async setDefaultOutbound(params: { gateway: string | null }): Promise { await pauseFor(2000) const patch = [ { @@ -653,9 +663,10 @@ export class MockApiService extends ApiService { return null } - async setServiceOutbound( - params: RR.SetServiceOutboundReq, - ): Promise { + async setServiceOutbound(params: { + packageId: string + gateway: string | null + }): Promise { await pauseFor(2000) const patch = [ { @@ -671,13 +682,13 @@ export class MockApiService extends ApiService { // wifi - async enableWifi(params: RR.EnabledWifiReq): Promise { + async enableWifi(params: T.SetWifiEnabledParams): Promise { await pauseFor(2000) const patch = [ { op: PatchOp.REPLACE, path: '/serverInfo/network/wifi/enabled', - value: params.enable, + value: params.enabled, }, ] this.mockRevision(patch) @@ -685,36 +696,34 @@ export class MockApiService extends ApiService { return null } - async setWifiCountry( - params: RR.SetWifiCountryReq, - ): Promise { + async setWifiCountry(params: T.SetCountryParams): Promise { await pauseFor(2000) return null } - async getWifi(params: RR.GetWifiReq): Promise { + async getWifi(params: {}, timeout: number): Promise { await pauseFor(2000) return Mock.Wifi } - async addWifi(params: RR.AddWifiReq): Promise { + async addWifi(params: T.WifiAddParams): Promise { await pauseFor(2000) return null } - async connectWifi(params: RR.ConnectWifiReq): Promise { + async connectWifi(params: T.WifiSsidParams): Promise { await pauseFor(2000) return null } - async deleteWifi(params: RR.DeleteWifiReq): Promise { + async deleteWifi(params: T.WifiSsidParams): Promise { await pauseFor(2000) return null } // smtp - async setSmtp(params: RR.SetSMTPReq): Promise { + async setSmtp(params: T.SmtpValue): Promise { await pauseFor(2000) const patch = [ { @@ -728,7 +737,7 @@ export class MockApiService extends ApiService { return null } - async clearSmtp(params: RR.ClearSMTPReq): Promise { + async clearSmtp(params: {}): Promise { await pauseFor(2000) const patch = [ { @@ -742,40 +751,40 @@ export class MockApiService extends ApiService { return null } - async testSmtp(params: RR.TestSMTPReq): Promise { + async testSmtp(params: T.TestSmtpParams): Promise { await pauseFor(2000) return null } // ssh - async getSshKeys(params: RR.GetSSHKeysReq): Promise { + async getSshKeys(params: {}): Promise { await pauseFor(2000) return Mock.SshKeys } - async addSshKey(params: RR.AddSSHKeyReq): Promise { + async addSshKey(params: T.SshAddParams): Promise { await pauseFor(2000) return Mock.SshKey } - async deleteSshKey(params: RR.DeleteSSHKeyReq): Promise { + async deleteSshKey(params: T.SshDeleteParams): Promise { await pauseFor(2000) return null } // backup - async getBackupTargets( - params: RR.GetBackupTargetsReq, - ): Promise { + async getBackupTargets(params: {}): Promise<{ + [id: string]: T.BackupTarget + }> { await pauseFor(2000) return Mock.BackupTargets } async addBackupTarget( - params: RR.AddBackupTargetReq, - ): Promise { + params: T.CifsAddParams, + ): Promise<{ [id: string]: CifsBackupTarget }> { await pauseFor(2000) const { hostname, path, username } = params return { @@ -791,8 +800,8 @@ export class MockApiService extends ApiService { } async updateBackupTarget( - params: RR.UpdateBackupTargetReq, - ): Promise { + params: T.CifsUpdateParams, + ): Promise<{ [id: string]: CifsBackupTarget }> { await pauseFor(2000) const { id, hostname, path, username } = params return { @@ -805,24 +814,20 @@ export class MockApiService extends ApiService { } } - async removeBackupTarget( - params: RR.RemoveBackupTargetReq, - ): Promise { + async removeBackupTarget(params: T.CifsRemoveParams): Promise { await pauseFor(2000) return null } - async getBackupInfo( - params: RR.GetBackupInfoReq, - ): Promise { + async getBackupInfo(params: T.InfoParams): Promise { await pauseFor(2000) return Mock.BackupInfo } - async createBackup(params: RR.CreateBackupReq): Promise { + async createBackup(params: T.BackupParams): Promise { await pauseFor(2000) const serverPath = '/serverInfo/statusInfo/backupProgress' - const ids = params.packageIds + const ids = params.packageIds || [] setTimeout(async () => { for (let i = 0; i < ids.length; i++) { @@ -978,9 +983,7 @@ export class MockApiService extends ApiService { // package - async getPackageLogs( - params: RR.GetPackageLogsReq, - ): Promise { + async getPackageLogs(params: GetPackageLogsReq): Promise { await pauseFor(2000) let entries if (Math.random() < 0.2) { @@ -1001,8 +1004,8 @@ export class MockApiService extends ApiService { } async followPackageLogs( - params: RR.FollowPackageLogsReq, - ): Promise { + params: FollowPackageLogsReq, + ): Promise { await pauseFor(2000) return { startCursor: 'start-cursor', @@ -1010,9 +1013,7 @@ export class MockApiService extends ApiService { } } - async installPackage( - params: RR.InstallPackageReq, - ): Promise { + async installPackage(params: T.InstallParams): Promise { await pauseFor(2000) setTimeout(async () => { @@ -1049,9 +1050,7 @@ export class MockApiService extends ApiService { return null } - async cancelInstallPackage( - params: RR.CancelInstallPackageReq, - ): Promise { + async cancelInstallPackage(params: T.CancelInstallParams): Promise { await pauseFor(500) const patch: RemoveOperation[] = [ @@ -1066,8 +1065,8 @@ export class MockApiService extends ApiService { } async getActionInput( - params: RR.GetActionInputReq, - ): Promise { + params: T.GetActionInputParams, + ): Promise { await pauseFor(2000) return { eventId: 'ANZXNWIFRTTBZ6T52KQPZILIQQODDHXQ', @@ -1076,7 +1075,7 @@ export class MockApiService extends ApiService { } } - async runAction(params: RR.ActionReq): Promise { + async runAction(params: T.RunActionParams): Promise { await pauseFor(2000) const patch: ReplaceOperation<{ [key: string]: T.TaskEntry }>[] = [ @@ -1093,7 +1092,7 @@ export class MockApiService extends ApiService { // return Mock.ActionResSingle } - async clearTask(params: RR.ClearTaskReq): Promise { + async clearTask(params: T.ClearTaskParams): Promise { await pauseFor(2000) const patch: RemoveOperation[] = [ @@ -1107,9 +1106,7 @@ export class MockApiService extends ApiService { return null } - async restorePackages( - params: RR.RestorePackagesReq, - ): Promise { + async restorePackages(params: T.RestorePackageParams): Promise { await pauseFor(2000) const patch: AddOperation[] = params.ids.map(id => { setTimeout(async () => { @@ -1137,7 +1134,7 @@ export class MockApiService extends ApiService { return null } - async startPackage(params: RR.StartPackageReq): Promise { + async startPackage(params: T.ControlParams): Promise { const path = `/packageData/${params.id}/statusInfo` await pauseFor(2000) @@ -1202,9 +1199,7 @@ export class MockApiService extends ApiService { return null } - async restartPackage( - params: RR.RestartPackageReq, - ): Promise { + async restartPackage(params: T.ControlParams): Promise { await pauseFor(2000) const path = `/packageData/${params.id}/statusInfo` @@ -1268,7 +1263,7 @@ export class MockApiService extends ApiService { return null } - async stopPackage(params: RR.StopPackageReq): Promise { + async stopPackage(params: T.ControlParams): Promise { await pauseFor(2000) const path = `/packageData/${params.id}/statusInfo` @@ -1306,15 +1301,11 @@ export class MockApiService extends ApiService { return null } - async rebuildPackage( - params: RR.RebuildPackageReq, - ): Promise { + async rebuildPackage(params: T.RebuildParams): Promise { return this.restartPackage(params) } - async uninstallPackage( - params: RR.UninstallPackageReq, - ): Promise { + async uninstallPackage(params: T.UninstallParams): Promise { await pauseFor(2000) setTimeout(async () => { @@ -1340,7 +1331,7 @@ export class MockApiService extends ApiService { return null } - async sideloadPackage(): Promise { + async sideloadPackage(): Promise { await pauseFor(2000) return { upload: 'sideload-upload-guid', // no significance, randomly generated @@ -1364,7 +1355,7 @@ export class MockApiService extends ApiService { // return null // } - async initAcme(params: RR.InitAcmeReq): Promise { + async initAcme(params: T.InitAcmeParams): Promise { await pauseFor(2000) const patch = [ @@ -1381,7 +1372,7 @@ export class MockApiService extends ApiService { return null } - async removeAcme(params: RR.RemoveAcmeReq): Promise { + async removeAcme(params: T.RemoveAcmeParams): Promise { await pauseFor(2000) const regex = new RegExp('/', 'g') @@ -1398,8 +1389,8 @@ export class MockApiService extends ApiService { } async serverBindingSetAddressEnabled( - params: RR.ServerBindingSetAddressEnabledReq, - ): Promise { + params: ServerBindingSetAddressEnabledReq, + ): Promise { await pauseFor(2000) const basePath = `/serverInfo/network/host/bindings/${params.internalPort}/addresses` @@ -1409,8 +1400,8 @@ export class MockApiService extends ApiService { } async osUiAddPublicDomain( - params: RR.OsUiAddPublicDomainReq, - ): Promise { + params: T.AddPublicDomainParams, + ): Promise { await pauseFor(2000) const patch: Operation[] = [ @@ -1438,9 +1429,7 @@ export class MockApiService extends ApiService { return null } - async osUiRemovePublicDomain( - params: RR.OsUiRemovePublicDomainReq, - ): Promise { + async osUiRemovePublicDomain(params: T.RemoveDomainParams): Promise { await pauseFor(2000) const patch: RemoveOperation[] = [ @@ -1454,9 +1443,7 @@ export class MockApiService extends ApiService { return null } - async osUiAddPrivateDomain( - params: RR.OsUiAddPrivateDomainReq, - ): Promise { + async osUiAddPrivateDomain(params: T.AddPrivateDomainParams): Promise { await pauseFor(2000) const patch: Operation[] = [ @@ -1482,9 +1469,7 @@ export class MockApiService extends ApiService { return null } - async osUiRemovePrivateDomain( - params: RR.OsUiRemovePrivateDomainReq, - ): Promise { + async osUiRemovePrivateDomain(params: T.RemoveDomainParams): Promise { await pauseFor(2000) const patch: RemoveOperation[] = [ @@ -1499,8 +1484,8 @@ export class MockApiService extends ApiService { } async pkgBindingSetAddressEnabled( - params: RR.PkgBindingSetAddressEnabledReq, - ): Promise { + params: PkgBindingSetAddressEnabledReq, + ): Promise { await pauseFor(2000) const basePath = `/packageData/${params.package}/hosts/${params.host}/bindings/${params.internalPort}/addresses` @@ -1510,8 +1495,8 @@ export class MockApiService extends ApiService { } async pkgAddPublicDomain( - params: RR.PkgAddPublicDomainReq, - ): Promise { + params: PkgAddPublicDomainReq, + ): Promise { await pauseFor(2000) const patch: Operation[] = [ @@ -1539,9 +1524,7 @@ export class MockApiService extends ApiService { return null } - async pkgRemovePublicDomain( - params: RR.PkgRemovePublicDomainReq, - ): Promise { + async pkgRemovePublicDomain(params: PkgRemovePublicDomainReq): Promise { await pauseFor(2000) const patch: RemoveOperation[] = [ @@ -1555,9 +1538,7 @@ export class MockApiService extends ApiService { return null } - async pkgAddPrivateDomain( - params: RR.PkgAddPrivateDomainReq, - ): Promise { + async pkgAddPrivateDomain(params: PkgAddPrivateDomainReq): Promise { await pauseFor(2000) const patch: Operation[] = [ @@ -1584,8 +1565,8 @@ export class MockApiService extends ApiService { } async pkgRemovePrivateDomain( - params: RR.PkgRemovePrivateDomainReq, - ): Promise { + params: PkgRemovePrivateDomainReq, + ): Promise { await pauseFor(2000) const patch: RemoveOperation[] = [ 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 e3f7e9834..a98ea6b85 100644 --- a/web/projects/ui/src/app/services/api/mock-patch.ts +++ b/web/projects/ui/src/app/services/api/mock-patch.ts @@ -110,6 +110,7 @@ export const mockPatchData: DataModel = { }, publicDomains: {}, privateDomains: {}, + portForwards: [], }, gateways: { eth0: { @@ -607,6 +608,7 @@ export const mockPatchData: DataModel = { privateDomains: { 'my-bitcoin.home': ['wlan0'], }, + portForwards: [], }, bcdefgh: { bindings: { @@ -648,6 +650,7 @@ export const mockPatchData: DataModel = { }, publicDomains: {}, privateDomains: {}, + portForwards: [], }, cdefghi: { bindings: { @@ -671,6 +674,7 @@ export const mockPatchData: DataModel = { }, publicDomains: {}, privateDomains: {}, + portForwards: [], }, }, storeExposedDependents: [], diff --git a/web/projects/ui/src/app/services/marketplace.service.ts b/web/projects/ui/src/app/services/marketplace.service.ts index aa1b37eb0..b5bfec34a 100644 --- a/web/projects/ui/src/app/services/marketplace.service.ts +++ b/web/projects/ui/src/app/services/marketplace.service.ts @@ -28,7 +28,6 @@ import { switchMap, tap, } from 'rxjs' -import { RR } from 'src/app/services/api/api.types' import { ApiService } from 'src/app/services/api/embassy-api.service' import { DataModel } from 'src/app/services/patch-db/data-model' @@ -247,7 +246,7 @@ export class MarketplaceService { version: string, url: string, ): Promise { - const params: RR.InstallPackageReq = { + const params: T.InstallParams = { id, version, registry: url, diff --git a/web/projects/ui/src/app/services/os.service.ts b/web/projects/ui/src/app/services/os.service.ts index 422ce1643..0c5fb57cb 100644 --- a/web/projects/ui/src/app/services/os.service.ts +++ b/web/projects/ui/src/app/services/os.service.ts @@ -10,8 +10,7 @@ import { import { ApiService } from 'src/app/services/api/embassy-api.service' import { getServerInfo } from 'src/app/utils/get-server-info' import { DataModel } from './patch-db/data-model' -import { Version } from '@start9labs/start-sdk' -import { RR } from './api/api.types' +import { T, Version } from '@start9labs/start-sdk' @Injectable({ providedIn: 'root', @@ -20,7 +19,7 @@ export class OSService { private readonly api = inject(ApiService) private readonly patch = inject>(PatchDB) - osUpdate?: RR.CheckOsUpdateRes + osUpdate?: T.OsVersionInfoMap readonly updateAvailable$ = new BehaviorSubject(false) readonly updating$ = this.patch.watch$('serverInfo', 'statusInfo').pipe( diff --git a/web/projects/ui/src/app/services/standard-actions.service.ts b/web/projects/ui/src/app/services/standard-actions.service.ts index 5cd002139..4d645e8d3 100644 --- a/web/projects/ui/src/app/services/standard-actions.service.ts +++ b/web/projects/ui/src/app/services/standard-actions.service.ts @@ -15,7 +15,6 @@ import { getAllPackages } from '../utils/get-package-data' import { hasCurrentDeps } from '../utils/has-deps' import { ApiService } from './api/embassy-api.service' import { DataModel } from './patch-db/data-model' -import { RR } from './api/api.types' @Injectable({ providedIn: 'root', @@ -78,7 +77,7 @@ export class StandardActionsService { .subscribe(() => this.doUninstall({ id, force, soft })) } - private async doUninstall(options: RR.UninstallPackageReq) { + private async doUninstall(options: T.UninstallParams) { const loader = this.loader.open('Beginning uninstall').subscribe() try { diff --git a/web/projects/ui/src/app/services/state.service.ts b/web/projects/ui/src/app/services/state.service.ts index 162031df6..d21c0f679 100644 --- a/web/projects/ui/src/app/services/state.service.ts +++ b/web/projects/ui/src/app/services/state.service.ts @@ -26,7 +26,7 @@ import { takeUntil, tap, } from 'rxjs/operators' -import { RR } from 'src/app/services/api/api.types' +import { ServerState } from 'src/app/services/api/api.types' import { ApiService } from 'src/app/services/api/embassy-api.service' import { NetworkService } from 'src/app/services/network.service' @@ -56,7 +56,7 @@ class DisconnectedToast {} @Injectable({ providedIn: 'root', }) -export class StateService extends Observable { +export class StateService extends Observable { private readonly alerts = inject(TuiAlertService) private readonly i18n = inject(i18nPipe) private readonly api = inject(ApiService) @@ -115,7 +115,7 @@ export class StateService extends Observable { setTimeout(() => this.trigger$.next(gracefully), delay) } - private handleState(state: RR.ServerState): void { + private handleState(state: ServerState): void { switch (state) { case 'initializing': this.router.navigate(['initializing'], { replaceUrl: true }) @@ -136,7 +136,7 @@ export class StateService extends Observable { } } -export function stateNot(state: RR.ServerState[]): CanActivateFn { +export function stateNot(state: ServerState[]): CanActivateFn { return () => inject(StateService).pipe( filter(current => !current || !state.includes(current)), diff --git a/web/projects/ui/src/app/services/time.service.ts b/web/projects/ui/src/app/services/time.service.ts index bd088242a..6107a212f 100644 --- a/web/projects/ui/src/app/services/time.service.ts +++ b/web/projects/ui/src/app/services/time.service.ts @@ -12,14 +12,15 @@ export class TimeService { private readonly time$ = defer(() => inject(ApiService).getSystemTime({}), ).pipe( - switchMap(({ now, uptime }) => - timer(0, 1000).pipe( + switchMap(({ now, uptime }) => { + const uptimeSecs = Number(uptime) + return timer(0, 1000).pipe( map(index => ({ now: new Date(now).valueOf() + 1000 * index, - uptime: uptime + index, + uptime: uptimeSecs + index, })), - ), - ), + ) + }), shareReplay(1), )