NYM-1199: fix @nymproject/types generation gap (export NodeAnnotation deps)

The generated NodeAnnotationV1/V2.ts imported DetailedNodePerformanceV1/V2,
DisplayRole, RoutingScore, ConfigScore and StressTestingScore, but those types
(all of which derive ts_rs::TS with an export_to) were missing from
tools/ts-rs-cli, so the files were never emitted — leaving dangling imports that
broke `tsc` for the whole @nymproject/types package.

Add the 6 types to ts-rs-cli (use + do_export!) and regenerate. The package now
builds with 0 tsc errors, and the full nym-wallet Jest run goes from "84 pass +
4 suites unable to run" to 101 pass / 0 fail — recovering delegationIdentity and
unbondedDelegation.acceptance. The 3 touched FamilyInvitation*/PastFamilyInvitation
files are doc-comment syncs from the regeneration (the `at: number` overrides and
enum variants are unchanged).

Out of scope / still failing for a separate reason: api/nodeStatus.test.ts and
api/networkOverview.test.ts reference the network value 'QA', which the Network
enum (nym-wallet-types → SANDBOX | MAINNET) no longer includes — an app-code
drift unrelated to families or type generation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Yana Matrosova
2026-06-10 18:57:13 +03:00
parent fcc4cbceea
commit ec51855500
11 changed files with 74 additions and 13 deletions
@@ -35,7 +35,7 @@
## 6. Verify & docs
- [~] 6.1 **Families work is regression-free:** `cargo build` + `cargo clippy` clean; families code has no tsc errors; the contract-shape guard passes; families Jest suites green (43); full Jest run = **84 tests pass, 0 fail**. **Pre-existing, out-of-scope blocker:** 4 suites (`delegationIdentity`, `unbondedDelegation.acceptance`, `api/networkOverview`, `api/nodeStatus`) fail to *run* because the local `@nymproject/types` `dist` is stale and the package can't be rebuilt — its source has dangling imports to never-generated sibling types (`DetailedNodePerformanceV1`, `DisplayRole`) and a `Network`/`DelegationWithEverything` shape mismatch. None touch families; my uncommitted diff is entirely family-scoped (verified). Fixing the types-package generation gap is a separate change. Mock Tier-1 Playwright unaffected by the family type changes (mock path untouched).
- [~] 6.1 **Families work is regression-free; types-package generation gap fixed.** `cargo build` + `cargo clippy` clean; families code has no tsc errors; the contract-shape guard passes. Fixed the `@nymproject/types` build: `NodeAnnotationV1/V2` generated imports for `DetailedNodePerformanceV1/V2`, `DisplayRole`, `RoutingScore`, `ConfigScore`, `StressTestingScore` dangled because those (TS-deriving) types weren't in `tools/ts-rs-cli`; added them + regenerated → `tsc` builds the package with **0 errors**. Full wallet Jest now **101 pass, 0 fail** (was 84 + 4 suites unable to run); the two recovered suites are `delegationIdentity` + `unbondedDelegation.acceptance`. **Remaining (separate, out-of-scope, pre-existing):** `api/nodeStatus.test.ts` + `api/networkOverview.test.ts` fail to compile because `src/api/{nodeStatus,networkOverview}.ts` + their tests reference `'QA'`, which the source-of-truth `Network` enum (`nym-wallet-types`, → `SANDBOX | MAINNET`) doesn't include — an app-code drift unrelated to families or type generation; needs a product call (drop `QA` from the app code vs re-add it to `Network`). Mock Tier-1 Playwright unaffected (mock path untouched).
- [x] 6.2 Confirmed against the deployed contract source: `ExecuteMsg::UpdateFamily { updated_name: Option<String>, updated_description: Option<String> }` (`node-families-contract/src/msg.rs`) — matches the `update_family` command + frontend `UpdateFamilyArgs` + parent §9.5.
- [x] 6.3 Documented the real-IPC path in `e2e/README.md`: a "Real IPC layer (what the mock stands in for)" section (the 18 commands, the contract→wallet IPC-boundary translations, the mock→real provider switch) plus "Tier 3 — Sandbox real-IPC read smoke" and the guarded write-flow procedure (dedicated funded sandbox account, mnemonic via secret, target-only-self + cleanup).
- [x] 6.4 Updated parent change `node-families-wallet` §9.4 to `[~]` "Realised by the `node-families-real-ipc` change" with a pointer to this change's Rust command layer + provider wiring.
+13 -5
View File
@@ -1,11 +1,12 @@
#![allow(deprecated)]
use nym_api_requests::models::{
AnnotationResponseV1, AnnotationResponseV2, DeclaredRolesV1, DescribedNodeTypeV1,
GatewayCoreStatusResponse, HistoricalPerformanceResponse, HistoricalUptimeResponse,
MixnodeCoreStatusResponse, MixnodeStatus, MixnodeStatusResponse, NodeAnnotationV1,
NodeAnnotationV2, NodeDatePerformanceResponse, NodePerformanceResponse,
PerformanceHistoryResponse, StakeSaturationResponse, UptimeHistoryResponse,
AnnotationResponseV1, AnnotationResponseV2, ConfigScore, DeclaredRolesV1, DescribedNodeTypeV1,
DetailedNodePerformanceV1, DetailedNodePerformanceV2, DisplayRole, GatewayCoreStatusResponse,
HistoricalPerformanceResponse, HistoricalUptimeResponse, MixnodeCoreStatusResponse,
MixnodeStatus, MixnodeStatusResponse, NodeAnnotationV1, NodeAnnotationV2,
NodeDatePerformanceResponse, NodePerformanceResponse, PerformanceHistoryResponse, RoutingScore,
StakeSaturationResponse, StressTestingScore, UptimeHistoryResponse,
};
use nym_api_requests::pagination::{PaginatedResponse, Pagination};
use nym_mixnet_contract_common::nym_node::{NodeConfigUpdate, Role};
@@ -182,6 +183,13 @@ fn main() -> anyhow::Result<()> {
do_export!(AnnotationResponseV1);
do_export!(NodeAnnotationV2);
do_export!(AnnotationResponseV2);
// dependencies of NodeAnnotationV1/V2 (otherwise their generated imports dangle)
do_export!(DisplayRole);
do_export!(DetailedNodePerformanceV1);
do_export!(DetailedNodePerformanceV2);
do_export!(RoutingScore);
do_export!(ConfigScore);
do_export!(StressTestingScore);
do_export!(NodePerformanceResponse);
do_export!(NodeDatePerformanceResponse);
do_export!(PerformanceHistoryResponse);
@@ -0,0 +1,7 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type ConfigScore = {
/**
* Total score after taking all the criteria into consideration
*/
score: number, versions_behind: number | null, self_described_api_available: boolean, accepted_terms_and_conditions: boolean, runs_nym_node_binary: boolean, };
@@ -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 { ConfigScore } from "./ConfigScore";
import type { RoutingScore } from "./RoutingScore";
export type DetailedNodePerformanceV1 = {
/**
* routing_score * config_score
*/
performance_score: number, routing_score: RoutingScore, config_score: ConfigScore, };
@@ -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 { ConfigScore } from "./ConfigScore";
import type { RoutingScore } from "./RoutingScore";
import type { StressTestingScore } from "./StressTestingScore";
export type DetailedNodePerformanceV2 = {
/**
* routing_score * config_score
* or
* routing_score * config_score * stress_testing_score, if enabled
*/
performance_score: number, routing_score: RoutingScore, config_score: ConfigScore, stress_testing_score: StressTestingScore, };
@@ -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 DisplayRole = "entryGateway" | "layer1" | "layer2" | "layer3" | "exitGateway" | "standby";
@@ -3,9 +3,12 @@
/**
* A pending invitation for a node to join a particular family.
*
* Invitations are stored until they are accepted, rejected, revoked, or until the
* chain advances past `expires_at` (in which case they remain in storage but are
* treated as inert — there is no background process clearing expired invitations).
* Invitations are stored until they are accepted, rejected, or revoked. Once the
* chain advances past `expires_at` an invitation becomes inert but stays in storage
* — there is no background process clearing expired invitations. A timed-out
* invitation is cleared either when explicitly revoked/rejected, or when the family
* issues a fresh invitation for the same node, which archives the stale one as
* `Expired` and supersedes it.
*/
export type FamilyInvitation = {
/**
@@ -3,7 +3,9 @@
/**
* Terminal status for an invitation that has been moved out of the pending set.
*
* Note: timed-out invitations are not represented here — they are simply left in
* the pending set (see `FamilyInvitation::expires_at`).
* Note: an invitation that merely times out is **not** archived here on its own —
* it is left inert in the pending set (see `FamilyInvitation::expires_at`). It only
* reaches `Expired` if the family issues a fresh invitation for the same node, which
* supersedes and archives the stale one.
*/
export type FamilyInvitationStatus = { "pending": { at: number, } } | { "accepted": { at: number, } } | { "rejected": { at: number, } } | { "revoked": { at: number, } };
@@ -4,8 +4,9 @@ import type { FamilyInvitationStatus } from "./FamilyInvitationStatus";
/**
* Historical record of an invitation that has reached a terminal state
* (`Accepted`, `Rejected`, or `Revoked`). Timed-out invitations are **not**
* archived here — they remain in the pending map until explicitly cleared.
* (`Accepted`, `Rejected`, `Revoked`, or `Expired`). A timed-out invitation is
* archived here only when a fresh invitation for the same node supersedes it
* (status `Expired`); otherwise it stays in the pending map until explicitly cleared.
*/
export type PastFamilyInvitation = {
/**
@@ -0,0 +1,7 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type RoutingScore = {
/**
* Total score after taking all the criteria into consideration
*/
score: number, };
@@ -0,0 +1,9 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type StressTestingScore = { score: number,
/**
* Distinguishes a genuine zero score (node was tested and scored 0) from
* "node was unreachable" (no successful sample was collected). Consumers may use
* this to decide whether to penalise the node or treat the score as missing.
*/
was_reachable: boolean, };