Skip to content
2 changes: 2 additions & 0 deletions packages/live-status-gateway-api/api/asyncapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ channels:
$ref: './topics/studio/studioTopic.yaml'
activePlaylist:
$ref: './topics/activePlaylist/activePlaylistTopic.yaml'
resolvedPlaylist:
$ref: './topics/resolvedPlaylist/resolvedPlaylistTopic.yaml'
activePieces:
$ref: './topics/activePieces/activePiecesTopic.yaml'
segments:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
id: 'ol_pgm'
name: 'PGM'
isFlattened: false
isPGM: true
sourceLayerIds:
- 'sl_camera'
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
$defs:
outputLayer:
type: object
title: OutputLayer
description: Definition of an output layer used in a segment
properties:
id:
type: string
description: Unique id of the output layer
name:
type: string
description: User-presentable name of the output layer
isFlattened:
type: boolean
description: Whether the output layer is flattened
isPGM:
type: boolean
description: Whether PGM treatment should be in effect
sourceLayerIds:
description: The set of sourceLayer ids that feed this output layer
type: array
items:
type: string
required: [id, name, isFlattened, isPGM, sourceLayerIds]
additionalProperties: false
examples:
- $ref: './outputLayer-example.yaml'
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
id: 'sl_camera'
name: 'Camera'
abbreviation: 'CAM'
isHidden: false
type: 1
rank: 0
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
$defs:
sourceLayer:
type: object
title: SourceLayer
description: Definition of a source layer used in a segment
properties:
id:
type: string
description: Unique id of the source layer
name:
type: string
description: User-presentable name of the source layer
abbreviation:
type: string
description: Abbreviation for display
isHidden:
type: boolean
description: Whether the source layer is hidden in the UI
type:
type: number
description: Source layer content type (numeric enum)
rank:
type: number
description: Rank for ordering
required: [id, name, abbreviation, isHidden, type, rank]
additionalProperties: false
examples:
- $ref: './sourceLayer-example.yaml'
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
message: 'Invalid clip reference'
severity: warning
color: '#ff0000'
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
$defs:
partInvalidReason:
title: PartInvalidReason
description: Explanation for why a part is invalid
type: object
properties:
message:
type: string
description: Human-readable message explaining why the part is invalid
severity:
description: Severity hint for displaying the invalid reason
$ref: '../../notifications/notificationSeverity.yaml#/$defs/severity'
color:
description: Optional UI color hint
type: string
required: [message]
additionalProperties: false
examples:
- $ref: './partInvalidReason-example.yaml'
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
$ref: '../partBase/partBase-example.yaml'
instanceId: 'partInstance_current_1'
externalId: 'ext_part_1'
rank: 10
invalid: false
floated: false
untimed: false
invalidReason:
$ref: '../partInvalidReason/partInvalidReason-example.yaml'
state: current
createdByAdLib: false
publicData:
partType: 'intro'
timing:
$ref: '../../timing/resolvedPartTiming/resolvedPartTiming-example.yaml'
pieces:
- $ref: '../../piece/resolvedPiece/resolvedPiece-example.yaml'
Comment on lines +1 to +17
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
fd -t f 'package.json' packages/live-status-gateway-api | head -5 | xargs -I{} cat {}
fd -t f 'generate-schema' packages/live-status-gateway-api

Repository: Sofie-Automation/sofie-core

Length of output: 2243


🏁 Script executed:

cat packages/live-status-gateway-api/scripts/generate-schema-types.mjs

Repository: Sofie-Automation/sofie-core

Length of output: 4474


🏁 Script executed:

cat packages/live-status-gateway-api/scripts/merge-schemas.mjs

Repository: Sofie-Automation/sofie-core

Length of output: 1156


🏁 Script executed:

fd -t f 'schema.ts' packages/live-status-gateway-api/src | head -1 | xargs wc -l
fd -t f 'asyncapi.yaml' packages/live-status-gateway-api/src | xargs ls -lh

Repository: Sofie-Automation/sofie-core

Length of output: 242


🏁 Script executed:

grep -A 30 'ResolvedPart:' packages/live-status-gateway-api/src/generated/asyncapi.yaml | head -40

