decodeEvent static method
Decodes one event, rejecting unknown or malformed payloads safely.
Implementation
static JackfieldEvent decodeEvent(Object? payload) {
if (payload is! Map) {
throw const JackfieldProtocolException('Expected an event object');
}
final data = <String, Object?>{};
for (final entry in payload.entries) {
if (entry.key is! String) {
throw const JackfieldProtocolException('Expected string field names');
}
data[entry.key as String] = entry.value;
}
if (data['version'] is! int || data['version'] != version) {
throw const JackfieldProtocolException('Unsupported event version');
}
final type = data['type'];
final requiredKeys = switch (type) {
'answer_requested' => const {
'version',
'type',
'callId',
'actionId',
'eventId',
'sequence',
'occurredAt',
'deadline',
},
'ended' => const {
'version',
'type',
'callId',
'eventId',
'sequence',
'occurredAt',
'reason',
},
_ => throw const JackfieldProtocolException('Unknown event type'),
};
if (data.keys.toSet().difference(requiredKeys).isNotEmpty ||
requiredKeys.difference(data.keys.toSet()).isNotEmpty) {
throw const JackfieldProtocolException('Invalid event fields');
}
final callId = CallId(_nonemptyString(data, 'callId'));
final eventId = EventId(_nonemptyString(data, 'eventId'));
final sequence = data['sequence'];
if (sequence is! int || sequence < 0) {
throw const JackfieldProtocolException('Invalid event sequence');
}
final occurredAt = _timestamp(data, 'occurredAt');
return switch (type) {
'answer_requested' => AnswerRequested(
callId: callId,
eventId: eventId,
sequence: sequence,
occurredAt: occurredAt,
actionId: ActionId(_nonemptyString(data, 'actionId')),
deadline: _timestamp(data, 'deadline'),
),
'ended' => CallEnded(
callId: callId,
eventId: eventId,
sequence: sequence,
occurredAt: occurredAt,
reason: _endReason(data),
),
_ => throw const JackfieldProtocolException('Unknown event type'),
};
}