Skip to content

Commit afcdb27

Browse files
committed
feat: delete statusDetailsToMessages and errorsToMessages
These functions are no longer needed: - Devices now return pre-rendered messages via DeviceStatusDetail.message - normaliseDeviceStatus() uses statusDetails.map(d => d.message) directly - Consumers who need string arrays can do the same Also fix stray 'messages:' field in atem.spec.ts getStatus() assertion
1 parent 71e5d7a commit afcdb27

6 files changed

Lines changed: 1 addition & 277 deletions

File tree

packages/timeline-state-resolver-types/src/__tests__/__snapshots__/index.spec.ts.snap

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,10 +129,8 @@ exports[`index imports 1`] = `
129129
"WebSocketClientStatusCode",
130130
"WebSocketClientStatusMessages",
131131
"WebsocketClientActions",
132-
"errorsToMessages",
133132
"fillStateFromDatastore",
134133
"interpolateTemplateString",
135134
"interpolateTemplateStringIfNeeded",
136-
"statusDetailsToMessages",
137135
]
138136
`;
Lines changed: 1 addition & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import { interpolateTemplateString, interpolateTemplateStringIfNeeded, errorsToMessages } from '../templateString.js'
2-
import { DeviceStatusDetail } from '../deviceStatusDetail.js'
1+
import { interpolateTemplateString, interpolateTemplateStringIfNeeded } from '../templateString.js'
32