Repository: Sofie-Automation/sofie-core

Length of output: 53


🏁 Script executed:

rg -i 'resolvedpart' packages/live-status-gateway-api/src/generated/asyncapi.yaml -A 5 | head -50

Repository: Sofie-Automation/sofie-core

Length of output: 1668


🏁 Script executed:

cat packages/live-status-gateway-api/api/components/part/resolvedPart/resolvedPart.yaml

Repository: Sofie-Automation/sofie-core

Length of output: 2133


🏁 Script executed:

cat packages/live-status-gateway-api/api/components/part/resolvedPart/resolvedPart-example.yaml

Repository: Sofie-Automation/sofie-core

Length of output: 529


🏁 Script executed:

rg -A 20 'resolvedPart-example' packages/live-status-gateway-api/src/generated/asyncapi.yaml | head -40

Repository: Sofie-Automation/sofie-core

Length of output: 53


🏁 Script executed:

npm info `@apidevtools/json-schema-ref-parser` versions --json | head -20

Repository: Sofie-Automation/sofie-core

Length of output: 286


🏁 Script executed:

fd -t f 'README' packages/live-status-gateway-api | xargs cat

Repository: Sofie-Automation/sofie-core

Length of output: 771


🏁 Script executed:

rg -B 5 -A 50 'examples:' packages/live-status-gateway-api/src/generated/asyncapi.yaml | grep -A 50 'ResolvedPart' | head -70

Repository: Sofie-Automation/sofie-core

Length of output: 4977


🏁 Script executed:

cat > /tmp/check_ref_behavior.js << 'EOF'
// Check json-schema-ref-parser behavior with $ref and siblings
const content = `
$ref: '../partBase/partBase-example.yaml'
instanceId: 'partInstance_current_1'
externalId: 'ext_part_1'
rank: 10
`;

console.log("According to JSON Schema spec (section 8.2.4):");
console.log("When processing a $ref keyword, sibling keywords should be ignored in strict compliance.");
console.log("\nHowever, `@apidevtools/json-schema-ref-parser.dereference`() is a convenience tool");
console.log("that MERGES sibling keywords with the referenced content (non-standard behavior).");
console.log("\nThis creates portability issues with strict validators and other tooling.");
EOF
node /tmp/check_ref_behavior.js

Repository: Sofie-Automation/sofie-core

Length of output: 445


🏁 Script executed:

rg -t yaml 'allOf' packages/live-status-gateway-api/api/components/part/resolvedPart/ -B 5 -A 10

Repository: Sofie-Automation/sofie-core

Length of output: 1860


Fix the example file to match the schema's composition pattern.

The schema definition in resolvedPart.yaml correctly uses allOf to compose partBase with sibling properties. However, the example file resolvedPart-example.yaml uses a $ref at the root with sibling keys, which violates strict JSON Schema semantics—though your current tooling (@apidevtools/json-schema-ref-parser) happens to merge them.

For portability and spec compliance, align the example with the schema's allOf pattern by either inlining the base example fields or using allOf syntax in the example as well.

