feat: add t-timers info to LSG#1708
Conversation
WalkthroughAdds T-Timers: new OpenAPI schemas (indices, modes, states, status), required Changes
Sequence DiagramsequenceDiagram
participant Corelib as Corelib (Data Model)
participant Topic as ActivePlaylistTopic (Transformer)
participant Gateway as WebSocket (Event Dispatch)
participant Client as Sample Client (Receiver / Renderer)
Corelib->>Topic: emit playlist with RundownTTimer[]
activate Topic
Topic->>Topic: transformTTimers() → TTimerStatus[3]
Topic->>Gateway: send activePlaylist event { ..., tTimers }
deactivate Topic
Gateway->>Client: WebSocket message (activePlaylist)
activate Client
Client->>Client: parse activePlaylist.tTimers
Client->>Client: render timer DOM placeholders
loop periodic (e.g., 100ms)
Client->>Client: updateTTimers() — compute values from zeroTime/pauseTime/projected
Client->>Client: update DOM timer values & projected indicators
end
deactivate Client
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (4)
packages/live-status-gateway-api/api/components/tTimers/timerState/paused/timerStatePaused.yaml (1)
11-23: Prefer integer types for ms/timestamp fields.Line 12 (
duration) and Line 22 (pauseTime) currently allow fractional numbers; integer typing would better match millisecond semantics.🛠️ Suggested schema tweak
duration: - type: number + type: integer description: >- Frozen duration value in milliseconds. For countdown timers, this is remaining time. For free-run timers, this is elapsed time. ... oneOf: - - type: number + - type: integer - type: 'null'🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/live-status-gateway-api/api/components/tTimers/timerState/paused/timerStatePaused.yaml` around lines 11 - 23, The duration and pauseTime schema fields currently use type:number which allows fractional values; update duration's type to integer and change the pauseTime oneOf entry from type:number to type:integer so both fields enforce millisecond/timestamp integer semantics (leave descriptions and the null option for pauseTime unchanged); locate the duration and pauseTime entries in timerStatePaused.yaml to make these edits.packages/live-status-gateway-api/api/components/tTimers/timerMode/countdown/timerModeCountdown.yaml (1)
10-12: Tightendurationto integer milliseconds.On Line 11,
type: numberpermits fractional values. For millisecond durations,integer(and non-negative bound) is usually safer.🛠️ Suggested schema tweak
duration: - type: number + type: integer + minimum: 0 description: The original countdown duration in milliseconds (used for reset)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/live-status-gateway-api/api/components/tTimers/timerMode/countdown/timerModeCountdown.yaml` around lines 10 - 12, The schema's duration field currently allows fractional numbers; update the timerModeCountdown schema's duration property to use type: integer and add a minimum: 0 constraint so it only accepts non-negative millisecond integers (i.e., change the duration definition in timerModeCountdown.yaml to type: integer and include minimum: 0).packages/live-status-gateway/src/topics/__tests__/activePlaylist.spec.ts (2)
66-94: Consider adding a configured T-Timer expectation test.These updates assert the default/unconfigured case, but a focused test for a configured timer (
mode/state/projected/anchorPartId) would better protect the new mapping path.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/live-status-gateway/src/topics/__tests__/activePlaylist.spec.ts` around lines 66 - 94, Add a focused test in activePlaylist.spec.ts that covers a configured T-Timer mapping path: create a tTimers entry with configured: true and non-null values for mode, state, projected, and anchorPartId (e.g., for index 1), then assert that the code which maps/returns tTimers (the logic under test referenced by tTimers in the spec) preserves those fields and produces the expected mapped output; use the existing test structure to add an expectation verifying mode/state/projected/anchorPartId are present and correct for the configured timer.
66-94: Extract duplicated defaulttTimersfixture.Lines 66-94, 196-224, and 331-359 repeat the same array literal; pulling this into a shared constant/helper will make future schema updates safer.
♻️ Suggested refactor
+const DEFAULT_UNCONFIGURED_T_TIMERS: ActivePlaylistEvent['tTimers'] = [ + { index: 1, label: '', configured: false, mode: null, state: null, projected: null, anchorPartId: null }, + { index: 2, label: '', configured: false, mode: null, state: null, projected: null, anchorPartId: null }, + { index: 3, label: '', configured: false, mode: null, state: null, projected: null, anchorPartId: null }, +] ... - tTimers: [ - { ... }, - { ... }, - { ... }, - ], + tTimers: DEFAULT_UNCONFIGURED_T_TIMERS,Also applies to: 196-224, 331-359
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/live-status-gateway/src/topics/__tests__/activePlaylist.spec.ts` around lines 66 - 94, The test file repeats the same tTimers array literal in multiple places; extract it into a single shared constant (e.g., DEFAULT_T_TIMERS) declared once at the top of the spec and replace the three inline literals with references to that constant, ensuring tests that mutate the array clone it (e.g., structuredClone or JSON.parse(JSON.stringify(...))) before mutating; update usages of the inline tTimers to use DEFAULT_T_TIMERS so schema changes only need one edit and tests remain independent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@packages/live-status-gateway-api/api/components/tTimers/tTimerStatus/tTimerStatus-configured-example.yaml`:
- Around line 4-7: The example uses literal $ref keys inside the example object
(fields mode and state) which will not be dereferenced by JSON Schema/AsyncAPI
tooling; replace those $ref entries by inlining the actual example objects from
../timerMode/countdown/timerModeCountdown-example.yaml and
../timerState/running/timerStateRunning-example.yaml directly into the mode and
state properties in tTimerStatus-configured-example.yaml, or implement a
preprocessing step to merge those example files into the example payload before
tooling runs so mode and state contain real example objects rather than "{
\"$ref\": ... }".
---
Nitpick comments:
In
`@packages/live-status-gateway-api/api/components/tTimers/timerMode/countdown/timerModeCountdown.yaml`:
- Around line 10-12: The schema's duration field currently allows fractional
numbers; update the timerModeCountdown schema's duration property to use type:
integer and add a minimum: 0 constraint so it only accepts non-negative
millisecond integers (i.e., change the duration definition in
timerModeCountdown.yaml to type: integer and include minimum: 0).
In
`@packages/live-status-gateway-api/api/components/tTimers/timerState/paused/timerStatePaused.yaml`:
- Around line 11-23: The duration and pauseTime schema fields currently use
type:number which allows fractional values; update duration's type to integer
and change the pauseTime oneOf entry from type:number to type:integer so both
fields enforce millisecond/timestamp integer semantics (leave descriptions and
the null option for pauseTime unchanged); locate the duration and pauseTime
entries in timerStatePaused.yaml to make these edits.
In `@packages/live-status-gateway/src/topics/__tests__/activePlaylist.spec.ts`:
- Around line 66-94: Add a focused test in activePlaylist.spec.ts that covers a
configured T-Timer mapping path: create a tTimers entry with configured: true
and non-null values for mode, state, projected, and anchorPartId (e.g., for
index 1), then assert that the code which maps/returns tTimers (the logic under
test referenced by tTimers in the spec) preserves those fields and produces the
expected mapped output; use the existing test structure to add an expectation
verifying mode/state/projected/anchorPartId are present and correct for the
configured timer.
- Around line 66-94: The test file repeats the same tTimers array literal in
multiple places; extract it into a single shared constant (e.g.,
DEFAULT_T_TIMERS) declared once at the top of the spec and replace the three
inline literals with references to that constant, ensuring tests that mutate the
array clone it (e.g., structuredClone or JSON.parse(JSON.stringify(...))) before
mutating; update usages of the inline tTimers to use DEFAULT_T_TIMERS so schema
changes only need one edit and tests remain independent.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: d969bd02-76fd-4868-88f1-74ee6137d31e
⛔ Files ignored due to path filters (2)
packages/live-status-gateway-api/src/generated/asyncapi.yamlis excluded by!**/generated/**packages/live-status-gateway-api/src/generated/schema.tsis excluded by!**/generated/**
📒 Files selected for processing (24)
packages/live-status-gateway-api/api/components/playlist/activePlaylistEvent/activePlaylistEvent-example.yamlpackages/live-status-gateway-api/api/components/playlist/activePlaylistEvent/activePlaylistEvent.yamlpackages/live-status-gateway-api/api/components/tTimers/tTimerIndex.yamlpackages/live-status-gateway-api/api/components/tTimers/tTimerStatus.yamlpackages/live-status-gateway-api/api/components/tTimers/tTimerStatus/tTimerStatus-array-example.yamlpackages/live-status-gateway-api/api/components/tTimers/tTimerStatus/tTimerStatus-configured-example.yamlpackages/live-status-gateway-api/api/components/tTimers/tTimerStatus/tTimerStatus-unconfigured-example.yamlpackages/live-status-gateway-api/api/components/tTimers/tTimerStatus/tTimerStatus.yamlpackages/live-status-gateway-api/api/components/tTimers/timerMode.yamlpackages/live-status-gateway-api/api/components/tTimers/timerMode/countdown/timerModeCountdown-example.yamlpackages/live-status-gateway-api/api/components/tTimers/timerMode/countdown/timerModeCountdown.yamlpackages/live-status-gateway-api/api/components/tTimers/timerMode/freeRun/timerModeFreeRun-example.yamlpackages/live-status-gateway-api/api/components/tTimers/timerMode/freeRun/timerModeFreeRun.yamlpackages/live-status-gateway-api/api/components/tTimers/timerMode/timeOfDay/timerModeTimeOfDay-example.yamlpackages/live-status-gateway-api/api/components/tTimers/timerMode/timeOfDay/timerModeTimeOfDay.yamlpackages/live-status-gateway-api/api/components/tTimers/timerState.yamlpackages/live-status-gateway-api/api/components/tTimers/timerState/paused/timerStatePaused-example.yamlpackages/live-status-gateway-api/api/components/tTimers/timerState/paused/timerStatePaused.yamlpackages/live-status-gateway-api/api/components/tTimers/timerState/running/timerStateRunning-example.yamlpackages/live-status-gateway-api/api/components/tTimers/timerState/running/timerStateRunning.yamlpackages/live-status-gateway/sample-client/index.htmlpackages/live-status-gateway/sample-client/script.jspackages/live-status-gateway/src/topics/__tests__/activePlaylist.spec.tspackages/live-status-gateway/src/topics/activePlaylistTopic.ts
e3aca49 to
d3c11c8
Compare
This adds basic T-Timer support to the Live Status Gateway API by exposing the underlying data model structure directly, rather than denormalizing/reshaping it. Structure: - TimerMode: Configuration (countdown/freeRun/timeOfDay) - TimerState: Runtime data (paused/running, zeroTime/duration) - TTimerStatus: Combines mode, state, label, configured flag This keeps the transformation layer thin - the API just passes through the well-designed internal structures. The types match the corelib TimerState and RundownTTimerMode types exactly. Benefits over previous denormalized approach: - 90% less transformation code - Single source of truth for TimerState structure - Easier to add timeOfDay mode support later - Self-documenting (reuses existing inline docs) Schema generation: Added tTimers example to activePlaylistEvent-example.yaml to fix AsyncAPI parser validation. The parser requires all required fields to be present in examples. Tests: Updated activePlaylist.spec.ts to include tTimers in all cases
- Add pauseTime field to TimerState (both running and paused states) - Running: timestamp for automatic pause when part ends - Paused: typically null when already paused - Add projected field to TTimerStatus (TimerState | null) - Enables calculation of over/under diff relative to anchor - Running state means progressing towards anchor - Paused state means pushing/delaying anchor - Add anchorPartId field to TTimerStatus (string | null) - Target Part ID that timer is counting towards - Update example with realistic projected/pauseTime/anchorPartId values - Fix imports: use specific timer mode/state types and define local unions - Update all test cases to include new fields (projected, anchorPartId) - All tests passing (17/17)
Break down T-Timer schemas and examples into separate files for reusability: Timer Modes (with examples): - timerMode/countdown/ - Countdown timer with duration - timerMode/freeRun/ - Free-running timer - timerMode/timeOfDay/ - Time-of-day target timer Timer States (with examples): - timerState/running/ - Running state with zeroTime and pauseTime - timerState/paused/ - Paused state with frozen duration T-Timer Status (with examples): - tTimerStatus-configured-example.yaml - Configured timer - tTimerStatus-unconfigured-example.yaml - Empty timer slot - tTimerStatus-array-example.yaml - Array of 3 timers for reuse This follows the pattern used in other components (e.g., notifications/target/) and allows individual examples and schemas to be referenced independently.
- Add formatTimestampToTimeOfDay() to display timestamps in HH:MM:SS format - Show timer state context: (paused), (pauseTime: HH:MM:SS), or (zeroTime: HH:MM:SS) - Factor in pauseTime when calculating timer display values to freeze countdown correctly - Apply same logic to both current and projected timer states
c7cd646 to
37d2d77
Compare
justandras
left a comment
There was a problem hiding this comment.
All changes have been previously reviewed and approved
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
packages/live-status-gateway/src/topics/activePlaylistTopic.ts (1)
306-316: Type safety: make timer transformation more robust to future schema changes.The
ascasts (mode as TimerMode | null,state as TimerState | null,projected: projectedState as TimerState) currently work because corelib and API timer types are structurally identical. However, these unchecked casts bypass the compiler's structural verification. If corelib ever adds a new mode variant (e.g., with different field casing), renames a discriminant, or changes field types, the transformation will silently serialize incorrect payloads to LSG clients without a compile-time signal.Consider adding a small discriminant switch (on
mode.typeandstate.paused) withassertNeverin the default case to catch schema drift early. Alternatively, follow the pattern oftransformQuickLoopMarkerStatuswith an explicit mapper. This adds minimal runtime overhead but provides early warning of breaking changes.The ternary
projectedState ? (projectedState as TimerState) : nullis appropriate as-is; it clearly expresses the intent to return null only when projectedState is absent.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/live-status-gateway/src/topics/activePlaylistTopic.ts` around lines 306 - 316, The transformTTimer function currently uses unchecked `as` casts for mode/state which can hide schema drift; replace those casts in transformTTimer by mapping the RundownTTimer.mode and .state through explicit discriminant-based conversions (e.g., switch on mode.type and on state.paused or another discriminant) similar to transformQuickLoopMarkerStatus, returning the corresponding TimerMode/TimerState shapes and using an assertNever (or equivalent) in the default branch to fail loudly on unknown variants; keep the projectedState ternary (projectedState ? projectedState as TimerState : null) as-is per the review.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/live-status-gateway/src/topics/activePlaylistTopic.ts`:
- Around line 269-304: The transformTTimers function's parameter tTimers is
declared as RundownTTimer[] but the data model guarantees a fixed 3-tuple;
change the parameter type to [RundownTTimer, RundownTTimer, RundownTTimer] |
null | undefined so the signature reflects the invariant, keeping the body
(positional indexing and the return of three this.transformTTimer calls)
unchanged; update the import or type reference if necessary to use the
RundownTTimer tuple form and ensure TTimerStatus/TTimerIndex usages remain
compatible.
---
Nitpick comments:
In `@packages/live-status-gateway/src/topics/activePlaylistTopic.ts`:
- Around line 306-316: The transformTTimer function currently uses unchecked
`as` casts for mode/state which can hide schema drift; replace those casts in
transformTTimer by mapping the RundownTTimer.mode and .state through explicit
discriminant-based conversions (e.g., switch on mode.type and on state.paused or
another discriminant) similar to transformQuickLoopMarkerStatus, returning the
corresponding TimerMode/TimerState shapes and using an assertNever (or
equivalent) in the default branch to fail loudly on unknown variants; keep the
projectedState ternary (projectedState ? projectedState as TimerState : null)
as-is per the review.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 6e85dc1a-3a9b-4195-b023-70e9e60ded95
⛔ Files ignored due to path filters (2)
packages/live-status-gateway-api/src/generated/asyncapi.yamlis excluded by!**/generated/**packages/live-status-gateway-api/src/generated/schema.tsis excluded by!**/generated/**
📒 Files selected for processing (26)
packages/live-status-gateway-api/api/components/playlist/activePlaylistEvent/activePlaylistEvent-example.yamlpackages/live-status-gateway-api/api/components/playlist/activePlaylistEvent/activePlaylistEvent.yamlpackages/live-status-gateway-api/api/components/tTimers/tTimerIndex.yamlpackages/live-status-gateway-api/api/components/tTimers/tTimerStatus.yamlpackages/live-status-gateway-api/api/components/tTimers/tTimerStatus/tTimerStatus-array-example.yamlpackages/live-status-gateway-api/api/components/tTimers/tTimerStatus/tTimerStatus-configured-example.yamlpackages/live-status-gateway-api/api/components/tTimers/tTimerStatus/tTimerStatus-unconfigured-example.yamlpackages/live-status-gateway-api/api/components/tTimers/tTimerStatus/tTimerStatus.yamlpackages/live-status-gateway-api/api/components/tTimers/timerMode.yamlpackages/live-status-gateway-api/api/components/tTimers/timerMode/countdown/timerModeCountdown-example.yamlpackages/live-status-gateway-api/api/components/tTimers/timerMode/countdown/timerModeCountdown.yamlpackages/live-status-gateway-api/api/components/tTimers/timerMode/freeRun/timerModeFreeRun-example.yamlpackages/live-status-gateway-api/api/components/tTimers/timerMode/freeRun/timerModeFreeRun.yamlpackages/live-status-gateway-api/api/components/tTimers/timerMode/timeOfDay/timerModeTimeOfDay-example.yamlpackages/live-status-gateway-api/api/components/tTimers/timerMode/timeOfDay/timerModeTimeOfDay.yamlpackages/live-status-gateway-api/api/components/tTimers/timerState.yamlpackages/live-status-gateway-api/api/components/tTimers/timerState/paused/timerStatePaused-example.yamlpackages/live-status-gateway-api/api/components/tTimers/timerState/paused/timerStatePaused.yamlpackages/live-status-gateway-api/api/components/tTimers/timerState/running/timerStateRunning-example.yamlpackages/live-status-gateway-api/api/components/tTimers/timerState/running/timerStateRunning.yamlpackages/live-status-gateway-api/tsconfig.build.jsonpackages/live-status-gateway/sample-client/index.htmlpackages/live-status-gateway/sample-client/script.jspackages/live-status-gateway/src/topics/__tests__/activePlaylist.spec.tspackages/live-status-gateway/src/topics/activePlaylistTopic.tspackages/tsconfig.build.json
✅ Files skipped from review due to trivial changes (20)
- packages/live-status-gateway-api/api/components/tTimers/timerState/running/timerStateRunning-example.yaml
- packages/live-status-gateway-api/api/components/tTimers/timerMode/timeOfDay/timerModeTimeOfDay-example.yaml
- packages/live-status-gateway-api/api/components/tTimers/timerMode/freeRun/timerModeFreeRun-example.yaml
- packages/tsconfig.build.json
- packages/live-status-gateway-api/api/components/tTimers/tTimerStatus/tTimerStatus-unconfigured-example.yaml
- packages/live-status-gateway-api/tsconfig.build.json
- packages/live-status-gateway-api/api/components/tTimers/timerMode/countdown/timerModeCountdown-example.yaml
- packages/live-status-gateway-api/api/components/tTimers/tTimerIndex.yaml
- packages/live-status-gateway-api/api/components/tTimers/tTimerStatus/tTimerStatus-configured-example.yaml
- packages/live-status-gateway-api/api/components/tTimers/timerState/paused/timerStatePaused.yaml
- packages/live-status-gateway-api/api/components/tTimers/timerState/running/timerStateRunning.yaml
- packages/live-status-gateway-api/api/components/tTimers/timerState.yaml
- packages/live-status-gateway-api/api/components/tTimers/tTimerStatus/tTimerStatus-array-example.yaml
- packages/live-status-gateway/sample-client/index.html
- packages/live-status-gateway-api/api/components/tTimers/timerMode/freeRun/timerModeFreeRun.yaml
- packages/live-status-gateway-api/api/components/tTimers/timerMode/timeOfDay/timerModeTimeOfDay.yaml
- packages/live-status-gateway-api/api/components/tTimers/tTimerStatus/tTimerStatus.yaml
- packages/live-status-gateway-api/api/components/tTimers/timerMode/countdown/timerModeCountdown.yaml
- packages/live-status-gateway-api/api/components/tTimers/tTimerStatus.yaml
- packages/live-status-gateway-api/api/components/tTimers/timerMode.yaml
🚧 Files skipped from review as they are similar to previous changes (5)
- packages/live-status-gateway-api/api/components/tTimers/timerState/paused/timerStatePaused-example.yaml
- packages/live-status-gateway-api/api/components/playlist/activePlaylistEvent/activePlaylistEvent-example.yaml
- packages/live-status-gateway/sample-client/script.js
- packages/live-status-gateway-api/api/components/playlist/activePlaylistEvent/activePlaylistEvent.yaml
- packages/live-status-gateway/src/topics/tests/activePlaylist.spec.ts
| private transformTTimers(tTimers: RundownTTimer[] | null | undefined): [TTimerStatus, TTimerStatus, TTimerStatus] { | ||
| // Always return exactly 3 timers | ||
| if (!tTimers || tTimers.length === 0) { | ||
| return [ | ||
| { | ||
| index: 1 as TTimerIndex, | ||
| label: '', | ||
| configured: false, | ||
| mode: null, | ||
| state: null, | ||
| projected: null, | ||
| anchorPartId: null, | ||
| }, | ||
| { | ||
| index: 2 as TTimerIndex, | ||
| label: '', | ||
| configured: false, | ||
| mode: null, | ||
| state: null, | ||
| projected: null, | ||
| anchorPartId: null, | ||
| }, | ||
| { | ||
| index: 3 as TTimerIndex, | ||
| label: '', | ||
| configured: false, | ||
| mode: null, | ||
| state: null, | ||
| projected: null, | ||
| anchorPartId: null, | ||
| }, | ||
| ] | ||
| } | ||
|
|
||
| return [this.transformTTimer(tTimers[0]), this.transformTTimer(tTimers[1]), this.transformTTimer(tTimers[2])] | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Find all sites that write/initialize/mutate tTimers on RundownPlaylist to verify invariants.
rg -nP --type=ts -C3 '\btTimers\b' -g '!**/__tests__/**' -g '!**/*.spec.ts'Repository: Sofie-Automation/sofie-core
Length of output: 22639
Fix misleading type annotation for tTimers parameter; positional indexing is correct given data model invariant.
The data model (packages/corelib/src/dataModel/RundownPlaylist/RundownPlaylist.ts:191) defines tTimers as a fixed tuple of exactly 3 elements: [RundownTTimer, RundownTTimer, RundownTTimer]. All initialization and mutation sites enforce this invariant (see job-worker, migration, and mock fixtures). The parameter type on line 269 should therefore be [RundownTTimer, RundownTTimer, RundownTTimer] | null | undefined instead of RundownTTimer[], which is misleading and masks the fixed-size guarantee. The positional indexing [0], [1], [2] is correct because the data is always ordered by index 1, 2, 3 in that respective order.
Change the type annotation from RundownTTimer[] to the precise tuple type to improve type safety and prevent accidental misuse:
Type annotation fix
- private transformTTimers(tTimers: RundownTTimer[] | null | undefined): [TTimerStatus, TTimerStatus, TTimerStatus] {
+ private transformTTimers(tTimers: [RundownTTimer, RundownTTimer, RundownTTimer] | null | undefined): [TTimerStatus, TTimerStatus, TTimerStatus] {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| private transformTTimers(tTimers: RundownTTimer[] | null | undefined): [TTimerStatus, TTimerStatus, TTimerStatus] { | |
| // Always return exactly 3 timers | |
| if (!tTimers || tTimers.length === 0) { | |
| return [ | |
| { | |
| index: 1 as TTimerIndex, | |
| label: '', | |
| configured: false, | |
| mode: null, | |
| state: null, | |
| projected: null, | |
| anchorPartId: null, | |
| }, | |
| { | |
| index: 2 as TTimerIndex, | |
| label: '', | |
| configured: false, | |
| mode: null, | |
| state: null, | |
| projected: null, | |
| anchorPartId: null, | |
| }, | |
| { | |
| index: 3 as TTimerIndex, | |
| label: '', | |
| configured: false, | |
| mode: null, | |
| state: null, | |
| projected: null, | |
| anchorPartId: null, | |
| }, | |
| ] | |
| } | |
| return [this.transformTTimer(tTimers[0]), this.transformTTimer(tTimers[1]), this.transformTTimer(tTimers[2])] | |
| } | |
| private transformTTimers(tTimers: [RundownTTimer, RundownTTimer, RundownTTimer] | null | undefined): [TTimerStatus, TTimerStatus, TTimerStatus] { | |
| // Always return exactly 3 timers | |
| if (!tTimers || tTimers.length === 0) { | |
| return [ | |
| { | |
| index: 1 as TTimerIndex, | |
| label: '', | |
| configured: false, | |
| mode: null, | |
| state: null, | |
| projected: null, | |
| anchorPartId: null, | |
| }, | |
| { | |
| index: 2 as TTimerIndex, | |
| label: '', | |
| configured: false, | |
| mode: null, | |
| state: null, | |
| projected: null, | |
| anchorPartId: null, | |
| }, | |
| { | |
| index: 3 as TTimerIndex, | |
| label: '', | |
| configured: false, | |
| mode: null, | |
| state: null, | |
| projected: null, | |
| anchorPartId: null, | |
| }, | |
| ] | |
| } | |
| return [this.transformTTimer(tTimers[0]), this.transformTTimer(tTimers[1]), this.transformTTimer(tTimers[2])] | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/live-status-gateway/src/topics/activePlaylistTopic.ts` around lines
269 - 304, The transformTTimers function's parameter tTimers is declared as
RundownTTimer[] but the data model guarantees a fixed 3-tuple; change the
parameter type to [RundownTTimer, RundownTTimer, RundownTTimer] | null |
undefined so the signature reflects the invariant, keeping the body (positional
indexing and the return of three this.transformTTimer calls) unchanged; update
the import or type reference if necessary to use the RundownTTimer tuple form
and ensure TTimerStatus/TTimerIndex usages remain compatible.
About the Contributor
This PR is posted on behalf of the BBC
Type of Contribution
This is a: feature
Current Behavior
Currently, t-timers state is not available through LSG
New Behavior
This PR adds t-timers state to the LSG in the following form:
Testing
Affected areas
This PR affects the LSG outputs
Time Frame
Not urgent, but we would like to get this merged into the in-development release.
Other Information
Replaces bbc#74 - merges upstream rather than to BBC fork.
Status