diff --git a/packages/algoliasearch/pubspec.yaml b/packages/algoliasearch/pubspec.yaml
index b8028f1..51e5226 100644
--- a/packages/algoliasearch/pubspec.yaml
+++ b/packages/algoliasearch/pubspec.yaml
@@ -22,4 +22,4 @@ dev_dependencies:
   json_serializable: ^6.7.0
   lints: ^5.0.0
   logging: ^1.2.0
-  test: ^1.25.8
+  test: ^1.25.8
\ No newline at end of file
diff --git a/packages/client_composition/LICENSE b/packages/client_composition/LICENSE
new file mode 100644
index 0000000..fddf416
--- /dev/null
+++ b/packages/client_composition/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2013-Present Algolia
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/packages/client_composition/build.yaml b/packages/client_composition/build.yaml
new file mode 100644
index 0000000..6d71b40
--- /dev/null
+++ b/packages/client_composition/build.yaml
@@ -0,0 +1,14 @@
+targets:
+  $default:
+    builders:
+      json_serializable:
+        options:
+          any_map: false
+          checked: true
+          create_factory: true
+          create_to_json: true
+          disallow_unrecognized_keys: false
+          explicit_to_json: true
+          field_rename: none
+          ignore_unannotated: false
+          include_if_null: false
diff --git a/packages/client_composition/lib/algolia_client_composition.dart b/packages/client_composition/lib/algolia_client_composition.dart
new file mode 100644
index 0000000..24311a8
--- /dev/null
+++ b/packages/client_composition/lib/algolia_client_composition.dart
@@ -0,0 +1,58 @@
+// A sub-package of the AlgoliaSearch library, offering composition-specific functionalities for enhanced search and discovery in Dart/Flutter apps.
+library;
+
+export 'package:algolia_client_core/algolia_client_core.dart';
+
+export 'src/api/composition_client.dart';
+
+export 'src/model/around_radius_all.dart';
+export 'src/model/banner.dart';
+export 'src/model/banner_image.dart';
+export 'src/model/banner_image_url.dart';
+export 'src/model/banner_link.dart';
+export 'src/model/base_search_response.dart';
+export 'src/model/composition_base_search_response.dart';
+export 'src/model/composition_id_ranking_info.dart';
+export 'src/model/composition_ranking_info.dart';
+export 'src/model/composition_run_applied_rules.dart';
+export 'src/model/composition_run_search_response.dart';
+export 'src/model/compositions_search_response.dart';
+export 'src/model/error_base.dart';
+export 'src/model/exhaustive.dart';
+export 'src/model/facet_hits.dart';
+export 'src/model/facet_ordering.dart';
+export 'src/model/facet_stats.dart';
+export 'src/model/facets.dart';
+export 'src/model/highlight_result_option.dart';
+export 'src/model/hit.dart';
+export 'src/model/hit_ranking_info.dart';
+export 'src/model/match_level.dart';
+export 'src/model/matched_geo_location.dart';
+export 'src/model/params.dart';
+export 'src/model/personalization.dart';
+export 'src/model/range.dart';
+export 'src/model/ranking_info.dart';
+export 'src/model/redirect.dart';
+export 'src/model/redirect_rule_index_data.dart';
+export 'src/model/redirect_rule_index_metadata.dart';
+export 'src/model/redirect_url.dart';
+export 'src/model/rendering_content.dart';
+export 'src/model/request_body.dart';
+export 'src/model/results_composition_info_response.dart';
+export 'src/model/results_compositions_response.dart';
+export 'src/model/results_injected_item_applied_rules_info_response.dart';
+export 'src/model/results_injected_item_info_response.dart';
+export 'src/model/search_for_facet_values_params.dart';
+export 'src/model/search_for_facet_values_request.dart';
+export 'src/model/search_for_facet_values_response.dart';
+export 'src/model/search_for_facet_values_results.dart';
+export 'src/model/search_hits.dart';
+export 'src/model/search_pagination.dart';
+export 'src/model/search_response.dart';
+export 'src/model/search_results.dart';
+export 'src/model/search_results_item.dart';
+export 'src/model/snippet_result_option.dart';
+export 'src/model/sort_remaining_by.dart';
+export 'src/model/supported_language.dart';
+export 'src/model/value.dart';
+export 'src/model/widgets.dart';
diff --git a/packages/client_composition/lib/src/api/composition_client.dart b/packages/client_composition/lib/src/api/composition_client.dart
new file mode 100644
index 0000000..1990fdf
--- /dev/null
+++ b/packages/client_composition/lib/src/api/composition_client.dart
@@ -0,0 +1,133 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+
+import 'package:algolia_client_core/algolia_client_core.dart';
+import 'package:algolia_client_composition/src/deserialize.dart';
+import 'package:algolia_client_composition/src/version.dart';
+
+import 'package:algolia_client_composition/src/model/request_body.dart';
+import 'package:algolia_client_composition/src/model/search_for_facet_values_request.dart';
+import 'package:algolia_client_composition/src/model/search_for_facet_values_response.dart';
+import 'package:algolia_client_composition/src/model/search_response.dart';
+
+final class CompositionClient implements ApiClient {
+  @override
+  final ClientOptions options;
+
+  final RetryStrategy _retryStrategy;
+
+  CompositionClient({
+    required String appId,
+    required String apiKey,
+    this.options = const ClientOptions(),
+  }) : _retryStrategy = RetryStrategy.create(
+          segment: AgentSegment(value: "Composition", version: packageVersion),
+          appId: appId,
+          apiKey: apiKey,
+          options: options,
+          defaultHosts: () =>
+              [
+                Host(url: '$appId-dsn.algolia.net', callType: CallType.read),
+                Host(url: '$appId.algolia.net', callType: CallType.write),
+              ] +
+              ([
+                Host(url: '$appId-1.algolianet.com'),
+                Host(url: '$appId-2.algolianet.com'),
+                Host(url: '$appId-3.algolianet.com'),
+              ]..shuffle()),
+        ) {
+    assert(appId.isNotEmpty, '`appId` is missing.');
+    assert(apiKey.isNotEmpty, '`apiKey` is missing.');
+  }
+
+  /// Allows to switch the API key used to authenticate requests.
+  @override
+  void setClientApiKey({required String apiKey}) {
+    _retryStrategy.requester.setClientApiKey(apiKey);
+  }
+
+  /// Runs a query on a single composition and returns matching results.
+  ///
+  /// Required API Key ACLs:
+  ///   - search
+  ///
+  /// Parameters:
+  /// * [compositionID] Unique Composition ObjectID.
+  /// * [requestBody]
+  /// * [requestOptions] additional request configuration.
+  Future<SearchResponse> search({
+    required String compositionID,
+    required RequestBody requestBody,
+    RequestOptions? requestOptions,
+  }) async {
+    assert(
+      compositionID.isNotEmpty,
+      'Parameter `compositionID` is required when calling `search`.',
+    );
+    final request = ApiRequest(
+      method: RequestMethod.post,
+      path: r'/1/compositions/{compositionID}/run'.replaceAll(
+          '{' r'compositionID' '}',
+          Uri.encodeComponent(compositionID.toString())),
+      isRead: true,
+      body: requestBody.toJson(),
+    );
+    final response = await _retryStrategy.execute(
+      request: request,
+      options: requestOptions,
+    );
+    return deserialize<SearchResponse, SearchResponse>(
+      response,
+      'SearchResponse',
+      growable: true,
+    );
+  }
+
+  /// Searches for values of a specified facet attribute on the composition's main source's index.  - By default, facet values are sorted by decreasing count.   You can adjust this with the `sortFacetValueBy` parameter. - Searching for facet values doesn't work if you have **more than 65 searchable facets and searchable attributes combined**.
+  ///
+  /// Required API Key ACLs:
+  ///   - search
+  ///
+  /// Parameters:
+  /// * [compositionID] Unique Composition ObjectID.
+  /// * [facetName] Facet attribute in which to search for values.  This attribute must be included in the `attributesForFaceting` index setting with the `searchable()` modifier.
+  /// * [searchForFacetValuesRequest]
+  /// * [requestOptions] additional request configuration.
+  Future<SearchForFacetValuesResponse> searchForFacetValues({
+    required String compositionID,
+    required String facetName,
+    SearchForFacetValuesRequest? searchForFacetValuesRequest,
+    RequestOptions? requestOptions,
+  }) async {
+    assert(
+      compositionID.isNotEmpty,
+      'Parameter `compositionID` is required when calling `searchForFacetValues`.',
+    );
+    assert(
+      facetName.isNotEmpty,
+      'Parameter `facetName` is required when calling `searchForFacetValues`.',
+    );
+    final request = ApiRequest(
+      method: RequestMethod.post,
+      path: r'/1/compositions/{compositionID}/facets/{facetName}/query'
+          .replaceAll('{' r'compositionID' '}',
+              Uri.encodeComponent(compositionID.toString()))
+          .replaceAll(
+              '{' r'facetName' '}', Uri.encodeComponent(facetName.toString())),
+      isRead: true,
+      body: searchForFacetValuesRequest?.toJson(),
+    );
+    final response = await _retryStrategy.execute(
+      request: request,
+      options: requestOptions,
+    );
+    return deserialize<SearchForFacetValuesResponse,
+        SearchForFacetValuesResponse>(
+      response,
+      'SearchForFacetValuesResponse',
+      growable: true,
+    );
+  }
+
+  @override
+  void dispose() => _retryStrategy.dispose();
+}
diff --git a/packages/client_composition/lib/src/deserialize.dart b/packages/client_composition/lib/src/deserialize.dart
new file mode 100644
index 0000000..8d7528c
--- /dev/null
+++ b/packages/client_composition/lib/src/deserialize.dart
@@ -0,0 +1,237 @@
+import 'package:algolia_client_composition/src/model/around_radius_all.dart';
+import 'package:algolia_client_composition/src/model/banner.dart';
+import 'package:algolia_client_composition/src/model/banner_image.dart';
+import 'package:algolia_client_composition/src/model/banner_image_url.dart';
+import 'package:algolia_client_composition/src/model/banner_link.dart';
+import 'package:algolia_client_composition/src/model/base_search_response.dart';
+import 'package:algolia_client_composition/src/model/composition_base_search_response.dart';
+import 'package:algolia_client_composition/src/model/composition_id_ranking_info.dart';
+import 'package:algolia_client_composition/src/model/composition_ranking_info.dart';
+import 'package:algolia_client_composition/src/model/composition_run_applied_rules.dart';
+import 'package:algolia_client_composition/src/model/composition_run_search_response.dart';
+import 'package:algolia_client_composition/src/model/compositions_search_response.dart';
+import 'package:algolia_client_composition/src/model/error_base.dart';
+import 'package:algolia_client_composition/src/model/exhaustive.dart';
+import 'package:algolia_client_composition/src/model/facet_hits.dart';
+import 'package:algolia_client_composition/src/model/facet_ordering.dart';
+import 'package:algolia_client_composition/src/model/facet_stats.dart';
+import 'package:algolia_client_composition/src/model/facets.dart';
+import 'package:algolia_client_composition/src/model/highlight_result_option.dart';
+import 'package:algolia_client_composition/src/model/hit.dart';
+import 'package:algolia_client_composition/src/model/hit_ranking_info.dart';
+import 'package:algolia_client_composition/src/model/match_level.dart';
+import 'package:algolia_client_composition/src/model/matched_geo_location.dart';
+import 'package:algolia_client_composition/src/model/params.dart';
+import 'package:algolia_client_composition/src/model/personalization.dart';
+import 'package:algolia_client_composition/src/model/range.dart';
+import 'package:algolia_client_composition/src/model/ranking_info.dart';
+import 'package:algolia_client_composition/src/model/redirect.dart';
+import 'package:algolia_client_composition/src/model/redirect_rule_index_data.dart';
+import 'package:algolia_client_composition/src/model/redirect_rule_index_metadata.dart';
+import 'package:algolia_client_composition/src/model/redirect_url.dart';
+import 'package:algolia_client_composition/src/model/rendering_content.dart';
+import 'package:algolia_client_composition/src/model/request_body.dart';
+import 'package:algolia_client_composition/src/model/results_composition_info_response.dart';
+import 'package:algolia_client_composition/src/model/results_compositions_response.dart';
+import 'package:algolia_client_composition/src/model/results_injected_item_applied_rules_info_response.dart';
+import 'package:algolia_client_composition/src/model/results_injected_item_info_response.dart';
+import 'package:algolia_client_composition/src/model/search_for_facet_values_params.dart';
+import 'package:algolia_client_composition/src/model/search_for_facet_values_request.dart';
+import 'package:algolia_client_composition/src/model/search_for_facet_values_response.dart';
+import 'package:algolia_client_composition/src/model/search_for_facet_values_results.dart';
+import 'package:algolia_client_composition/src/model/search_hits.dart';
+import 'package:algolia_client_composition/src/model/search_pagination.dart';
+import 'package:algolia_client_composition/src/model/search_response.dart';
+import 'package:algolia_client_composition/src/model/search_results.dart';
+import 'package:algolia_client_composition/src/model/search_results_item.dart';
+import 'package:algolia_client_composition/src/model/snippet_result_option.dart';
+import 'package:algolia_client_composition/src/model/sort_remaining_by.dart';
+import 'package:algolia_client_composition/src/model/supported_language.dart';
+import 'package:algolia_client_composition/src/model/value.dart';
+import 'package:algolia_client_composition/src/model/widgets.dart';
+
+final _regList = RegExp(r'^List<(.*)>$');
+final _regSet = RegExp(r'^Set<(.*)>$');
+final _regMap = RegExp(r'^Map<String,(.*)>$');
+
+ReturnType deserialize<ReturnType, BaseType>(dynamic value, String targetType,
+    {bool growable = true}) {
+  switch (targetType) {
+    case 'String':
+      return '$value' as ReturnType;
+    case 'int':
+      return (value is int ? value : int.parse('$value')) as ReturnType;
+    case 'bool':
+      if (value is bool) {
+        return value as ReturnType;
+      }
+      final valueString = '$value'.toLowerCase();
+      return (valueString == 'true' || valueString == '1') as ReturnType;
+    case 'double':
+      return (value is double ? value : double.parse('$value')) as ReturnType;
+    case 'AroundRadiusAll':
+      return AroundRadiusAll.fromJson(value) as ReturnType;
+    case 'Banner':
+      return Banner.fromJson(value as Map<String, dynamic>) as ReturnType;
+    case 'BannerImage':
+      return BannerImage.fromJson(value as Map<String, dynamic>) as ReturnType;
+    case 'BannerImageUrl':
+      return BannerImageUrl.fromJson(value as Map<String, dynamic>)
+          as ReturnType;
+    case 'BannerLink':
+      return BannerLink.fromJson(value as Map<String, dynamic>) as ReturnType;
+    case 'BaseSearchResponse':
+      return BaseSearchResponse.fromJson(value as Map<String, dynamic>)
+          as ReturnType;
+    case 'CompositionBaseSearchResponse':
+      return CompositionBaseSearchResponse.fromJson(
+          value as Map<String, dynamic>) as ReturnType;
+    case 'CompositionIdRankingInfo':
+      return CompositionIdRankingInfo.fromJson(value as Map<String, dynamic>)
+          as ReturnType;
+    case 'CompositionRankingInfo':
+      return CompositionRankingInfo.fromJson(value as Map<String, dynamic>)
+          as ReturnType;
+    case 'CompositionRunAppliedRules':
+      return CompositionRunAppliedRules.fromJson(value as Map<String, dynamic>)
+          as ReturnType;
+    case 'CompositionRunSearchResponse':
+      return CompositionRunSearchResponse.fromJson(
+          value as Map<String, dynamic>) as ReturnType;
+    case 'CompositionsSearchResponse':
+      return CompositionsSearchResponse.fromJson(value as Map<String, dynamic>)
+          as ReturnType;
+    case 'ErrorBase':
+      return ErrorBase.fromJson(value as Map<String, dynamic>) as ReturnType;
+    case 'Exhaustive':
+      return Exhaustive.fromJson(value as Map<String, dynamic>) as ReturnType;
+    case 'FacetHits':
+      return FacetHits.fromJson(value as Map<String, dynamic>) as ReturnType;
+    case 'FacetOrdering':
+      return FacetOrdering.fromJson(value as Map<String, dynamic>)
+          as ReturnType;
+    case 'FacetStats':
+      return FacetStats.fromJson(value as Map<String, dynamic>) as ReturnType;
+    case 'Facets':
+      return Facets.fromJson(value as Map<String, dynamic>) as ReturnType;
+    case 'HighlightResultOption':
+      return HighlightResultOption.fromJson(value as Map<String, dynamic>)
+          as ReturnType;
+    case 'Hit':
+      return Hit.fromJson(value as Map<String, dynamic>) as ReturnType;
+    case 'HitRankingInfo':
+      return HitRankingInfo.fromJson(value as Map<String, dynamic>)
+          as ReturnType;
+    case 'MatchLevel':
+      return MatchLevel.fromJson(value) as ReturnType;
+    case 'MatchedGeoLocation':
+      return MatchedGeoLocation.fromJson(value as Map<String, dynamic>)
+          as ReturnType;
+    case 'Params':
+      return Params.fromJson(value as Map<String, dynamic>) as ReturnType;
+    case 'Personalization':
+      return Personalization.fromJson(value as Map<String, dynamic>)
+          as ReturnType;
+    case 'Range':
+      return Range.fromJson(value as Map<String, dynamic>) as ReturnType;
+    case 'RankingInfo':
+      return RankingInfo.fromJson(value as Map<String, dynamic>) as ReturnType;
+    case 'Redirect':
+      return Redirect.fromJson(value as Map<String, dynamic>) as ReturnType;
+    case 'RedirectRuleIndexData':
+      return RedirectRuleIndexData.fromJson(value as Map<String, dynamic>)
+          as ReturnType;
+    case 'RedirectRuleIndexMetadata':
+      return RedirectRuleIndexMetadata.fromJson(value as Map<String, dynamic>)
+          as ReturnType;
+    case 'RedirectURL':
+      return RedirectURL.fromJson(value as Map<String, dynamic>) as ReturnType;
+    case 'RenderingContent':
+      return RenderingContent.fromJson(value as Map<String, dynamic>)
+          as ReturnType;
+    case 'RequestBody':
+      return RequestBody.fromJson(value as Map<String, dynamic>) as ReturnType;
+    case 'ResultsCompositionInfoResponse':
+      return ResultsCompositionInfoResponse.fromJson(
+          value as Map<String, dynamic>) as ReturnType;
+    case 'ResultsCompositionsResponse':
+      return ResultsCompositionsResponse.fromJson(value as Map<String, dynamic>)
+          as ReturnType;
+    case 'ResultsInjectedItemAppliedRulesInfoResponse':
+      return ResultsInjectedItemAppliedRulesInfoResponse.fromJson(
+          value as Map<String, dynamic>) as ReturnType;
+    case 'ResultsInjectedItemInfoResponse':
+      return ResultsInjectedItemInfoResponse.fromJson(
+          value as Map<String, dynamic>) as ReturnType;
+    case 'SearchForFacetValuesParams':
+      return SearchForFacetValuesParams.fromJson(value as Map<String, dynamic>)
+          as ReturnType;
+    case 'SearchForFacetValuesRequest':
+      return SearchForFacetValuesRequest.fromJson(value as Map<String, dynamic>)
+          as ReturnType;
+    case 'SearchForFacetValuesResponse':
+      return SearchForFacetValuesResponse.fromJson(
+          value as Map<String, dynamic>) as ReturnType;
+    case 'SearchForFacetValuesResults':
+      return SearchForFacetValuesResults.fromJson(value as Map<String, dynamic>)
+          as ReturnType;
+    case 'SearchHits':
+      return SearchHits.fromJson(value as Map<String, dynamic>) as ReturnType;
+    case 'SearchPagination':
+      return SearchPagination.fromJson(value as Map<String, dynamic>)
+          as ReturnType;
+    case 'SearchResponse':
+      return SearchResponse.fromJson(value as Map<String, dynamic>)
+          as ReturnType;
+    case 'SearchResults':
+      return SearchResults.fromJson(value as Map<String, dynamic>)
+          as ReturnType;
+    case 'SearchResultsItem':
+      return SearchResultsItem.fromJson(value as Map<String, dynamic>)
+          as ReturnType;
+    case 'SnippetResultOption':
+      return SnippetResultOption.fromJson(value as Map<String, dynamic>)
+          as ReturnType;
+    case 'SortRemainingBy':
+      return SortRemainingBy.fromJson(value) as ReturnType;
+    case 'SupportedLanguage':
+      return SupportedLanguage.fromJson(value) as ReturnType;
+    case 'Value':
+      return Value.fromJson(value as Map<String, dynamic>) as ReturnType;
+    case 'Widgets':
+      return Widgets.fromJson(value as Map<String, dynamic>) as ReturnType;
+    default:
+      RegExpMatch? match;
+
+      if (value is List && (match = _regList.firstMatch(targetType)) != null) {
+        targetType = match![1]!; // ignore: parameter_assignments
+        return value
+            .map<BaseType>((dynamic v) => deserialize<BaseType, BaseType>(
+                v, targetType,
+                growable: growable))
+            .toList(growable: growable) as ReturnType;
+      }
+      if (value is Set && (match = _regSet.firstMatch(targetType)) != null) {
+        targetType = match![1]!; // ignore: parameter_assignments
+        return value
+            .map<BaseType>((dynamic v) => deserialize<BaseType, BaseType>(
+                v, targetType,
+                growable: growable))
+            .toSet() as ReturnType;
+      }
+      if (value is Map && (match = _regMap.firstMatch(targetType)) != null) {
+        targetType = match![1]!; // ignore: parameter_assignments
+        return Map<dynamic, BaseType>.fromIterables(
+          value.keys,
+          value.values.map((dynamic v) => deserialize<BaseType, BaseType>(
+              v, targetType,
+              growable: growable)),
+        ) as ReturnType;
+      }
+      if (targetType == 'Object') {
+        return value;
+      }
+      break;
+  }
+  throw Exception('Cannot deserialize');
+}
diff --git a/packages/client_composition/lib/src/model/around_radius_all.dart b/packages/client_composition/lib/src/model/around_radius_all.dart
new file mode 100644
index 0000000..32716a4
--- /dev/null
+++ b/packages/client_composition/lib/src/model/around_radius_all.dart
@@ -0,0 +1,24 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+import 'package:json_annotation/json_annotation.dart';
+
+/// Return all records with a valid `_geoloc` attribute. Don't filter by distance.
+@JsonEnum(valueField: 'raw')
+enum AroundRadiusAll {
+  all(r'all');
+
+  const AroundRadiusAll(this.raw);
+  final dynamic raw;
+
+  dynamic toJson() => raw;
+
+  static AroundRadiusAll fromJson(dynamic json) {
+    for (final value in values) {
+      if (value.raw == json) return value;
+    }
+    throw ArgumentError.value(json, "raw", "No enum value with that value");
+  }
+
+  @override
+  String toString() => raw.toString();
+}
diff --git a/packages/client_composition/lib/src/model/banner.dart b/packages/client_composition/lib/src/model/banner.dart
new file mode 100644
index 0000000..85459a3
--- /dev/null
+++ b/packages/client_composition/lib/src/model/banner.dart
@@ -0,0 +1,40 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+import 'package:algolia_client_composition/src/model/banner_image.dart';
+import 'package:algolia_client_composition/src/model/banner_link.dart';
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'banner.g.dart';
+
+@JsonSerializable()
+final class Banner {
+  /// Returns a new [Banner] instance.
+  const Banner({
+    this.image,
+    this.link,
+  });
+
+  @JsonKey(name: r'image')
+  final BannerImage? image;
+
+  @JsonKey(name: r'link')
+  final BannerLink? link;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is Banner && other.image == image && other.link == link;
+
+  @override
+  int get hashCode => image.hashCode + link.hashCode;
+
+  factory Banner.fromJson(Map<String, dynamic> json) => _$BannerFromJson(json);
+
+  Map<String, dynamic> toJson() => _$BannerToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/banner.g.dart b/packages/client_composition/lib/src/model/banner.g.dart
new file mode 100644
index 0000000..516662f
--- /dev/null
+++ b/packages/client_composition/lib/src/model/banner.g.dart
@@ -0,0 +1,32 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'banner.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+Banner _$BannerFromJson(Map<String, dynamic> json) => $checkedCreate(
+      'Banner',
+      json,
+      ($checkedConvert) {
+        final val = Banner(
+          image: $checkedConvert(
+              'image',
+              (v) => v == null
+                  ? null
+                  : BannerImage.fromJson(v as Map<String, dynamic>)),
+          link: $checkedConvert(
+              'link',
+              (v) => v == null
+                  ? null
+                  : BannerLink.fromJson(v as Map<String, dynamic>)),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$BannerToJson(Banner instance) => <String, dynamic>{
+      if (instance.image?.toJson() case final value?) 'image': value,
+      if (instance.link?.toJson() case final value?) 'link': value,
+    };
diff --git a/packages/client_composition/lib/src/model/banner_image.dart b/packages/client_composition/lib/src/model/banner_image.dart
new file mode 100644
index 0000000..1f8ac93
--- /dev/null
+++ b/packages/client_composition/lib/src/model/banner_image.dart
@@ -0,0 +1,40 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+import 'package:algolia_client_composition/src/model/banner_image_url.dart';
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'banner_image.g.dart';
+
+@JsonSerializable()
+final class BannerImage {
+  /// Returns a new [BannerImage] instance.
+  const BannerImage({
+    this.urls,
+    this.title,
+  });
+
+  @JsonKey(name: r'urls')
+  final List<BannerImageUrl>? urls;
+
+  @JsonKey(name: r'title')
+  final String? title;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is BannerImage && other.urls == urls && other.title == title;
+
+  @override
+  int get hashCode => urls.hashCode + title.hashCode;
+
+  factory BannerImage.fromJson(Map<String, dynamic> json) =>
+      _$BannerImageFromJson(json);
+
+  Map<String, dynamic> toJson() => _$BannerImageToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/banner_image.g.dart b/packages/client_composition/lib/src/model/banner_image.g.dart
new file mode 100644
index 0000000..ac1b1f7
--- /dev/null
+++ b/packages/client_composition/lib/src/model/banner_image.g.dart
@@ -0,0 +1,31 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'banner_image.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+BannerImage _$BannerImageFromJson(Map<String, dynamic> json) => $checkedCreate(
+      'BannerImage',
+      json,
+      ($checkedConvert) {
+        final val = BannerImage(
+          urls: $checkedConvert(
+              'urls',
+              (v) => (v as List<dynamic>?)
+                  ?.map(
+                      (e) => BannerImageUrl.fromJson(e as Map<String, dynamic>))
+                  .toList()),
+          title: $checkedConvert('title', (v) => v as String?),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$BannerImageToJson(BannerImage instance) =>
+    <String, dynamic>{
+      if (instance.urls?.map((e) => e.toJson()).toList() case final value?)
+        'urls': value,
+      if (instance.title case final value?) 'title': value,
+    };
diff --git a/packages/client_composition/lib/src/model/banner_image_url.dart b/packages/client_composition/lib/src/model/banner_image_url.dart
new file mode 100644
index 0000000..f6c3382
--- /dev/null
+++ b/packages/client_composition/lib/src/model/banner_image_url.dart
@@ -0,0 +1,34 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'banner_image_url.g.dart';
+
+@JsonSerializable()
+final class BannerImageUrl {
+  /// Returns a new [BannerImageUrl] instance.
+  const BannerImageUrl({
+    this.url,
+  });
+
+  @JsonKey(name: r'url')
+  final String? url;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) || other is BannerImageUrl && other.url == url;
+
+  @override
+  int get hashCode => url.hashCode;
+
+  factory BannerImageUrl.fromJson(Map<String, dynamic> json) =>
+      _$BannerImageUrlFromJson(json);
+
+  Map<String, dynamic> toJson() => _$BannerImageUrlToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/banner_image_url.g.dart b/packages/client_composition/lib/src/model/banner_image_url.g.dart
new file mode 100644
index 0000000..93bd338
--- /dev/null
+++ b/packages/client_composition/lib/src/model/banner_image_url.g.dart
@@ -0,0 +1,24 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'banner_image_url.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+BannerImageUrl _$BannerImageUrlFromJson(Map<String, dynamic> json) =>
+    $checkedCreate(
+      'BannerImageUrl',
+      json,
+      ($checkedConvert) {
+        final val = BannerImageUrl(
+          url: $checkedConvert('url', (v) => v as String?),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$BannerImageUrlToJson(BannerImageUrl instance) =>
+    <String, dynamic>{
+      if (instance.url case final value?) 'url': value,
+    };
diff --git a/packages/client_composition/lib/src/model/banner_link.dart b/packages/client_composition/lib/src/model/banner_link.dart
new file mode 100644
index 0000000..1596cd1
--- /dev/null
+++ b/packages/client_composition/lib/src/model/banner_link.dart
@@ -0,0 +1,34 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'banner_link.g.dart';
+
+@JsonSerializable()
+final class BannerLink {
+  /// Returns a new [BannerLink] instance.
+  const BannerLink({
+    this.url,
+  });
+
+  @JsonKey(name: r'url')
+  final String? url;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) || other is BannerLink && other.url == url;
+
+  @override
+  int get hashCode => url.hashCode;
+
+  factory BannerLink.fromJson(Map<String, dynamic> json) =>
+      _$BannerLinkFromJson(json);
+
+  Map<String, dynamic> toJson() => _$BannerLinkToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/banner_link.g.dart b/packages/client_composition/lib/src/model/banner_link.g.dart
new file mode 100644
index 0000000..da3660b
--- /dev/null
+++ b/packages/client_composition/lib/src/model/banner_link.g.dart
@@ -0,0 +1,23 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'banner_link.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+BannerLink _$BannerLinkFromJson(Map<String, dynamic> json) => $checkedCreate(
+      'BannerLink',
+      json,
+      ($checkedConvert) {
+        final val = BannerLink(
+          url: $checkedConvert('url', (v) => v as String?),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$BannerLinkToJson(BannerLink instance) =>
+    <String, dynamic>{
+      if (instance.url case final value?) 'url': value,
+    };
diff --git a/packages/client_composition/lib/src/model/base_search_response.dart b/packages/client_composition/lib/src/model/base_search_response.dart
new file mode 100644
index 0000000..1622dc2
--- /dev/null
+++ b/packages/client_composition/lib/src/model/base_search_response.dart
@@ -0,0 +1,256 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+import 'package:algolia_client_composition/src/model/redirect.dart';
+import 'package:algolia_client_composition/src/model/facet_stats.dart';
+import 'package:algolia_client_composition/src/model/rendering_content.dart';
+import 'package:algolia_client_composition/src/model/exhaustive.dart';
+
+import 'package:collection/collection.dart';
+import 'package:json_annotation/json_annotation.dart';
+
+part 'base_search_response.g.dart';
+
+@JsonSerializable(createFieldMap: true)
+final class BaseSearchResponse extends DelegatingMap<String, dynamic> {
+  /// Returns a new [BaseSearchResponse] instance.
+  const BaseSearchResponse({
+    this.abTestID,
+    this.abTestVariantID,
+    this.aroundLatLng,
+    this.automaticRadius,
+    this.exhaustive,
+    this.appliedRules,
+    this.exhaustiveFacetsCount,
+    this.exhaustiveNbHits,
+    this.exhaustiveTypo,
+    this.facets,
+    this.facetsStats,
+    this.index,
+    this.indexUsed,
+    this.message,
+    this.nbSortedHits,
+    this.parsedQuery,
+    required this.processingTimeMS,
+    this.processingTimingsMS,
+    this.queryAfterRemoval,
+    this.redirect,
+    this.renderingContent,
+    this.serverTimeMS,
+    this.serverUsed,
+    this.userData,
+    this.queryID,
+    this.automaticInsights,
+    Map<String, dynamic> additionalProperties = const {},
+  }) : super(additionalProperties);
+
+  /// A/B test ID. This is only included in the response for indices that are part of an A/B test.
+  @JsonKey(name: r'abTestID')
+  final int? abTestID;
+
+  /// Variant ID. This is only included in the response for indices that are part of an A/B test.
+  // minimum: 1
+  @JsonKey(name: r'abTestVariantID')
+  final int? abTestVariantID;
+
+  /// Computed geographical location.
+  @JsonKey(name: r'aroundLatLng')
+  final String? aroundLatLng;
+
+  /// Distance from a central coordinate provided by `aroundLatLng`.
+  @JsonKey(name: r'automaticRadius')
+  final String? automaticRadius;
+
+  @JsonKey(name: r'exhaustive')
+  final Exhaustive? exhaustive;
+
+  /// Rules applied to the query.
+  @JsonKey(name: r'appliedRules')
+  final List<Object>? appliedRules;
+
+  /// See the `facetsCount` field of the `exhaustive` object in the response.
+  @Deprecated('exhaustiveFacetsCount has been deprecated')
+  @JsonKey(name: r'exhaustiveFacetsCount')
+  final bool? exhaustiveFacetsCount;
+
+  /// See the `nbHits` field of the `exhaustive` object in the response.
+  @Deprecated('exhaustiveNbHits has been deprecated')
+  @JsonKey(name: r'exhaustiveNbHits')
+  final bool? exhaustiveNbHits;
+
+  /// See the `typo` field of the `exhaustive` object in the response.
+  @Deprecated('exhaustiveTypo has been deprecated')
+  @JsonKey(name: r'exhaustiveTypo')
+  final bool? exhaustiveTypo;
+
+  /// Facet counts.
+  @JsonKey(name: r'facets')
+  final Map<String, Map<String, int>>? facets;
+
+  /// Statistics for numerical facets.
+  @JsonKey(name: r'facets_stats')
+  final Map<String, FacetStats>? facetsStats;
+
+  /// Index name used for the query.
+  @JsonKey(name: r'index')
+  final String? index;
+
+  /// Index name used for the query. During A/B testing, the targeted index isn't always the index used by the query.
+  @JsonKey(name: r'indexUsed')
+  final String? indexUsed;
+
+  /// Warnings about the query.
+  @JsonKey(name: r'message')
+  final String? message;
+
+  /// Number of hits selected and sorted by the relevant sort algorithm.
+  @JsonKey(name: r'nbSortedHits')
+  final int? nbSortedHits;
+
+  /// Post-[normalization](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/#what-does-normalization-mean) query string that will be searched.
+  @JsonKey(name: r'parsedQuery')
+  final String? parsedQuery;
+
+  /// Time the server took to process the request, in milliseconds.
+  @JsonKey(name: r'processingTimeMS')
+  final int processingTimeMS;
+
+  /// Experimental. List of processing steps and their times, in milliseconds. You can use this list to investigate performance issues.
+  @JsonKey(name: r'processingTimingsMS')
+  final Object? processingTimingsMS;
+
+  /// Markup text indicating which parts of the original query have been removed to retrieve a non-empty result set.
+  @JsonKey(name: r'queryAfterRemoval')
+  final String? queryAfterRemoval;
+
+  @JsonKey(name: r'redirect')
+  final Redirect? redirect;
+
+  @JsonKey(name: r'renderingContent')
+  final RenderingContent? renderingContent;
+
+  /// Time the server took to process the request, in milliseconds.
+  @JsonKey(name: r'serverTimeMS')
+  final int? serverTimeMS;
+
+  /// Host name of the server that processed the request.
+  @JsonKey(name: r'serverUsed')
+  final String? serverUsed;
+
+  /// An object with custom data.  You can store up to 32kB as custom data.
+  @JsonKey(name: r'userData')
+  final Object? userData;
+
+  /// Unique identifier for the query. This is used for [click analytics](https://www.algolia.com/doc/guides/analytics/click-analytics/).
+  @JsonKey(name: r'queryID')
+  final String? queryID;
+
+  /// Whether automatic events collection is enabled for the application.
+  @JsonKey(name: r'_automaticInsights')
+  final bool? automaticInsights;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is BaseSearchResponse &&
+          other.abTestID == abTestID &&
+          other.abTestVariantID == abTestVariantID &&
+          other.aroundLatLng == aroundLatLng &&
+          other.automaticRadius == automaticRadius &&
+          other.exhaustive == exhaustive &&
+          other.appliedRules == appliedRules &&
+          other.exhaustiveFacetsCount == exhaustiveFacetsCount &&
+          other.exhaustiveNbHits == exhaustiveNbHits &&
+          other.exhaustiveTypo == exhaustiveTypo &&
+          other.facets == facets &&
+          other.facetsStats == facetsStats &&
+          other.index == index &&
+          other.indexUsed == indexUsed &&
+          other.message == message &&
+          other.nbSortedHits == nbSortedHits &&
+          other.parsedQuery == parsedQuery &&
+          other.processingTimeMS == processingTimeMS &&
+          other.processingTimingsMS == processingTimingsMS &&
+          other.queryAfterRemoval == queryAfterRemoval &&
+          other.redirect == redirect &&
+          other.renderingContent == renderingContent &&
+          other.serverTimeMS == serverTimeMS &&
+          other.serverUsed == serverUsed &&
+          other.userData == userData &&
+          other.queryID == queryID &&
+          other.automaticInsights == automaticInsights &&
+          const MapEquality<String, dynamic>().equals(this, this);
+
+  @override
+  int get hashCode =>
+      abTestID.hashCode +
+      abTestVariantID.hashCode +
+      aroundLatLng.hashCode +
+      automaticRadius.hashCode +
+      exhaustive.hashCode +
+      appliedRules.hashCode +
+      exhaustiveFacetsCount.hashCode +
+      exhaustiveNbHits.hashCode +
+      exhaustiveTypo.hashCode +
+      facets.hashCode +
+      facetsStats.hashCode +
+      index.hashCode +
+      indexUsed.hashCode +
+      message.hashCode +
+      nbSortedHits.hashCode +
+      parsedQuery.hashCode +
+      processingTimeMS.hashCode +
+      processingTimingsMS.hashCode +
+      queryAfterRemoval.hashCode +
+      redirect.hashCode +
+      renderingContent.hashCode +
+      serverTimeMS.hashCode +
+      serverUsed.hashCode +
+      userData.hashCode +
+      queryID.hashCode +
+      automaticInsights.hashCode +
+      const MapEquality<String, dynamic>().hash(this);
+
+  factory BaseSearchResponse.fromJson(Map<String, dynamic> json) {
+    final instance = _$BaseSearchResponseFromJson(json);
+    final additionalProperties = Map<String, dynamic>.from(json)
+      ..removeWhere(
+          (key, value) => _$BaseSearchResponseFieldMap.containsKey(key));
+    return BaseSearchResponse(
+      abTestID: instance.abTestID,
+      abTestVariantID: instance.abTestVariantID,
+      aroundLatLng: instance.aroundLatLng,
+      automaticRadius: instance.automaticRadius,
+      exhaustive: instance.exhaustive,
+      appliedRules: instance.appliedRules,
+      exhaustiveFacetsCount: instance.exhaustiveFacetsCount,
+      exhaustiveNbHits: instance.exhaustiveNbHits,
+      exhaustiveTypo: instance.exhaustiveTypo,
+      facets: instance.facets,
+      facetsStats: instance.facetsStats,
+      index: instance.index,
+      indexUsed: instance.indexUsed,
+      message: instance.message,
+      nbSortedHits: instance.nbSortedHits,
+      parsedQuery: instance.parsedQuery,
+      processingTimeMS: instance.processingTimeMS,
+      processingTimingsMS: instance.processingTimingsMS,
+      queryAfterRemoval: instance.queryAfterRemoval,
+      redirect: instance.redirect,
+      renderingContent: instance.renderingContent,
+      serverTimeMS: instance.serverTimeMS,
+      serverUsed: instance.serverUsed,
+      userData: instance.userData,
+      queryID: instance.queryID,
+      automaticInsights: instance.automaticInsights,
+      additionalProperties: additionalProperties,
+    );
+  }
+
+  Map<String, dynamic> toJson() =>
+      _$BaseSearchResponseToJson(this)..addAll(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/base_search_response.g.dart b/packages/client_composition/lib/src/model/base_search_response.g.dart
new file mode 100644
index 0000000..02a60e8
--- /dev/null
+++ b/packages/client_composition/lib/src/model/base_search_response.g.dart
@@ -0,0 +1,146 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'base_search_response.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+BaseSearchResponse _$BaseSearchResponseFromJson(Map<String, dynamic> json) =>
+    $checkedCreate(
+      'BaseSearchResponse',
+      json,
+      ($checkedConvert) {
+        final val = BaseSearchResponse(
+          abTestID: $checkedConvert('abTestID', (v) => (v as num?)?.toInt()),
+          abTestVariantID:
+              $checkedConvert('abTestVariantID', (v) => (v as num?)?.toInt()),
+          aroundLatLng: $checkedConvert('aroundLatLng', (v) => v as String?),
+          automaticRadius:
+              $checkedConvert('automaticRadius', (v) => v as String?),
+          exhaustive: $checkedConvert(
+              'exhaustive',
+              (v) => v == null
+                  ? null
+                  : Exhaustive.fromJson(v as Map<String, dynamic>)),
+          appliedRules: $checkedConvert('appliedRules',
+              (v) => (v as List<dynamic>?)?.map((e) => e as Object).toList()),
+          exhaustiveFacetsCount:
+              $checkedConvert('exhaustiveFacetsCount', (v) => v as bool?),
+          exhaustiveNbHits:
+              $checkedConvert('exhaustiveNbHits', (v) => v as bool?),
+          exhaustiveTypo: $checkedConvert('exhaustiveTypo', (v) => v as bool?),
+          facets: $checkedConvert(
+              'facets',
+              (v) => (v as Map<String, dynamic>?)?.map(
+                    (k, e) => MapEntry(k, Map<String, int>.from(e as Map)),
+                  )),
+          facetsStats: $checkedConvert(
+              'facets_stats',
+              (v) => (v as Map<String, dynamic>?)?.map(
+                    (k, e) => MapEntry(
+                        k, FacetStats.fromJson(e as Map<String, dynamic>)),
+                  )),
+          index: $checkedConvert('index', (v) => v as String?),
+          indexUsed: $checkedConvert('indexUsed', (v) => v as String?),
+          message: $checkedConvert('message', (v) => v as String?),
+          nbSortedHits:
+              $checkedConvert('nbSortedHits', (v) => (v as num?)?.toInt()),
+          parsedQuery: $checkedConvert('parsedQuery', (v) => v as String?),
+          processingTimeMS:
+              $checkedConvert('processingTimeMS', (v) => (v as num).toInt()),
+          processingTimingsMS: $checkedConvert('processingTimingsMS', (v) => v),
+          queryAfterRemoval:
+              $checkedConvert('queryAfterRemoval', (v) => v as String?),
+          redirect: $checkedConvert(
+              'redirect',
+              (v) => v == null
+                  ? null
+                  : Redirect.fromJson(v as Map<String, dynamic>)),
+          renderingContent: $checkedConvert(
+              'renderingContent',
+              (v) => v == null
+                  ? null
+                  : RenderingContent.fromJson(v as Map<String, dynamic>)),
+          serverTimeMS:
+              $checkedConvert('serverTimeMS', (v) => (v as num?)?.toInt()),
+          serverUsed: $checkedConvert('serverUsed', (v) => v as String?),
+          userData: $checkedConvert('userData', (v) => v),
+          queryID: $checkedConvert('queryID', (v) => v as String?),
+          automaticInsights:
+              $checkedConvert('_automaticInsights', (v) => v as bool?),
+        );
+        return val;
+      },
+      fieldKeyMap: const {
+        'facetsStats': 'facets_stats',
+        'automaticInsights': '_automaticInsights'
+      },
+    );
+
+const _$BaseSearchResponseFieldMap = <String, String>{
+  'abTestID': 'abTestID',
+  'abTestVariantID': 'abTestVariantID',
+  'aroundLatLng': 'aroundLatLng',
+  'automaticRadius': 'automaticRadius',
+  'exhaustive': 'exhaustive',
+  'appliedRules': 'appliedRules',
+  'exhaustiveFacetsCount': 'exhaustiveFacetsCount',
+  'exhaustiveNbHits': 'exhaustiveNbHits',
+  'exhaustiveTypo': 'exhaustiveTypo',
+  'facets': 'facets',
+  'facetsStats': 'facets_stats',
+  'index': 'index',
+  'indexUsed': 'indexUsed',
+  'message': 'message',
+  'nbSortedHits': 'nbSortedHits',
+  'parsedQuery': 'parsedQuery',
+  'processingTimeMS': 'processingTimeMS',
+  'processingTimingsMS': 'processingTimingsMS',
+  'queryAfterRemoval': 'queryAfterRemoval',
+  'redirect': 'redirect',
+  'renderingContent': 'renderingContent',
+  'serverTimeMS': 'serverTimeMS',
+  'serverUsed': 'serverUsed',
+  'userData': 'userData',
+  'queryID': 'queryID',
+  'automaticInsights': '_automaticInsights',
+};
+
+Map<String, dynamic> _$BaseSearchResponseToJson(BaseSearchResponse instance) =>
+    <String, dynamic>{
+      if (instance.abTestID case final value?) 'abTestID': value,
+      if (instance.abTestVariantID case final value?) 'abTestVariantID': value,
+      if (instance.aroundLatLng case final value?) 'aroundLatLng': value,
+      if (instance.automaticRadius case final value?) 'automaticRadius': value,
+      if (instance.exhaustive?.toJson() case final value?) 'exhaustive': value,
+      if (instance.appliedRules case final value?) 'appliedRules': value,
+      if (instance.exhaustiveFacetsCount case final value?)
+        'exhaustiveFacetsCount': value,
+      if (instance.exhaustiveNbHits case final value?)
+        'exhaustiveNbHits': value,
+      if (instance.exhaustiveTypo case final value?) 'exhaustiveTypo': value,
+      if (instance.facets case final value?) 'facets': value,
+      if (instance.facetsStats?.map((k, e) => MapEntry(k, e.toJson()))
+          case final value?)
+        'facets_stats': value,
+      if (instance.index case final value?) 'index': value,
+      if (instance.indexUsed case final value?) 'indexUsed': value,
+      if (instance.message case final value?) 'message': value,
+      if (instance.nbSortedHits case final value?) 'nbSortedHits': value,
+      if (instance.parsedQuery case final value?) 'parsedQuery': value,
+      'processingTimeMS': instance.processingTimeMS,
+      if (instance.processingTimingsMS case final value?)
+        'processingTimingsMS': value,
+      if (instance.queryAfterRemoval case final value?)
+        'queryAfterRemoval': value,
+      if (instance.redirect?.toJson() case final value?) 'redirect': value,
+      if (instance.renderingContent?.toJson() case final value?)
+        'renderingContent': value,
+      if (instance.serverTimeMS case final value?) 'serverTimeMS': value,
+      if (instance.serverUsed case final value?) 'serverUsed': value,
+      if (instance.userData case final value?) 'userData': value,
+      if (instance.queryID case final value?) 'queryID': value,
+      if (instance.automaticInsights case final value?)
+        '_automaticInsights': value,
+    };
diff --git a/packages/client_composition/lib/src/model/composition_base_search_response.dart b/packages/client_composition/lib/src/model/composition_base_search_response.dart
new file mode 100644
index 0000000..12cab58
--- /dev/null
+++ b/packages/client_composition/lib/src/model/composition_base_search_response.dart
@@ -0,0 +1,51 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+import 'package:algolia_client_composition/src/model/compositions_search_response.dart';
+
+import 'package:collection/collection.dart';
+import 'package:json_annotation/json_annotation.dart';
+
+part 'composition_base_search_response.g.dart';
+
+@JsonSerializable(createFieldMap: true)
+final class CompositionBaseSearchResponse
+    extends DelegatingMap<String, dynamic> {
+  /// Returns a new [CompositionBaseSearchResponse] instance.
+  const CompositionBaseSearchResponse({
+    this.compositions,
+    Map<String, dynamic> additionalProperties = const {},
+  }) : super(additionalProperties);
+
+  @JsonKey(name: r'compositions')
+  final CompositionsSearchResponse? compositions;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is CompositionBaseSearchResponse &&
+          other.compositions == compositions &&
+          const MapEquality<String, dynamic>().equals(this, this);
+
+  @override
+  int get hashCode =>
+      compositions.hashCode + const MapEquality<String, dynamic>().hash(this);
+
+  factory CompositionBaseSearchResponse.fromJson(Map<String, dynamic> json) {
+    final instance = _$CompositionBaseSearchResponseFromJson(json);
+    final additionalProperties = Map<String, dynamic>.from(json)
+      ..removeWhere((key, value) =>
+          _$CompositionBaseSearchResponseFieldMap.containsKey(key));
+    return CompositionBaseSearchResponse(
+      compositions: instance.compositions,
+      additionalProperties: additionalProperties,
+    );
+  }
+
+  Map<String, dynamic> toJson() =>
+      _$CompositionBaseSearchResponseToJson(this)..addAll(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/composition_base_search_response.g.dart b/packages/client_composition/lib/src/model/composition_base_search_response.g.dart
new file mode 100644
index 0000000..f4f3274
--- /dev/null
+++ b/packages/client_composition/lib/src/model/composition_base_search_response.g.dart
@@ -0,0 +1,36 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'composition_base_search_response.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+CompositionBaseSearchResponse _$CompositionBaseSearchResponseFromJson(
+        Map<String, dynamic> json) =>
+    $checkedCreate(
+      'CompositionBaseSearchResponse',
+      json,
+      ($checkedConvert) {
+        final val = CompositionBaseSearchResponse(
+          compositions: $checkedConvert(
+              'compositions',
+              (v) => v == null
+                  ? null
+                  : CompositionsSearchResponse.fromJson(
+                      v as Map<String, dynamic>)),
+        );
+        return val;
+      },
+    );
+
+const _$CompositionBaseSearchResponseFieldMap = <String, String>{
+  'compositions': 'compositions',
+};
+
+Map<String, dynamic> _$CompositionBaseSearchResponseToJson(
+        CompositionBaseSearchResponse instance) =>
+    <String, dynamic>{
+      if (instance.compositions?.toJson() case final value?)
+        'compositions': value,
+    };
diff --git a/packages/client_composition/lib/src/model/composition_id_ranking_info.dart b/packages/client_composition/lib/src/model/composition_id_ranking_info.dart
new file mode 100644
index 0000000..aa44caa
--- /dev/null
+++ b/packages/client_composition/lib/src/model/composition_id_ranking_info.dart
@@ -0,0 +1,41 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'composition_id_ranking_info.g.dart';
+
+@JsonSerializable()
+final class CompositionIdRankingInfo {
+  /// Returns a new [CompositionIdRankingInfo] instance.
+  const CompositionIdRankingInfo({
+    required this.index,
+    required this.injectedItemKey,
+  });
+
+  @JsonKey(name: r'index')
+  final String index;
+
+  @JsonKey(name: r'injectedItemKey')
+  final String injectedItemKey;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is CompositionIdRankingInfo &&
+          other.index == index &&
+          other.injectedItemKey == injectedItemKey;
+
+  @override
+  int get hashCode => index.hashCode + injectedItemKey.hashCode;
+
+  factory CompositionIdRankingInfo.fromJson(Map<String, dynamic> json) =>
+      _$CompositionIdRankingInfoFromJson(json);
+
+  Map<String, dynamic> toJson() => _$CompositionIdRankingInfoToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/composition_id_ranking_info.g.dart b/packages/client_composition/lib/src/model/composition_id_ranking_info.g.dart
new file mode 100644
index 0000000..ef19ca4
--- /dev/null
+++ b/packages/client_composition/lib/src/model/composition_id_ranking_info.g.dart
@@ -0,0 +1,29 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'composition_id_ranking_info.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+CompositionIdRankingInfo _$CompositionIdRankingInfoFromJson(
+        Map<String, dynamic> json) =>
+    $checkedCreate(
+      'CompositionIdRankingInfo',
+      json,
+      ($checkedConvert) {
+        final val = CompositionIdRankingInfo(
+          index: $checkedConvert('index', (v) => v as String),
+          injectedItemKey:
+              $checkedConvert('injectedItemKey', (v) => v as String),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$CompositionIdRankingInfoToJson(
+        CompositionIdRankingInfo instance) =>
+    <String, dynamic>{
+      'index': instance.index,
+      'injectedItemKey': instance.injectedItemKey,
+    };
diff --git a/packages/client_composition/lib/src/model/composition_ranking_info.dart b/packages/client_composition/lib/src/model/composition_ranking_info.dart
new file mode 100644
index 0000000..04e6fb7
--- /dev/null
+++ b/packages/client_composition/lib/src/model/composition_ranking_info.dart
@@ -0,0 +1,36 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+import 'package:algolia_client_composition/src/model/composition_id_ranking_info.dart';
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'composition_ranking_info.g.dart';
+
+@JsonSerializable()
+final class CompositionRankingInfo {
+  /// Returns a new [CompositionRankingInfo] instance.
+  const CompositionRankingInfo({
+    this.composed,
+  });
+
+  @JsonKey(name: r'composed')
+  final Map<String, CompositionIdRankingInfo>? composed;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is CompositionRankingInfo && other.composed == composed;
+
+  @override
+  int get hashCode => composed.hashCode;
+
+  factory CompositionRankingInfo.fromJson(Map<String, dynamic> json) =>
+      _$CompositionRankingInfoFromJson(json);
+
+  Map<String, dynamic> toJson() => _$CompositionRankingInfoToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/composition_ranking_info.g.dart b/packages/client_composition/lib/src/model/composition_ranking_info.g.dart
new file mode 100644
index 0000000..0adafba
--- /dev/null
+++ b/packages/client_composition/lib/src/model/composition_ranking_info.g.dart
@@ -0,0 +1,35 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'composition_ranking_info.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+CompositionRankingInfo _$CompositionRankingInfoFromJson(
+        Map<String, dynamic> json) =>
+    $checkedCreate(
+      'CompositionRankingInfo',
+      json,
+      ($checkedConvert) {
+        final val = CompositionRankingInfo(
+          composed: $checkedConvert(
+              'composed',
+              (v) => (v as Map<String, dynamic>?)?.map(
+                    (k, e) => MapEntry(
+                        k,
+                        CompositionIdRankingInfo.fromJson(
+                            e as Map<String, dynamic>)),
+                  )),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$CompositionRankingInfoToJson(
+        CompositionRankingInfo instance) =>
+    <String, dynamic>{
+      if (instance.composed?.map((k, e) => MapEntry(k, e.toJson()))
+          case final value?)
+        'composed': value,
+    };
diff --git a/packages/client_composition/lib/src/model/composition_run_applied_rules.dart b/packages/client_composition/lib/src/model/composition_run_applied_rules.dart
new file mode 100644
index 0000000..43a8841
--- /dev/null
+++ b/packages/client_composition/lib/src/model/composition_run_applied_rules.dart
@@ -0,0 +1,36 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'composition_run_applied_rules.g.dart';
+
+@JsonSerializable()
+final class CompositionRunAppliedRules {
+  /// Returns a new [CompositionRunAppliedRules] instance.
+  const CompositionRunAppliedRules({
+    required this.objectID,
+  });
+
+  /// Unique record identifier.
+  @JsonKey(name: r'objectID')
+  final String objectID;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is CompositionRunAppliedRules && other.objectID == objectID;
+
+  @override
+  int get hashCode => objectID.hashCode;
+
+  factory CompositionRunAppliedRules.fromJson(Map<String, dynamic> json) =>
+      _$CompositionRunAppliedRulesFromJson(json);
+
+  Map<String, dynamic> toJson() => _$CompositionRunAppliedRulesToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/composition_run_applied_rules.g.dart b/packages/client_composition/lib/src/model/composition_run_applied_rules.g.dart
new file mode 100644
index 0000000..0d224ec
--- /dev/null
+++ b/packages/client_composition/lib/src/model/composition_run_applied_rules.g.dart
@@ -0,0 +1,26 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'composition_run_applied_rules.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+CompositionRunAppliedRules _$CompositionRunAppliedRulesFromJson(
+        Map<String, dynamic> json) =>
+    $checkedCreate(
+      'CompositionRunAppliedRules',
+      json,
+      ($checkedConvert) {
+        final val = CompositionRunAppliedRules(
+          objectID: $checkedConvert('objectID', (v) => v as String),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$CompositionRunAppliedRulesToJson(
+        CompositionRunAppliedRules instance) =>
+    <String, dynamic>{
+      'objectID': instance.objectID,
+    };
diff --git a/packages/client_composition/lib/src/model/composition_run_search_response.dart b/packages/client_composition/lib/src/model/composition_run_search_response.dart
new file mode 100644
index 0000000..19b23ed
--- /dev/null
+++ b/packages/client_composition/lib/src/model/composition_run_search_response.dart
@@ -0,0 +1,60 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+import 'package:algolia_client_composition/src/model/composition_run_applied_rules.dart';
+
+import 'package:collection/collection.dart';
+import 'package:json_annotation/json_annotation.dart';
+
+part 'composition_run_search_response.g.dart';
+
+@JsonSerializable(createFieldMap: true)
+final class CompositionRunSearchResponse
+    extends DelegatingMap<String, dynamic> {
+  /// Returns a new [CompositionRunSearchResponse] instance.
+  const CompositionRunSearchResponse({
+    required this.objectID,
+    this.appliedRules,
+    Map<String, dynamic> additionalProperties = const {},
+  }) : super(additionalProperties);
+
+  /// Unique record identifier.
+  @JsonKey(name: r'objectID')
+  final String objectID;
+
+  @JsonKey(name: r'appliedRules')
+  final List<CompositionRunAppliedRules>? appliedRules;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is CompositionRunSearchResponse &&
+          other.objectID == objectID &&
+          other.appliedRules == appliedRules &&
+          const MapEquality<String, dynamic>().equals(this, this);
+
+  @override
+  int get hashCode =>
+      objectID.hashCode +
+      appliedRules.hashCode +
+      const MapEquality<String, dynamic>().hash(this);
+
+  factory CompositionRunSearchResponse.fromJson(Map<String, dynamic> json) {
+    final instance = _$CompositionRunSearchResponseFromJson(json);
+    final additionalProperties = Map<String, dynamic>.from(json)
+      ..removeWhere((key, value) =>
+          _$CompositionRunSearchResponseFieldMap.containsKey(key));
+    return CompositionRunSearchResponse(
+      objectID: instance.objectID,
+      appliedRules: instance.appliedRules,
+      additionalProperties: additionalProperties,
+    );
+  }
+
+  Map<String, dynamic> toJson() =>
+      _$CompositionRunSearchResponseToJson(this)..addAll(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/composition_run_search_response.g.dart b/packages/client_composition/lib/src/model/composition_run_search_response.g.dart
new file mode 100644
index 0000000..33771b2
--- /dev/null
+++ b/packages/client_composition/lib/src/model/composition_run_search_response.g.dart
@@ -0,0 +1,40 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'composition_run_search_response.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+CompositionRunSearchResponse _$CompositionRunSearchResponseFromJson(
+        Map<String, dynamic> json) =>
+    $checkedCreate(
+      'CompositionRunSearchResponse',
+      json,
+      ($checkedConvert) {
+        final val = CompositionRunSearchResponse(
+          objectID: $checkedConvert('objectID', (v) => v as String),
+          appliedRules: $checkedConvert(
+              'appliedRules',
+              (v) => (v as List<dynamic>?)
+                  ?.map((e) => CompositionRunAppliedRules.fromJson(
+                      e as Map<String, dynamic>))
+                  .toList()),
+        );
+        return val;
+      },
+    );
+
+const _$CompositionRunSearchResponseFieldMap = <String, String>{
+  'objectID': 'objectID',
+  'appliedRules': 'appliedRules',
+};
+
+Map<String, dynamic> _$CompositionRunSearchResponseToJson(
+        CompositionRunSearchResponse instance) =>
+    <String, dynamic>{
+      'objectID': instance.objectID,
+      if (instance.appliedRules?.map((e) => e.toJson()).toList()
+          case final value?)
+        'appliedRules': value,
+    };
diff --git a/packages/client_composition/lib/src/model/compositions_search_response.dart b/packages/client_composition/lib/src/model/compositions_search_response.dart
new file mode 100644
index 0000000..0f80e2f
--- /dev/null
+++ b/packages/client_composition/lib/src/model/compositions_search_response.dart
@@ -0,0 +1,50 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+import 'package:algolia_client_composition/src/model/composition_run_search_response.dart';
+
+import 'package:collection/collection.dart';
+import 'package:json_annotation/json_annotation.dart';
+
+part 'compositions_search_response.g.dart';
+
+@JsonSerializable(createFieldMap: true)
+final class CompositionsSearchResponse extends DelegatingMap<String, dynamic> {
+  /// Returns a new [CompositionsSearchResponse] instance.
+  const CompositionsSearchResponse({
+    required this.run,
+    Map<String, dynamic> additionalProperties = const {},
+  }) : super(additionalProperties);
+
+  @JsonKey(name: r'run')
+  final List<CompositionRunSearchResponse> run;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is CompositionsSearchResponse &&
+          other.run == run &&
+          const MapEquality<String, dynamic>().equals(this, this);
+
+  @override
+  int get hashCode =>
+      run.hashCode + const MapEquality<String, dynamic>().hash(this);
+
+  factory CompositionsSearchResponse.fromJson(Map<String, dynamic> json) {
+    final instance = _$CompositionsSearchResponseFromJson(json);
+    final additionalProperties = Map<String, dynamic>.from(json)
+      ..removeWhere((key, value) =>
+          _$CompositionsSearchResponseFieldMap.containsKey(key));
+    return CompositionsSearchResponse(
+      run: instance.run,
+      additionalProperties: additionalProperties,
+    );
+  }
+
+  Map<String, dynamic> toJson() =>
+      _$CompositionsSearchResponseToJson(this)..addAll(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/compositions_search_response.g.dart b/packages/client_composition/lib/src/model/compositions_search_response.g.dart
new file mode 100644
index 0000000..c9ff10b
--- /dev/null
+++ b/packages/client_composition/lib/src/model/compositions_search_response.g.dart
@@ -0,0 +1,35 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'compositions_search_response.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+CompositionsSearchResponse _$CompositionsSearchResponseFromJson(
+        Map<String, dynamic> json) =>
+    $checkedCreate(
+      'CompositionsSearchResponse',
+      json,
+      ($checkedConvert) {
+        final val = CompositionsSearchResponse(
+          run: $checkedConvert(
+              'run',
+              (v) => (v as List<dynamic>)
+                  .map((e) => CompositionRunSearchResponse.fromJson(
+                      e as Map<String, dynamic>))
+                  .toList()),
+        );
+        return val;
+      },
+    );
+
+const _$CompositionsSearchResponseFieldMap = <String, String>{
+  'run': 'run',
+};
+
+Map<String, dynamic> _$CompositionsSearchResponseToJson(
+        CompositionsSearchResponse instance) =>
+    <String, dynamic>{
+      'run': instance.run.map((e) => e.toJson()).toList(),
+    };
diff --git a/packages/client_composition/lib/src/model/error_base.dart b/packages/client_composition/lib/src/model/error_base.dart
new file mode 100644
index 0000000..df5d4ad
--- /dev/null
+++ b/packages/client_composition/lib/src/model/error_base.dart
@@ -0,0 +1,47 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+
+import 'package:collection/collection.dart';
+import 'package:json_annotation/json_annotation.dart';
+
+part 'error_base.g.dart';
+
+@JsonSerializable(createFieldMap: true)
+final class ErrorBase extends DelegatingMap<String, dynamic> {
+  /// Returns a new [ErrorBase] instance.
+  const ErrorBase({
+    this.message,
+    Map<String, dynamic> additionalProperties = const {},
+  }) : super(additionalProperties);
+
+  @JsonKey(name: r'message')
+  final String? message;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is ErrorBase &&
+          other.message == message &&
+          const MapEquality<String, dynamic>().equals(this, this);
+
+  @override
+  int get hashCode =>
+      message.hashCode + const MapEquality<String, dynamic>().hash(this);
+
+  factory ErrorBase.fromJson(Map<String, dynamic> json) {
+    final instance = _$ErrorBaseFromJson(json);
+    final additionalProperties = Map<String, dynamic>.from(json)
+      ..removeWhere((key, value) => _$ErrorBaseFieldMap.containsKey(key));
+    return ErrorBase(
+      message: instance.message,
+      additionalProperties: additionalProperties,
+    );
+  }
+
+  Map<String, dynamic> toJson() => _$ErrorBaseToJson(this)..addAll(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/error_base.g.dart b/packages/client_composition/lib/src/model/error_base.g.dart
new file mode 100644
index 0000000..f4fbb65
--- /dev/null
+++ b/packages/client_composition/lib/src/model/error_base.g.dart
@@ -0,0 +1,26 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'error_base.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+ErrorBase _$ErrorBaseFromJson(Map<String, dynamic> json) => $checkedCreate(
+      'ErrorBase',
+      json,
+      ($checkedConvert) {
+        final val = ErrorBase(
+          message: $checkedConvert('message', (v) => v as String?),
+        );
+        return val;
+      },
+    );
+
+const _$ErrorBaseFieldMap = <String, String>{
+  'message': 'message',
+};
+
+Map<String, dynamic> _$ErrorBaseToJson(ErrorBase instance) => <String, dynamic>{
+      if (instance.message case final value?) 'message': value,
+    };
diff --git a/packages/client_composition/lib/src/model/exhaustive.dart b/packages/client_composition/lib/src/model/exhaustive.dart
new file mode 100644
index 0000000..73da337
--- /dev/null
+++ b/packages/client_composition/lib/src/model/exhaustive.dart
@@ -0,0 +1,66 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'exhaustive.g.dart';
+
+@JsonSerializable()
+final class Exhaustive {
+  /// Returns a new [Exhaustive] instance.
+  const Exhaustive({
+    this.facetsCount,
+    this.facetValues,
+    this.nbHits,
+    this.rulesMatch,
+    this.typo,
+  });
+
+  /// Whether the facet count is exhaustive (`true`) or approximate (`false`). See the [related discussion](https://support.algolia.com/hc/en-us/articles/4406975248145-Why-are-my-facet-and-hit-counts-not-accurate-).
+  @JsonKey(name: r'facetsCount')
+  final bool? facetsCount;
+
+  /// The value is `false` if not all facet values are retrieved.
+  @JsonKey(name: r'facetValues')
+  final bool? facetValues;
+
+  /// Whether the `nbHits` is exhaustive (`true`) or approximate (`false`). When the query takes more than 50ms to be processed, the engine makes an approximation. This can happen when using complex filters on millions of records, when typo-tolerance was not exhaustive, or when enough hits have been retrieved (for example, after the engine finds 10,000 exact matches). `nbHits` is reported as non-exhaustive whenever an approximation is made, even if the approximation didn’t, in the end, impact the exhaustivity of the query.
+  @JsonKey(name: r'nbHits')
+  final bool? nbHits;
+
+  /// Rules matching exhaustivity. The value is `false` if rules were enable for this query, and could not be fully processed due a timeout. This is generally caused by the number of alternatives (such as typos) which is too large.
+  @JsonKey(name: r'rulesMatch')
+  final bool? rulesMatch;
+
+  /// Whether the typo search was exhaustive (`true`) or approximate (`false`). An approximation is done when the typo search query part takes more than 10% of the query budget (ie. 5ms by default) to be processed (this can happen when a lot of typo alternatives exist for the query). This field will not be included when typo-tolerance is entirely disabled.
+  @JsonKey(name: r'typo')
+  final bool? typo;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is Exhaustive &&
+          other.facetsCount == facetsCount &&
+          other.facetValues == facetValues &&
+          other.nbHits == nbHits &&
+          other.rulesMatch == rulesMatch &&
+          other.typo == typo;
+
+  @override
+  int get hashCode =>
+      facetsCount.hashCode +
+      facetValues.hashCode +
+      nbHits.hashCode +
+      rulesMatch.hashCode +
+      typo.hashCode;
+
+  factory Exhaustive.fromJson(Map<String, dynamic> json) =>
+      _$ExhaustiveFromJson(json);
+
+  Map<String, dynamic> toJson() => _$ExhaustiveToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/exhaustive.g.dart b/packages/client_composition/lib/src/model/exhaustive.g.dart
new file mode 100644
index 0000000..3670319
--- /dev/null
+++ b/packages/client_composition/lib/src/model/exhaustive.g.dart
@@ -0,0 +1,31 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'exhaustive.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+Exhaustive _$ExhaustiveFromJson(Map<String, dynamic> json) => $checkedCreate(
+      'Exhaustive',
+      json,
+      ($checkedConvert) {
+        final val = Exhaustive(
+          facetsCount: $checkedConvert('facetsCount', (v) => v as bool?),
+          facetValues: $checkedConvert('facetValues', (v) => v as bool?),
+          nbHits: $checkedConvert('nbHits', (v) => v as bool?),
+          rulesMatch: $checkedConvert('rulesMatch', (v) => v as bool?),
+          typo: $checkedConvert('typo', (v) => v as bool?),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$ExhaustiveToJson(Exhaustive instance) =>
+    <String, dynamic>{
+      if (instance.facetsCount case final value?) 'facetsCount': value,
+      if (instance.facetValues case final value?) 'facetValues': value,
+      if (instance.nbHits case final value?) 'nbHits': value,
+      if (instance.rulesMatch case final value?) 'rulesMatch': value,
+      if (instance.typo case final value?) 'typo': value,
+    };
diff --git a/packages/client_composition/lib/src/model/facet_hits.dart b/packages/client_composition/lib/src/model/facet_hits.dart
new file mode 100644
index 0000000..6abf6f2
--- /dev/null
+++ b/packages/client_composition/lib/src/model/facet_hits.dart
@@ -0,0 +1,49 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'facet_hits.g.dart';
+
+@JsonSerializable()
+final class FacetHits {
+  /// Returns a new [FacetHits] instance.
+  const FacetHits({
+    required this.value,
+    required this.highlighted,
+    required this.count,
+  });
+
+  /// Facet value.
+  @JsonKey(name: r'value')
+  final String value;
+
+  /// Highlighted attribute value, including HTML tags.
+  @JsonKey(name: r'highlighted')
+  final String highlighted;
+
+  /// Number of records with this facet value. [The count may be approximated](https://support.algolia.com/hc/en-us/articles/4406975248145-Why-are-my-facet-and-hit-counts-not-accurate-).
+  @JsonKey(name: r'count')
+  final int count;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is FacetHits &&
+          other.value == value &&
+          other.highlighted == highlighted &&
+          other.count == count;
+
+  @override
+  int get hashCode => value.hashCode + highlighted.hashCode + count.hashCode;
+
+  factory FacetHits.fromJson(Map<String, dynamic> json) =>
+      _$FacetHitsFromJson(json);
+
+  Map<String, dynamic> toJson() => _$FacetHitsToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/facet_hits.g.dart b/packages/client_composition/lib/src/model/facet_hits.g.dart
new file mode 100644
index 0000000..c8e22cb
--- /dev/null
+++ b/packages/client_composition/lib/src/model/facet_hits.g.dart
@@ -0,0 +1,26 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'facet_hits.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+FacetHits _$FacetHitsFromJson(Map<String, dynamic> json) => $checkedCreate(
+      'FacetHits',
+      json,
+      ($checkedConvert) {
+        final val = FacetHits(
+          value: $checkedConvert('value', (v) => v as String),
+          highlighted: $checkedConvert('highlighted', (v) => v as String),
+          count: $checkedConvert('count', (v) => (v as num).toInt()),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$FacetHitsToJson(FacetHits instance) => <String, dynamic>{
+      'value': instance.value,
+      'highlighted': instance.highlighted,
+      'count': instance.count,
+    };
diff --git a/packages/client_composition/lib/src/model/facet_ordering.dart b/packages/client_composition/lib/src/model/facet_ordering.dart
new file mode 100644
index 0000000..7346116
--- /dev/null
+++ b/packages/client_composition/lib/src/model/facet_ordering.dart
@@ -0,0 +1,44 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+import 'package:algolia_client_composition/src/model/facets.dart';
+import 'package:algolia_client_composition/src/model/value.dart';
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'facet_ordering.g.dart';
+
+@JsonSerializable()
+final class FacetOrdering {
+  /// Returns a new [FacetOrdering] instance.
+  const FacetOrdering({
+    this.facets,
+    this.values,
+  });
+
+  @JsonKey(name: r'facets')
+  final Facets? facets;
+
+  /// Order of facet values. One object for each facet.
+  @JsonKey(name: r'values')
+  final Map<String, Value>? values;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is FacetOrdering &&
+          other.facets == facets &&
+          other.values == values;
+
+  @override
+  int get hashCode => facets.hashCode + values.hashCode;
+
+  factory FacetOrdering.fromJson(Map<String, dynamic> json) =>
+      _$FacetOrderingFromJson(json);
+
+  Map<String, dynamic> toJson() => _$FacetOrderingToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/facet_ordering.g.dart b/packages/client_composition/lib/src/model/facet_ordering.g.dart
new file mode 100644
index 0000000..916ac30
--- /dev/null
+++ b/packages/client_composition/lib/src/model/facet_ordering.g.dart
@@ -0,0 +1,37 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'facet_ordering.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+FacetOrdering _$FacetOrderingFromJson(Map<String, dynamic> json) =>
+    $checkedCreate(
+      'FacetOrdering',
+      json,
+      ($checkedConvert) {
+        final val = FacetOrdering(
+          facets: $checkedConvert(
+              'facets',
+              (v) => v == null
+                  ? null
+                  : Facets.fromJson(v as Map<String, dynamic>)),
+          values: $checkedConvert(
+              'values',
+              (v) => (v as Map<String, dynamic>?)?.map(
+                    (k, e) =>
+                        MapEntry(k, Value.fromJson(e as Map<String, dynamic>)),
+                  )),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$FacetOrderingToJson(FacetOrdering instance) =>
+    <String, dynamic>{
+      if (instance.facets?.toJson() case final value?) 'facets': value,
+      if (instance.values?.map((k, e) => MapEntry(k, e.toJson()))
+          case final value?)
+        'values': value,
+    };
diff --git a/packages/client_composition/lib/src/model/facet_stats.dart b/packages/client_composition/lib/src/model/facet_stats.dart
new file mode 100644
index 0000000..2f873d0
--- /dev/null
+++ b/packages/client_composition/lib/src/model/facet_stats.dart
@@ -0,0 +1,55 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'facet_stats.g.dart';
+
+@JsonSerializable()
+final class FacetStats {
+  /// Returns a new [FacetStats] instance.
+  const FacetStats({
+    this.min,
+    this.max,
+    this.avg,
+    this.sum,
+  });
+
+  /// Minimum value in the results.
+  @JsonKey(name: r'min')
+  final double? min;
+
+  /// Maximum value in the results.
+  @JsonKey(name: r'max')
+  final double? max;
+
+  /// Average facet value in the results.
+  @JsonKey(name: r'avg')
+  final double? avg;
+
+  /// Sum of all values in the results.
+  @JsonKey(name: r'sum')
+  final double? sum;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is FacetStats &&
+          other.min == min &&
+          other.max == max &&
+          other.avg == avg &&
+          other.sum == sum;
+
+  @override
+  int get hashCode => min.hashCode + max.hashCode + avg.hashCode + sum.hashCode;
+
+  factory FacetStats.fromJson(Map<String, dynamic> json) =>
+      _$FacetStatsFromJson(json);
+
+  Map<String, dynamic> toJson() => _$FacetStatsToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/facet_stats.g.dart b/packages/client_composition/lib/src/model/facet_stats.g.dart
new file mode 100644
index 0000000..bbb4a8e
--- /dev/null
+++ b/packages/client_composition/lib/src/model/facet_stats.g.dart
@@ -0,0 +1,29 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'facet_stats.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+FacetStats _$FacetStatsFromJson(Map<String, dynamic> json) => $checkedCreate(
+      'FacetStats',
+      json,
+      ($checkedConvert) {
+        final val = FacetStats(
+          min: $checkedConvert('min', (v) => (v as num?)?.toDouble()),
+          max: $checkedConvert('max', (v) => (v as num?)?.toDouble()),
+          avg: $checkedConvert('avg', (v) => (v as num?)?.toDouble()),
+          sum: $checkedConvert('sum', (v) => (v as num?)?.toDouble()),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$FacetStatsToJson(FacetStats instance) =>
+    <String, dynamic>{
+      if (instance.min case final value?) 'min': value,
+      if (instance.max case final value?) 'max': value,
+      if (instance.avg case final value?) 'avg': value,
+      if (instance.sum case final value?) 'sum': value,
+    };
diff --git a/packages/client_composition/lib/src/model/facets.dart b/packages/client_composition/lib/src/model/facets.dart
new file mode 100644
index 0000000..9b3dad5
--- /dev/null
+++ b/packages/client_composition/lib/src/model/facets.dart
@@ -0,0 +1,34 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'facets.g.dart';
+
+@JsonSerializable()
+final class Facets {
+  /// Returns a new [Facets] instance.
+  const Facets({
+    this.order,
+  });
+
+  /// Explicit order of facets or facet values.  This setting lets you always show specific facets or facet values at the top of the list.
+  @JsonKey(name: r'order')
+  final List<String>? order;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) || other is Facets && other.order == order;
+
+  @override
+  int get hashCode => order.hashCode;
+
+  factory Facets.fromJson(Map<String, dynamic> json) => _$FacetsFromJson(json);
+
+  Map<String, dynamic> toJson() => _$FacetsToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/facets.g.dart b/packages/client_composition/lib/src/model/facets.g.dart
new file mode 100644
index 0000000..c4c944c
--- /dev/null
+++ b/packages/client_composition/lib/src/model/facets.g.dart
@@ -0,0 +1,23 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'facets.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+Facets _$FacetsFromJson(Map<String, dynamic> json) => $checkedCreate(
+      'Facets',
+      json,
+      ($checkedConvert) {
+        final val = Facets(
+          order: $checkedConvert('order',
+              (v) => (v as List<dynamic>?)?.map((e) => e as String).toList()),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$FacetsToJson(Facets instance) => <String, dynamic>{
+      if (instance.order case final value?) 'order': value,
+    };
diff --git a/packages/client_composition/lib/src/model/highlight_result_option.dart b/packages/client_composition/lib/src/model/highlight_result_option.dart
new file mode 100644
index 0000000..cef7c06
--- /dev/null
+++ b/packages/client_composition/lib/src/model/highlight_result_option.dart
@@ -0,0 +1,59 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+import 'package:algolia_client_composition/src/model/match_level.dart';
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'highlight_result_option.g.dart';
+
+@JsonSerializable()
+final class HighlightResultOption {
+  /// Returns a new [HighlightResultOption] instance.
+  const HighlightResultOption({
+    required this.value,
+    required this.matchLevel,
+    required this.matchedWords,
+    this.fullyHighlighted,
+  });
+
+  /// Highlighted attribute value, including HTML tags.
+  @JsonKey(name: r'value')
+  final String value;
+
+  @JsonKey(name: r'matchLevel')
+  final MatchLevel matchLevel;
+
+  /// List of matched words from the search query.
+  @JsonKey(name: r'matchedWords')
+  final List<String> matchedWords;
+
+  /// Whether the entire attribute value is highlighted.
+  @JsonKey(name: r'fullyHighlighted')
+  final bool? fullyHighlighted;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is HighlightResultOption &&
+          other.value == value &&
+          other.matchLevel == matchLevel &&
+          other.matchedWords == matchedWords &&
+          other.fullyHighlighted == fullyHighlighted;
+
+  @override
+  int get hashCode =>
+      value.hashCode +
+      matchLevel.hashCode +
+      matchedWords.hashCode +
+      fullyHighlighted.hashCode;
+
+  factory HighlightResultOption.fromJson(Map<String, dynamic> json) =>
+      _$HighlightResultOptionFromJson(json);
+
+  Map<String, dynamic> toJson() => _$HighlightResultOptionToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/highlight_result_option.g.dart b/packages/client_composition/lib/src/model/highlight_result_option.g.dart
new file mode 100644
index 0000000..b8b582a
--- /dev/null
+++ b/packages/client_composition/lib/src/model/highlight_result_option.g.dart
@@ -0,0 +1,42 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'highlight_result_option.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+HighlightResultOption _$HighlightResultOptionFromJson(
+        Map<String, dynamic> json) =>
+    $checkedCreate(
+      'HighlightResultOption',
+      json,
+      ($checkedConvert) {
+        final val = HighlightResultOption(
+          value: $checkedConvert('value', (v) => v as String),
+          matchLevel: $checkedConvert(
+              'matchLevel', (v) => $enumDecode(_$MatchLevelEnumMap, v)),
+          matchedWords: $checkedConvert('matchedWords',
+              (v) => (v as List<dynamic>).map((e) => e as String).toList()),
+          fullyHighlighted:
+              $checkedConvert('fullyHighlighted', (v) => v as bool?),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$HighlightResultOptionToJson(
+        HighlightResultOption instance) =>
+    <String, dynamic>{
+      'value': instance.value,
+      'matchLevel': instance.matchLevel.toJson(),
+      'matchedWords': instance.matchedWords,
+      if (instance.fullyHighlighted case final value?)
+        'fullyHighlighted': value,
+    };
+
+const _$MatchLevelEnumMap = {
+  MatchLevel.none: 'none',
+  MatchLevel.partial: 'partial',
+  MatchLevel.full: 'full',
+};
diff --git a/packages/client_composition/lib/src/model/hit.dart b/packages/client_composition/lib/src/model/hit.dart
new file mode 100644
index 0000000..5bccb77
--- /dev/null
+++ b/packages/client_composition/lib/src/model/hit.dart
@@ -0,0 +1,80 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+import 'package:algolia_client_composition/src/model/hit_ranking_info.dart';
+
+import 'package:collection/collection.dart';
+import 'package:json_annotation/json_annotation.dart';
+
+part 'hit.g.dart';
+
+@JsonSerializable(createFieldMap: true)
+final class Hit extends DelegatingMap<String, dynamic> {
+  /// Returns a new [Hit] instance.
+  const Hit({
+    required this.objectID,
+    this.highlightResult,
+    this.snippetResult,
+    this.rankingInfo,
+    this.distinctSeqID,
+    Map<String, dynamic> additionalProperties = const {},
+  }) : super(additionalProperties);
+
+  /// Unique record identifier.
+  @JsonKey(name: r'objectID')
+  final String objectID;
+
+  /// Surround words that match the query with HTML tags for highlighting.
+  @JsonKey(name: r'_highlightResult')
+  final Map<String, dynamic>? highlightResult;
+
+  /// Snippets that show the context around a matching search query.
+  @JsonKey(name: r'_snippetResult')
+  final Map<String, dynamic>? snippetResult;
+
+  @JsonKey(name: r'_rankingInfo')
+  final HitRankingInfo? rankingInfo;
+
+  @JsonKey(name: r'_distinctSeqID')
+  final int? distinctSeqID;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is Hit &&
+          other.objectID == objectID &&
+          other.highlightResult == highlightResult &&
+          other.snippetResult == snippetResult &&
+          other.rankingInfo == rankingInfo &&
+          other.distinctSeqID == distinctSeqID &&
+          const MapEquality<String, dynamic>().equals(this, this);
+
+  @override
+  int get hashCode =>
+      objectID.hashCode +
+      highlightResult.hashCode +
+      snippetResult.hashCode +
+      rankingInfo.hashCode +
+      distinctSeqID.hashCode +
+      const MapEquality<String, dynamic>().hash(this);
+
+  factory Hit.fromJson(Map<String, dynamic> json) {
+    final instance = _$HitFromJson(json);
+    final additionalProperties = Map<String, dynamic>.from(json)
+      ..removeWhere((key, value) => _$HitFieldMap.containsKey(key));
+    return Hit(
+      objectID: instance.objectID,
+      highlightResult: instance.highlightResult,
+      snippetResult: instance.snippetResult,
+      rankingInfo: instance.rankingInfo,
+      distinctSeqID: instance.distinctSeqID,
+      additionalProperties: additionalProperties,
+    );
+  }
+
+  Map<String, dynamic> toJson() => _$HitToJson(this)..addAll(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/hit.g.dart b/packages/client_composition/lib/src/model/hit.g.dart
new file mode 100644
index 0000000..2dd4524
--- /dev/null
+++ b/packages/client_composition/lib/src/model/hit.g.dart
@@ -0,0 +1,52 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'hit.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+Hit _$HitFromJson(Map<String, dynamic> json) => $checkedCreate(
+      'Hit',
+      json,
+      ($checkedConvert) {
+        final val = Hit(
+          objectID: $checkedConvert('objectID', (v) => v as String),
+          highlightResult: $checkedConvert(
+              '_highlightResult', (v) => v as Map<String, dynamic>?),
+          snippetResult: $checkedConvert(
+              '_snippetResult', (v) => v as Map<String, dynamic>?),
+          rankingInfo: $checkedConvert(
+              '_rankingInfo',
+              (v) => v == null
+                  ? null
+                  : HitRankingInfo.fromJson(v as Map<String, dynamic>)),
+          distinctSeqID:
+              $checkedConvert('_distinctSeqID', (v) => (v as num?)?.toInt()),
+        );
+        return val;
+      },
+      fieldKeyMap: const {
+        'highlightResult': '_highlightResult',
+        'snippetResult': '_snippetResult',
+        'rankingInfo': '_rankingInfo',
+        'distinctSeqID': '_distinctSeqID'
+      },
+    );
+
+const _$HitFieldMap = <String, String>{
+  'objectID': 'objectID',
+  'highlightResult': '_highlightResult',
+  'snippetResult': '_snippetResult',
+  'rankingInfo': '_rankingInfo',
+  'distinctSeqID': '_distinctSeqID',
+};
+
+Map<String, dynamic> _$HitToJson(Hit instance) => <String, dynamic>{
+      'objectID': instance.objectID,
+      if (instance.highlightResult case final value?) '_highlightResult': value,
+      if (instance.snippetResult case final value?) '_snippetResult': value,
+      if (instance.rankingInfo?.toJson() case final value?)
+        '_rankingInfo': value,
+      if (instance.distinctSeqID case final value?) '_distinctSeqID': value,
+    };
diff --git a/packages/client_composition/lib/src/model/hit_ranking_info.dart b/packages/client_composition/lib/src/model/hit_ranking_info.dart
new file mode 100644
index 0000000..ac265b3
--- /dev/null
+++ b/packages/client_composition/lib/src/model/hit_ranking_info.dart
@@ -0,0 +1,137 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+import 'package:algolia_client_composition/src/model/composition_id_ranking_info.dart';
+import 'package:algolia_client_composition/src/model/personalization.dart';
+import 'package:algolia_client_composition/src/model/matched_geo_location.dart';
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'hit_ranking_info.g.dart';
+
+@JsonSerializable()
+final class HitRankingInfo {
+  /// Returns a new [HitRankingInfo] instance.
+  const HitRankingInfo({
+    this.filters,
+    required this.firstMatchedWord,
+    required this.geoDistance,
+    this.geoPrecision,
+    this.matchedGeoLocation,
+    this.personalization,
+    required this.nbExactWords,
+    required this.nbTypos,
+    this.promoted,
+    this.proximityDistance,
+    required this.userScore,
+    this.words,
+    this.promotedByReRanking,
+    this.composed,
+  });
+
+  /// Whether a filter matched the query.
+  // minimum: 0
+  @JsonKey(name: r'filters')
+  final int? filters;
+
+  /// Position of the first matched word in the best matching attribute of the record.
+  // minimum: 0
+  @JsonKey(name: r'firstMatchedWord')
+  final int firstMatchedWord;
+
+  /// Distance between the geo location in the search query and the best matching geo location in the record, divided by the geo precision (in meters).
+  // minimum: 0
+  @JsonKey(name: r'geoDistance')
+  final int geoDistance;
+
+  /// Precision used when computing the geo distance, in meters.
+  // minimum: 1
+  @JsonKey(name: r'geoPrecision')
+  final int? geoPrecision;
+
+  @JsonKey(name: r'matchedGeoLocation')
+  final MatchedGeoLocation? matchedGeoLocation;
+
+  @JsonKey(name: r'personalization')
+  final Personalization? personalization;
+
+  /// Number of exactly matched words.
+  // minimum: 0
+  @JsonKey(name: r'nbExactWords')
+  final int nbExactWords;
+
+  /// Number of typos encountered when matching the record.
+  // minimum: 0
+  @JsonKey(name: r'nbTypos')
+  final int nbTypos;
+
+  /// Whether the record was promoted by a rule.
+  @JsonKey(name: r'promoted')
+  final bool? promoted;
+
+  /// Number of words between multiple matches in the query plus 1. For single word queries, `proximityDistance` is 0.
+  // minimum: 0
+  @JsonKey(name: r'proximityDistance')
+  final int? proximityDistance;
+
+  /// Overall ranking of the record, expressed as a single integer. This attribute is internal.
+  @JsonKey(name: r'userScore')
+  final int userScore;
+
+  /// Number of matched words.
+  // minimum: 1
+  @JsonKey(name: r'words')
+  final int? words;
+
+  /// Whether the record is re-ranked.
+  @JsonKey(name: r'promotedByReRanking')
+  final bool? promotedByReRanking;
+
+  @JsonKey(name: r'composed')
+  final Map<String, CompositionIdRankingInfo>? composed;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is HitRankingInfo &&
+          other.filters == filters &&
+          other.firstMatchedWord == firstMatchedWord &&
+          other.geoDistance == geoDistance &&
+          other.geoPrecision == geoPrecision &&
+          other.matchedGeoLocation == matchedGeoLocation &&
+          other.personalization == personalization &&
+          other.nbExactWords == nbExactWords &&
+          other.nbTypos == nbTypos &&
+          other.promoted == promoted &&
+          other.proximityDistance == proximityDistance &&
+          other.userScore == userScore &&
+          other.words == words &&
+          other.promotedByReRanking == promotedByReRanking &&
+          other.composed == composed;
+
+  @override
+  int get hashCode =>
+      filters.hashCode +
+      firstMatchedWord.hashCode +
+      geoDistance.hashCode +
+      geoPrecision.hashCode +
+      matchedGeoLocation.hashCode +
+      personalization.hashCode +
+      nbExactWords.hashCode +
+      nbTypos.hashCode +
+      promoted.hashCode +
+      proximityDistance.hashCode +
+      userScore.hashCode +
+      words.hashCode +
+      promotedByReRanking.hashCode +
+      composed.hashCode;
+
+  factory HitRankingInfo.fromJson(Map<String, dynamic> json) =>
+      _$HitRankingInfoFromJson(json);
+
+  Map<String, dynamic> toJson() => _$HitRankingInfoToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/hit_ranking_info.g.dart b/packages/client_composition/lib/src/model/hit_ranking_info.g.dart
new file mode 100644
index 0000000..ac3b1b2
--- /dev/null
+++ b/packages/client_composition/lib/src/model/hit_ranking_info.g.dart
@@ -0,0 +1,77 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'hit_ranking_info.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+HitRankingInfo _$HitRankingInfoFromJson(Map<String, dynamic> json) =>
+    $checkedCreate(
+      'HitRankingInfo',
+      json,
+      ($checkedConvert) {
+        final val = HitRankingInfo(
+          filters: $checkedConvert('filters', (v) => (v as num?)?.toInt()),
+          firstMatchedWord:
+              $checkedConvert('firstMatchedWord', (v) => (v as num).toInt()),
+          geoDistance:
+              $checkedConvert('geoDistance', (v) => (v as num).toInt()),
+          geoPrecision:
+              $checkedConvert('geoPrecision', (v) => (v as num?)?.toInt()),
+          matchedGeoLocation: $checkedConvert(
+              'matchedGeoLocation',
+              (v) => v == null
+                  ? null
+                  : MatchedGeoLocation.fromJson(v as Map<String, dynamic>)),
+          personalization: $checkedConvert(
+              'personalization',
+              (v) => v == null
+                  ? null
+                  : Personalization.fromJson(v as Map<String, dynamic>)),
+          nbExactWords:
+              $checkedConvert('nbExactWords', (v) => (v as num).toInt()),
+          nbTypos: $checkedConvert('nbTypos', (v) => (v as num).toInt()),
+          promoted: $checkedConvert('promoted', (v) => v as bool?),
+          proximityDistance:
+              $checkedConvert('proximityDistance', (v) => (v as num?)?.toInt()),
+          userScore: $checkedConvert('userScore', (v) => (v as num).toInt()),
+          words: $checkedConvert('words', (v) => (v as num?)?.toInt()),
+          promotedByReRanking:
+              $checkedConvert('promotedByReRanking', (v) => v as bool?),
+          composed: $checkedConvert(
+              'composed',
+              (v) => (v as Map<String, dynamic>?)?.map(
+                    (k, e) => MapEntry(
+                        k,
+                        CompositionIdRankingInfo.fromJson(
+                            e as Map<String, dynamic>)),
+                  )),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$HitRankingInfoToJson(HitRankingInfo instance) =>
+    <String, dynamic>{
+      if (instance.filters case final value?) 'filters': value,
+      'firstMatchedWord': instance.firstMatchedWord,
+      'geoDistance': instance.geoDistance,
+      if (instance.geoPrecision case final value?) 'geoPrecision': value,
+      if (instance.matchedGeoLocation?.toJson() case final value?)
+        'matchedGeoLocation': value,
+      if (instance.personalization?.toJson() case final value?)
+        'personalization': value,
+      'nbExactWords': instance.nbExactWords,
+      'nbTypos': instance.nbTypos,
+      if (instance.promoted case final value?) 'promoted': value,
+      if (instance.proximityDistance case final value?)
+        'proximityDistance': value,
+      'userScore': instance.userScore,
+      if (instance.words case final value?) 'words': value,
+      if (instance.promotedByReRanking case final value?)
+        'promotedByReRanking': value,
+      if (instance.composed?.map((k, e) => MapEntry(k, e.toJson()))
+          case final value?)
+        'composed': value,
+    };
diff --git a/packages/client_composition/lib/src/model/match_level.dart b/packages/client_composition/lib/src/model/match_level.dart
new file mode 100644
index 0000000..a01ef22
--- /dev/null
+++ b/packages/client_composition/lib/src/model/match_level.dart
@@ -0,0 +1,26 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+import 'package:json_annotation/json_annotation.dart';
+
+/// Whether the whole query string matches or only a part.
+@JsonEnum(valueField: 'raw')
+enum MatchLevel {
+  none(r'none'),
+  partial(r'partial'),
+  full(r'full');
+
+  const MatchLevel(this.raw);
+  final dynamic raw;
+
+  dynamic toJson() => raw;
+
+  static MatchLevel fromJson(dynamic json) {
+    for (final value in values) {
+      if (value.raw == json) return value;
+    }
+    throw ArgumentError.value(json, "raw", "No enum value with that value");
+  }
+
+  @override
+  String toString() => raw.toString();
+}
diff --git a/packages/client_composition/lib/src/model/matched_geo_location.dart b/packages/client_composition/lib/src/model/matched_geo_location.dart
new file mode 100644
index 0000000..43a4d47
--- /dev/null
+++ b/packages/client_composition/lib/src/model/matched_geo_location.dart
@@ -0,0 +1,49 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'matched_geo_location.g.dart';
+
+@JsonSerializable()
+final class MatchedGeoLocation {
+  /// Returns a new [MatchedGeoLocation] instance.
+  const MatchedGeoLocation({
+    this.lat,
+    this.lng,
+    this.distance,
+  });
+
+  /// Latitude of the matched location.
+  @JsonKey(name: r'lat')
+  final double? lat;
+
+  /// Longitude of the matched location.
+  @JsonKey(name: r'lng')
+  final double? lng;
+
+  /// Distance between the matched location and the search location (in meters).
+  @JsonKey(name: r'distance')
+  final int? distance;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is MatchedGeoLocation &&
+          other.lat == lat &&
+          other.lng == lng &&
+          other.distance == distance;
+
+  @override
+  int get hashCode => lat.hashCode + lng.hashCode + distance.hashCode;
+
+  factory MatchedGeoLocation.fromJson(Map<String, dynamic> json) =>
+      _$MatchedGeoLocationFromJson(json);
+
+  Map<String, dynamic> toJson() => _$MatchedGeoLocationToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/matched_geo_location.g.dart b/packages/client_composition/lib/src/model/matched_geo_location.g.dart
new file mode 100644
index 0000000..6a36cb1
--- /dev/null
+++ b/packages/client_composition/lib/src/model/matched_geo_location.g.dart
@@ -0,0 +1,28 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'matched_geo_location.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+MatchedGeoLocation _$MatchedGeoLocationFromJson(Map<String, dynamic> json) =>
+    $checkedCreate(
+      'MatchedGeoLocation',
+      json,
+      ($checkedConvert) {
+        final val = MatchedGeoLocation(
+          lat: $checkedConvert('lat', (v) => (v as num?)?.toDouble()),
+          lng: $checkedConvert('lng', (v) => (v as num?)?.toDouble()),
+          distance: $checkedConvert('distance', (v) => (v as num?)?.toInt()),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$MatchedGeoLocationToJson(MatchedGeoLocation instance) =>
+    <String, dynamic>{
+      if (instance.lat case final value?) 'lat': value,
+      if (instance.lng case final value?) 'lng': value,
+      if (instance.distance case final value?) 'distance': value,
+    };
diff --git a/packages/client_composition/lib/src/model/params.dart b/packages/client_composition/lib/src/model/params.dart
new file mode 100644
index 0000000..d5961fb
--- /dev/null
+++ b/packages/client_composition/lib/src/model/params.dart
@@ -0,0 +1,231 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+import 'package:algolia_client_composition/src/model/supported_language.dart';
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'params.g.dart';
+
+@JsonSerializable()
+final class Params {
+  /// Returns a new [Params] instance.
+  const Params({
+    this.query,
+    this.filters,
+    this.page,
+    this.getRankingInfo,
+    this.relevancyStrictness,
+    this.facetFilters,
+    this.optionalFilters,
+    this.numericFilters,
+    this.hitsPerPage,
+    this.aroundLatLng,
+    this.aroundLatLngViaIP,
+    this.aroundRadius,
+    this.aroundPrecision,
+    this.minimumAroundRadius,
+    this.insideBoundingBox,
+    this.insidePolygon,
+    this.queryLanguages,
+    this.naturalLanguages,
+    this.enableRules,
+    this.ruleContexts,
+    this.userToken,
+    this.clickAnalytics,
+    this.analytics,
+    this.analyticsTags,
+    this.enableABTest,
+    this.enableReRanking,
+  });
+
+  /// Search query.
+  @JsonKey(name: r'query')
+  final String? query;
+
+  /// Filter expression to only include items that match the filter criteria in the response.  You can use these filter expressions:  - **Numeric filters.** `<facet> <op> <number>`, where `<op>` is one of `<`, `<=`, `=`, `!=`, `>`, `>=`. - **Ranges.** `<facet>:<lower> TO <upper>` where `<lower>` and `<upper>` are the lower and upper limits of the range (inclusive). - **Facet filters.** `<facet>:<value>` where `<facet>` is a facet attribute (case-sensitive) and `<value>` a facet value. - **Tag filters.** `_tags:<value>` or just `<value>` (case-sensitive). - **Boolean filters.** `<facet>: true | false`.  You can combine filters with `AND`, `OR`, and `NOT` operators with the following restrictions:  - You can only combine filters of the same type with `OR`.   **Not supported:** `facet:value OR num > 3`. - You can't use `NOT` with combinations of filters.   **Not supported:** `NOT(facet:value OR facet:value)` - You can't combine conjunctions (`AND`) with `OR`.   **Not supported:** `facet:value OR (facet:value AND facet:value)`  Use quotes around your filters, if the facet attribute name or facet value has spaces, keywords (`OR`, `AND`, `NOT`), or quotes. If a facet attribute is an array, the filter matches if it matches at least one element of the array.  For more information, see [Filters](https://www.algolia.com/doc/guides/managing-results/refine-results/filtering/).
+  @JsonKey(name: r'filters')
+  final String? filters;
+
+  /// Page of search results to retrieve.
+  // minimum: 0
+  @JsonKey(name: r'page')
+  final int? page;
+
+  /// Whether the search response should include detailed ranking information.
+  @JsonKey(name: r'getRankingInfo')
+  final bool? getRankingInfo;
+
+  @JsonKey(name: r'relevancyStrictness')
+  final int? relevancyStrictness;
+
+  /// One of types:
+  /// - [List<List<FacetFilters>>]
+  /// - [String]
+  /// - [List<String>]
+  @JsonKey(name: r'facetFilters')
+  final dynamic facetFilters;
+
+  /// One of types:
+  /// - [String]
+  /// - [List<List<OptionalFilters>>]
+  /// - [List<String>]
+  @JsonKey(name: r'optionalFilters')
+  final dynamic optionalFilters;
+
+  /// One of types:
+  /// - [List<List<NumericFilters>>]
+  /// - [String]
+  /// - [List<String>]
+  @JsonKey(name: r'numericFilters')
+  final dynamic numericFilters;
+
+  /// Number of hits per page.
+  // minimum: 1
+  // maximum: 1000
+  @JsonKey(name: r'hitsPerPage')
+  final int? hitsPerPage;
+
+  /// Coordinates for the center of a circle, expressed as a comma-separated string of latitude and longitude.  Only records included within a circle around this central location are included in the results. The radius of the circle is determined by the `aroundRadius` and `minimumAroundRadius` settings. This parameter is ignored if you also specify `insidePolygon` or `insideBoundingBox`.
+  @JsonKey(name: r'aroundLatLng')
+  final String? aroundLatLng;
+
+  /// Whether to obtain the coordinates from the request's IP address.
+  @JsonKey(name: r'aroundLatLngViaIP')
+  final bool? aroundLatLngViaIP;
+
+  /// One of types:
+  /// - [AroundRadiusAll]
+  /// - [int]
+  @JsonKey(name: r'aroundRadius')
+  final dynamic aroundRadius;
+
+  /// One of types:
+  /// - [List<Range>]
+  /// - [int]
+  @JsonKey(name: r'aroundPrecision')
+  final dynamic aroundPrecision;
+
+  /// Minimum radius (in meters) for a search around a location when `aroundRadius` isn't set.
+  // minimum: 1
+  @JsonKey(name: r'minimumAroundRadius')
+  final int? minimumAroundRadius;
+
+  /// One of types:
+  /// - [List<List<double>>]
+  /// - [String]
+  @JsonKey(name: r'insideBoundingBox')
+  final dynamic insideBoundingBox;
+
+  /// Coordinates of a polygon in which to search.  Polygons are defined by 3 to 10,000 points. Each point is represented by its latitude and longitude. Provide multiple polygons as nested arrays. For more information, see [filtering inside polygons](https://www.algolia.com/doc/guides/managing-results/refine-results/geolocation/#filtering-inside-rectangular-or-polygonal-areas). This parameter is ignored if you also specify `insideBoundingBox`.
+  @JsonKey(name: r'insidePolygon')
+  final List<List<double>>? insidePolygon;
+
+  /// Languages for language-specific query processing steps such as plurals, stop-word removal, and word-detection dictionaries.  This setting sets a default list of languages used by the `removeStopWords` and `ignorePlurals` settings. This setting also sets a dictionary for word detection in the logogram-based [CJK](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/in-depth/normalization/#normalization-for-logogram-based-languages-cjk) languages. To support this, you must place the CJK language **first**.  **You should always specify a query language.** If you don't specify an indexing language, the search engine uses all [supported languages](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/in-depth/supported-languages/), or the languages you specified with the `ignorePlurals` or `removeStopWords` parameters. This can lead to unexpected search results. For more information, see [Language-specific configuration](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/in-depth/language-specific-configurations/).
+  @JsonKey(name: r'queryLanguages')
+  final List<SupportedLanguage>? queryLanguages;
+
+  /// ISO language codes that adjust settings that are useful for processing natural language queries (as opposed to keyword searches):  - Sets `removeStopWords` and `ignorePlurals` to the list of provided languages. - Sets `removeWordsIfNoResults` to `allOptional`. - Adds a `natural_language` attribute to `ruleContexts` and `analyticsTags`.
+  @JsonKey(name: r'naturalLanguages')
+  final List<SupportedLanguage>? naturalLanguages;
+
+  /// Whether to enable rules.
+  @JsonKey(name: r'enableRules')
+  final bool? enableRules;
+
+  /// Assigns a rule context to the search query.  [Rule contexts](https://www.algolia.com/doc/guides/managing-results/rules/rules-overview/how-to/customize-search-results-by-platform/#whats-a-context) are strings that you can use to trigger matching rules.
+  @JsonKey(name: r'ruleContexts')
+  final List<String>? ruleContexts;
+
+  /// Unique pseudonymous or anonymous user identifier.  This helps with analytics and click and conversion events. For more information, see [user token](https://www.algolia.com/doc/guides/sending-events/concepts/usertoken/).
+  @JsonKey(name: r'userToken')
+  final String? userToken;
+
+  /// Whether to include a `queryID` attribute in the response.  The query ID is a unique identifier for a search query and is required for tracking [click and conversion events](https://www.algolia.com/guides/sending-events/getting-started/).
+  @JsonKey(name: r'clickAnalytics')
+  final bool? clickAnalytics;
+
+  /// Whether this search will be included in Analytics.
+  @JsonKey(name: r'analytics')
+  final bool? analytics;
+
+  /// Tags to apply to the query for [segmenting analytics data](https://www.algolia.com/doc/guides/search-analytics/guides/segments/).
+  @JsonKey(name: r'analyticsTags')
+  final List<String>? analyticsTags;
+
+  /// Whether to enable A/B testing for this search.
+  @JsonKey(name: r'enableABTest')
+  final bool? enableABTest;
+
+  /// Whether this search will use [Dynamic Re-Ranking](https://www.algolia.com/doc/guides/algolia-ai/re-ranking/).  This setting only has an effect if you activated Dynamic Re-Ranking for this index in the Algolia dashboard.
+  @JsonKey(name: r'enableReRanking')
+  final bool? enableReRanking;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is Params &&
+          other.query == query &&
+          other.filters == filters &&
+          other.page == page &&
+          other.getRankingInfo == getRankingInfo &&
+          other.relevancyStrictness == relevancyStrictness &&
+          other.facetFilters == facetFilters &&
+          other.optionalFilters == optionalFilters &&
+          other.numericFilters == numericFilters &&
+          other.hitsPerPage == hitsPerPage &&
+          other.aroundLatLng == aroundLatLng &&
+          other.aroundLatLngViaIP == aroundLatLngViaIP &&
+          other.aroundRadius == aroundRadius &&
+          other.aroundPrecision == aroundPrecision &&
+          other.minimumAroundRadius == minimumAroundRadius &&
+          other.insideBoundingBox == insideBoundingBox &&
+          other.insidePolygon == insidePolygon &&
+          other.queryLanguages == queryLanguages &&
+          other.naturalLanguages == naturalLanguages &&
+          other.enableRules == enableRules &&
+          other.ruleContexts == ruleContexts &&
+          other.userToken == userToken &&
+          other.clickAnalytics == clickAnalytics &&
+          other.analytics == analytics &&
+          other.analyticsTags == analyticsTags &&
+          other.enableABTest == enableABTest &&
+          other.enableReRanking == enableReRanking;
+
+  @override
+  int get hashCode =>
+      query.hashCode +
+      filters.hashCode +
+      page.hashCode +
+      getRankingInfo.hashCode +
+      relevancyStrictness.hashCode +
+      facetFilters.hashCode +
+      optionalFilters.hashCode +
+      numericFilters.hashCode +
+      hitsPerPage.hashCode +
+      aroundLatLng.hashCode +
+      aroundLatLngViaIP.hashCode +
+      aroundRadius.hashCode +
+      aroundPrecision.hashCode +
+      minimumAroundRadius.hashCode +
+      (insideBoundingBox == null ? 0 : insideBoundingBox.hashCode) +
+      insidePolygon.hashCode +
+      queryLanguages.hashCode +
+      naturalLanguages.hashCode +
+      enableRules.hashCode +
+      ruleContexts.hashCode +
+      userToken.hashCode +
+      clickAnalytics.hashCode +
+      analytics.hashCode +
+      analyticsTags.hashCode +
+      enableABTest.hashCode +
+      enableReRanking.hashCode;
+
+  factory Params.fromJson(Map<String, dynamic> json) => _$ParamsFromJson(json);
+
+  Map<String, dynamic> toJson() => _$ParamsToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/params.g.dart b/packages/client_composition/lib/src/model/params.g.dart
new file mode 100644
index 0000000..58ca3f8
--- /dev/null
+++ b/packages/client_composition/lib/src/model/params.g.dart
@@ -0,0 +1,172 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'params.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+Params _$ParamsFromJson(Map<String, dynamic> json) => $checkedCreate(
+      'Params',
+      json,
+      ($checkedConvert) {
+        final val = Params(
+          query: $checkedConvert('query', (v) => v as String?),
+          filters: $checkedConvert('filters', (v) => v as String?),
+          page: $checkedConvert('page', (v) => (v as num?)?.toInt()),
+          getRankingInfo: $checkedConvert('getRankingInfo', (v) => v as bool?),
+          relevancyStrictness: $checkedConvert(
+              'relevancyStrictness', (v) => (v as num?)?.toInt()),
+          facetFilters: $checkedConvert('facetFilters', (v) => v),
+          optionalFilters: $checkedConvert('optionalFilters', (v) => v),
+          numericFilters: $checkedConvert('numericFilters', (v) => v),
+          hitsPerPage:
+              $checkedConvert('hitsPerPage', (v) => (v as num?)?.toInt()),
+          aroundLatLng: $checkedConvert('aroundLatLng', (v) => v as String?),
+          aroundLatLngViaIP:
+              $checkedConvert('aroundLatLngViaIP', (v) => v as bool?),
+          aroundRadius: $checkedConvert('aroundRadius', (v) => v),
+          aroundPrecision: $checkedConvert('aroundPrecision', (v) => v),
+          minimumAroundRadius: $checkedConvert(
+              'minimumAroundRadius', (v) => (v as num?)?.toInt()),
+          insideBoundingBox: $checkedConvert('insideBoundingBox', (v) => v),
+          insidePolygon: $checkedConvert(
+              'insidePolygon',
+              (v) => (v as List<dynamic>?)
+                  ?.map((e) => (e as List<dynamic>)
+                      .map((e) => (e as num).toDouble())
+                      .toList())
+                  .toList()),
+          queryLanguages: $checkedConvert(
+              'queryLanguages',
+              (v) => (v as List<dynamic>?)
+                  ?.map((e) => $enumDecode(_$SupportedLanguageEnumMap, e))
+                  .toList()),
+          naturalLanguages: $checkedConvert(
+              'naturalLanguages',
+              (v) => (v as List<dynamic>?)
+                  ?.map((e) => $enumDecode(_$SupportedLanguageEnumMap, e))
+                  .toList()),
+          enableRules: $checkedConvert('enableRules', (v) => v as bool?),
+          ruleContexts: $checkedConvert('ruleContexts',
+              (v) => (v as List<dynamic>?)?.map((e) => e as String).toList()),
+          userToken: $checkedConvert('userToken', (v) => v as String?),
+          clickAnalytics: $checkedConvert('clickAnalytics', (v) => v as bool?),
+          analytics: $checkedConvert('analytics', (v) => v as bool?),
+          analyticsTags: $checkedConvert('analyticsTags',
+              (v) => (v as List<dynamic>?)?.map((e) => e as String).toList()),
+          enableABTest: $checkedConvert('enableABTest', (v) => v as bool?),
+          enableReRanking:
+              $checkedConvert('enableReRanking', (v) => v as bool?),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$ParamsToJson(Params instance) => <String, dynamic>{
+      if (instance.query case final value?) 'query': value,
+      if (instance.filters case final value?) 'filters': value,
+      if (instance.page case final value?) 'page': value,
+      if (instance.getRankingInfo case final value?) 'getRankingInfo': value,
+      if (instance.relevancyStrictness case final value?)
+        'relevancyStrictness': value,
+      if (instance.facetFilters case final value?) 'facetFilters': value,
+      if (instance.optionalFilters case final value?) 'optionalFilters': value,
+      if (instance.numericFilters case final value?) 'numericFilters': value,
+      if (instance.hitsPerPage case final value?) 'hitsPerPage': value,
+      if (instance.aroundLatLng case final value?) 'aroundLatLng': value,
+      if (instance.aroundLatLngViaIP case final value?)
+        'aroundLatLngViaIP': value,
+      if (instance.aroundRadius case final value?) 'aroundRadius': value,
+      if (instance.aroundPrecision case final value?) 'aroundPrecision': value,
+      if (instance.minimumAroundRadius case final value?)
+        'minimumAroundRadius': value,
+      if (instance.insideBoundingBox case final value?)
+        'insideBoundingBox': value,
+      if (instance.insidePolygon case final value?) 'insidePolygon': value,
+      if (instance.queryLanguages?.map((e) => e.toJson()).toList()
+          case final value?)
+        'queryLanguages': value,
+      if (instance.naturalLanguages?.map((e) => e.toJson()).toList()
+          case final value?)
+        'naturalLanguages': value,
+      if (instance.enableRules case final value?) 'enableRules': value,
+      if (instance.ruleContexts case final value?) 'ruleContexts': value,
+      if (instance.userToken case final value?) 'userToken': value,
+      if (instance.clickAnalytics case final value?) 'clickAnalytics': value,
+      if (instance.analytics case final value?) 'analytics': value,
+      if (instance.analyticsTags case final value?) 'analyticsTags': value,
+      if (instance.enableABTest case final value?) 'enableABTest': value,
+      if (instance.enableReRanking case final value?) 'enableReRanking': value,
+    };
+
+const _$SupportedLanguageEnumMap = {
+  SupportedLanguage.af: 'af',
+  SupportedLanguage.ar: 'ar',
+  SupportedLanguage.az: 'az',
+  SupportedLanguage.bg: 'bg',
+  SupportedLanguage.bn: 'bn',
+  SupportedLanguage.ca: 'ca',
+  SupportedLanguage.cs: 'cs',
+  SupportedLanguage.cy: 'cy',
+  SupportedLanguage.da: 'da',
+  SupportedLanguage.de: 'de',
+  SupportedLanguage.el: 'el',
+  SupportedLanguage.en: 'en',
+  SupportedLanguage.eo: 'eo',
+  SupportedLanguage.es: 'es',
+  SupportedLanguage.et: 'et',
+  SupportedLanguage.eu: 'eu',
+  SupportedLanguage.fa: 'fa',
+  SupportedLanguage.fi: 'fi',
+  SupportedLanguage.fo: 'fo',
+  SupportedLanguage.fr: 'fr',
+  SupportedLanguage.ga: 'ga',
+  SupportedLanguage.gl: 'gl',
+  SupportedLanguage.he: 'he',
+  SupportedLanguage.hi: 'hi',
+  SupportedLanguage.hu: 'hu',
+  SupportedLanguage.hy: 'hy',
+  SupportedLanguage.id: 'id',
+  SupportedLanguage.is_: 'is',
+  SupportedLanguage.it: 'it',
+  SupportedLanguage.ja: 'ja',
+  SupportedLanguage.ka: 'ka',
+  SupportedLanguage.kk: 'kk',
+  SupportedLanguage.ko: 'ko',
+  SupportedLanguage.ku: 'ku',
+  SupportedLanguage.ky: 'ky',
+  SupportedLanguage.lt: 'lt',
+  SupportedLanguage.lv: 'lv',
+  SupportedLanguage.mi: 'mi',
+  SupportedLanguage.mn: 'mn',
+  SupportedLanguage.mr: 'mr',
+  SupportedLanguage.ms: 'ms',
+  SupportedLanguage.mt: 'mt',
+  SupportedLanguage.nb: 'nb',
+  SupportedLanguage.nl: 'nl',
+  SupportedLanguage.no: 'no',
+  SupportedLanguage.ns: 'ns',
+  SupportedLanguage.pl: 'pl',
+  SupportedLanguage.ps: 'ps',
+  SupportedLanguage.pt: 'pt',
+  SupportedLanguage.ptBr: 'pt-br',
+  SupportedLanguage.qu: 'qu',
+  SupportedLanguage.ro: 'ro',
+  SupportedLanguage.ru: 'ru',
+  SupportedLanguage.sk: 'sk',
+  SupportedLanguage.sq: 'sq',
+  SupportedLanguage.sv: 'sv',
+  SupportedLanguage.sw: 'sw',
+  SupportedLanguage.ta: 'ta',
+  SupportedLanguage.te: 'te',
+  SupportedLanguage.th: 'th',
+  SupportedLanguage.tl: 'tl',
+  SupportedLanguage.tn: 'tn',
+  SupportedLanguage.tr: 'tr',
+  SupportedLanguage.tt: 'tt',
+  SupportedLanguage.uk: 'uk',
+  SupportedLanguage.ur: 'ur',
+  SupportedLanguage.uz: 'uz',
+  SupportedLanguage.zh: 'zh',
+};
diff --git a/packages/client_composition/lib/src/model/personalization.dart b/packages/client_composition/lib/src/model/personalization.dart
new file mode 100644
index 0000000..c336d9f
--- /dev/null
+++ b/packages/client_composition/lib/src/model/personalization.dart
@@ -0,0 +1,50 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'personalization.g.dart';
+
+@JsonSerializable()
+final class Personalization {
+  /// Returns a new [Personalization] instance.
+  const Personalization({
+    this.filtersScore,
+    this.rankingScore,
+    this.score,
+  });
+
+  /// The score of the filters.
+  @JsonKey(name: r'filtersScore')
+  final int? filtersScore;
+
+  /// The score of the ranking.
+  @JsonKey(name: r'rankingScore')
+  final int? rankingScore;
+
+  /// The score of the event.
+  @JsonKey(name: r'score')
+  final int? score;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is Personalization &&
+          other.filtersScore == filtersScore &&
+          other.rankingScore == rankingScore &&
+          other.score == score;
+
+  @override
+  int get hashCode =>
+      filtersScore.hashCode + rankingScore.hashCode + score.hashCode;
+
+  factory Personalization.fromJson(Map<String, dynamic> json) =>
+      _$PersonalizationFromJson(json);
+
+  Map<String, dynamic> toJson() => _$PersonalizationToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/personalization.g.dart b/packages/client_composition/lib/src/model/personalization.g.dart
new file mode 100644
index 0000000..78a116c
--- /dev/null
+++ b/packages/client_composition/lib/src/model/personalization.g.dart
@@ -0,0 +1,30 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'personalization.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+Personalization _$PersonalizationFromJson(Map<String, dynamic> json) =>
+    $checkedCreate(
+      'Personalization',
+      json,
+      ($checkedConvert) {
+        final val = Personalization(
+          filtersScore:
+              $checkedConvert('filtersScore', (v) => (v as num?)?.toInt()),
+          rankingScore:
+              $checkedConvert('rankingScore', (v) => (v as num?)?.toInt()),
+          score: $checkedConvert('score', (v) => (v as num?)?.toInt()),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$PersonalizationToJson(Personalization instance) =>
+    <String, dynamic>{
+      if (instance.filtersScore case final value?) 'filtersScore': value,
+      if (instance.rankingScore case final value?) 'rankingScore': value,
+      if (instance.score case final value?) 'score': value,
+    };
diff --git a/packages/client_composition/lib/src/model/range.dart b/packages/client_composition/lib/src/model/range.dart
new file mode 100644
index 0000000..029577a
--- /dev/null
+++ b/packages/client_composition/lib/src/model/range.dart
@@ -0,0 +1,40 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'range.g.dart';
+
+@JsonSerializable()
+final class Range {
+  /// Returns a new [Range] instance.
+  const Range({
+    this.from,
+    this.value,
+  });
+
+  /// Lower boundary of a range in meters. The Geo ranking criterion considers all records within the range to be equal.
+  @JsonKey(name: r'from')
+  final int? from;
+
+  /// Upper boundary of a range in meters. The Geo ranking criterion considers all records within the range to be equal.
+  @JsonKey(name: r'value')
+  final int? value;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is Range && other.from == from && other.value == value;
+
+  @override
+  int get hashCode => from.hashCode + value.hashCode;
+
+  factory Range.fromJson(Map<String, dynamic> json) => _$RangeFromJson(json);
+
+  Map<String, dynamic> toJson() => _$RangeToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/range.g.dart b/packages/client_composition/lib/src/model/range.g.dart
new file mode 100644
index 0000000..a76c135
--- /dev/null
+++ b/packages/client_composition/lib/src/model/range.g.dart
@@ -0,0 +1,24 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'range.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+Range _$RangeFromJson(Map<String, dynamic> json) => $checkedCreate(
+      'Range',
+      json,
+      ($checkedConvert) {
+        final val = Range(
+          from: $checkedConvert('from', (v) => (v as num?)?.toInt()),
+          value: $checkedConvert('value', (v) => (v as num?)?.toInt()),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$RangeToJson(Range instance) => <String, dynamic>{
+      if (instance.from case final value?) 'from': value,
+      if (instance.value case final value?) 'value': value,
+    };
diff --git a/packages/client_composition/lib/src/model/ranking_info.dart b/packages/client_composition/lib/src/model/ranking_info.dart
new file mode 100644
index 0000000..9dc3af3
--- /dev/null
+++ b/packages/client_composition/lib/src/model/ranking_info.dart
@@ -0,0 +1,130 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+import 'package:algolia_client_composition/src/model/personalization.dart';
+import 'package:algolia_client_composition/src/model/matched_geo_location.dart';
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'ranking_info.g.dart';
+
+@JsonSerializable()
+final class RankingInfo {
+  /// Returns a new [RankingInfo] instance.
+  const RankingInfo({
+    this.filters,
+    required this.firstMatchedWord,
+    required this.geoDistance,
+    this.geoPrecision,
+    this.matchedGeoLocation,
+    this.personalization,
+    required this.nbExactWords,
+    required this.nbTypos,
+    this.promoted,
+    this.proximityDistance,
+    required this.userScore,
+    this.words,
+    this.promotedByReRanking,
+  });
+
+  /// Whether a filter matched the query.
+  // minimum: 0
+  @JsonKey(name: r'filters')
+  final int? filters;
+
+  /// Position of the first matched word in the best matching attribute of the record.
+  // minimum: 0
+  @JsonKey(name: r'firstMatchedWord')
+  final int firstMatchedWord;
+
+  /// Distance between the geo location in the search query and the best matching geo location in the record, divided by the geo precision (in meters).
+  // minimum: 0
+  @JsonKey(name: r'geoDistance')
+  final int geoDistance;
+
+  /// Precision used when computing the geo distance, in meters.
+  // minimum: 1
+  @JsonKey(name: r'geoPrecision')
+  final int? geoPrecision;
+
+  @JsonKey(name: r'matchedGeoLocation')
+  final MatchedGeoLocation? matchedGeoLocation;
+
+  @JsonKey(name: r'personalization')
+  final Personalization? personalization;
+
+  /// Number of exactly matched words.
+  // minimum: 0
+  @JsonKey(name: r'nbExactWords')
+  final int nbExactWords;
+
+  /// Number of typos encountered when matching the record.
+  // minimum: 0
+  @JsonKey(name: r'nbTypos')
+  final int nbTypos;
+
+  /// Whether the record was promoted by a rule.
+  @JsonKey(name: r'promoted')
+  final bool? promoted;
+
+  /// Number of words between multiple matches in the query plus 1. For single word queries, `proximityDistance` is 0.
+  // minimum: 0
+  @JsonKey(name: r'proximityDistance')
+  final int? proximityDistance;
+
+  /// Overall ranking of the record, expressed as a single integer. This attribute is internal.
+  @JsonKey(name: r'userScore')
+  final int userScore;
+
+  /// Number of matched words.
+  // minimum: 1
+  @JsonKey(name: r'words')
+  final int? words;
+
+  /// Whether the record is re-ranked.
+  @JsonKey(name: r'promotedByReRanking')
+  final bool? promotedByReRanking;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is RankingInfo &&
+          other.filters == filters &&
+          other.firstMatchedWord == firstMatchedWord &&
+          other.geoDistance == geoDistance &&
+          other.geoPrecision == geoPrecision &&
+          other.matchedGeoLocation == matchedGeoLocation &&
+          other.personalization == personalization &&
+          other.nbExactWords == nbExactWords &&
+          other.nbTypos == nbTypos &&
+          other.promoted == promoted &&
+          other.proximityDistance == proximityDistance &&
+          other.userScore == userScore &&
+          other.words == words &&
+          other.promotedByReRanking == promotedByReRanking;
+
+  @override
+  int get hashCode =>
+      filters.hashCode +
+      firstMatchedWord.hashCode +
+      geoDistance.hashCode +
+      geoPrecision.hashCode +
+      matchedGeoLocation.hashCode +
+      personalization.hashCode +
+      nbExactWords.hashCode +
+      nbTypos.hashCode +
+      promoted.hashCode +
+      proximityDistance.hashCode +
+      userScore.hashCode +
+      words.hashCode +
+      promotedByReRanking.hashCode;
+
+  factory RankingInfo.fromJson(Map<String, dynamic> json) =>
+      _$RankingInfoFromJson(json);
+
+  Map<String, dynamic> toJson() => _$RankingInfoToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/ranking_info.g.dart b/packages/client_composition/lib/src/model/ranking_info.g.dart
new file mode 100644
index 0000000..31b1b60
--- /dev/null
+++ b/packages/client_composition/lib/src/model/ranking_info.g.dart
@@ -0,0 +1,65 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'ranking_info.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+RankingInfo _$RankingInfoFromJson(Map<String, dynamic> json) => $checkedCreate(
+      'RankingInfo',
+      json,
+      ($checkedConvert) {
+        final val = RankingInfo(
+          filters: $checkedConvert('filters', (v) => (v as num?)?.toInt()),
+          firstMatchedWord:
+              $checkedConvert('firstMatchedWord', (v) => (v as num).toInt()),
+          geoDistance:
+              $checkedConvert('geoDistance', (v) => (v as num).toInt()),
+          geoPrecision:
+              $checkedConvert('geoPrecision', (v) => (v as num?)?.toInt()),
+          matchedGeoLocation: $checkedConvert(
+              'matchedGeoLocation',
+              (v) => v == null
+                  ? null
+                  : MatchedGeoLocation.fromJson(v as Map<String, dynamic>)),
+          personalization: $checkedConvert(
+              'personalization',
+              (v) => v == null
+                  ? null
+                  : Personalization.fromJson(v as Map<String, dynamic>)),
+          nbExactWords:
+              $checkedConvert('nbExactWords', (v) => (v as num).toInt()),
+          nbTypos: $checkedConvert('nbTypos', (v) => (v as num).toInt()),
+          promoted: $checkedConvert('promoted', (v) => v as bool?),
+          proximityDistance:
+              $checkedConvert('proximityDistance', (v) => (v as num?)?.toInt()),
+          userScore: $checkedConvert('userScore', (v) => (v as num).toInt()),
+          words: $checkedConvert('words', (v) => (v as num?)?.toInt()),
+          promotedByReRanking:
+              $checkedConvert('promotedByReRanking', (v) => v as bool?),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$RankingInfoToJson(RankingInfo instance) =>
+    <String, dynamic>{
+      if (instance.filters case final value?) 'filters': value,
+      'firstMatchedWord': instance.firstMatchedWord,
+      'geoDistance': instance.geoDistance,
+      if (instance.geoPrecision case final value?) 'geoPrecision': value,
+      if (instance.matchedGeoLocation?.toJson() case final value?)
+        'matchedGeoLocation': value,
+      if (instance.personalization?.toJson() case final value?)
+        'personalization': value,
+      'nbExactWords': instance.nbExactWords,
+      'nbTypos': instance.nbTypos,
+      if (instance.promoted case final value?) 'promoted': value,
+      if (instance.proximityDistance case final value?)
+        'proximityDistance': value,
+      'userScore': instance.userScore,
+      if (instance.words case final value?) 'words': value,
+      if (instance.promotedByReRanking case final value?)
+        'promotedByReRanking': value,
+    };
diff --git a/packages/client_composition/lib/src/model/redirect.dart b/packages/client_composition/lib/src/model/redirect.dart
new file mode 100644
index 0000000..42affe7
--- /dev/null
+++ b/packages/client_composition/lib/src/model/redirect.dart
@@ -0,0 +1,35 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+import 'package:algolia_client_composition/src/model/redirect_rule_index_metadata.dart';
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'redirect.g.dart';
+
+@JsonSerializable()
+final class Redirect {
+  /// Returns a new [Redirect] instance.
+  const Redirect({
+    this.index,
+  });
+
+  @JsonKey(name: r'index')
+  final List<RedirectRuleIndexMetadata>? index;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) || other is Redirect && other.index == index;
+
+  @override
+  int get hashCode => index.hashCode;
+
+  factory Redirect.fromJson(Map<String, dynamic> json) =>
+      _$RedirectFromJson(json);
+
+  Map<String, dynamic> toJson() => _$RedirectToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/redirect.g.dart b/packages/client_composition/lib/src/model/redirect.g.dart
new file mode 100644
index 0000000..23c584b
--- /dev/null
+++ b/packages/client_composition/lib/src/model/redirect.g.dart
@@ -0,0 +1,28 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'redirect.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+Redirect _$RedirectFromJson(Map<String, dynamic> json) => $checkedCreate(
+      'Redirect',
+      json,
+      ($checkedConvert) {
+        final val = Redirect(
+          index: $checkedConvert(
+              'index',
+              (v) => (v as List<dynamic>?)
+                  ?.map((e) => RedirectRuleIndexMetadata.fromJson(
+                      e as Map<String, dynamic>))
+                  .toList()),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$RedirectToJson(Redirect instance) => <String, dynamic>{
+      if (instance.index?.map((e) => e.toJson()).toList() case final value?)
+        'index': value,
+    };
diff --git a/packages/client_composition/lib/src/model/redirect_rule_index_data.dart b/packages/client_composition/lib/src/model/redirect_rule_index_data.dart
new file mode 100644
index 0000000..55f0f0e
--- /dev/null
+++ b/packages/client_composition/lib/src/model/redirect_rule_index_data.dart
@@ -0,0 +1,35 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'redirect_rule_index_data.g.dart';
+
+@JsonSerializable()
+final class RedirectRuleIndexData {
+  /// Returns a new [RedirectRuleIndexData] instance.
+  const RedirectRuleIndexData({
+    required this.ruleObjectID,
+  });
+
+  @JsonKey(name: r'ruleObjectID')
+  final String ruleObjectID;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is RedirectRuleIndexData && other.ruleObjectID == ruleObjectID;
+
+  @override
+  int get hashCode => ruleObjectID.hashCode;
+
+  factory RedirectRuleIndexData.fromJson(Map<String, dynamic> json) =>
+      _$RedirectRuleIndexDataFromJson(json);
+
+  Map<String, dynamic> toJson() => _$RedirectRuleIndexDataToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/redirect_rule_index_data.g.dart b/packages/client_composition/lib/src/model/redirect_rule_index_data.g.dart
new file mode 100644
index 0000000..a038eb9
--- /dev/null
+++ b/packages/client_composition/lib/src/model/redirect_rule_index_data.g.dart
@@ -0,0 +1,26 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'redirect_rule_index_data.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+RedirectRuleIndexData _$RedirectRuleIndexDataFromJson(
+        Map<String, dynamic> json) =>
+    $checkedCreate(
+      'RedirectRuleIndexData',
+      json,
+      ($checkedConvert) {
+        final val = RedirectRuleIndexData(
+          ruleObjectID: $checkedConvert('ruleObjectID', (v) => v as String),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$RedirectRuleIndexDataToJson(
+        RedirectRuleIndexData instance) =>
+    <String, dynamic>{
+      'ruleObjectID': instance.ruleObjectID,
+    };
diff --git a/packages/client_composition/lib/src/model/redirect_rule_index_metadata.dart b/packages/client_composition/lib/src/model/redirect_rule_index_metadata.dart
new file mode 100644
index 0000000..9244def
--- /dev/null
+++ b/packages/client_composition/lib/src/model/redirect_rule_index_metadata.dart
@@ -0,0 +1,66 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+import 'package:algolia_client_composition/src/model/redirect_rule_index_data.dart';
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'redirect_rule_index_metadata.g.dart';
+
+@JsonSerializable()
+final class RedirectRuleIndexMetadata {
+  /// Returns a new [RedirectRuleIndexMetadata] instance.
+  const RedirectRuleIndexMetadata({
+    required this.source,
+    required this.dest,
+    required this.reason,
+    required this.succeed,
+    required this.data,
+  });
+
+  /// Source index for the redirect rule.
+  @JsonKey(name: r'source')
+  final String source;
+
+  /// Destination index for the redirect rule.
+  @JsonKey(name: r'dest')
+  final String dest;
+
+  /// Reason for the redirect rule.
+  @JsonKey(name: r'reason')
+  final String reason;
+
+  /// Redirect rule status.
+  @JsonKey(name: r'succeed')
+  final bool succeed;
+
+  @JsonKey(name: r'data')
+  final RedirectRuleIndexData data;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is RedirectRuleIndexMetadata &&
+          other.source == source &&
+          other.dest == dest &&
+          other.reason == reason &&
+          other.succeed == succeed &&
+          other.data == data;
+
+  @override
+  int get hashCode =>
+      source.hashCode +
+      dest.hashCode +
+      reason.hashCode +
+      succeed.hashCode +
+      data.hashCode;
+
+  factory RedirectRuleIndexMetadata.fromJson(Map<String, dynamic> json) =>
+      _$RedirectRuleIndexMetadataFromJson(json);
+
+  Map<String, dynamic> toJson() => _$RedirectRuleIndexMetadataToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/redirect_rule_index_metadata.g.dart b/packages/client_composition/lib/src/model/redirect_rule_index_metadata.g.dart
new file mode 100644
index 0000000..91cb7e5
--- /dev/null
+++ b/packages/client_composition/lib/src/model/redirect_rule_index_metadata.g.dart
@@ -0,0 +1,35 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'redirect_rule_index_metadata.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+RedirectRuleIndexMetadata _$RedirectRuleIndexMetadataFromJson(
+        Map<String, dynamic> json) =>
+    $checkedCreate(
+      'RedirectRuleIndexMetadata',
+      json,
+      ($checkedConvert) {
+        final val = RedirectRuleIndexMetadata(
+          source: $checkedConvert('source', (v) => v as String),
+          dest: $checkedConvert('dest', (v) => v as String),
+          reason: $checkedConvert('reason', (v) => v as String),
+          succeed: $checkedConvert('succeed', (v) => v as bool),
+          data: $checkedConvert('data',
+              (v) => RedirectRuleIndexData.fromJson(v as Map<String, dynamic>)),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$RedirectRuleIndexMetadataToJson(
+        RedirectRuleIndexMetadata instance) =>
+    <String, dynamic>{
+      'source': instance.source,
+      'dest': instance.dest,
+      'reason': instance.reason,
+      'succeed': instance.succeed,
+      'data': instance.data.toJson(),
+    };
diff --git a/packages/client_composition/lib/src/model/redirect_url.dart b/packages/client_composition/lib/src/model/redirect_url.dart
new file mode 100644
index 0000000..b433a64
--- /dev/null
+++ b/packages/client_composition/lib/src/model/redirect_url.dart
@@ -0,0 +1,34 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'redirect_url.g.dart';
+
+@JsonSerializable()
+final class RedirectURL {
+  /// Returns a new [RedirectURL] instance.
+  const RedirectURL({
+    this.url,
+  });
+
+  @JsonKey(name: r'url')
+  final String? url;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) || other is RedirectURL && other.url == url;
+
+  @override
+  int get hashCode => url.hashCode;
+
+  factory RedirectURL.fromJson(Map<String, dynamic> json) =>
+      _$RedirectURLFromJson(json);
+
+  Map<String, dynamic> toJson() => _$RedirectURLToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/redirect_url.g.dart b/packages/client_composition/lib/src/model/redirect_url.g.dart
new file mode 100644
index 0000000..2c0cfbc
--- /dev/null
+++ b/packages/client_composition/lib/src/model/redirect_url.g.dart
@@ -0,0 +1,23 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'redirect_url.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+RedirectURL _$RedirectURLFromJson(Map<String, dynamic> json) => $checkedCreate(
+      'RedirectURL',
+      json,
+      ($checkedConvert) {
+        final val = RedirectURL(
+          url: $checkedConvert('url', (v) => v as String?),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$RedirectURLToJson(RedirectURL instance) =>
+    <String, dynamic>{
+      if (instance.url case final value?) 'url': value,
+    };
diff --git a/packages/client_composition/lib/src/model/rendering_content.dart b/packages/client_composition/lib/src/model/rendering_content.dart
new file mode 100644
index 0000000..e66de18
--- /dev/null
+++ b/packages/client_composition/lib/src/model/rendering_content.dart
@@ -0,0 +1,50 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+import 'package:algolia_client_composition/src/model/redirect_url.dart';
+import 'package:algolia_client_composition/src/model/facet_ordering.dart';
+import 'package:algolia_client_composition/src/model/widgets.dart';
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'rendering_content.g.dart';
+
+@JsonSerializable()
+final class RenderingContent {
+  /// Returns a new [RenderingContent] instance.
+  const RenderingContent({
+    this.facetOrdering,
+    this.redirect,
+    this.widgets,
+  });
+
+  @JsonKey(name: r'facetOrdering')
+  final FacetOrdering? facetOrdering;
+
+  @JsonKey(name: r'redirect')
+  final RedirectURL? redirect;
+
+  @JsonKey(name: r'widgets')
+  final Widgets? widgets;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is RenderingContent &&
+          other.facetOrdering == facetOrdering &&
+          other.redirect == redirect &&
+          other.widgets == widgets;
+
+  @override
+  int get hashCode =>
+      facetOrdering.hashCode + redirect.hashCode + widgets.hashCode;
+
+  factory RenderingContent.fromJson(Map<String, dynamic> json) =>
+      _$RenderingContentFromJson(json);
+
+  Map<String, dynamic> toJson() => _$RenderingContentToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/rendering_content.g.dart b/packages/client_composition/lib/src/model/rendering_content.g.dart
new file mode 100644
index 0000000..821e5ce
--- /dev/null
+++ b/packages/client_composition/lib/src/model/rendering_content.g.dart
@@ -0,0 +1,41 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'rendering_content.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+RenderingContent _$RenderingContentFromJson(Map<String, dynamic> json) =>
+    $checkedCreate(
+      'RenderingContent',
+      json,
+      ($checkedConvert) {
+        final val = RenderingContent(
+          facetOrdering: $checkedConvert(
+              'facetOrdering',
+              (v) => v == null
+                  ? null
+                  : FacetOrdering.fromJson(v as Map<String, dynamic>)),
+          redirect: $checkedConvert(
+              'redirect',
+              (v) => v == null
+                  ? null
+                  : RedirectURL.fromJson(v as Map<String, dynamic>)),
+          widgets: $checkedConvert(
+              'widgets',
+              (v) => v == null
+                  ? null
+                  : Widgets.fromJson(v as Map<String, dynamic>)),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$RenderingContentToJson(RenderingContent instance) =>
+    <String, dynamic>{
+      if (instance.facetOrdering?.toJson() case final value?)
+        'facetOrdering': value,
+      if (instance.redirect?.toJson() case final value?) 'redirect': value,
+      if (instance.widgets?.toJson() case final value?) 'widgets': value,
+    };
diff --git a/packages/client_composition/lib/src/model/request_body.dart b/packages/client_composition/lib/src/model/request_body.dart
new file mode 100644
index 0000000..3b1ea7d
--- /dev/null
+++ b/packages/client_composition/lib/src/model/request_body.dart
@@ -0,0 +1,35 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+import 'package:algolia_client_composition/src/model/params.dart';
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'request_body.g.dart';
+
+@JsonSerializable()
+final class RequestBody {
+  /// Returns a new [RequestBody] instance.
+  const RequestBody({
+    this.params,
+  });
+
+  @JsonKey(name: r'params')
+  final Params? params;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) || other is RequestBody && other.params == params;
+
+  @override
+  int get hashCode => params.hashCode;
+
+  factory RequestBody.fromJson(Map<String, dynamic> json) =>
+      _$RequestBodyFromJson(json);
+
+  Map<String, dynamic> toJson() => _$RequestBodyToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/request_body.g.dart b/packages/client_composition/lib/src/model/request_body.g.dart
new file mode 100644
index 0000000..b8e5a0c
--- /dev/null
+++ b/packages/client_composition/lib/src/model/request_body.g.dart
@@ -0,0 +1,27 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'request_body.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+RequestBody _$RequestBodyFromJson(Map<String, dynamic> json) => $checkedCreate(
+      'RequestBody',
+      json,
+      ($checkedConvert) {
+        final val = RequestBody(
+          params: $checkedConvert(
+              'params',
+              (v) => v == null
+                  ? null
+                  : Params.fromJson(v as Map<String, dynamic>)),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$RequestBodyToJson(RequestBody instance) =>
+    <String, dynamic>{
+      if (instance.params?.toJson() case final value?) 'params': value,
+    };
diff --git a/packages/client_composition/lib/src/model/results_composition_info_response.dart b/packages/client_composition/lib/src/model/results_composition_info_response.dart
new file mode 100644
index 0000000..f070df4
--- /dev/null
+++ b/packages/client_composition/lib/src/model/results_composition_info_response.dart
@@ -0,0 +1,37 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+import 'package:algolia_client_composition/src/model/results_injected_item_info_response.dart';
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'results_composition_info_response.g.dart';
+
+@JsonSerializable()
+final class ResultsCompositionInfoResponse {
+  /// Returns a new [ResultsCompositionInfoResponse] instance.
+  const ResultsCompositionInfoResponse({
+    required this.injectedItems,
+  });
+
+  @JsonKey(name: r'injectedItems')
+  final List<ResultsInjectedItemInfoResponse> injectedItems;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is ResultsCompositionInfoResponse &&
+          other.injectedItems == injectedItems;
+
+  @override
+  int get hashCode => injectedItems.hashCode;
+
+  factory ResultsCompositionInfoResponse.fromJson(Map<String, dynamic> json) =>
+      _$ResultsCompositionInfoResponseFromJson(json);
+
+  Map<String, dynamic> toJson() => _$ResultsCompositionInfoResponseToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/results_composition_info_response.g.dart b/packages/client_composition/lib/src/model/results_composition_info_response.g.dart
new file mode 100644
index 0000000..f52e2ae
--- /dev/null
+++ b/packages/client_composition/lib/src/model/results_composition_info_response.g.dart
@@ -0,0 +1,31 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'results_composition_info_response.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+ResultsCompositionInfoResponse _$ResultsCompositionInfoResponseFromJson(
+        Map<String, dynamic> json) =>
+    $checkedCreate(
+      'ResultsCompositionInfoResponse',
+      json,
+      ($checkedConvert) {
+        final val = ResultsCompositionInfoResponse(
+          injectedItems: $checkedConvert(
+              'injectedItems',
+              (v) => (v as List<dynamic>)
+                  .map((e) => ResultsInjectedItemInfoResponse.fromJson(
+                      e as Map<String, dynamic>))
+                  .toList()),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$ResultsCompositionInfoResponseToJson(
+        ResultsCompositionInfoResponse instance) =>
+    <String, dynamic>{
+      'injectedItems': instance.injectedItems.map((e) => e.toJson()).toList(),
+    };
diff --git a/packages/client_composition/lib/src/model/results_compositions_response.dart b/packages/client_composition/lib/src/model/results_compositions_response.dart
new file mode 100644
index 0000000..a81349a
--- /dev/null
+++ b/packages/client_composition/lib/src/model/results_compositions_response.dart
@@ -0,0 +1,50 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+import 'package:algolia_client_composition/src/model/results_composition_info_response.dart';
+
+import 'package:collection/collection.dart';
+import 'package:json_annotation/json_annotation.dart';
+
+part 'results_compositions_response.g.dart';
+
+@JsonSerializable(createFieldMap: true)
+final class ResultsCompositionsResponse extends DelegatingMap<String, dynamic> {
+  /// Returns a new [ResultsCompositionsResponse] instance.
+  const ResultsCompositionsResponse({
+    required this.compositions,
+    Map<String, dynamic> additionalProperties = const {},
+  }) : super(additionalProperties);
+
+  @JsonKey(name: r'compositions')
+  final Map<String, ResultsCompositionInfoResponse> compositions;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is ResultsCompositionsResponse &&
+          other.compositions == compositions &&
+          const MapEquality<String, dynamic>().equals(this, this);
+
+  @override
+  int get hashCode =>
+      compositions.hashCode + const MapEquality<String, dynamic>().hash(this);
+
+  factory ResultsCompositionsResponse.fromJson(Map<String, dynamic> json) {
+    final instance = _$ResultsCompositionsResponseFromJson(json);
+    final additionalProperties = Map<String, dynamic>.from(json)
+      ..removeWhere((key, value) =>
+          _$ResultsCompositionsResponseFieldMap.containsKey(key));
+    return ResultsCompositionsResponse(
+      compositions: instance.compositions,
+      additionalProperties: additionalProperties,
+    );
+  }
+
+  Map<String, dynamic> toJson() =>
+      _$ResultsCompositionsResponseToJson(this)..addAll(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/results_compositions_response.g.dart b/packages/client_composition/lib/src/model/results_compositions_response.g.dart
new file mode 100644
index 0000000..e7c9b1e
--- /dev/null
+++ b/packages/client_composition/lib/src/model/results_compositions_response.g.dart
@@ -0,0 +1,38 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'results_compositions_response.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+ResultsCompositionsResponse _$ResultsCompositionsResponseFromJson(
+        Map<String, dynamic> json) =>
+    $checkedCreate(
+      'ResultsCompositionsResponse',
+      json,
+      ($checkedConvert) {
+        final val = ResultsCompositionsResponse(
+          compositions: $checkedConvert(
+              'compositions',
+              (v) => (v as Map<String, dynamic>).map(
+                    (k, e) => MapEntry(
+                        k,
+                        ResultsCompositionInfoResponse.fromJson(
+                            e as Map<String, dynamic>)),
+                  )),
+        );
+        return val;
+      },
+    );
+
+const _$ResultsCompositionsResponseFieldMap = <String, String>{
+  'compositions': 'compositions',
+};
+
+Map<String, dynamic> _$ResultsCompositionsResponseToJson(
+        ResultsCompositionsResponse instance) =>
+    <String, dynamic>{
+      'compositions':
+          instance.compositions.map((k, e) => MapEntry(k, e.toJson())),
+    };
diff --git a/packages/client_composition/lib/src/model/results_injected_item_applied_rules_info_response.dart b/packages/client_composition/lib/src/model/results_injected_item_applied_rules_info_response.dart
new file mode 100644
index 0000000..e38a2e5
--- /dev/null
+++ b/packages/client_composition/lib/src/model/results_injected_item_applied_rules_info_response.dart
@@ -0,0 +1,39 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'results_injected_item_applied_rules_info_response.g.dart';
+
+@JsonSerializable()
+final class ResultsInjectedItemAppliedRulesInfoResponse {
+  /// Returns a new [ResultsInjectedItemAppliedRulesInfoResponse] instance.
+  const ResultsInjectedItemAppliedRulesInfoResponse({
+    required this.objectID,
+  });
+
+  /// Unique record identifier.
+  @JsonKey(name: r'objectID')
+  final String objectID;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is ResultsInjectedItemAppliedRulesInfoResponse &&
+          other.objectID == objectID;
+
+  @override
+  int get hashCode => objectID.hashCode;
+
+  factory ResultsInjectedItemAppliedRulesInfoResponse.fromJson(
+          Map<String, dynamic> json) =>
+      _$ResultsInjectedItemAppliedRulesInfoResponseFromJson(json);
+
+  Map<String, dynamic> toJson() =>
+      _$ResultsInjectedItemAppliedRulesInfoResponseToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/results_injected_item_applied_rules_info_response.g.dart b/packages/client_composition/lib/src/model/results_injected_item_applied_rules_info_response.g.dart
new file mode 100644
index 0000000..17f7d1a
--- /dev/null
+++ b/packages/client_composition/lib/src/model/results_injected_item_applied_rules_info_response.g.dart
@@ -0,0 +1,27 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'results_injected_item_applied_rules_info_response.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+ResultsInjectedItemAppliedRulesInfoResponse
+    _$ResultsInjectedItemAppliedRulesInfoResponseFromJson(
+            Map<String, dynamic> json) =>
+        $checkedCreate(
+          'ResultsInjectedItemAppliedRulesInfoResponse',
+          json,
+          ($checkedConvert) {
+            final val = ResultsInjectedItemAppliedRulesInfoResponse(
+              objectID: $checkedConvert('objectID', (v) => v as String),
+            );
+            return val;
+          },
+        );
+
+Map<String, dynamic> _$ResultsInjectedItemAppliedRulesInfoResponseToJson(
+        ResultsInjectedItemAppliedRulesInfoResponse instance) =>
+    <String, dynamic>{
+      'objectID': instance.objectID,
+    };
diff --git a/packages/client_composition/lib/src/model/results_injected_item_info_response.dart b/packages/client_composition/lib/src/model/results_injected_item_info_response.dart
new file mode 100644
index 0000000..64c7e08
--- /dev/null
+++ b/packages/client_composition/lib/src/model/results_injected_item_info_response.dart
@@ -0,0 +1,59 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+import 'package:algolia_client_composition/src/model/results_injected_item_applied_rules_info_response.dart';
+
+import 'package:collection/collection.dart';
+import 'package:json_annotation/json_annotation.dart';
+
+part 'results_injected_item_info_response.g.dart';
+
+@JsonSerializable(createFieldMap: true)
+final class ResultsInjectedItemInfoResponse
+    extends DelegatingMap<String, dynamic> {
+  /// Returns a new [ResultsInjectedItemInfoResponse] instance.
+  const ResultsInjectedItemInfoResponse({
+    required this.key,
+    this.appliedRules,
+    Map<String, dynamic> additionalProperties = const {},
+  }) : super(additionalProperties);
+
+  @JsonKey(name: r'key')
+  final String key;
+
+  @JsonKey(name: r'appliedRules')
+  final List<ResultsInjectedItemAppliedRulesInfoResponse>? appliedRules;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is ResultsInjectedItemInfoResponse &&
+          other.key == key &&
+          other.appliedRules == appliedRules &&
+          const MapEquality<String, dynamic>().equals(this, this);
+
+  @override
+  int get hashCode =>
+      key.hashCode +
+      appliedRules.hashCode +
+      const MapEquality<String, dynamic>().hash(this);
+
+  factory ResultsInjectedItemInfoResponse.fromJson(Map<String, dynamic> json) {
+    final instance = _$ResultsInjectedItemInfoResponseFromJson(json);
+    final additionalProperties = Map<String, dynamic>.from(json)
+      ..removeWhere((key, value) =>
+          _$ResultsInjectedItemInfoResponseFieldMap.containsKey(key));
+    return ResultsInjectedItemInfoResponse(
+      key: instance.key,
+      appliedRules: instance.appliedRules,
+      additionalProperties: additionalProperties,
+    );
+  }
+
+  Map<String, dynamic> toJson() =>
+      _$ResultsInjectedItemInfoResponseToJson(this)..addAll(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/results_injected_item_info_response.g.dart b/packages/client_composition/lib/src/model/results_injected_item_info_response.g.dart
new file mode 100644
index 0000000..ad2180a
--- /dev/null
+++ b/packages/client_composition/lib/src/model/results_injected_item_info_response.g.dart
@@ -0,0 +1,41 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'results_injected_item_info_response.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+ResultsInjectedItemInfoResponse _$ResultsInjectedItemInfoResponseFromJson(
+        Map<String, dynamic> json) =>
+    $checkedCreate(
+      'ResultsInjectedItemInfoResponse',
+      json,
+      ($checkedConvert) {
+        final val = ResultsInjectedItemInfoResponse(
+          key: $checkedConvert('key', (v) => v as String),
+          appliedRules: $checkedConvert(
+              'appliedRules',
+              (v) => (v as List<dynamic>?)
+                  ?.map((e) =>
+                      ResultsInjectedItemAppliedRulesInfoResponse.fromJson(
+                          e as Map<String, dynamic>))
+                  .toList()),
+        );
+        return val;
+      },
+    );
+
+const _$ResultsInjectedItemInfoResponseFieldMap = <String, String>{
+  'key': 'key',
+  'appliedRules': 'appliedRules',
+};
+
+Map<String, dynamic> _$ResultsInjectedItemInfoResponseToJson(
+        ResultsInjectedItemInfoResponse instance) =>
+    <String, dynamic>{
+      'key': instance.key,
+      if (instance.appliedRules?.map((e) => e.toJson()).toList()
+          case final value?)
+        'appliedRules': value,
+    };
diff --git a/packages/client_composition/lib/src/model/search_for_facet_values_params.dart b/packages/client_composition/lib/src/model/search_for_facet_values_params.dart
new file mode 100644
index 0000000..5ed2343
--- /dev/null
+++ b/packages/client_composition/lib/src/model/search_for_facet_values_params.dart
@@ -0,0 +1,51 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+import 'package:algolia_client_composition/src/model/params.dart';
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'search_for_facet_values_params.g.dart';
+
+@JsonSerializable()
+final class SearchForFacetValuesParams {
+  /// Returns a new [SearchForFacetValuesParams] instance.
+  const SearchForFacetValuesParams({
+    this.query,
+    this.maxFacetHits,
+    this.searchQuery,
+  });
+
+  /// Search query.
+  @JsonKey(name: r'query')
+  final String? query;
+
+  /// Maximum number of facet values to return when [searching for facet values](https://www.algolia.com/doc/guides/managing-results/refine-results/faceting/#search-for-facet-values).
+  // maximum: 100
+  @JsonKey(name: r'maxFacetHits')
+  final int? maxFacetHits;
+
+  @JsonKey(name: r'searchQuery')
+  final Params? searchQuery;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is SearchForFacetValuesParams &&
+          other.query == query &&
+          other.maxFacetHits == maxFacetHits &&
+          other.searchQuery == searchQuery;
+
+  @override
+  int get hashCode =>
+      query.hashCode + maxFacetHits.hashCode + searchQuery.hashCode;
+
+  factory SearchForFacetValuesParams.fromJson(Map<String, dynamic> json) =>
+      _$SearchForFacetValuesParamsFromJson(json);
+
+  Map<String, dynamic> toJson() => _$SearchForFacetValuesParamsToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/search_for_facet_values_params.g.dart b/packages/client_composition/lib/src/model/search_for_facet_values_params.g.dart
new file mode 100644
index 0000000..4166fe3
--- /dev/null
+++ b/packages/client_composition/lib/src/model/search_for_facet_values_params.g.dart
@@ -0,0 +1,36 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'search_for_facet_values_params.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+SearchForFacetValuesParams _$SearchForFacetValuesParamsFromJson(
+        Map<String, dynamic> json) =>
+    $checkedCreate(
+      'SearchForFacetValuesParams',
+      json,
+      ($checkedConvert) {
+        final val = SearchForFacetValuesParams(
+          query: $checkedConvert('query', (v) => v as String?),
+          maxFacetHits:
+              $checkedConvert('maxFacetHits', (v) => (v as num?)?.toInt()),
+          searchQuery: $checkedConvert(
+              'searchQuery',
+              (v) => v == null
+                  ? null
+                  : Params.fromJson(v as Map<String, dynamic>)),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$SearchForFacetValuesParamsToJson(
+        SearchForFacetValuesParams instance) =>
+    <String, dynamic>{
+      if (instance.query case final value?) 'query': value,
+      if (instance.maxFacetHits case final value?) 'maxFacetHits': value,
+      if (instance.searchQuery?.toJson() case final value?)
+        'searchQuery': value,
+    };
diff --git a/packages/client_composition/lib/src/model/search_for_facet_values_request.dart b/packages/client_composition/lib/src/model/search_for_facet_values_request.dart
new file mode 100644
index 0000000..d162f4e
--- /dev/null
+++ b/packages/client_composition/lib/src/model/search_for_facet_values_request.dart
@@ -0,0 +1,36 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+import 'package:algolia_client_composition/src/model/search_for_facet_values_params.dart';
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'search_for_facet_values_request.g.dart';
+
+@JsonSerializable()
+final class SearchForFacetValuesRequest {
+  /// Returns a new [SearchForFacetValuesRequest] instance.
+  const SearchForFacetValuesRequest({
+    this.params,
+  });
+
+  @JsonKey(name: r'params')
+  final SearchForFacetValuesParams? params;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is SearchForFacetValuesRequest && other.params == params;
+
+  @override
+  int get hashCode => params.hashCode;
+
+  factory SearchForFacetValuesRequest.fromJson(Map<String, dynamic> json) =>
+      _$SearchForFacetValuesRequestFromJson(json);
+
+  Map<String, dynamic> toJson() => _$SearchForFacetValuesRequestToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/search_for_facet_values_request.g.dart b/packages/client_composition/lib/src/model/search_for_facet_values_request.g.dart
new file mode 100644
index 0000000..7bf7e82
--- /dev/null
+++ b/packages/client_composition/lib/src/model/search_for_facet_values_request.g.dart
@@ -0,0 +1,31 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'search_for_facet_values_request.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+SearchForFacetValuesRequest _$SearchForFacetValuesRequestFromJson(
+        Map<String, dynamic> json) =>
+    $checkedCreate(
+      'SearchForFacetValuesRequest',
+      json,
+      ($checkedConvert) {
+        final val = SearchForFacetValuesRequest(
+          params: $checkedConvert(
+              'params',
+              (v) => v == null
+                  ? null
+                  : SearchForFacetValuesParams.fromJson(
+                      v as Map<String, dynamic>)),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$SearchForFacetValuesRequestToJson(
+        SearchForFacetValuesRequest instance) =>
+    <String, dynamic>{
+      if (instance.params?.toJson() case final value?) 'params': value,
+    };
diff --git a/packages/client_composition/lib/src/model/search_for_facet_values_response.dart b/packages/client_composition/lib/src/model/search_for_facet_values_response.dart
new file mode 100644
index 0000000..328d6b5
--- /dev/null
+++ b/packages/client_composition/lib/src/model/search_for_facet_values_response.dart
@@ -0,0 +1,37 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+import 'package:algolia_client_composition/src/model/search_for_facet_values_results.dart';
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'search_for_facet_values_response.g.dart';
+
+@JsonSerializable()
+final class SearchForFacetValuesResponse {
+  /// Returns a new [SearchForFacetValuesResponse] instance.
+  const SearchForFacetValuesResponse({
+    this.results,
+  });
+
+  /// Search for facet values results.
+  @JsonKey(name: r'results')
+  final List<SearchForFacetValuesResults>? results;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is SearchForFacetValuesResponse && other.results == results;
+
+  @override
+  int get hashCode => results.hashCode;
+
+  factory SearchForFacetValuesResponse.fromJson(Map<String, dynamic> json) =>
+      _$SearchForFacetValuesResponseFromJson(json);
+
+  Map<String, dynamic> toJson() => _$SearchForFacetValuesResponseToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/search_for_facet_values_response.g.dart b/packages/client_composition/lib/src/model/search_for_facet_values_response.g.dart
new file mode 100644
index 0000000..e0d8fbc
--- /dev/null
+++ b/packages/client_composition/lib/src/model/search_for_facet_values_response.g.dart
@@ -0,0 +1,32 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'search_for_facet_values_response.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+SearchForFacetValuesResponse _$SearchForFacetValuesResponseFromJson(
+        Map<String, dynamic> json) =>
+    $checkedCreate(
+      'SearchForFacetValuesResponse',
+      json,
+      ($checkedConvert) {
+        final val = SearchForFacetValuesResponse(
+          results: $checkedConvert(
+              'results',
+              (v) => (v as List<dynamic>?)
+                  ?.map((e) => SearchForFacetValuesResults.fromJson(
+                      e as Map<String, dynamic>))
+                  .toList()),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$SearchForFacetValuesResponseToJson(
+        SearchForFacetValuesResponse instance) =>
+    <String, dynamic>{
+      if (instance.results?.map((e) => e.toJson()).toList() case final value?)
+        'results': value,
+    };
diff --git a/packages/client_composition/lib/src/model/search_for_facet_values_results.dart b/packages/client_composition/lib/src/model/search_for_facet_values_results.dart
new file mode 100644
index 0000000..0d63d86
--- /dev/null
+++ b/packages/client_composition/lib/src/model/search_for_facet_values_results.dart
@@ -0,0 +1,59 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+import 'package:algolia_client_composition/src/model/facet_hits.dart';
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'search_for_facet_values_results.g.dart';
+
+@JsonSerializable()
+final class SearchForFacetValuesResults {
+  /// Returns a new [SearchForFacetValuesResults] instance.
+  const SearchForFacetValuesResults({
+    required this.indexName,
+    required this.facetHits,
+    required this.exhaustiveFacetsCount,
+    this.processingTimeMS,
+  });
+
+  @JsonKey(name: r'indexName')
+  final String indexName;
+
+  /// Matching facet values.
+  @JsonKey(name: r'facetHits')
+  final List<FacetHits> facetHits;
+
+  /// Whether the facet count is exhaustive (true) or approximate (false). For more information, see [Why are my facet and hit counts not accurate](https://support.algolia.com/hc/en-us/articles/4406975248145-Why-are-my-facet-and-hit-counts-not-accurate-).
+  @JsonKey(name: r'exhaustiveFacetsCount')
+  final bool exhaustiveFacetsCount;
+
+  /// Time the server took to process the request, in milliseconds.
+  @JsonKey(name: r'processingTimeMS')
+  final int? processingTimeMS;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is SearchForFacetValuesResults &&
+          other.indexName == indexName &&
+          other.facetHits == facetHits &&
+          other.exhaustiveFacetsCount == exhaustiveFacetsCount &&
+          other.processingTimeMS == processingTimeMS;
+
+  @override
+  int get hashCode =>
+      indexName.hashCode +
+      facetHits.hashCode +
+      exhaustiveFacetsCount.hashCode +
+      processingTimeMS.hashCode;
+
+  factory SearchForFacetValuesResults.fromJson(Map<String, dynamic> json) =>
+      _$SearchForFacetValuesResultsFromJson(json);
+
+  Map<String, dynamic> toJson() => _$SearchForFacetValuesResultsToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/search_for_facet_values_results.g.dart b/packages/client_composition/lib/src/model/search_for_facet_values_results.g.dart
new file mode 100644
index 0000000..ce79661
--- /dev/null
+++ b/packages/client_composition/lib/src/model/search_for_facet_values_results.g.dart
@@ -0,0 +1,39 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'search_for_facet_values_results.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+SearchForFacetValuesResults _$SearchForFacetValuesResultsFromJson(
+        Map<String, dynamic> json) =>
+    $checkedCreate(
+      'SearchForFacetValuesResults',
+      json,
+      ($checkedConvert) {
+        final val = SearchForFacetValuesResults(
+          indexName: $checkedConvert('indexName', (v) => v as String),
+          facetHits: $checkedConvert(
+              'facetHits',
+              (v) => (v as List<dynamic>)
+                  .map((e) => FacetHits.fromJson(e as Map<String, dynamic>))
+                  .toList()),
+          exhaustiveFacetsCount:
+              $checkedConvert('exhaustiveFacetsCount', (v) => v as bool),
+          processingTimeMS:
+              $checkedConvert('processingTimeMS', (v) => (v as num?)?.toInt()),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$SearchForFacetValuesResultsToJson(
+        SearchForFacetValuesResults instance) =>
+    <String, dynamic>{
+      'indexName': instance.indexName,
+      'facetHits': instance.facetHits.map((e) => e.toJson()).toList(),
+      'exhaustiveFacetsCount': instance.exhaustiveFacetsCount,
+      if (instance.processingTimeMS case final value?)
+        'processingTimeMS': value,
+    };
diff --git a/packages/client_composition/lib/src/model/search_hits.dart b/packages/client_composition/lib/src/model/search_hits.dart
new file mode 100644
index 0000000..83b9288
--- /dev/null
+++ b/packages/client_composition/lib/src/model/search_hits.dart
@@ -0,0 +1,66 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+import 'package:algolia_client_composition/src/model/hit.dart';
+
+import 'package:collection/collection.dart';
+import 'package:json_annotation/json_annotation.dart';
+
+part 'search_hits.g.dart';
+
+@JsonSerializable(createFieldMap: true)
+final class SearchHits extends DelegatingMap<String, dynamic> {
+  /// Returns a new [SearchHits] instance.
+  const SearchHits({
+    required this.hits,
+    required this.query,
+    required this.params,
+    Map<String, dynamic> additionalProperties = const {},
+  }) : super(additionalProperties);
+
+  /// Search results (hits).  Hits are records from your index that match the search criteria, augmented with additional attributes, such as, for highlighting.
+  @JsonKey(name: r'hits')
+  final List<Hit> hits;
+
+  /// Search query.
+  @JsonKey(name: r'query')
+  final String query;
+
+  /// URL-encoded string of all search parameters.
+  @JsonKey(name: r'params')
+  final String params;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is SearchHits &&
+          other.hits == hits &&
+          other.query == query &&
+          other.params == params &&
+          const MapEquality<String, dynamic>().equals(this, this);
+
+  @override
+  int get hashCode =>
+      hits.hashCode +
+      query.hashCode +
+      params.hashCode +
+      const MapEquality<String, dynamic>().hash(this);
+
+  factory SearchHits.fromJson(Map<String, dynamic> json) {
+    final instance = _$SearchHitsFromJson(json);
+    final additionalProperties = Map<String, dynamic>.from(json)
+      ..removeWhere((key, value) => _$SearchHitsFieldMap.containsKey(key));
+    return SearchHits(
+      hits: instance.hits,
+      query: instance.query,
+      params: instance.params,
+      additionalProperties: additionalProperties,
+    );
+  }
+
+  Map<String, dynamic> toJson() => _$SearchHitsToJson(this)..addAll(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/search_hits.g.dart b/packages/client_composition/lib/src/model/search_hits.g.dart
new file mode 100644
index 0000000..50e2dda
--- /dev/null
+++ b/packages/client_composition/lib/src/model/search_hits.g.dart
@@ -0,0 +1,37 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'search_hits.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+SearchHits _$SearchHitsFromJson(Map<String, dynamic> json) => $checkedCreate(
+      'SearchHits',
+      json,
+      ($checkedConvert) {
+        final val = SearchHits(
+          hits: $checkedConvert(
+              'hits',
+              (v) => (v as List<dynamic>)
+                  .map((e) => Hit.fromJson(e as Map<String, dynamic>))
+                  .toList()),
+          query: $checkedConvert('query', (v) => v as String),
+          params: $checkedConvert('params', (v) => v as String),
+        );
+        return val;
+      },
+    );
+
+const _$SearchHitsFieldMap = <String, String>{
+  'hits': 'hits',
+  'query': 'query',
+  'params': 'params',
+};
+
+Map<String, dynamic> _$SearchHitsToJson(SearchHits instance) =>
+    <String, dynamic>{
+      'hits': instance.hits.map((e) => e.toJson()).toList(),
+      'query': instance.query,
+      'params': instance.params,
+    };
diff --git a/packages/client_composition/lib/src/model/search_pagination.dart b/packages/client_composition/lib/src/model/search_pagination.dart
new file mode 100644
index 0000000..4c7eb08
--- /dev/null
+++ b/packages/client_composition/lib/src/model/search_pagination.dart
@@ -0,0 +1,59 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'search_pagination.g.dart';
+
+@JsonSerializable()
+final class SearchPagination {
+  /// Returns a new [SearchPagination] instance.
+  const SearchPagination({
+    required this.page,
+    required this.nbHits,
+    required this.nbPages,
+    required this.hitsPerPage,
+  });
+
+  /// Page of search results to retrieve.
+  // minimum: 0
+  @JsonKey(name: r'page')
+  final int page;
+
+  /// Number of results (hits).
+  @JsonKey(name: r'nbHits')
+  final int nbHits;
+
+  /// Number of pages of results.
+  @JsonKey(name: r'nbPages')
+  final int nbPages;
+
+  /// Number of hits per page.
+  // minimum: 1
+  // maximum: 1000
+  @JsonKey(name: r'hitsPerPage')
+  final int hitsPerPage;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is SearchPagination &&
+          other.page == page &&
+          other.nbHits == nbHits &&
+          other.nbPages == nbPages &&
+          other.hitsPerPage == hitsPerPage;
+
+  @override
+  int get hashCode =>
+      page.hashCode + nbHits.hashCode + nbPages.hashCode + hitsPerPage.hashCode;
+
+  factory SearchPagination.fromJson(Map<String, dynamic> json) =>
+      _$SearchPaginationFromJson(json);
+
+  Map<String, dynamic> toJson() => _$SearchPaginationToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/search_pagination.g.dart b/packages/client_composition/lib/src/model/search_pagination.g.dart
new file mode 100644
index 0000000..b58a96c
--- /dev/null
+++ b/packages/client_composition/lib/src/model/search_pagination.g.dart
@@ -0,0 +1,31 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'search_pagination.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+SearchPagination _$SearchPaginationFromJson(Map<String, dynamic> json) =>
+    $checkedCreate(
+      'SearchPagination',
+      json,
+      ($checkedConvert) {
+        final val = SearchPagination(
+          page: $checkedConvert('page', (v) => (v as num).toInt()),
+          nbHits: $checkedConvert('nbHits', (v) => (v as num).toInt()),
+          nbPages: $checkedConvert('nbPages', (v) => (v as num).toInt()),
+          hitsPerPage:
+              $checkedConvert('hitsPerPage', (v) => (v as num).toInt()),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$SearchPaginationToJson(SearchPagination instance) =>
+    <String, dynamic>{
+      'page': instance.page,
+      'nbHits': instance.nbHits,
+      'nbPages': instance.nbPages,
+      'hitsPerPage': instance.hitsPerPage,
+    };
diff --git a/packages/client_composition/lib/src/model/search_response.dart b/packages/client_composition/lib/src/model/search_response.dart
new file mode 100644
index 0000000..0d504fb
--- /dev/null
+++ b/packages/client_composition/lib/src/model/search_response.dart
@@ -0,0 +1,44 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+import 'package:algolia_client_composition/src/model/compositions_search_response.dart';
+import 'package:algolia_client_composition/src/model/search_results_item.dart';
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'search_response.g.dart';
+
+@JsonSerializable()
+final class SearchResponse {
+  /// Returns a new [SearchResponse] instance.
+  const SearchResponse({
+    this.compositions,
+    required this.results,
+  });
+
+  @JsonKey(name: r'compositions')
+  final CompositionsSearchResponse? compositions;
+
+  /// Search results.
+  @JsonKey(name: r'results')
+  final List<SearchResultsItem> results;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is SearchResponse &&
+          other.compositions == compositions &&
+          other.results == results;
+
+  @override
+  int get hashCode => compositions.hashCode + results.hashCode;
+
+  factory SearchResponse.fromJson(Map<String, dynamic> json) =>
+      _$SearchResponseFromJson(json);
+
+  Map<String, dynamic> toJson() => _$SearchResponseToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/search_response.g.dart b/packages/client_composition/lib/src/model/search_response.g.dart
new file mode 100644
index 0000000..4a29ca5
--- /dev/null
+++ b/packages/client_composition/lib/src/model/search_response.g.dart
@@ -0,0 +1,37 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'search_response.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+SearchResponse _$SearchResponseFromJson(Map<String, dynamic> json) =>
+    $checkedCreate(
+      'SearchResponse',
+      json,
+      ($checkedConvert) {
+        final val = SearchResponse(
+          compositions: $checkedConvert(
+              'compositions',
+              (v) => v == null
+                  ? null
+                  : CompositionsSearchResponse.fromJson(
+                      v as Map<String, dynamic>)),
+          results: $checkedConvert(
+              'results',
+              (v) => (v as List<dynamic>)
+                  .map((e) =>
+                      SearchResultsItem.fromJson(e as Map<String, dynamic>))
+                  .toList()),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$SearchResponseToJson(SearchResponse instance) =>
+    <String, dynamic>{
+      if (instance.compositions?.toJson() case final value?)
+        'compositions': value,
+      'results': instance.results.map((e) => e.toJson()).toList(),
+    };
diff --git a/packages/client_composition/lib/src/model/search_results.dart b/packages/client_composition/lib/src/model/search_results.dart
new file mode 100644
index 0000000..18d03d7
--- /dev/null
+++ b/packages/client_composition/lib/src/model/search_results.dart
@@ -0,0 +1,37 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+import 'package:algolia_client_composition/src/model/search_results_item.dart';
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'search_results.g.dart';
+
+@JsonSerializable()
+final class SearchResults {
+  /// Returns a new [SearchResults] instance.
+  const SearchResults({
+    required this.results,
+  });
+
+  /// Search results.
+  @JsonKey(name: r'results')
+  final List<SearchResultsItem> results;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is SearchResults && other.results == results;
+
+  @override
+  int get hashCode => results.hashCode;
+
+  factory SearchResults.fromJson(Map<String, dynamic> json) =>
+      _$SearchResultsFromJson(json);
+
+  Map<String, dynamic> toJson() => _$SearchResultsToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/search_results.g.dart b/packages/client_composition/lib/src/model/search_results.g.dart
new file mode 100644
index 0000000..55fcb60
--- /dev/null
+++ b/packages/client_composition/lib/src/model/search_results.g.dart
@@ -0,0 +1,29 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'search_results.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+SearchResults _$SearchResultsFromJson(Map<String, dynamic> json) =>
+    $checkedCreate(
+      'SearchResults',
+      json,
+      ($checkedConvert) {
+        final val = SearchResults(
+          results: $checkedConvert(
+              'results',
+              (v) => (v as List<dynamic>)
+                  .map((e) =>
+                      SearchResultsItem.fromJson(e as Map<String, dynamic>))
+                  .toList()),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$SearchResultsToJson(SearchResults instance) =>
+    <String, dynamic>{
+      'results': instance.results.map((e) => e.toJson()).toList(),
+    };
diff --git a/packages/client_composition/lib/src/model/search_results_item.dart b/packages/client_composition/lib/src/model/search_results_item.dart
new file mode 100644
index 0000000..d48c615
--- /dev/null
+++ b/packages/client_composition/lib/src/model/search_results_item.dart
@@ -0,0 +1,272 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+import 'package:algolia_client_composition/src/model/redirect.dart';
+import 'package:algolia_client_composition/src/model/results_composition_info_response.dart';
+import 'package:algolia_client_composition/src/model/facet_stats.dart';
+import 'package:algolia_client_composition/src/model/hit.dart';
+import 'package:algolia_client_composition/src/model/rendering_content.dart';
+import 'package:algolia_client_composition/src/model/exhaustive.dart';
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'search_results_item.g.dart';
+
+@JsonSerializable()
+final class SearchResultsItem {
+  /// Returns a new [SearchResultsItem] instance.
+  const SearchResultsItem({
+    this.abTestID,
+    this.abTestVariantID,
+    this.aroundLatLng,
+    this.automaticRadius,
+    this.exhaustive,
+    this.appliedRules,
+    this.exhaustiveFacetsCount,
+    this.exhaustiveNbHits,
+    this.exhaustiveTypo,
+    this.facets,
+    this.facetsStats,
+    this.index,
+    this.indexUsed,
+    this.message,
+    this.nbSortedHits,
+    this.parsedQuery,
+    required this.processingTimeMS,
+    this.processingTimingsMS,
+    this.queryAfterRemoval,
+    this.redirect,
+    this.renderingContent,
+    this.serverTimeMS,
+    this.serverUsed,
+    this.userData,
+    this.queryID,
+    this.automaticInsights,
+    required this.page,
+    required this.nbHits,
+    required this.nbPages,
+    required this.hitsPerPage,
+    required this.hits,
+    required this.query,
+    required this.params,
+    required this.compositions,
+  });
+
+  /// A/B test ID. This is only included in the response for indices that are part of an A/B test.
+  @JsonKey(name: r'abTestID')
+  final int? abTestID;
+
+  /// Variant ID. This is only included in the response for indices that are part of an A/B test.
+  // minimum: 1
+  @JsonKey(name: r'abTestVariantID')
+  final int? abTestVariantID;
+
+  /// Computed geographical location.
+  @JsonKey(name: r'aroundLatLng')
+  final String? aroundLatLng;
+
+  /// Distance from a central coordinate provided by `aroundLatLng`.
+  @JsonKey(name: r'automaticRadius')
+  final String? automaticRadius;
+
+  @JsonKey(name: r'exhaustive')
+  final Exhaustive? exhaustive;
+
+  /// Rules applied to the query.
+  @JsonKey(name: r'appliedRules')
+  final List<Object>? appliedRules;
+
+  /// See the `facetsCount` field of the `exhaustive` object in the response.
+  @Deprecated('exhaustiveFacetsCount has been deprecated')
+  @JsonKey(name: r'exhaustiveFacetsCount')
+  final bool? exhaustiveFacetsCount;
+
+  /// See the `nbHits` field of the `exhaustive` object in the response.
+  @Deprecated('exhaustiveNbHits has been deprecated')
+  @JsonKey(name: r'exhaustiveNbHits')
+  final bool? exhaustiveNbHits;
+
+  /// See the `typo` field of the `exhaustive` object in the response.
+  @Deprecated('exhaustiveTypo has been deprecated')
+  @JsonKey(name: r'exhaustiveTypo')
+  final bool? exhaustiveTypo;
+
+  /// Facet counts.
+  @JsonKey(name: r'facets')
+  final Map<String, Map<String, int>>? facets;
+
+  /// Statistics for numerical facets.
+  @JsonKey(name: r'facets_stats')
+  final Map<String, FacetStats>? facetsStats;
+
+  /// Index name used for the query.
+  @JsonKey(name: r'index')
+  final String? index;
+
+  /// Index name used for the query. During A/B testing, the targeted index isn't always the index used by the query.
+  @JsonKey(name: r'indexUsed')
+  final String? indexUsed;
+
+  /// Warnings about the query.
+  @JsonKey(name: r'message')
+  final String? message;
+
+  /// Number of hits selected and sorted by the relevant sort algorithm.
+  @JsonKey(name: r'nbSortedHits')
+  final int? nbSortedHits;
+
+  /// Post-[normalization](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/#what-does-normalization-mean) query string that will be searched.
+  @JsonKey(name: r'parsedQuery')
+  final String? parsedQuery;
+
+  /// Time the server took to process the request, in milliseconds.
+  @JsonKey(name: r'processingTimeMS')
+  final int processingTimeMS;
+
+  /// Experimental. List of processing steps and their times, in milliseconds. You can use this list to investigate performance issues.
+  @JsonKey(name: r'processingTimingsMS')
+  final Object? processingTimingsMS;
+
+  /// Markup text indicating which parts of the original query have been removed to retrieve a non-empty result set.
+  @JsonKey(name: r'queryAfterRemoval')
+  final String? queryAfterRemoval;
+
+  @JsonKey(name: r'redirect')
+  final Redirect? redirect;
+
+  @JsonKey(name: r'renderingContent')
+  final RenderingContent? renderingContent;
+
+  /// Time the server took to process the request, in milliseconds.
+  @JsonKey(name: r'serverTimeMS')
+  final int? serverTimeMS;
+
+  /// Host name of the server that processed the request.
+  @JsonKey(name: r'serverUsed')
+  final String? serverUsed;
+
+  /// An object with custom data.  You can store up to 32kB as custom data.
+  @JsonKey(name: r'userData')
+  final Object? userData;
+
+  /// Unique identifier for the query. This is used for [click analytics](https://www.algolia.com/doc/guides/analytics/click-analytics/).
+  @JsonKey(name: r'queryID')
+  final String? queryID;
+
+  /// Whether automatic events collection is enabled for the application.
+  @JsonKey(name: r'_automaticInsights')
+  final bool? automaticInsights;
+
+  /// Page of search results to retrieve.
+  // minimum: 0
+  @JsonKey(name: r'page')
+  final int page;
+
+  /// Number of results (hits).
+  @JsonKey(name: r'nbHits')
+  final int nbHits;
+
+  /// Number of pages of results.
+  @JsonKey(name: r'nbPages')
+  final int nbPages;
+
+  /// Number of hits per page.
+  // minimum: 1
+  // maximum: 1000
+  @JsonKey(name: r'hitsPerPage')
+  final int hitsPerPage;
+
+  /// Search results (hits).  Hits are records from your index that match the search criteria, augmented with additional attributes, such as, for highlighting.
+  @JsonKey(name: r'hits')
+  final List<Hit> hits;
+
+  /// Search query.
+  @JsonKey(name: r'query')
+  final String query;
+
+  /// URL-encoded string of all search parameters.
+  @JsonKey(name: r'params')
+  final String params;
+
+  @JsonKey(name: r'compositions')
+  final Map<String, ResultsCompositionInfoResponse> compositions;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is SearchResultsItem &&
+          other.abTestID == abTestID &&
+          other.abTestVariantID == abTestVariantID &&
+          other.aroundLatLng == aroundLatLng &&
+          other.automaticRadius == automaticRadius &&
+          other.exhaustive == exhaustive &&
+          other.appliedRules == appliedRules &&
+          other.facets == facets &&
+          other.facetsStats == facetsStats &&
+          other.index == index &&
+          other.indexUsed == indexUsed &&
+          other.message == message &&
+          other.nbSortedHits == nbSortedHits &&
+          other.parsedQuery == parsedQuery &&
+          other.processingTimeMS == processingTimeMS &&
+          other.processingTimingsMS == processingTimingsMS &&
+          other.queryAfterRemoval == queryAfterRemoval &&
+          other.redirect == redirect &&
+          other.renderingContent == renderingContent &&
+          other.serverTimeMS == serverTimeMS &&
+          other.serverUsed == serverUsed &&
+          other.userData == userData &&
+          other.queryID == queryID &&
+          other.automaticInsights == automaticInsights &&
+          other.page == page &&
+          other.nbHits == nbHits &&
+          other.nbPages == nbPages &&
+          other.hitsPerPage == hitsPerPage &&
+          other.hits == hits &&
+          other.query == query &&
+          other.params == params &&
+          other.compositions == compositions;
+
+  @override
+  int get hashCode =>
+      abTestID.hashCode +
+      abTestVariantID.hashCode +
+      aroundLatLng.hashCode +
+      automaticRadius.hashCode +
+      exhaustive.hashCode +
+      appliedRules.hashCode +
+      facets.hashCode +
+      facetsStats.hashCode +
+      index.hashCode +
+      indexUsed.hashCode +
+      message.hashCode +
+      nbSortedHits.hashCode +
+      parsedQuery.hashCode +
+      processingTimeMS.hashCode +
+      processingTimingsMS.hashCode +
+      queryAfterRemoval.hashCode +
+      redirect.hashCode +
+      renderingContent.hashCode +
+      serverTimeMS.hashCode +
+      serverUsed.hashCode +
+      userData.hashCode +
+      queryID.hashCode +
+      automaticInsights.hashCode +
+      page.hashCode +
+      nbHits.hashCode +
+      nbPages.hashCode +
+      hitsPerPage.hashCode +
+      hits.hashCode +
+      query.hashCode +
+      params.hashCode +
+      compositions.hashCode;
+
+  factory SearchResultsItem.fromJson(Map<String, dynamic> json) =>
+      _$SearchResultsItemFromJson(json);
+
+  Map<String, dynamic> toJson() => _$SearchResultsItemToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/search_results_item.g.dart b/packages/client_composition/lib/src/model/search_results_item.g.dart
new file mode 100644
index 0000000..a98d75f
--- /dev/null
+++ b/packages/client_composition/lib/src/model/search_results_item.g.dart
@@ -0,0 +1,146 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'search_results_item.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+SearchResultsItem _$SearchResultsItemFromJson(Map<String, dynamic> json) =>
+    $checkedCreate(
+      'SearchResultsItem',
+      json,
+      ($checkedConvert) {
+        final val = SearchResultsItem(
+          abTestID: $checkedConvert('abTestID', (v) => (v as num?)?.toInt()),
+          abTestVariantID:
+              $checkedConvert('abTestVariantID', (v) => (v as num?)?.toInt()),
+          aroundLatLng: $checkedConvert('aroundLatLng', (v) => v as String?),
+          automaticRadius:
+              $checkedConvert('automaticRadius', (v) => v as String?),
+          exhaustive: $checkedConvert(
+              'exhaustive',
+              (v) => v == null
+                  ? null
+                  : Exhaustive.fromJson(v as Map<String, dynamic>)),
+          appliedRules: $checkedConvert('appliedRules',
+              (v) => (v as List<dynamic>?)?.map((e) => e as Object).toList()),
+          exhaustiveFacetsCount:
+              $checkedConvert('exhaustiveFacetsCount', (v) => v as bool?),
+          exhaustiveNbHits:
+              $checkedConvert('exhaustiveNbHits', (v) => v as bool?),
+          exhaustiveTypo: $checkedConvert('exhaustiveTypo', (v) => v as bool?),
+          facets: $checkedConvert(
+              'facets',
+              (v) => (v as Map<String, dynamic>?)?.map(
+                    (k, e) => MapEntry(k, Map<String, int>.from(e as Map)),
+                  )),
+          facetsStats: $checkedConvert(
+              'facets_stats',
+              (v) => (v as Map<String, dynamic>?)?.map(
+                    (k, e) => MapEntry(
+                        k, FacetStats.fromJson(e as Map<String, dynamic>)),
+                  )),
+          index: $checkedConvert('index', (v) => v as String?),
+          indexUsed: $checkedConvert('indexUsed', (v) => v as String?),
+          message: $checkedConvert('message', (v) => v as String?),
+          nbSortedHits:
+              $checkedConvert('nbSortedHits', (v) => (v as num?)?.toInt()),
+          parsedQuery: $checkedConvert('parsedQuery', (v) => v as String?),
+          processingTimeMS:
+              $checkedConvert('processingTimeMS', (v) => (v as num).toInt()),
+          processingTimingsMS: $checkedConvert('processingTimingsMS', (v) => v),
+          queryAfterRemoval:
+              $checkedConvert('queryAfterRemoval', (v) => v as String?),
+          redirect: $checkedConvert(
+              'redirect',
+              (v) => v == null
+                  ? null
+                  : Redirect.fromJson(v as Map<String, dynamic>)),
+          renderingContent: $checkedConvert(
+              'renderingContent',
+              (v) => v == null
+                  ? null
+                  : RenderingContent.fromJson(v as Map<String, dynamic>)),
+          serverTimeMS:
+              $checkedConvert('serverTimeMS', (v) => (v as num?)?.toInt()),
+          serverUsed: $checkedConvert('serverUsed', (v) => v as String?),
+          userData: $checkedConvert('userData', (v) => v),
+          queryID: $checkedConvert('queryID', (v) => v as String?),
+          automaticInsights:
+              $checkedConvert('_automaticInsights', (v) => v as bool?),
+          page: $checkedConvert('page', (v) => (v as num).toInt()),
+          nbHits: $checkedConvert('nbHits', (v) => (v as num).toInt()),
+          nbPages: $checkedConvert('nbPages', (v) => (v as num).toInt()),
+          hitsPerPage:
+              $checkedConvert('hitsPerPage', (v) => (v as num).toInt()),
+          hits: $checkedConvert(
+              'hits',
+              (v) => (v as List<dynamic>)
+                  .map((e) => Hit.fromJson(e as Map<String, dynamic>))
+                  .toList()),
+          query: $checkedConvert('query', (v) => v as String),
+          params: $checkedConvert('params', (v) => v as String),
+          compositions: $checkedConvert(
+              'compositions',
+              (v) => (v as Map<String, dynamic>).map(
+                    (k, e) => MapEntry(
+                        k,
+                        ResultsCompositionInfoResponse.fromJson(
+                            e as Map<String, dynamic>)),
+                  )),
+        );
+        return val;
+      },
+      fieldKeyMap: const {
+        'facetsStats': 'facets_stats',
+        'automaticInsights': '_automaticInsights'
+      },
+    );
+
+Map<String, dynamic> _$SearchResultsItemToJson(SearchResultsItem instance) =>
+    <String, dynamic>{
+      if (instance.abTestID case final value?) 'abTestID': value,
+      if (instance.abTestVariantID case final value?) 'abTestVariantID': value,
+      if (instance.aroundLatLng case final value?) 'aroundLatLng': value,
+      if (instance.automaticRadius case final value?) 'automaticRadius': value,
+      if (instance.exhaustive?.toJson() case final value?) 'exhaustive': value,
+      if (instance.appliedRules case final value?) 'appliedRules': value,
+      if (instance.exhaustiveFacetsCount case final value?)
+        'exhaustiveFacetsCount': value,
+      if (instance.exhaustiveNbHits case final value?)
+        'exhaustiveNbHits': value,
+      if (instance.exhaustiveTypo case final value?) 'exhaustiveTypo': value,
+      if (instance.facets case final value?) 'facets': value,
+      if (instance.facetsStats?.map((k, e) => MapEntry(k, e.toJson()))
+          case final value?)
+        'facets_stats': value,
+      if (instance.index case final value?) 'index': value,
+      if (instance.indexUsed case final value?) 'indexUsed': value,
+      if (instance.message case final value?) 'message': value,
+      if (instance.nbSortedHits case final value?) 'nbSortedHits': value,
+      if (instance.parsedQuery case final value?) 'parsedQuery': value,
+      'processingTimeMS': instance.processingTimeMS,
+      if (instance.processingTimingsMS case final value?)
+        'processingTimingsMS': value,
+      if (instance.queryAfterRemoval case final value?)
+        'queryAfterRemoval': value,
+      if (instance.redirect?.toJson() case final value?) 'redirect': value,
+      if (instance.renderingContent?.toJson() case final value?)
+        'renderingContent': value,
+      if (instance.serverTimeMS case final value?) 'serverTimeMS': value,
+      if (instance.serverUsed case final value?) 'serverUsed': value,
+      if (instance.userData case final value?) 'userData': value,
+      if (instance.queryID case final value?) 'queryID': value,
+      if (instance.automaticInsights case final value?)
+        '_automaticInsights': value,
+      'page': instance.page,
+      'nbHits': instance.nbHits,
+      'nbPages': instance.nbPages,
+      'hitsPerPage': instance.hitsPerPage,
+      'hits': instance.hits.map((e) => e.toJson()).toList(),
+      'query': instance.query,
+      'params': instance.params,
+      'compositions':
+          instance.compositions.map((k, e) => MapEntry(k, e.toJson())),
+    };
diff --git a/packages/client_composition/lib/src/model/snippet_result_option.dart b/packages/client_composition/lib/src/model/snippet_result_option.dart
new file mode 100644
index 0000000..bba6029
--- /dev/null
+++ b/packages/client_composition/lib/src/model/snippet_result_option.dart
@@ -0,0 +1,43 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+import 'package:algolia_client_composition/src/model/match_level.dart';
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'snippet_result_option.g.dart';
+
+@JsonSerializable()
+final class SnippetResultOption {
+  /// Returns a new [SnippetResultOption] instance.
+  const SnippetResultOption({
+    required this.value,
+    required this.matchLevel,
+  });
+
+  /// Highlighted attribute value, including HTML tags.
+  @JsonKey(name: r'value')
+  final String value;
+
+  @JsonKey(name: r'matchLevel')
+  final MatchLevel matchLevel;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is SnippetResultOption &&
+          other.value == value &&
+          other.matchLevel == matchLevel;
+
+  @override
+  int get hashCode => value.hashCode + matchLevel.hashCode;
+
+  factory SnippetResultOption.fromJson(Map<String, dynamic> json) =>
+      _$SnippetResultOptionFromJson(json);
+
+  Map<String, dynamic> toJson() => _$SnippetResultOptionToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/snippet_result_option.g.dart b/packages/client_composition/lib/src/model/snippet_result_option.g.dart
new file mode 100644
index 0000000..99c5645
--- /dev/null
+++ b/packages/client_composition/lib/src/model/snippet_result_option.g.dart
@@ -0,0 +1,34 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'snippet_result_option.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+SnippetResultOption _$SnippetResultOptionFromJson(Map<String, dynamic> json) =>
+    $checkedCreate(
+      'SnippetResultOption',
+      json,
+      ($checkedConvert) {
+        final val = SnippetResultOption(
+          value: $checkedConvert('value', (v) => v as String),
+          matchLevel: $checkedConvert(
+              'matchLevel', (v) => $enumDecode(_$MatchLevelEnumMap, v)),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$SnippetResultOptionToJson(
+        SnippetResultOption instance) =>
+    <String, dynamic>{
+      'value': instance.value,
+      'matchLevel': instance.matchLevel.toJson(),
+    };
+
+const _$MatchLevelEnumMap = {
+  MatchLevel.none: 'none',
+  MatchLevel.partial: 'partial',
+  MatchLevel.full: 'full',
+};
diff --git a/packages/client_composition/lib/src/model/sort_remaining_by.dart b/packages/client_composition/lib/src/model/sort_remaining_by.dart
new file mode 100644
index 0000000..54ab805
--- /dev/null
+++ b/packages/client_composition/lib/src/model/sort_remaining_by.dart
@@ -0,0 +1,26 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+import 'package:json_annotation/json_annotation.dart';
+
+/// Order of facet values that aren't explicitly positioned with the `order` setting.  - `count`.   Order remaining facet values by decreasing count.   The count is the number of matching records containing this facet value.  - `alpha`.   Sort facet values alphabetically.  - `hidden`.   Don't show facet values that aren't explicitly positioned.
+@JsonEnum(valueField: 'raw')
+enum SortRemainingBy {
+  count(r'count'),
+  alpha(r'alpha'),
+  hidden(r'hidden');
+
+  const SortRemainingBy(this.raw);
+  final dynamic raw;
+
+  dynamic toJson() => raw;
+
+  static SortRemainingBy fromJson(dynamic json) {
+    for (final value in values) {
+      if (value.raw == json) return value;
+    }
+    throw ArgumentError.value(json, "raw", "No enum value with that value");
+  }
+
+  @override
+  String toString() => raw.toString();
+}
diff --git a/packages/client_composition/lib/src/model/supported_language.dart b/packages/client_composition/lib/src/model/supported_language.dart
new file mode 100644
index 0000000..8f234fb
--- /dev/null
+++ b/packages/client_composition/lib/src/model/supported_language.dart
@@ -0,0 +1,91 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+import 'package:json_annotation/json_annotation.dart';
+
+/// ISO code for a supported language.
+@JsonEnum(valueField: 'raw')
+enum SupportedLanguage {
+  af(r'af'),
+  ar(r'ar'),
+  az(r'az'),
+  bg(r'bg'),
+  bn(r'bn'),
+  ca(r'ca'),
+  cs(r'cs'),
+  cy(r'cy'),
+  da(r'da'),
+  de(r'de'),
+  el(r'el'),
+  en(r'en'),
+  eo(r'eo'),
+  es(r'es'),
+  et(r'et'),
+  eu(r'eu'),
+  fa(r'fa'),
+  fi(r'fi'),
+  fo(r'fo'),
+  fr(r'fr'),
+  ga(r'ga'),
+  gl(r'gl'),
+  he(r'he'),
+  hi(r'hi'),
+  hu(r'hu'),
+  hy(r'hy'),
+  id(r'id'),
+  is_(r'is'),
+  it(r'it'),
+  ja(r'ja'),
+  ka(r'ka'),
+  kk(r'kk'),
+  ko(r'ko'),
+  ku(r'ku'),
+  ky(r'ky'),
+  lt(r'lt'),
+  lv(r'lv'),
+  mi(r'mi'),
+  mn(r'mn'),
+  mr(r'mr'),
+  ms(r'ms'),
+  mt(r'mt'),
+  nb(r'nb'),
+  nl(r'nl'),
+  no(r'no'),
+  ns(r'ns'),
+  pl(r'pl'),
+  ps(r'ps'),
+  pt(r'pt'),
+  ptBr(r'pt-br'),
+  qu(r'qu'),
+  ro(r'ro'),
+  ru(r'ru'),
+  sk(r'sk'),
+  sq(r'sq'),
+  sv(r'sv'),
+  sw(r'sw'),
+  ta(r'ta'),
+  te(r'te'),
+  th(r'th'),
+  tl(r'tl'),
+  tn(r'tn'),
+  tr(r'tr'),
+  tt(r'tt'),
+  uk(r'uk'),
+  ur(r'ur'),
+  uz(r'uz'),
+  zh(r'zh');
+
+  const SupportedLanguage(this.raw);
+  final dynamic raw;
+
+  dynamic toJson() => raw;
+
+  static SupportedLanguage fromJson(dynamic json) {
+    for (final value in values) {
+      if (value.raw == json) return value;
+    }
+    throw ArgumentError.value(json, "raw", "No enum value with that value");
+  }
+
+  @override
+  String toString() => raw.toString();
+}
diff --git a/packages/client_composition/lib/src/model/value.dart b/packages/client_composition/lib/src/model/value.dart
new file mode 100644
index 0000000..0c0d85a
--- /dev/null
+++ b/packages/client_composition/lib/src/model/value.dart
@@ -0,0 +1,48 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+import 'package:algolia_client_composition/src/model/sort_remaining_by.dart';
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'value.g.dart';
+
+@JsonSerializable()
+final class Value {
+  /// Returns a new [Value] instance.
+  const Value({
+    this.order,
+    this.sortRemainingBy,
+    this.hide,
+  });
+
+  /// Explicit order of facets or facet values.  This setting lets you always show specific facets or facet values at the top of the list.
+  @JsonKey(name: r'order')
+  final List<String>? order;
+
+  @JsonKey(name: r'sortRemainingBy')
+  final SortRemainingBy? sortRemainingBy;
+
+  /// Hide facet values.
+  @JsonKey(name: r'hide')
+  final List<String>? hide;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is Value &&
+          other.order == order &&
+          other.sortRemainingBy == sortRemainingBy &&
+          other.hide == hide;
+
+  @override
+  int get hashCode => order.hashCode + sortRemainingBy.hashCode + hide.hashCode;
+
+  factory Value.fromJson(Map<String, dynamic> json) => _$ValueFromJson(json);
+
+  Map<String, dynamic> toJson() => _$ValueToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/value.g.dart b/packages/client_composition/lib/src/model/value.g.dart
new file mode 100644
index 0000000..f7ab574
--- /dev/null
+++ b/packages/client_composition/lib/src/model/value.g.dart
@@ -0,0 +1,36 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'value.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+Value _$ValueFromJson(Map<String, dynamic> json) => $checkedCreate(
+      'Value',
+      json,
+      ($checkedConvert) {
+        final val = Value(
+          order: $checkedConvert('order',
+              (v) => (v as List<dynamic>?)?.map((e) => e as String).toList()),
+          sortRemainingBy: $checkedConvert('sortRemainingBy',
+              (v) => $enumDecodeNullable(_$SortRemainingByEnumMap, v)),
+          hide: $checkedConvert('hide',
+              (v) => (v as List<dynamic>?)?.map((e) => e as String).toList()),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$ValueToJson(Value instance) => <String, dynamic>{
+      if (instance.order case final value?) 'order': value,
+      if (instance.sortRemainingBy?.toJson() case final value?)
+        'sortRemainingBy': value,
+      if (instance.hide case final value?) 'hide': value,
+    };
+
+const _$SortRemainingByEnumMap = {
+  SortRemainingBy.count: 'count',
+  SortRemainingBy.alpha: 'alpha',
+  SortRemainingBy.hidden: 'hidden',
+};
diff --git a/packages/client_composition/lib/src/model/widgets.dart b/packages/client_composition/lib/src/model/widgets.dart
new file mode 100644
index 0000000..5e1fb5a
--- /dev/null
+++ b/packages/client_composition/lib/src/model/widgets.dart
@@ -0,0 +1,36 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+// ignore_for_file: unused_element
+import 'package:algolia_client_composition/src/model/banner.dart';
+
+import 'package:json_annotation/json_annotation.dart';
+
+part 'widgets.g.dart';
+
+@JsonSerializable()
+final class Widgets {
+  /// Returns a new [Widgets] instance.
+  const Widgets({
+    this.banners,
+  });
+
+  /// Banners defined in the Merchandising Studio for a given search.
+  @JsonKey(name: r'banners')
+  final List<Banner>? banners;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) || other is Widgets && other.banners == banners;
+
+  @override
+  int get hashCode => banners.hashCode;
+
+  factory Widgets.fromJson(Map<String, dynamic> json) =>
+      _$WidgetsFromJson(json);
+
+  Map<String, dynamic> toJson() => _$WidgetsToJson(this);
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/packages/client_composition/lib/src/model/widgets.g.dart b/packages/client_composition/lib/src/model/widgets.g.dart
new file mode 100644
index 0000000..90e9d26
--- /dev/null
+++ b/packages/client_composition/lib/src/model/widgets.g.dart
@@ -0,0 +1,27 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'widgets.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+Widgets _$WidgetsFromJson(Map<String, dynamic> json) => $checkedCreate(
+      'Widgets',
+      json,
+      ($checkedConvert) {
+        final val = Widgets(
+          banners: $checkedConvert(
+              'banners',
+              (v) => (v as List<dynamic>?)
+                  ?.map((e) => Banner.fromJson(e as Map<String, dynamic>))
+                  .toList()),
+        );
+        return val;
+      },
+    );
+
+Map<String, dynamic> _$WidgetsToJson(Widgets instance) => <String, dynamic>{
+      if (instance.banners?.map((e) => e.toJson()).toList() case final value?)
+        'banners': value,
+    };
diff --git a/packages/client_composition/lib/src/version.dart b/packages/client_composition/lib/src/version.dart
new file mode 100644
index 0000000..150a8d6
--- /dev/null
+++ b/packages/client_composition/lib/src/version.dart
@@ -0,0 +1,2 @@
+/// Current package version
+const packageVersion = '1.29.0';
diff --git a/packages/client_composition/pubspec.yaml b/packages/client_composition/pubspec.yaml
new file mode 100644
index 0000000..b1a11c9
--- /dev/null
+++ b/packages/client_composition/pubspec.yaml
@@ -0,0 +1,23 @@
+name: algolia_client_composition
+version: 1.29.0
+description: A sub-package of the AlgoliaSearch library, offering composition-specific functionalities for enhanced search and discovery in Dart/Flutter apps.
+homepage: https://www.algolia.com/doc/
+repository: https://github.com/algolia/algoliasearch-client-dart/tree/main/packages/client_composition
+topics:
+  - search
+  - discovery
+
+environment:
+  sdk: '>=3.0.0 <4.0.0'
+
+dependencies:
+  algolia_client_core: ^1.29.0
+  json_annotation: ^4.8.1
+  collection: ^1.17.1
+
+dev_dependencies:
+  build_runner: ^2.4.4
+  json_serializable: ^6.7.0
+  lints: ^5.0.0
+  logging: ^1.2.0
+  test: ^1.25.8
\ No newline at end of file
diff --git a/packages/client_insights/pubspec.yaml b/packages/client_insights/pubspec.yaml
index 40f5a56..0391e08 100644
--- a/packages/client_insights/pubspec.yaml
+++ b/packages/client_insights/pubspec.yaml
@@ -20,4 +20,4 @@ dev_dependencies:
   json_serializable: ^6.7.0
   lints: ^5.0.0
   logging: ^1.2.0
-  test: ^1.25.8
+  test: ^1.25.8
\ No newline at end of file
diff --git a/packages/client_recommend/pubspec.yaml b/packages/client_recommend/pubspec.yaml
index 25aff1a..8942cfb 100644
--- a/packages/client_recommend/pubspec.yaml
+++ b/packages/client_recommend/pubspec.yaml
@@ -20,4 +20,4 @@ dev_dependencies:
   json_serializable: ^6.7.0
   lints: ^5.0.0
   logging: ^1.2.0
-  test: ^1.25.8
+  test: ^1.25.8
\ No newline at end of file
diff --git a/packages/client_search/pubspec.yaml b/packages/client_search/pubspec.yaml
index 2844ac7..2e63947 100644
--- a/packages/client_search/pubspec.yaml
+++ b/packages/client_search/pubspec.yaml
@@ -20,4 +20,4 @@ dev_dependencies:
   json_serializable: ^6.7.0
   lints: ^5.0.0
   logging: ^1.2.0
-  test: ^1.25.8
+  test: ^1.25.8
\ No newline at end of file