🤖 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/part/resolvedPart/resolvedPart-example.yaml`
around lines 1 - 17, The example file resolvedPart-example.yaml currently uses a
root-level $ref to partBase-example.yaml with sibling properties which violates
JSON Schema composition semantics; update the example to match the schema's
allOf composition by replacing the root $ref with an allOf array that includes a
$ref to '../partBase/partBase-example.yaml' and a second object containing the
sibling properties (instanceId, externalId, rank, invalid, floated, untimed,
invalidReason ref, state, createdByAdLib, publicData, timing ref, pieces refs),
or alternatively inline all fields from partBase into this file so there is no
root $ref with siblings; ensure references to
'../partInvalidReason/partInvalidReason-example.yaml',
'../../timing/resolvedPartTiming/resolvedPartTiming-example.yaml', and
'../../piece/resolvedPiece/resolvedPiece-example.yaml' remain intact.

Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
$defs:
resolvedPartState:
title: ResolvedPartState
type: string
enum:
- current
- next

resolvedPart:
title: ResolvedPart
description: A part within a resolved segment
allOf:
- $ref: '../partBase/partBase.yaml#/$defs/partBase'
- type: object
title: ResolvedPart
description: A part within a resolved segment
properties:
instanceId:
type: string
description: Unique id of the part instance
externalId:
type: string
description: Id normally sourced from the ingest system
rank:
type: number
description: Rank for ordering
invalid:
type: boolean
description: Whether this part is invalid and should not be taken
floated:
type: boolean
description: Whether this part is floated and cannot be taken/nexted
untimed:
type: boolean
description: Whether this part is excluded from normal timing calculations
invalidReason:
description: Optional explanation for why the part is invalid
$ref: '../partInvalidReason/partInvalidReason.yaml#/$defs/partInvalidReason'
state:
description: Set only for the current or next part
$ref: '#/$defs/resolvedPartState'
createdByAdLib:
type: boolean
description: Whether this part was created by an adlib
publicData:
description: Optional arbitrary data
timing:
$ref: '../../timing/resolvedPartTiming/resolvedPartTiming.yaml#/$defs/resolvedPartTiming'
pieces:
description: Pieces in this part
type: array
items:
$ref: '../../piece/resolvedPiece/resolvedPiece.yaml#/$defs/resolvedPiece'
required: [instanceId, externalId, rank, createdByAdLib, timing, pieces, invalid, floated, untimed]
examples:
- $ref: './resolvedPart-example.yaml'
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
id: 'piece_1'
instanceId: 'pieceInstance_1'
externalId: 'ext_piece_1'
name: 'Camera 1'
priority: 0
sourceLayerId: 'sl_camera'
outputLayerId: 'ol_pgm'
createdByAdLib: false
invalid: false
publicData:
switcherSource: 1
timing:
$ref: '../../timing/resolvedPieceTiming/resolvedPieceTiming-example.yaml'
tags:
- 'camera'
abSessions:
- $ref: '../pieceStatus/abSessionAssignment-example.yaml'
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
$defs:
resolvedPiece:
type: object
title: ResolvedPiece
description: A piece within a resolved part
properties:
id:
type: string
description: Unique id of the piece
instanceId:
type: string
description: Unique id of the piece instance
externalId:
type: string
description: Id normally sourced from the ingest system
name:
type: string
description: User-facing name of the piece
priority:
type: number
description: Priority of the piece
sourceLayerId:
type: string
description: Id of the source layer for this piece
outputLayerId:
type: string
description: Id of the output layer for this piece
createdByAdLib:
type: boolean
description: Whether this piece was created by an adlib
invalid:
type: boolean
description: Whether this piece is invalid and should be ignored
publicData:
description: Optional arbitrary data
timing:
$ref: '../../timing/resolvedPieceTiming/resolvedPieceTiming.yaml#/$defs/resolvedPieceTiming'
tags:
description: Optional tags attached to this piece
type: array
items:
type: string
abSessions:
description: Optional AB playback session assignments for this piece
type: array
items:
$ref: '../pieceStatus/abSessionAssignment.yaml'
required:
[id, instanceId, externalId, name, priority, sourceLayerId, outputLayerId, createdByAdLib, invalid, timing]
additionalProperties: false
examples:
- $ref: './resolvedPiece-example.yaml'
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,5 @@ $defs:
- rehearsal
- activated
required: [id, externalId, name, activationStatus]
additionalProperties: false
examples:
- $ref: './playlistStatus-example.yaml'
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
components:
messages:
resolvedPlaylistMessage:
name: resolvedPlaylist
messageId: resolvedPlaylistUpdate
description: Resolved Playlist status
payload:
$ref: '../resolvedPlaylistEvent/resolvedPlaylistEvent.yaml#/$defs/resolvedPlaylistEvent'
examples:
- payload:
$ref: '../resolvedPlaylistEvent/resolvedPlaylistEvent-example.yaml'
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
$ref: '../../playlist/playlistStatus/playlistStatus-example.yaml'
event: resolvedPlaylist
currentPartInstanceId: 'partInstance_current_1'
nextPartInstanceId: 'partInstance_next_1'
playoutState:
mode: 'AUTO'
publicData:
category: 'Evening News'
timing:
$ref: '../../timing/resolvedPlaylistTiming/resolvedPlaylistTiming-example.yaml'
tTimers:
- $ref: '../../tTimers/tTimerStatus-countdownRunning-example.yaml'
- $ref: '../../tTimers/tTimerStatus-freeRunRunning-example.yaml'
- $ref: '../../tTimers/tTimerStatus-unconfigured-example.yaml'
quickLoop:
$ref: '../../quickLoop/activePlaylistQuickLoop/activePlaylistQuickLoop-example.yaml'
rundowns:
- $ref: '../../rundown/resolvedRundown/resolvedRundown-example.yaml'
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
title: Resolved Playlist
description: Resolved Playlist schema for websocket subscriptions
$defs:
resolvedPlaylistEvent:
title: ResolvedPlaylistEvent
description: Resolved playlist details, including the base playlist status.
allOf:
- $ref: '../../playlist/playlistStatus/playlistStatus.yaml#/$defs/playlistStatus'
- type: object
title: ResolvedPlaylistEvent
description: Resolved playlist details, including rundown/segment/part/piece structure.
properties:
event:
type: string
const: resolvedPlaylist
currentPartInstanceId:
description: Instance id of the current part, if any
oneOf:
- type: string
- type: 'null'
nextPartInstanceId:
description: Instance id of the next part, if any
oneOf:
- type: string
- type: 'null'
playoutState:
description: Blueprint-defined playout state, used to expose arbitrary information about playout
publicData:
description: Optional arbitrary data
timing:
$ref: '../../timing/resolvedPlaylistTiming/resolvedPlaylistTiming.yaml#/$defs/resolvedPlaylistTiming'
tTimers:
description: Status of the 3 T-timers in the playlist
type: array
items:
$ref: '../../tTimers/tTimerStatus.yaml#/$defs/tTimerStatus'
minItems: 3
maxItems: 3
quickLoop:
description: Information about the current quickLoop, if any
oneOf:
- type: 'null'
- $ref: '../../quickLoop/activePlaylistQuickLoop/activePlaylistQuickLoop.yaml#/$defs/activePlaylistQuickLoop'
rundowns:
description: The rundowns in the playlist, in rank order
type: array
items:
$ref: '../../rundown/resolvedRundown/resolvedRundown.yaml#/$defs/resolvedRundown'
required: [event, currentPartInstanceId, nextPartInstanceId, timing, tTimers, rundowns]
examples:
- $ref: './resolvedPlaylistEvent-example.yaml'
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
id: 'rd_1'
externalId: 'ext_rd_1'
name: 'Rundown 1'
rank: 10
description: ''
publicData:
ingestSource: 'NRK'
segments:
- $ref: '../../segment/resolvedSegment/resolvedSegment-example.yaml'
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
$defs:
resolvedRundown:
type: object
title: ResolvedRundown
description: A rundown within a resolved playlist
properties:
id:
type: string
description: Unique id of the rundown
externalId:
type: string
description: Id normally sourced from the ingest system
name:
type: string
description: User-presentable name of the rundown
rank:
type: number
description: Rank for ordering
description:
type: string
description: Optional description
publicData:
description: Optional arbitrary data
segments:
description: Segments in this rundown
type: array
items:
$ref: '../../segment/resolvedSegment/resolvedSegment.yaml#/$defs/resolvedSegment'
required: [id, externalId, name, rank, segments]
additionalProperties: false
examples:
- $ref: './resolvedRundown-example.yaml'
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
$ref: '../segmentBase/segmentBase-example.yaml'
externalId: 'ext_seg_1'
identifier: 'A'
name: 'Headlines'
rank: 1
isHidden: false
sourceLayers:
- $ref: '../../layers/sourceLayer/sourceLayer-example.yaml'
outputLayers:
- $ref: '../../layers/outputLayer/outputLayer-example.yaml'
publicData:
slug: 'HEAD'
timing:
$ref: '../../timing/resolvedSegmentTiming/resolvedSegmentTiming-example.yaml'
parts:
- $ref: '../../part/resolvedPart/resolvedPart-example.yaml'
Loading
Loading