Skip to content

refactor(frontend): replace local API type copies with strom-types - #915

Merged
srperens merged 3 commits into
Eyevinn:mainfrom
wagenet:wagenet/shared-types-audit
Oct 5, 2026
Merged

srperens merged 3 commits into
Eyevinn:mainfrom
wagenet:wagenet/shared-types-audit

Conversation

@wagenet

@wagenet wagenet commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

The frontend defined its own copies of ten request and response types that already exist in strom-types. The copies existed because each shared type derived only the serde direction the backend needs (Serialize for responses, Deserialize for requests). Add the missing derive and delete the copies.

Frontend copy Replaced by
discovery::DiscoveredStream discovery::DiscoveredStreamResponse
discovery::AnnouncedStream discovery::AnnouncedStreamResponse (+Deserialize)
discovery::DiscoveredDevice (alias NdiSource) discovery::DeviceResponse; the NDI ip_address/url_address getters move onto it
local NdiStatus discovery::NdiDiscoveryStatus (+Deserialize)
local DynamicPadsResponse api::DynamicPadsResponse
local ParseRequest, ExportRequest api::ParseGstLaunchRequest, api::ExportGstLaunchRequest
local SetPlaylistRequest, SeekRequest, ControlRequest mediaplayer::SetPlaylistRequest, SeekRequest, PlayerControlRequest (+Serialize)

control_player now takes a PlayerAction instead of a string. The one caller already matched on the five valid action strings, so the mapping moved there.

None of the copies had drifted in a way that caused a bug. The wire format is unchanged:

  • openapi.json is unchanged, because utoipa ignores which serde direction a type derives.
  • A new test in types/src/mediaplayer.rs pins the PlayerAction wire strings to the values the frontend sent before. It won't compile without the new Serialize derive.
  • New tests in types/src/discovery.rs decode backend-shaped discovery JSON with the optional interface fields left out, and round-trip a DeviceResponse through its NDI ip_address/url_address getters.

The frontend now decodes discovery responses more strictly. DeviceResponse.category is an enum where the copy had a String, and properties no longer defaults when missing. The backend always sends both, and the frontend ships in the same build.

Tests run locally, from the workspace root:

  • cargo test --workspace --lib: 728 + 7 + 98 passed, including the new tests.
  • cargo test --test openapi_test: passed.
  • cargo clippy --workspace --all-targets -- -D warnings and cargo fmt --check: clean.
  • The WASM frontend build through trunk succeeded.

Not run locally: the CI job that runs clippy on the frontend for the wasm32 target.

🤖 Generated with Claude Code

@wagenet
wagenet marked this pull request as ready for review September 29, 2026 15:39
wagenet added a commit to wagenet/strom that referenced this pull request Sep 29, 2026
Eyevinn#915 decodes the NDI discovery responses as strom-types' NdiDiscoveryStatus
and DeviceResponse. Both require fields the backend always sends and
Eyevinn#916's fixtures left out: source_count on the status, and properties plus
a real category ("networksource", not "ndi") on each source.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@srperens srperens mentioned this pull request Sep 30, 2026
wagenet added a commit to wagenet/strom that referenced this pull request Oct 1, 2026
Eyevinn#915 decodes the NDI discovery responses as strom-types' NdiDiscoveryStatus
and DeviceResponse. Both require fields the backend always sends and
Eyevinn#916's fixtures left out: source_count on the status, and properties plus
a real category ("networksource", not "ndi") on each source.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
wagenet added a commit to wagenet/strom that referenced this pull request Oct 1, 2026
The backend always sends source_count on the NDI discovery status, and
properties plus a real category ("networksource", not "ndi") on each
source. The fixtures now match, so they also decode once Eyevinn#915 switches
these responses to strom-types' NdiDiscoveryStatus and DeviceResponse,
which require those fields.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@srperens srperens left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: Request changes. The refactor is right and its wire-format claims hold. But merged into today's main it stops the frontend compiling. This PR deletes the serde import from player.rs, and main has since added goto_player there, which still derives Serialize. GitHub reports this PR as MERGEABLE because the text merges cleanly. The breakage is in what the merged code means.