43
describe('interpolateTemplateString', () => {
54
test('basic input', () => {
@@ -37,68 +36,3 @@ describe('interpolateTemplateStringIfNeeded', () => {
3736
).toEqual('Hello there Bob')
3837
})
3938
})
40-
41-
describe('errorsToMessages', () => {
42-
const mockErrorCode = {
43-
DISCONNECTED: 'DEVICE_MOCK_DISCONNECTED',
44-
TIMEOUT: 'DEVICE_MOCK_TIMEOUT',
45-
} as const
46-
47-
const mockErrorMessages = {
48-
[mockErrorCode.DISCONNECTED]: '{{deviceName}} disconnected',
49-
[mockErrorCode.TIMEOUT]: '{{deviceName}} timeout after {{timeout}}ms',
50-
}
51-
52-
test('converts single error to message', () => {
53-
const errors: DeviceStatusDetail[] = [
54-
{ code: mockErrorCode.DISCONNECTED, context: { deviceName: 'Test Device' }, message: 'Test Device disconnected' },
55-
]
56-
const messages = errorsToMessages(errors, mockErrorMessages)
57-
expect(messages).toEqual(['Test Device disconnected'])
58-
})
59-
60-
test('converts multiple errors to messages', () => {
61-
const errors: DeviceStatusDetail[] = [
62-
{ code: mockErrorCode.DISCONNECTED, context: { deviceName: 'Device A' }, message: 'Device A disconnected' },
63-
{
64-
code: mockErrorCode.TIMEOUT,
65-
context: { deviceName: 'Device B', timeout: 5000 },
66-
message: 'Device B timeout after 5000ms',
67-
},
68-
]
69-
const messages = errorsToMessages(errors, mockErrorMessages)
70-
expect(messages).toEqual(['Device A disconnected', 'Device B timeout after 5000ms'])
71-
})
72-
73-
test('falls back to pre-rendered message when template not found', () => {
74-
const errors: DeviceStatusDetail[] = [
75-
{ code: 'DEVICE_UNKNOWN_ERROR', context: { deviceName: 'Test Device' }, message: 'DEVICE_UNKNOWN_ERROR' },
76-
]
77-
const messages = errorsToMessages(errors, mockErrorMessages)
78-
expect(messages).toEqual(['DEVICE_UNKNOWN_ERROR'])
79-
})
80-
81-
test('preserves unknown placeholders in templates', () => {
82-
const errors: DeviceStatusDetail[] = [
83-
{ code: mockErrorCode.DISCONNECTED, context: { deviceName: 'Test Device' }, message: 'Test Device disconnected' },
84-
]
85-
const customTemplates = {
86-
[mockErrorCode.DISCONNECTED]: '{{deviceName}} offline - {{missingVar}} - contact {{admin}}',
87-
}
88-
const messages = errorsToMessages(errors, customTemplates)
89-
expect(messages).toEqual(['Test Device offline - {{missingVar}} - contact {{admin}}'])
90-
})
91-
92-
test('handles empty errors array', () => {
93-
const messages = errorsToMessages([])
94-
expect(messages).toEqual([])
95-
})
96-
97-
test('handles empty templates object', () => {
98-
const errors: DeviceStatusDetail[] = [
99-
{ code: mockErrorCode.DISCONNECTED, context: { deviceName: 'Test Device' }, message: 'Test Device disconnected' },
100-
]
101-
const messages = errorsToMessages(errors, {})
102-
expect(messages).toEqual(['Test Device disconnected'])
103-
})
104-
})
Lines changed: 0 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { DeviceStatusDetail } from './deviceStatusDetail.js'
2-
31
/** This resolves to a string, where parts can be defined by the datastore */
42
export interface TemplateString {
53
/** The string template. Example: "http://google.com?q={{searchString}}" */
@@ -32,68 +30,3 @@ export function interpolateTemplateStringIfNeeded(str: string | TemplateString):
3230
if (typeof str === 'string') return str
3331
return interpolateTemplateString(str.key, str.args ?? {})
3432
}
35-
36-
/**
37-
* Converts structured device status details to human-readable messages using templates.
38-
*
39-
* This function is used by:
40-
* - TSR devices internally to populate the messages array in getStatus()
41-
* - Consuming applications (Sofie, SuperConductor) to apply custom message templates
42-
* - Blueprints to customize status messages for operators
43-
*
44-
* Template syntax: Use {{variable}} placeholders, which are replaced with values from detail.context.
45-
* Unknown status codes fall back to displaying the code itself.
46-
* Unknown placeholders are preserved as {{key}} for downstream translation systems.
47-
*
48-
* @param statusDetails - Array of DeviceStatusDetail objects from device.getStatus()
49-
* @param templates - Message templates keyed by status code. Each device exports default templates
50-
* (e.g., AtemStatusMessages). Consuming applications can provide custom templates.
51-
* @returns Array of interpolated message strings
52-
*
53-
* @example
54-
* // Device usage (internal):
55-
* import { AtemStatusMessages } from 'timeline-state-resolver-types'
56-
* return {
57-
* statusCode: StatusCode.BAD,
58-
* messages: statusDetailsToMessages(statusDetails, AtemStatusMessages),
59-
* statusDetails
60-
* }
61-
*
62-
* @example
63-
* // Multi-device usage:
64-
* import { AtemStatusMessages, CasparCGStatusMessages, statusDetailsToMessages } from 'timeline-state-resolver-types'
65-
*
66-
* const allMessages = { ...AtemStatusMessages, ...CasparCGStatusMessages }
67-
*
68-
* const statusDetails = [
69-
* { code: 'DEVICE_ATEM_DISCONNECTED', context: { deviceName: 'Studio A Vision Mixer', host: '192.168.1.10' } },
70-
* { code: 'DEVICE_ATEM_PSU_FAULT', context: { deviceName: 'Studio A Vision Mixer', host: '192.168.1.10', psuNumber: 2, totalPsus: 2 } }
71-
* ]
72-
* const messages = statusDetailsToMessages(statusDetails, allMessages)
73-
* // ['ATEM Studio A Vision Mixer disconnected', 'ATEM PSU 2 is faulty. The device has 2 PSU(s) in total.']
74-
*
75-
* @example
76-
* // Blueprint usage with custom templates:
77-
* import { statusDetailsToMessages, AtemStatusCode } from 'timeline-state-resolver-types'
78-
*
79-
* const customMessages = {
80-
* [AtemStatusCode.DISCONNECTED]: '🎬 {{deviceName}} offline - check network!'
81-
* }
82-
* const messages = statusDetailsToMessages(statusDetails, customMessages)
83-
*/
84-
export function statusDetailsToMessages(
85-
statusDetails: DeviceStatusDetail[],
86-
templates: Record<string, string> = {}
87-
): string[] {
88-
return statusDetails.map((detail) => {
89-
if (detail.code) {
90-
const template = templates[detail.code]
91-
if (template) return interpolateTemplateString(template, detail.context ?? {})
92-
}
93-
return detail.message
94-
})
95-
}
96-
97-
// Backward compatibility alias
98-
/** @deprecated Use statusDetailsToMessages instead */
99-
export const errorsToMessages = statusDetailsToMessages

packages/timeline-state-resolver/src/__tests__/__snapshots__/index.spec.ts.snap

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,10 +148,8 @@ exports[`index imports 1`] = `
148148
"WebSocketClientStatusCode",
149149
"WebSocketClientStatusMessages",
150150
"WebsocketClientActions",
151-
"errorsToMessages",
152151
"fillStateFromDatastore",
153152
"interpolateTemplateString",
154153
"interpolateTemplateStringIfNeeded",
155-
"statusDetailsToMessages",
156154
]
157155
`;

packages/timeline-state-resolver/src/__tests__/deviceErrorMessages.spec.ts

Lines changed: 0 additions & 138 deletions
This file was deleted.

packages/timeline-state-resolver/src/integrations/atem/__tests__/atem.spec.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ describe('Atem', () => {
7676
})
7777
)
7878
expect(device.getStatus()).toEqual({
79-
messages: ['ATEM disconnected'],
8079
statusCode: StatusCode.BAD,
8180
statusDetails: [
8281
createAtemStatusDetail(AtemStatusCode.DISCONNECTED, {

0 commit comments

Comments
 (0)