diff --git a/.changes/json-serializable b/.changes/json-serializable new file mode 100644 index 00000000..fb5fdad9 --- /dev/null +++ b/.changes/json-serializable @@ -0,0 +1 @@ +patch type="changed" "Migrate manual json serialization to json_serializable code generation" diff --git a/build.yaml b/build.yaml new file mode 100644 index 00000000..02bf52e6 --- /dev/null +++ b/build.yaml @@ -0,0 +1,24 @@ +# Copyright 2024 LiveKit, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +targets: + $default: + sources: + exclude: + - example/** + builders: + json_serializable: + options: + include_if_null: false + explicit_to_json: true diff --git a/lib/src/token_source/caching.dart b/lib/src/token_source/caching.dart index f11d9fa0..f63e6693 100644 --- a/lib/src/token_source/caching.dart +++ b/lib/src/token_source/caching.dart @@ -14,10 +14,14 @@ import 'dart:async'; +import 'package:json_annotation/json_annotation.dart'; + import '../support/reusable_completer.dart'; import 'jwt.dart'; import 'token_source.dart'; +part 'caching.g.dart'; + /// A validator function that determines if cached credentials are still valid. /// /// The validator receives the original request options and cached response, and should @@ -27,6 +31,7 @@ import 'token_source.dart'; typedef TokenValidator = bool Function(TokenRequestOptions options, TokenSourceResponse response); /// A tuple containing the request options and response that were cached. +@JsonSerializable() class TokenStoreItem { final TokenRequestOptions options; final TokenSourceResponse response; @@ -35,6 +40,9 @@ class TokenStoreItem { required this.options, required this.response, }); + + factory TokenStoreItem.fromJson(Map json) => _$TokenStoreItemFromJson(json); + Map toJson() => _$TokenStoreItemToJson(this); } /// Protocol for storing and retrieving cached token credentials. diff --git a/lib/src/token_source/caching.g.dart b/lib/src/token_source/caching.g.dart new file mode 100644 index 00000000..2874d60e --- /dev/null +++ b/lib/src/token_source/caching.g.dart @@ -0,0 +1,17 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'caching.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +TokenStoreItem _$TokenStoreItemFromJson(Map json) => TokenStoreItem( + options: TokenRequestOptions.fromJson(json['options'] as Map), + response: TokenSourceResponse.fromJson(json['response'] as Map), + ); + +Map _$TokenStoreItemToJson(TokenStoreItem instance) => { + 'options': instance.options.toJson(), + 'response': instance.response.toJson(), + }; diff --git a/lib/src/token_source/jwt.dart b/lib/src/token_source/jwt.dart index d613ee7f..35962987 100644 --- a/lib/src/token_source/jwt.dart +++ b/lib/src/token_source/jwt.dart @@ -13,9 +13,12 @@ // limitations under the License. import 'package:dart_jsonwebtoken/dart_jsonwebtoken.dart'; +import 'package:json_annotation/json_annotation.dart'; import 'token_source.dart'; +part 'jwt.g.dart'; + /// Parsed payload for a LiveKit-issued JWT. class LiveKitJwtPayload { LiveKitJwtPayload._(this._claims); @@ -114,17 +117,37 @@ class LiveKitJwtPayload { } /// LiveKit-specific video grants embedded within a JWT. +@JsonSerializable() class LiveKitVideoGrant { final String? room; + + @JsonKey(name: 'room_create') final bool? roomCreate; + + @JsonKey(name: 'room_join') final bool? roomJoin; + + @JsonKey(name: 'room_list') final bool? roomList; + + @JsonKey(name: 'room_record') final bool? roomRecord; + + @JsonKey(name: 'room_admin') final bool? roomAdmin; + + @JsonKey(name: 'can_publish') final bool? canPublish; + + @JsonKey(name: 'can_subscribe') final bool? canSubscribe; + + @JsonKey(name: 'can_publish_data') final bool? canPublishData; + + @JsonKey(name: 'can_publish_sources') final List? canPublishSources; + final bool? hidden; final bool? recorder; @@ -143,20 +166,8 @@ class LiveKitVideoGrant { this.recorder, }); - factory LiveKitVideoGrant.fromJson(Map json) => LiveKitVideoGrant( - room: json['room'] as String?, - roomCreate: json['room_create'] as bool?, - roomJoin: json['room_join'] as bool?, - roomList: json['room_list'] as bool?, - roomRecord: json['room_record'] as bool?, - roomAdmin: json['room_admin'] as bool?, - canPublish: json['can_publish'] as bool?, - canSubscribe: json['can_subscribe'] as bool?, - canPublishData: json['can_publish_data'] as bool?, - canPublishSources: (json['can_publish_sources'] as List?)?.map((dynamic item) => item.toString()).toList(), - hidden: json['hidden'] as bool?, - recorder: json['recorder'] as bool?, - ); + factory LiveKitVideoGrant.fromJson(Map json) => _$LiveKitVideoGrantFromJson(json); + Map toJson() => _$LiveKitVideoGrantToJson(this); } extension TokenSourceJwt on TokenSourceResponse { diff --git a/lib/src/token_source/jwt.g.dart b/lib/src/token_source/jwt.g.dart new file mode 100644 index 00000000..66fd7d5b --- /dev/null +++ b/lib/src/token_source/jwt.g.dart @@ -0,0 +1,37 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'jwt.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +LiveKitVideoGrant _$LiveKitVideoGrantFromJson(Map json) => LiveKitVideoGrant( + room: json['room'] as String?, + roomCreate: json['room_create'] as bool?, + roomJoin: json['room_join'] as bool?, + roomList: json['room_list'] as bool?, + roomRecord: json['room_record'] as bool?, + roomAdmin: json['room_admin'] as bool?, + canPublish: json['can_publish'] as bool?, + canSubscribe: json['can_subscribe'] as bool?, + canPublishData: json['can_publish_data'] as bool?, + canPublishSources: (json['can_publish_sources'] as List?)?.map((e) => e as String).toList(), + hidden: json['hidden'] as bool?, + recorder: json['recorder'] as bool?, + ); + +Map _$LiveKitVideoGrantToJson(LiveKitVideoGrant instance) => { + if (instance.room case final value?) 'room': value, + if (instance.roomCreate case final value?) 'room_create': value, + if (instance.roomJoin case final value?) 'room_join': value, + if (instance.roomList case final value?) 'room_list': value, + if (instance.roomRecord case final value?) 'room_record': value, + if (instance.roomAdmin case final value?) 'room_admin': value, + if (instance.canPublish case final value?) 'can_publish': value, + if (instance.canSubscribe case final value?) 'can_subscribe': value, + if (instance.canPublishData case final value?) 'can_publish_data': value, + if (instance.canPublishSources case final value?) 'can_publish_sources': value, + if (instance.hidden case final value?) 'hidden': value, + if (instance.recorder case final value?) 'recorder': value, + }; diff --git a/lib/src/token_source/room_configuration.dart b/lib/src/token_source/room_configuration.dart index da019fcb..24ce8af8 100644 --- a/lib/src/token_source/room_configuration.dart +++ b/lib/src/token_source/room_configuration.dart @@ -12,9 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +import 'package:json_annotation/json_annotation.dart'; + +part 'room_configuration.g.dart'; + /// Configuration for dispatching an agent to a room. +@JsonSerializable() class RoomAgentDispatch { /// Name of the agent to dispatch. + @JsonKey(name: 'agent_name') final String? agentName; /// Metadata for the agent. @@ -25,40 +31,45 @@ class RoomAgentDispatch { this.metadata, }); - Map toJson() => { - if (agentName != null) 'agent_name': agentName, - if (metadata != null) 'metadata': metadata, - }; + factory RoomAgentDispatch.fromJson(Map json) => _$RoomAgentDispatchFromJson(json); + Map toJson() => _$RoomAgentDispatchToJson(this); } /// Configuration for a LiveKit room. /// /// This class contains various settings that control room behavior such as timeouts, /// participant limits, and agent dispatching. +@JsonSerializable() class RoomConfiguration { /// Room name, used as ID, must be unique. final String? name; /// Number of seconds to keep the room open if no one joins. + @JsonKey(name: 'empty_timeout') final int? emptyTimeout; /// Number of seconds to keep the room open after everyone leaves. + @JsonKey(name: 'departure_timeout') final int? departureTimeout; /// Limit number of participants that can be in a room, excluding Egress and Ingress participants. + @JsonKey(name: 'max_participants') final int? maxParticipants; /// Metadata of room. final String? metadata; /// Minimum playout delay of subscriber. + @JsonKey(name: 'min_playout_delay') final int? minPlayoutDelay; /// Maximum playout delay of subscriber. + @JsonKey(name: 'max_playout_delay') final int? maxPlayoutDelay; /// Improves A/V sync when playout delay set to a value larger than 200ms. /// It will disable transceiver re-use so not recommended for rooms with frequent subscription changes. + @JsonKey(name: 'sync_streams') final bool? syncStreams; /// Define agents that should be dispatched to this room. @@ -76,15 +87,6 @@ class RoomConfiguration { this.agents, }); - Map toJson() => { - if (name != null) 'name': name, - if (emptyTimeout != null) 'empty_timeout': emptyTimeout, - if (departureTimeout != null) 'departure_timeout': departureTimeout, - if (maxParticipants != null) 'max_participants': maxParticipants, - if (metadata != null) 'metadata': metadata, - if (minPlayoutDelay != null) 'min_playout_delay': minPlayoutDelay, - if (maxPlayoutDelay != null) 'max_playout_delay': maxPlayoutDelay, - if (syncStreams != null) 'sync_streams': syncStreams, - if (agents != null) 'agents': agents!.map((a) => a.toJson()).toList(), - }; + factory RoomConfiguration.fromJson(Map json) => _$RoomConfigurationFromJson(json); + Map toJson() => _$RoomConfigurationToJson(this); } diff --git a/lib/src/token_source/room_configuration.g.dart b/lib/src/token_source/room_configuration.g.dart new file mode 100644 index 00000000..c7517a57 --- /dev/null +++ b/lib/src/token_source/room_configuration.g.dart @@ -0,0 +1,43 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'room_configuration.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +RoomAgentDispatch _$RoomAgentDispatchFromJson(Map json) => RoomAgentDispatch( + agentName: json['agent_name'] as String?, + metadata: json['metadata'] as String?, + ); + +Map _$RoomAgentDispatchToJson(RoomAgentDispatch instance) => { + if (instance.agentName case final value?) 'agent_name': value, + if (instance.metadata case final value?) 'metadata': value, + }; + +RoomConfiguration _$RoomConfigurationFromJson(Map json) => RoomConfiguration( + name: json['name'] as String?, + emptyTimeout: (json['empty_timeout'] as num?)?.toInt(), + departureTimeout: (json['departure_timeout'] as num?)?.toInt(), + maxParticipants: (json['max_participants'] as num?)?.toInt(), + metadata: json['metadata'] as String?, + minPlayoutDelay: (json['min_playout_delay'] as num?)?.toInt(), + maxPlayoutDelay: (json['max_playout_delay'] as num?)?.toInt(), + syncStreams: json['sync_streams'] as bool?, + agents: (json['agents'] as List?) + ?.map((e) => RoomAgentDispatch.fromJson(e as Map)) + .toList(), + ); + +Map _$RoomConfigurationToJson(RoomConfiguration instance) => { + if (instance.name case final value?) 'name': value, + if (instance.emptyTimeout case final value?) 'empty_timeout': value, + if (instance.departureTimeout case final value?) 'departure_timeout': value, + if (instance.maxParticipants case final value?) 'max_participants': value, + if (instance.metadata case final value?) 'metadata': value, + if (instance.minPlayoutDelay case final value?) 'min_playout_delay': value, + if (instance.maxPlayoutDelay case final value?) 'max_playout_delay': value, + if (instance.syncStreams case final value?) 'sync_streams': value, + if (instance.agents?.map((e) => e.toJson()).toList() case final value?) 'agents': value, + }; diff --git a/lib/src/token_source/token_source.dart b/lib/src/token_source/token_source.dart index 46137d53..f2f4e830 100644 --- a/lib/src/token_source/token_source.dart +++ b/lib/src/token_source/token_source.dart @@ -13,10 +13,14 @@ // limitations under the License. import 'package:collection/collection.dart'; +import 'package:json_annotation/json_annotation.dart'; import 'room_configuration.dart'; +part 'token_source.g.dart'; + /// Request parameters for generating connection credentials. +@JsonSerializable() class TokenRequestOptions { /// The name of the room to connect to. Required for most token generation scenarios. final String? roomName; @@ -49,6 +53,9 @@ class TokenRequestOptions { this.agentMetadata, }); + factory TokenRequestOptions.fromJson(Map json) => _$TokenRequestOptionsFromJson(json); + Map toJson() => _$TokenRequestOptionsToJson(this); + /// Converts this options object to a wire-format request. TokenSourceRequest toRequest() { final List? agents = (agentName != null || agentMetadata != null) @@ -97,12 +104,24 @@ class TokenRequestOptions { /// /// This is an internal wire format class that separates the public API ([TokenRequestOptions]) /// from the JSON structure sent over the network. +@JsonSerializable() class TokenSourceRequest { + @JsonKey(name: 'room_name') final String? roomName; + + @JsonKey(name: 'participant_name') final String? participantName; + + @JsonKey(name: 'participant_identity') final String? participantIdentity; + + @JsonKey(name: 'participant_metadata') final String? participantMetadata; + + @JsonKey(name: 'participant_attributes') final Map? participantAttributes; + + @JsonKey(name: 'room_config') final RoomConfiguration? roomConfiguration; const TokenSourceRequest({ @@ -114,30 +133,27 @@ class TokenSourceRequest { this.roomConfiguration, }); - Map toJson() { - return { - if (roomName != null) 'room_name': roomName, - if (participantName != null) 'participant_name': participantName, - if (participantIdentity != null) 'participant_identity': participantIdentity, - if (participantMetadata != null) 'participant_metadata': participantMetadata, - if (participantAttributes != null) 'participant_attributes': participantAttributes, - if (roomConfiguration != null) 'room_config': roomConfiguration!.toJson(), - }; - } + factory TokenSourceRequest.fromJson(Map json) => _$TokenSourceRequestFromJson(json); + Map toJson() => _$TokenSourceRequestToJson(this); } /// Response containing the credentials needed to connect to a LiveKit room. +@JsonSerializable() class TokenSourceResponse { /// The WebSocket URL for the LiveKit server. Use this to establish the connection. + @JsonKey(name: 'server_url') final String serverUrl; /// The JWT token containing participant permissions and metadata. Required for authentication. + @JsonKey(name: 'participant_token') final String participantToken; /// The display name for the participant in the room. May be null if not specified. + @JsonKey(name: 'participant_name') final String? participantName; /// The name of the room the participant will join. May be null if not specified. + @JsonKey(name: 'room_name') final String? roomName; const TokenSourceResponse({ @@ -147,14 +163,20 @@ class TokenSourceResponse { this.roomName, }); + /// Factory constructor supporting both snake_case and camelCase for backward compatibility. factory TokenSourceResponse.fromJson(Map json) { - return TokenSourceResponse( - serverUrl: (json['server_url'] ?? json['serverUrl']) as String, - participantToken: (json['participant_token'] ?? json['participantToken']) as String, - participantName: (json['participant_name'] ?? json['participantName']) as String?, - roomName: (json['room_name'] ?? json['roomName']) as String?, - ); + // Normalize camelCase to snake_case for backward compatibility + final normalized = { + 'server_url': json['server_url'] ?? json['serverUrl'], + 'participant_token': json['participant_token'] ?? json['participantToken'], + if (json['participant_name'] != null || json['participantName'] != null) + 'participant_name': json['participant_name'] ?? json['participantName'], + if (json['room_name'] != null || json['roomName'] != null) 'room_name': json['room_name'] ?? json['roomName'], + }; + return _$TokenSourceResponseFromJson(normalized); } + + Map toJson() => _$TokenSourceResponseToJson(this); } /// A token source that returns a fixed set of credentials without configurable options. diff --git a/lib/src/token_source/token_source.g.dart b/lib/src/token_source/token_source.g.dart new file mode 100644 index 00000000..a5ac7308 --- /dev/null +++ b/lib/src/token_source/token_source.g.dart @@ -0,0 +1,64 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'token_source.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +TokenRequestOptions _$TokenRequestOptionsFromJson(Map json) => TokenRequestOptions( + roomName: json['roomName'] as String?, + participantName: json['participantName'] as String?, + participantIdentity: json['participantIdentity'] as String?, + participantMetadata: json['participantMetadata'] as String?, + participantAttributes: (json['participantAttributes'] as Map?)?.map( + (k, e) => MapEntry(k, e as String), + ), + agentName: json['agentName'] as String?, + agentMetadata: json['agentMetadata'] as String?, + ); + +Map _$TokenRequestOptionsToJson(TokenRequestOptions instance) => { + if (instance.roomName case final value?) 'roomName': value, + if (instance.participantName case final value?) 'participantName': value, + if (instance.participantIdentity case final value?) 'participantIdentity': value, + if (instance.participantMetadata case final value?) 'participantMetadata': value, + if (instance.participantAttributes case final value?) 'participantAttributes': value, + if (instance.agentName case final value?) 'agentName': value, + if (instance.agentMetadata case final value?) 'agentMetadata': value, + }; + +TokenSourceRequest _$TokenSourceRequestFromJson(Map json) => TokenSourceRequest( + roomName: json['room_name'] as String?, + participantName: json['participant_name'] as String?, + participantIdentity: json['participant_identity'] as String?, + participantMetadata: json['participant_metadata'] as String?, + participantAttributes: (json['participant_attributes'] as Map?)?.map( + (k, e) => MapEntry(k, e as String), + ), + roomConfiguration: + json['room_config'] == null ? null : RoomConfiguration.fromJson(json['room_config'] as Map), + ); + +Map _$TokenSourceRequestToJson(TokenSourceRequest instance) => { + if (instance.roomName case final value?) 'room_name': value, + if (instance.participantName case final value?) 'participant_name': value, + if (instance.participantIdentity case final value?) 'participant_identity': value, + if (instance.participantMetadata case final value?) 'participant_metadata': value, + if (instance.participantAttributes case final value?) 'participant_attributes': value, + if (instance.roomConfiguration?.toJson() case final value?) 'room_config': value, + }; + +TokenSourceResponse _$TokenSourceResponseFromJson(Map json) => TokenSourceResponse( + serverUrl: json['server_url'] as String, + participantToken: json['participant_token'] as String, + participantName: json['participant_name'] as String?, + roomName: json['room_name'] as String?, + ); + +Map _$TokenSourceResponseToJson(TokenSourceResponse instance) => { + 'server_url': instance.serverUrl, + 'participant_token': instance.participantToken, + if (instance.participantName case final value?) 'participant_name': value, + if (instance.roomName case final value?) 'room_name': value, + }; diff --git a/lib/src/types/attribute_typings.dart b/lib/src/types/attribute_typings.dart index b389f055..2601b0f2 100644 --- a/lib/src/types/attribute_typings.dart +++ b/lib/src/types/attribute_typings.dart @@ -5,6 +5,10 @@ import 'dart:convert'; +import 'package:json_annotation/json_annotation.dart'; + +part 'attribute_typings.g.dart'; + AgentAttributes agentAttributesFromJson(String str) => AgentAttributes.fromJson(json.decode(str)); String agentAttributesToJson(AgentAttributes data) => json.encode(data.toJson()); @@ -14,10 +18,18 @@ TranscriptionAttributes transcriptionAttributesFromJson(String str) => String transcriptionAttributesToJson(TranscriptionAttributes data) => json.encode(data.toJson()); +@JsonSerializable() class AgentAttributes { + @JsonKey(name: 'lk.agent.inputs') List? lkAgentInputs; + + @JsonKey(name: 'lk.agent.outputs') List? lkAgentOutputs; + + @JsonKey(name: 'lk.agent.state') AgentState? lkAgentState; + + @JsonKey(name: 'lk.publish_on_behalf') String? lkPublishOnBehalf; AgentAttributes({ @@ -27,54 +39,55 @@ class AgentAttributes { this.lkPublishOnBehalf, }); - factory AgentAttributes.fromJson(Map json) => AgentAttributes( - lkAgentInputs: json['lk.agent.inputs'] == null - ? [] - : List.from(json['lk.agent.inputs']!.map((x) => agentInputValues.map[x]!)), - lkAgentOutputs: json['lk.agent.outputs'] == null - ? [] - : List.from(json['lk.agent.outputs']!.map((x) => agentOutputValues.map[x]!)), - lkAgentState: agentStateValues.map[json['lk.agent.state']]!, - lkPublishOnBehalf: json['lk.publish_on_behalf'], - ); - - Map toJson() => { - 'lk.agent.inputs': - lkAgentInputs == null ? [] : List.from(lkAgentInputs!.map((x) => agentInputValues.reverse[x])), - 'lk.agent.outputs': - lkAgentOutputs == null ? [] : List.from(lkAgentOutputs!.map((x) => agentOutputValues.reverse[x])), - 'lk.agent.state': agentStateValues.reverse[lkAgentState], - 'lk.publish_on_behalf': lkPublishOnBehalf, - }; + factory AgentAttributes.fromJson(Map json) => _$AgentAttributesFromJson(json); + Map toJson() => _$AgentAttributesToJson(this); } -enum AgentInput { AUDIO, TEXT, VIDEO } - -final agentInputValues = EnumValues({'audio': AgentInput.AUDIO, 'text': AgentInput.TEXT, 'video': AgentInput.VIDEO}); - -enum AgentOutput { AUDIO, TRANSCRIPTION } - -final agentOutputValues = EnumValues({'audio': AgentOutput.AUDIO, 'transcription': AgentOutput.TRANSCRIPTION}); +@JsonEnum() +enum AgentInput { + @JsonValue('audio') + audio, + @JsonValue('text') + text, + @JsonValue('video') + video, +} -enum AgentState { IDLE, INITIALIZING, LISTENING, SPEAKING, THINKING } +@JsonEnum() +enum AgentOutput { + @JsonValue('audio') + audio, + @JsonValue('transcription') + transcription, +} -final agentStateValues = EnumValues({ - 'idle': AgentState.IDLE, - 'initializing': AgentState.INITIALIZING, - 'listening': AgentState.LISTENING, - 'speaking': AgentState.SPEAKING, - 'thinking': AgentState.THINKING -}); +@JsonEnum() +enum AgentState { + @JsonValue('idle') + idle, + @JsonValue('initializing') + initializing, + @JsonValue('listening') + listening, + @JsonValue('speaking') + speaking, + @JsonValue('thinking') + thinking, +} ///Schema for transcription-related attributes +@JsonSerializable() class TranscriptionAttributes { ///The segment id of the transcription + @JsonKey(name: 'lk.segment_id') String? lkSegmentId; ///The associated track id of the transcription + @JsonKey(name: 'lk.transcribed_track_id') String? lkTranscribedTrackId; ///Whether the transcription is final + @JsonKey(name: 'lk.transcription_final') bool? lkTranscriptionFinal; TranscriptionAttributes({ @@ -83,27 +96,6 @@ class TranscriptionAttributes { this.lkTranscriptionFinal, }); - factory TranscriptionAttributes.fromJson(Map json) => TranscriptionAttributes( - lkSegmentId: json['lk.segment_id'], - lkTranscribedTrackId: json['lk.transcribed_track_id'], - lkTranscriptionFinal: json['lk.transcription_final'], - ); - - Map toJson() => { - 'lk.segment_id': lkSegmentId, - 'lk.transcribed_track_id': lkTranscribedTrackId, - 'lk.transcription_final': lkTranscriptionFinal, - }; -} - -class EnumValues { - Map map; - late Map reverseMap; - - EnumValues(this.map); - - Map get reverse { - reverseMap = map.map((k, v) => MapEntry(v, k)); - return reverseMap; - } + factory TranscriptionAttributes.fromJson(Map json) => _$TranscriptionAttributesFromJson(json); + Map toJson() => _$TranscriptionAttributesToJson(this); } diff --git a/lib/src/types/attribute_typings.g.dart b/lib/src/types/attribute_typings.g.dart new file mode 100644 index 00000000..05814fe1 --- /dev/null +++ b/lib/src/types/attribute_typings.g.dart @@ -0,0 +1,56 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'attribute_typings.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +AgentAttributes _$AgentAttributesFromJson(Map json) => AgentAttributes( + lkAgentInputs: + (json['lk.agent.inputs'] as List?)?.map((e) => $enumDecode(_$AgentInputEnumMap, e)).toList(), + lkAgentOutputs: + (json['lk.agent.outputs'] as List?)?.map((e) => $enumDecode(_$AgentOutputEnumMap, e)).toList(), + lkAgentState: $enumDecodeNullable(_$AgentStateEnumMap, json['lk.agent.state']), + lkPublishOnBehalf: json['lk.publish_on_behalf'] as String?, + ); + +Map _$AgentAttributesToJson(AgentAttributes instance) => { + if (instance.lkAgentInputs?.map((e) => _$AgentInputEnumMap[e]!).toList() case final value?) + 'lk.agent.inputs': value, + if (instance.lkAgentOutputs?.map((e) => _$AgentOutputEnumMap[e]!).toList() case final value?) + 'lk.agent.outputs': value, + if (_$AgentStateEnumMap[instance.lkAgentState] case final value?) 'lk.agent.state': value, + if (instance.lkPublishOnBehalf case final value?) 'lk.publish_on_behalf': value, + }; + +const _$AgentInputEnumMap = { + AgentInput.audio: 'audio', + AgentInput.text: 'text', + AgentInput.video: 'video', +}; + +const _$AgentOutputEnumMap = { + AgentOutput.audio: 'audio', + AgentOutput.transcription: 'transcription', +}; + +const _$AgentStateEnumMap = { + AgentState.idle: 'idle', + AgentState.initializing: 'initializing', + AgentState.listening: 'listening', + AgentState.speaking: 'speaking', + AgentState.thinking: 'thinking', +}; + +TranscriptionAttributes _$TranscriptionAttributesFromJson(Map json) => TranscriptionAttributes( + lkSegmentId: json['lk.segment_id'] as String?, + lkTranscribedTrackId: json['lk.transcribed_track_id'] as String?, + lkTranscriptionFinal: json['lk.transcription_final'] as bool?, + ); + +Map _$TranscriptionAttributesToJson(TranscriptionAttributes instance) => { + if (instance.lkSegmentId case final value?) 'lk.segment_id': value, + if (instance.lkTranscribedTrackId case final value?) 'lk.transcribed_track_id': value, + if (instance.lkTranscriptionFinal case final value?) 'lk.transcription_final': value, + }; diff --git a/pubspec.lock b/pubspec.lock index b38eb7b1..dd095b14 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: c209688d9f5a5f26b2fb47a188131a6fb9e876ae9e47af3737c0b4f58a93470d + sha256: da0d9209ca76bde579f2da330aeb9df62b6319c834fa7baae052021b0462401f url: "https://pub.dev" source: hosted - version: "91.0.0" + version: "85.0.0" adaptive_number: dependency: transitive description: @@ -21,10 +21,10 @@ packages: dependency: transitive description: name: analyzer - sha256: f51c8499b35f9b26820cfe914828a6a98a94efd5cc78b37bb7d03debae3a1d08 + sha256: "974859dc0ff5f37bc4313244b3218c791810d03ab3470a579580279ba971a48d" url: "https://pub.dev" source: hosted - version: "8.4.1" + version: "7.7.1" args: dependency: transitive description: @@ -53,10 +53,50 @@ packages: dependency: transitive description: name: build - sha256: dfb67ccc9a78c642193e0c2d94cb9e48c2c818b3178a86097d644acdcde6a8d9 + sha256: "51dc711996cbf609b90cbe5b335bbce83143875a9d58e4b5c6d3c4f684d3dda7" url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "2.5.4" + build_config: + dependency: transitive + description: + name: build_config + sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33" + url: "https://pub.dev" + source: hosted + version: "1.1.2" + build_daemon: + dependency: transitive + description: + name: build_daemon + sha256: "409002f1adeea601018715d613115cfaf0e31f512cb80ae4534c79867ae2363d" + url: "https://pub.dev" + source: hosted + version: "4.1.0" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + sha256: ee4257b3f20c0c90e72ed2b57ad637f694ccba48839a821e87db762548c22a62 + url: "https://pub.dev" + source: hosted + version: "2.5.4" + build_runner: + dependency: "direct dev" + description: + name: build_runner + sha256: "382a4d649addbfb7ba71a3631df0ec6a45d5ab9b098638144faf27f02778eb53" + url: "https://pub.dev" + source: hosted + version: "2.5.4" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + sha256: "85fbbb1036d576d966332a3f5ce83f2ce66a40bea1a94ad2d5fc29a19a0d3792" + url: "https://pub.dev" + source: hosted + version: "9.1.2" built_collection: dependency: transitive description: @@ -81,6 +121,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.0" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f" + url: "https://pub.dev" + source: hosted + version: "2.0.4" clock: dependency: transitive description: @@ -149,10 +197,10 @@ packages: dependency: transitive description: name: dart_style - sha256: c87dfe3d56f183ffe9106a18aebc6db431fc7c98c31a54b952a77f3d54a85697 + sha256: "8a0e5fba27e8ee025d2ffb4ee820b4e6e2cf5e4246a6b1a477eb66866947e0bb" url: "https://pub.dev" source: hosted - version: "3.1.2" + version: "3.1.1" dart_webrtc: dependency: "direct main" description: @@ -248,6 +296,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 + url: "https://pub.dev" + source: hosted + version: "4.0.0" glob: dependency: transitive description: @@ -256,6 +312,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.3" + graphs: + dependency: transitive + description: + name: graphs + sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" + url: "https://pub.dev" + source: hosted + version: "2.3.2" http: dependency: "direct main" description: @@ -264,6 +328,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.0" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8 + url: "https://pub.dev" + source: hosted + version: "3.2.2" http_parser: dependency: transitive description: @@ -280,6 +352,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.6.0" + io: + dependency: transitive + description: + name: io + sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b + url: "https://pub.dev" + source: hosted + version: "1.0.5" js: dependency: transitive description: @@ -288,6 +368,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.2" + json_annotation: + dependency: "direct main" + description: + name: json_annotation + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" + url: "https://pub.dev" + source: hosted + version: "4.9.0" + json_serializable: + dependency: "direct dev" + description: + name: json_serializable + sha256: c50ef5fc083d5b5e12eef489503ba3bf5ccc899e487d691584699b4bdefeea8c + url: "https://pub.dev" + source: hosted + version: "6.9.5" leak_tracker: dependency: transitive description: @@ -360,6 +456,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.16.0" + mime: + dependency: transitive + description: + name: mime + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + url: "https://pub.dev" + source: hosted + version: "2.0.0" mime_type: dependency: "direct main" description: @@ -372,10 +476,10 @@ packages: dependency: "direct dev" description: name: mockito - sha256: "4feb43bc4eb6c03e832f5fcd637d1abb44b98f9cfa245c58e27382f58859f8f6" + sha256: "4546eac99e8967ea91bae633d2ca7698181d008e95fa4627330cf903d573277a" url: "https://pub.dev" source: hosted - version: "5.5.1" + version: "5.4.6" nm: dependency: transitive description: @@ -480,6 +584,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.0" + pool: + dependency: transitive + description: + name: pool + sha256: "978783255c543aa3586a1b3c21f6e9d720eb315376a915872c61ef8b5c20177d" + url: "https://pub.dev" + source: hosted + version: "1.5.2" protobuf: dependency: "direct main" description: @@ -496,6 +608,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.0" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082" + url: "https://pub.dev" + source: hosted + version: "1.5.0" sdp_transform: dependency: "direct main" description: @@ -504,6 +624,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.3.2" + shelf: + dependency: transitive + description: + name: shelf + sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 + url: "https://pub.dev" + source: hosted + version: "1.4.2" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925" + url: "https://pub.dev" + source: hosted + version: "3.0.0" sky_engine: dependency: transitive description: flutter @@ -513,10 +649,18 @@ packages: dependency: transitive description: name: source_gen - sha256: "9098ab86015c4f1d8af6486b547b11100e73b193e1899015033cb3e14ad20243" + sha256: "35c8150ece9e8c8d263337a265153c3329667640850b9304861faea59fc98f6b" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + source_helper: + dependency: transitive + description: + name: source_helper + sha256: a447acb083d3a5ef17f983dd36201aeea33fedadb3228fa831f2f0c92f0f3aca url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "1.3.7" source_span: dependency: transitive description: @@ -549,6 +693,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 + url: "https://pub.dev" + source: hosted + version: "2.1.1" string_scanner: dependency: transitive description: @@ -581,6 +733,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.6" + timing: + dependency: transitive + description: + name: timing + sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" + url: "https://pub.dev" + source: hosted + version: "1.0.2" tint: dependency: transitive description: @@ -637,6 +797,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.1" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8 + url: "https://pub.dev" + source: hosted + version: "3.0.3" webrtc_interface: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index c55990b8..5d15cef0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -43,6 +43,7 @@ dependencies: mime_type: ^1.0.1 path: ^1.9.1 dart_jsonwebtoken: ^3.3.1 + json_annotation: ^4.9.0 # Fix version to avoid version conflicts between WebRTC-SDK pods, which both this package and flutter_webrtc depend on. flutter_webrtc: 1.2.0 @@ -55,6 +56,8 @@ dev_dependencies: mockito: ^5.3.2 import_sorter: ^4.6.0 yaml: ^3.1.2 + build_runner: ^2.4.13 + json_serializable: '>=6.9.1 <6.10.0' import_sorter: comments: false