Skip to content

IPC types: generate TypeScript types for the DTOs and the Feature enum from Rust; CI checks they are up to date #919

Open

Description

@smart-ssh-planner

Goal

The TypeScript types for the IPC DTOs are generated from the Rust definitions, so a renamed or added field shows up as a type error in the frontend instead of a runtime undefined.

Context

  • apps/smart-ssh-community/frontend/src/types.ts (≈ 1,650 lines, 159 exported types) is written by hand and mirrors crates/app-logic/src/dto.rs (66 top-level types) plus types defined in command modules. types.test.ts only tests supportsModelDiscovery.
  • src/extensions/entitlements.ts:6-25 copies the Feature enum of ssh_manager_core::entitlements by hand.
  • No code generator (ts-rs, specta, typeshare) is used anywhere.
  • app-logic must stay free of Tauri in its whole dependency tree (Spec 0084 A3/T4, checked in CI).
  • Serde attributes matter: most DTOs are #[serde(rename_all = "camelCase")], ProviderType uses per-variant rename (snake_case).

Requirements

  • Use ts-rs (Tauri-free, derive-based) behind a cargo feature (e.g. ts-export) in app-logic and ssh_manager_core, so normal builds do not compile it. Alternative generators are fine if they keep app-logic Tauri-free and honour serde attributes.
  • Derive the export for every type in dto.rs, for DTOs defined in command modules that cross IPC, and for Feature/Tier/Entitlements/FeatureLocked.
  • Generate into one checked-in file src/generated/ipc.ts (header: "generated – do not edit", plus the command to regenerate). A script npm run gen:ipc (calls cargo test -p app-logic --features ts-export export_bindings or equivalent) regenerates it.
  • types.ts re-exports the generated types under their existing names (so imports do not change) and keeps only hand-written helpers (type guards, functions like supportsModelDiscovery). Where the generated type differs from the hand-written one, the generated one wins; fix frontend code accordingly (these are real mismatches – list them in the PR).
  • entitlements.ts uses the generated Feature. If feature ids are extensible at that point (registered by extensions), the generated union covers the core's ids and the TS type accepts registered string ids as well.
  • CI: a check (part of npm run lint or a Rust test) fails when regenerating changes src/generated/ipc.ts. If this needs a .github/ change, describe it exactly in the PR (file, job, step).

Acceptance Criteria

  • src/generated/ipc.ts exists and covers every type in dto.rs and Feature/Tier; types.ts no longer hand-writes them.
  • Renaming a field of a DTO in Rust without regenerating fails the check; after regenerating, the frontend type-check fails where the field is used (demonstrated in the PR on a scratch commit, then reverted).
  • app-logic stays Tauri-free (existing CI check passes); cargo build --workspace without the feature does not compile ts-rs.
  • Mismatches found between old hand-written and generated types are listed in the PR and fixed.
  • npm run lint, type-check, npm test, cargo test --workspace pass.

Technical Notes

  • Large but mostly mechanical. Do the DTO module by sub-module if it has been split (dto/…).
  • DTOs that carry secrets as input (#[derive(Debug)] input DTOs with passwords/keys) must keep their redaction rules; generation must not add Debug or logging (.claude/skills/smart-ssh-coder/references/security-invariants.md).

Spec impact: none

Related Work

Activity

  1. added this to the 0.8.0 milestone on Oct 26, 2026
  2. 3 remaining items

  3. marked this as blocked by 15 issues on Oct 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    frontendFrontend (React/TypeScript)

    Type

    Fields

    Priority

    P2 - Normal

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions