Subscriptions
Golden Reports streams two kinds of real-time events over GraphQL subscriptions: data source health checks and data context lock transitions.
Overview
Subscriptions are delivered over a WebSocket connection using the graphql-ws protocol (the modern successor to the legacy subscriptions-transport-ws).
wss://api.goldenreports.dev/graphql
Subscriptions require the same bearer token as queries and mutations. Send it in the connectionParams payload of the GraphQL-over-WS connection_init message, since browsers can't set arbitrary headers on WebSocket handshakes.
Connecting
Most GraphQL clients (urql, Apollo Client, Relay) have an out-of-the-box graphql-ws link. With the graphql-ws package directly:
import { createClient } from 'graphql-ws'
const client = createClient({
url: 'wss://api.goldenreports.dev/graphql',
connectionParams: () => ({
Authorization: `Bearer ${token}`,
}),
})
const unsubscribe = client.subscribe(
{
query: /* GraphQL */ `
subscription {
onDataSourceHealthChanged {
dataSourceId
status
latencyMs
}
}
`,
},
{
next: (event) => console.log(event.data),
error: (err) => console.error(err),
complete: () => console.log('done'),
},
)
Data source health
onDataSourceHealthChanged
Emits whenever a health check is recorded for any data source the caller can see. Use this to drive a dashboard or to invalidate cached health snapshots from dataSource / dataSources.
This subscription takes no arguments — it's a tenant-wide stream. Filter on the client side by dataSourceId if you only care about a specific source.
DataSourceHealthChangedPayload
- Name
dataSourceId- Type
- UUID!
- Description
- Data source whose health was recorded.
- Name
status- Type
- DataSourceHealthStatus!
- Description
UNTESTED,HEALTHY, orUNHEALTHY.
- Name
errorCode- Type
- ConnectorErrorCode
- Description
Error code when the check failed — one of
AUTHENTICATION_FAILED,CONNECTION_REFUSED,TIMEOUT,HOST_UNREACHABLE,INVALID_CONFIGURATION,PERMISSION_DENIED,UNKNOWN.nullwhen healthy.
- Name
errorDetail- Type
- String
- Description
- Detailed error message if the check failed.
- Name
latencyMs- Type
- Long!
- Description
- Latency observed during this check, in milliseconds.
- Name
checkedAt- Type
- DateTime!
- Description
- When the check was recorded (UTC).
Subscription
subscription {
onDataSourceHealthChanged {
dataSourceId
status
errorCode
errorDetail
latencyMs
checkedAt
}
}
Sample event
{
"data": {
"onDataSourceHealthChanged": {
"dataSourceId": "8b3f…",
"status": "UNHEALTHY",
"errorCode": "TIMEOUT",
"errorDetail": "Connection timed out after 10s",
"latencyMs": 10003,
"checkedAt": "2026-05-13T14:22:11.482Z"
}
}
}
Data context locks
onDataContextLockChanged
Emits whenever the editing lock on a specific data context transitions — acquired by a new holder, released, or expired. Use this in a collaborative editor to surface "X is editing" indicators and to detect when your own lock has been taken.
Arguments
- Name
id- Type
- UUID!
- Description
- Data context identifier to watch.
DataContextLockChangedPayload
- Name
status- Type
- DataContextLockStatus!
- Description
ACQUIRED,RELEASED, orEXPIRED.
- Name
holder- Type
- DataContextLockHolder
- Description
New holder when
statusisACQUIRED.nullonRELEASEDandEXPIRED.
- Name
clientId- Type
- String
- Description
Client session that triggered the transition.
Subscription
subscription Lock($id: UUID!) {
onDataContextLockChanged(id: $id) {
status
holder {
userId
userName
}
clientId
}
}
Sample event
{
"data": {
"onDataContextLockChanged": {
"status": "ACQUIRED",
"holder": {
"userId": "1ad2…",
"userName": "Ana Costa"
},
"clientId": "browser-tab-7f3a"
}
}
}
Pair this subscription with resumeDataContextLock to recover gracefully when a reconnect happens while you still hold the lock. See the lock lifecycle for the full editor flow.