Requested changes

  1. Rebase onto main. In frontend/src/api/player.rs, replace goto_player's local GotoRequest with strom_types::mediaplayer::GotoRequest, and add Serialize to that type's derive in types/src/mediaplayer.rs. That removes the last local copy in the file, which is this PR's own goal, and it also fixes the build.

The break. I merged this head into main d78c3ee locally, with no conflicts. In the result:

  • frontend/src/api/player.rs:1 — use strom_types::mediaplayer::{ replaces the old use serde::Serialize;.
  • frontend/src/api/player.rs:99 — #[derive(Serialize)] still sits on main's local GotoRequest.
  • frontend/src/api/player.rs:6 — use super::*; cannot supply it: frontend/src/api/mod.rs has no serde import, and no #[macro_use] exists in the crate.

The shared type already exists, with Deserialize only: types/src/mediaplayer.rs:66 — #[derive(Debug, Clone, Deserialize)]. I did not compile this (no toolchain here). The finding is static: nothing in scope names Serialize at that line.

Claims

Claim Verdict Evidence
Wire strings for PlayerAction unchanged CONFIRMED mediaplayer::tests::player_control_request_wire_format ... ok in Check (Linux)
Discovery responses still decode with the optional fields absent CONFIRMED discovery::tests::responses_decode_with_optional_fields_absent ... ok, same job
Stricter decoding is safe CONFIRMED types/src/discovery.rs:103 — pub category: DeviceCategory, and types/src/discovery.rs:107 — pub properties: HashMap<String, String>, are the types the backend serialises, so the two cannot drift
CI covers the merged tree CONTRADICTED run 36588341385 is at 089dee9 on base f1a46dd, so it predates goto_player

Radius: SHARED. Four strom-types structs gain a serde direction, and frontend API calls switch types. openapi.json is unchanged, and API Contract Check is green.

Overlaps: #916 tests the same get_ndi_sources path. Its fixture sends "category":"networksource" and "properties":{}, so it decodes under the stricter types, and the two can land in either order. #879 changes other files under frontend/src/api/. No open issue owns this decision.

Tests & CI: Check (Linux), Check & Build (WASM), both Linux builds and API Contract Check are green at 089dee9. The three new strom-types tests ran in Check (Linux), by name. macOS and Windows were skipped, and nothing platform-specific changed.

Confidence: HIGH

wagenet and others added 3 commits October 2, 2026 08:30
The frontend defined its own copies of ten request/response types that
already exist in strom-types, because the shared types derived only the
serde direction the backend needs. Add the missing derive and use the
shared types:

- DiscoveredStream, AnnouncedStream, DiscoveredDevice and NdiStatus
  become DiscoveredStreamResponse, AnnouncedStreamResponse,
  DeviceResponse and NdiDiscoveryStatus. The NDI ip/url property getters
  move onto DeviceResponse.
- The local DynamicPadsResponse, ParseRequest and ExportRequest become
  the strom-types equivalents.
- SetPlaylistRequest, SeekRequest and ControlRequest become the
  strom-types player requests; control_player takes a PlayerAction
  instead of a string.

openapi.json is unchanged. A test pins the PlayerAction wire strings to
the values the frontend sent before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The frontend now decodes discovery responses with the shared types.
Check that stream and announced-stream JSON decodes with the optional
interface fields absent, that NDI status decodes, and that a
DeviceResponse round-trips with its NDI ip and url-address properties.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
goto_player, added on main after this branch was cut, still declared a
local GotoRequest deriving Serialize. The earlier commit in this branch
removed player.rs's serde import, so the frontend stopped compiling once
rebased. Use strom_types::mediaplayer::GotoRequest instead and derive
Serialize on it, with a wire-format test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@wagenet
wagenet force-pushed the wagenet/shared-types-audit branch from 089dee9 to b1b0a30 Compare October 2, 2026 15:46
@wagenet

wagenet commented Oct 2, 2026

Copy link
Copy Markdown
Contributor Author

Claude (AI), on behalf of @wagenet.

1. Rebase, and use the shared GotoRequest in goto_player. Done. The branch is rebased onto main ca85fabc with no conflicts. In b1b0a30, goto_player uses strom_types::mediaplayer::GotoRequest, which now derives Serialize, and a goto_request_wire_format test checks that it sends {"index":3}. That was the last local type in player.rs.

The build break was real. Before b1b0a30, cargo check --workspace --all-targets failed on the rebased tree with cannot find derive macro Serialize at frontend/src/api/player.rs:99.

Tests run at b1b0a30 (macOS):

  • cargo check --workspace --all-targets: pass
  • cargo clippy --workspace --all-targets -- -D warnings: pass
  • cargo clippy --package strom-frontend --target wasm32-unknown-unknown --all-features -- -D warnings (the CI wasm step): pass
  • cargo test --workspace: 1238 passed, 0 failed, 6 ignored. That includes strom-types (101) and strom-frontend (28). goto_request_wire_format, player_control_request_wire_format and responses_decode_with_optional_fields_absent all ran and passed.
  • cargo test --test openapi_test: pass. openapi.json is unchanged.

#916: No conflict. It merges cleanly on top of b1b0a30, and the merged tree passes cargo test --workspace --lib --bins: strom-frontend 46 (28 here plus #916's 18), strom-types 101.

@srperens srperens left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: Approve. This supersedes my Request changes at 089dee9. The rebase fixes the build break that review found, and it does so the way the review asked: the last local type in player.rs now comes from strom-types.

What moved. The branch was rebased onto main ca85fab and gained one commit, b1b0a30. In that commit:

  • frontend/src/api/player.rs:101 — .json(&GotoRequest { index }) now sends the shared type.
  • types/src/mediaplayer.rs:66 — #[derive(Debug, Clone, Serialize, Deserialize)] adds the Serialize the frontend needs.
  • types/src/mediaplayer.rs:114 — fn goto_request_wire_format() { pins the wire form as {"index":3}.

Main has moved two commits past the merge base, to af35c47. Both change only backend/src/blocks/builtin/mediaplayer/ and touch nothing in frontend/ or types/. A local trial merge of this head into af35c47 has no conflicts. I did not compile it, because there is no toolchain here. This time I also checked that no file this PR changes was changed on main since the base.

Claims

Claim Verdict Evidence
goto_player wire format unchanged CONFIRMED mediaplayer::tests::goto_request_wire_format ... ok in Check (Linux), run 37029330404 at b1b0a30
PlayerAction and discovery decoding unchanged CONFIRMED player_control_request_wire_format ... ok and responses_decode_with_optional_fields_absent ... ok, same job. The other rows of my earlier review are carried unchanged: the diff outside b1b0a30 is the same
CI covers this head CONFIRMED Check (Linux), Check & Build (WASM), both Linux builds and API Contract Check pass at b1b0a30. pipeline_lifecycle_test ran in the same job

Radius: SHARED, for the reasons in my earlier review. Four strom-types structs gain a serde direction, and frontend API calls switch to them. GotoRequest gaining Serialize adds a direction and changes nothing for the backend's Deserialize path. openapi.json is unchanged.

Overlaps: none that this PR would settle. #944, #897, #796, #792 and #786 change frontend/src/app/update.rs. None of their diffs mention control_player or the removed types (DiscoveredStream, AnnouncedStream, DiscoveredDevice). #916 changes frontend/src/api/mod.rs and frontend/src/api/tests.rs, and the author reports a clean merge with it.

Tests & CI: see the claims table. macOS and Windows were skipped. Nothing here is platform-specific, so the main-branch run covers them.

Confidence: HIGH

@srperens
srperens dismissed their stale review October 5, 2026 08:06

Superseded by my review at b1b0a30: the rebase fixed the build break this review found.

@srperens
srperens merged commit cdd41fb into Eyevinn:main Oct 5, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants