From 339e5f799a27600459a8f6007cded423524069db Mon Sep 17 00:00:00 2001 From: Matt Hill Date: Thu, 12 Feb 2026 11:32:29 -0700 Subject: [PATCH] build ts types and fix i18n --- agents/TODO.md | 33 +++++++++++++++++++ core/build/build-ts.sh | 4 +-- sdk/base/lib/osBindings/AddTunnelParams.ts | 8 ++++- sdk/base/lib/osBindings/DerivedAddressInfo.ts | 4 +-- sdk/base/lib/osBindings/GatewayType.ts | 3 ++ sdk/base/lib/osBindings/NetworkInfo.ts | 1 + .../lib/osBindings/NetworkInterfaceInfo.ts | 3 +- sdk/base/lib/osBindings/PackageDataEntry.ts | 1 + sdk/base/lib/osBindings/PackageInfoShort.ts | 3 +- sdk/base/lib/osBindings/index.ts | 1 + .../shared/src/i18n/dictionaries/de.ts | 1 + .../shared/src/i18n/dictionaries/en.ts | 7 ++-- .../shared/src/i18n/dictionaries/es.ts | 1 + .../shared/src/i18n/dictionaries/fr.ts | 1 + .../shared/src/i18n/dictionaries/pl.ts | 1 + .../routes/gateways/gateways.component.ts | 2 +- .../system/routes/gateways/item.component.ts | 4 +-- 17 files changed, 65 insertions(+), 13 deletions(-) create mode 100644 sdk/base/lib/osBindings/GatewayType.ts diff --git a/agents/TODO.md b/agents/TODO.md index cabae12fb..2c3f67315 100644 --- a/agents/TODO.md +++ b/agents/TODO.md @@ -217,6 +217,39 @@ Pending tasks for AI agents. Remove items when completed. | `sdk/base/lib/interfaces/Host.ts` | SDK `MultiHost.bindPort()` — no changes needed | | `core/src/db/model/public.rs` | Public DB model — port forward mapping | +- [ ] Extract TS-exported types into a lightweight sub-crate for fast binding generation + + **Problem**: `make ts-bindings` compiles the entire `start-os` crate (with all dependencies: tokio, + axum, openssl, etc.) just to run test functions that serialize type definitions to `.ts` files. + Even in debug mode, this takes minutes. The generated output is pure type info — no runtime code + is needed. + + **Goal**: Generate TS bindings in seconds by isolating exported types in a small crate with minimal + dependencies. + + **Approach**: Create a `core/bindings-types/` sub-crate containing (or re-exporting) all 168 + `#[ts(export)]` types. This crate depends only on `serde`, `ts-rs`, `exver`, and other type-only + crates — not on tokio, axum, openssl, etc. Then `build-ts.sh` runs `cargo test -p bindings-types` + instead of `cargo test -p start-os`. + + **Challenge**: The exported types are scattered across `core/src/` and reference each other and + other crate types. Extracting them requires either moving the type definitions into the sub-crate + (and importing them back into `start-os`) or restructuring to share a common types crate. + +- [ ] Use auto-generated RPC types in the frontend instead of manual duplicates + + **Problem**: The web frontend manually defines ~755 lines of API request/response types in + `web/projects/ui/src/app/services/api/api.types.ts` that can drift from the actual Rust types. + + **Current state**: The Rust backend already has `#[ts(export)]` on RPC param types (e.g. + `AddTunnelParams`, `SetWifiEnabledParams`, `LoginParams`), and they are generated into + `core/bindings/`. However, commit `71b83245b` ("Chore/unexport api ts #2585", April 2024) + deliberately stopped building them into the SDK and had the frontend maintain its own types. + + **Goal**: Reverse that decision — pipe the generated RPC types through the SDK into the frontend + so `api.types.ts` can import them instead of duplicating them. This eliminates drift between + backend and frontend API contracts. + - [ ] Auto-configure port forwards via UPnP/NAT-PMP/PCP - @dr-bonez **Blocked by**: "Support preferred external ports besides 443" (must be implemented and tested diff --git a/core/build/build-ts.sh b/core/build/build-ts.sh index ad808310a..9f659af24 100755 --- a/core/build/build-ts.sh +++ b/core/build/build-ts.sh @@ -7,7 +7,7 @@ source ./builder-alias.sh set -ea shopt -s expand_aliases -PROFILE=${PROFILE:-release} +PROFILE=${PROFILE:-debug} if [ "${PROFILE}" = "release" ]; then BUILD_FLAGS="--release" else @@ -38,7 +38,7 @@ if [[ "${ENVIRONMENT}" =~ (^|-)console($|-) ]]; then fi echo "FEATURES=\"$FEATURES\"" echo "RUSTFLAGS=\"$RUSTFLAGS\"" -rust-zig-builder cargo test --manifest-path=./core/Cargo.toml $BUILD_FLAGS --features test,$FEATURES --locked 'export_bindings_' +rust-zig-builder cargo test --manifest-path=./core/Cargo.toml --lib $BUILD_FLAGS --features test,$FEATURES --locked 'export_bindings_' if [ "$(ls -nd "core/bindings" | awk '{ print $3 }')" != "$UID" ]; then rust-zig-builder sh -c "chown -R $UID:$UID core/target && chown -R $UID:$UID core/bindings && chown -R $UID:$UID /usr/local/cargo" fi \ No newline at end of file diff --git a/sdk/base/lib/osBindings/AddTunnelParams.ts b/sdk/base/lib/osBindings/AddTunnelParams.ts index 018b22bb5..639a4e36a 100644 --- a/sdk/base/lib/osBindings/AddTunnelParams.ts +++ b/sdk/base/lib/osBindings/AddTunnelParams.ts @@ -1,3 +1,9 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { GatewayType } from './GatewayType' -export type AddTunnelParams = { name: string; config: string; public: boolean } +export type AddTunnelParams = { + name: string + config: string + type: GatewayType | null + setAsDefaultOutbound: boolean +} diff --git a/sdk/base/lib/osBindings/DerivedAddressInfo.ts b/sdk/base/lib/osBindings/DerivedAddressInfo.ts index 2c83191fd..19926d44a 100644 --- a/sdk/base/lib/osBindings/DerivedAddressInfo.ts +++ b/sdk/base/lib/osBindings/DerivedAddressInfo.ts @@ -3,11 +3,11 @@ import type { HostnameInfo } from './HostnameInfo' export type DerivedAddressInfo = { /** - * User-controlled: private-gateway addresses the user has disabled + * User-controlled: private addresses the user has disabled */ privateDisabled: Array /** - * User-controlled: public-gateway addresses the user has enabled + * User-controlled: public addresses the user has enabled */ publicEnabled: Array /** diff --git a/sdk/base/lib/osBindings/GatewayType.ts b/sdk/base/lib/osBindings/GatewayType.ts new file mode 100644 index 000000000..aa7a2d6ed --- /dev/null +++ b/sdk/base/lib/osBindings/GatewayType.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 GatewayType = 'inbound-outbound' | 'outbound-only' diff --git a/sdk/base/lib/osBindings/NetworkInfo.ts b/sdk/base/lib/osBindings/NetworkInfo.ts index 5debd58d1..3acfb3851 100644 --- a/sdk/base/lib/osBindings/NetworkInfo.ts +++ b/sdk/base/lib/osBindings/NetworkInfo.ts @@ -13,4 +13,5 @@ export type NetworkInfo = { gateways: { [key: GatewayId]: NetworkInterfaceInfo } acme: { [key: AcmeProvider]: AcmeSettings } dns: DnsSettings + defaultOutbound: string | null } diff --git a/sdk/base/lib/osBindings/NetworkInterfaceInfo.ts b/sdk/base/lib/osBindings/NetworkInterfaceInfo.ts index dd3be99d9..a57f3c1e9 100644 --- a/sdk/base/lib/osBindings/NetworkInterfaceInfo.ts +++ b/sdk/base/lib/osBindings/NetworkInterfaceInfo.ts @@ -1,9 +1,10 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { GatewayType } from './GatewayType' import type { IpInfo } from './IpInfo' export type NetworkInterfaceInfo = { name: string | null - public: boolean | null secure: boolean | null ipInfo: IpInfo | null + type: GatewayType | null } diff --git a/sdk/base/lib/osBindings/PackageDataEntry.ts b/sdk/base/lib/osBindings/PackageDataEntry.ts index 05188c792..a0ea2fff7 100644 --- a/sdk/base/lib/osBindings/PackageDataEntry.ts +++ b/sdk/base/lib/osBindings/PackageDataEntry.ts @@ -25,4 +25,5 @@ export type PackageDataEntry = { serviceInterfaces: { [key: ServiceInterfaceId]: ServiceInterface } hosts: Hosts storeExposedDependents: string[] + outboundGateway: string | null } diff --git a/sdk/base/lib/osBindings/PackageInfoShort.ts b/sdk/base/lib/osBindings/PackageInfoShort.ts index 22c7fbea4..0bf858781 100644 --- a/sdk/base/lib/osBindings/PackageInfoShort.ts +++ b/sdk/base/lib/osBindings/PackageInfoShort.ts @@ -1,3 +1,4 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { LocaleString } from './LocaleString' -export type PackageInfoShort = { releaseNotes: string } +export type PackageInfoShort = { releaseNotes: LocaleString } diff --git a/sdk/base/lib/osBindings/index.ts b/sdk/base/lib/osBindings/index.ts index 18cca9c9a..5dc4d2865 100644 --- a/sdk/base/lib/osBindings/index.ts +++ b/sdk/base/lib/osBindings/index.ts @@ -85,6 +85,7 @@ export { FullIndex } from './FullIndex' export { FullProgress } from './FullProgress' export { GatewayId } from './GatewayId' export { GatewayInfo } from './GatewayInfo' +export { GatewayType } from './GatewayType' export { GetActionInputParams } from './GetActionInputParams' export { GetContainerIpParams } from './GetContainerIpParams' export { GetHostInfoParams } from './GetHostInfoParams' diff --git a/web/projects/shared/src/i18n/dictionaries/de.ts b/web/projects/shared/src/i18n/dictionaries/de.ts index 8f5c3d0ee..c9bd6f38c 100644 --- a/web/projects/shared/src/i18n/dictionaries/de.ts +++ b/web/projects/shared/src/i18n/dictionaries/de.ts @@ -691,4 +691,5 @@ export default { 726: '', 727: '', 728: '', + 729: '', } satisfies i18n diff --git a/web/projects/shared/src/i18n/dictionaries/en.ts b/web/projects/shared/src/i18n/dictionaries/en.ts index 2878444ae..a121cfea8 100644 --- a/web/projects/shared/src/i18n/dictionaries/en.ts +++ b/web/projects/shared/src/i18n/dictionaries/en.ts @@ -563,7 +563,7 @@ export const ENGLISH: Record = { 'Requires setting a static IP address for': 591, // this is a partial sentence. An IP address will be added after "for" to complete the sentence. 'Ideal for VPN access via': 592, // this is a partial sentence. A connection medium will be added after "via" to complete the sentence. 'in your gateway': 593, // this is a partial sentence. It is preceded by an instruction: e.g. "do something" in your gateway. Gateway refers to a router or VPN server. - "your router's Wireguard server": 594, // this is a partial sentence. It is preceded by "ideal for access via" + "your router's WireGuard server": 594, // this is a partial sentence. It is preceded by "ideal for access via" 'Requires port forwarding in gateway': 595, 'Requires a DNS record for': 596, // this is a partial sentence. A domain name will be added after "for" to complete the sentence. 'that resolves to': 597, // this is a partial sentence. It is preceded by "requires a DNS record for [domain] " @@ -681,14 +681,15 @@ export const ENGLISH: Record = { 'Continue to Setup': 716, 'Set Outbound Gateway': 717, 'Current': 718, - 'System default)': 719, + 'System default': 719, 'Outbound Gateway': 720, 'Select the gateway for outbound traffic': 721, 'The type of gateway': 722, 'Outbound Only': 723, 'Set as default outbound': 724, 'Route all outbound traffic through this gateway': 725, - 'Wireguard Config File': 726, + 'WireGuard Config File': 726, 'Inbound/Outbound': 727, 'StartTunnel (Inbound/Outbound)': 728, + 'Ethernet': 729 } diff --git a/web/projects/shared/src/i18n/dictionaries/es.ts b/web/projects/shared/src/i18n/dictionaries/es.ts index c143992f0..a2e6b42ab 100644 --- a/web/projects/shared/src/i18n/dictionaries/es.ts +++ b/web/projects/shared/src/i18n/dictionaries/es.ts @@ -691,4 +691,5 @@ export default { 726: '', 727: '', 728: '', + 729: '', } satisfies i18n diff --git a/web/projects/shared/src/i18n/dictionaries/fr.ts b/web/projects/shared/src/i18n/dictionaries/fr.ts index 85a052194..ffb25d7f4 100644 --- a/web/projects/shared/src/i18n/dictionaries/fr.ts +++ b/web/projects/shared/src/i18n/dictionaries/fr.ts @@ -691,4 +691,5 @@ export default { 726: '', 727: '', 728: '', + 729: '', } satisfies i18n diff --git a/web/projects/shared/src/i18n/dictionaries/pl.ts b/web/projects/shared/src/i18n/dictionaries/pl.ts index bd8fd59df..09562f285 100644 --- a/web/projects/shared/src/i18n/dictionaries/pl.ts +++ b/web/projects/shared/src/i18n/dictionaries/pl.ts @@ -691,4 +691,5 @@ export default { 726: '', 727: '', 728: '', + 729: '', } satisfies i18n 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 027803fe3..983d9a4a0 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 @@ -93,7 +93,7 @@ export default class GatewaysComponent { }, }), config: ISB.Value.union({ - name: this.i18n.transform('Wireguard Config File'), + name: this.i18n.transform('WireGuard Config File'), default: 'paste', variants: ISB.Variants.of({ paste: { diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/gateways/item.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/gateways/item.component.ts index 14f63662d..7ace53401 100644 --- a/web/projects/ui/src/app/routes/portal/routes/system/routes/gateways/item.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/gateways/item.component.ts @@ -49,7 +49,7 @@ import { TuiBadge } from '@taiga-ui/kit' } @case ('wireguard') { - {{ 'WireGuard' | i18n }} + WireGuard' } @default { {{ gateway.ipInfo.deviceType }} @@ -99,7 +99,7 @@ import { TuiBadge } from '@taiga-ui/kit' iconStart="@tui.arrow-up-right" (click)="setDefaultOutbound()" > - {{ 'Set as Default Outbound' | i18n }} + {{ 'Set as default outbound' | i18n }} }