diff -pruN 9.1.1-2/.buildkite/Dockerfile 9.2.0-1/.buildkite/Dockerfile
--- 9.1.1-2/.buildkite/Dockerfile	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/.buildkite/Dockerfile	2025-10-28 16:50:53.000000000 +0000
@@ -1,4 +1,4 @@
-ARG PYTHON_VERSION=3.13
+ARG PYTHON_VERSION=3.14
 FROM python:${PYTHON_VERSION}
 
 # Default UID/GID to 1000
diff -pruN 9.1.1-2/.buildkite/functions/imports.sh 9.2.0-1/.buildkite/functions/imports.sh
--- 9.1.1-2/.buildkite/functions/imports.sh	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/.buildkite/functions/imports.sh	2025-10-28 16:50:53.000000000 +0000
@@ -43,7 +43,7 @@ if [[ -z $es_node_name ]]; then
 
 fi
 
-  export script_path=$(dirname $(realpath -s $0))
+  export script_path=$(dirname $(realpath $0))
   source $script_path/functions/cleanup.sh
   source $script_path/functions/wait-for-container.sh
   trap "cleanup_trap ${network_name}" EXIT
diff -pruN 9.1.1-2/.buildkite/pipeline.yml 9.2.0-1/.buildkite/pipeline.yml
--- 9.1.1-2/.buildkite/pipeline.yml	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/.buildkite/pipeline.yml	2025-10-28 16:50:53.000000000 +0000
@@ -5,17 +5,17 @@ steps:
     env:
       PYTHON_VERSION: "{{ matrix.python }}"
       TEST_SUITE: "platinum"
-      STACK_VERSION: "9.1.0-SNAPSHOT"
+      STACK_VERSION: "9.2.0-SNAPSHOT"
       PYTHON_CONNECTION_CLASS: "{{ matrix.connection }}"
       NOX_SESSION: "{{ matrix.nox_session }}"
     matrix:
       setup:
         python:
-          - "3.9"
           - "3.10"
           - "3.11"
           - "3.12"
           - "3.13"
+          - "3.14"
         connection:
           - "urllib3"
           - "requests"
@@ -23,11 +23,11 @@ steps:
           - "test"
       adjustments:
         - with:
-            python: "3.9"
+            python: "3.10"
             connection: "urllib3"
             nox_session: "test_otel"
         - with:
-            python: "3.13"
+            python: "3.14"
             connection: "urllib3"
             nox_session: "test_otel"
     command: ./.buildkite/run-tests
diff -pruN 9.1.1-2/.buildkite/run-elasticsearch.sh 9.2.0-1/.buildkite/run-elasticsearch.sh
--- 9.1.1-2/.buildkite/run-elasticsearch.sh	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/.buildkite/run-elasticsearch.sh	2025-10-28 16:50:53.000000000 +0000
@@ -21,7 +21,7 @@
 # - Moved ELASTIC_PASSWORD and xpack.security.enabled to the base arguments for "Security On by default"
 # - Use https only when TEST_SUITE is "platinum", when "free" use http
 
-script_path=$(dirname $(realpath -s $0))
+script_path=$(dirname $(realpath $0))
 source $script_path/functions/imports.sh
 set -euo pipefail
 
diff -pruN 9.1.1-2/.buildkite/run-tests 9.2.0-1/.buildkite/run-tests
--- 9.1.1-2/.buildkite/run-tests	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/.buildkite/run-tests	2025-10-28 16:50:53.000000000 +0000
@@ -7,10 +7,10 @@
 # Default environment variables
 export STACK_VERSION="${STACK_VERSION:=8.0.0-SNAPSHOT}"
 export TEST_SUITE="${TEST_SUITE:=platinum}"
-export PYTHON_VERSION="${PYTHON_VERSION:=3.13}"
+export PYTHON_VERSION="${PYTHON_VERSION:=3.14}"
 export PYTHON_CONNECTION_CLASS="${PYTHON_CONNECTION_CLASS:=urllib3}"
 
-script_path=$(dirname $(realpath -s $0))
+script_path=$(dirname $(realpath $0))
 source $script_path/functions/imports.sh
 set -euo pipefail
 
diff -pruN 9.1.1-2/.github/workflows/ci.yml 9.2.0-1/.github/workflows/ci.yml
--- 9.1.1-2/.github/workflows/ci.yml	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/.github/workflows/ci.yml	2025-10-28 16:50:53.000000000 +0000
@@ -8,7 +8,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - name: Checkout Repository
-        uses: actions/checkout@v4
+        uses: actions/checkout@v5
       - name: Set up Python 3.x
         uses: actions/setup-python@v5
         with:
@@ -23,7 +23,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - name: Checkout Repository
-        uses: actions/checkout@v4
+        uses: actions/checkout@v5
       - name: Set up Python 3.x
         uses: actions/setup-python@v5
         with:
@@ -38,7 +38,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
+        python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
         nox-session: [""]
         runs-on: ["ubuntu-latest"]
 
@@ -47,7 +47,7 @@ jobs:
     continue-on-error: false
     steps:
       - name: Checkout Repository
-        uses: actions/checkout@v4
+        uses: actions/checkout@v5
       - name: Set Up Python - ${{ matrix.python-version }}
         uses: actions/setup-python@v5
         with:
diff -pruN 9.1.1-2/CONTRIBUTING.md 9.2.0-1/CONTRIBUTING.md
--- 9.1.1-2/CONTRIBUTING.md	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/CONTRIBUTING.md	2025-10-28 16:50:53.000000000 +0000
@@ -17,7 +17,7 @@ found at `.buildkite/run-elasticsearch.s
 
 There are several environment variables that control integration tests:
 
-- `PYTHON_VERSION`: Version of Python to use, defaults to `3.9`
+- `PYTHON_VERSION`: Version of Python to use, defaults to `3.14`
 - `PYTHON_CONNECTION_CLASS`: Connection class to use, defaults to `Urllib3HttpConnection`
 - `STACK_VERSION`: Version of Elasticsearch to use. These should be
   the same as tags of `docker.elastic.co/elasticsearch/elasticsearch`
diff -pruN 9.1.1-2/README.md 9.2.0-1/README.md
--- 9.1.1-2/README.md	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/README.md	2025-10-28 16:50:53.000000000 +0000
@@ -90,6 +90,24 @@ Documentation for the client is [availab
 [Read the Docs]: https://elasticsearch-py.readthedocs.io
 
 
+## Try Elasticsearch and Kibana locally
+
+If you want to try Elasticsearch and Kibana locally, you can run the following command:
+
+```bash
+curl -fsSL https://elastic.co/start-local | sh
+```
+
+This will run Elasticsearch at [http://localhost:9200](http://localhost:9200) and Kibana at [http://localhost:5601](http://localhost:5601).
+
+More information is available [here](https://www.elastic.co/guide/en/elasticsearch/reference/current/run-elasticsearch-locally.html).
+
+
+## Contributing
+
+See [CONTRIBUTING.md](./CONTRIBUTING.md)
+
+
 ## License
 
 This software is licensed under the [Apache License 2.0](./LICENSE). See [NOTICE](./NOTICE).
diff -pruN 9.1.1-2/debian/changelog 9.2.0-1/debian/changelog
--- 9.1.1-2/debian/changelog	2025-10-02 11:42:22.000000000 +0000
+++ 9.2.0-1/debian/changelog	2025-10-29 11:51:11.000000000 +0000
@@ -1,3 +1,13 @@
+python-elasticsearch (9.2.0-1) unstable; urgency=medium
+
+  * New upstream version 9.2.0
+  * d/watch: Convert to version 5
+  * d/control: Update BD
+  * d/rules: Enable test_vectors, 
+    since sentence_transformers no longer has a dependency.
+
+ -- Karsten Schöke <karsten.schoeke@geobasis-bb.de>  Wed, 29 Oct 2025 12:51:11 +0100
+
 python-elasticsearch (9.1.1-2) unstable; urgency=medium
 
   * change link to elasticsearch9
diff -pruN 9.1.1-2/debian/control 9.2.0-1/debian/control
--- 9.1.1-2/debian/control	2025-10-01 11:03:06.000000000 +0000
+++ 9.2.0-1/debian/control	2025-10-29 10:14:03.000000000 +0000
@@ -13,17 +13,20 @@ Build-Depends: debhelper-compat (= 13),
                python-elastic-transport-doc <!nodoc>,
                python3-aiohttp <!nocheck>,
                python3-all,
+               python3-anyio,
                python3-dateutil <!nocheck>,
                python3-doc <!nodoc>,
                python3-elastic-transport,
                python3-hatchling,
-               python3-nltk <!nocheck>,
                python3-orjson <!nocheck>,
+               python3-pydantic <!nocheck>,
                python3-pytest <!nocheck>,
                python3-pytest-asyncio <!nocheck>,
                python3-setuptools,
+               python3-sniffio,
                python3-sphinx <!nodoc>,
                python3-sphinx-rtd-theme <!nodoc>,
+               python3-trio <!nodoc>,
                python3-typing-extensions,
                python3-pytz <!nocheck>,
                python3-yaml <!nocheck>,
diff -pruN 9.1.1-2/debian/rules 9.2.0-1/debian/rules
--- 9.1.1-2/debian/rules	2025-10-01 11:03:06.000000000 +0000
+++ 9.2.0-1/debian/rules	2025-10-29 11:44:06.000000000 +0000
@@ -5,10 +5,7 @@
 
 export PYBUILD_NAME := elasticsearch
 
-# disable the vectors tests because sentence_transformers is missing in Debian
-export PYBUILD_TEST_ARGS = {dir}/test_elasticsearch \
- --ignore={dir}/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_vectors.py \
- --ignore={dir}/test_elasticsearch/test_dsl/test_integration/test_examples/_sync/test_vectors.py
+export PYBUILD_TEST_ARGS = {dir}/test_elasticsearch
 
 %:
 	dh $@ --with sphinxdoc --buildsystem=pybuild
diff -pruN 9.1.1-2/debian/watch 9.2.0-1/debian/watch
--- 9.1.1-2/debian/watch	2025-10-01 11:03:06.000000000 +0000
+++ 9.2.0-1/debian/watch	2025-10-29 11:43:10.000000000 +0000
@@ -1,8 +1,8 @@
-version=4
+Version: 5
 
-opts="mode=git, \
-      compression=gz, \
-      uversionmangle=s/(\d)[_\.\-\+]?((RC|rc|pre|dev|beta|alpha)\.?\d*)$/$1~$2/, \
-      dversionmangle=s/\+ds(\.?\d+)?$//" \
-https://github.com/elastic/elasticsearch-py.git \
-      refs/tags/@ANY_VERSION@
+Source: https://github.com/elastic/elasticsearch-py.git
+Matching-Pattern: refs/tags/@ANY_VERSION@
+Compression: gz
+Dversionmangle: s/\+ds(\.?\d+)?$//
+Mode: git
+Uversionmangle: s/(\d)[_\.\-\+]?((RC|rc|pre|dev|beta|alpha)\.?\d*)$/$1~$2/
diff -pruN 9.1.1-2/docs/reference/async.md 9.2.0-1/docs/reference/async.md
--- 9.1.1-2/docs/reference/async.md	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/docs/reference/async.md	2025-10-28 16:50:53.000000000 +0000
@@ -50,6 +50,27 @@ All APIs that are available under the sy
 
 See also the [Using OpenTelemetry](/reference/opentelemetry.md) page.
 
+## Trio support
+
+If you prefer using Trio instead of asyncio to take advantage of its better structured concurrency support, you can use the HTTPX async node which supports Trio out of the box.
+
+```python
+import trio
+from elasticsearch import AsyncElasticsearch
+
+client = AsyncElasticsearch(
+    "https://...",
+    api_key="...",
+    node_class="httpxasync")
+
+async def main():
+    resp = await client.info()
+    print(resp.body)
+
+trio.run(main)
+```
+
+The one limitation of Trio support is that it does not currently support node sniffing, which was not implemented with structured concurrency in mind.
 
 ## Frequently Asked Questions [_frequently_asked_questions]
 
diff -pruN 9.1.1-2/docs/reference/configuration.md 9.2.0-1/docs/reference/configuration.md
--- 9.1.1-2/docs/reference/configuration.md	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/docs/reference/configuration.md	2025-10-28 16:50:53.000000000 +0000
@@ -1,9 +1,10 @@
 ---
 mapped_pages:
   - https://www.elastic.co/guide/en/elasticsearch/client/python-api/current/config.html
+navigation_title: Configuration
 ---
 
-# Configuration [config]
+# Python client configuration for {{es}} [config]
 
 This page contains information about the most important configuration options of the Python {{es}} client.
 
diff -pruN 9.1.1-2/docs/reference/connecting.md 9.2.0-1/docs/reference/connecting.md
--- 9.1.1-2/docs/reference/connecting.md	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/docs/reference/connecting.md	2025-10-28 16:50:53.000000000 +0000
@@ -277,13 +277,6 @@ client = Elasticsearch(
 ```
 
 
-## Enabling the Compatibility Mode [compatibility-mode]
-
-The {{es}} server version 8.0 is introducing a new compatibility mode that allows you a smoother upgrade experience from 7 to 8. In a nutshell, you can use the latest 7.x Python {{es}} {{es}} client with an 8.x {{es}} server, giving more room to coordinate the upgrade of your codebase to the next major version.
-
-If you want to leverage this functionality, please make sure that you are using the latest 7.x Python {{es}} client and set the environment variable `ELASTIC_CLIENT_APIVERSIONING` to `true`. The client is handling the rest internally. For every 8.0 and beyond Python {{es}} client, you’re all set! The compatibility mode is enabled by default.
-
-
 ## Using the Client in a Function-as-a-Service Environment [connecting-faas]
 
 This section illustrates the best practices for leveraging the {{es}} client in a Function-as-a-Service (FaaS) environment.
diff -pruN 9.1.1-2/docs/reference/dsl_configuration.md 9.2.0-1/docs/reference/dsl_configuration.md
--- 9.1.1-2/docs/reference/dsl_configuration.md	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/docs/reference/dsl_configuration.md	2025-10-28 16:50:53.000000000 +0000
@@ -1,9 +1,10 @@
 ---
 mapped_pages:
   - https://www.elastic.co/guide/en/elasticsearch/client/python-api/current/_configuration.html
+navigation_title: Configuration
 ---
 
-# Configuration [_configuration]
+# Python DSL configuration for {{es}} [_configuration]
 
 There are several ways to configure connections for the library. The easiest and most useful approach is to define one default connection that can be used every time an API call is made without explicitly passing in other connections.
 
diff -pruN 9.1.1-2/docs/reference/dsl_examples.md 9.2.0-1/docs/reference/dsl_examples.md
--- 9.1.1-2/docs/reference/dsl_examples.md	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/docs/reference/dsl_examples.md	2025-10-28 16:50:53.000000000 +0000
@@ -1,9 +1,10 @@
 ---
 mapped_pages:
   - https://www.elastic.co/guide/en/elasticsearch/client/python-api/current/_examples.html
+navigation_title: Examples
 ---
 
-# Examples [_examples]
+# {{es}} Python DSL examples [_examples]
 
 Please see the [DSL examples](https://github.com/elastic/elasticsearch-py/tree/master/examples/dsl) directory to see some complex examples using the DSL module.
 
diff -pruN 9.1.1-2/docs/reference/dsl_how_to_guides.md 9.2.0-1/docs/reference/dsl_how_to_guides.md
--- 9.1.1-2/docs/reference/dsl_how_to_guides.md	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/docs/reference/dsl_how_to_guides.md	2025-10-28 16:50:53.000000000 +0000
@@ -630,7 +630,7 @@ For more comprehensive examples have a l
 
 ### Document [doc_type]
 
-If you want to create a model-like wrapper around your documents, use the `Document` class. It can also be used to create all the necessary mappings and settings in elasticsearch (see `life-cycle` for details).
+If you want to create a model-like wrapper around your documents, use the `Document` class (or the equivalent `AsyncDocument` for asynchronous applications). It can also be used to create all the necessary mappings and settings in Elasticsearch (see [Document life cycle](#life-cycle) below for details).
 
 ```python
 from datetime import datetime
@@ -721,9 +721,19 @@ class Post(Document):
     published: bool                 # same as published = Boolean(required=True)
 ```
 
-It is important to note that when using `Field` subclasses such as `Text`, `Date` and `Boolean`, they must be given in the right-side of an assignment, as shown in examples above. Using these classes as type hints will result in errors.
+::::{note}
+When using `Field` subclasses such as `Text`, `Date` and `Boolean` to define attributes, these classes must be given in the right-hand side.
+
+```python
+class Post(Document):
+    title = Text()  # correct
+    subtitle: Text  # incorrect
+```
+
+Using a `Field` subclass as a Python type hint will result in errors.
+::::
 
-Python types are mapped to their corresponding field types according to the following table:
+Python types are mapped to their corresponding `Field` types according to the following table:
 
 | Python type | DSL field |
 | --- | --- |
@@ -735,7 +745,7 @@ Python types are mapped to their corresp
 | `datetime` | `Date(required=True)` |
 | `date` | `Date(format="yyyy-MM-dd", required=True)` |
 
-To type a field as optional, the standard `Optional` modifier from the Python `typing` package can be used. When using Python 3.10 or newer, "pipe" syntax can also be used, by adding `| None` to a type. The `List` modifier can be added to a field to convert it to an array, similar to using the `multi=True` argument on the field object.
+To type a field as optional, the standard `Optional` modifier from the Python `typing` package can be used. When using Python 3.10 or newer, "pipe" syntax can also be used, by adding `| None` to a type. The `List` modifier can be added to a field to convert it to an array, similar to using the `multi=True` argument on the `Field` object.
 
 ```python
 from typing import Optional, List
@@ -763,7 +773,7 @@ class Post(Document):
     comments: List[Comment]  # same as comments = Nested(Comment, required=True)
 ```
 
-Unfortunately it is impossible to have Python type hints that uniquely identify every possible Elasticsearch field type. To choose a field type that is different than the one that is assigned according to the table above, the desired field instance can be added explicitly as a right-side assignment in the field declaration. The next example creates a field that is typed as `Optional[str]`, but is mapped to `Keyword` instead of `Text`:
+Unfortunately it is impossible to have Python type hints that uniquely identify every possible Elasticsearch `Field` type. To choose a type that is different than the one that is assigned according to the table above, the desired `Field` instance can be added explicitly as a right-side assignment in the field declaration. The next example creates a field that is typed as `Optional[str]`, but is mapped to `Keyword` instead of `Text`:
 
 ```python
 class MyDocument(Document):
@@ -787,7 +797,7 @@ class MyDocument(Document):
     category: str = mapped_field(Keyword(), default="general")
 ```
 
-When using the `mapped_field()` wrapper function, an explicit field type instance can be passed as a first positional argument, as the `category` field does in the example above.
+The `mapped_field()` wrapper function can optionally be given an explicit field type instance as a first positional argument, as the `category` field does in the example above to be defined as `Keyword` instead of the `Text` default.
 
 Static type checkers such as [mypy](https://mypy-lang.org/) and [pyright](https://github.com/microsoft/pyright) can use the type hints and the dataclass-specific options added to the `mapped_field()` function to improve type inference and provide better real-time code completion and suggestions in IDEs.
 
@@ -829,7 +839,7 @@ s = MyDocument.search().sort(-MyDocument
 
 When specifying sorting order, the `+` and `-` unary operators can be used on the class field attributes to indicate ascending and descending order.
 
-Finally, the `ClassVar` annotation can be used to define a regular class attribute that should not be mapped to the Elasticsearch index:
+Finally, it is also possible to define class attributes and request that they are ignored when building the Elasticsearch mapping. One way is to type attributes with the `ClassVar` annotation. Alternatively, the `mapped_field()` wrapper function accepts an `exclude` argument that can be set to `True`:
 
 ```python
 from typing import ClassVar
@@ -837,9 +847,9 @@ from typing import ClassVar
 class MyDoc(Document):
     title: M[str] created_at: M[datetime] = mapped_field(default_factory=datetime.now)
     my_var: ClassVar[str]  # regular class variable, ignored by Elasticsearch
+    anoter_custom_var: int = mapped_field(exclude=True)  # also ignored by Elasticsearch
 ```
 
-
 #### Note on dates [_note_on_dates]
 
 The DSL module will always respect the timezone information (or lack thereof) on the `datetime` objects passed in or stored in Elasticsearch. Elasticsearch itself interprets all datetimes with no timezone information as `UTC`. If you wish to reflect this in your python code, you can specify `default_timezone` when instantiating a `Date` field:
@@ -878,7 +888,7 @@ first.meta.id = 47
 first.save()
 ```
 
-All the metadata fields (`id`, `routing`, `index` etc) can be accessed (and set) via a `meta` attribute or directly using the underscored variant:
+All the metadata fields (`id`, `routing`, `index`, etc.) can be accessed (and set) via a `meta` attribute or directly using the underscored variant:
 
 ```python
 post = Post(meta={'id': 42})
@@ -917,7 +927,7 @@ first = Post.get(id=42)
 first.update(published=True, published_by='me')
 ```
 
-In case you wish to use a `painless` script to perform the update you can pass in the script string as `script` or the `id` of a [stored script](docs-content://explore-analyze/scripting/modules-scripting-using.md#script-stored-scripts) via `script_id`. All additional keyword arguments to the `update` method will then be passed in as parameters of the script. The document will not be updated in place.
+In case you wish to use a `painless` script to perform the update you can pass in the script string as `script` or the `id` of a [stored script](docs-content://explore-analyze/scripting/modules-scripting-using.md) via `script_id`. All additional keyword arguments to the `update` method will then be passed in as parameters of the script. The document will not be updated in place.
 
 ```python
 # retrieve the document
@@ -961,12 +971,111 @@ first = Post.get(id=42)
 first.delete()
 ```
 
+#### Integration with Pydantic models
+
+::::{warning}
+This functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features.
+::::
+
+::::{note}
+This feature is available in the Python Elasticsearch client starting with release 9.2.0.
+::::
+
+Applications that define their data models using [Pydantic](https://docs.pydantic.dev/latest/) can combine these
+models with Elasticsearch DSL annotations. To take advantage of this option, Pydantic's `BaseModel` base class
+needs to be replaced with `BaseESModel` (or `AsyncBaseESModel` for asynchronous applications), and then the model
+can include type annotations for Pydantic and Elasticsearch both, as demonstrated in the following example:
+
+```python
+from typing import Annotated
+from pydantic import Field
+from elasticsearch import dsl
+from elasticsearch.dsl.pydantic import BaseESModel
+
+class Quote(BaseESModel):
+    quote: str
+    author: Annotated[str, dsl.Keyword()]
+    tags: Annotated[list[str], dsl.Keyword(normalizer="lowercase")]
+    embedding: Annotated[list[float], dsl.DenseVector()] = Field(init=False, default=[])
+
+    class Index:
+        name = "quotes"
+```
+
+In this example, the `quote` attribute is annotated with a `str` type hint. Both Pydantic and Elasticsearch use this 
+annotation.
+
+The `author` and `tags` attributes have a Python type hint and an Elasticsearch annotation, both wrapped with
+Python's `typing.Annotated`. When using the `BaseESModel` class, the typing information intended for Elasticsearch needs
+to be defined inside `Annotated`.
+
+The `embedding` attribute includes a base Python type and an Elasticsearch annotation in the same format as the
+other fields, but it adds Pydantic's `Field` definition as a right-hand side assignment.
+
+Finally, any other items that need to be defined for the Elasticsearch document class, such as `class Index` and
+`class Meta` entries (discussed later), can be added as well.
+
+The next example demonstrates how to define `Object` and `Nested` fields:
+
+```python
+from typing import Annotated
+from pydantic import BaseModel, Field
+from elasticsearch import dsl
+from elasticsearch.dsl.pydantic import BaseESModel
+
+class Phone(BaseModel):
+    type: Annotated[str, dsl.Keyword()] = Field(default="Home")
+    number: str
+
+class Person(BaseESModel):
+    name: str
+    main_phone: Phone          # same as Object(Phone)
+    other_phones: list[Phone]  # same as Nested(Phone)
+
+    class Index:
+        name = "people"
+```
+
+Note that inner classes do not need to be defined with a custom base class; these should be standard Pydantic model 
+classes. The attributes defined in these classes can include Elasticsearch annotations, as long as they are given
+in an `Annotated` type hint.
+
+All model classes that are created as described in this section function like normal Pydantic models and can be used
+anywhere standard Pydantic models are used, but they have some added attributes:
+
+- `_doc`: a class attribute that is a dynamically generated `Document` class to use with the Elasticsearch index.
+- `meta`: an attribute added to all models that includes Elasticsearch document metadata items such as `id`, `score`, etc.
+- `to_doc()`: a method that converts the Pydantic model to an Elasticsearch document.
+- `from_doc()`: a class method that accepts an Elasticsearch document as an argument and returns an equivalent Pydantic model.
+
+These are demonstrated in the examples below:
+
+```python
+# create a Pydantic model
+quote = Quote(
+    quote="An unexamined life is not worth living.",
+    author="Socrates",
+    tags=["phillosophy"]
+)
+
+# save the model to the Elasticsearch index
+quote.to_doc().save()
+
+# get a document from the Elasticsearch index as a Pydantic model
+quote = Quote.from_doc(Quote._doc.get(id=42))
+
+# run a search and print the Pydantic models
+s = Quote._doc.search().query(Match(Quote._doc.quote, "life"))
+for doc in s:
+    quote = Quote.from_doc(doc)
+    print(quote.meta.id, quote.meta.score, quote.quote)
+```
 
 #### Analysis [_analysis]
 
 To specify `analyzer` values for `Text` fields you can just use the name of the analyzer (as a string) and either rely on the analyzer being defined (like built-in analyzers) or define the analyzer yourself manually.
 
-Alternatively you can create your own analyzer and have the persistence layer handle its creation, from our example earlier:
+Alternatively, you can create your own analyzer and have the persistence layer handle its creation, from our example earlier:
 
 ```python
 from elasticsearch.dsl import analyzer, tokenizer
@@ -1555,6 +1664,12 @@ The DSL module supports async/await with
 $ python -m pip install "elasticsearch[async]"
 ```
 
+The DSL module also supports [Trio](https://trio.readthedocs.io/en/stable/) when using the Async HTTPX client. You do need to install Trio and HTTPX separately:
+
+```bash
+$ python -m pip install "elasticsearch trio httpx"
+```
+
 ### Connections [_connections]
 
 Use the `async_connections` module to manage your asynchronous connections.
@@ -1565,6 +1680,14 @@ from elasticsearch.dsl import async_conn
 async_connections.create_connection(hosts=['localhost'], timeout=20)
 ```
 
+If you're using Trio, you need to explicitly request the Async HTTP client:
+
+```python
+from elasticsearch.dsl import async_connections
+
+async_connections.create_connection(hosts=['localhost'], node_class="httpxasync")
+```
+
 All the options available in the `connections` module can be used with `async_connections`.
 
 #### How to avoid *Unclosed client session / connector* warnings on exit [_how_to_avoid_unclosed_client_session_connector_warnings_on_exit]
@@ -1576,8 +1699,6 @@ es = async_connections.get_connection()
 await es.close()
 ```
 
-
-
 ### Search DSL [_search_dsl]
 
 Use the `AsyncSearch` class to perform asynchronous searches.
@@ -1622,7 +1743,7 @@ for response in responses:
 
 ### Asynchronous Documents, Indexes, and more [_asynchronous_documents_indexes_and_more]
 
-The `Document`, `Index`, `IndexTemplate`, `Mapping`, `UpdateByQuery` and `FacetedSearch` classes all have asynchronous versions that use the same name with an `Async` prefix. These classes expose the same interfaces as the synchronous versions, but any methods that perform I/O are defined as coroutines.
+The `Document`, `BaseESModel`, `Index`, `IndexTemplate`, `Mapping`, `UpdateByQuery` and `FacetedSearch` classes all have asynchronous versions that use the same name with an `Async` prefix. These classes expose the same interfaces as the synchronous versions, but any methods that perform I/O are defined as coroutines.
 
 Auxiliary classes that do not perform I/O do not have asynchronous versions. The same classes can be used in synchronous and asynchronous applications.
 
diff -pruN 9.1.1-2/docs/reference/dsl_tutorials.md 9.2.0-1/docs/reference/dsl_tutorials.md
--- 9.1.1-2/docs/reference/dsl_tutorials.md	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/docs/reference/dsl_tutorials.md	2025-10-28 16:50:53.000000000 +0000
@@ -134,7 +134,7 @@ In this example you can see:
 * retrieving and saving the object into Elasticsearch
 * accessing the underlying client for other APIs
 
-You can see more in the `persistence` chapter.
+You can see more in the [persistence](dsl_how_to_guides.md#_persistence_2) chapter.
 
 
 ## Pre-built Faceted Search [_pre_built_faceted_search]
diff -pruN 9.1.1-2/docs/reference/examples.md 9.2.0-1/docs/reference/examples.md
--- 9.1.1-2/docs/reference/examples.md	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/docs/reference/examples.md	2025-10-28 16:50:53.000000000 +0000
@@ -1,9 +1,10 @@
 ---
 mapped_pages:
   - https://www.elastic.co/guide/en/elasticsearch/client/python-api/current/examples.html
+navigation_title: Examples
 ---
 
-# Examples [examples]
+# {{es}} Python client examples [examples]
 
 Below you can find examples of how to use the most frequently called APIs with the Python client.
 
diff -pruN 9.1.1-2/docs/reference/getting-started.md 9.2.0-1/docs/reference/getting-started.md
--- 9.1.1-2/docs/reference/getting-started.md	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/docs/reference/getting-started.md	2025-10-28 16:50:53.000000000 +0000
@@ -11,7 +11,7 @@ This page guides you through the install
 
 ### Requirements [_requirements]
 
-* [Python](https://www.python.org/) 3.9 or newer
+* [Python](https://www.python.org/) 3.10 or newer
 * [`pip`](https://pip.pypa.io/en/stable/), installed by default alongside Python
 
 
diff -pruN 9.1.1-2/docs/reference/index.md 9.2.0-1/docs/reference/index.md
--- 9.1.1-2/docs/reference/index.md	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/docs/reference/index.md	2025-10-28 16:50:53.000000000 +0000
@@ -69,8 +69,14 @@ Compatibility does not imply full featur
 
 {{es}} language clients are also _backward compatible_ across minor versions &mdash; with default distributions and without guarantees. 
 
+### Major version upgrades
+
 :::{tip}
 To upgrade to a new major version, first upgrade {{es}}, then upgrade the Python {{es}} client.
 :::
 
-If you need to work with multiple client versions, note that older versions are also released as `elasticsearch7` and `elasticsearch8`.
+Since version 8.0, the {{es}} server supports a compatibility mode that allows smoother upgrade experiences. In a nutshell, this makes it possible to upgrade the {{es}} server to the next major version, while continuing to use the same client. This gives more room to coordinate the upgrade of your codebase to the next major version.
+
+For example, to upgrade a system that uses {{es}} 8.x you can upgrade the {{es}} server to 9.x first, and the 8.x Python {{es}} client will continue to work (aside from any breaking changes, which should be listed in the server release notes). You can continue using the 8.x client during the server migration, and only upgrade it once the server migration is complete. The process is described in detail in the [REST API compatibility workflow](https://www.elastic.co/docs/reference/elasticsearch/rest-apis/compatibility#_rest_api_compatibility_workflow) section of the {{es}} documentation.
+
+If you need to work with multiple client versions, note that older versions are also released with the `elasticsearch8` and `elasticsearch9` package names so that they can be installed together.
diff -pruN 9.1.1-2/docs/release-notes/index.md 9.2.0-1/docs/release-notes/index.md
--- 9.1.1-2/docs/release-notes/index.md	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/docs/release-notes/index.md	2025-10-28 16:50:53.000000000 +0000
@@ -18,19 +18,69 @@ To check for security updates, go to [Se
 % *
 
 % ### Fixes [elasticsearch-python-client-next-fixes]
+## 9.2.0 (2025-10-28)
+
+### Enhancements
+
+* Support Trio when using the `HTTPX <https://www.python-httpx.org/>`_ async client ([#3089](https://github.com/elastic/elasticsearch-py/pull/3089))
+* Pydantic integration for the DSL module ([#3086](https://github.com/elastic/elasticsearch-py/pull/3086))
+* Add `flush_after_seconds` option to `streaming_bulk()` ([#3064](https://github.com/elastic/elasticsearch-py/pull/3064))
+* Add `TS`, `FUSE` and `INLINE STATS` commands to the ES|QL query builder ([#3096](https://github.com/elastic/elasticsearch-py/pull/3096))
+
+### Bug Fixes
+
+* DSL: support passing inner documents as `AttrDict` instances ([#3080](https://github.com/elastic/elasticsearch-py/pull/3080))
+* DSL: add some recently added field classes as top-level exports for the package ([#3078](https://github.com/elastic/elasticsearch-py/pull/3078))
+
+### API
+
+- Add `streams` namespace with `streams.logs_disable`, `streams.logs_enable`, `streams.status` APIs
+- Add `inference.contextualai` API
+- Add `security.get_stats` API
+- Add `bytes` and `time` parameters to various APIs in the `cat` namespace.
+- Add `include_execution_metadata` parameter to `esql.async_query` and `esql.query` APIs
+- Add `index_template` parameter to `indices.simulate_index_template` API
+- Add `input_type` parameter to `inference.text_embedding` API
+- Add `field_access_pattern` parameter to `ingest.put_pipeline` API
+- Removed unsupported `size` parameter from `reindex` API
+
+#### Serverless-specific
+
+- Add `project` namespace with `project.tags` API
+- Add `project_routing` parameter to `count`, `field_caps`, `msearch`, `msearch_template`, `open_point_in_time`, `search`, `search_mvt`, `search_template`, `async_search.submit`, `cat.count`, `eql.search`, `indices.resolve_index`, `sql.query` APIs
+
+### DSL
+
+- New `CartesianBounds`, `CartesianCentroid`, `ChangePoint` aggregations
+- Add `p_value` parameter to `SignificantTerms` aggregation
+- Add `fields` parameter to `SemanticText` field
+- Add `visit_percentage` parameter to `Knn` query
+- Add `on_disk_rescore` field to `DenseVectorIndexOptions` type
+- Add `sparse_vector` field to `SemanticTextIndexOptions` type
+
+### Other
+
+* Add 3.14 to CI builds ([#3103](https://github.com/elastic/elasticsearch-py/pull/3103))
+* Drop Python 3.9 support ([#3114](https://github.com/elastic/elasticsearch-py/pull/3114))
+
+
 ## 9.1.1 (2025-09-11)
 
+### Enhancements
+
 * ES|QL query builder integration with the DSL module ([#3058](https://github.com/elastic/elasticsearch-py/pull/3058))
 * ES|QL query builder robustness fixes ([#3017](https://github.com/elastic/elasticsearch-py/pull/3017))
 * Fix ES|QL `multi_match()` signature ([#3052](https://github.com/elastic/elasticsearch-py/pull/3052))
 
-API
+### API
+
 * Add support for ES|QL query builder objects to ES|QL Query and Async Query APIs
 * Add Transform Set Upgrade Mode API
 * Fix type of `fields` parameter of Term Vectors API to array of strings
 * Fix type of `params` parameter of SQL Query API to array
 
-DSL
+### DSL
+
 * Preserve the `skip_empty` setting in `to_dict()` recursive serializations ([#3041](https://github.com/elastic/elasticsearch-py/pull/3041))
 * Add `separator_group` and `separators` attributes to `ChunkingSettings` type
 * Add `primary` attribute to `ShardFailure` type
@@ -39,13 +89,13 @@ DSL
 
 ## 9.1.0 (2025-07-30)
 
-Enhancements
+### Enhancements
 
 * ES|QL query builder (technical preview) ([#2997](https://github.com/elastic/elasticsearch-py/pull/2997))
 * Update OpenTelemetry conventions ([#2999](https://github.com/elastic/elasticsearch-py/pull/2999))
 * Add option to disable accurate reporting of file and line location in warnings (Fixes #3003) ([#3006](https://github.com/elastic/elasticsearch-py/pull/3006))
 
-APIs
+### APIs
 
 * Remove `if_primary_term`, `if_seq_no` and `op_type` from Create API
 * Remove `master_timeout` from Ingest Get Ip Location Database API
@@ -75,7 +125,7 @@ APIs
 * Add `state` to Snapshot Get API
 * Add `refresh` to Synonyms Put Synonym, Put Synonym Rule and Delete Synonym Rule APIs
 
-DSL
+### DSL
 
 * Handle lists in `copy_to` option in DSL field declarations correctly (Fixes #2992) ([#2993](https://github.com/elastic/elasticsearch-py/pull/2993))
 * Add `index_options` to SparseVector type
@@ -87,6 +137,57 @@ Other changes
 * Drop support for Python 3.8 ([#3001](https://github.com/elastic/elasticsearch-py/pull/3001))
 
 
+## 9.0.4 (2025-09-11)
+
+### Enhancements
+
+* ES|QL query builder integration with the DSL module ([#3058](https://github.com/elastic/elasticsearch-py/pull/3058))
+* ES|QL query builder robustness fixes ([#3017](https://github.com/elastic/elasticsearch-py/pull/3017))
+* Fix ES|QL `multi_match()` signature ([#3052](https://github.com/elastic/elasticsearch-py/pull/3052))
+
+### API
+
+* Add support for ES|QL query builder objects to ES|QL Query and Async Query APIs
+* Add Transform Set Upgrade Mode API
+* Fix type of `fields` parameter of Term Vectors API to array of strings
+* Fix type of `params` parameter of SQL Query API to array
+
+### DSL
+
+* Preserve the `skip_empty` setting in `to_dict()` recursive serializations ([#3041](https://github.com/elastic/elasticsearch-py/pull/3041))
+* Add `primary` attribute to `ShardFailure` type
+* Fix type of `key` attribute of `ArrayPercentilesItem` to float
+
+## 9.0.3 (2025-07-30)
+
+### Enhancements
+
+* ES|QL query builder (technical preview) ([#2997](https://github.com/elastic/elasticsearch-py/pull/2997))
+* Add option to disable accurate reporting of file and line location in warnings (Fixes #3003) ([#3006](https://github.com/elastic/elasticsearch-py/pull/3006))
+
+### APIs
+
+* Remove `if_primary_term`, `if_seq_no` and `op_type` from Create API
+* Remove `stored_fields` from Get Source API
+* Remove `master_timeout` from Ingest Get Ip Location Database API
+* Remove `application`, `priviledge` and `username` from the Security Get User API
+* Rename `type_query_string` to `type` in License Post Start Trial API
+* Add `require_data_stream` to Index API
+* Add `settings_filter` to Cluster Get Component Template API
+* Add `cause` to Cluster Put Component Template API
+* Add `ccs_minimize_roundtrips` to EQL Search API
+* Add `keep_alive` and `keep_on_completion` to ES|QL Async Query API
+* Add `format` to ES|QL Async Query Get API
+* Add `allow_no_indices`, `expand_wildcards` and `ignore_available` to Indices Recovery API
+* Add `timeout` to all Inference Put APIs
+* Add `refresh` to Security Get User Profile API
+* Add `wait_for_completion` to the Snapshot Delete API
+
+### DSL
+
+* Handle lists in `copy_to` field option correctly (Fixes #2992) ([#2993](https://github.com/elastic/elasticsearch-py/pull/2993))
+* Add `key` to FiltersBucket type
+
 
 ## 9.0.2 (2025-06-05) [elasticsearch-python-client-902-release-notes]
 
diff -pruN 9.1.1-2/docs/sphinx/api/indices.rst 9.2.0-1/docs/sphinx/api/indices.rst
--- 9.1.1-2/docs/sphinx/api/indices.rst	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/docs/sphinx/api/indices.rst	2025-10-28 16:50:53.000000000 +0000
@@ -6,4 +6,4 @@ Indices
    :no-index:
 
 .. autoclass:: IndicesClient
-   :members:
\ No newline at end of file
+   :members:
diff -pruN 9.1.1-2/docs/sphinx/api/project.rst 9.2.0-1/docs/sphinx/api/project.rst
--- 9.1.1-2/docs/sphinx/api/project.rst	1970-01-01 00:00:00.000000000 +0000
+++ 9.2.0-1/docs/sphinx/api/project.rst	2025-10-28 16:50:53.000000000 +0000
@@ -0,0 +1,9 @@
+.. _project:
+
+Project
+-------
+.. py:module:: elasticsearch.client
+   :no-index:
+
+.. autoclass:: ProjectClient
+   :members:
diff -pruN 9.1.1-2/docs/sphinx/api/streams.rst 9.2.0-1/docs/sphinx/api/streams.rst
--- 9.1.1-2/docs/sphinx/api/streams.rst	1970-01-01 00:00:00.000000000 +0000
+++ 9.2.0-1/docs/sphinx/api/streams.rst	2025-10-28 16:50:53.000000000 +0000
@@ -0,0 +1,9 @@
+.. _streams:
+
+Streams
+-------
+.. py:module:: elasticsearch.client
+   :no-index:
+
+.. autoclass:: StreamsClient
+   :members:
diff -pruN 9.1.1-2/docs/sphinx/es_api.rst 9.2.0-1/docs/sphinx/es_api.rst
--- 9.1.1-2/docs/sphinx/es_api.rst	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/docs/sphinx/es_api.rst	2025-10-28 16:50:53.000000000 +0000
@@ -39,6 +39,7 @@ arguments are required for all calls.
    api/ml
    api/monitoring
    api/nodes
+   api/project
    api/query-rules
    api/rollup-indices
    api/search-application
@@ -50,6 +51,7 @@ arguments are required for all calls.
    api/snapshots
    api/snapshottable-features
    api/sql
+   api/streams
    api/synonyms
    api/tls-ssl
    api/tasks
diff -pruN 9.1.1-2/elasticsearch/_async/client/__init__.py 9.2.0-1/elasticsearch/_async/client/__init__.py
--- 9.1.1-2/elasticsearch/_async/client/__init__.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_async/client/__init__.py	2025-10-28 16:50:53.000000000 +0000
@@ -63,6 +63,7 @@ from .migration import MigrationClient
 from .ml import MlClient
 from .monitoring import MonitoringClient
 from .nodes import NodesClient
+from .project import ProjectClient
 from .query_rules import QueryRulesClient
 from .rollup import RollupClient
 from .search_application import SearchApplicationClient
@@ -74,6 +75,7 @@ from .slm import SlmClient
 from .snapshot import SnapshotClient
 from .sql import SqlClient
 from .ssl import SslClient
+from .streams import StreamsClient
 from .synonyms import SynonymsClient
 from .tasks import TasksClient
 from .text_structure import TextStructureClient
@@ -368,6 +370,7 @@ class AsyncElasticsearch(BaseClient):
         self.migration = MigrationClient(self)
         self.ml = MlClient(self)
         self.monitoring = MonitoringClient(self)
+        self.project = ProjectClient(self)
         self.query_rules = QueryRulesClient(self)
         self.rollup = RollupClient(self)
         self.search_application = SearchApplicationClient(self)
@@ -378,6 +381,7 @@ class AsyncElasticsearch(BaseClient):
         self.shutdown = ShutdownClient(self)
         self.sql = SqlClient(self)
         self.ssl = SslClient(self)
+        self.streams = StreamsClient(self)
         self.synonyms = SynonymsClient(self)
         self.text_structure = TextStructureClient(self)
         self.transform = TransformClient(self)
@@ -845,11 +849,7 @@ class AsyncElasticsearch(BaseClient):
         if not __body:
             if id is not None:
                 __body["id"] = id
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "DELETE",
             __path,
@@ -889,6 +889,7 @@ class AsyncElasticsearch(BaseClient):
         min_score: t.Optional[float] = None,
         preference: t.Optional[str] = None,
         pretty: t.Optional[bool] = None,
+        project_routing: t.Optional[str] = None,
         q: t.Optional[str] = None,
         query: t.Optional[t.Mapping[str, t.Any]] = None,
         routing: t.Optional[str] = None,
@@ -922,8 +923,8 @@ class AsyncElasticsearch(BaseClient):
             This parameter can be used only when the `q` query string parameter is specified.
         :param analyzer: The analyzer to use for the query string. This parameter can
             be used only when the `q` query string parameter is specified.
-        :param default_operator: The default operator for query string query: `AND` or
-            `OR`. This parameter can be used only when the `q` query string parameter
+        :param default_operator: The default operator for query string query: `and` or
+            `or`. This parameter can be used only when the `q` query string parameter
             is specified.
         :param df: The field to use as a default when no field prefix is given in the
             query string. This parameter can be used only when the `q` query string parameter
@@ -943,6 +944,10 @@ class AsyncElasticsearch(BaseClient):
             in the result.
         :param preference: The node or shard the operation should be performed on. By
             default, it is random.
+        :param project_routing: Specifies a subset of projects to target for the search
+            using project metadata tags in a subset of Lucene query syntax. Allowed Lucene
+            queries: the _alias tag and a single value (possibly wildcarded). Examples:
+            _alias:my-project _alias:_origin _alias:*pr* Supported in serverless only.
         :param q: The query in Lucene query string syntax. This parameter cannot be used
             with a request body.
         :param query: Defines the search query using Query DSL. A request body query
@@ -995,6 +1000,8 @@ class AsyncElasticsearch(BaseClient):
             __query["preference"] = preference
         if pretty is not None:
             __query["pretty"] = pretty
+        if project_routing is not None:
+            __query["project_routing"] = project_routing
         if q is not None:
             __query["q"] = q
         if routing is not None:
@@ -1044,7 +1051,7 @@ class AsyncElasticsearch(BaseClient):
         timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         version: t.Optional[int] = None,
         version_type: t.Optional[
-            t.Union[str, t.Literal["external", "external_gte", "force", "internal"]]
+            t.Union[str, t.Literal["external", "external_gte", "internal"]]
         ] = None,
         wait_for_active_shards: t.Optional[
             t.Union[int, t.Union[str, t.Literal["all", "index-setting"]]]
@@ -1223,7 +1230,7 @@ class AsyncElasticsearch(BaseClient):
         timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         version: t.Optional[int] = None,
         version_type: t.Optional[
-            t.Union[str, t.Literal["external", "external_gte", "force", "internal"]]
+            t.Union[str, t.Literal["external", "external_gte", "internal"]]
         ] = None,
         wait_for_active_shards: t.Optional[
             t.Union[int, t.Union[str, t.Literal["all", "index-setting"]]]
@@ -1468,8 +1475,8 @@ class AsyncElasticsearch(BaseClient):
             used only when the `q` query string parameter is specified.
         :param conflicts: What to do if delete by query hits version conflicts: `abort`
             or `proceed`.
-        :param default_operator: The default operator for query string query: `AND` or
-            `OR`. This parameter can be used only when the `q` query string parameter
+        :param default_operator: The default operator for query string query: `and` or
+            `or`. This parameter can be used only when the `q` query string parameter
             is specified.
         :param df: The field to use as default where no field prefix is given in the
             query string. This parameter can be used only when the `q` query string parameter
@@ -1763,7 +1770,7 @@ class AsyncElasticsearch(BaseClient):
         stored_fields: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         version: t.Optional[int] = None,
         version_type: t.Optional[
-            t.Union[str, t.Literal["external", "external_gte", "force", "internal"]]
+            t.Union[str, t.Literal["external", "external_gte", "internal"]]
         ] = None,
     ) -> HeadApiResponse:
         """
@@ -1892,7 +1899,7 @@ class AsyncElasticsearch(BaseClient):
         source_includes: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         version: t.Optional[int] = None,
         version_type: t.Optional[
-            t.Union[str, t.Literal["external", "external_gte", "force", "internal"]]
+            t.Union[str, t.Literal["external", "external_gte", "internal"]]
         ] = None,
     ) -> HeadApiResponse:
         """
@@ -2021,8 +2028,8 @@ class AsyncElasticsearch(BaseClient):
             This parameter can be used only when the `q` query string parameter is specified.
         :param analyzer: The analyzer to use for the query string. This parameter can
             be used only when the `q` query string parameter is specified.
-        :param default_operator: The default operator for query string query: `AND` or
-            `OR`. This parameter can be used only when the `q` query string parameter
+        :param default_operator: The default operator for query string query: `and` or
+            `or`. This parameter can be used only when the `q` query string parameter
             is specified.
         :param df: The field to use as default where no field prefix is given in the
             query string. This parameter can be used only when the `q` query string parameter
@@ -2133,6 +2140,7 @@ class AsyncElasticsearch(BaseClient):
         include_unmapped: t.Optional[bool] = None,
         index_filter: t.Optional[t.Mapping[str, t.Any]] = None,
         pretty: t.Optional[bool] = None,
+        project_routing: t.Optional[str] = None,
         runtime_mappings: t.Optional[t.Mapping[str, t.Mapping[str, t.Any]]] = None,
         types: t.Optional[t.Sequence[str]] = None,
         body: t.Optional[t.Dict[str, t.Any]] = None,
@@ -2176,6 +2184,11 @@ class AsyncElasticsearch(BaseClient):
             deleted documents) are outside of the provided range. However, not all queries
             can rewrite to `match_none` so this API may return an index even if the provided
             filter matches no document.
+        :param project_routing: Specifies a subset of projects to target for the field-caps
+            query using project metadata tags in a subset of Lucene query syntax. Allowed
+            Lucene queries: the _alias tag and a single value (possibly wildcarded).
+            Examples: _alias:my-project _alias:_origin _alias:*pr* Supported in serverless
+            only.
         :param runtime_mappings: Define ad-hoc runtime fields in the request similar
             to the way it is done in search requests. These fields exist only as part
             of the query and take precedence over fields defined with the same name in
@@ -2213,6 +2226,8 @@ class AsyncElasticsearch(BaseClient):
             __query["include_unmapped"] = include_unmapped
         if pretty is not None:
             __query["pretty"] = pretty
+        if project_routing is not None:
+            __query["project_routing"] = project_routing
         if types is not None:
             __query["types"] = types
         if not __body:
@@ -2240,6 +2255,7 @@ class AsyncElasticsearch(BaseClient):
     @_rewrite_parameters(
         parameter_aliases={
             "_source": "source",
+            "_source_exclude_vectors": "source_exclude_vectors",
             "_source_excludes": "source_excludes",
             "_source_includes": "source_includes",
         },
@@ -2259,12 +2275,13 @@ class AsyncElasticsearch(BaseClient):
         refresh: t.Optional[bool] = None,
         routing: t.Optional[str] = None,
         source: t.Optional[t.Union[bool, t.Union[str, t.Sequence[str]]]] = None,
+        source_exclude_vectors: t.Optional[bool] = None,
         source_excludes: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         source_includes: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         stored_fields: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         version: t.Optional[int] = None,
         version_type: t.Optional[
-            t.Union[str, t.Literal["external", "external_gte", "force", "internal"]]
+            t.Union[str, t.Literal["external", "external_gte", "internal"]]
         ] = None,
     ) -> ObjectApiResponse[t.Any]:
         """
@@ -2332,6 +2349,7 @@ class AsyncElasticsearch(BaseClient):
         :param routing: A custom value used to route operations to a specific shard.
         :param source: Indicates whether to return the `_source` field (`true` or `false`)
             or lists the fields to return.
+        :param source_exclude_vectors: Whether vectors should be excluded from _source
         :param source_excludes: A comma-separated list of source fields to exclude from
             the response. You can also use this parameter to exclude fields from the
             subset specified in `_source_includes` query parameter. If the `_source`
@@ -2377,6 +2395,8 @@ class AsyncElasticsearch(BaseClient):
             __query["routing"] = routing
         if source is not None:
             __query["_source"] = source
+        if source_exclude_vectors is not None:
+            __query["_source_exclude_vectors"] = source_exclude_vectors
         if source_excludes is not None:
             __query["_source_excludes"] = source_excludes
         if source_includes is not None:
@@ -2551,7 +2571,7 @@ class AsyncElasticsearch(BaseClient):
         source_includes: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         version: t.Optional[int] = None,
         version_type: t.Optional[
-            t.Union[str, t.Literal["external", "external_gte", "force", "internal"]]
+            t.Union[str, t.Literal["external", "external_gte", "internal"]]
         ] = None,
     ) -> ObjectApiResponse[t.Any]:
         """
@@ -2731,7 +2751,7 @@ class AsyncElasticsearch(BaseClient):
         timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         version: t.Optional[int] = None,
         version_type: t.Optional[
-            t.Union[str, t.Literal["external", "external_gte", "force", "internal"]]
+            t.Union[str, t.Literal["external", "external_gte", "internal"]]
         ] = None,
         wait_for_active_shards: t.Optional[
             t.Union[int, t.Union[str, t.Literal["all", "index-setting"]]]
@@ -3146,6 +3166,7 @@ class AsyncElasticsearch(BaseClient):
         max_concurrent_shard_requests: t.Optional[int] = None,
         pre_filter_shard_size: t.Optional[int] = None,
         pretty: t.Optional[bool] = None,
+        project_routing: t.Optional[str] = None,
         rest_total_hits_as_int: t.Optional[bool] = None,
         routing: t.Optional[str] = None,
         search_type: t.Optional[
@@ -3207,6 +3228,10 @@ class AsyncElasticsearch(BaseClient):
             roundtrip can limit the number of shards significantly if for instance a
             shard can not match any documents based on its rewrite method i.e., if date
             filters are mandatory to match but the shard bounds and the query are disjoint.
+        :param project_routing: Specifies a subset of projects to target for a search
+            using project metadata tags in a subset Lucene syntax. Allowed Lucene queries:
+            the _alias tag and a single value (possible wildcarded). Examples: _alias:my-project
+            _alias:_origin _alias:*pr* Supported in serverless only.
         :param rest_total_hits_as_int: If true, hits.total are returned as an integer
             in the response. Defaults to false, which returns an object.
         :param routing: Custom routing value used to route search operations to a specific
@@ -3256,6 +3281,8 @@ class AsyncElasticsearch(BaseClient):
             __query["pre_filter_shard_size"] = pre_filter_shard_size
         if pretty is not None:
             __query["pretty"] = pretty
+        if project_routing is not None:
+            __query["project_routing"] = project_routing
         if rest_total_hits_as_int is not None:
             __query["rest_total_hits_as_int"] = rest_total_hits_as_int
         if routing is not None:
@@ -3294,6 +3321,7 @@ class AsyncElasticsearch(BaseClient):
         human: t.Optional[bool] = None,
         max_concurrent_searches: t.Optional[int] = None,
         pretty: t.Optional[bool] = None,
+        project_routing: t.Optional[str] = None,
         rest_total_hits_as_int: t.Optional[bool] = None,
         search_type: t.Optional[
             t.Union[str, t.Literal["dfs_query_then_fetch", "query_then_fetch"]]
@@ -3327,6 +3355,10 @@ class AsyncElasticsearch(BaseClient):
             for cross-cluster search requests.
         :param max_concurrent_searches: The maximum number of concurrent searches the
             API can run.
+        :param project_routing: Specifies a subset of projects to target for the search
+            using project metadata tags in a subset of Lucene query syntax. Allowed Lucene
+            queries: the _alias tag and a single value (possibly wildcarded). Examples:
+            _alias:my-project _alias:_origin _alias:*pr* Supported in serverless only.
         :param rest_total_hits_as_int: If `true`, the response returns `hits.total` as
             an integer. If `false`, it returns `hits.total` as an object.
         :param search_type: The type of the search operation.
@@ -3359,6 +3391,8 @@ class AsyncElasticsearch(BaseClient):
             __query["max_concurrent_searches"] = max_concurrent_searches
         if pretty is not None:
             __query["pretty"] = pretty
+        if project_routing is not None:
+            __query["project_routing"] = project_routing
         if rest_total_hits_as_int is not None:
             __query["rest_total_hits_as_int"] = rest_total_hits_as_int
         if search_type is not None:
@@ -3404,7 +3438,7 @@ class AsyncElasticsearch(BaseClient):
         term_statistics: t.Optional[bool] = None,
         version: t.Optional[int] = None,
         version_type: t.Optional[
-            t.Union[str, t.Literal["external", "external_gte", "force", "internal"]]
+            t.Union[str, t.Literal["external", "external_gte", "internal"]]
         ] = None,
         body: t.Optional[t.Dict[str, t.Any]] = None,
     ) -> ObjectApiResponse[t.Any]:
@@ -3529,6 +3563,7 @@ class AsyncElasticsearch(BaseClient):
         max_concurrent_shard_requests: t.Optional[int] = None,
         preference: t.Optional[str] = None,
         pretty: t.Optional[bool] = None,
+        project_routing: t.Optional[str] = None,
         routing: t.Optional[str] = None,
         body: t.Optional[t.Dict[str, t.Any]] = None,
     ) -> ObjectApiResponse[t.Any]:
@@ -3585,6 +3620,11 @@ class AsyncElasticsearch(BaseClient):
             that each sub-search request executes per node.
         :param preference: The node or shard the operation should be performed on. By
             default, it is random.
+        :param project_routing: Specifies a subset of projects to target for the PIT
+            request using project metadata tags in a subset of Lucene query syntax. Allowed
+            Lucene queries: the _alias tag and a single value (possibly wildcarded).
+            Examples: _alias:my-project _alias:_origin _alias:*pr* Supported in serverless
+            only.
         :param routing: A custom value that is used to route operations to a specific
             shard.
         """
@@ -3616,6 +3656,8 @@ class AsyncElasticsearch(BaseClient):
             __query["preference"] = preference
         if pretty is not None:
             __query["pretty"] = pretty
+        if project_routing is not None:
+            __query["project_routing"] = project_routing
         if routing is not None:
             __query["routing"] = routing
         if not __body:
@@ -3814,7 +3856,7 @@ class AsyncElasticsearch(BaseClient):
         )
 
     @_rewrite_parameters(
-        body_fields=("dest", "source", "conflicts", "max_docs", "script", "size"),
+        body_fields=("dest", "source", "conflicts", "max_docs", "script"),
     )
     async def reindex(
         self,
@@ -3832,7 +3874,6 @@ class AsyncElasticsearch(BaseClient):
         require_alias: t.Optional[bool] = None,
         script: t.Optional[t.Mapping[str, t.Any]] = None,
         scroll: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
-        size: t.Optional[int] = None,
         slices: t.Optional[t.Union[int, t.Union[str, t.Literal["auto"]]]] = None,
         timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         wait_for_active_shards: t.Optional[
@@ -3908,7 +3949,6 @@ class AsyncElasticsearch(BaseClient):
             reindexing.
         :param scroll: The period of time that a consistent view of the index should
             be maintained for scrolled search.
-        :param size:
         :param slices: The number of slices this task should be divided into. It defaults
             to one slice, which means the task isn't sliced into subtasks. Reindex supports
             sliced scroll to parallelize the reindexing process. This parallelization
@@ -3973,8 +4013,6 @@ class AsyncElasticsearch(BaseClient):
                 __body["max_docs"] = max_docs
             if script is not None:
                 __body["script"] = script
-            if size is not None:
-                __body["size"] = size
         __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "POST",
@@ -4101,11 +4139,7 @@ class AsyncElasticsearch(BaseClient):
                 __body["params"] = params
             if source is not None:
                 __body["source"] = source
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "POST",
             __path,
@@ -4188,11 +4222,7 @@ class AsyncElasticsearch(BaseClient):
                 __body["context_setup"] = context_setup
             if script is not None:
                 __body["script"] = script
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "POST",
             __path,
@@ -4317,6 +4347,7 @@ class AsyncElasticsearch(BaseClient):
         ),
         parameter_aliases={
             "_source": "source",
+            "_source_exclude_vectors": "source_exclude_vectors",
             "_source_excludes": "source_excludes",
             "_source_includes": "source_includes",
             "from": "from_",
@@ -4371,6 +4402,7 @@ class AsyncElasticsearch(BaseClient):
         preference: t.Optional[str] = None,
         pretty: t.Optional[bool] = None,
         profile: t.Optional[bool] = None,
+        project_routing: t.Optional[str] = None,
         q: t.Optional[str] = None,
         query: t.Optional[t.Mapping[str, t.Any]] = None,
         rank: t.Optional[t.Mapping[str, t.Any]] = None,
@@ -4400,6 +4432,7 @@ class AsyncElasticsearch(BaseClient):
             ]
         ] = None,
         source: t.Optional[t.Union[bool, t.Mapping[str, t.Any]]] = None,
+        source_exclude_vectors: t.Optional[bool] = None,
         source_excludes: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         source_includes: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         stats: t.Optional[t.Sequence[str]] = None,
@@ -4467,8 +4500,8 @@ class AsyncElasticsearch(BaseClient):
             node and the remote clusters are minimized when running cross-cluster search
             (CCS) requests.
         :param collapse: Collapses search results the values of the specified field.
-        :param default_operator: The default operator for the query string query: `AND`
-            or `OR`. This parameter can be used only when the `q` query string parameter
+        :param default_operator: The default operator for the query string query: `and`
+            or `or`. This parameter can be used only when the `q` query string parameter
             is specified.
         :param df: The field to use as a default when no field prefix is given in the
             query string. This parameter can be used only when the `q` query string parameter
@@ -4553,6 +4586,10 @@ class AsyncElasticsearch(BaseClient):
         :param profile: Set to `true` to return detailed timing information about the
             execution of individual components in a search request. NOTE: This is a debugging
             tool and adds significant overhead to search execution.
+        :param project_routing: Specifies a subset of projects to target for the search
+            using project metadata tags in a subset of Lucene query syntax. Allowed Lucene
+            queries: the _alias tag and a single value (possibly wildcarded). Examples:
+            _alias:my-project _alias:_origin _alias:*pr* Supported in serverless only.
         :param q: A query in the Lucene query string syntax. Query parameter searches
             do not support the full Elasticsearch Query DSL but are handy for testing.
             IMPORTANT: This parameter overrides the query parameter in the request body.
@@ -4594,6 +4631,7 @@ class AsyncElasticsearch(BaseClient):
             fields are returned in the `hits._source` property of the search response.
             If the `stored_fields` property is specified, the `_source` property defaults
             to `false`. Otherwise, it defaults to `true`.
+        :param source_exclude_vectors: Whether vectors should be excluded from _source
         :param source_excludes: A comma-separated list of source fields to exclude from
             the response. You can also use this parameter to exclude fields from the
             subset specified in `_source_includes` query parameter. If the `_source`
@@ -4706,6 +4744,8 @@ class AsyncElasticsearch(BaseClient):
             __query["preference"] = preference
         if pretty is not None:
             __query["pretty"] = pretty
+        if project_routing is not None:
+            __query["project_routing"] = project_routing
         if q is not None:
             __query["q"] = q
         if request_cache is not None:
@@ -4718,6 +4758,8 @@ class AsyncElasticsearch(BaseClient):
             __query["scroll"] = scroll
         if search_type is not None:
             __query["search_type"] = search_type
+        if source_exclude_vectors is not None:
+            __query["_source_exclude_vectors"] = source_exclude_vectors
         if source_excludes is not None:
             __query["_source_excludes"] = source_excludes
         if source_includes is not None:
@@ -4858,6 +4900,7 @@ class AsyncElasticsearch(BaseClient):
         ] = None,
         human: t.Optional[bool] = None,
         pretty: t.Optional[bool] = None,
+        project_routing: t.Optional[str] = None,
         query: t.Optional[t.Mapping[str, t.Any]] = None,
         runtime_mappings: t.Optional[t.Mapping[str, t.Mapping[str, t.Any]]] = None,
         size: t.Optional[int] = None,
@@ -5175,6 +5218,10 @@ class AsyncElasticsearch(BaseClient):
             In the aggs layer, each feature represents a `geotile_grid` cell. If `grid,
             each feature is a polygon of the cells bounding box. If `point`, each feature
             is a Point that is the centroid of the cell.
+        :param project_routing: Specifies a subset of projects to target for the search
+            using project metadata tags in a subset of Lucene query syntax. Allowed Lucene
+            queries: the _alias tag and a single value (possibly wildcarded). Examples:
+            _alias:my-project _alias:_origin _alias:*pr* Supported in serverless only.
         :param query: The query DSL used to filter documents for the search.
         :param runtime_mappings: Defines one or more runtime fields in the search request.
             These fields take precedence over mapped fields with the same name.
@@ -5238,6 +5285,8 @@ class AsyncElasticsearch(BaseClient):
             __query["human"] = human
         if pretty is not None:
             __query["pretty"] = pretty
+        if project_routing is not None:
+            __query["project_routing"] = project_routing
         if not __body:
             if aggs is not None:
                 __body["aggs"] = aggs
@@ -5411,6 +5460,7 @@ class AsyncElasticsearch(BaseClient):
         preference: t.Optional[str] = None,
         pretty: t.Optional[bool] = None,
         profile: t.Optional[bool] = None,
+        project_routing: t.Optional[str] = None,
         rest_total_hits_as_int: t.Optional[bool] = None,
         routing: t.Optional[str] = None,
         scroll: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
@@ -5456,6 +5506,10 @@ class AsyncElasticsearch(BaseClient):
         :param preference: The node or shard the operation should be performed on. It
             is random by default.
         :param profile: If `true`, the query execution is profiled.
+        :param project_routing: Specifies a subset of projects to target for the search
+            using project metadata tags in a subset of Lucene query syntax. Allowed Lucene
+            queries: the _alias tag and a single value (possibly wildcarded). Examples:
+            _alias:my-project _alias:_origin _alias:*pr* Supported in serverless only.
         :param rest_total_hits_as_int: If `true`, `hits.total` is rendered as an integer
             in the response. If `false`, it is rendered as an object.
         :param routing: A custom value used to route operations to a specific shard.
@@ -5497,6 +5551,8 @@ class AsyncElasticsearch(BaseClient):
             __query["preference"] = preference
         if pretty is not None:
             __query["pretty"] = pretty
+        if project_routing is not None:
+            __query["project_routing"] = project_routing
         if rest_total_hits_as_int is not None:
             __query["rest_total_hits_as_int"] = rest_total_hits_as_int
         if routing is not None:
@@ -5623,11 +5679,7 @@ class AsyncElasticsearch(BaseClient):
                 __body["string"] = string
             if timeout is not None:
                 __body["timeout"] = timeout
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "POST",
             __path,
@@ -5677,7 +5729,7 @@ class AsyncElasticsearch(BaseClient):
         term_statistics: t.Optional[bool] = None,
         version: t.Optional[int] = None,
         version_type: t.Optional[
-            t.Union[str, t.Literal["external", "external_gte", "force", "internal"]]
+            t.Union[str, t.Literal["external", "external_gte", "internal"]]
         ] = None,
         body: t.Optional[t.Dict[str, t.Any]] = None,
     ) -> ObjectApiResponse[t.Any]:
@@ -6153,8 +6205,8 @@ class AsyncElasticsearch(BaseClient):
             be used only when the `q` query string parameter is specified.
         :param conflicts: The preferred behavior when update by query hits version conflicts:
             `abort` or `proceed`.
-        :param default_operator: The default operator for query string query: `AND` or
-            `OR`. This parameter can be used only when the `q` query string parameter
+        :param default_operator: The default operator for query string query: `and` or
+            `or`. This parameter can be used only when the `q` query string parameter
             is specified.
         :param df: The field to use as default where no field prefix is given in the
             query string. This parameter can be used only when the `q` query string parameter
diff -pruN 9.1.1-2/elasticsearch/_async/client/async_search.py 9.2.0-1/elasticsearch/_async/client/async_search.py
--- 9.1.1-2/elasticsearch/_async/client/async_search.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_async/client/async_search.py	2025-10-28 16:50:53.000000000 +0000
@@ -287,6 +287,7 @@ class AsyncSearchClient(NamespacedClient
         preference: t.Optional[str] = None,
         pretty: t.Optional[bool] = None,
         profile: t.Optional[bool] = None,
+        project_routing: t.Optional[str] = None,
         q: t.Optional[str] = None,
         query: t.Optional[t.Mapping[str, t.Any]] = None,
         request_cache: t.Optional[bool] = None,
@@ -408,6 +409,10 @@ class AsyncSearchClient(NamespacedClient
         :param preference: Specify the node or shard the operation should be performed
             on (default: random)
         :param profile:
+        :param project_routing: Specifies a subset of projects to target for the search
+            using project metadata tags in a subset of Lucene query syntax. Allowed Lucene
+            queries: the _alias tag and a single value (possibly wildcarded). Examples:
+            _alias:my-project _alias:_origin _alias:*pr* Supported in serverless only.
         :param q: Query in the Lucene query string syntax
         :param query: Defines the search definition using the Query DSL.
         :param request_cache: Specify if request cache should be used for this request
@@ -528,6 +533,8 @@ class AsyncSearchClient(NamespacedClient
             __query["preference"] = preference
         if pretty is not None:
             __query["pretty"] = pretty
+        if project_routing is not None:
+            __query["project_routing"] = project_routing
         if q is not None:
             __query["q"] = q
         if request_cache is not None:
diff -pruN 9.1.1-2/elasticsearch/_async/client/cat.py 9.2.0-1/elasticsearch/_async/client/cat.py
--- 9.1.1-2/elasticsearch/_async/client/cat.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_async/client/cat.py	2025-10-28 16:50:53.000000000 +0000
@@ -36,6 +36,9 @@ class CatClient(NamespacedClient):
         self,
         *,
         name: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        bytes: t.Optional[
+            t.Union[str, t.Literal["b", "gb", "kb", "mb", "pb", "tb"]]
+        ] = None,
         error_trace: t.Optional[bool] = None,
         expand_wildcards: t.Optional[
             t.Union[
@@ -80,6 +83,9 @@ class CatClient(NamespacedClient):
         master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         pretty: t.Optional[bool] = None,
         s: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        time: t.Optional[
+            t.Union[str, t.Literal["d", "h", "m", "micros", "ms", "nanos", "s"]]
+        ] = None,
         v: t.Optional[bool] = None,
     ) -> t.Union[ObjectApiResponse[t.Any], TextApiResponse]:
         """
@@ -95,6 +101,14 @@ class CatClient(NamespacedClient):
 
         :param name: A comma-separated list of aliases to retrieve. Supports wildcards
             (`*`). To retrieve all aliases, omit this parameter or use `*` or `_all`.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param expand_wildcards: The type of index that wildcard patterns can match.
             If the request can target data streams, this argument determines whether
             wildcard expressions match hidden data streams. It supports comma-separated
@@ -112,6 +126,12 @@ class CatClient(NamespacedClient):
         :param s: List of columns that determine how the table should be sorted. Sorting
             defaults to ascending and can be changed by setting `:asc` or `:desc` as
             a suffix to the column name.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str]
@@ -122,6 +142,8 @@ class CatClient(NamespacedClient):
             __path_parts = {}
             __path = "/_cat/aliases"
         __query: t.Dict[str, t.Any] = {}
+        if bytes is not None:
+            __query["bytes"] = bytes
         if error_trace is not None:
             __query["error_trace"] = error_trace
         if expand_wildcards is not None:
@@ -142,6 +164,8 @@ class CatClient(NamespacedClient):
             __query["pretty"] = pretty
         if s is not None:
             __query["s"] = s
+        if time is not None:
+            __query["time"] = time
         if v is not None:
             __query["v"] = v
         __headers = {"accept": "text/plain,application/json"}
@@ -213,6 +237,9 @@ class CatClient(NamespacedClient):
         master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         pretty: t.Optional[bool] = None,
         s: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        time: t.Optional[
+            t.Union[str, t.Literal["d", "h", "m", "micros", "ms", "nanos", "s"]]
+        ] = None,
         v: t.Optional[bool] = None,
     ) -> t.Union[ObjectApiResponse[t.Any], TextApiResponse]:
         """
@@ -227,7 +254,14 @@ class CatClient(NamespacedClient):
 
         :param node_id: A comma-separated list of node identifiers or names used to limit
             the returned information.
-        :param bytes: The unit used to display byte values.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: A comma-separated list of columns names to display. It supports simple
@@ -242,6 +276,12 @@ class CatClient(NamespacedClient):
         :param s: List of columns that determine how the table should be sorted. Sorting
             defaults to ascending and can be changed by setting `:asc` or `:desc` as
             a suffix to the column name.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str]
@@ -274,6 +314,8 @@ class CatClient(NamespacedClient):
             __query["pretty"] = pretty
         if s is not None:
             __query["s"] = s
+        if time is not None:
+            __query["time"] = time
         if v is not None:
             __query["v"] = v
         __headers = {"accept": "text/plain,application/json"}
@@ -291,6 +333,9 @@ class CatClient(NamespacedClient):
         self,
         *,
         name: t.Optional[str] = None,
+        bytes: t.Optional[
+            t.Union[str, t.Literal["b", "gb", "kb", "mb", "pb", "tb"]]
+        ] = None,
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         format: t.Optional[str] = None,
@@ -330,6 +375,9 @@ class CatClient(NamespacedClient):
         master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         pretty: t.Optional[bool] = None,
         s: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        time: t.Optional[
+            t.Union[str, t.Literal["d", "h", "m", "micros", "ms", "nanos", "s"]]
+        ] = None,
         v: t.Optional[bool] = None,
     ) -> t.Union[ObjectApiResponse[t.Any], TextApiResponse]:
         """
@@ -346,6 +394,14 @@ class CatClient(NamespacedClient):
 
         :param name: The name of the component template. It accepts wildcard expressions.
             If it is omitted, all component templates are returned.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: A comma-separated list of columns names to display. It supports simple
@@ -360,6 +416,12 @@ class CatClient(NamespacedClient):
         :param s: List of columns that determine how the table should be sorted. Sorting
             defaults to ascending and can be changed by setting `:asc` or `:desc` as
             a suffix to the column name.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str]
@@ -370,6 +432,8 @@ class CatClient(NamespacedClient):
             __path_parts = {}
             __path = "/_cat/component_templates"
         __query: t.Dict[str, t.Any] = {}
+        if bytes is not None:
+            __query["bytes"] = bytes
         if error_trace is not None:
             __query["error_trace"] = error_trace
         if filter_path is not None:
@@ -390,6 +454,8 @@ class CatClient(NamespacedClient):
             __query["pretty"] = pretty
         if s is not None:
             __query["s"] = s
+        if time is not None:
+            __query["time"] = time
         if v is not None:
             __query["v"] = v
         __headers = {"accept": "text/plain,application/json"}
@@ -407,6 +473,9 @@ class CatClient(NamespacedClient):
         self,
         *,
         index: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        bytes: t.Optional[
+            t.Union[str, t.Literal["b", "gb", "kb", "mb", "pb", "tb"]]
+        ] = None,
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         format: t.Optional[str] = None,
@@ -419,7 +488,11 @@ class CatClient(NamespacedClient):
         help: t.Optional[bool] = None,
         human: t.Optional[bool] = None,
         pretty: t.Optional[bool] = None,
+        project_routing: t.Optional[str] = None,
         s: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        time: t.Optional[
+            t.Union[str, t.Literal["d", "h", "m", "micros", "ms", "nanos", "s"]]
+        ] = None,
         v: t.Optional[bool] = None,
     ) -> t.Union[ObjectApiResponse[t.Any], TextApiResponse]:
         """
@@ -437,15 +510,33 @@ class CatClient(NamespacedClient):
         :param index: A comma-separated list of data streams, indices, and aliases used
             to limit the request. It supports wildcards (`*`). To target all data streams
             and indices, omit this parameter or use `*` or `_all`.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: A comma-separated list of columns names to display. It supports simple
             wildcards.
         :param help: When set to `true` will output available columns. This option can't
             be combined with any other query string option.
+        :param project_routing: Specifies a subset of projects to target for the search
+            using project metadata tags in a subset of Lucene query syntax. Allowed Lucene
+            queries: the _alias tag and a single value (possibly wildcarded). Examples:
+            _alias:my-project _alias:_origin _alias:*pr* Supported in serverless only.
         :param s: List of columns that determine how the table should be sorted. Sorting
             defaults to ascending and can be changed by setting `:asc` or `:desc` as
             a suffix to the column name.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str]
@@ -456,6 +547,8 @@ class CatClient(NamespacedClient):
             __path_parts = {}
             __path = "/_cat/count"
         __query: t.Dict[str, t.Any] = {}
+        if bytes is not None:
+            __query["bytes"] = bytes
         if error_trace is not None:
             __query["error_trace"] = error_trace
         if filter_path is not None:
@@ -470,8 +563,12 @@ class CatClient(NamespacedClient):
             __query["human"] = human
         if pretty is not None:
             __query["pretty"] = pretty
+        if project_routing is not None:
+            __query["project_routing"] = project_routing
         if s is not None:
             __query["s"] = s
+        if time is not None:
+            __query["time"] = time
         if v is not None:
             __query["v"] = v
         __headers = {"accept": "text/plain,application/json"}
@@ -507,6 +604,9 @@ class CatClient(NamespacedClient):
         human: t.Optional[bool] = None,
         pretty: t.Optional[bool] = None,
         s: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        time: t.Optional[
+            t.Union[str, t.Literal["d", "h", "m", "micros", "ms", "nanos", "s"]]
+        ] = None,
         v: t.Optional[bool] = None,
     ) -> t.Union[ObjectApiResponse[t.Any], TextApiResponse]:
         """
@@ -522,7 +622,14 @@ class CatClient(NamespacedClient):
 
         :param fields: Comma-separated list of fields used to limit returned information.
             To retrieve all fields, omit this parameter.
-        :param bytes: The unit used to display byte values.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: A comma-separated list of columns names to display. It supports simple
@@ -532,6 +639,12 @@ class CatClient(NamespacedClient):
         :param s: List of columns that determine how the table should be sorted. Sorting
             defaults to ascending and can be changed by setting `:asc` or `:desc` as
             a suffix to the column name.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str]
@@ -560,6 +673,8 @@ class CatClient(NamespacedClient):
             __query["pretty"] = pretty
         if s is not None:
             __query["s"] = s
+        if time is not None:
+            __query["time"] = time
         if v is not None:
             __query["v"] = v
         __headers = {"accept": "text/plain,application/json"}
@@ -576,6 +691,9 @@ class CatClient(NamespacedClient):
     async def health(
         self,
         *,
+        bytes: t.Optional[
+            t.Union[str, t.Literal["b", "gb", "kb", "mb", "pb", "tb"]]
+        ] = None,
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         format: t.Optional[str] = None,
@@ -652,6 +770,14 @@ class CatClient(NamespacedClient):
 
         `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-health>`_
 
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: A comma-separated list of columns names to display. It supports simple
@@ -661,13 +787,20 @@ class CatClient(NamespacedClient):
         :param s: List of columns that determine how the table should be sorted. Sorting
             defaults to ascending and can be changed by setting `:asc` or `:desc` as
             a suffix to the column name.
-        :param time: The unit used to display time values.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param ts: If true, returns `HH:MM:SS` and Unix epoch timestamps.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str] = {}
         __path = "/_cat/health"
         __query: t.Dict[str, t.Any] = {}
+        if bytes is not None:
+            __query["bytes"] = bytes
         if error_trace is not None:
             __query["error_trace"] = error_trace
         if filter_path is not None:
@@ -1092,7 +1225,14 @@ class CatClient(NamespacedClient):
         :param index: Comma-separated list of data streams, indices, and aliases used
             to limit the request. Supports wildcards (`*`). To target all data streams
             and indices, omit this parameter or use `*` or `_all`.
-        :param bytes: The unit used to display byte values.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param expand_wildcards: The type of index that wildcard patterns can match.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
@@ -1109,7 +1249,12 @@ class CatClient(NamespacedClient):
         :param s: List of columns that determine how the table should be sorted. Sorting
             defaults to ascending and can be changed by setting `:asc` or `:desc` as
             a suffix to the column name.
-        :param time: The unit used to display time values.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str]
@@ -1166,6 +1311,9 @@ class CatClient(NamespacedClient):
     async def master(
         self,
         *,
+        bytes: t.Optional[
+            t.Union[str, t.Literal["b", "gb", "kb", "mb", "pb", "tb"]]
+        ] = None,
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         format: t.Optional[str] = None,
@@ -1181,6 +1329,9 @@ class CatClient(NamespacedClient):
         master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         pretty: t.Optional[bool] = None,
         s: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        time: t.Optional[
+            t.Union[str, t.Literal["d", "h", "m", "micros", "ms", "nanos", "s"]]
+        ] = None,
         v: t.Optional[bool] = None,
     ) -> t.Union[ObjectApiResponse[t.Any], TextApiResponse]:
         """
@@ -1193,6 +1344,14 @@ class CatClient(NamespacedClient):
 
         `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-master>`_
 
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: A comma-separated list of columns names to display. It supports simple
@@ -1207,11 +1366,19 @@ class CatClient(NamespacedClient):
         :param s: List of columns that determine how the table should be sorted. Sorting
             defaults to ascending and can be changed by setting `:asc` or `:desc` as
             a suffix to the column name.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str] = {}
         __path = "/_cat/master"
         __query: t.Dict[str, t.Any] = {}
+        if bytes is not None:
+            __query["bytes"] = bytes
         if error_trace is not None:
             __query["error_trace"] = error_trace
         if filter_path is not None:
@@ -1232,6 +1399,8 @@ class CatClient(NamespacedClient):
             __query["pretty"] = pretty
         if s is not None:
             __query["s"] = s
+        if time is not None:
+            __query["time"] = time
         if v is not None:
             __query["v"] = v
         __headers = {"accept": "text/plain,application/json"}
@@ -1374,8 +1543,15 @@ class CatClient(NamespacedClient):
 
         :param id: The ID of the data frame analytics to fetch
         :param allow_no_match: Whether to ignore if a wildcard expression matches no
-            configs. (This includes `_all` string or when no configs have been specified)
-        :param bytes: The unit in which to display byte values
+            configs. (This includes `_all` string or when no configs have been specified.)
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: Comma-separated list of column names to display.
@@ -1383,7 +1559,12 @@ class CatClient(NamespacedClient):
             be combined with any other query string option.
         :param s: Comma-separated list of column names or column aliases used to sort
             the response.
-        :param time: Unit used to display time values.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str]
@@ -1434,6 +1615,9 @@ class CatClient(NamespacedClient):
         *,
         datafeed_id: t.Optional[str] = None,
         allow_no_match: t.Optional[bool] = None,
+        bytes: t.Optional[
+            t.Union[str, t.Literal["b", "gb", "kb", "mb", "pb", "tb"]]
+        ] = None,
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         format: t.Optional[str] = None,
@@ -1549,6 +1733,14 @@ class CatClient(NamespacedClient):
             array when there are no matches and the subset of results when there are
             partial matches. If `false`, the API returns a 404 status code when there
             are no matches or only partial matches.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: Comma-separated list of column names to display.
@@ -1556,7 +1748,12 @@ class CatClient(NamespacedClient):
             be combined with any other query string option.
         :param s: Comma-separated list of column names or column aliases used to sort
             the response.
-        :param time: The unit used to display time values.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str]
@@ -1569,6 +1766,8 @@ class CatClient(NamespacedClient):
         __query: t.Dict[str, t.Any] = {}
         if allow_no_match is not None:
             __query["allow_no_match"] = allow_no_match
+        if bytes is not None:
+            __query["bytes"] = bytes
         if error_trace is not None:
             __query["error_trace"] = error_trace
         if filter_path is not None:
@@ -1914,7 +2113,14 @@ class CatClient(NamespacedClient):
             array when there are no matches and the subset of results when there are
             partial matches. If `false`, the API returns a 404 status code when there
             are no matches or only partial matches.
-        :param bytes: The unit used to display byte values.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: Comma-separated list of column names to display.
@@ -1922,7 +2128,12 @@ class CatClient(NamespacedClient):
             be combined with any other query string option.
         :param s: Comma-separated list of column names or column aliases used to sort
             the response.
-        :param time: The unit used to display time values.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str]
@@ -2099,7 +2310,14 @@ class CatClient(NamespacedClient):
             when there are no matches and the subset of results when there are partial
             matches. If `false`, the API returns a 404 status code when there are no
             matches or only partial matches.
-        :param bytes: The unit used to display byte values.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param from_: Skips the specified number of transforms.
@@ -2109,7 +2327,12 @@ class CatClient(NamespacedClient):
         :param s: A comma-separated list of column names or aliases used to sort the
             response.
         :param size: The maximum number of transforms to display.
-        :param time: Unit used to display time values.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str]
@@ -2162,6 +2385,9 @@ class CatClient(NamespacedClient):
     async def nodeattrs(
         self,
         *,
+        bytes: t.Optional[
+            t.Union[str, t.Literal["b", "gb", "kb", "mb", "pb", "tb"]]
+        ] = None,
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         format: t.Optional[str] = None,
@@ -2189,6 +2415,9 @@ class CatClient(NamespacedClient):
         master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         pretty: t.Optional[bool] = None,
         s: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        time: t.Optional[
+            t.Union[str, t.Literal["d", "h", "m", "micros", "ms", "nanos", "s"]]
+        ] = None,
         v: t.Optional[bool] = None,
     ) -> t.Union[ObjectApiResponse[t.Any], TextApiResponse]:
         """
@@ -2201,6 +2430,14 @@ class CatClient(NamespacedClient):
 
         `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-nodeattrs>`_
 
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: A comma-separated list of columns names to display. It supports simple
@@ -2215,11 +2452,19 @@ class CatClient(NamespacedClient):
         :param s: List of columns that determine how the table should be sorted. Sorting
             defaults to ascending and can be changed by setting `:asc` or `:desc` as
             a suffix to the column name.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str] = {}
         __path = "/_cat/nodeattrs"
         __query: t.Dict[str, t.Any] = {}
+        if bytes is not None:
+            __query["bytes"] = bytes
         if error_trace is not None:
             __query["error_trace"] = error_trace
         if filter_path is not None:
@@ -2240,6 +2485,8 @@ class CatClient(NamespacedClient):
             __query["pretty"] = pretty
         if s is not None:
             __query["s"] = s
+        if time is not None:
+            __query["time"] = time
         if v is not None:
             __query["v"] = v
         __headers = {"accept": "text/plain,application/json"}
@@ -2262,7 +2509,7 @@ class CatClient(NamespacedClient):
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         format: t.Optional[str] = None,
-        full_id: t.Optional[t.Union[bool, str]] = None,
+        full_id: t.Optional[bool] = None,
         h: t.Optional[
             t.Union[
                 t.Sequence[
@@ -2478,7 +2725,14 @@ class CatClient(NamespacedClient):
 
         `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-nodes>`_
 
-        :param bytes: The unit used to display byte values.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param full_id: If `true`, return the full node ID. If `false`, return the shortened
@@ -2493,7 +2747,12 @@ class CatClient(NamespacedClient):
         :param s: A comma-separated list of column names or aliases that determines the
             sort order. Sorting defaults to ascending and can be changed by setting `:asc`
             or `:desc` as a suffix to the column name.
-        :param time: The unit used to display time values.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str] = {}
@@ -2541,6 +2800,9 @@ class CatClient(NamespacedClient):
     async def pending_tasks(
         self,
         *,
+        bytes: t.Optional[
+            t.Union[str, t.Literal["b", "gb", "kb", "mb", "pb", "tb"]]
+        ] = None,
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         format: t.Optional[str] = None,
@@ -2578,6 +2840,14 @@ class CatClient(NamespacedClient):
 
         `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-pending-tasks>`_
 
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: A comma-separated list of columns names to display. It supports simple
@@ -2592,12 +2862,19 @@ class CatClient(NamespacedClient):
         :param s: List of columns that determine how the table should be sorted. Sorting
             defaults to ascending and can be changed by setting `:asc` or `:desc` as
             a suffix to the column name.
-        :param time: Unit used to display time values.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str] = {}
         __path = "/_cat/pending_tasks"
         __query: t.Dict[str, t.Any] = {}
+        if bytes is not None:
+            __query["bytes"] = bytes
         if error_trace is not None:
             __query["error_trace"] = error_trace
         if filter_path is not None:
@@ -2636,6 +2913,9 @@ class CatClient(NamespacedClient):
     async def plugins(
         self,
         *,
+        bytes: t.Optional[
+            t.Union[str, t.Literal["b", "gb", "kb", "mb", "pb", "tb"]]
+        ] = None,
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         format: t.Optional[str] = None,
@@ -2659,6 +2939,9 @@ class CatClient(NamespacedClient):
         master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         pretty: t.Optional[bool] = None,
         s: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        time: t.Optional[
+            t.Union[str, t.Literal["d", "h", "m", "micros", "ms", "nanos", "s"]]
+        ] = None,
         v: t.Optional[bool] = None,
     ) -> t.Union[ObjectApiResponse[t.Any], TextApiResponse]:
         """
@@ -2671,6 +2954,14 @@ class CatClient(NamespacedClient):
 
         `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-plugins>`_
 
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: A comma-separated list of columns names to display. It supports simple
@@ -2686,11 +2977,19 @@ class CatClient(NamespacedClient):
         :param s: List of columns that determine how the table should be sorted. Sorting
             defaults to ascending and can be changed by setting `:asc` or `:desc` as
             a suffix to the column name.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str] = {}
         __path = "/_cat/plugins"
         __query: t.Dict[str, t.Any] = {}
+        if bytes is not None:
+            __query["bytes"] = bytes
         if error_trace is not None:
             __query["error_trace"] = error_trace
         if filter_path is not None:
@@ -2713,6 +3012,8 @@ class CatClient(NamespacedClient):
             __query["pretty"] = pretty
         if s is not None:
             __query["s"] = s
+        if time is not None:
+            __query["time"] = time
         if v is not None:
             __query["v"] = v
         __headers = {"accept": "text/plain,application/json"}
@@ -2831,7 +3132,14 @@ class CatClient(NamespacedClient):
             to limit the request. Supports wildcards (`*`). To target all data streams
             and indices, omit this parameter or use `*` or `_all`.
         :param active_only: If `true`, the response only includes ongoing shard recoveries.
-        :param bytes: The unit used to display byte values.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param detailed: If `true`, the response includes detailed information about
             shard recoveries.
         :param format: Specifies the format to return the columnar data in, can be set
@@ -2843,7 +3151,12 @@ class CatClient(NamespacedClient):
         :param s: A comma-separated list of column names or aliases that determines the
             sort order. Sorting defaults to ascending and can be changed by setting `:asc`
             or `:desc` as a suffix to the column name.
-        :param time: The unit used to display time values.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str]
@@ -2894,6 +3207,9 @@ class CatClient(NamespacedClient):
     async def repositories(
         self,
         *,
+        bytes: t.Optional[
+            t.Union[str, t.Literal["b", "gb", "kb", "mb", "pb", "tb"]]
+        ] = None,
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         format: t.Optional[str] = None,
@@ -2904,6 +3220,9 @@ class CatClient(NamespacedClient):
         master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         pretty: t.Optional[bool] = None,
         s: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        time: t.Optional[
+            t.Union[str, t.Literal["d", "h", "m", "micros", "ms", "nanos", "s"]]
+        ] = None,
         v: t.Optional[bool] = None,
     ) -> t.Union[ObjectApiResponse[t.Any], TextApiResponse]:
         """
@@ -2916,6 +3235,14 @@ class CatClient(NamespacedClient):
 
         `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-repositories>`_
 
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: List of columns to appear in the response. Supports simple wildcards.
@@ -2929,11 +3256,19 @@ class CatClient(NamespacedClient):
         :param s: List of columns that determine how the table should be sorted. Sorting
             defaults to ascending and can be changed by setting `:asc` or `:desc` as
             a suffix to the column name.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str] = {}
         __path = "/_cat/repositories"
         __query: t.Dict[str, t.Any] = {}
+        if bytes is not None:
+            __query["bytes"] = bytes
         if error_trace is not None:
             __query["error_trace"] = error_trace
         if filter_path is not None:
@@ -2954,6 +3289,8 @@ class CatClient(NamespacedClient):
             __query["pretty"] = pretty
         if s is not None:
             __query["s"] = s
+        if time is not None:
+            __query["time"] = time
         if v is not None:
             __query["v"] = v
         __headers = {"accept": "text/plain,application/json"}
@@ -3029,6 +3366,9 @@ class CatClient(NamespacedClient):
         master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         pretty: t.Optional[bool] = None,
         s: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        time: t.Optional[
+            t.Union[str, t.Literal["d", "h", "m", "micros", "ms", "nanos", "s"]]
+        ] = None,
         v: t.Optional[bool] = None,
     ) -> t.Union[ObjectApiResponse[t.Any], TextApiResponse]:
         """
@@ -3045,7 +3385,14 @@ class CatClient(NamespacedClient):
         :param index: A comma-separated list of data streams, indices, and aliases used
             to limit the request. Supports wildcards (`*`). To target all data streams
             and indices, omit this parameter or use `*` or `_all`.
-        :param bytes: The unit used to display byte values.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: A comma-separated list of columns names to display. It supports simple
@@ -3060,6 +3407,12 @@ class CatClient(NamespacedClient):
         :param s: A comma-separated list of column names or aliases that determines the
             sort order. Sorting defaults to ascending and can be changed by setting `:asc`
             or `:desc` as a suffix to the column name.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str]
@@ -3092,6 +3445,8 @@ class CatClient(NamespacedClient):
             __query["pretty"] = pretty
         if s is not None:
             __query["s"] = s
+        if time is not None:
+            __query["time"] = time
         if v is not None:
             __query["v"] = v
         __headers = {"accept": "text/plain,application/json"}
@@ -3295,7 +3650,14 @@ class CatClient(NamespacedClient):
         :param index: A comma-separated list of data streams, indices, and aliases used
             to limit the request. Supports wildcards (`*`). To target all data streams
             and indices, omit this parameter or use `*` or `_all`.
-        :param bytes: The unit used to display byte values.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: List of columns to appear in the response. Supports simple wildcards.
@@ -3305,7 +3667,12 @@ class CatClient(NamespacedClient):
         :param s: A comma-separated list of column names or aliases that determines the
             sort order. Sorting defaults to ascending and can be changed by setting `:asc`
             or `:desc` as a suffix to the column name.
-        :param time: The unit used to display time values.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str]
@@ -3355,6 +3722,9 @@ class CatClient(NamespacedClient):
         self,
         *,
         repository: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        bytes: t.Optional[
+            t.Union[str, t.Literal["b", "gb", "kb", "mb", "pb", "tb"]]
+        ] = None,
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         format: t.Optional[str] = None,
@@ -3425,6 +3795,14 @@ class CatClient(NamespacedClient):
         :param repository: A comma-separated list of snapshot repositories used to limit
             the request. Accepts wildcard expressions. `_all` returns all repositories.
             If any repository fails during the request, Elasticsearch returns an error.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: A comma-separated list of columns names to display. It supports simple
@@ -3437,7 +3815,12 @@ class CatClient(NamespacedClient):
         :param s: List of columns that determine how the table should be sorted. Sorting
             defaults to ascending and can be changed by setting `:asc` or `:desc` as
             a suffix to the column name.
-        :param time: Unit used to display time values.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str]
@@ -3448,6 +3831,8 @@ class CatClient(NamespacedClient):
             __path_parts = {}
             __path = "/_cat/snapshots"
         __query: t.Dict[str, t.Any] = {}
+        if bytes is not None:
+            __query["bytes"] = bytes
         if error_trace is not None:
             __query["error_trace"] = error_trace
         if filter_path is not None:
@@ -3488,6 +3873,9 @@ class CatClient(NamespacedClient):
         self,
         *,
         actions: t.Optional[t.Sequence[str]] = None,
+        bytes: t.Optional[
+            t.Union[str, t.Literal["b", "gb", "kb", "mb", "pb", "tb"]]
+        ] = None,
         detailed: t.Optional[bool] = None,
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
@@ -3562,6 +3950,14 @@ class CatClient(NamespacedClient):
         `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-tasks>`_
 
         :param actions: The task action names, which are used to limit the response.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param detailed: If `true`, the response includes detailed information about
             shard recoveries.
         :param format: Specifies the format to return the columnar data in, can be set
@@ -3576,7 +3972,12 @@ class CatClient(NamespacedClient):
         :param s: List of columns that determine how the table should be sorted. Sorting
             defaults to ascending and can be changed by setting `:asc` or `:desc` as
             a suffix to the column name.
-        :param time: Unit used to display time values.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param timeout: Period to wait for a response. If no response is received before
             the timeout expires, the request fails and returns an error.
         :param v: When set to `true` will enable verbose output.
@@ -3588,6 +3989,8 @@ class CatClient(NamespacedClient):
         __query: t.Dict[str, t.Any] = {}
         if actions is not None:
             __query["actions"] = actions
+        if bytes is not None:
+            __query["bytes"] = bytes
         if detailed is not None:
             __query["detailed"] = detailed
         if error_trace is not None:
@@ -3633,6 +4036,9 @@ class CatClient(NamespacedClient):
         self,
         *,
         name: t.Optional[str] = None,
+        bytes: t.Optional[
+            t.Union[str, t.Literal["b", "gb", "kb", "mb", "pb", "tb"]]
+        ] = None,
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         format: t.Optional[str] = None,
@@ -3660,6 +4066,9 @@ class CatClient(NamespacedClient):
         master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         pretty: t.Optional[bool] = None,
         s: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        time: t.Optional[
+            t.Union[str, t.Literal["d", "h", "m", "micros", "ms", "nanos", "s"]]
+        ] = None,
         v: t.Optional[bool] = None,
     ) -> t.Union[ObjectApiResponse[t.Any], TextApiResponse]:
         """
@@ -3675,6 +4084,14 @@ class CatClient(NamespacedClient):
 
         :param name: The name of the template to return. Accepts wildcard expressions.
             If omitted, all templates are returned.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: A comma-separated list of columns names to display. It supports simple
@@ -3689,6 +4106,12 @@ class CatClient(NamespacedClient):
         :param s: List of columns that determine how the table should be sorted. Sorting
             defaults to ascending and can be changed by setting `:asc` or `:desc` as
             a suffix to the column name.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str]
@@ -3699,6 +4122,8 @@ class CatClient(NamespacedClient):
             __path_parts = {}
             __path = "/_cat/templates"
         __query: t.Dict[str, t.Any] = {}
+        if bytes is not None:
+            __query["bytes"] = bytes
         if error_trace is not None:
             __query["error_trace"] = error_trace
         if filter_path is not None:
@@ -3719,6 +4144,8 @@ class CatClient(NamespacedClient):
             __query["pretty"] = pretty
         if s is not None:
             __query["s"] = s
+        if time is not None:
+            __query["time"] = time
         if v is not None:
             __query["v"] = v
         __headers = {"accept": "text/plain,application/json"}
@@ -3736,6 +4163,9 @@ class CatClient(NamespacedClient):
         self,
         *,
         thread_pool_patterns: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        bytes: t.Optional[
+            t.Union[str, t.Literal["b", "gb", "kb", "mb", "pb", "tb"]]
+        ] = None,
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         format: t.Optional[str] = None,
@@ -3819,6 +4249,14 @@ class CatClient(NamespacedClient):
 
         :param thread_pool_patterns: A comma-separated list of thread pool names used
             to limit the request. Accepts wildcard expressions.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: List of columns to appear in the response. Supports simple wildcards.
@@ -3832,7 +4270,12 @@ class CatClient(NamespacedClient):
         :param s: A comma-separated list of column names or aliases that determines the
             sort order. Sorting defaults to ascending and can be changed by setting `:asc`
             or `:desc` as a suffix to the column name.
-        :param time: The unit used to display time values.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str]
@@ -3843,6 +4286,8 @@ class CatClient(NamespacedClient):
             __path_parts = {}
             __path = "/_cat/thread_pool"
         __query: t.Dict[str, t.Any] = {}
+        if bytes is not None:
+            __query["bytes"] = bytes
         if error_trace is not None:
             __query["error_trace"] = error_trace
         if filter_path is not None:
@@ -3885,6 +4330,9 @@ class CatClient(NamespacedClient):
         *,
         transform_id: t.Optional[str] = None,
         allow_no_match: t.Optional[bool] = None,
+        bytes: t.Optional[
+            t.Union[str, t.Literal["b", "gb", "kb", "mb", "pb", "tb"]]
+        ] = None,
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         format: t.Optional[str] = None,
@@ -4084,6 +4532,14 @@ class CatClient(NamespacedClient):
             array when there are no matches and the subset of results when there are
             partial matches. If `false`, the request returns a 404 status code when there
             are no matches or only partial matches.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param from_: Skips the specified number of transforms.
@@ -4093,7 +4549,12 @@ class CatClient(NamespacedClient):
         :param s: Comma-separated list of column names or column aliases used to sort
             the response.
         :param size: The maximum number of transforms to obtain.
-        :param time: The unit used to display time values.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str]
@@ -4106,6 +4567,8 @@ class CatClient(NamespacedClient):
         __query: t.Dict[str, t.Any] = {}
         if allow_no_match is not None:
             __query["allow_no_match"] = allow_no_match
+        if bytes is not None:
+            __query["bytes"] = bytes
         if error_trace is not None:
             __query["error_trace"] = error_trace
         if filter_path is not None:
diff -pruN 9.1.1-2/elasticsearch/_async/client/cluster.py 9.2.0-1/elasticsearch/_async/client/cluster.py
--- 9.1.1-2/elasticsearch/_async/client/cluster.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_async/client/cluster.py	2025-10-28 16:50:53.000000000 +0000
@@ -49,6 +49,7 @@ class ClusterClient(NamespacedClient):
 
           <p>Explain the shard allocations.
           Get explanations for shard allocations in the cluster.
+          This API accepts the current_node, index, primary and shard parameters in the request body or in query parameters, but not in both at the same time.
           For unassigned shards, it provides an explanation for why the shard is unassigned.
           For assigned shards, it provides an explanation for why the shard is remaining on its current node and has not moved or rebalanced to another node.
           This API can be very useful when attempting to diagnose why a shard is unassigned or why a shard continues to remain on its current node when you might expect otherwise.
@@ -57,17 +58,16 @@ class ClusterClient(NamespacedClient):
 
         `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cluster-allocation-explain>`_
 
-        :param current_node: Specifies the node ID or the name of the node to only explain
-            a shard that is currently located on the specified node.
+        :param current_node: Explain a shard only if it is currently located on the specified
+            node name or node ID.
         :param include_disk_info: If true, returns information about disk usage and shard
             sizes.
         :param include_yes_decisions: If true, returns YES decisions in explanation.
-        :param index: Specifies the name of the index that you would like an explanation
-            for.
+        :param index: The name of the index that you would like an explanation for.
         :param master_timeout: Period to wait for a connection to the master node.
-        :param primary: If true, returns explanation for the primary shard for the given
-            shard ID.
-        :param shard: Specifies the ID of the shard that you would like an explanation
+        :param primary: If true, returns an explanation for the primary shard for the
+            specified shard ID.
+        :param shard: An identifier for the shard that you would like an explanation
             for.
         """
         __path_parts: t.Dict[str, str] = {}
@@ -1124,7 +1124,8 @@ class ClusterClient(NamespacedClient):
             when unavailable (missing or closed)
         :param local: Return local information, do not retrieve the state from master
             node (default: false)
-        :param master_timeout: Specify timeout for connection to master
+        :param master_timeout: Timeout for waiting for new cluster state in case it is
+            blocked
         :param wait_for_metadata_version: Wait for the metadata version to be equal or
             greater than the specified metadata version
         :param wait_for_timeout: The maximum time to wait for wait_for_metadata_version
diff -pruN 9.1.1-2/elasticsearch/_async/client/connector.py 9.2.0-1/elasticsearch/_async/client/connector.py
--- 9.1.1-2/elasticsearch/_async/client/connector.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_async/client/connector.py	2025-10-28 16:50:53.000000000 +0000
@@ -103,7 +103,7 @@ class ConnectorClient(NamespacedClient):
 
         :param connector_id: The unique identifier of the connector to be deleted
         :param delete_sync_jobs: A flag indicating if associated sync jobs should be
-            also removed. Defaults to false.
+            also removed.
         :param hard: A flag indicating if the connector should be hard deleted.
         """
         if connector_id in SKIP_IN_PATH:
@@ -360,7 +360,7 @@ class ConnectorClient(NamespacedClient):
 
         :param connector_name: A comma-separated list of connector names to fetch connector
             documents for
-        :param from_: Starting offset (default: 0)
+        :param from_: Starting offset
         :param include_deleted: A flag to indicate if the desired connector should be
             fetched, even if it was soft-deleted.
         :param index_name: A comma-separated list of connector index names to fetch connector
@@ -955,7 +955,7 @@ class ConnectorClient(NamespacedClient):
         `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-connector-sync-job-list>`_
 
         :param connector_id: A connector id to fetch connector sync jobs for
-        :param from_: Starting offset (default: 0)
+        :param from_: Starting offset
         :param job_type: A comma-separated list of job types to fetch the sync jobs for
         :param size: Specifies a max number of results to get
         :param status: A sync job status to fetch connector sync jobs for
diff -pruN 9.1.1-2/elasticsearch/_async/client/eql.py 9.2.0-1/elasticsearch/_async/client/eql.py
--- 9.1.1-2/elasticsearch/_async/client/eql.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_async/client/eql.py	2025-10-28 16:50:53.000000000 +0000
@@ -229,6 +229,7 @@ class EqlClient(NamespacedClient):
         keep_on_completion: t.Optional[bool] = None,
         max_samples_per_key: t.Optional[int] = None,
         pretty: t.Optional[bool] = None,
+        project_routing: t.Optional[str] = None,
         result_position: t.Optional[t.Union[str, t.Literal["head", "tail"]]] = None,
         runtime_mappings: t.Optional[t.Mapping[str, t.Mapping[str, t.Any]]] = None,
         size: t.Optional[int] = None,
@@ -285,6 +286,10 @@ class EqlClient(NamespacedClient):
             `size` parameter to get a smaller or larger set of samples. To retrieve more
             than one sample per set of join keys, use the `max_samples_per_key` parameter.
             Pipes are not supported for sample queries.
+        :param project_routing: Specifies a subset of projects to target for the search
+            using project metadata tags in a subset of Lucene query syntax. Allowed Lucene
+            queries: the _alias tag and a single value (possibly wildcarded). Examples:
+            _alias:my-project _alias:_origin _alias:*pr* Supported in serverless only.
         :param result_position:
         :param runtime_mappings:
         :param size: For basic queries, the maximum number of matching events to return.
@@ -318,6 +323,8 @@ class EqlClient(NamespacedClient):
             __query["ignore_unavailable"] = ignore_unavailable
         if pretty is not None:
             __query["pretty"] = pretty
+        if project_routing is not None:
+            __query["project_routing"] = project_routing
         if not __body:
             if query is not None:
                 __body["query"] = query
diff -pruN 9.1.1-2/elasticsearch/_async/client/esql.py 9.2.0-1/elasticsearch/_async/client/esql.py
--- 9.1.1-2/elasticsearch/_async/client/esql.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_async/client/esql.py	2025-10-28 16:50:53.000000000 +0000
@@ -40,6 +40,7 @@ class EsqlClient(NamespacedClient):
             "columnar",
             "filter",
             "include_ccs_metadata",
+            "include_execution_metadata",
             "keep_alive",
             "keep_on_completion",
             "locale",
@@ -71,6 +72,7 @@ class EsqlClient(NamespacedClient):
         ] = None,
         human: t.Optional[bool] = None,
         include_ccs_metadata: t.Optional[bool] = None,
+        include_execution_metadata: t.Optional[bool] = None,
         keep_alive: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         keep_on_completion: t.Optional[bool] = None,
         locale: t.Optional[str] = None,
@@ -120,7 +122,11 @@ class EsqlClient(NamespacedClient):
             be returned if the async query doesn't finish within the timeout. The query
             ID and running status are available in the `X-Elasticsearch-Async-Id` and
             `X-Elasticsearch-Async-Is-Running` HTTP headers of the response, respectively.
-        :param include_ccs_metadata: When set to `true` and performing a cross-cluster
+        :param include_ccs_metadata: When set to `true` and performing a cross-cluster/cross-project
+            query, the response will include an extra `_clusters` object with information
+            about the clusters that participated in the search along with info such as
+            shards count.
+        :param include_execution_metadata: When set to `true` and performing a cross-cluster/cross-project
             query, the response will include an extra `_clusters` object with information
             about the clusters that participated in the search along with info such as
             shards count.
@@ -180,6 +186,8 @@ class EsqlClient(NamespacedClient):
                 __body["filter"] = filter
             if include_ccs_metadata is not None:
                 __body["include_ccs_metadata"] = include_ccs_metadata
+            if include_execution_metadata is not None:
+                __body["include_execution_metadata"] = include_execution_metadata
             if keep_alive is not None:
                 __body["keep_alive"] = keep_alive
             if keep_on_completion is not None:
@@ -486,6 +494,7 @@ class EsqlClient(NamespacedClient):
             "columnar",
             "filter",
             "include_ccs_metadata",
+            "include_execution_metadata",
             "locale",
             "params",
             "profile",
@@ -514,8 +523,16 @@ class EsqlClient(NamespacedClient):
         ] = None,
         human: t.Optional[bool] = None,
         include_ccs_metadata: t.Optional[bool] = None,
+        include_execution_metadata: t.Optional[bool] = None,
         locale: t.Optional[str] = None,
-        params: t.Optional[t.Sequence[t.Union[None, bool, float, int, str]]] = None,
+        params: t.Optional[
+            t.Sequence[
+                t.Union[
+                    t.Sequence[t.Union[None, bool, float, int, str]],
+                    t.Union[None, bool, float, int, str],
+                ]
+            ]
+        ] = None,
         pretty: t.Optional[bool] = None,
         profile: t.Optional[bool] = None,
         tables: t.Optional[
@@ -554,7 +571,11 @@ class EsqlClient(NamespacedClient):
         :param format: A short version of the Accept header, e.g. json, yaml. `csv`,
             `tsv`, and `txt` formats will return results in a tabular format, excluding
             other metadata fields from the response.
-        :param include_ccs_metadata: When set to `true` and performing a cross-cluster
+        :param include_ccs_metadata: When set to `true` and performing a cross-cluster/cross-project
+            query, the response will include an extra `_clusters` object with information
+            about the clusters that participated in the search along with info such as
+            shards count.
+        :param include_execution_metadata: When set to `true` and performing a cross-cluster/cross-project
             query, the response will include an extra `_clusters` object with information
             about the clusters that participated in the search along with info such as
             shards count.
@@ -600,6 +621,8 @@ class EsqlClient(NamespacedClient):
                 __body["filter"] = filter
             if include_ccs_metadata is not None:
                 __body["include_ccs_metadata"] = include_ccs_metadata
+            if include_execution_metadata is not None:
+                __body["include_execution_metadata"] = include_execution_metadata
             if locale is not None:
                 __body["locale"] = locale
             if params is not None:
diff -pruN 9.1.1-2/elasticsearch/_async/client/fleet.py 9.2.0-1/elasticsearch/_async/client/fleet.py
--- 9.1.1-2/elasticsearch/_async/client/fleet.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_async/client/fleet.py	2025-10-28 16:50:53.000000000 +0000
@@ -642,11 +642,7 @@ class FleetClient(NamespacedClient):
                 __body["track_total_hits"] = track_total_hits
             if version is not None:
                 __body["version"] = version
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "POST",
             __path,
diff -pruN 9.1.1-2/elasticsearch/_async/client/graph.py 9.2.0-1/elasticsearch/_async/client/graph.py
--- 9.1.1-2/elasticsearch/_async/client/graph.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_async/client/graph.py	2025-10-28 16:50:53.000000000 +0000
@@ -97,11 +97,7 @@ class GraphClient(NamespacedClient):
                 __body["query"] = query
             if vertices is not None:
                 __body["vertices"] = vertices
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "POST",
             __path,
diff -pruN 9.1.1-2/elasticsearch/_async/client/ilm.py 9.2.0-1/elasticsearch/_async/client/ilm.py
--- 9.1.1-2/elasticsearch/_async/client/ilm.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_async/client/ilm.py	2025-10-28 16:50:53.000000000 +0000
@@ -383,11 +383,7 @@ class IlmClient(NamespacedClient):
                 __body["current_step"] = current_step
             if next_step is not None:
                 __body["next_step"] = next_step
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "POST",
             __path,
@@ -453,11 +449,7 @@ class IlmClient(NamespacedClient):
         if not __body:
             if policy is not None:
                 __body["policy"] = policy
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
diff -pruN 9.1.1-2/elasticsearch/_async/client/indices.py 9.2.0-1/elasticsearch/_async/client/indices.py
--- 9.1.1-2/elasticsearch/_async/client/indices.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_async/client/indices.py	2025-10-28 16:50:53.000000000 +0000
@@ -232,11 +232,7 @@ class IndicesClient(NamespacedClient):
                 __body["text"] = text
             if tokenizer is not None:
                 __body["tokenizer"] = tokenizer
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "POST",
             __path,
@@ -812,11 +808,7 @@ class IndicesClient(NamespacedClient):
             raise ValueError("Empty value passed for parameter 'source'")
         if dest in SKIP_IN_PATH:
             raise ValueError("Empty value passed for parameter 'dest'")
-        if create_from is None and body is None:
-            raise ValueError(
-                "Empty value passed for parameters 'create_from' and 'body', one of them should be set."
-            )
-        elif create_from is not None and body is not None:
+        if create_from is not None and body is not None:
             raise ValueError("Cannot set both 'create_from' and 'body'")
         __path_parts: t.Dict[str, str] = {
             "source": _quote(source),
@@ -833,7 +825,11 @@ class IndicesClient(NamespacedClient):
         if pretty is not None:
             __query["pretty"] = pretty
         __body = create_from if create_from is not None else body
-        __headers = {"accept": "application/json", "content-type": "application/json"}
+        if not __body:
+            __body = None
+        __headers = {"accept": "application/json"}
+        if __body is not None:
+            __headers["content-type"] = "application/json"
         return await self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -1393,6 +1389,7 @@ class IndicesClient(NamespacedClient):
           <p>NOTE: The total size of fields of the analyzed shards of the index in the response is usually smaller than the index <code>store_size</code> value because some small metadata files are ignored and some parts of data files might not be scanned by the API.
           Since stored fields are stored together in a compressed format, the sizes of stored fields are also estimates and can be inaccurate.
           The stored size of the <code>_id</code> field is likely underestimated while the <code>_source</code> field is overestimated.</p>
+          <p>For usage examples see the External documentation or refer to <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/index-disk-usage">Analyze the index disk usage example</a> for an example.</p>
 
 
         `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-disk-usage>`_
@@ -2543,6 +2540,57 @@ class IndicesClient(NamespacedClient):
         )
 
     @_rewrite_parameters()
+    async def get_data_stream_mappings(
+        self,
+        *,
+        name: t.Union[str, t.Sequence[str]],
+        error_trace: t.Optional[bool] = None,
+        filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        human: t.Optional[bool] = None,
+        master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
+        pretty: t.Optional[bool] = None,
+    ) -> ObjectApiResponse[t.Any]:
+        """
+        .. raw:: html
+
+          <p>Get data stream mappings.</p>
+          <p>Get mapping information for one or more data streams.</p>
+
+
+        `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-get-data-stream-mappings>`_
+
+        :param name: A comma-separated list of data streams or data stream patterns.
+            Supports wildcards (`*`).
+        :param master_timeout: The period to wait for a connection to the master node.
+            If no response is received before the timeout expires, the request fails
+            and returns an error.
+        """
+        if name in SKIP_IN_PATH:
+            raise ValueError("Empty value passed for parameter 'name'")
+        __path_parts: t.Dict[str, str] = {"name": _quote(name)}
+        __path = f'/_data_stream/{__path_parts["name"]}/_mappings'
+        __query: t.Dict[str, t.Any] = {}
+        if error_trace is not None:
+            __query["error_trace"] = error_trace
+        if filter_path is not None:
+            __query["filter_path"] = filter_path
+        if human is not None:
+            __query["human"] = human
+        if master_timeout is not None:
+            __query["master_timeout"] = master_timeout
+        if pretty is not None:
+            __query["pretty"] = pretty
+        __headers = {"accept": "application/json"}
+        return await self.perform_request(  # type: ignore[return-value]
+            "GET",
+            __path,
+            params=__query,
+            headers=__headers,
+            endpoint_id="indices.get_data_stream_mappings",
+            path_parts=__path_parts,
+        )
+
+    @_rewrite_parameters()
     async def get_data_stream_options(
         self,
         *,
@@ -3638,11 +3686,7 @@ class IndicesClient(NamespacedClient):
                 __body["downsampling"] = downsampling
             if enabled is not None:
                 __body["enabled"] = enabled
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -3654,6 +3698,83 @@ class IndicesClient(NamespacedClient):
         )
 
     @_rewrite_parameters(
+        body_name="mappings",
+    )
+    async def put_data_stream_mappings(
+        self,
+        *,
+        name: t.Union[str, t.Sequence[str]],
+        mappings: t.Optional[t.Mapping[str, t.Any]] = None,
+        body: t.Optional[t.Mapping[str, t.Any]] = None,
+        dry_run: t.Optional[bool] = None,
+        error_trace: t.Optional[bool] = None,
+        filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        human: t.Optional[bool] = None,
+        master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
+        pretty: t.Optional[bool] = None,
+        timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
+    ) -> ObjectApiResponse[t.Any]:
+        """
+        .. raw:: html
+
+          <p>Update data stream mappings.</p>
+          <p>This API can be used to override mappings on specific data streams. These overrides will take precedence over what
+          is specified in the template that the data stream matches. The mapping change is only applied to new write indices
+          that are created during rollover after this API is called. No indices are changed by this API.</p>
+
+
+        `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-put-data-stream-mappings>`_
+
+        :param name: A comma-separated list of data streams or data stream patterns.
+        :param mappings:
+        :param dry_run: If `true`, the request does not actually change the mappings
+            on any data streams. Instead, it simulates changing the settings and reports
+            back to the user what would have happened had these settings actually been
+            applied.
+        :param master_timeout: The period to wait for a connection to the master node.
+            If no response is received before the timeout expires, the request fails
+            and returns an error.
+        :param timeout: The period to wait for a response. If no response is received
+            before the timeout expires, the request fails and returns an error.
+        """
+        if name in SKIP_IN_PATH:
+            raise ValueError("Empty value passed for parameter 'name'")
+        if mappings is None and body is None:
+            raise ValueError(
+                "Empty value passed for parameters 'mappings' and 'body', one of them should be set."
+            )
+        elif mappings is not None and body is not None:
+            raise ValueError("Cannot set both 'mappings' and 'body'")
+        __path_parts: t.Dict[str, str] = {"name": _quote(name)}
+        __path = f'/_data_stream/{__path_parts["name"]}/_mappings'
+        __query: t.Dict[str, t.Any] = {}
+        if dry_run is not None:
+            __query["dry_run"] = dry_run
+        if error_trace is not None:
+            __query["error_trace"] = error_trace
+        if filter_path is not None:
+            __query["filter_path"] = filter_path
+        if human is not None:
+            __query["human"] = human
+        if master_timeout is not None:
+            __query["master_timeout"] = master_timeout
+        if pretty is not None:
+            __query["pretty"] = pretty
+        if timeout is not None:
+            __query["timeout"] = timeout
+        __body = mappings if mappings is not None else body
+        __headers = {"accept": "application/json", "content-type": "application/json"}
+        return await self.perform_request(  # type: ignore[return-value]
+            "PUT",
+            __path,
+            params=__query,
+            headers=__headers,
+            body=__body,
+            endpoint_id="indices.put_data_stream_mappings",
+            path_parts=__path_parts,
+        )
+
+    @_rewrite_parameters(
         body_fields=("failure_store",),
     )
     async def put_data_stream_options(
@@ -3721,11 +3842,7 @@ class IndicesClient(NamespacedClient):
         if not __body:
             if failure_store is not None:
                 __body["failure_store"] = failure_store
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -4549,6 +4666,7 @@ class IndicesClient(NamespacedClient):
           For data streams, the API runs the refresh operation on the stream’s backing indices.</p>
           <p>By default, Elasticsearch periodically refreshes indices every second, but only on indices that have received one search request or more in the last 30 seconds.
           You can change this default interval with the <code>index.refresh_interval</code> setting.</p>
+          <p>In Elastic Cloud Serverless, the default refresh interval is 5 seconds across all indices.</p>
           <p>Refresh requests are synchronous and do not return a response until the refresh operation completes.</p>
           <p>Refreshes are resource-intensive.
           To ensure good cluster performance, it's recommended to wait for Elasticsearch's periodic refresh rather than performing an explicit refresh when possible.</p>
@@ -4937,7 +5055,18 @@ class IndicesClient(NamespacedClient):
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         human: t.Optional[bool] = None,
         ignore_unavailable: t.Optional[bool] = None,
+        mode: t.Optional[
+            t.Union[
+                t.Sequence[
+                    t.Union[
+                        str, t.Literal["logsdb", "lookup", "standard", "time_series"]
+                    ]
+                ],
+                t.Union[str, t.Literal["logsdb", "lookup", "standard", "time_series"]],
+            ]
+        ] = None,
         pretty: t.Optional[bool] = None,
+        project_routing: t.Optional[str] = None,
     ) -> ObjectApiResponse[t.Any]:
         """
         .. raw:: html
@@ -4963,6 +5092,12 @@ class IndicesClient(NamespacedClient):
             as `open,hidden`.
         :param ignore_unavailable: If `false`, the request returns an error if it targets
             a missing or closed index.
+        :param mode: Filter indices by index mode - standard, lookup, time_series, etc.
+            Comma-separated list of IndexMode. Empty means no filter.
+        :param project_routing: Specifies a subset of projects to target using project
+            metadata tags in a subset of Lucene query syntax. Allowed Lucene queries:
+            the _alias tag and a single value (possibly wildcarded). Examples: _alias:my-project
+            _alias:_origin _alias:*pr* Supported in serverless only.
         """
         if name in SKIP_IN_PATH:
             raise ValueError("Empty value passed for parameter 'name'")
@@ -4981,8 +5116,12 @@ class IndicesClient(NamespacedClient):
             __query["human"] = human
         if ignore_unavailable is not None:
             __query["ignore_unavailable"] = ignore_unavailable
+        if mode is not None:
+            __query["mode"] = mode
         if pretty is not None:
             __query["pretty"] = pretty
+        if project_routing is not None:
+            __query["project_routing"] = project_routing
         __headers = {"accept": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "GET",
@@ -5022,7 +5161,7 @@ class IndicesClient(NamespacedClient):
         .. raw:: html
 
           <p>Roll over to a new index.
-          TIP: It is recommended to use the index lifecycle rollover action to automate rollovers.</p>
+          TIP: We recommend using the index lifecycle rollover action to automate rollovers. However, Serverless does not support Index Lifecycle Management (ILM), so don't use this approach in the Serverless context.</p>
           <p>The rollover API creates a new index for a data stream or index alias.
           The API behavior depends on the rollover target.</p>
           <p><strong>Roll over a data stream</strong></p>
@@ -5399,11 +5538,7 @@ class IndicesClient(NamespacedClient):
                 __body["aliases"] = aliases
             if settings is not None:
                 __body["settings"] = settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -5414,7 +5549,9 @@ class IndicesClient(NamespacedClient):
             path_parts=__path_parts,
         )
 
-    @_rewrite_parameters()
+    @_rewrite_parameters(
+        body_name="index_template",
+    )
     async def simulate_index_template(
         self,
         *,
@@ -5425,6 +5562,8 @@ class IndicesClient(NamespacedClient):
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         human: t.Optional[bool] = None,
         include_defaults: t.Optional[bool] = None,
+        index_template: t.Optional[t.Mapping[str, t.Any]] = None,
+        body: t.Optional[t.Mapping[str, t.Any]] = None,
         master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         pretty: t.Optional[bool] = None,
     ) -> ObjectApiResponse[t.Any]:
@@ -5444,12 +5583,15 @@ class IndicesClient(NamespacedClient):
             only be dry-run added if new or can also replace an existing one
         :param include_defaults: If true, returns all relevant default configurations
             for the index template.
+        :param index_template:
         :param master_timeout: Period to wait for a connection to the master node. If
             no response is received before the timeout expires, the request fails and
             returns an error.
         """
         if name in SKIP_IN_PATH:
             raise ValueError("Empty value passed for parameter 'name'")
+        if index_template is not None and body is not None:
+            raise ValueError("Cannot set both 'index_template' and 'body'")
         __path_parts: t.Dict[str, str] = {"name": _quote(name)}
         __path = f'/_index_template/_simulate_index/{__path_parts["name"]}'
         __query: t.Dict[str, t.Any] = {}
@@ -5469,12 +5611,18 @@ class IndicesClient(NamespacedClient):
             __query["master_timeout"] = master_timeout
         if pretty is not None:
             __query["pretty"] = pretty
+        __body = index_template if index_template is not None else body
+        if not __body:
+            __body = None
         __headers = {"accept": "application/json"}
+        if __body is not None:
+            __headers["content-type"] = "application/json"
         return await self.perform_request(  # type: ignore[return-value]
             "POST",
             __path,
             params=__query,
             headers=__headers,
+            body=__body,
             endpoint_id="indices.simulate_index_template",
             path_parts=__path_parts,
         )
@@ -5742,11 +5890,7 @@ class IndicesClient(NamespacedClient):
                 __body["aliases"] = aliases
             if settings is not None:
                 __body["settings"] = settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -5823,8 +5967,8 @@ class IndicesClient(NamespacedClient):
             are requested).
         :param include_unloaded_segments: If true, the response includes information
             from segments that are not loaded into memory.
-        :param level: Indicates whether statistics are aggregated at the cluster, index,
-            or shard level.
+        :param level: Indicates whether statistics are aggregated at the cluster, indices,
+            or shards level.
         """
         __path_parts: t.Dict[str, str]
         if index not in SKIP_IN_PATH and metric not in SKIP_IN_PATH:
@@ -5990,8 +6134,8 @@ class IndicesClient(NamespacedClient):
         :param analyze_wildcard: If `true`, wildcard and prefix queries are analyzed.
         :param analyzer: Analyzer to use for the query string. This parameter can only
             be used when the `q` query string parameter is specified.
-        :param default_operator: The default operator for query string query: `AND` or
-            `OR`.
+        :param default_operator: The default operator for query string query: `and` or
+            `or`.
         :param df: Field to use as default where no field prefix is given in the query
             string. This parameter can only be used when the `q` query string parameter
             is specified.
diff -pruN 9.1.1-2/elasticsearch/_async/client/inference.py 9.2.0-1/elasticsearch/_async/client/inference.py
--- 9.1.1-2/elasticsearch/_async/client/inference.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_async/client/inference.py	2025-10-28 16:50:53.000000000 +0000
@@ -78,11 +78,7 @@ class InferenceClient(NamespacedClient):
                 __body["input"] = input
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "POST",
             __path,
@@ -338,11 +334,7 @@ class InferenceClient(NamespacedClient):
                 __body["query"] = query
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "POST",
             __path,
@@ -389,11 +381,12 @@ class InferenceClient(NamespacedClient):
           However, if you do not plan to use the inference APIs to use these models or if you want to use non-NLP models, use the machine learning trained model APIs.</p>
           <p>The following integrations are available through the inference API. You can find the available task types next to the integration name:</p>
           <ul>
+          <li>AI21 (<code>chat_completion</code>, <code>completion</code>)</li>
           <li>AlibabaCloud AI Search (<code>completion</code>, <code>rerank</code>, <code>sparse_embedding</code>, <code>text_embedding</code>)</li>
           <li>Amazon Bedrock (<code>completion</code>, <code>text_embedding</code>)</li>
           <li>Amazon SageMaker (<code>chat_completion</code>, <code>completion</code>, <code>rerank</code>, <code>sparse_embedding</code>, <code>text_embedding</code>)</li>
           <li>Anthropic (<code>completion</code>)</li>
-          <li>Azure AI Studio (<code>completion</code>, <code>text_embedding</code>)</li>
+          <li>Azure AI Studio (<code>completion</code>, 'rerank', <code>text_embedding</code>)</li>
           <li>Azure OpenAI (<code>completion</code>, <code>text_embedding</code>)</li>
           <li>Cohere (<code>completion</code>, <code>rerank</code>, <code>text_embedding</code>)</li>
           <li>DeepSeek (<code>chat_completion</code>, <code>completion</code>)</li>
@@ -464,6 +457,82 @@ class InferenceClient(NamespacedClient):
         )
 
     @_rewrite_parameters(
+        body_fields=("service", "service_settings"),
+    )
+    async def put_ai21(
+        self,
+        *,
+        task_type: t.Union[str, t.Literal["chat_completion", "completion"]],
+        ai21_inference_id: str,
+        service: t.Optional[t.Union[str, t.Literal["ai21"]]] = None,
+        service_settings: t.Optional[t.Mapping[str, t.Any]] = None,
+        error_trace: t.Optional[bool] = None,
+        filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        human: t.Optional[bool] = None,
+        pretty: t.Optional[bool] = None,
+        timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
+        body: t.Optional[t.Dict[str, t.Any]] = None,
+    ) -> ObjectApiResponse[t.Any]:
+        """
+        .. raw:: html
+
+          <p>Create a AI21 inference endpoint.</p>
+          <p>Create an inference endpoint to perform an inference task with the <code>ai21</code> service.</p>
+
+
+        `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-put-ai21>`_
+
+        :param task_type: The type of the inference task that the model will perform.
+        :param ai21_inference_id: The unique identifier of the inference endpoint.
+        :param service: The type of service supported for the specified task type. In
+            this case, `ai21`.
+        :param service_settings: Settings used to install the inference model. These
+            settings are specific to the `ai21` service.
+        :param timeout: Specifies the amount of time to wait for the inference endpoint
+            to be created.
+        """
+        if task_type in SKIP_IN_PATH:
+            raise ValueError("Empty value passed for parameter 'task_type'")
+        if ai21_inference_id in SKIP_IN_PATH:
+            raise ValueError("Empty value passed for parameter 'ai21_inference_id'")
+        if service is None and body is None:
+            raise ValueError("Empty value passed for parameter 'service'")
+        if service_settings is None and body is None:
+            raise ValueError("Empty value passed for parameter 'service_settings'")
+        __path_parts: t.Dict[str, str] = {
+            "task_type": _quote(task_type),
+            "ai21_inference_id": _quote(ai21_inference_id),
+        }
+        __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["ai21_inference_id"]}'
+        __query: t.Dict[str, t.Any] = {}
+        __body: t.Dict[str, t.Any] = body if body is not None else {}
+        if error_trace is not None:
+            __query["error_trace"] = error_trace
+        if filter_path is not None:
+            __query["filter_path"] = filter_path
+        if human is not None:
+            __query["human"] = human
+        if pretty is not None:
+            __query["pretty"] = pretty
+        if timeout is not None:
+            __query["timeout"] = timeout
+        if not __body:
+            if service is not None:
+                __body["service"] = service
+            if service_settings is not None:
+                __body["service_settings"] = service_settings
+        __headers = {"accept": "application/json", "content-type": "application/json"}
+        return await self.perform_request(  # type: ignore[return-value]
+            "PUT",
+            __path,
+            params=__query,
+            headers=__headers,
+            body=__body,
+            endpoint_id="inference.put_ai21",
+            path_parts=__path_parts,
+        )
+
+    @_rewrite_parameters(
         body_fields=(
             "service",
             "service_settings",
@@ -546,11 +615,7 @@ class InferenceClient(NamespacedClient):
                 __body["chunking_settings"] = chunking_settings
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -646,11 +711,7 @@ class InferenceClient(NamespacedClient):
                 __body["chunking_settings"] = chunking_settings
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -752,11 +813,7 @@ class InferenceClient(NamespacedClient):
                 __body["chunking_settings"] = chunking_settings
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -849,11 +906,7 @@ class InferenceClient(NamespacedClient):
                 __body["chunking_settings"] = chunking_settings
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -875,7 +928,7 @@ class InferenceClient(NamespacedClient):
     async def put_azureaistudio(
         self,
         *,
-        task_type: t.Union[str, t.Literal["completion", "text_embedding"]],
+        task_type: t.Union[str, t.Literal["completion", "rerank", "text_embedding"]],
         azureaistudio_inference_id: str,
         service: t.Optional[t.Union[str, t.Literal["azureaistudio"]]] = None,
         service_settings: t.Optional[t.Mapping[str, t.Any]] = None,
@@ -945,11 +998,7 @@ class InferenceClient(NamespacedClient):
                 __body["chunking_settings"] = chunking_settings
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -1049,11 +1098,7 @@ class InferenceClient(NamespacedClient):
                 __body["chunking_settings"] = chunking_settings
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -1143,11 +1188,7 @@ class InferenceClient(NamespacedClient):
                 __body["chunking_settings"] = chunking_settings
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -1166,6 +1207,99 @@ class InferenceClient(NamespacedClient):
             "task_settings",
         ),
     )
+    async def put_contextualai(
+        self,
+        *,
+        task_type: t.Union[str, t.Literal["rerank"]],
+        contextualai_inference_id: str,
+        service: t.Optional[t.Union[str, t.Literal["contextualai"]]] = None,
+        service_settings: t.Optional[t.Mapping[str, t.Any]] = None,
+        chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None,
+        error_trace: t.Optional[bool] = None,
+        filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        human: t.Optional[bool] = None,
+        pretty: t.Optional[bool] = None,
+        task_settings: t.Optional[t.Mapping[str, t.Any]] = None,
+        timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
+        body: t.Optional[t.Dict[str, t.Any]] = None,
+    ) -> ObjectApiResponse[t.Any]:
+        """
+        .. raw:: html
+
+          <p>Create an Contextual AI inference endpoint.</p>
+          <p>Create an inference endpoint to perform an inference task with the <code>contexualai</code> service.</p>
+          <p>To review the available <code>rerank</code> models, refer to <a href="https://docs.contextual.ai/api-reference/rerank/rerank#body-model">https://docs.contextual.ai/api-reference/rerank/rerank#body-model</a>.</p>
+
+
+        `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-put-contextualai>`_
+
+        :param task_type: The type of the inference task that the model will perform.
+        :param contextualai_inference_id: The unique identifier of the inference endpoint.
+        :param service: The type of service supported for the specified task type. In
+            this case, `contextualai`.
+        :param service_settings: Settings used to install the inference model. These
+            settings are specific to the `contextualai` service.
+        :param chunking_settings: The chunking configuration object.
+        :param task_settings: Settings to configure the inference task. These settings
+            are specific to the task type you specified.
+        :param timeout: Specifies the amount of time to wait for the inference endpoint
+            to be created.
+        """
+        if task_type in SKIP_IN_PATH:
+            raise ValueError("Empty value passed for parameter 'task_type'")
+        if contextualai_inference_id in SKIP_IN_PATH:
+            raise ValueError(
+                "Empty value passed for parameter 'contextualai_inference_id'"
+            )
+        if service is None and body is None:
+            raise ValueError("Empty value passed for parameter 'service'")
+        if service_settings is None and body is None:
+            raise ValueError("Empty value passed for parameter 'service_settings'")
+        __path_parts: t.Dict[str, str] = {
+            "task_type": _quote(task_type),
+            "contextualai_inference_id": _quote(contextualai_inference_id),
+        }
+        __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["contextualai_inference_id"]}'
+        __query: t.Dict[str, t.Any] = {}
+        __body: t.Dict[str, t.Any] = body if body is not None else {}
+        if error_trace is not None:
+            __query["error_trace"] = error_trace
+        if filter_path is not None:
+            __query["filter_path"] = filter_path
+        if human is not None:
+            __query["human"] = human
+        if pretty is not None:
+            __query["pretty"] = pretty
+        if timeout is not None:
+            __query["timeout"] = timeout
+        if not __body:
+            if service is not None:
+                __body["service"] = service
+            if service_settings is not None:
+                __body["service_settings"] = service_settings
+            if chunking_settings is not None:
+                __body["chunking_settings"] = chunking_settings
+            if task_settings is not None:
+                __body["task_settings"] = task_settings
+        __headers = {"accept": "application/json", "content-type": "application/json"}
+        return await self.perform_request(  # type: ignore[return-value]
+            "PUT",
+            __path,
+            params=__query,
+            headers=__headers,
+            body=__body,
+            endpoint_id="inference.put_contextualai",
+            path_parts=__path_parts,
+        )
+
+    @_rewrite_parameters(
+        body_fields=(
+            "service",
+            "service_settings",
+            "chunking_settings",
+            "task_settings",
+        ),
+    )
     async def put_custom(
         self,
         *,
@@ -1274,11 +1408,7 @@ class InferenceClient(NamespacedClient):
                 __body["chunking_settings"] = chunking_settings
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -1358,11 +1488,7 @@ class InferenceClient(NamespacedClient):
                 __body["service_settings"] = service_settings
             if chunking_settings is not None:
                 __body["chunking_settings"] = chunking_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -1470,11 +1596,7 @@ class InferenceClient(NamespacedClient):
                 __body["chunking_settings"] = chunking_settings
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -1532,7 +1654,8 @@ class InferenceClient(NamespacedClient):
             this case, `elser`.
         :param service_settings: Settings used to install the inference model. These
             settings are specific to the `elser` service.
-        :param chunking_settings: The chunking configuration object.
+        :param chunking_settings: The chunking configuration object. Note that for ELSER
+            endpoints, the max_chunk_size may not exceed `300`.
         :param timeout: Specifies the amount of time to wait for the inference endpoint
             to be created.
         """
@@ -1568,11 +1691,7 @@ class InferenceClient(NamespacedClient):
                 __body["service_settings"] = service_settings
             if chunking_settings is not None:
                 __body["chunking_settings"] = chunking_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -1654,11 +1773,7 @@ class InferenceClient(NamespacedClient):
                 __body["service_settings"] = service_settings
             if chunking_settings is not None:
                 __body["chunking_settings"] = chunking_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -1752,11 +1867,7 @@ class InferenceClient(NamespacedClient):
                 __body["chunking_settings"] = chunking_settings
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -1884,11 +1995,7 @@ class InferenceClient(NamespacedClient):
                 __body["chunking_settings"] = chunking_settings
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -1980,11 +2087,7 @@ class InferenceClient(NamespacedClient):
                 __body["chunking_settings"] = chunking_settings
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -1998,6 +2101,88 @@ class InferenceClient(NamespacedClient):
     @_rewrite_parameters(
         body_fields=("service", "service_settings", "chunking_settings"),
     )
+    async def put_llama(
+        self,
+        *,
+        task_type: t.Union[
+            str, t.Literal["chat_completion", "completion", "text_embedding"]
+        ],
+        llama_inference_id: str,
+        service: t.Optional[t.Union[str, t.Literal["llama"]]] = None,
+        service_settings: t.Optional[t.Mapping[str, t.Any]] = None,
+        chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None,
+        error_trace: t.Optional[bool] = None,
+        filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        human: t.Optional[bool] = None,
+        pretty: t.Optional[bool] = None,
+        timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
+        body: t.Optional[t.Dict[str, t.Any]] = None,
+    ) -> ObjectApiResponse[t.Any]:
+        """
+        .. raw:: html
+
+          <p>Create a Llama inference endpoint.</p>
+          <p>Create an inference endpoint to perform an inference task with the <code>llama</code> service.</p>
+
+
+        `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-put-llama>`_
+
+        :param task_type: The type of the inference task that the model will perform.
+        :param llama_inference_id: The unique identifier of the inference endpoint.
+        :param service: The type of service supported for the specified task type. In
+            this case, `llama`.
+        :param service_settings: Settings used to install the inference model. These
+            settings are specific to the `llama` service.
+        :param chunking_settings: The chunking configuration object.
+        :param timeout: Specifies the amount of time to wait for the inference endpoint
+            to be created.
+        """
+        if task_type in SKIP_IN_PATH:
+            raise ValueError("Empty value passed for parameter 'task_type'")
+        if llama_inference_id in SKIP_IN_PATH:
+            raise ValueError("Empty value passed for parameter 'llama_inference_id'")
+        if service is None and body is None:
+            raise ValueError("Empty value passed for parameter 'service'")
+        if service_settings is None and body is None:
+            raise ValueError("Empty value passed for parameter 'service_settings'")
+        __path_parts: t.Dict[str, str] = {
+            "task_type": _quote(task_type),
+            "llama_inference_id": _quote(llama_inference_id),
+        }
+        __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["llama_inference_id"]}'
+        __query: t.Dict[str, t.Any] = {}
+        __body: t.Dict[str, t.Any] = body if body is not None else {}
+        if error_trace is not None:
+            __query["error_trace"] = error_trace
+        if filter_path is not None:
+            __query["filter_path"] = filter_path
+        if human is not None:
+            __query["human"] = human
+        if pretty is not None:
+            __query["pretty"] = pretty
+        if timeout is not None:
+            __query["timeout"] = timeout
+        if not __body:
+            if service is not None:
+                __body["service"] = service
+            if service_settings is not None:
+                __body["service_settings"] = service_settings
+            if chunking_settings is not None:
+                __body["chunking_settings"] = chunking_settings
+        __headers = {"accept": "application/json", "content-type": "application/json"}
+        return await self.perform_request(  # type: ignore[return-value]
+            "PUT",
+            __path,
+            params=__query,
+            headers=__headers,
+            body=__body,
+            endpoint_id="inference.put_llama",
+            path_parts=__path_parts,
+        )
+
+    @_rewrite_parameters(
+        body_fields=("service", "service_settings", "chunking_settings"),
+    )
     async def put_mistral(
         self,
         *,
@@ -2066,11 +2251,7 @@ class InferenceClient(NamespacedClient):
                 __body["service_settings"] = service_settings
             if chunking_settings is not None:
                 __body["chunking_settings"] = chunking_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -2164,11 +2345,7 @@ class InferenceClient(NamespacedClient):
                 __body["chunking_settings"] = chunking_settings
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -2259,11 +2436,7 @@ class InferenceClient(NamespacedClient):
                 __body["chunking_settings"] = chunking_settings
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -2343,11 +2516,7 @@ class InferenceClient(NamespacedClient):
                 __body["service"] = service
             if service_settings is not None:
                 __body["service_settings"] = service_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -2420,11 +2589,7 @@ class InferenceClient(NamespacedClient):
                 __body["query"] = query
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "POST",
             __path,
@@ -2488,11 +2653,7 @@ class InferenceClient(NamespacedClient):
                 __body["input"] = input
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "POST",
             __path,
@@ -2504,7 +2665,7 @@ class InferenceClient(NamespacedClient):
         )
 
     @_rewrite_parameters(
-        body_fields=("input", "task_settings"),
+        body_fields=("input", "input_type", "task_settings"),
     )
     async def text_embedding(
         self,
@@ -2514,6 +2675,7 @@ class InferenceClient(NamespacedClient):
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         human: t.Optional[bool] = None,
+        input_type: t.Optional[str] = None,
         pretty: t.Optional[bool] = None,
         task_settings: t.Optional[t.Any] = None,
         timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
@@ -2529,6 +2691,13 @@ class InferenceClient(NamespacedClient):
 
         :param inference_id: The inference Id
         :param input: Inference input. Either a string or an array of strings.
+        :param input_type: The input data type for the text embedding model. Possible
+            values include: * `SEARCH` * `INGEST` * `CLASSIFICATION` * `CLUSTERING` Not
+            all services support all values. Unsupported values will trigger a validation
+            exception. Accepted values depend on the configured inference service, refer
+            to the relevant service-specific documentation for more info. > info > The
+            `input_type` parameter specified on the root level of the request body will
+            take precedence over the `input_type` parameter specified in `task_settings`.
         :param task_settings: Optional task settings
         :param timeout: Specifies the amount of time to wait for the inference request
             to complete.
@@ -2554,13 +2723,11 @@ class InferenceClient(NamespacedClient):
         if not __body:
             if input is not None:
                 __body["input"] = input
+            if input_type is not None:
+                __body["input_type"] = input_type
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "POST",
             __path,
diff -pruN 9.1.1-2/elasticsearch/_async/client/ingest.py 9.2.0-1/elasticsearch/_async/client/ingest.py
--- 9.1.1-2/elasticsearch/_async/client/ingest.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_async/client/ingest.py	2025-10-28 16:50:53.000000000 +0000
@@ -580,6 +580,7 @@ class IngestClient(NamespacedClient):
         body_fields=(
             "deprecated",
             "description",
+            "field_access_pattern",
             "meta",
             "on_failure",
             "processors",
@@ -594,6 +595,9 @@ class IngestClient(NamespacedClient):
         deprecated: t.Optional[bool] = None,
         description: t.Optional[str] = None,
         error_trace: t.Optional[bool] = None,
+        field_access_pattern: t.Optional[
+            t.Union[str, t.Literal["classic", "flexible"]]
+        ] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         human: t.Optional[bool] = None,
         if_version: t.Optional[int] = None,
@@ -621,6 +625,8 @@ class IngestClient(NamespacedClient):
             or updating a non-deprecated index template, Elasticsearch will emit a deprecation
             warning.
         :param description: Description of the ingest pipeline.
+        :param field_access_pattern: Controls how processors in this pipeline should
+            read and write data on a document's source.
         :param if_version: Required version for optimistic concurrency control for pipeline
             updates
         :param master_timeout: Period to wait for a connection to the master node. If
@@ -667,6 +673,8 @@ class IngestClient(NamespacedClient):
                 __body["deprecated"] = deprecated
             if description is not None:
                 __body["description"] = description
+            if field_access_pattern is not None:
+                __body["field_access_pattern"] = field_access_pattern
             if meta is not None:
                 __body["_meta"] = meta
             if on_failure is not None:
diff -pruN 9.1.1-2/elasticsearch/_async/client/license.py 9.2.0-1/elasticsearch/_async/client/license.py
--- 9.1.1-2/elasticsearch/_async/client/license.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_async/client/license.py	2025-10-28 16:50:53.000000000 +0000
@@ -104,8 +104,10 @@ class LicenseClient(NamespacedClient):
             license types. If `false`, this parameter returns platinum for both platinum
             and enterprise license types. This behavior is maintained for backwards compatibility.
             This parameter is deprecated and will always be set to true in 8.x.
-        :param local: Specifies whether to retrieve local information. The default value
-            is `false`, which means the information is retrieved from the master node.
+        :param local: Specifies whether to retrieve local information. From 9.2 onwards
+            the default value is `true`, which means the information is retrieved from
+            the responding node. In earlier versions the default is `false`, which means
+            the information is retrieved from the elected master node.
         """
         __path_parts: t.Dict[str, str] = {}
         __path = "/_license"
diff -pruN 9.1.1-2/elasticsearch/_async/client/logstash.py 9.2.0-1/elasticsearch/_async/client/logstash.py
--- 9.1.1-2/elasticsearch/_async/client/logstash.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_async/client/logstash.py	2025-10-28 16:50:53.000000000 +0000
@@ -141,7 +141,9 @@ class LogstashClient(NamespacedClient):
 
         `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-logstash-put-pipeline>`_
 
-        :param id: An identifier for the pipeline.
+        :param id: An identifier for the pipeline. Pipeline IDs must begin with a letter
+            or underscore and contain only letters, underscores, dashes, hyphens and
+            numbers.
         :param pipeline:
         """
         if id in SKIP_IN_PATH:
diff -pruN 9.1.1-2/elasticsearch/_async/client/ml.py 9.2.0-1/elasticsearch/_async/client/ml.py
--- 9.1.1-2/elasticsearch/_async/client/ml.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_async/client/ml.py	2025-10-28 16:50:53.000000000 +0000
@@ -2390,7 +2390,7 @@ class MlClient(NamespacedClient):
         exclude_interim: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         human: t.Optional[bool] = None,
-        overall_score: t.Optional[t.Union[float, str]] = None,
+        overall_score: t.Optional[float] = None,
         pretty: t.Optional[bool] = None,
         start: t.Optional[t.Union[str, t.Any]] = None,
         top_n: t.Optional[int] = None,
@@ -5716,7 +5716,7 @@ class MlClient(NamespacedClient):
           <p>Validate an anomaly detection job.</p>
 
 
-        `<https://www.elastic.co/guide/en/machine-learning/9.1/ml-jobs.html>`_
+        `<https://www.elastic.co/guide/en/machine-learning/9.2/ml-jobs.html>`_
 
         :param analysis_config:
         :param analysis_limits:
diff -pruN 9.1.1-2/elasticsearch/_async/client/nodes.py 9.2.0-1/elasticsearch/_async/client/nodes.py
--- 9.1.1-2/elasticsearch/_async/client/nodes.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_async/client/nodes.py	2025-10-28 16:50:53.000000000 +0000
@@ -368,9 +368,7 @@ class NodesClient(NamespacedClient):
         human: t.Optional[bool] = None,
         include_segment_file_sizes: t.Optional[bool] = None,
         include_unloaded_segments: t.Optional[bool] = None,
-        level: t.Optional[
-            t.Union[str, t.Literal["cluster", "indices", "shards"]]
-        ] = None,
+        level: t.Optional[t.Union[str, t.Literal["indices", "node", "shards"]]] = None,
         pretty: t.Optional[bool] = None,
         timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         types: t.Optional[t.Sequence[str]] = None,
@@ -404,8 +402,8 @@ class NodesClient(NamespacedClient):
             are requested).
         :param include_unloaded_segments: If `true`, the response includes information
             from segments that are not loaded into memory.
-        :param level: Indicates whether statistics are aggregated at the cluster, index,
-            or shard level.
+        :param level: Indicates whether statistics are aggregated at the node, indices,
+            or shards level.
         :param timeout: Period to wait for a response. If no response is received before
             the timeout expires, the request fails and returns an error.
         :param types: A comma-separated list of document types for the indexing index
diff -pruN 9.1.1-2/elasticsearch/_async/client/project.py 9.2.0-1/elasticsearch/_async/client/project.py
--- 9.1.1-2/elasticsearch/_async/client/project.py	1970-01-01 00:00:00.000000000 +0000
+++ 9.2.0-1/elasticsearch/_async/client/project.py	2025-10-28 16:50:53.000000000 +0000
@@ -0,0 +1,67 @@
+#  Licensed to Elasticsearch B.V. under one or more contributor
+#  license agreements. See the NOTICE file distributed with
+#  this work for additional information regarding copyright
+#  ownership. Elasticsearch B.V. licenses this file to you under
+#  the Apache License, Version 2.0 (the "License"); you may
+#  not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+# 	http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing,
+#  software distributed under the License is distributed on an
+#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#  KIND, either express or implied.  See the License for the
+#  specific language governing permissions and limitations
+#  under the License.
+
+import typing as t
+
+from elastic_transport import ObjectApiResponse
+
+from ._base import NamespacedClient
+from .utils import (
+    Stability,
+    _rewrite_parameters,
+    _stability_warning,
+)
+
+
+class ProjectClient(NamespacedClient):
+
+    @_rewrite_parameters()
+    @_stability_warning(Stability.EXPERIMENTAL)
+    async def tags(
+        self,
+        *,
+        error_trace: t.Optional[bool] = None,
+        filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        human: t.Optional[bool] = None,
+        pretty: t.Optional[bool] = None,
+    ) -> ObjectApiResponse[t.Any]:
+        """
+        .. raw:: html
+
+          <p>Return tags defined for the project</p>
+
+        """
+        __path_parts: t.Dict[str, str] = {}
+        __path = "/_project/tags"
+        __query: t.Dict[str, t.Any] = {}
+        if error_trace is not None:
+            __query["error_trace"] = error_trace
+        if filter_path is not None:
+            __query["filter_path"] = filter_path
+        if human is not None:
+            __query["human"] = human
+        if pretty is not None:
+            __query["pretty"] = pretty
+        __headers = {"accept": "application/json"}
+        return await self.perform_request(  # type: ignore[return-value]
+            "GET",
+            __path,
+            params=__query,
+            headers=__headers,
+            endpoint_id="project.tags",
+            path_parts=__path_parts,
+        )
diff -pruN 9.1.1-2/elasticsearch/_async/client/security.py 9.2.0-1/elasticsearch/_async/client/security.py
--- 9.1.1-2/elasticsearch/_async/client/security.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_async/client/security.py	2025-10-28 16:50:53.000000000 +0000
@@ -2052,6 +2052,45 @@ class SecurityClient(NamespacedClient):
             path_parts=__path_parts,
         )
 
+    @_rewrite_parameters()
+    async def get_stats(
+        self,
+        *,
+        error_trace: t.Optional[bool] = None,
+        filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        human: t.Optional[bool] = None,
+        pretty: t.Optional[bool] = None,
+    ) -> ObjectApiResponse[t.Any]:
+        """
+        .. raw:: html
+
+          <p>Get security stats.</p>
+          <p>Gather security usage statistics from all node(s) within the cluster.</p>
+
+
+        `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-security-get-stats>`_
+        """
+        __path_parts: t.Dict[str, str] = {}
+        __path = "/_security/stats"
+        __query: t.Dict[str, t.Any] = {}
+        if error_trace is not None:
+            __query["error_trace"] = error_trace
+        if filter_path is not None:
+            __query["filter_path"] = filter_path
+        if human is not None:
+            __query["human"] = human
+        if pretty is not None:
+            __query["pretty"] = pretty
+        __headers = {"accept": "application/json"}
+        return await self.perform_request(  # type: ignore[return-value]
+            "GET",
+            __path,
+            params=__query,
+            headers=__headers,
+            endpoint_id="security.get_stats",
+            path_parts=__path_parts,
+        )
+
     @_rewrite_parameters(
         body_fields=(
             "grant_type",
diff -pruN 9.1.1-2/elasticsearch/_async/client/shutdown.py 9.2.0-1/elasticsearch/_async/client/shutdown.py
--- 9.1.1-2/elasticsearch/_async/client/shutdown.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_async/client/shutdown.py	2025-10-28 16:50:53.000000000 +0000
@@ -33,13 +33,9 @@ class ShutdownClient(NamespacedClient):
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         human: t.Optional[bool] = None,
-        master_timeout: t.Optional[
-            t.Union[str, t.Literal["d", "h", "m", "micros", "ms", "nanos", "s"]]
-        ] = None,
+        master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         pretty: t.Optional[bool] = None,
-        timeout: t.Optional[
-            t.Union[str, t.Literal["d", "h", "m", "micros", "ms", "nanos", "s"]]
-        ] = None,
+        timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
     ) -> ObjectApiResponse[t.Any]:
         """
         .. raw:: html
@@ -97,9 +93,7 @@ class ShutdownClient(NamespacedClient):
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         human: t.Optional[bool] = None,
-        master_timeout: t.Optional[
-            t.Union[str, t.Literal["d", "h", "m", "micros", "ms", "nanos", "s"]]
-        ] = None,
+        master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         pretty: t.Optional[bool] = None,
     ) -> ObjectApiResponse[t.Any]:
         """
@@ -162,14 +156,10 @@ class ShutdownClient(NamespacedClient):
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         human: t.Optional[bool] = None,
-        master_timeout: t.Optional[
-            t.Union[str, t.Literal["d", "h", "m", "micros", "ms", "nanos", "s"]]
-        ] = None,
+        master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         pretty: t.Optional[bool] = None,
         target_node_name: t.Optional[str] = None,
-        timeout: t.Optional[
-            t.Union[str, t.Literal["d", "h", "m", "micros", "ms", "nanos", "s"]]
-        ] = None,
+        timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         body: t.Optional[t.Dict[str, t.Any]] = None,
     ) -> ObjectApiResponse[t.Any]:
         """
diff -pruN 9.1.1-2/elasticsearch/_async/client/simulate.py 9.2.0-1/elasticsearch/_async/client/simulate.py
--- 9.1.1-2/elasticsearch/_async/client/simulate.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_async/client/simulate.py	2025-10-28 16:50:53.000000000 +0000
@@ -56,6 +56,7 @@ class SimulateClient(NamespacedClient):
             t.Mapping[str, t.Mapping[str, t.Any]]
         ] = None,
         mapping_addition: t.Optional[t.Mapping[str, t.Any]] = None,
+        merge_type: t.Optional[t.Union[str, t.Literal["index", "template"]]] = None,
         pipeline: t.Optional[str] = None,
         pipeline_substitutions: t.Optional[
             t.Mapping[str, t.Mapping[str, t.Any]]
@@ -93,6 +94,11 @@ class SimulateClient(NamespacedClient):
         :param index_template_substitutions: A map of index template names to substitute
             index template definition objects.
         :param mapping_addition:
+        :param merge_type: The mapping merge type if mapping overrides are being provided
+            in mapping_addition. The allowed values are one of index or template. The
+            index option merges mappings the way they would be merged into an existing
+            index. The template option merges mappings the way they would be merged into
+            a template.
         :param pipeline: The pipeline to use as the default pipeline. This value can
             be used to override the default pipeline of the index.
         :param pipeline_substitutions: Pipelines to test. If you don’t specify the `pipeline`
@@ -116,6 +122,8 @@ class SimulateClient(NamespacedClient):
             __query["filter_path"] = filter_path
         if human is not None:
             __query["human"] = human
+        if merge_type is not None:
+            __query["merge_type"] = merge_type
         if pipeline is not None:
             __query["pipeline"] = pipeline
         if pretty is not None:
diff -pruN 9.1.1-2/elasticsearch/_async/client/slm.py 9.2.0-1/elasticsearch/_async/client/slm.py
--- 9.1.1-2/elasticsearch/_async/client/slm.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_async/client/slm.py	2025-10-28 16:50:53.000000000 +0000
@@ -431,11 +431,7 @@ class SlmClient(NamespacedClient):
                 __body["retention"] = retention
             if schedule is not None:
                 __body["schedule"] = schedule
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
diff -pruN 9.1.1-2/elasticsearch/_async/client/snapshot.py 9.2.0-1/elasticsearch/_async/client/snapshot.py
--- 9.1.1-2/elasticsearch/_async/client/snapshot.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_async/client/snapshot.py	2025-10-28 16:50:53.000000000 +0000
@@ -872,35 +872,40 @@ class SnapshotClient(NamespacedClient):
 
         :param name: The name of the repository.
         :param blob_count: The total number of blobs to write to the repository during
-            the test. For realistic experiments, you should set it to at least `2000`.
+            the test. For realistic experiments, set this parameter to at least `2000`.
         :param concurrency: The number of operations to run concurrently during the test.
+            For realistic experiments, leave this parameter unset.
         :param detailed: Indicates whether to return detailed results, including timing
             information for every operation performed during the analysis. If false,
             it returns only a summary of the analysis.
         :param early_read_node_count: The number of nodes on which to perform an early
             read operation while writing each blob. Early read operations are only rarely
-            performed.
+            performed. For realistic experiments, leave this parameter unset.
         :param max_blob_size: The maximum size of a blob to be written during the test.
-            For realistic experiments, you should set it to at least `2gb`.
+            For realistic experiments, set this parameter to at least `2gb`.
         :param max_total_data_size: An upper limit on the total size of all the blobs
-            written during the test. For realistic experiments, you should set it to
+            written during the test. For realistic experiments, set this parameter to
             at least `1tb`.
         :param rare_action_probability: The probability of performing a rare action such
-            as an early read, an overwrite, or an aborted write on each blob.
+            as an early read, an overwrite, or an aborted write on each blob. For realistic
+            experiments, leave this parameter unset.
         :param rarely_abort_writes: Indicates whether to rarely cancel writes before
-            they complete.
+            they complete. For realistic experiments, leave this parameter unset.
         :param read_node_count: The number of nodes on which to read a blob after writing.
+            For realistic experiments, leave this parameter unset.
         :param register_operation_count: The minimum number of linearizable register
-            operations to perform in total. For realistic experiments, you should set
-            it to at least `100`.
+            operations to perform in total. For realistic experiments, set this parameter
+            to at least `100`.
         :param seed: The seed for the pseudo-random number generator used to generate
             the list of operations performed during the test. To repeat the same set
             of operations in multiple experiments, use the same seed in each experiment.
             Note that the operations are performed concurrently so might not always happen
-            in the same order on each run.
+            in the same order on each run. For realistic experiments, leave this parameter
+            unset.
         :param timeout: The period of time to wait for the test to complete. If no response
             is received before the timeout expires, the test is cancelled and returns
-            an error.
+            an error. For realistic experiments, set this parameter sufficiently long
+            to allow the test to complete.
         """
         if name in SKIP_IN_PATH:
             raise ValueError("Empty value passed for parameter 'name'")
@@ -1266,6 +1271,11 @@ class SnapshotClient(NamespacedClient):
           <p>If you omit the <code>&lt;snapshot&gt;</code> request path parameter, the request retrieves information only for currently running snapshots.
           This usage is preferred.
           If needed, you can specify <code>&lt;repository&gt;</code> and <code>&lt;snapshot&gt;</code> to retrieve information for specific snapshots, even if they're not currently running.</p>
+          <p>Note that the stats will not be available for any shard snapshots in an ongoing snapshot completed by a node that (even momentarily) left the cluster.
+          Loading the stats from the repository is an expensive operation (see the WARNING below).
+          Therefore the stats values for such shards will be -1 even though the &quot;stage&quot; value will be &quot;DONE&quot;, in order to minimize latency.
+          A &quot;description&quot; field will be present for a shard snapshot completed by a departed node explaining why the shard snapshot's stats results are invalid.
+          Consequently, the total stats for the index will be less than expected due to the missing values from these shards.</p>
           <p>WARNING: Using the API to return the status of any snapshots other than currently running snapshots can be expensive.
           The API requires a read from the repository for each shard in each snapshot.
           For example, if you have 100 snapshots with 1,000 shards each, an API request that includes all snapshots will require 100,000 reads (100 snapshots x 1,000 shards).</p>
diff -pruN 9.1.1-2/elasticsearch/_async/client/sql.py 9.2.0-1/elasticsearch/_async/client/sql.py
--- 9.1.1-2/elasticsearch/_async/client/sql.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_async/client/sql.py	2025-10-28 16:50:53.000000000 +0000
@@ -285,6 +285,7 @@ class SqlClient(NamespacedClient):
         page_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         params: t.Optional[t.Sequence[t.Any]] = None,
         pretty: t.Optional[bool] = None,
+        project_routing: t.Optional[str] = None,
         query: t.Optional[str] = None,
         request_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         runtime_mappings: t.Optional[t.Mapping[str, t.Mapping[str, t.Any]]] = None,
@@ -332,6 +333,10 @@ class SqlClient(NamespacedClient):
             is no longer available. Subsequent scroll requests prolong the lifetime of
             the scroll cursor by the duration of `page_timeout` in the scroll request.
         :param params: The values for parameters in the query.
+        :param project_routing: Specifies a subset of projects to target for the search
+            using project metadata tags in a subset of Lucene query syntax. Allowed Lucene
+            queries: the _alias tag and a single value (possibly wildcarded). Examples:
+            _alias:my-project _alias:_origin _alias:*pr* Supported in serverless only.
         :param query: The SQL query to run.
         :param request_timeout: The timeout before the request fails.
         :param runtime_mappings: One or more runtime fields for the search request. These
@@ -357,6 +362,8 @@ class SqlClient(NamespacedClient):
             __query["human"] = human
         if pretty is not None:
             __query["pretty"] = pretty
+        if project_routing is not None:
+            __query["project_routing"] = project_routing
         if not __body:
             if allow_partial_search_results is not None:
                 __body["allow_partial_search_results"] = allow_partial_search_results
diff -pruN 9.1.1-2/elasticsearch/_async/client/streams.py 9.2.0-1/elasticsearch/_async/client/streams.py
--- 9.1.1-2/elasticsearch/_async/client/streams.py	1970-01-01 00:00:00.000000000 +0000
+++ 9.2.0-1/elasticsearch/_async/client/streams.py	2025-10-28 16:50:53.000000000 +0000
@@ -0,0 +1,185 @@
+#  Licensed to Elasticsearch B.V. under one or more contributor
+#  license agreements. See the NOTICE file distributed with
+#  this work for additional information regarding copyright
+#  ownership. Elasticsearch B.V. licenses this file to you under
+#  the Apache License, Version 2.0 (the "License"); you may
+#  not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+# 	http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing,
+#  software distributed under the License is distributed on an
+#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#  KIND, either express or implied.  See the License for the
+#  specific language governing permissions and limitations
+#  under the License.
+
+
+import typing as t
+
+from elastic_transport import ObjectApiResponse, TextApiResponse
+
+from ._base import NamespacedClient
+from .utils import (
+    Stability,
+    _rewrite_parameters,
+    _stability_warning,
+)
+
+
+class StreamsClient(NamespacedClient):
+
+    @_rewrite_parameters()
+    @_stability_warning(Stability.EXPERIMENTAL)
+    async def logs_disable(
+        self,
+        *,
+        error_trace: t.Optional[bool] = None,
+        filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        human: t.Optional[bool] = None,
+        master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
+        pretty: t.Optional[bool] = None,
+        timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
+    ) -> t.Union[ObjectApiResponse[t.Any], TextApiResponse]:
+        """
+        .. raw:: html
+
+          <p>Disable logs stream.</p>
+          <p>Turn off the logs stream feature for this cluster.</p>
+
+
+        `<https://www.elastic.co/docs/api/doc/elasticsearch#TODO>`_
+
+        :param master_timeout: The period to wait for a connection to the master node.
+            If no response is received before the timeout expires, the request fails
+            and returns an error.
+        :param timeout: The period to wait for a response. If no response is received
+            before the timeout expires, the request fails and returns an error.
+        """
+        __path_parts: t.Dict[str, str] = {}
+        __path = "/_streams/logs/_disable"
+        __query: t.Dict[str, t.Any] = {}
+        if error_trace is not None:
+            __query["error_trace"] = error_trace
+        if filter_path is not None:
+            __query["filter_path"] = filter_path
+        if human is not None:
+            __query["human"] = human
+        if master_timeout is not None:
+            __query["master_timeout"] = master_timeout
+        if pretty is not None:
+            __query["pretty"] = pretty
+        if timeout is not None:
+            __query["timeout"] = timeout
+        __headers = {"accept": "application/json,text/plain"}
+        return await self.perform_request(  # type: ignore[return-value]
+            "POST",
+            __path,
+            params=__query,
+            headers=__headers,
+            endpoint_id="streams.logs_disable",
+            path_parts=__path_parts,
+        )
+
+    @_rewrite_parameters()
+    @_stability_warning(Stability.EXPERIMENTAL)
+    async def logs_enable(
+        self,
+        *,
+        error_trace: t.Optional[bool] = None,
+        filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        human: t.Optional[bool] = None,
+        master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
+        pretty: t.Optional[bool] = None,
+        timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
+    ) -> t.Union[ObjectApiResponse[t.Any], TextApiResponse]:
+        """
+        .. raw:: html
+
+          <p>Enable logs stream.</p>
+          <p>Turn on the logs stream feature for this cluster.</p>
+          <p>NOTE: To protect existing data, this feature can be turned on only if the
+          cluster does not have existing indices or data streams that match the pattern <code>logs|logs.*</code>.
+          If those indices or data streams exist, a <code>409 - Conflict</code> response and error is returned.</p>
+
+
+        `<https://www.elastic.co/docs/api/doc/elasticsearch#TODO>`_
+
+        :param master_timeout: The period to wait for a connection to the master node.
+            If no response is received before the timeout expires, the request fails
+            and returns an error.
+        :param timeout: The period to wait for a response. If no response is received
+            before the timeout expires, the request fails and returns an error.
+        """
+        __path_parts: t.Dict[str, str] = {}
+        __path = "/_streams/logs/_enable"
+        __query: t.Dict[str, t.Any] = {}
+        if error_trace is not None:
+            __query["error_trace"] = error_trace
+        if filter_path is not None:
+            __query["filter_path"] = filter_path
+        if human is not None:
+            __query["human"] = human
+        if master_timeout is not None:
+            __query["master_timeout"] = master_timeout
+        if pretty is not None:
+            __query["pretty"] = pretty
+        if timeout is not None:
+            __query["timeout"] = timeout
+        __headers = {"accept": "application/json,text/plain"}
+        return await self.perform_request(  # type: ignore[return-value]
+            "POST",
+            __path,
+            params=__query,
+            headers=__headers,
+            endpoint_id="streams.logs_enable",
+            path_parts=__path_parts,
+        )
+
+    @_rewrite_parameters()
+    @_stability_warning(Stability.EXPERIMENTAL)
+    async def status(
+        self,
+        *,
+        error_trace: t.Optional[bool] = None,
+        filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        human: t.Optional[bool] = None,
+        master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
+        pretty: t.Optional[bool] = None,
+    ) -> ObjectApiResponse[t.Any]:
+        """
+        .. raw:: html
+
+          <p>Get the status of streams.</p>
+          <p>Get the current status for all types of streams.</p>
+
+
+        `<https://www.elastic.co/docs/api/doc/elasticsearch#TODO>`_
+
+        :param master_timeout: Period to wait for a connection to the master node. If
+            no response is received before the timeout expires, the request fails and
+            returns an error.
+        """
+        __path_parts: t.Dict[str, str] = {}
+        __path = "/_streams/status"
+        __query: t.Dict[str, t.Any] = {}
+        if error_trace is not None:
+            __query["error_trace"] = error_trace
+        if filter_path is not None:
+            __query["filter_path"] = filter_path
+        if human is not None:
+            __query["human"] = human
+        if master_timeout is not None:
+            __query["master_timeout"] = master_timeout
+        if pretty is not None:
+            __query["pretty"] = pretty
+        __headers = {"accept": "application/json"}
+        return await self.perform_request(  # type: ignore[return-value]
+            "GET",
+            __path,
+            params=__query,
+            headers=__headers,
+            endpoint_id="streams.status",
+            path_parts=__path_parts,
+        )
diff -pruN 9.1.1-2/elasticsearch/_async/client/watcher.py 9.2.0-1/elasticsearch/_async/client/watcher.py
--- 9.1.1-2/elasticsearch/_async/client/watcher.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_async/client/watcher.py	2025-10-28 16:50:53.000000000 +0000
@@ -552,11 +552,7 @@ class WatcherClient(NamespacedClient):
                 __body["transform"] = transform
             if trigger is not None:
                 __body["trigger"] = trigger
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return await self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
diff -pruN 9.1.1-2/elasticsearch/_async/helpers.py 9.2.0-1/elasticsearch/_async/helpers.py
--- 9.1.1-2/elasticsearch/_async/helpers.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_async/helpers.py	2025-10-28 16:50:53.000000000 +0000
@@ -33,12 +33,18 @@ from typing import (
     Union,
 )
 
+import sniffio
+from anyio import create_memory_object_stream, create_task_group, move_on_after
+
 from ..exceptions import ApiError, NotFoundError, TransportError
 from ..helpers.actions import (
     _TYPE_BULK_ACTION,
     _TYPE_BULK_ACTION_BODY,
     _TYPE_BULK_ACTION_HEADER,
     _TYPE_BULK_ACTION_HEADER_AND_BODY,
+    _TYPE_BULK_ACTION_HEADER_WITH_META_AND_BODY,
+    _TYPE_BULK_ACTION_WITH_META,
+    BulkMeta,
     _ActionChunker,
     _process_bulk_chunk_error,
     _process_bulk_chunk_success,
@@ -53,10 +59,20 @@ logger = logging.getLogger("elasticsearc
 T = TypeVar("T")
 
 
+async def _sleep(seconds: float) -> None:
+    if sniffio.current_async_library() == "trio":
+        import trio
+
+        await trio.sleep(seconds)
+    else:
+        await asyncio.sleep(seconds)
+
+
 async def _chunk_actions(
-    actions: AsyncIterable[_TYPE_BULK_ACTION_HEADER_AND_BODY],
+    actions: AsyncIterable[_TYPE_BULK_ACTION_HEADER_WITH_META_AND_BODY],
     chunk_size: int,
     max_chunk_bytes: int,
+    flush_after_seconds: Optional[float],
     serializer: Serializer,
 ) -> AsyncIterable[
     Tuple[
@@ -76,10 +92,46 @@ async def _chunk_actions(
     chunker = _ActionChunker(
         chunk_size=chunk_size, max_chunk_bytes=max_chunk_bytes, serializer=serializer
     )
-    async for action, data in actions:
-        ret = chunker.feed(action, data)
-        if ret:
-            yield ret
+
+    action: _TYPE_BULK_ACTION_WITH_META
+    data: _TYPE_BULK_ACTION_BODY
+    if not flush_after_seconds:
+        async for action, data in actions:
+            ret = chunker.feed(action, data)
+            if ret:
+                yield ret
+    else:
+        sender, receiver = create_memory_object_stream[
+            _TYPE_BULK_ACTION_HEADER_WITH_META_AND_BODY
+        ]()
+
+        async def get_items() -> None:
+            try:
+                async for item in actions:
+                    await sender.send(item)
+            finally:
+                await sender.send((BulkMeta.done, None))
+
+        async with create_task_group() as tg:
+            tg.start_soon(get_items)
+
+            timeout: Optional[float] = flush_after_seconds
+            while True:
+                action = {}
+                data = None
+                with move_on_after(timeout) as scope:
+                    action, data = await receiver.receive()
+                    timeout = flush_after_seconds
+                if scope.cancelled_caught:
+                    action, data = BulkMeta.flush, None
+                    timeout = None
+
+                if action is BulkMeta.done:
+                    break
+                ret = chunker.feed(action, data)
+                if ret:
+                    yield ret
+
     ret = chunker.flush()
     if ret:
         yield ret
@@ -159,9 +211,13 @@ async def azip(
 
 async def async_streaming_bulk(
     client: AsyncElasticsearch,
-    actions: Union[Iterable[_TYPE_BULK_ACTION], AsyncIterable[_TYPE_BULK_ACTION]],
+    actions: Union[
+        Iterable[_TYPE_BULK_ACTION_WITH_META],
+        AsyncIterable[_TYPE_BULK_ACTION_WITH_META],
+    ],
     chunk_size: int = 500,
     max_chunk_bytes: int = 100 * 1024 * 1024,
+    flush_after_seconds: Optional[float] = None,
     raise_on_error: bool = True,
     expand_action_callback: Callable[
         [_TYPE_BULK_ACTION], _TYPE_BULK_ACTION_HEADER_AND_BODY
@@ -194,6 +250,9 @@ async def async_streaming_bulk(
     :arg actions: iterable or async iterable containing the actions to be executed
     :arg chunk_size: number of docs in one chunk sent to es (default: 500)
     :arg max_chunk_bytes: the maximum size of the request in bytes (default: 100MB)
+    :arg flush_after_seconds: time in seconds after which a chunk is written even
+        if hasn't reached `chunk_size` or `max_chunk_bytes`. Set to 0 to not use a
+        timeout-based flush. (default: 0)
     :arg raise_on_error: raise ``BulkIndexError`` containing errors (as `.errors`)
         from the execution of the last chunk when some occur. By default we raise.
     :arg raise_on_exception: if ``False`` then don't propagate exceptions from
@@ -220,9 +279,14 @@ async def async_streaming_bulk(
     if isinstance(retry_on_status, int):
         retry_on_status = (retry_on_status,)
 
-    async def map_actions() -> AsyncIterable[_TYPE_BULK_ACTION_HEADER_AND_BODY]:
+    async def map_actions() -> (
+        AsyncIterable[_TYPE_BULK_ACTION_HEADER_WITH_META_AND_BODY]
+    ):
         async for item in aiter(actions):
-            yield expand_action_callback(item)
+            if isinstance(item, BulkMeta):
+                yield item, None
+            else:
+                yield expand_action_callback(item)
 
     serializer = client.transport.serializers.get_serializer("application/json")
 
@@ -234,7 +298,7 @@ async def async_streaming_bulk(
     ]
     bulk_actions: List[bytes]
     async for bulk_data, bulk_actions in _chunk_actions(
-        map_actions(), chunk_size, max_chunk_bytes, serializer
+        map_actions(), chunk_size, max_chunk_bytes, flush_after_seconds, serializer
     ):
         for attempt in range(max_retries + 1):
             to_retry: List[bytes] = []
@@ -245,9 +309,7 @@ async def async_streaming_bulk(
                 ]
             ] = []
             if attempt:
-                await asyncio.sleep(
-                    min(max_backoff, initial_backoff * 2 ** (attempt - 1))
-                )
+                await _sleep(min(max_backoff, initial_backoff * 2 ** (attempt - 1)))
 
             try:
                 data: Union[
diff -pruN 9.1.1-2/elasticsearch/_sync/client/__init__.py 9.2.0-1/elasticsearch/_sync/client/__init__.py
--- 9.1.1-2/elasticsearch/_sync/client/__init__.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_sync/client/__init__.py	2025-10-28 16:50:53.000000000 +0000
@@ -63,6 +63,7 @@ from .migration import MigrationClient
 from .ml import MlClient
 from .monitoring import MonitoringClient
 from .nodes import NodesClient
+from .project import ProjectClient
 from .query_rules import QueryRulesClient
 from .rollup import RollupClient
 from .search_application import SearchApplicationClient
@@ -74,6 +75,7 @@ from .slm import SlmClient
 from .snapshot import SnapshotClient
 from .sql import SqlClient
 from .ssl import SslClient
+from .streams import StreamsClient
 from .synonyms import SynonymsClient
 from .tasks import TasksClient
 from .text_structure import TextStructureClient
@@ -368,6 +370,7 @@ class Elasticsearch(BaseClient):
         self.migration = MigrationClient(self)
         self.ml = MlClient(self)
         self.monitoring = MonitoringClient(self)
+        self.project = ProjectClient(self)
         self.query_rules = QueryRulesClient(self)
         self.rollup = RollupClient(self)
         self.search_application = SearchApplicationClient(self)
@@ -378,6 +381,7 @@ class Elasticsearch(BaseClient):
         self.shutdown = ShutdownClient(self)
         self.sql = SqlClient(self)
         self.ssl = SslClient(self)
+        self.streams = StreamsClient(self)
         self.synonyms = SynonymsClient(self)
         self.text_structure = TextStructureClient(self)
         self.transform = TransformClient(self)
@@ -843,11 +847,7 @@ class Elasticsearch(BaseClient):
         if not __body:
             if id is not None:
                 __body["id"] = id
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "DELETE",
             __path,
@@ -887,6 +887,7 @@ class Elasticsearch(BaseClient):
         min_score: t.Optional[float] = None,
         preference: t.Optional[str] = None,
         pretty: t.Optional[bool] = None,
+        project_routing: t.Optional[str] = None,
         q: t.Optional[str] = None,
         query: t.Optional[t.Mapping[str, t.Any]] = None,
         routing: t.Optional[str] = None,
@@ -920,8 +921,8 @@ class Elasticsearch(BaseClient):
             This parameter can be used only when the `q` query string parameter is specified.
         :param analyzer: The analyzer to use for the query string. This parameter can
             be used only when the `q` query string parameter is specified.
-        :param default_operator: The default operator for query string query: `AND` or
-            `OR`. This parameter can be used only when the `q` query string parameter
+        :param default_operator: The default operator for query string query: `and` or
+            `or`. This parameter can be used only when the `q` query string parameter
             is specified.
         :param df: The field to use as a default when no field prefix is given in the
             query string. This parameter can be used only when the `q` query string parameter
@@ -941,6 +942,10 @@ class Elasticsearch(BaseClient):
             in the result.
         :param preference: The node or shard the operation should be performed on. By
             default, it is random.
+        :param project_routing: Specifies a subset of projects to target for the search
+            using project metadata tags in a subset of Lucene query syntax. Allowed Lucene
+            queries: the _alias tag and a single value (possibly wildcarded). Examples:
+            _alias:my-project _alias:_origin _alias:*pr* Supported in serverless only.
         :param q: The query in Lucene query string syntax. This parameter cannot be used
             with a request body.
         :param query: Defines the search query using Query DSL. A request body query
@@ -993,6 +998,8 @@ class Elasticsearch(BaseClient):
             __query["preference"] = preference
         if pretty is not None:
             __query["pretty"] = pretty
+        if project_routing is not None:
+            __query["project_routing"] = project_routing
         if q is not None:
             __query["q"] = q
         if routing is not None:
@@ -1042,7 +1049,7 @@ class Elasticsearch(BaseClient):
         timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         version: t.Optional[int] = None,
         version_type: t.Optional[
-            t.Union[str, t.Literal["external", "external_gte", "force", "internal"]]
+            t.Union[str, t.Literal["external", "external_gte", "internal"]]
         ] = None,
         wait_for_active_shards: t.Optional[
             t.Union[int, t.Union[str, t.Literal["all", "index-setting"]]]
@@ -1221,7 +1228,7 @@ class Elasticsearch(BaseClient):
         timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         version: t.Optional[int] = None,
         version_type: t.Optional[
-            t.Union[str, t.Literal["external", "external_gte", "force", "internal"]]
+            t.Union[str, t.Literal["external", "external_gte", "internal"]]
         ] = None,
         wait_for_active_shards: t.Optional[
             t.Union[int, t.Union[str, t.Literal["all", "index-setting"]]]
@@ -1466,8 +1473,8 @@ class Elasticsearch(BaseClient):
             used only when the `q` query string parameter is specified.
         :param conflicts: What to do if delete by query hits version conflicts: `abort`
             or `proceed`.
-        :param default_operator: The default operator for query string query: `AND` or
-            `OR`. This parameter can be used only when the `q` query string parameter
+        :param default_operator: The default operator for query string query: `and` or
+            `or`. This parameter can be used only when the `q` query string parameter
             is specified.
         :param df: The field to use as default where no field prefix is given in the
             query string. This parameter can be used only when the `q` query string parameter
@@ -1761,7 +1768,7 @@ class Elasticsearch(BaseClient):
         stored_fields: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         version: t.Optional[int] = None,
         version_type: t.Optional[
-            t.Union[str, t.Literal["external", "external_gte", "force", "internal"]]
+            t.Union[str, t.Literal["external", "external_gte", "internal"]]
         ] = None,
     ) -> HeadApiResponse:
         """
@@ -1890,7 +1897,7 @@ class Elasticsearch(BaseClient):
         source_includes: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         version: t.Optional[int] = None,
         version_type: t.Optional[
-            t.Union[str, t.Literal["external", "external_gte", "force", "internal"]]
+            t.Union[str, t.Literal["external", "external_gte", "internal"]]
         ] = None,
     ) -> HeadApiResponse:
         """
@@ -2019,8 +2026,8 @@ class Elasticsearch(BaseClient):
             This parameter can be used only when the `q` query string parameter is specified.
         :param analyzer: The analyzer to use for the query string. This parameter can
             be used only when the `q` query string parameter is specified.
-        :param default_operator: The default operator for query string query: `AND` or
-            `OR`. This parameter can be used only when the `q` query string parameter
+        :param default_operator: The default operator for query string query: `and` or
+            `or`. This parameter can be used only when the `q` query string parameter
             is specified.
         :param df: The field to use as default where no field prefix is given in the
             query string. This parameter can be used only when the `q` query string parameter
@@ -2131,6 +2138,7 @@ class Elasticsearch(BaseClient):
         include_unmapped: t.Optional[bool] = None,
         index_filter: t.Optional[t.Mapping[str, t.Any]] = None,
         pretty: t.Optional[bool] = None,
+        project_routing: t.Optional[str] = None,
         runtime_mappings: t.Optional[t.Mapping[str, t.Mapping[str, t.Any]]] = None,
         types: t.Optional[t.Sequence[str]] = None,
         body: t.Optional[t.Dict[str, t.Any]] = None,
@@ -2174,6 +2182,11 @@ class Elasticsearch(BaseClient):
             deleted documents) are outside of the provided range. However, not all queries
             can rewrite to `match_none` so this API may return an index even if the provided
             filter matches no document.
+        :param project_routing: Specifies a subset of projects to target for the field-caps
+            query using project metadata tags in a subset of Lucene query syntax. Allowed
+            Lucene queries: the _alias tag and a single value (possibly wildcarded).
+            Examples: _alias:my-project _alias:_origin _alias:*pr* Supported in serverless
+            only.
         :param runtime_mappings: Define ad-hoc runtime fields in the request similar
             to the way it is done in search requests. These fields exist only as part
             of the query and take precedence over fields defined with the same name in
@@ -2211,6 +2224,8 @@ class Elasticsearch(BaseClient):
             __query["include_unmapped"] = include_unmapped
         if pretty is not None:
             __query["pretty"] = pretty
+        if project_routing is not None:
+            __query["project_routing"] = project_routing
         if types is not None:
             __query["types"] = types
         if not __body:
@@ -2238,6 +2253,7 @@ class Elasticsearch(BaseClient):
     @_rewrite_parameters(
         parameter_aliases={
             "_source": "source",
+            "_source_exclude_vectors": "source_exclude_vectors",
             "_source_excludes": "source_excludes",
             "_source_includes": "source_includes",
         },
@@ -2257,12 +2273,13 @@ class Elasticsearch(BaseClient):
         refresh: t.Optional[bool] = None,
         routing: t.Optional[str] = None,
         source: t.Optional[t.Union[bool, t.Union[str, t.Sequence[str]]]] = None,
+        source_exclude_vectors: t.Optional[bool] = None,
         source_excludes: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         source_includes: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         stored_fields: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         version: t.Optional[int] = None,
         version_type: t.Optional[
-            t.Union[str, t.Literal["external", "external_gte", "force", "internal"]]
+            t.Union[str, t.Literal["external", "external_gte", "internal"]]
         ] = None,
     ) -> ObjectApiResponse[t.Any]:
         """
@@ -2330,6 +2347,7 @@ class Elasticsearch(BaseClient):
         :param routing: A custom value used to route operations to a specific shard.
         :param source: Indicates whether to return the `_source` field (`true` or `false`)
             or lists the fields to return.
+        :param source_exclude_vectors: Whether vectors should be excluded from _source
         :param source_excludes: A comma-separated list of source fields to exclude from
             the response. You can also use this parameter to exclude fields from the
             subset specified in `_source_includes` query parameter. If the `_source`
@@ -2375,6 +2393,8 @@ class Elasticsearch(BaseClient):
             __query["routing"] = routing
         if source is not None:
             __query["_source"] = source
+        if source_exclude_vectors is not None:
+            __query["_source_exclude_vectors"] = source_exclude_vectors
         if source_excludes is not None:
             __query["_source_excludes"] = source_excludes
         if source_includes is not None:
@@ -2549,7 +2569,7 @@ class Elasticsearch(BaseClient):
         source_includes: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         version: t.Optional[int] = None,
         version_type: t.Optional[
-            t.Union[str, t.Literal["external", "external_gte", "force", "internal"]]
+            t.Union[str, t.Literal["external", "external_gte", "internal"]]
         ] = None,
     ) -> ObjectApiResponse[t.Any]:
         """
@@ -2729,7 +2749,7 @@ class Elasticsearch(BaseClient):
         timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         version: t.Optional[int] = None,
         version_type: t.Optional[
-            t.Union[str, t.Literal["external", "external_gte", "force", "internal"]]
+            t.Union[str, t.Literal["external", "external_gte", "internal"]]
         ] = None,
         wait_for_active_shards: t.Optional[
             t.Union[int, t.Union[str, t.Literal["all", "index-setting"]]]
@@ -3144,6 +3164,7 @@ class Elasticsearch(BaseClient):
         max_concurrent_shard_requests: t.Optional[int] = None,
         pre_filter_shard_size: t.Optional[int] = None,
         pretty: t.Optional[bool] = None,
+        project_routing: t.Optional[str] = None,
         rest_total_hits_as_int: t.Optional[bool] = None,
         routing: t.Optional[str] = None,
         search_type: t.Optional[
@@ -3205,6 +3226,10 @@ class Elasticsearch(BaseClient):
             roundtrip can limit the number of shards significantly if for instance a
             shard can not match any documents based on its rewrite method i.e., if date
             filters are mandatory to match but the shard bounds and the query are disjoint.
+        :param project_routing: Specifies a subset of projects to target for a search
+            using project metadata tags in a subset Lucene syntax. Allowed Lucene queries:
+            the _alias tag and a single value (possible wildcarded). Examples: _alias:my-project
+            _alias:_origin _alias:*pr* Supported in serverless only.
         :param rest_total_hits_as_int: If true, hits.total are returned as an integer
             in the response. Defaults to false, which returns an object.
         :param routing: Custom routing value used to route search operations to a specific
@@ -3254,6 +3279,8 @@ class Elasticsearch(BaseClient):
             __query["pre_filter_shard_size"] = pre_filter_shard_size
         if pretty is not None:
             __query["pretty"] = pretty
+        if project_routing is not None:
+            __query["project_routing"] = project_routing
         if rest_total_hits_as_int is not None:
             __query["rest_total_hits_as_int"] = rest_total_hits_as_int
         if routing is not None:
@@ -3292,6 +3319,7 @@ class Elasticsearch(BaseClient):
         human: t.Optional[bool] = None,
         max_concurrent_searches: t.Optional[int] = None,
         pretty: t.Optional[bool] = None,
+        project_routing: t.Optional[str] = None,
         rest_total_hits_as_int: t.Optional[bool] = None,
         search_type: t.Optional[
             t.Union[str, t.Literal["dfs_query_then_fetch", "query_then_fetch"]]
@@ -3325,6 +3353,10 @@ class Elasticsearch(BaseClient):
             for cross-cluster search requests.
         :param max_concurrent_searches: The maximum number of concurrent searches the
             API can run.
+        :param project_routing: Specifies a subset of projects to target for the search
+            using project metadata tags in a subset of Lucene query syntax. Allowed Lucene
+            queries: the _alias tag and a single value (possibly wildcarded). Examples:
+            _alias:my-project _alias:_origin _alias:*pr* Supported in serverless only.
         :param rest_total_hits_as_int: If `true`, the response returns `hits.total` as
             an integer. If `false`, it returns `hits.total` as an object.
         :param search_type: The type of the search operation.
@@ -3357,6 +3389,8 @@ class Elasticsearch(BaseClient):
             __query["max_concurrent_searches"] = max_concurrent_searches
         if pretty is not None:
             __query["pretty"] = pretty
+        if project_routing is not None:
+            __query["project_routing"] = project_routing
         if rest_total_hits_as_int is not None:
             __query["rest_total_hits_as_int"] = rest_total_hits_as_int
         if search_type is not None:
@@ -3402,7 +3436,7 @@ class Elasticsearch(BaseClient):
         term_statistics: t.Optional[bool] = None,
         version: t.Optional[int] = None,
         version_type: t.Optional[
-            t.Union[str, t.Literal["external", "external_gte", "force", "internal"]]
+            t.Union[str, t.Literal["external", "external_gte", "internal"]]
         ] = None,
         body: t.Optional[t.Dict[str, t.Any]] = None,
     ) -> ObjectApiResponse[t.Any]:
@@ -3527,6 +3561,7 @@ class Elasticsearch(BaseClient):
         max_concurrent_shard_requests: t.Optional[int] = None,
         preference: t.Optional[str] = None,
         pretty: t.Optional[bool] = None,
+        project_routing: t.Optional[str] = None,
         routing: t.Optional[str] = None,
         body: t.Optional[t.Dict[str, t.Any]] = None,
     ) -> ObjectApiResponse[t.Any]:
@@ -3583,6 +3618,11 @@ class Elasticsearch(BaseClient):
             that each sub-search request executes per node.
         :param preference: The node or shard the operation should be performed on. By
             default, it is random.
+        :param project_routing: Specifies a subset of projects to target for the PIT
+            request using project metadata tags in a subset of Lucene query syntax. Allowed
+            Lucene queries: the _alias tag and a single value (possibly wildcarded).
+            Examples: _alias:my-project _alias:_origin _alias:*pr* Supported in serverless
+            only.
         :param routing: A custom value that is used to route operations to a specific
             shard.
         """
@@ -3614,6 +3654,8 @@ class Elasticsearch(BaseClient):
             __query["preference"] = preference
         if pretty is not None:
             __query["pretty"] = pretty
+        if project_routing is not None:
+            __query["project_routing"] = project_routing
         if routing is not None:
             __query["routing"] = routing
         if not __body:
@@ -3812,7 +3854,7 @@ class Elasticsearch(BaseClient):
         )
 
     @_rewrite_parameters(
-        body_fields=("dest", "source", "conflicts", "max_docs", "script", "size"),
+        body_fields=("dest", "source", "conflicts", "max_docs", "script"),
     )
     def reindex(
         self,
@@ -3830,7 +3872,6 @@ class Elasticsearch(BaseClient):
         require_alias: t.Optional[bool] = None,
         script: t.Optional[t.Mapping[str, t.Any]] = None,
         scroll: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
-        size: t.Optional[int] = None,
         slices: t.Optional[t.Union[int, t.Union[str, t.Literal["auto"]]]] = None,
         timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         wait_for_active_shards: t.Optional[
@@ -3906,7 +3947,6 @@ class Elasticsearch(BaseClient):
             reindexing.
         :param scroll: The period of time that a consistent view of the index should
             be maintained for scrolled search.
-        :param size:
         :param slices: The number of slices this task should be divided into. It defaults
             to one slice, which means the task isn't sliced into subtasks. Reindex supports
             sliced scroll to parallelize the reindexing process. This parallelization
@@ -3971,8 +4011,6 @@ class Elasticsearch(BaseClient):
                 __body["max_docs"] = max_docs
             if script is not None:
                 __body["script"] = script
-            if size is not None:
-                __body["size"] = size
         __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "POST",
@@ -4099,11 +4137,7 @@ class Elasticsearch(BaseClient):
                 __body["params"] = params
             if source is not None:
                 __body["source"] = source
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "POST",
             __path,
@@ -4186,11 +4220,7 @@ class Elasticsearch(BaseClient):
                 __body["context_setup"] = context_setup
             if script is not None:
                 __body["script"] = script
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "POST",
             __path,
@@ -4315,6 +4345,7 @@ class Elasticsearch(BaseClient):
         ),
         parameter_aliases={
             "_source": "source",
+            "_source_exclude_vectors": "source_exclude_vectors",
             "_source_excludes": "source_excludes",
             "_source_includes": "source_includes",
             "from": "from_",
@@ -4369,6 +4400,7 @@ class Elasticsearch(BaseClient):
         preference: t.Optional[str] = None,
         pretty: t.Optional[bool] = None,
         profile: t.Optional[bool] = None,
+        project_routing: t.Optional[str] = None,
         q: t.Optional[str] = None,
         query: t.Optional[t.Mapping[str, t.Any]] = None,
         rank: t.Optional[t.Mapping[str, t.Any]] = None,
@@ -4398,6 +4430,7 @@ class Elasticsearch(BaseClient):
             ]
         ] = None,
         source: t.Optional[t.Union[bool, t.Mapping[str, t.Any]]] = None,
+        source_exclude_vectors: t.Optional[bool] = None,
         source_excludes: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         source_includes: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         stats: t.Optional[t.Sequence[str]] = None,
@@ -4465,8 +4498,8 @@ class Elasticsearch(BaseClient):
             node and the remote clusters are minimized when running cross-cluster search
             (CCS) requests.
         :param collapse: Collapses search results the values of the specified field.
-        :param default_operator: The default operator for the query string query: `AND`
-            or `OR`. This parameter can be used only when the `q` query string parameter
+        :param default_operator: The default operator for the query string query: `and`
+            or `or`. This parameter can be used only when the `q` query string parameter
             is specified.
         :param df: The field to use as a default when no field prefix is given in the
             query string. This parameter can be used only when the `q` query string parameter
@@ -4551,6 +4584,10 @@ class Elasticsearch(BaseClient):
         :param profile: Set to `true` to return detailed timing information about the
             execution of individual components in a search request. NOTE: This is a debugging
             tool and adds significant overhead to search execution.
+        :param project_routing: Specifies a subset of projects to target for the search
+            using project metadata tags in a subset of Lucene query syntax. Allowed Lucene
+            queries: the _alias tag and a single value (possibly wildcarded). Examples:
+            _alias:my-project _alias:_origin _alias:*pr* Supported in serverless only.
         :param q: A query in the Lucene query string syntax. Query parameter searches
             do not support the full Elasticsearch Query DSL but are handy for testing.
             IMPORTANT: This parameter overrides the query parameter in the request body.
@@ -4592,6 +4629,7 @@ class Elasticsearch(BaseClient):
             fields are returned in the `hits._source` property of the search response.
             If the `stored_fields` property is specified, the `_source` property defaults
             to `false`. Otherwise, it defaults to `true`.
+        :param source_exclude_vectors: Whether vectors should be excluded from _source
         :param source_excludes: A comma-separated list of source fields to exclude from
             the response. You can also use this parameter to exclude fields from the
             subset specified in `_source_includes` query parameter. If the `_source`
@@ -4704,6 +4742,8 @@ class Elasticsearch(BaseClient):
             __query["preference"] = preference
         if pretty is not None:
             __query["pretty"] = pretty
+        if project_routing is not None:
+            __query["project_routing"] = project_routing
         if q is not None:
             __query["q"] = q
         if request_cache is not None:
@@ -4716,6 +4756,8 @@ class Elasticsearch(BaseClient):
             __query["scroll"] = scroll
         if search_type is not None:
             __query["search_type"] = search_type
+        if source_exclude_vectors is not None:
+            __query["_source_exclude_vectors"] = source_exclude_vectors
         if source_excludes is not None:
             __query["_source_excludes"] = source_excludes
         if source_includes is not None:
@@ -4856,6 +4898,7 @@ class Elasticsearch(BaseClient):
         ] = None,
         human: t.Optional[bool] = None,
         pretty: t.Optional[bool] = None,
+        project_routing: t.Optional[str] = None,
         query: t.Optional[t.Mapping[str, t.Any]] = None,
         runtime_mappings: t.Optional[t.Mapping[str, t.Mapping[str, t.Any]]] = None,
         size: t.Optional[int] = None,
@@ -5173,6 +5216,10 @@ class Elasticsearch(BaseClient):
             In the aggs layer, each feature represents a `geotile_grid` cell. If `grid,
             each feature is a polygon of the cells bounding box. If `point`, each feature
             is a Point that is the centroid of the cell.
+        :param project_routing: Specifies a subset of projects to target for the search
+            using project metadata tags in a subset of Lucene query syntax. Allowed Lucene
+            queries: the _alias tag and a single value (possibly wildcarded). Examples:
+            _alias:my-project _alias:_origin _alias:*pr* Supported in serverless only.
         :param query: The query DSL used to filter documents for the search.
         :param runtime_mappings: Defines one or more runtime fields in the search request.
             These fields take precedence over mapped fields with the same name.
@@ -5236,6 +5283,8 @@ class Elasticsearch(BaseClient):
             __query["human"] = human
         if pretty is not None:
             __query["pretty"] = pretty
+        if project_routing is not None:
+            __query["project_routing"] = project_routing
         if not __body:
             if aggs is not None:
                 __body["aggs"] = aggs
@@ -5409,6 +5458,7 @@ class Elasticsearch(BaseClient):
         preference: t.Optional[str] = None,
         pretty: t.Optional[bool] = None,
         profile: t.Optional[bool] = None,
+        project_routing: t.Optional[str] = None,
         rest_total_hits_as_int: t.Optional[bool] = None,
         routing: t.Optional[str] = None,
         scroll: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
@@ -5454,6 +5504,10 @@ class Elasticsearch(BaseClient):
         :param preference: The node or shard the operation should be performed on. It
             is random by default.
         :param profile: If `true`, the query execution is profiled.
+        :param project_routing: Specifies a subset of projects to target for the search
+            using project metadata tags in a subset of Lucene query syntax. Allowed Lucene
+            queries: the _alias tag and a single value (possibly wildcarded). Examples:
+            _alias:my-project _alias:_origin _alias:*pr* Supported in serverless only.
         :param rest_total_hits_as_int: If `true`, `hits.total` is rendered as an integer
             in the response. If `false`, it is rendered as an object.
         :param routing: A custom value used to route operations to a specific shard.
@@ -5495,6 +5549,8 @@ class Elasticsearch(BaseClient):
             __query["preference"] = preference
         if pretty is not None:
             __query["pretty"] = pretty
+        if project_routing is not None:
+            __query["project_routing"] = project_routing
         if rest_total_hits_as_int is not None:
             __query["rest_total_hits_as_int"] = rest_total_hits_as_int
         if routing is not None:
@@ -5621,11 +5677,7 @@ class Elasticsearch(BaseClient):
                 __body["string"] = string
             if timeout is not None:
                 __body["timeout"] = timeout
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "POST",
             __path,
@@ -5675,7 +5727,7 @@ class Elasticsearch(BaseClient):
         term_statistics: t.Optional[bool] = None,
         version: t.Optional[int] = None,
         version_type: t.Optional[
-            t.Union[str, t.Literal["external", "external_gte", "force", "internal"]]
+            t.Union[str, t.Literal["external", "external_gte", "internal"]]
         ] = None,
         body: t.Optional[t.Dict[str, t.Any]] = None,
     ) -> ObjectApiResponse[t.Any]:
@@ -6151,8 +6203,8 @@ class Elasticsearch(BaseClient):
             be used only when the `q` query string parameter is specified.
         :param conflicts: The preferred behavior when update by query hits version conflicts:
             `abort` or `proceed`.
-        :param default_operator: The default operator for query string query: `AND` or
-            `OR`. This parameter can be used only when the `q` query string parameter
+        :param default_operator: The default operator for query string query: `and` or
+            `or`. This parameter can be used only when the `q` query string parameter
             is specified.
         :param df: The field to use as default where no field prefix is given in the
             query string. This parameter can be used only when the `q` query string parameter
diff -pruN 9.1.1-2/elasticsearch/_sync/client/async_search.py 9.2.0-1/elasticsearch/_sync/client/async_search.py
--- 9.1.1-2/elasticsearch/_sync/client/async_search.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_sync/client/async_search.py	2025-10-28 16:50:53.000000000 +0000
@@ -287,6 +287,7 @@ class AsyncSearchClient(NamespacedClient
         preference: t.Optional[str] = None,
         pretty: t.Optional[bool] = None,
         profile: t.Optional[bool] = None,
+        project_routing: t.Optional[str] = None,
         q: t.Optional[str] = None,
         query: t.Optional[t.Mapping[str, t.Any]] = None,
         request_cache: t.Optional[bool] = None,
@@ -408,6 +409,10 @@ class AsyncSearchClient(NamespacedClient
         :param preference: Specify the node or shard the operation should be performed
             on (default: random)
         :param profile:
+        :param project_routing: Specifies a subset of projects to target for the search
+            using project metadata tags in a subset of Lucene query syntax. Allowed Lucene
+            queries: the _alias tag and a single value (possibly wildcarded). Examples:
+            _alias:my-project _alias:_origin _alias:*pr* Supported in serverless only.
         :param q: Query in the Lucene query string syntax
         :param query: Defines the search definition using the Query DSL.
         :param request_cache: Specify if request cache should be used for this request
@@ -528,6 +533,8 @@ class AsyncSearchClient(NamespacedClient
             __query["preference"] = preference
         if pretty is not None:
             __query["pretty"] = pretty
+        if project_routing is not None:
+            __query["project_routing"] = project_routing
         if q is not None:
             __query["q"] = q
         if request_cache is not None:
diff -pruN 9.1.1-2/elasticsearch/_sync/client/cat.py 9.2.0-1/elasticsearch/_sync/client/cat.py
--- 9.1.1-2/elasticsearch/_sync/client/cat.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_sync/client/cat.py	2025-10-28 16:50:53.000000000 +0000
@@ -36,6 +36,9 @@ class CatClient(NamespacedClient):
         self,
         *,
         name: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        bytes: t.Optional[
+            t.Union[str, t.Literal["b", "gb", "kb", "mb", "pb", "tb"]]
+        ] = None,
         error_trace: t.Optional[bool] = None,
         expand_wildcards: t.Optional[
             t.Union[
@@ -80,6 +83,9 @@ class CatClient(NamespacedClient):
         master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         pretty: t.Optional[bool] = None,
         s: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        time: t.Optional[
+            t.Union[str, t.Literal["d", "h", "m", "micros", "ms", "nanos", "s"]]
+        ] = None,
         v: t.Optional[bool] = None,
     ) -> t.Union[ObjectApiResponse[t.Any], TextApiResponse]:
         """
@@ -95,6 +101,14 @@ class CatClient(NamespacedClient):
 
         :param name: A comma-separated list of aliases to retrieve. Supports wildcards
             (`*`). To retrieve all aliases, omit this parameter or use `*` or `_all`.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param expand_wildcards: The type of index that wildcard patterns can match.
             If the request can target data streams, this argument determines whether
             wildcard expressions match hidden data streams. It supports comma-separated
@@ -112,6 +126,12 @@ class CatClient(NamespacedClient):
         :param s: List of columns that determine how the table should be sorted. Sorting
             defaults to ascending and can be changed by setting `:asc` or `:desc` as
             a suffix to the column name.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str]
@@ -122,6 +142,8 @@ class CatClient(NamespacedClient):
             __path_parts = {}
             __path = "/_cat/aliases"
         __query: t.Dict[str, t.Any] = {}
+        if bytes is not None:
+            __query["bytes"] = bytes
         if error_trace is not None:
             __query["error_trace"] = error_trace
         if expand_wildcards is not None:
@@ -142,6 +164,8 @@ class CatClient(NamespacedClient):
             __query["pretty"] = pretty
         if s is not None:
             __query["s"] = s
+        if time is not None:
+            __query["time"] = time
         if v is not None:
             __query["v"] = v
         __headers = {"accept": "text/plain,application/json"}
@@ -213,6 +237,9 @@ class CatClient(NamespacedClient):
         master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         pretty: t.Optional[bool] = None,
         s: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        time: t.Optional[
+            t.Union[str, t.Literal["d", "h", "m", "micros", "ms", "nanos", "s"]]
+        ] = None,
         v: t.Optional[bool] = None,
     ) -> t.Union[ObjectApiResponse[t.Any], TextApiResponse]:
         """
@@ -227,7 +254,14 @@ class CatClient(NamespacedClient):
 
         :param node_id: A comma-separated list of node identifiers or names used to limit
             the returned information.
-        :param bytes: The unit used to display byte values.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: A comma-separated list of columns names to display. It supports simple
@@ -242,6 +276,12 @@ class CatClient(NamespacedClient):
         :param s: List of columns that determine how the table should be sorted. Sorting
             defaults to ascending and can be changed by setting `:asc` or `:desc` as
             a suffix to the column name.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str]
@@ -274,6 +314,8 @@ class CatClient(NamespacedClient):
             __query["pretty"] = pretty
         if s is not None:
             __query["s"] = s
+        if time is not None:
+            __query["time"] = time
         if v is not None:
             __query["v"] = v
         __headers = {"accept": "text/plain,application/json"}
@@ -291,6 +333,9 @@ class CatClient(NamespacedClient):
         self,
         *,
         name: t.Optional[str] = None,
+        bytes: t.Optional[
+            t.Union[str, t.Literal["b", "gb", "kb", "mb", "pb", "tb"]]
+        ] = None,
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         format: t.Optional[str] = None,
@@ -330,6 +375,9 @@ class CatClient(NamespacedClient):
         master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         pretty: t.Optional[bool] = None,
         s: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        time: t.Optional[
+            t.Union[str, t.Literal["d", "h", "m", "micros", "ms", "nanos", "s"]]
+        ] = None,
         v: t.Optional[bool] = None,
     ) -> t.Union[ObjectApiResponse[t.Any], TextApiResponse]:
         """
@@ -346,6 +394,14 @@ class CatClient(NamespacedClient):
 
         :param name: The name of the component template. It accepts wildcard expressions.
             If it is omitted, all component templates are returned.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: A comma-separated list of columns names to display. It supports simple
@@ -360,6 +416,12 @@ class CatClient(NamespacedClient):
         :param s: List of columns that determine how the table should be sorted. Sorting
             defaults to ascending and can be changed by setting `:asc` or `:desc` as
             a suffix to the column name.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str]
@@ -370,6 +432,8 @@ class CatClient(NamespacedClient):
             __path_parts = {}
             __path = "/_cat/component_templates"
         __query: t.Dict[str, t.Any] = {}
+        if bytes is not None:
+            __query["bytes"] = bytes
         if error_trace is not None:
             __query["error_trace"] = error_trace
         if filter_path is not None:
@@ -390,6 +454,8 @@ class CatClient(NamespacedClient):
             __query["pretty"] = pretty
         if s is not None:
             __query["s"] = s
+        if time is not None:
+            __query["time"] = time
         if v is not None:
             __query["v"] = v
         __headers = {"accept": "text/plain,application/json"}
@@ -407,6 +473,9 @@ class CatClient(NamespacedClient):
         self,
         *,
         index: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        bytes: t.Optional[
+            t.Union[str, t.Literal["b", "gb", "kb", "mb", "pb", "tb"]]
+        ] = None,
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         format: t.Optional[str] = None,
@@ -419,7 +488,11 @@ class CatClient(NamespacedClient):
         help: t.Optional[bool] = None,
         human: t.Optional[bool] = None,
         pretty: t.Optional[bool] = None,
+        project_routing: t.Optional[str] = None,
         s: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        time: t.Optional[
+            t.Union[str, t.Literal["d", "h", "m", "micros", "ms", "nanos", "s"]]
+        ] = None,
         v: t.Optional[bool] = None,
     ) -> t.Union[ObjectApiResponse[t.Any], TextApiResponse]:
         """
@@ -437,15 +510,33 @@ class CatClient(NamespacedClient):
         :param index: A comma-separated list of data streams, indices, and aliases used
             to limit the request. It supports wildcards (`*`). To target all data streams
             and indices, omit this parameter or use `*` or `_all`.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: A comma-separated list of columns names to display. It supports simple
             wildcards.
         :param help: When set to `true` will output available columns. This option can't
             be combined with any other query string option.
+        :param project_routing: Specifies a subset of projects to target for the search
+            using project metadata tags in a subset of Lucene query syntax. Allowed Lucene
+            queries: the _alias tag and a single value (possibly wildcarded). Examples:
+            _alias:my-project _alias:_origin _alias:*pr* Supported in serverless only.
         :param s: List of columns that determine how the table should be sorted. Sorting
             defaults to ascending and can be changed by setting `:asc` or `:desc` as
             a suffix to the column name.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str]
@@ -456,6 +547,8 @@ class CatClient(NamespacedClient):
             __path_parts = {}
             __path = "/_cat/count"
         __query: t.Dict[str, t.Any] = {}
+        if bytes is not None:
+            __query["bytes"] = bytes
         if error_trace is not None:
             __query["error_trace"] = error_trace
         if filter_path is not None:
@@ -470,8 +563,12 @@ class CatClient(NamespacedClient):
             __query["human"] = human
         if pretty is not None:
             __query["pretty"] = pretty
+        if project_routing is not None:
+            __query["project_routing"] = project_routing
         if s is not None:
             __query["s"] = s
+        if time is not None:
+            __query["time"] = time
         if v is not None:
             __query["v"] = v
         __headers = {"accept": "text/plain,application/json"}
@@ -507,6 +604,9 @@ class CatClient(NamespacedClient):
         human: t.Optional[bool] = None,
         pretty: t.Optional[bool] = None,
         s: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        time: t.Optional[
+            t.Union[str, t.Literal["d", "h", "m", "micros", "ms", "nanos", "s"]]
+        ] = None,
         v: t.Optional[bool] = None,
     ) -> t.Union[ObjectApiResponse[t.Any], TextApiResponse]:
         """
@@ -522,7 +622,14 @@ class CatClient(NamespacedClient):
 
         :param fields: Comma-separated list of fields used to limit returned information.
             To retrieve all fields, omit this parameter.
-        :param bytes: The unit used to display byte values.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: A comma-separated list of columns names to display. It supports simple
@@ -532,6 +639,12 @@ class CatClient(NamespacedClient):
         :param s: List of columns that determine how the table should be sorted. Sorting
             defaults to ascending and can be changed by setting `:asc` or `:desc` as
             a suffix to the column name.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str]
@@ -560,6 +673,8 @@ class CatClient(NamespacedClient):
             __query["pretty"] = pretty
         if s is not None:
             __query["s"] = s
+        if time is not None:
+            __query["time"] = time
         if v is not None:
             __query["v"] = v
         __headers = {"accept": "text/plain,application/json"}
@@ -576,6 +691,9 @@ class CatClient(NamespacedClient):
     def health(
         self,
         *,
+        bytes: t.Optional[
+            t.Union[str, t.Literal["b", "gb", "kb", "mb", "pb", "tb"]]
+        ] = None,
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         format: t.Optional[str] = None,
@@ -652,6 +770,14 @@ class CatClient(NamespacedClient):
 
         `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-health>`_
 
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: A comma-separated list of columns names to display. It supports simple
@@ -661,13 +787,20 @@ class CatClient(NamespacedClient):
         :param s: List of columns that determine how the table should be sorted. Sorting
             defaults to ascending and can be changed by setting `:asc` or `:desc` as
             a suffix to the column name.
-        :param time: The unit used to display time values.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param ts: If true, returns `HH:MM:SS` and Unix epoch timestamps.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str] = {}
         __path = "/_cat/health"
         __query: t.Dict[str, t.Any] = {}
+        if bytes is not None:
+            __query["bytes"] = bytes
         if error_trace is not None:
             __query["error_trace"] = error_trace
         if filter_path is not None:
@@ -1092,7 +1225,14 @@ class CatClient(NamespacedClient):
         :param index: Comma-separated list of data streams, indices, and aliases used
             to limit the request. Supports wildcards (`*`). To target all data streams
             and indices, omit this parameter or use `*` or `_all`.
-        :param bytes: The unit used to display byte values.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param expand_wildcards: The type of index that wildcard patterns can match.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
@@ -1109,7 +1249,12 @@ class CatClient(NamespacedClient):
         :param s: List of columns that determine how the table should be sorted. Sorting
             defaults to ascending and can be changed by setting `:asc` or `:desc` as
             a suffix to the column name.
-        :param time: The unit used to display time values.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str]
@@ -1166,6 +1311,9 @@ class CatClient(NamespacedClient):
     def master(
         self,
         *,
+        bytes: t.Optional[
+            t.Union[str, t.Literal["b", "gb", "kb", "mb", "pb", "tb"]]
+        ] = None,
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         format: t.Optional[str] = None,
@@ -1181,6 +1329,9 @@ class CatClient(NamespacedClient):
         master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         pretty: t.Optional[bool] = None,
         s: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        time: t.Optional[
+            t.Union[str, t.Literal["d", "h", "m", "micros", "ms", "nanos", "s"]]
+        ] = None,
         v: t.Optional[bool] = None,
     ) -> t.Union[ObjectApiResponse[t.Any], TextApiResponse]:
         """
@@ -1193,6 +1344,14 @@ class CatClient(NamespacedClient):
 
         `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-master>`_
 
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: A comma-separated list of columns names to display. It supports simple
@@ -1207,11 +1366,19 @@ class CatClient(NamespacedClient):
         :param s: List of columns that determine how the table should be sorted. Sorting
             defaults to ascending and can be changed by setting `:asc` or `:desc` as
             a suffix to the column name.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str] = {}
         __path = "/_cat/master"
         __query: t.Dict[str, t.Any] = {}
+        if bytes is not None:
+            __query["bytes"] = bytes
         if error_trace is not None:
             __query["error_trace"] = error_trace
         if filter_path is not None:
@@ -1232,6 +1399,8 @@ class CatClient(NamespacedClient):
             __query["pretty"] = pretty
         if s is not None:
             __query["s"] = s
+        if time is not None:
+            __query["time"] = time
         if v is not None:
             __query["v"] = v
         __headers = {"accept": "text/plain,application/json"}
@@ -1374,8 +1543,15 @@ class CatClient(NamespacedClient):
 
         :param id: The ID of the data frame analytics to fetch
         :param allow_no_match: Whether to ignore if a wildcard expression matches no
-            configs. (This includes `_all` string or when no configs have been specified)
-        :param bytes: The unit in which to display byte values
+            configs. (This includes `_all` string or when no configs have been specified.)
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: Comma-separated list of column names to display.
@@ -1383,7 +1559,12 @@ class CatClient(NamespacedClient):
             be combined with any other query string option.
         :param s: Comma-separated list of column names or column aliases used to sort
             the response.
-        :param time: Unit used to display time values.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str]
@@ -1434,6 +1615,9 @@ class CatClient(NamespacedClient):
         *,
         datafeed_id: t.Optional[str] = None,
         allow_no_match: t.Optional[bool] = None,
+        bytes: t.Optional[
+            t.Union[str, t.Literal["b", "gb", "kb", "mb", "pb", "tb"]]
+        ] = None,
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         format: t.Optional[str] = None,
@@ -1549,6 +1733,14 @@ class CatClient(NamespacedClient):
             array when there are no matches and the subset of results when there are
             partial matches. If `false`, the API returns a 404 status code when there
             are no matches or only partial matches.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: Comma-separated list of column names to display.
@@ -1556,7 +1748,12 @@ class CatClient(NamespacedClient):
             be combined with any other query string option.
         :param s: Comma-separated list of column names or column aliases used to sort
             the response.
-        :param time: The unit used to display time values.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str]
@@ -1569,6 +1766,8 @@ class CatClient(NamespacedClient):
         __query: t.Dict[str, t.Any] = {}
         if allow_no_match is not None:
             __query["allow_no_match"] = allow_no_match
+        if bytes is not None:
+            __query["bytes"] = bytes
         if error_trace is not None:
             __query["error_trace"] = error_trace
         if filter_path is not None:
@@ -1914,7 +2113,14 @@ class CatClient(NamespacedClient):
             array when there are no matches and the subset of results when there are
             partial matches. If `false`, the API returns a 404 status code when there
             are no matches or only partial matches.
-        :param bytes: The unit used to display byte values.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: Comma-separated list of column names to display.
@@ -1922,7 +2128,12 @@ class CatClient(NamespacedClient):
             be combined with any other query string option.
         :param s: Comma-separated list of column names or column aliases used to sort
             the response.
-        :param time: The unit used to display time values.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str]
@@ -2099,7 +2310,14 @@ class CatClient(NamespacedClient):
             when there are no matches and the subset of results when there are partial
             matches. If `false`, the API returns a 404 status code when there are no
             matches or only partial matches.
-        :param bytes: The unit used to display byte values.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param from_: Skips the specified number of transforms.
@@ -2109,7 +2327,12 @@ class CatClient(NamespacedClient):
         :param s: A comma-separated list of column names or aliases used to sort the
             response.
         :param size: The maximum number of transforms to display.
-        :param time: Unit used to display time values.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str]
@@ -2162,6 +2385,9 @@ class CatClient(NamespacedClient):
     def nodeattrs(
         self,
         *,
+        bytes: t.Optional[
+            t.Union[str, t.Literal["b", "gb", "kb", "mb", "pb", "tb"]]
+        ] = None,
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         format: t.Optional[str] = None,
@@ -2189,6 +2415,9 @@ class CatClient(NamespacedClient):
         master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         pretty: t.Optional[bool] = None,
         s: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        time: t.Optional[
+            t.Union[str, t.Literal["d", "h", "m", "micros", "ms", "nanos", "s"]]
+        ] = None,
         v: t.Optional[bool] = None,
     ) -> t.Union[ObjectApiResponse[t.Any], TextApiResponse]:
         """
@@ -2201,6 +2430,14 @@ class CatClient(NamespacedClient):
 
         `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-nodeattrs>`_
 
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: A comma-separated list of columns names to display. It supports simple
@@ -2215,11 +2452,19 @@ class CatClient(NamespacedClient):
         :param s: List of columns that determine how the table should be sorted. Sorting
             defaults to ascending and can be changed by setting `:asc` or `:desc` as
             a suffix to the column name.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str] = {}
         __path = "/_cat/nodeattrs"
         __query: t.Dict[str, t.Any] = {}
+        if bytes is not None:
+            __query["bytes"] = bytes
         if error_trace is not None:
             __query["error_trace"] = error_trace
         if filter_path is not None:
@@ -2240,6 +2485,8 @@ class CatClient(NamespacedClient):
             __query["pretty"] = pretty
         if s is not None:
             __query["s"] = s
+        if time is not None:
+            __query["time"] = time
         if v is not None:
             __query["v"] = v
         __headers = {"accept": "text/plain,application/json"}
@@ -2262,7 +2509,7 @@ class CatClient(NamespacedClient):
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         format: t.Optional[str] = None,
-        full_id: t.Optional[t.Union[bool, str]] = None,
+        full_id: t.Optional[bool] = None,
         h: t.Optional[
             t.Union[
                 t.Sequence[
@@ -2478,7 +2725,14 @@ class CatClient(NamespacedClient):
 
         `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-nodes>`_
 
-        :param bytes: The unit used to display byte values.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param full_id: If `true`, return the full node ID. If `false`, return the shortened
@@ -2493,7 +2747,12 @@ class CatClient(NamespacedClient):
         :param s: A comma-separated list of column names or aliases that determines the
             sort order. Sorting defaults to ascending and can be changed by setting `:asc`
             or `:desc` as a suffix to the column name.
-        :param time: The unit used to display time values.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str] = {}
@@ -2541,6 +2800,9 @@ class CatClient(NamespacedClient):
     def pending_tasks(
         self,
         *,
+        bytes: t.Optional[
+            t.Union[str, t.Literal["b", "gb", "kb", "mb", "pb", "tb"]]
+        ] = None,
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         format: t.Optional[str] = None,
@@ -2578,6 +2840,14 @@ class CatClient(NamespacedClient):
 
         `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-pending-tasks>`_
 
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: A comma-separated list of columns names to display. It supports simple
@@ -2592,12 +2862,19 @@ class CatClient(NamespacedClient):
         :param s: List of columns that determine how the table should be sorted. Sorting
             defaults to ascending and can be changed by setting `:asc` or `:desc` as
             a suffix to the column name.
-        :param time: Unit used to display time values.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str] = {}
         __path = "/_cat/pending_tasks"
         __query: t.Dict[str, t.Any] = {}
+        if bytes is not None:
+            __query["bytes"] = bytes
         if error_trace is not None:
             __query["error_trace"] = error_trace
         if filter_path is not None:
@@ -2636,6 +2913,9 @@ class CatClient(NamespacedClient):
     def plugins(
         self,
         *,
+        bytes: t.Optional[
+            t.Union[str, t.Literal["b", "gb", "kb", "mb", "pb", "tb"]]
+        ] = None,
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         format: t.Optional[str] = None,
@@ -2659,6 +2939,9 @@ class CatClient(NamespacedClient):
         master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         pretty: t.Optional[bool] = None,
         s: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        time: t.Optional[
+            t.Union[str, t.Literal["d", "h", "m", "micros", "ms", "nanos", "s"]]
+        ] = None,
         v: t.Optional[bool] = None,
     ) -> t.Union[ObjectApiResponse[t.Any], TextApiResponse]:
         """
@@ -2671,6 +2954,14 @@ class CatClient(NamespacedClient):
 
         `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-plugins>`_
 
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: A comma-separated list of columns names to display. It supports simple
@@ -2686,11 +2977,19 @@ class CatClient(NamespacedClient):
         :param s: List of columns that determine how the table should be sorted. Sorting
             defaults to ascending and can be changed by setting `:asc` or `:desc` as
             a suffix to the column name.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str] = {}
         __path = "/_cat/plugins"
         __query: t.Dict[str, t.Any] = {}
+        if bytes is not None:
+            __query["bytes"] = bytes
         if error_trace is not None:
             __query["error_trace"] = error_trace
         if filter_path is not None:
@@ -2713,6 +3012,8 @@ class CatClient(NamespacedClient):
             __query["pretty"] = pretty
         if s is not None:
             __query["s"] = s
+        if time is not None:
+            __query["time"] = time
         if v is not None:
             __query["v"] = v
         __headers = {"accept": "text/plain,application/json"}
@@ -2831,7 +3132,14 @@ class CatClient(NamespacedClient):
             to limit the request. Supports wildcards (`*`). To target all data streams
             and indices, omit this parameter or use `*` or `_all`.
         :param active_only: If `true`, the response only includes ongoing shard recoveries.
-        :param bytes: The unit used to display byte values.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param detailed: If `true`, the response includes detailed information about
             shard recoveries.
         :param format: Specifies the format to return the columnar data in, can be set
@@ -2843,7 +3151,12 @@ class CatClient(NamespacedClient):
         :param s: A comma-separated list of column names or aliases that determines the
             sort order. Sorting defaults to ascending and can be changed by setting `:asc`
             or `:desc` as a suffix to the column name.
-        :param time: The unit used to display time values.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str]
@@ -2894,6 +3207,9 @@ class CatClient(NamespacedClient):
     def repositories(
         self,
         *,
+        bytes: t.Optional[
+            t.Union[str, t.Literal["b", "gb", "kb", "mb", "pb", "tb"]]
+        ] = None,
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         format: t.Optional[str] = None,
@@ -2904,6 +3220,9 @@ class CatClient(NamespacedClient):
         master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         pretty: t.Optional[bool] = None,
         s: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        time: t.Optional[
+            t.Union[str, t.Literal["d", "h", "m", "micros", "ms", "nanos", "s"]]
+        ] = None,
         v: t.Optional[bool] = None,
     ) -> t.Union[ObjectApiResponse[t.Any], TextApiResponse]:
         """
@@ -2916,6 +3235,14 @@ class CatClient(NamespacedClient):
 
         `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-repositories>`_
 
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: List of columns to appear in the response. Supports simple wildcards.
@@ -2929,11 +3256,19 @@ class CatClient(NamespacedClient):
         :param s: List of columns that determine how the table should be sorted. Sorting
             defaults to ascending and can be changed by setting `:asc` or `:desc` as
             a suffix to the column name.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str] = {}
         __path = "/_cat/repositories"
         __query: t.Dict[str, t.Any] = {}
+        if bytes is not None:
+            __query["bytes"] = bytes
         if error_trace is not None:
             __query["error_trace"] = error_trace
         if filter_path is not None:
@@ -2954,6 +3289,8 @@ class CatClient(NamespacedClient):
             __query["pretty"] = pretty
         if s is not None:
             __query["s"] = s
+        if time is not None:
+            __query["time"] = time
         if v is not None:
             __query["v"] = v
         __headers = {"accept": "text/plain,application/json"}
@@ -3029,6 +3366,9 @@ class CatClient(NamespacedClient):
         master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         pretty: t.Optional[bool] = None,
         s: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        time: t.Optional[
+            t.Union[str, t.Literal["d", "h", "m", "micros", "ms", "nanos", "s"]]
+        ] = None,
         v: t.Optional[bool] = None,
     ) -> t.Union[ObjectApiResponse[t.Any], TextApiResponse]:
         """
@@ -3045,7 +3385,14 @@ class CatClient(NamespacedClient):
         :param index: A comma-separated list of data streams, indices, and aliases used
             to limit the request. Supports wildcards (`*`). To target all data streams
             and indices, omit this parameter or use `*` or `_all`.
-        :param bytes: The unit used to display byte values.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: A comma-separated list of columns names to display. It supports simple
@@ -3060,6 +3407,12 @@ class CatClient(NamespacedClient):
         :param s: A comma-separated list of column names or aliases that determines the
             sort order. Sorting defaults to ascending and can be changed by setting `:asc`
             or `:desc` as a suffix to the column name.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str]
@@ -3092,6 +3445,8 @@ class CatClient(NamespacedClient):
             __query["pretty"] = pretty
         if s is not None:
             __query["s"] = s
+        if time is not None:
+            __query["time"] = time
         if v is not None:
             __query["v"] = v
         __headers = {"accept": "text/plain,application/json"}
@@ -3295,7 +3650,14 @@ class CatClient(NamespacedClient):
         :param index: A comma-separated list of data streams, indices, and aliases used
             to limit the request. Supports wildcards (`*`). To target all data streams
             and indices, omit this parameter or use `*` or `_all`.
-        :param bytes: The unit used to display byte values.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: List of columns to appear in the response. Supports simple wildcards.
@@ -3305,7 +3667,12 @@ class CatClient(NamespacedClient):
         :param s: A comma-separated list of column names or aliases that determines the
             sort order. Sorting defaults to ascending and can be changed by setting `:asc`
             or `:desc` as a suffix to the column name.
-        :param time: The unit used to display time values.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str]
@@ -3355,6 +3722,9 @@ class CatClient(NamespacedClient):
         self,
         *,
         repository: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        bytes: t.Optional[
+            t.Union[str, t.Literal["b", "gb", "kb", "mb", "pb", "tb"]]
+        ] = None,
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         format: t.Optional[str] = None,
@@ -3425,6 +3795,14 @@ class CatClient(NamespacedClient):
         :param repository: A comma-separated list of snapshot repositories used to limit
             the request. Accepts wildcard expressions. `_all` returns all repositories.
             If any repository fails during the request, Elasticsearch returns an error.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: A comma-separated list of columns names to display. It supports simple
@@ -3437,7 +3815,12 @@ class CatClient(NamespacedClient):
         :param s: List of columns that determine how the table should be sorted. Sorting
             defaults to ascending and can be changed by setting `:asc` or `:desc` as
             a suffix to the column name.
-        :param time: Unit used to display time values.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str]
@@ -3448,6 +3831,8 @@ class CatClient(NamespacedClient):
             __path_parts = {}
             __path = "/_cat/snapshots"
         __query: t.Dict[str, t.Any] = {}
+        if bytes is not None:
+            __query["bytes"] = bytes
         if error_trace is not None:
             __query["error_trace"] = error_trace
         if filter_path is not None:
@@ -3488,6 +3873,9 @@ class CatClient(NamespacedClient):
         self,
         *,
         actions: t.Optional[t.Sequence[str]] = None,
+        bytes: t.Optional[
+            t.Union[str, t.Literal["b", "gb", "kb", "mb", "pb", "tb"]]
+        ] = None,
         detailed: t.Optional[bool] = None,
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
@@ -3562,6 +3950,14 @@ class CatClient(NamespacedClient):
         `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-tasks>`_
 
         :param actions: The task action names, which are used to limit the response.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param detailed: If `true`, the response includes detailed information about
             shard recoveries.
         :param format: Specifies the format to return the columnar data in, can be set
@@ -3576,7 +3972,12 @@ class CatClient(NamespacedClient):
         :param s: List of columns that determine how the table should be sorted. Sorting
             defaults to ascending and can be changed by setting `:asc` or `:desc` as
             a suffix to the column name.
-        :param time: Unit used to display time values.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param timeout: Period to wait for a response. If no response is received before
             the timeout expires, the request fails and returns an error.
         :param v: When set to `true` will enable verbose output.
@@ -3588,6 +3989,8 @@ class CatClient(NamespacedClient):
         __query: t.Dict[str, t.Any] = {}
         if actions is not None:
             __query["actions"] = actions
+        if bytes is not None:
+            __query["bytes"] = bytes
         if detailed is not None:
             __query["detailed"] = detailed
         if error_trace is not None:
@@ -3633,6 +4036,9 @@ class CatClient(NamespacedClient):
         self,
         *,
         name: t.Optional[str] = None,
+        bytes: t.Optional[
+            t.Union[str, t.Literal["b", "gb", "kb", "mb", "pb", "tb"]]
+        ] = None,
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         format: t.Optional[str] = None,
@@ -3660,6 +4066,9 @@ class CatClient(NamespacedClient):
         master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         pretty: t.Optional[bool] = None,
         s: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        time: t.Optional[
+            t.Union[str, t.Literal["d", "h", "m", "micros", "ms", "nanos", "s"]]
+        ] = None,
         v: t.Optional[bool] = None,
     ) -> t.Union[ObjectApiResponse[t.Any], TextApiResponse]:
         """
@@ -3675,6 +4084,14 @@ class CatClient(NamespacedClient):
 
         :param name: The name of the template to return. Accepts wildcard expressions.
             If omitted, all templates are returned.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: A comma-separated list of columns names to display. It supports simple
@@ -3689,6 +4106,12 @@ class CatClient(NamespacedClient):
         :param s: List of columns that determine how the table should be sorted. Sorting
             defaults to ascending and can be changed by setting `:asc` or `:desc` as
             a suffix to the column name.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str]
@@ -3699,6 +4122,8 @@ class CatClient(NamespacedClient):
             __path_parts = {}
             __path = "/_cat/templates"
         __query: t.Dict[str, t.Any] = {}
+        if bytes is not None:
+            __query["bytes"] = bytes
         if error_trace is not None:
             __query["error_trace"] = error_trace
         if filter_path is not None:
@@ -3719,6 +4144,8 @@ class CatClient(NamespacedClient):
             __query["pretty"] = pretty
         if s is not None:
             __query["s"] = s
+        if time is not None:
+            __query["time"] = time
         if v is not None:
             __query["v"] = v
         __headers = {"accept": "text/plain,application/json"}
@@ -3736,6 +4163,9 @@ class CatClient(NamespacedClient):
         self,
         *,
         thread_pool_patterns: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        bytes: t.Optional[
+            t.Union[str, t.Literal["b", "gb", "kb", "mb", "pb", "tb"]]
+        ] = None,
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         format: t.Optional[str] = None,
@@ -3819,6 +4249,14 @@ class CatClient(NamespacedClient):
 
         :param thread_pool_patterns: A comma-separated list of thread pool names used
             to limit the request. Accepts wildcard expressions.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param h: List of columns to appear in the response. Supports simple wildcards.
@@ -3832,7 +4270,12 @@ class CatClient(NamespacedClient):
         :param s: A comma-separated list of column names or aliases that determines the
             sort order. Sorting defaults to ascending and can be changed by setting `:asc`
             or `:desc` as a suffix to the column name.
-        :param time: The unit used to display time values.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str]
@@ -3843,6 +4286,8 @@ class CatClient(NamespacedClient):
             __path_parts = {}
             __path = "/_cat/thread_pool"
         __query: t.Dict[str, t.Any] = {}
+        if bytes is not None:
+            __query["bytes"] = bytes
         if error_trace is not None:
             __query["error_trace"] = error_trace
         if filter_path is not None:
@@ -3885,6 +4330,9 @@ class CatClient(NamespacedClient):
         *,
         transform_id: t.Optional[str] = None,
         allow_no_match: t.Optional[bool] = None,
+        bytes: t.Optional[
+            t.Union[str, t.Literal["b", "gb", "kb", "mb", "pb", "tb"]]
+        ] = None,
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         format: t.Optional[str] = None,
@@ -4084,6 +4532,14 @@ class CatClient(NamespacedClient):
             array when there are no matches and the subset of results when there are
             partial matches. If `false`, the request returns a 404 status code when there
             are no matches or only partial matches.
+        :param bytes: Sets the units for columns that contain a byte-size value. Note
+            that byte-size value units work in terms of powers of 1024. For instance
+            `1kb` means 1024 bytes, not 1000 bytes. If omitted, byte-size values are
+            rendered with a suffix such as `kb`, `mb`, or `gb`, chosen such that the
+            numeric value of the column is as small as possible whilst still being at
+            least `1.0`. If given, byte-size values are rendered as an integer with no
+            suffix, representing the value of the column in the chosen unit. Values that
+            are not an exact multiple of the chosen unit are rounded down.
         :param format: Specifies the format to return the columnar data in, can be set
             to `text`, `json`, `cbor`, `yaml`, or `smile`.
         :param from_: Skips the specified number of transforms.
@@ -4093,7 +4549,12 @@ class CatClient(NamespacedClient):
         :param s: Comma-separated list of column names or column aliases used to sort
             the response.
         :param size: The maximum number of transforms to obtain.
-        :param time: The unit used to display time values.
+        :param time: Sets the units for columns that contain a time duration. If omitted,
+            time duration values are rendered with a suffix such as `ms`, `s`, `m` or
+            `h`, chosen such that the numeric value of the column is as small as possible
+            whilst still being at least `1.0`. If given, time duration values are rendered
+            as an integer with no suffix. Values that are not an exact multiple of the
+            chosen unit are rounded down.
         :param v: When set to `true` will enable verbose output.
         """
         __path_parts: t.Dict[str, str]
@@ -4106,6 +4567,8 @@ class CatClient(NamespacedClient):
         __query: t.Dict[str, t.Any] = {}
         if allow_no_match is not None:
             __query["allow_no_match"] = allow_no_match
+        if bytes is not None:
+            __query["bytes"] = bytes
         if error_trace is not None:
             __query["error_trace"] = error_trace
         if filter_path is not None:
diff -pruN 9.1.1-2/elasticsearch/_sync/client/cluster.py 9.2.0-1/elasticsearch/_sync/client/cluster.py
--- 9.1.1-2/elasticsearch/_sync/client/cluster.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_sync/client/cluster.py	2025-10-28 16:50:53.000000000 +0000
@@ -49,6 +49,7 @@ class ClusterClient(NamespacedClient):
 
           <p>Explain the shard allocations.
           Get explanations for shard allocations in the cluster.
+          This API accepts the current_node, index, primary and shard parameters in the request body or in query parameters, but not in both at the same time.
           For unassigned shards, it provides an explanation for why the shard is unassigned.
           For assigned shards, it provides an explanation for why the shard is remaining on its current node and has not moved or rebalanced to another node.
           This API can be very useful when attempting to diagnose why a shard is unassigned or why a shard continues to remain on its current node when you might expect otherwise.
@@ -57,17 +58,16 @@ class ClusterClient(NamespacedClient):
 
         `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cluster-allocation-explain>`_
 
-        :param current_node: Specifies the node ID or the name of the node to only explain
-            a shard that is currently located on the specified node.
+        :param current_node: Explain a shard only if it is currently located on the specified
+            node name or node ID.
         :param include_disk_info: If true, returns information about disk usage and shard
             sizes.
         :param include_yes_decisions: If true, returns YES decisions in explanation.
-        :param index: Specifies the name of the index that you would like an explanation
-            for.
+        :param index: The name of the index that you would like an explanation for.
         :param master_timeout: Period to wait for a connection to the master node.
-        :param primary: If true, returns explanation for the primary shard for the given
-            shard ID.
-        :param shard: Specifies the ID of the shard that you would like an explanation
+        :param primary: If true, returns an explanation for the primary shard for the
+            specified shard ID.
+        :param shard: An identifier for the shard that you would like an explanation
             for.
         """
         __path_parts: t.Dict[str, str] = {}
@@ -1124,7 +1124,8 @@ class ClusterClient(NamespacedClient):
             when unavailable (missing or closed)
         :param local: Return local information, do not retrieve the state from master
             node (default: false)
-        :param master_timeout: Specify timeout for connection to master
+        :param master_timeout: Timeout for waiting for new cluster state in case it is
+            blocked
         :param wait_for_metadata_version: Wait for the metadata version to be equal or
             greater than the specified metadata version
         :param wait_for_timeout: The maximum time to wait for wait_for_metadata_version
diff -pruN 9.1.1-2/elasticsearch/_sync/client/connector.py 9.2.0-1/elasticsearch/_sync/client/connector.py
--- 9.1.1-2/elasticsearch/_sync/client/connector.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_sync/client/connector.py	2025-10-28 16:50:53.000000000 +0000
@@ -103,7 +103,7 @@ class ConnectorClient(NamespacedClient):
 
         :param connector_id: The unique identifier of the connector to be deleted
         :param delete_sync_jobs: A flag indicating if associated sync jobs should be
-            also removed. Defaults to false.
+            also removed.
         :param hard: A flag indicating if the connector should be hard deleted.
         """
         if connector_id in SKIP_IN_PATH:
@@ -360,7 +360,7 @@ class ConnectorClient(NamespacedClient):
 
         :param connector_name: A comma-separated list of connector names to fetch connector
             documents for
-        :param from_: Starting offset (default: 0)
+        :param from_: Starting offset
         :param include_deleted: A flag to indicate if the desired connector should be
             fetched, even if it was soft-deleted.
         :param index_name: A comma-separated list of connector index names to fetch connector
@@ -955,7 +955,7 @@ class ConnectorClient(NamespacedClient):
         `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-connector-sync-job-list>`_
 
         :param connector_id: A connector id to fetch connector sync jobs for
-        :param from_: Starting offset (default: 0)
+        :param from_: Starting offset
         :param job_type: A comma-separated list of job types to fetch the sync jobs for
         :param size: Specifies a max number of results to get
         :param status: A sync job status to fetch connector sync jobs for
diff -pruN 9.1.1-2/elasticsearch/_sync/client/eql.py 9.2.0-1/elasticsearch/_sync/client/eql.py
--- 9.1.1-2/elasticsearch/_sync/client/eql.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_sync/client/eql.py	2025-10-28 16:50:53.000000000 +0000
@@ -229,6 +229,7 @@ class EqlClient(NamespacedClient):
         keep_on_completion: t.Optional[bool] = None,
         max_samples_per_key: t.Optional[int] = None,
         pretty: t.Optional[bool] = None,
+        project_routing: t.Optional[str] = None,
         result_position: t.Optional[t.Union[str, t.Literal["head", "tail"]]] = None,
         runtime_mappings: t.Optional[t.Mapping[str, t.Mapping[str, t.Any]]] = None,
         size: t.Optional[int] = None,
@@ -285,6 +286,10 @@ class EqlClient(NamespacedClient):
             `size` parameter to get a smaller or larger set of samples. To retrieve more
             than one sample per set of join keys, use the `max_samples_per_key` parameter.
             Pipes are not supported for sample queries.
+        :param project_routing: Specifies a subset of projects to target for the search
+            using project metadata tags in a subset of Lucene query syntax. Allowed Lucene
+            queries: the _alias tag and a single value (possibly wildcarded). Examples:
+            _alias:my-project _alias:_origin _alias:*pr* Supported in serverless only.
         :param result_position:
         :param runtime_mappings:
         :param size: For basic queries, the maximum number of matching events to return.
@@ -318,6 +323,8 @@ class EqlClient(NamespacedClient):
             __query["ignore_unavailable"] = ignore_unavailable
         if pretty is not None:
             __query["pretty"] = pretty
+        if project_routing is not None:
+            __query["project_routing"] = project_routing
         if not __body:
             if query is not None:
                 __body["query"] = query
diff -pruN 9.1.1-2/elasticsearch/_sync/client/esql.py 9.2.0-1/elasticsearch/_sync/client/esql.py
--- 9.1.1-2/elasticsearch/_sync/client/esql.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_sync/client/esql.py	2025-10-28 16:50:53.000000000 +0000
@@ -40,6 +40,7 @@ class EsqlClient(NamespacedClient):
             "columnar",
             "filter",
             "include_ccs_metadata",
+            "include_execution_metadata",
             "keep_alive",
             "keep_on_completion",
             "locale",
@@ -71,6 +72,7 @@ class EsqlClient(NamespacedClient):
         ] = None,
         human: t.Optional[bool] = None,
         include_ccs_metadata: t.Optional[bool] = None,
+        include_execution_metadata: t.Optional[bool] = None,
         keep_alive: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         keep_on_completion: t.Optional[bool] = None,
         locale: t.Optional[str] = None,
@@ -120,7 +122,11 @@ class EsqlClient(NamespacedClient):
             be returned if the async query doesn't finish within the timeout. The query
             ID and running status are available in the `X-Elasticsearch-Async-Id` and
             `X-Elasticsearch-Async-Is-Running` HTTP headers of the response, respectively.
-        :param include_ccs_metadata: When set to `true` and performing a cross-cluster
+        :param include_ccs_metadata: When set to `true` and performing a cross-cluster/cross-project
+            query, the response will include an extra `_clusters` object with information
+            about the clusters that participated in the search along with info such as
+            shards count.
+        :param include_execution_metadata: When set to `true` and performing a cross-cluster/cross-project
             query, the response will include an extra `_clusters` object with information
             about the clusters that participated in the search along with info such as
             shards count.
@@ -180,6 +186,8 @@ class EsqlClient(NamespacedClient):
                 __body["filter"] = filter
             if include_ccs_metadata is not None:
                 __body["include_ccs_metadata"] = include_ccs_metadata
+            if include_execution_metadata is not None:
+                __body["include_execution_metadata"] = include_execution_metadata
             if keep_alive is not None:
                 __body["keep_alive"] = keep_alive
             if keep_on_completion is not None:
@@ -486,6 +494,7 @@ class EsqlClient(NamespacedClient):
             "columnar",
             "filter",
             "include_ccs_metadata",
+            "include_execution_metadata",
             "locale",
             "params",
             "profile",
@@ -514,8 +523,16 @@ class EsqlClient(NamespacedClient):
         ] = None,
         human: t.Optional[bool] = None,
         include_ccs_metadata: t.Optional[bool] = None,
+        include_execution_metadata: t.Optional[bool] = None,
         locale: t.Optional[str] = None,
-        params: t.Optional[t.Sequence[t.Union[None, bool, float, int, str]]] = None,
+        params: t.Optional[
+            t.Sequence[
+                t.Union[
+                    t.Sequence[t.Union[None, bool, float, int, str]],
+                    t.Union[None, bool, float, int, str],
+                ]
+            ]
+        ] = None,
         pretty: t.Optional[bool] = None,
         profile: t.Optional[bool] = None,
         tables: t.Optional[
@@ -554,7 +571,11 @@ class EsqlClient(NamespacedClient):
         :param format: A short version of the Accept header, e.g. json, yaml. `csv`,
             `tsv`, and `txt` formats will return results in a tabular format, excluding
             other metadata fields from the response.
-        :param include_ccs_metadata: When set to `true` and performing a cross-cluster
+        :param include_ccs_metadata: When set to `true` and performing a cross-cluster/cross-project
+            query, the response will include an extra `_clusters` object with information
+            about the clusters that participated in the search along with info such as
+            shards count.
+        :param include_execution_metadata: When set to `true` and performing a cross-cluster/cross-project
             query, the response will include an extra `_clusters` object with information
             about the clusters that participated in the search along with info such as
             shards count.
@@ -600,6 +621,8 @@ class EsqlClient(NamespacedClient):
                 __body["filter"] = filter
             if include_ccs_metadata is not None:
                 __body["include_ccs_metadata"] = include_ccs_metadata
+            if include_execution_metadata is not None:
+                __body["include_execution_metadata"] = include_execution_metadata
             if locale is not None:
                 __body["locale"] = locale
             if params is not None:
diff -pruN 9.1.1-2/elasticsearch/_sync/client/fleet.py 9.2.0-1/elasticsearch/_sync/client/fleet.py
--- 9.1.1-2/elasticsearch/_sync/client/fleet.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_sync/client/fleet.py	2025-10-28 16:50:53.000000000 +0000
@@ -642,11 +642,7 @@ class FleetClient(NamespacedClient):
                 __body["track_total_hits"] = track_total_hits
             if version is not None:
                 __body["version"] = version
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "POST",
             __path,
diff -pruN 9.1.1-2/elasticsearch/_sync/client/graph.py 9.2.0-1/elasticsearch/_sync/client/graph.py
--- 9.1.1-2/elasticsearch/_sync/client/graph.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_sync/client/graph.py	2025-10-28 16:50:53.000000000 +0000
@@ -97,11 +97,7 @@ class GraphClient(NamespacedClient):
                 __body["query"] = query
             if vertices is not None:
                 __body["vertices"] = vertices
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "POST",
             __path,
diff -pruN 9.1.1-2/elasticsearch/_sync/client/ilm.py 9.2.0-1/elasticsearch/_sync/client/ilm.py
--- 9.1.1-2/elasticsearch/_sync/client/ilm.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_sync/client/ilm.py	2025-10-28 16:50:53.000000000 +0000
@@ -383,11 +383,7 @@ class IlmClient(NamespacedClient):
                 __body["current_step"] = current_step
             if next_step is not None:
                 __body["next_step"] = next_step
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "POST",
             __path,
@@ -453,11 +449,7 @@ class IlmClient(NamespacedClient):
         if not __body:
             if policy is not None:
                 __body["policy"] = policy
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
diff -pruN 9.1.1-2/elasticsearch/_sync/client/indices.py 9.2.0-1/elasticsearch/_sync/client/indices.py
--- 9.1.1-2/elasticsearch/_sync/client/indices.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_sync/client/indices.py	2025-10-28 16:50:53.000000000 +0000
@@ -232,11 +232,7 @@ class IndicesClient(NamespacedClient):
                 __body["text"] = text
             if tokenizer is not None:
                 __body["tokenizer"] = tokenizer
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "POST",
             __path,
@@ -812,11 +808,7 @@ class IndicesClient(NamespacedClient):
             raise ValueError("Empty value passed for parameter 'source'")
         if dest in SKIP_IN_PATH:
             raise ValueError("Empty value passed for parameter 'dest'")
-        if create_from is None and body is None:
-            raise ValueError(
-                "Empty value passed for parameters 'create_from' and 'body', one of them should be set."
-            )
-        elif create_from is not None and body is not None:
+        if create_from is not None and body is not None:
             raise ValueError("Cannot set both 'create_from' and 'body'")
         __path_parts: t.Dict[str, str] = {
             "source": _quote(source),
@@ -833,7 +825,11 @@ class IndicesClient(NamespacedClient):
         if pretty is not None:
             __query["pretty"] = pretty
         __body = create_from if create_from is not None else body
-        __headers = {"accept": "application/json", "content-type": "application/json"}
+        if not __body:
+            __body = None
+        __headers = {"accept": "application/json"}
+        if __body is not None:
+            __headers["content-type"] = "application/json"
         return self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -1393,6 +1389,7 @@ class IndicesClient(NamespacedClient):
           <p>NOTE: The total size of fields of the analyzed shards of the index in the response is usually smaller than the index <code>store_size</code> value because some small metadata files are ignored and some parts of data files might not be scanned by the API.
           Since stored fields are stored together in a compressed format, the sizes of stored fields are also estimates and can be inaccurate.
           The stored size of the <code>_id</code> field is likely underestimated while the <code>_source</code> field is overestimated.</p>
+          <p>For usage examples see the External documentation or refer to <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/index-disk-usage">Analyze the index disk usage example</a> for an example.</p>
 
 
         `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-disk-usage>`_
@@ -2543,6 +2540,57 @@ class IndicesClient(NamespacedClient):
         )
 
     @_rewrite_parameters()
+    def get_data_stream_mappings(
+        self,
+        *,
+        name: t.Union[str, t.Sequence[str]],
+        error_trace: t.Optional[bool] = None,
+        filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        human: t.Optional[bool] = None,
+        master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
+        pretty: t.Optional[bool] = None,
+    ) -> ObjectApiResponse[t.Any]:
+        """
+        .. raw:: html
+
+          <p>Get data stream mappings.</p>
+          <p>Get mapping information for one or more data streams.</p>
+
+
+        `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-get-data-stream-mappings>`_
+
+        :param name: A comma-separated list of data streams or data stream patterns.
+            Supports wildcards (`*`).
+        :param master_timeout: The period to wait for a connection to the master node.
+            If no response is received before the timeout expires, the request fails
+            and returns an error.
+        """
+        if name in SKIP_IN_PATH:
+            raise ValueError("Empty value passed for parameter 'name'")
+        __path_parts: t.Dict[str, str] = {"name": _quote(name)}
+        __path = f'/_data_stream/{__path_parts["name"]}/_mappings'
+        __query: t.Dict[str, t.Any] = {}
+        if error_trace is not None:
+            __query["error_trace"] = error_trace
+        if filter_path is not None:
+            __query["filter_path"] = filter_path
+        if human is not None:
+            __query["human"] = human
+        if master_timeout is not None:
+            __query["master_timeout"] = master_timeout
+        if pretty is not None:
+            __query["pretty"] = pretty
+        __headers = {"accept": "application/json"}
+        return self.perform_request(  # type: ignore[return-value]
+            "GET",
+            __path,
+            params=__query,
+            headers=__headers,
+            endpoint_id="indices.get_data_stream_mappings",
+            path_parts=__path_parts,
+        )
+
+    @_rewrite_parameters()
     def get_data_stream_options(
         self,
         *,
@@ -3638,11 +3686,7 @@ class IndicesClient(NamespacedClient):
                 __body["downsampling"] = downsampling
             if enabled is not None:
                 __body["enabled"] = enabled
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -3654,6 +3698,83 @@ class IndicesClient(NamespacedClient):
         )
 
     @_rewrite_parameters(
+        body_name="mappings",
+    )
+    def put_data_stream_mappings(
+        self,
+        *,
+        name: t.Union[str, t.Sequence[str]],
+        mappings: t.Optional[t.Mapping[str, t.Any]] = None,
+        body: t.Optional[t.Mapping[str, t.Any]] = None,
+        dry_run: t.Optional[bool] = None,
+        error_trace: t.Optional[bool] = None,
+        filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        human: t.Optional[bool] = None,
+        master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
+        pretty: t.Optional[bool] = None,
+        timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
+    ) -> ObjectApiResponse[t.Any]:
+        """
+        .. raw:: html
+
+          <p>Update data stream mappings.</p>
+          <p>This API can be used to override mappings on specific data streams. These overrides will take precedence over what
+          is specified in the template that the data stream matches. The mapping change is only applied to new write indices
+          that are created during rollover after this API is called. No indices are changed by this API.</p>
+
+
+        `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-put-data-stream-mappings>`_
+
+        :param name: A comma-separated list of data streams or data stream patterns.
+        :param mappings:
+        :param dry_run: If `true`, the request does not actually change the mappings
+            on any data streams. Instead, it simulates changing the settings and reports
+            back to the user what would have happened had these settings actually been
+            applied.
+        :param master_timeout: The period to wait for a connection to the master node.
+            If no response is received before the timeout expires, the request fails
+            and returns an error.
+        :param timeout: The period to wait for a response. If no response is received
+            before the timeout expires, the request fails and returns an error.
+        """
+        if name in SKIP_IN_PATH:
+            raise ValueError("Empty value passed for parameter 'name'")
+        if mappings is None and body is None:
+            raise ValueError(
+                "Empty value passed for parameters 'mappings' and 'body', one of them should be set."
+            )
+        elif mappings is not None and body is not None:
+            raise ValueError("Cannot set both 'mappings' and 'body'")
+        __path_parts: t.Dict[str, str] = {"name": _quote(name)}
+        __path = f'/_data_stream/{__path_parts["name"]}/_mappings'
+        __query: t.Dict[str, t.Any] = {}
+        if dry_run is not None:
+            __query["dry_run"] = dry_run
+        if error_trace is not None:
+            __query["error_trace"] = error_trace
+        if filter_path is not None:
+            __query["filter_path"] = filter_path
+        if human is not None:
+            __query["human"] = human
+        if master_timeout is not None:
+            __query["master_timeout"] = master_timeout
+        if pretty is not None:
+            __query["pretty"] = pretty
+        if timeout is not None:
+            __query["timeout"] = timeout
+        __body = mappings if mappings is not None else body
+        __headers = {"accept": "application/json", "content-type": "application/json"}
+        return self.perform_request(  # type: ignore[return-value]
+            "PUT",
+            __path,
+            params=__query,
+            headers=__headers,
+            body=__body,
+            endpoint_id="indices.put_data_stream_mappings",
+            path_parts=__path_parts,
+        )
+
+    @_rewrite_parameters(
         body_fields=("failure_store",),
     )
     def put_data_stream_options(
@@ -3721,11 +3842,7 @@ class IndicesClient(NamespacedClient):
         if not __body:
             if failure_store is not None:
                 __body["failure_store"] = failure_store
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -4549,6 +4666,7 @@ class IndicesClient(NamespacedClient):
           For data streams, the API runs the refresh operation on the stream’s backing indices.</p>
           <p>By default, Elasticsearch periodically refreshes indices every second, but only on indices that have received one search request or more in the last 30 seconds.
           You can change this default interval with the <code>index.refresh_interval</code> setting.</p>
+          <p>In Elastic Cloud Serverless, the default refresh interval is 5 seconds across all indices.</p>
           <p>Refresh requests are synchronous and do not return a response until the refresh operation completes.</p>
           <p>Refreshes are resource-intensive.
           To ensure good cluster performance, it's recommended to wait for Elasticsearch's periodic refresh rather than performing an explicit refresh when possible.</p>
@@ -4937,7 +5055,18 @@ class IndicesClient(NamespacedClient):
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         human: t.Optional[bool] = None,
         ignore_unavailable: t.Optional[bool] = None,
+        mode: t.Optional[
+            t.Union[
+                t.Sequence[
+                    t.Union[
+                        str, t.Literal["logsdb", "lookup", "standard", "time_series"]
+                    ]
+                ],
+                t.Union[str, t.Literal["logsdb", "lookup", "standard", "time_series"]],
+            ]
+        ] = None,
         pretty: t.Optional[bool] = None,
+        project_routing: t.Optional[str] = None,
     ) -> ObjectApiResponse[t.Any]:
         """
         .. raw:: html
@@ -4963,6 +5092,12 @@ class IndicesClient(NamespacedClient):
             as `open,hidden`.
         :param ignore_unavailable: If `false`, the request returns an error if it targets
             a missing or closed index.
+        :param mode: Filter indices by index mode - standard, lookup, time_series, etc.
+            Comma-separated list of IndexMode. Empty means no filter.
+        :param project_routing: Specifies a subset of projects to target using project
+            metadata tags in a subset of Lucene query syntax. Allowed Lucene queries:
+            the _alias tag and a single value (possibly wildcarded). Examples: _alias:my-project
+            _alias:_origin _alias:*pr* Supported in serverless only.
         """
         if name in SKIP_IN_PATH:
             raise ValueError("Empty value passed for parameter 'name'")
@@ -4981,8 +5116,12 @@ class IndicesClient(NamespacedClient):
             __query["human"] = human
         if ignore_unavailable is not None:
             __query["ignore_unavailable"] = ignore_unavailable
+        if mode is not None:
+            __query["mode"] = mode
         if pretty is not None:
             __query["pretty"] = pretty
+        if project_routing is not None:
+            __query["project_routing"] = project_routing
         __headers = {"accept": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "GET",
@@ -5022,7 +5161,7 @@ class IndicesClient(NamespacedClient):
         .. raw:: html
 
           <p>Roll over to a new index.
-          TIP: It is recommended to use the index lifecycle rollover action to automate rollovers.</p>
+          TIP: We recommend using the index lifecycle rollover action to automate rollovers. However, Serverless does not support Index Lifecycle Management (ILM), so don't use this approach in the Serverless context.</p>
           <p>The rollover API creates a new index for a data stream or index alias.
           The API behavior depends on the rollover target.</p>
           <p><strong>Roll over a data stream</strong></p>
@@ -5399,11 +5538,7 @@ class IndicesClient(NamespacedClient):
                 __body["aliases"] = aliases
             if settings is not None:
                 __body["settings"] = settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -5414,7 +5549,9 @@ class IndicesClient(NamespacedClient):
             path_parts=__path_parts,
         )
 
-    @_rewrite_parameters()
+    @_rewrite_parameters(
+        body_name="index_template",
+    )
     def simulate_index_template(
         self,
         *,
@@ -5425,6 +5562,8 @@ class IndicesClient(NamespacedClient):
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         human: t.Optional[bool] = None,
         include_defaults: t.Optional[bool] = None,
+        index_template: t.Optional[t.Mapping[str, t.Any]] = None,
+        body: t.Optional[t.Mapping[str, t.Any]] = None,
         master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         pretty: t.Optional[bool] = None,
     ) -> ObjectApiResponse[t.Any]:
@@ -5444,12 +5583,15 @@ class IndicesClient(NamespacedClient):
             only be dry-run added if new or can also replace an existing one
         :param include_defaults: If true, returns all relevant default configurations
             for the index template.
+        :param index_template:
         :param master_timeout: Period to wait for a connection to the master node. If
             no response is received before the timeout expires, the request fails and
             returns an error.
         """
         if name in SKIP_IN_PATH:
             raise ValueError("Empty value passed for parameter 'name'")
+        if index_template is not None and body is not None:
+            raise ValueError("Cannot set both 'index_template' and 'body'")
         __path_parts: t.Dict[str, str] = {"name": _quote(name)}
         __path = f'/_index_template/_simulate_index/{__path_parts["name"]}'
         __query: t.Dict[str, t.Any] = {}
@@ -5469,12 +5611,18 @@ class IndicesClient(NamespacedClient):
             __query["master_timeout"] = master_timeout
         if pretty is not None:
             __query["pretty"] = pretty
+        __body = index_template if index_template is not None else body
+        if not __body:
+            __body = None
         __headers = {"accept": "application/json"}
+        if __body is not None:
+            __headers["content-type"] = "application/json"
         return self.perform_request(  # type: ignore[return-value]
             "POST",
             __path,
             params=__query,
             headers=__headers,
+            body=__body,
             endpoint_id="indices.simulate_index_template",
             path_parts=__path_parts,
         )
@@ -5742,11 +5890,7 @@ class IndicesClient(NamespacedClient):
                 __body["aliases"] = aliases
             if settings is not None:
                 __body["settings"] = settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -5823,8 +5967,8 @@ class IndicesClient(NamespacedClient):
             are requested).
         :param include_unloaded_segments: If true, the response includes information
             from segments that are not loaded into memory.
-        :param level: Indicates whether statistics are aggregated at the cluster, index,
-            or shard level.
+        :param level: Indicates whether statistics are aggregated at the cluster, indices,
+            or shards level.
         """
         __path_parts: t.Dict[str, str]
         if index not in SKIP_IN_PATH and metric not in SKIP_IN_PATH:
@@ -5990,8 +6134,8 @@ class IndicesClient(NamespacedClient):
         :param analyze_wildcard: If `true`, wildcard and prefix queries are analyzed.
         :param analyzer: Analyzer to use for the query string. This parameter can only
             be used when the `q` query string parameter is specified.
-        :param default_operator: The default operator for query string query: `AND` or
-            `OR`.
+        :param default_operator: The default operator for query string query: `and` or
+            `or`.
         :param df: Field to use as default where no field prefix is given in the query
             string. This parameter can only be used when the `q` query string parameter
             is specified.
diff -pruN 9.1.1-2/elasticsearch/_sync/client/inference.py 9.2.0-1/elasticsearch/_sync/client/inference.py
--- 9.1.1-2/elasticsearch/_sync/client/inference.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_sync/client/inference.py	2025-10-28 16:50:53.000000000 +0000
@@ -78,11 +78,7 @@ class InferenceClient(NamespacedClient):
                 __body["input"] = input
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "POST",
             __path,
@@ -338,11 +334,7 @@ class InferenceClient(NamespacedClient):
                 __body["query"] = query
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "POST",
             __path,
@@ -389,11 +381,12 @@ class InferenceClient(NamespacedClient):
           However, if you do not plan to use the inference APIs to use these models or if you want to use non-NLP models, use the machine learning trained model APIs.</p>
           <p>The following integrations are available through the inference API. You can find the available task types next to the integration name:</p>
           <ul>
+          <li>AI21 (<code>chat_completion</code>, <code>completion</code>)</li>
           <li>AlibabaCloud AI Search (<code>completion</code>, <code>rerank</code>, <code>sparse_embedding</code>, <code>text_embedding</code>)</li>
           <li>Amazon Bedrock (<code>completion</code>, <code>text_embedding</code>)</li>
           <li>Amazon SageMaker (<code>chat_completion</code>, <code>completion</code>, <code>rerank</code>, <code>sparse_embedding</code>, <code>text_embedding</code>)</li>
           <li>Anthropic (<code>completion</code>)</li>
-          <li>Azure AI Studio (<code>completion</code>, <code>text_embedding</code>)</li>
+          <li>Azure AI Studio (<code>completion</code>, 'rerank', <code>text_embedding</code>)</li>
           <li>Azure OpenAI (<code>completion</code>, <code>text_embedding</code>)</li>
           <li>Cohere (<code>completion</code>, <code>rerank</code>, <code>text_embedding</code>)</li>
           <li>DeepSeek (<code>chat_completion</code>, <code>completion</code>)</li>
@@ -464,6 +457,82 @@ class InferenceClient(NamespacedClient):
         )
 
     @_rewrite_parameters(
+        body_fields=("service", "service_settings"),
+    )
+    def put_ai21(
+        self,
+        *,
+        task_type: t.Union[str, t.Literal["chat_completion", "completion"]],
+        ai21_inference_id: str,
+        service: t.Optional[t.Union[str, t.Literal["ai21"]]] = None,
+        service_settings: t.Optional[t.Mapping[str, t.Any]] = None,
+        error_trace: t.Optional[bool] = None,
+        filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        human: t.Optional[bool] = None,
+        pretty: t.Optional[bool] = None,
+        timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
+        body: t.Optional[t.Dict[str, t.Any]] = None,
+    ) -> ObjectApiResponse[t.Any]:
+        """
+        .. raw:: html
+
+          <p>Create a AI21 inference endpoint.</p>
+          <p>Create an inference endpoint to perform an inference task with the <code>ai21</code> service.</p>
+
+
+        `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-put-ai21>`_
+
+        :param task_type: The type of the inference task that the model will perform.
+        :param ai21_inference_id: The unique identifier of the inference endpoint.
+        :param service: The type of service supported for the specified task type. In
+            this case, `ai21`.
+        :param service_settings: Settings used to install the inference model. These
+            settings are specific to the `ai21` service.
+        :param timeout: Specifies the amount of time to wait for the inference endpoint
+            to be created.
+        """
+        if task_type in SKIP_IN_PATH:
+            raise ValueError("Empty value passed for parameter 'task_type'")
+        if ai21_inference_id in SKIP_IN_PATH:
+            raise ValueError("Empty value passed for parameter 'ai21_inference_id'")
+        if service is None and body is None:
+            raise ValueError("Empty value passed for parameter 'service'")
+        if service_settings is None and body is None:
+            raise ValueError("Empty value passed for parameter 'service_settings'")
+        __path_parts: t.Dict[str, str] = {
+            "task_type": _quote(task_type),
+            "ai21_inference_id": _quote(ai21_inference_id),
+        }
+        __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["ai21_inference_id"]}'
+        __query: t.Dict[str, t.Any] = {}
+        __body: t.Dict[str, t.Any] = body if body is not None else {}
+        if error_trace is not None:
+            __query["error_trace"] = error_trace
+        if filter_path is not None:
+            __query["filter_path"] = filter_path
+        if human is not None:
+            __query["human"] = human
+        if pretty is not None:
+            __query["pretty"] = pretty
+        if timeout is not None:
+            __query["timeout"] = timeout
+        if not __body:
+            if service is not None:
+                __body["service"] = service
+            if service_settings is not None:
+                __body["service_settings"] = service_settings
+        __headers = {"accept": "application/json", "content-type": "application/json"}
+        return self.perform_request(  # type: ignore[return-value]
+            "PUT",
+            __path,
+            params=__query,
+            headers=__headers,
+            body=__body,
+            endpoint_id="inference.put_ai21",
+            path_parts=__path_parts,
+        )
+
+    @_rewrite_parameters(
         body_fields=(
             "service",
             "service_settings",
@@ -546,11 +615,7 @@ class InferenceClient(NamespacedClient):
                 __body["chunking_settings"] = chunking_settings
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -646,11 +711,7 @@ class InferenceClient(NamespacedClient):
                 __body["chunking_settings"] = chunking_settings
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -752,11 +813,7 @@ class InferenceClient(NamespacedClient):
                 __body["chunking_settings"] = chunking_settings
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -849,11 +906,7 @@ class InferenceClient(NamespacedClient):
                 __body["chunking_settings"] = chunking_settings
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -875,7 +928,7 @@ class InferenceClient(NamespacedClient):
     def put_azureaistudio(
         self,
         *,
-        task_type: t.Union[str, t.Literal["completion", "text_embedding"]],
+        task_type: t.Union[str, t.Literal["completion", "rerank", "text_embedding"]],
         azureaistudio_inference_id: str,
         service: t.Optional[t.Union[str, t.Literal["azureaistudio"]]] = None,
         service_settings: t.Optional[t.Mapping[str, t.Any]] = None,
@@ -945,11 +998,7 @@ class InferenceClient(NamespacedClient):
                 __body["chunking_settings"] = chunking_settings
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -1049,11 +1098,7 @@ class InferenceClient(NamespacedClient):
                 __body["chunking_settings"] = chunking_settings
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -1143,11 +1188,7 @@ class InferenceClient(NamespacedClient):
                 __body["chunking_settings"] = chunking_settings
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -1166,6 +1207,99 @@ class InferenceClient(NamespacedClient):
             "task_settings",
         ),
     )
+    def put_contextualai(
+        self,
+        *,
+        task_type: t.Union[str, t.Literal["rerank"]],
+        contextualai_inference_id: str,
+        service: t.Optional[t.Union[str, t.Literal["contextualai"]]] = None,
+        service_settings: t.Optional[t.Mapping[str, t.Any]] = None,
+        chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None,
+        error_trace: t.Optional[bool] = None,
+        filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        human: t.Optional[bool] = None,
+        pretty: t.Optional[bool] = None,
+        task_settings: t.Optional[t.Mapping[str, t.Any]] = None,
+        timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
+        body: t.Optional[t.Dict[str, t.Any]] = None,
+    ) -> ObjectApiResponse[t.Any]:
+        """
+        .. raw:: html
+
+          <p>Create an Contextual AI inference endpoint.</p>
+          <p>Create an inference endpoint to perform an inference task with the <code>contexualai</code> service.</p>
+          <p>To review the available <code>rerank</code> models, refer to <a href="https://docs.contextual.ai/api-reference/rerank/rerank#body-model">https://docs.contextual.ai/api-reference/rerank/rerank#body-model</a>.</p>
+
+
+        `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-put-contextualai>`_
+
+        :param task_type: The type of the inference task that the model will perform.
+        :param contextualai_inference_id: The unique identifier of the inference endpoint.
+        :param service: The type of service supported for the specified task type. In
+            this case, `contextualai`.
+        :param service_settings: Settings used to install the inference model. These
+            settings are specific to the `contextualai` service.
+        :param chunking_settings: The chunking configuration object.
+        :param task_settings: Settings to configure the inference task. These settings
+            are specific to the task type you specified.
+        :param timeout: Specifies the amount of time to wait for the inference endpoint
+            to be created.
+        """
+        if task_type in SKIP_IN_PATH:
+            raise ValueError("Empty value passed for parameter 'task_type'")
+        if contextualai_inference_id in SKIP_IN_PATH:
+            raise ValueError(
+                "Empty value passed for parameter 'contextualai_inference_id'"
+            )
+        if service is None and body is None:
+            raise ValueError("Empty value passed for parameter 'service'")
+        if service_settings is None and body is None:
+            raise ValueError("Empty value passed for parameter 'service_settings'")
+        __path_parts: t.Dict[str, str] = {
+            "task_type": _quote(task_type),
+            "contextualai_inference_id": _quote(contextualai_inference_id),
+        }
+        __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["contextualai_inference_id"]}'
+        __query: t.Dict[str, t.Any] = {}
+        __body: t.Dict[str, t.Any] = body if body is not None else {}
+        if error_trace is not None:
+            __query["error_trace"] = error_trace
+        if filter_path is not None:
+            __query["filter_path"] = filter_path
+        if human is not None:
+            __query["human"] = human
+        if pretty is not None:
+            __query["pretty"] = pretty
+        if timeout is not None:
+            __query["timeout"] = timeout
+        if not __body:
+            if service is not None:
+                __body["service"] = service
+            if service_settings is not None:
+                __body["service_settings"] = service_settings
+            if chunking_settings is not None:
+                __body["chunking_settings"] = chunking_settings
+            if task_settings is not None:
+                __body["task_settings"] = task_settings
+        __headers = {"accept": "application/json", "content-type": "application/json"}
+        return self.perform_request(  # type: ignore[return-value]
+            "PUT",
+            __path,
+            params=__query,
+            headers=__headers,
+            body=__body,
+            endpoint_id="inference.put_contextualai",
+            path_parts=__path_parts,
+        )
+
+    @_rewrite_parameters(
+        body_fields=(
+            "service",
+            "service_settings",
+            "chunking_settings",
+            "task_settings",
+        ),
+    )
     def put_custom(
         self,
         *,
@@ -1274,11 +1408,7 @@ class InferenceClient(NamespacedClient):
                 __body["chunking_settings"] = chunking_settings
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -1358,11 +1488,7 @@ class InferenceClient(NamespacedClient):
                 __body["service_settings"] = service_settings
             if chunking_settings is not None:
                 __body["chunking_settings"] = chunking_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -1470,11 +1596,7 @@ class InferenceClient(NamespacedClient):
                 __body["chunking_settings"] = chunking_settings
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -1532,7 +1654,8 @@ class InferenceClient(NamespacedClient):
             this case, `elser`.
         :param service_settings: Settings used to install the inference model. These
             settings are specific to the `elser` service.
-        :param chunking_settings: The chunking configuration object.
+        :param chunking_settings: The chunking configuration object. Note that for ELSER
+            endpoints, the max_chunk_size may not exceed `300`.
         :param timeout: Specifies the amount of time to wait for the inference endpoint
             to be created.
         """
@@ -1568,11 +1691,7 @@ class InferenceClient(NamespacedClient):
                 __body["service_settings"] = service_settings
             if chunking_settings is not None:
                 __body["chunking_settings"] = chunking_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -1654,11 +1773,7 @@ class InferenceClient(NamespacedClient):
                 __body["service_settings"] = service_settings
             if chunking_settings is not None:
                 __body["chunking_settings"] = chunking_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -1752,11 +1867,7 @@ class InferenceClient(NamespacedClient):
                 __body["chunking_settings"] = chunking_settings
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -1884,11 +1995,7 @@ class InferenceClient(NamespacedClient):
                 __body["chunking_settings"] = chunking_settings
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -1980,11 +2087,7 @@ class InferenceClient(NamespacedClient):
                 __body["chunking_settings"] = chunking_settings
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -1998,6 +2101,88 @@ class InferenceClient(NamespacedClient):
     @_rewrite_parameters(
         body_fields=("service", "service_settings", "chunking_settings"),
     )
+    def put_llama(
+        self,
+        *,
+        task_type: t.Union[
+            str, t.Literal["chat_completion", "completion", "text_embedding"]
+        ],
+        llama_inference_id: str,
+        service: t.Optional[t.Union[str, t.Literal["llama"]]] = None,
+        service_settings: t.Optional[t.Mapping[str, t.Any]] = None,
+        chunking_settings: t.Optional[t.Mapping[str, t.Any]] = None,
+        error_trace: t.Optional[bool] = None,
+        filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        human: t.Optional[bool] = None,
+        pretty: t.Optional[bool] = None,
+        timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
+        body: t.Optional[t.Dict[str, t.Any]] = None,
+    ) -> ObjectApiResponse[t.Any]:
+        """
+        .. raw:: html
+
+          <p>Create a Llama inference endpoint.</p>
+          <p>Create an inference endpoint to perform an inference task with the <code>llama</code> service.</p>
+
+
+        `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-put-llama>`_
+
+        :param task_type: The type of the inference task that the model will perform.
+        :param llama_inference_id: The unique identifier of the inference endpoint.
+        :param service: The type of service supported for the specified task type. In
+            this case, `llama`.
+        :param service_settings: Settings used to install the inference model. These
+            settings are specific to the `llama` service.
+        :param chunking_settings: The chunking configuration object.
+        :param timeout: Specifies the amount of time to wait for the inference endpoint
+            to be created.
+        """
+        if task_type in SKIP_IN_PATH:
+            raise ValueError("Empty value passed for parameter 'task_type'")
+        if llama_inference_id in SKIP_IN_PATH:
+            raise ValueError("Empty value passed for parameter 'llama_inference_id'")
+        if service is None and body is None:
+            raise ValueError("Empty value passed for parameter 'service'")
+        if service_settings is None and body is None:
+            raise ValueError("Empty value passed for parameter 'service_settings'")
+        __path_parts: t.Dict[str, str] = {
+            "task_type": _quote(task_type),
+            "llama_inference_id": _quote(llama_inference_id),
+        }
+        __path = f'/_inference/{__path_parts["task_type"]}/{__path_parts["llama_inference_id"]}'
+        __query: t.Dict[str, t.Any] = {}
+        __body: t.Dict[str, t.Any] = body if body is not None else {}
+        if error_trace is not None:
+            __query["error_trace"] = error_trace
+        if filter_path is not None:
+            __query["filter_path"] = filter_path
+        if human is not None:
+            __query["human"] = human
+        if pretty is not None:
+            __query["pretty"] = pretty
+        if timeout is not None:
+            __query["timeout"] = timeout
+        if not __body:
+            if service is not None:
+                __body["service"] = service
+            if service_settings is not None:
+                __body["service_settings"] = service_settings
+            if chunking_settings is not None:
+                __body["chunking_settings"] = chunking_settings
+        __headers = {"accept": "application/json", "content-type": "application/json"}
+        return self.perform_request(  # type: ignore[return-value]
+            "PUT",
+            __path,
+            params=__query,
+            headers=__headers,
+            body=__body,
+            endpoint_id="inference.put_llama",
+            path_parts=__path_parts,
+        )
+
+    @_rewrite_parameters(
+        body_fields=("service", "service_settings", "chunking_settings"),
+    )
     def put_mistral(
         self,
         *,
@@ -2066,11 +2251,7 @@ class InferenceClient(NamespacedClient):
                 __body["service_settings"] = service_settings
             if chunking_settings is not None:
                 __body["chunking_settings"] = chunking_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -2164,11 +2345,7 @@ class InferenceClient(NamespacedClient):
                 __body["chunking_settings"] = chunking_settings
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -2259,11 +2436,7 @@ class InferenceClient(NamespacedClient):
                 __body["chunking_settings"] = chunking_settings
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -2343,11 +2516,7 @@ class InferenceClient(NamespacedClient):
                 __body["service"] = service
             if service_settings is not None:
                 __body["service_settings"] = service_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
@@ -2420,11 +2589,7 @@ class InferenceClient(NamespacedClient):
                 __body["query"] = query
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "POST",
             __path,
@@ -2488,11 +2653,7 @@ class InferenceClient(NamespacedClient):
                 __body["input"] = input
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "POST",
             __path,
@@ -2504,7 +2665,7 @@ class InferenceClient(NamespacedClient):
         )
 
     @_rewrite_parameters(
-        body_fields=("input", "task_settings"),
+        body_fields=("input", "input_type", "task_settings"),
     )
     def text_embedding(
         self,
@@ -2514,6 +2675,7 @@ class InferenceClient(NamespacedClient):
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         human: t.Optional[bool] = None,
+        input_type: t.Optional[str] = None,
         pretty: t.Optional[bool] = None,
         task_settings: t.Optional[t.Any] = None,
         timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
@@ -2529,6 +2691,13 @@ class InferenceClient(NamespacedClient):
 
         :param inference_id: The inference Id
         :param input: Inference input. Either a string or an array of strings.
+        :param input_type: The input data type for the text embedding model. Possible
+            values include: * `SEARCH` * `INGEST` * `CLASSIFICATION` * `CLUSTERING` Not
+            all services support all values. Unsupported values will trigger a validation
+            exception. Accepted values depend on the configured inference service, refer
+            to the relevant service-specific documentation for more info. > info > The
+            `input_type` parameter specified on the root level of the request body will
+            take precedence over the `input_type` parameter specified in `task_settings`.
         :param task_settings: Optional task settings
         :param timeout: Specifies the amount of time to wait for the inference request
             to complete.
@@ -2554,13 +2723,11 @@ class InferenceClient(NamespacedClient):
         if not __body:
             if input is not None:
                 __body["input"] = input
+            if input_type is not None:
+                __body["input_type"] = input_type
             if task_settings is not None:
                 __body["task_settings"] = task_settings
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "POST",
             __path,
diff -pruN 9.1.1-2/elasticsearch/_sync/client/ingest.py 9.2.0-1/elasticsearch/_sync/client/ingest.py
--- 9.1.1-2/elasticsearch/_sync/client/ingest.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_sync/client/ingest.py	2025-10-28 16:50:53.000000000 +0000
@@ -580,6 +580,7 @@ class IngestClient(NamespacedClient):
         body_fields=(
             "deprecated",
             "description",
+            "field_access_pattern",
             "meta",
             "on_failure",
             "processors",
@@ -594,6 +595,9 @@ class IngestClient(NamespacedClient):
         deprecated: t.Optional[bool] = None,
         description: t.Optional[str] = None,
         error_trace: t.Optional[bool] = None,
+        field_access_pattern: t.Optional[
+            t.Union[str, t.Literal["classic", "flexible"]]
+        ] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         human: t.Optional[bool] = None,
         if_version: t.Optional[int] = None,
@@ -621,6 +625,8 @@ class IngestClient(NamespacedClient):
             or updating a non-deprecated index template, Elasticsearch will emit a deprecation
             warning.
         :param description: Description of the ingest pipeline.
+        :param field_access_pattern: Controls how processors in this pipeline should
+            read and write data on a document's source.
         :param if_version: Required version for optimistic concurrency control for pipeline
             updates
         :param master_timeout: Period to wait for a connection to the master node. If
@@ -667,6 +673,8 @@ class IngestClient(NamespacedClient):
                 __body["deprecated"] = deprecated
             if description is not None:
                 __body["description"] = description
+            if field_access_pattern is not None:
+                __body["field_access_pattern"] = field_access_pattern
             if meta is not None:
                 __body["_meta"] = meta
             if on_failure is not None:
diff -pruN 9.1.1-2/elasticsearch/_sync/client/license.py 9.2.0-1/elasticsearch/_sync/client/license.py
--- 9.1.1-2/elasticsearch/_sync/client/license.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_sync/client/license.py	2025-10-28 16:50:53.000000000 +0000
@@ -104,8 +104,10 @@ class LicenseClient(NamespacedClient):
             license types. If `false`, this parameter returns platinum for both platinum
             and enterprise license types. This behavior is maintained for backwards compatibility.
             This parameter is deprecated and will always be set to true in 8.x.
-        :param local: Specifies whether to retrieve local information. The default value
-            is `false`, which means the information is retrieved from the master node.
+        :param local: Specifies whether to retrieve local information. From 9.2 onwards
+            the default value is `true`, which means the information is retrieved from
+            the responding node. In earlier versions the default is `false`, which means
+            the information is retrieved from the elected master node.
         """
         __path_parts: t.Dict[str, str] = {}
         __path = "/_license"
diff -pruN 9.1.1-2/elasticsearch/_sync/client/logstash.py 9.2.0-1/elasticsearch/_sync/client/logstash.py
--- 9.1.1-2/elasticsearch/_sync/client/logstash.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_sync/client/logstash.py	2025-10-28 16:50:53.000000000 +0000
@@ -141,7 +141,9 @@ class LogstashClient(NamespacedClient):
 
         `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-logstash-put-pipeline>`_
 
-        :param id: An identifier for the pipeline.
+        :param id: An identifier for the pipeline. Pipeline IDs must begin with a letter
+            or underscore and contain only letters, underscores, dashes, hyphens and
+            numbers.
         :param pipeline:
         """
         if id in SKIP_IN_PATH:
diff -pruN 9.1.1-2/elasticsearch/_sync/client/ml.py 9.2.0-1/elasticsearch/_sync/client/ml.py
--- 9.1.1-2/elasticsearch/_sync/client/ml.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_sync/client/ml.py	2025-10-28 16:50:53.000000000 +0000
@@ -2390,7 +2390,7 @@ class MlClient(NamespacedClient):
         exclude_interim: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         human: t.Optional[bool] = None,
-        overall_score: t.Optional[t.Union[float, str]] = None,
+        overall_score: t.Optional[float] = None,
         pretty: t.Optional[bool] = None,
         start: t.Optional[t.Union[str, t.Any]] = None,
         top_n: t.Optional[int] = None,
@@ -5716,7 +5716,7 @@ class MlClient(NamespacedClient):
           <p>Validate an anomaly detection job.</p>
 
 
-        `<https://www.elastic.co/guide/en/machine-learning/9.1/ml-jobs.html>`_
+        `<https://www.elastic.co/guide/en/machine-learning/9.2/ml-jobs.html>`_
 
         :param analysis_config:
         :param analysis_limits:
diff -pruN 9.1.1-2/elasticsearch/_sync/client/nodes.py 9.2.0-1/elasticsearch/_sync/client/nodes.py
--- 9.1.1-2/elasticsearch/_sync/client/nodes.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_sync/client/nodes.py	2025-10-28 16:50:53.000000000 +0000
@@ -368,9 +368,7 @@ class NodesClient(NamespacedClient):
         human: t.Optional[bool] = None,
         include_segment_file_sizes: t.Optional[bool] = None,
         include_unloaded_segments: t.Optional[bool] = None,
-        level: t.Optional[
-            t.Union[str, t.Literal["cluster", "indices", "shards"]]
-        ] = None,
+        level: t.Optional[t.Union[str, t.Literal["indices", "node", "shards"]]] = None,
         pretty: t.Optional[bool] = None,
         timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         types: t.Optional[t.Sequence[str]] = None,
@@ -404,8 +402,8 @@ class NodesClient(NamespacedClient):
             are requested).
         :param include_unloaded_segments: If `true`, the response includes information
             from segments that are not loaded into memory.
-        :param level: Indicates whether statistics are aggregated at the cluster, index,
-            or shard level.
+        :param level: Indicates whether statistics are aggregated at the node, indices,
+            or shards level.
         :param timeout: Period to wait for a response. If no response is received before
             the timeout expires, the request fails and returns an error.
         :param types: A comma-separated list of document types for the indexing index
diff -pruN 9.1.1-2/elasticsearch/_sync/client/project.py 9.2.0-1/elasticsearch/_sync/client/project.py
--- 9.1.1-2/elasticsearch/_sync/client/project.py	1970-01-01 00:00:00.000000000 +0000
+++ 9.2.0-1/elasticsearch/_sync/client/project.py	2025-10-28 16:50:53.000000000 +0000
@@ -0,0 +1,67 @@
+#  Licensed to Elasticsearch B.V. under one or more contributor
+#  license agreements. See the NOTICE file distributed with
+#  this work for additional information regarding copyright
+#  ownership. Elasticsearch B.V. licenses this file to you under
+#  the Apache License, Version 2.0 (the "License"); you may
+#  not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+# 	http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing,
+#  software distributed under the License is distributed on an
+#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#  KIND, either express or implied.  See the License for the
+#  specific language governing permissions and limitations
+#  under the License.
+
+import typing as t
+
+from elastic_transport import ObjectApiResponse
+
+from ._base import NamespacedClient
+from .utils import (
+    Stability,
+    _rewrite_parameters,
+    _stability_warning,
+)
+
+
+class ProjectClient(NamespacedClient):
+
+    @_rewrite_parameters()
+    @_stability_warning(Stability.EXPERIMENTAL)
+    def tags(
+        self,
+        *,
+        error_trace: t.Optional[bool] = None,
+        filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        human: t.Optional[bool] = None,
+        pretty: t.Optional[bool] = None,
+    ) -> ObjectApiResponse[t.Any]:
+        """
+        .. raw:: html
+
+          <p>Return tags defined for the project</p>
+
+        """
+        __path_parts: t.Dict[str, str] = {}
+        __path = "/_project/tags"
+        __query: t.Dict[str, t.Any] = {}
+        if error_trace is not None:
+            __query["error_trace"] = error_trace
+        if filter_path is not None:
+            __query["filter_path"] = filter_path
+        if human is not None:
+            __query["human"] = human
+        if pretty is not None:
+            __query["pretty"] = pretty
+        __headers = {"accept": "application/json"}
+        return self.perform_request(  # type: ignore[return-value]
+            "GET",
+            __path,
+            params=__query,
+            headers=__headers,
+            endpoint_id="project.tags",
+            path_parts=__path_parts,
+        )
diff -pruN 9.1.1-2/elasticsearch/_sync/client/security.py 9.2.0-1/elasticsearch/_sync/client/security.py
--- 9.1.1-2/elasticsearch/_sync/client/security.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_sync/client/security.py	2025-10-28 16:50:53.000000000 +0000
@@ -2052,6 +2052,45 @@ class SecurityClient(NamespacedClient):
             path_parts=__path_parts,
         )
 
+    @_rewrite_parameters()
+    def get_stats(
+        self,
+        *,
+        error_trace: t.Optional[bool] = None,
+        filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        human: t.Optional[bool] = None,
+        pretty: t.Optional[bool] = None,
+    ) -> ObjectApiResponse[t.Any]:
+        """
+        .. raw:: html
+
+          <p>Get security stats.</p>
+          <p>Gather security usage statistics from all node(s) within the cluster.</p>
+
+
+        `<https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-security-get-stats>`_
+        """
+        __path_parts: t.Dict[str, str] = {}
+        __path = "/_security/stats"
+        __query: t.Dict[str, t.Any] = {}
+        if error_trace is not None:
+            __query["error_trace"] = error_trace
+        if filter_path is not None:
+            __query["filter_path"] = filter_path
+        if human is not None:
+            __query["human"] = human
+        if pretty is not None:
+            __query["pretty"] = pretty
+        __headers = {"accept": "application/json"}
+        return self.perform_request(  # type: ignore[return-value]
+            "GET",
+            __path,
+            params=__query,
+            headers=__headers,
+            endpoint_id="security.get_stats",
+            path_parts=__path_parts,
+        )
+
     @_rewrite_parameters(
         body_fields=(
             "grant_type",
diff -pruN 9.1.1-2/elasticsearch/_sync/client/shutdown.py 9.2.0-1/elasticsearch/_sync/client/shutdown.py
--- 9.1.1-2/elasticsearch/_sync/client/shutdown.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_sync/client/shutdown.py	2025-10-28 16:50:53.000000000 +0000
@@ -33,13 +33,9 @@ class ShutdownClient(NamespacedClient):
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         human: t.Optional[bool] = None,
-        master_timeout: t.Optional[
-            t.Union[str, t.Literal["d", "h", "m", "micros", "ms", "nanos", "s"]]
-        ] = None,
+        master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         pretty: t.Optional[bool] = None,
-        timeout: t.Optional[
-            t.Union[str, t.Literal["d", "h", "m", "micros", "ms", "nanos", "s"]]
-        ] = None,
+        timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
     ) -> ObjectApiResponse[t.Any]:
         """
         .. raw:: html
@@ -97,9 +93,7 @@ class ShutdownClient(NamespacedClient):
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         human: t.Optional[bool] = None,
-        master_timeout: t.Optional[
-            t.Union[str, t.Literal["d", "h", "m", "micros", "ms", "nanos", "s"]]
-        ] = None,
+        master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         pretty: t.Optional[bool] = None,
     ) -> ObjectApiResponse[t.Any]:
         """
@@ -162,14 +156,10 @@ class ShutdownClient(NamespacedClient):
         error_trace: t.Optional[bool] = None,
         filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
         human: t.Optional[bool] = None,
-        master_timeout: t.Optional[
-            t.Union[str, t.Literal["d", "h", "m", "micros", "ms", "nanos", "s"]]
-        ] = None,
+        master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         pretty: t.Optional[bool] = None,
         target_node_name: t.Optional[str] = None,
-        timeout: t.Optional[
-            t.Union[str, t.Literal["d", "h", "m", "micros", "ms", "nanos", "s"]]
-        ] = None,
+        timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         body: t.Optional[t.Dict[str, t.Any]] = None,
     ) -> ObjectApiResponse[t.Any]:
         """
diff -pruN 9.1.1-2/elasticsearch/_sync/client/simulate.py 9.2.0-1/elasticsearch/_sync/client/simulate.py
--- 9.1.1-2/elasticsearch/_sync/client/simulate.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_sync/client/simulate.py	2025-10-28 16:50:53.000000000 +0000
@@ -56,6 +56,7 @@ class SimulateClient(NamespacedClient):
             t.Mapping[str, t.Mapping[str, t.Any]]
         ] = None,
         mapping_addition: t.Optional[t.Mapping[str, t.Any]] = None,
+        merge_type: t.Optional[t.Union[str, t.Literal["index", "template"]]] = None,
         pipeline: t.Optional[str] = None,
         pipeline_substitutions: t.Optional[
             t.Mapping[str, t.Mapping[str, t.Any]]
@@ -93,6 +94,11 @@ class SimulateClient(NamespacedClient):
         :param index_template_substitutions: A map of index template names to substitute
             index template definition objects.
         :param mapping_addition:
+        :param merge_type: The mapping merge type if mapping overrides are being provided
+            in mapping_addition. The allowed values are one of index or template. The
+            index option merges mappings the way they would be merged into an existing
+            index. The template option merges mappings the way they would be merged into
+            a template.
         :param pipeline: The pipeline to use as the default pipeline. This value can
             be used to override the default pipeline of the index.
         :param pipeline_substitutions: Pipelines to test. If you don’t specify the `pipeline`
@@ -116,6 +122,8 @@ class SimulateClient(NamespacedClient):
             __query["filter_path"] = filter_path
         if human is not None:
             __query["human"] = human
+        if merge_type is not None:
+            __query["merge_type"] = merge_type
         if pipeline is not None:
             __query["pipeline"] = pipeline
         if pretty is not None:
diff -pruN 9.1.1-2/elasticsearch/_sync/client/slm.py 9.2.0-1/elasticsearch/_sync/client/slm.py
--- 9.1.1-2/elasticsearch/_sync/client/slm.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_sync/client/slm.py	2025-10-28 16:50:53.000000000 +0000
@@ -431,11 +431,7 @@ class SlmClient(NamespacedClient):
                 __body["retention"] = retention
             if schedule is not None:
                 __body["schedule"] = schedule
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
diff -pruN 9.1.1-2/elasticsearch/_sync/client/snapshot.py 9.2.0-1/elasticsearch/_sync/client/snapshot.py
--- 9.1.1-2/elasticsearch/_sync/client/snapshot.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_sync/client/snapshot.py	2025-10-28 16:50:53.000000000 +0000
@@ -872,35 +872,40 @@ class SnapshotClient(NamespacedClient):
 
         :param name: The name of the repository.
         :param blob_count: The total number of blobs to write to the repository during
-            the test. For realistic experiments, you should set it to at least `2000`.
+            the test. For realistic experiments, set this parameter to at least `2000`.
         :param concurrency: The number of operations to run concurrently during the test.
+            For realistic experiments, leave this parameter unset.
         :param detailed: Indicates whether to return detailed results, including timing
             information for every operation performed during the analysis. If false,
             it returns only a summary of the analysis.
         :param early_read_node_count: The number of nodes on which to perform an early
             read operation while writing each blob. Early read operations are only rarely
-            performed.
+            performed. For realistic experiments, leave this parameter unset.
         :param max_blob_size: The maximum size of a blob to be written during the test.
-            For realistic experiments, you should set it to at least `2gb`.
+            For realistic experiments, set this parameter to at least `2gb`.
         :param max_total_data_size: An upper limit on the total size of all the blobs
-            written during the test. For realistic experiments, you should set it to
+            written during the test. For realistic experiments, set this parameter to
             at least `1tb`.
         :param rare_action_probability: The probability of performing a rare action such
-            as an early read, an overwrite, or an aborted write on each blob.
+            as an early read, an overwrite, or an aborted write on each blob. For realistic
+            experiments, leave this parameter unset.
         :param rarely_abort_writes: Indicates whether to rarely cancel writes before
-            they complete.
+            they complete. For realistic experiments, leave this parameter unset.
         :param read_node_count: The number of nodes on which to read a blob after writing.
+            For realistic experiments, leave this parameter unset.
         :param register_operation_count: The minimum number of linearizable register
-            operations to perform in total. For realistic experiments, you should set
-            it to at least `100`.
+            operations to perform in total. For realistic experiments, set this parameter
+            to at least `100`.
         :param seed: The seed for the pseudo-random number generator used to generate
             the list of operations performed during the test. To repeat the same set
             of operations in multiple experiments, use the same seed in each experiment.
             Note that the operations are performed concurrently so might not always happen
-            in the same order on each run.
+            in the same order on each run. For realistic experiments, leave this parameter
+            unset.
         :param timeout: The period of time to wait for the test to complete. If no response
             is received before the timeout expires, the test is cancelled and returns
-            an error.
+            an error. For realistic experiments, set this parameter sufficiently long
+            to allow the test to complete.
         """
         if name in SKIP_IN_PATH:
             raise ValueError("Empty value passed for parameter 'name'")
@@ -1266,6 +1271,11 @@ class SnapshotClient(NamespacedClient):
           <p>If you omit the <code>&lt;snapshot&gt;</code> request path parameter, the request retrieves information only for currently running snapshots.
           This usage is preferred.
           If needed, you can specify <code>&lt;repository&gt;</code> and <code>&lt;snapshot&gt;</code> to retrieve information for specific snapshots, even if they're not currently running.</p>
+          <p>Note that the stats will not be available for any shard snapshots in an ongoing snapshot completed by a node that (even momentarily) left the cluster.
+          Loading the stats from the repository is an expensive operation (see the WARNING below).
+          Therefore the stats values for such shards will be -1 even though the &quot;stage&quot; value will be &quot;DONE&quot;, in order to minimize latency.
+          A &quot;description&quot; field will be present for a shard snapshot completed by a departed node explaining why the shard snapshot's stats results are invalid.
+          Consequently, the total stats for the index will be less than expected due to the missing values from these shards.</p>
           <p>WARNING: Using the API to return the status of any snapshots other than currently running snapshots can be expensive.
           The API requires a read from the repository for each shard in each snapshot.
           For example, if you have 100 snapshots with 1,000 shards each, an API request that includes all snapshots will require 100,000 reads (100 snapshots x 1,000 shards).</p>
diff -pruN 9.1.1-2/elasticsearch/_sync/client/sql.py 9.2.0-1/elasticsearch/_sync/client/sql.py
--- 9.1.1-2/elasticsearch/_sync/client/sql.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_sync/client/sql.py	2025-10-28 16:50:53.000000000 +0000
@@ -285,6 +285,7 @@ class SqlClient(NamespacedClient):
         page_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         params: t.Optional[t.Sequence[t.Any]] = None,
         pretty: t.Optional[bool] = None,
+        project_routing: t.Optional[str] = None,
         query: t.Optional[str] = None,
         request_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
         runtime_mappings: t.Optional[t.Mapping[str, t.Mapping[str, t.Any]]] = None,
@@ -332,6 +333,10 @@ class SqlClient(NamespacedClient):
             is no longer available. Subsequent scroll requests prolong the lifetime of
             the scroll cursor by the duration of `page_timeout` in the scroll request.
         :param params: The values for parameters in the query.
+        :param project_routing: Specifies a subset of projects to target for the search
+            using project metadata tags in a subset of Lucene query syntax. Allowed Lucene
+            queries: the _alias tag and a single value (possibly wildcarded). Examples:
+            _alias:my-project _alias:_origin _alias:*pr* Supported in serverless only.
         :param query: The SQL query to run.
         :param request_timeout: The timeout before the request fails.
         :param runtime_mappings: One or more runtime fields for the search request. These
@@ -357,6 +362,8 @@ class SqlClient(NamespacedClient):
             __query["human"] = human
         if pretty is not None:
             __query["pretty"] = pretty
+        if project_routing is not None:
+            __query["project_routing"] = project_routing
         if not __body:
             if allow_partial_search_results is not None:
                 __body["allow_partial_search_results"] = allow_partial_search_results
diff -pruN 9.1.1-2/elasticsearch/_sync/client/streams.py 9.2.0-1/elasticsearch/_sync/client/streams.py
--- 9.1.1-2/elasticsearch/_sync/client/streams.py	1970-01-01 00:00:00.000000000 +0000
+++ 9.2.0-1/elasticsearch/_sync/client/streams.py	2025-10-28 16:50:53.000000000 +0000
@@ -0,0 +1,185 @@
+#  Licensed to Elasticsearch B.V. under one or more contributor
+#  license agreements. See the NOTICE file distributed with
+#  this work for additional information regarding copyright
+#  ownership. Elasticsearch B.V. licenses this file to you under
+#  the Apache License, Version 2.0 (the "License"); you may
+#  not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+# 	http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing,
+#  software distributed under the License is distributed on an
+#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#  KIND, either express or implied.  See the License for the
+#  specific language governing permissions and limitations
+#  under the License.
+
+
+import typing as t
+
+from elastic_transport import ObjectApiResponse, TextApiResponse
+
+from ._base import NamespacedClient
+from .utils import (
+    Stability,
+    _rewrite_parameters,
+    _stability_warning,
+)
+
+
+class StreamsClient(NamespacedClient):
+
+    @_rewrite_parameters()
+    @_stability_warning(Stability.EXPERIMENTAL)
+    def logs_disable(
+        self,
+        *,
+        error_trace: t.Optional[bool] = None,
+        filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        human: t.Optional[bool] = None,
+        master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
+        pretty: t.Optional[bool] = None,
+        timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
+    ) -> t.Union[ObjectApiResponse[t.Any], TextApiResponse]:
+        """
+        .. raw:: html
+
+          <p>Disable logs stream.</p>
+          <p>Turn off the logs stream feature for this cluster.</p>
+
+
+        `<https://www.elastic.co/docs/api/doc/elasticsearch#TODO>`_
+
+        :param master_timeout: The period to wait for a connection to the master node.
+            If no response is received before the timeout expires, the request fails
+            and returns an error.
+        :param timeout: The period to wait for a response. If no response is received
+            before the timeout expires, the request fails and returns an error.
+        """
+        __path_parts: t.Dict[str, str] = {}
+        __path = "/_streams/logs/_disable"
+        __query: t.Dict[str, t.Any] = {}
+        if error_trace is not None:
+            __query["error_trace"] = error_trace
+        if filter_path is not None:
+            __query["filter_path"] = filter_path
+        if human is not None:
+            __query["human"] = human
+        if master_timeout is not None:
+            __query["master_timeout"] = master_timeout
+        if pretty is not None:
+            __query["pretty"] = pretty
+        if timeout is not None:
+            __query["timeout"] = timeout
+        __headers = {"accept": "application/json,text/plain"}
+        return self.perform_request(  # type: ignore[return-value]
+            "POST",
+            __path,
+            params=__query,
+            headers=__headers,
+            endpoint_id="streams.logs_disable",
+            path_parts=__path_parts,
+        )
+
+    @_rewrite_parameters()
+    @_stability_warning(Stability.EXPERIMENTAL)
+    def logs_enable(
+        self,
+        *,
+        error_trace: t.Optional[bool] = None,
+        filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        human: t.Optional[bool] = None,
+        master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
+        pretty: t.Optional[bool] = None,
+        timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
+    ) -> t.Union[ObjectApiResponse[t.Any], TextApiResponse]:
+        """
+        .. raw:: html
+
+          <p>Enable logs stream.</p>
+          <p>Turn on the logs stream feature for this cluster.</p>
+          <p>NOTE: To protect existing data, this feature can be turned on only if the
+          cluster does not have existing indices or data streams that match the pattern <code>logs|logs.*</code>.
+          If those indices or data streams exist, a <code>409 - Conflict</code> response and error is returned.</p>
+
+
+        `<https://www.elastic.co/docs/api/doc/elasticsearch#TODO>`_
+
+        :param master_timeout: The period to wait for a connection to the master node.
+            If no response is received before the timeout expires, the request fails
+            and returns an error.
+        :param timeout: The period to wait for a response. If no response is received
+            before the timeout expires, the request fails and returns an error.
+        """
+        __path_parts: t.Dict[str, str] = {}
+        __path = "/_streams/logs/_enable"
+        __query: t.Dict[str, t.Any] = {}
+        if error_trace is not None:
+            __query["error_trace"] = error_trace
+        if filter_path is not None:
+            __query["filter_path"] = filter_path
+        if human is not None:
+            __query["human"] = human
+        if master_timeout is not None:
+            __query["master_timeout"] = master_timeout
+        if pretty is not None:
+            __query["pretty"] = pretty
+        if timeout is not None:
+            __query["timeout"] = timeout
+        __headers = {"accept": "application/json,text/plain"}
+        return self.perform_request(  # type: ignore[return-value]
+            "POST",
+            __path,
+            params=__query,
+            headers=__headers,
+            endpoint_id="streams.logs_enable",
+            path_parts=__path_parts,
+        )
+
+    @_rewrite_parameters()
+    @_stability_warning(Stability.EXPERIMENTAL)
+    def status(
+        self,
+        *,
+        error_trace: t.Optional[bool] = None,
+        filter_path: t.Optional[t.Union[str, t.Sequence[str]]] = None,
+        human: t.Optional[bool] = None,
+        master_timeout: t.Optional[t.Union[str, t.Literal[-1], t.Literal[0]]] = None,
+        pretty: t.Optional[bool] = None,
+    ) -> ObjectApiResponse[t.Any]:
+        """
+        .. raw:: html
+
+          <p>Get the status of streams.</p>
+          <p>Get the current status for all types of streams.</p>
+
+
+        `<https://www.elastic.co/docs/api/doc/elasticsearch#TODO>`_
+
+        :param master_timeout: Period to wait for a connection to the master node. If
+            no response is received before the timeout expires, the request fails and
+            returns an error.
+        """
+        __path_parts: t.Dict[str, str] = {}
+        __path = "/_streams/status"
+        __query: t.Dict[str, t.Any] = {}
+        if error_trace is not None:
+            __query["error_trace"] = error_trace
+        if filter_path is not None:
+            __query["filter_path"] = filter_path
+        if human is not None:
+            __query["human"] = human
+        if master_timeout is not None:
+            __query["master_timeout"] = master_timeout
+        if pretty is not None:
+            __query["pretty"] = pretty
+        __headers = {"accept": "application/json"}
+        return self.perform_request(  # type: ignore[return-value]
+            "GET",
+            __path,
+            params=__query,
+            headers=__headers,
+            endpoint_id="streams.status",
+            path_parts=__path_parts,
+        )
diff -pruN 9.1.1-2/elasticsearch/_sync/client/watcher.py 9.2.0-1/elasticsearch/_sync/client/watcher.py
--- 9.1.1-2/elasticsearch/_sync/client/watcher.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_sync/client/watcher.py	2025-10-28 16:50:53.000000000 +0000
@@ -552,11 +552,7 @@ class WatcherClient(NamespacedClient):
                 __body["transform"] = transform
             if trigger is not None:
                 __body["trigger"] = trigger
-        if not __body:
-            __body = None  # type: ignore[assignment]
-        __headers = {"accept": "application/json"}
-        if __body is not None:
-            __headers["content-type"] = "application/json"
+        __headers = {"accept": "application/json", "content-type": "application/json"}
         return self.perform_request(  # type: ignore[return-value]
             "PUT",
             __path,
diff -pruN 9.1.1-2/elasticsearch/_version.py 9.2.0-1/elasticsearch/_version.py
--- 9.1.1-2/elasticsearch/_version.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/_version.py	2025-10-28 16:50:53.000000000 +0000
@@ -15,4 +15,5 @@
 #  specific language governing permissions and limitations
 #  under the License.
 
-__versionstr__ = "9.1.1"
+__versionstr__ = "9.2.0"
+__es_specification_commit__ = "2f74c26e0a1d66c42232ce2830652c01e8717f00"
diff -pruN 9.1.1-2/elasticsearch/client.py 9.2.0-1/elasticsearch/client.py
--- 9.1.1-2/elasticsearch/client.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/client.py	2025-10-28 16:50:53.000000000 +0000
@@ -47,6 +47,7 @@ from ._sync.client.migration import Migr
 from ._sync.client.ml import MlClient as MlClient  # noqa: F401
 from ._sync.client.monitoring import MonitoringClient as MonitoringClient  # noqa: F401
 from ._sync.client.nodes import NodesClient as NodesClient  # noqa: F401
+from ._sync.client.project import ProjectClient as ProjectClient  # noqa: F401
 from ._sync.client.query_rules import QueryRulesClient as QueryRulesClient  # noqa: F401
 from ._sync.client.rollup import RollupClient as RollupClient  # noqa: F401
 from ._sync.client.search_application import (  # noqa: F401
@@ -62,6 +63,7 @@ from ._sync.client.slm import SlmClient
 from ._sync.client.snapshot import SnapshotClient as SnapshotClient  # noqa: F401
 from ._sync.client.sql import SqlClient as SqlClient  # noqa: F401
 from ._sync.client.ssl import SslClient as SslClient  # noqa: F401
+from ._sync.client.streams import StreamsClient as StreamsClient  # noqa: F401
 from ._sync.client.synonyms import SynonymsClient as SynonymsClient  # noqa: F401
 from ._sync.client.tasks import TasksClient as TasksClient  # noqa: F401
 from ._sync.client.text_structure import (  # noqa: F401
@@ -105,6 +107,7 @@ __all__ = [
     "MlClient",
     "MonitoringClient",
     "NodesClient",
+    "ProjectClient",
     "RollupClient",
     "SearchApplicationClient",
     "SearchableSnapshotsClient",
@@ -115,6 +118,7 @@ __all__ = [
     "SnapshotClient",
     "SqlClient",
     "SslClient",
+    "StreamsClient",
     "TasksClient",
     "TextStructureClient",
     "TransformClient",
diff -pruN 9.1.1-2/elasticsearch/compat.py 9.2.0-1/elasticsearch/compat.py
--- 9.1.1-2/elasticsearch/compat.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/compat.py	2025-10-28 16:50:53.000000000 +0000
@@ -18,8 +18,10 @@
 import inspect
 import os
 import sys
+from contextlib import contextmanager
 from pathlib import Path
-from typing import Tuple, Type, Union
+from threading import Thread
+from typing import Any, Callable, Iterator, Tuple, Type, Union
 
 string_types: Tuple[Type[str], Type[bytes]] = (str, bytes)
 
@@ -76,9 +78,36 @@ def warn_stacklevel() -> int:
     return 0
 
 
+@contextmanager
+def safe_thread(
+    target: Callable[..., Any], *args: Any, **kwargs: Any
+) -> Iterator[Thread]:
+    """Run a thread within a context manager block.
+
+    The thread is automatically joined when the block ends. If the thread raised
+    an exception, it is raised in the caller's context.
+    """
+    captured_exception = None
+
+    def run() -> None:
+        try:
+            target(*args, **kwargs)
+        except BaseException as exc:
+            nonlocal captured_exception
+            captured_exception = exc
+
+    thread = Thread(target=run)
+    thread.start()
+    yield thread
+    thread.join()
+    if captured_exception:
+        raise captured_exception
+
+
 __all__ = [
     "string_types",
     "to_str",
     "to_bytes",
     "warn_stacklevel",
+    "safe_thread",
 ]
diff -pruN 9.1.1-2/elasticsearch/dsl/__init__.py 9.2.0-1/elasticsearch/dsl/__init__.py
--- 9.1.1-2/elasticsearch/dsl/__init__.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/dsl/__init__.py	2025-10-28 16:50:53.000000000 +0000
@@ -38,23 +38,30 @@ from .faceted_search import (
     TermsFacet,
 )
 from .field import (
+    AggregateMetricDouble,
+    Alias,
     Binary,
     Boolean,
     Byte,
     Completion,
     ConstantKeyword,
+    CountedKeyword,
     CustomField,
     Date,
+    DateNanos,
     DateRange,
     DenseVector,
     Double,
     DoubleRange,
     Field,
+    Flattened,
     Float,
     FloatRange,
     GeoPoint,
     GeoShape,
     HalfFloat,
+    Histogram,
+    IcuCollationKeyword,
     Integer,
     IntegerRange,
     Ip,
@@ -63,21 +70,28 @@ from .field import (
     Keyword,
     Long,
     LongRange,
+    MatchOnlyText,
     Murmur3,
     Nested,
     Object,
+    Passthrough,
     Percolator,
     Point,
     RangeField,
     RankFeature,
     RankFeatures,
+    RankVectors,
     ScaledFloat,
     SearchAsYouType,
+    SemanticText,
     Shape,
     Short,
     SparseVector,
     Text,
     TokenCount,
+    UnsignedLong,
+    Version,
+    Wildcard,
     construct_field,
 )
 from .function import SF
@@ -108,6 +122,8 @@ __all__ = [
     "A",
     "Agg",
     "AggResponse",
+    "AggregateMetricDouble",
+    "Alias",
     "AsyncComposableIndexTemplate",
     "AsyncDocument",
     "AsyncEmptySearch",
@@ -126,9 +142,11 @@ __all__ = [
     "Completion",
     "ComposableIndexTemplate",
     "ConstantKeyword",
+    "CountedKeyword",
     "CustomField",
     "Date",
     "DateHistogramFacet",
+    "DateNanos",
     "DateRange",
     "DenseVector",
     "Document",
@@ -142,12 +160,15 @@ __all__ = [
     "FacetedResponse",
     "FacetedSearch",
     "Field",
+    "Flattened",
     "Float",
     "FloatRange",
     "GeoPoint",
     "GeoShape",
     "HalfFloat",
+    "Histogram",
     "HistogramFacet",
+    "IcuCollationKeyword",
     "IllegalOperation",
     "Index",
     "IndexTemplate",
@@ -162,12 +183,14 @@ __all__ = [
     "LongRange",
     "M",
     "Mapping",
+    "MatchOnlyText",
     "MetaField",
     "MultiSearch",
     "Murmur3",
     "Nested",
     "NestedFacet",
     "Object",
+    "Passthrough",
     "Percolator",
     "Point",
     "Q",
@@ -177,11 +200,13 @@ __all__ = [
     "RangeField",
     "RankFeature",
     "RankFeatures",
+    "RankVectors",
     "Response",
     "SF",
     "ScaledFloat",
     "Search",
     "SearchAsYouType",
+    "SemanticText",
     "Shape",
     "Short",
     "SparseVector",
@@ -189,9 +214,12 @@ __all__ = [
     "Text",
     "TokenCount",
     "UnknownDslObject",
+    "UnsignedLong",
     "UpdateByQuery",
     "UpdateByQueryResponse",
     "ValidationException",
+    "Version",
+    "Wildcard",
     "analyzer",
     "async_connections",
     "char_filter",
diff -pruN 9.1.1-2/elasticsearch/dsl/_async/document.py 9.2.0-1/elasticsearch/dsl/_async/document.py
--- 9.1.1-2/elasticsearch/dsl/_async/document.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/dsl/_async/document.py	2025-10-28 16:50:53.000000000 +0000
@@ -126,9 +126,10 @@ class AsyncDocument(DocumentBase, metacl
         Create an :class:`~elasticsearch.dsl.Search` instance that will search
         over this ``Document``.
         """
-        return AsyncSearch(
+        s = AsyncSearch[Self](
             using=cls._get_using(using), index=cls._default_index(index), doc_type=[cls]
         )
+        return s.source(exclude_vectors=False)
 
     @classmethod
     async def get(
diff -pruN 9.1.1-2/elasticsearch/dsl/_sync/document.py 9.2.0-1/elasticsearch/dsl/_sync/document.py
--- 9.1.1-2/elasticsearch/dsl/_sync/document.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/dsl/_sync/document.py	2025-10-28 16:50:53.000000000 +0000
@@ -120,9 +120,10 @@ class Document(DocumentBase, metaclass=I
         Create an :class:`~elasticsearch.dsl.Search` instance that will search
         over this ``Document``.
         """
-        return Search(
+        s = Search[Self](
             using=cls._get_using(using), index=cls._default_index(index), doc_type=[cls]
         )
+        return s.source(exclude_vectors=False)
 
     @classmethod
     def get(
diff -pruN 9.1.1-2/elasticsearch/dsl/aggs.py 9.2.0-1/elasticsearch/dsl/aggs.py
--- 9.1.1-2/elasticsearch/dsl/aggs.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/dsl/aggs.py	2025-10-28 16:50:53.000000000 +0000
@@ -653,6 +653,54 @@ class Cardinality(Agg[_R]):
         )
 
 
+class CartesianBounds(Agg[_R]):
+    """
+    A metric aggregation that computes the spatial bounding box containing
+    all values for a Point or Shape field.
+
+    :arg field: The field on which to run the aggregation.
+    :arg missing: The value to apply to documents that do not have a
+        value. By default, documents without a value are ignored.
+    :arg script:
+    """
+
+    name = "cartesian_bounds"
+
+    def __init__(
+        self,
+        *,
+        field: Union[str, "InstrumentedField", "DefaultType"] = DEFAULT,
+        missing: Union[str, int, float, bool, "DefaultType"] = DEFAULT,
+        script: Union["types.Script", Dict[str, Any], "DefaultType"] = DEFAULT,
+        **kwargs: Any,
+    ):
+        super().__init__(field=field, missing=missing, script=script, **kwargs)
+
+
+class CartesianCentroid(Agg[_R]):
+    """
+    A metric aggregation that computes the weighted centroid from all
+    coordinate values for point and shape fields.
+
+    :arg field: The field on which to run the aggregation.
+    :arg missing: The value to apply to documents that do not have a
+        value. By default, documents without a value are ignored.
+    :arg script:
+    """
+
+    name = "cartesian_centroid"
+
+    def __init__(
+        self,
+        *,
+        field: Union[str, "InstrumentedField", "DefaultType"] = DEFAULT,
+        missing: Union[str, int, float, bool, "DefaultType"] = DEFAULT,
+        script: Union["types.Script", Dict[str, Any], "DefaultType"] = DEFAULT,
+        **kwargs: Any,
+    ):
+        super().__init__(field=field, missing=missing, script=script, **kwargs)
+
+
 class CategorizeText(Bucket[_R]):
     """
     A multi-bucket aggregation that groups semi-structured text into
@@ -735,6 +783,43 @@ class CategorizeText(Bucket[_R]):
         )
 
 
+class ChangePoint(Pipeline[_R]):
+    """
+    A sibling pipeline that detects, spikes, dips, and change points in a
+    metric. Given a distribution of values provided by the sibling multi-
+    bucket aggregation, this aggregation indicates the bucket of any spike
+    or dip and/or the bucket at which the largest change in the
+    distribution of values, if they are statistically significant. There
+    must be at least 22 bucketed values. Fewer than 1,000 is preferred.
+
+    :arg format: `DecimalFormat` pattern for the output value. If
+        specified, the formatted value is returned in the aggregation’s
+        `value_as_string` property.
+    :arg gap_policy: Policy to apply when gaps are found in the data.
+        Defaults to `skip` if omitted.
+    :arg buckets_path: Path to the buckets that contain one set of values
+        to correlate.
+    """
+
+    name = "change_point"
+
+    def __init__(
+        self,
+        *,
+        format: Union[str, "DefaultType"] = DEFAULT,
+        gap_policy: Union[
+            Literal["skip", "insert_zeros", "keep_values"], "DefaultType"
+        ] = DEFAULT,
+        buckets_path: Union[
+            str, Sequence[str], Mapping[str, str], "DefaultType"
+        ] = DEFAULT,
+        **kwargs: Any,
+    ):
+        super().__init__(
+            format=format, gap_policy=gap_policy, buckets_path=buckets_path, **kwargs
+        )
+
+
 class Children(Bucket[_R]):
     """
     A single bucket aggregation that selects child documents that have the
@@ -2980,6 +3065,14 @@ class SignificantTerms(Bucket[_R]):
         the foreground sample with a term divided by the number of
         documents in the background with the term.
     :arg script_heuristic: Customized score, implemented via a script.
+    :arg p_value: Significant terms heuristic that calculates the p-value
+        between the term existing in foreground and background sets.  The
+        p-value is the probability of obtaining test results at least as
+        extreme as the results actually observed, under the assumption
+        that the null hypothesis is correct. The p-value is calculated
+        assuming that the foreground set and the background set are
+        independent https://en.wikipedia.org/wiki/Bernoulli_trial, with
+        the null hypothesis that the probabilities are the same.
     :arg shard_min_doc_count: Regulates the certainty a shard has if the
         term should actually be added to the candidate list or not with
         respect to the `min_doc_count`. Terms will only be considered if
@@ -3033,6 +3126,9 @@ class SignificantTerms(Bucket[_R]):
         script_heuristic: Union[
             "types.ScriptedHeuristic", Dict[str, Any], "DefaultType"
         ] = DEFAULT,
+        p_value: Union[
+            "types.PValueHeuristic", Dict[str, Any], "DefaultType"
+        ] = DEFAULT,
         shard_min_doc_count: Union[int, "DefaultType"] = DEFAULT,
         shard_size: Union[int, "DefaultType"] = DEFAULT,
         size: Union[int, "DefaultType"] = DEFAULT,
@@ -3051,6 +3147,7 @@ class SignificantTerms(Bucket[_R]):
             mutual_information=mutual_information,
             percentage=percentage,
             script_heuristic=script_heuristic,
+            p_value=p_value,
             shard_min_doc_count=shard_min_doc_count,
             shard_size=shard_size,
             size=size,
diff -pruN 9.1.1-2/elasticsearch/dsl/document_base.py 9.2.0-1/elasticsearch/dsl/document_base.py
--- 9.1.1-2/elasticsearch/dsl/document_base.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/dsl/document_base.py	2025-10-28 16:50:53.000000000 +0000
@@ -34,6 +34,13 @@ from typing import (
     overload,
 )
 
+from typing_extensions import _AnnotatedAlias
+
+try:
+    import annotationlib
+except ImportError:
+    annotationlib = None
+
 try:
     from types import UnionType
 except ImportError:
@@ -332,6 +339,16 @@ class DocumentOptions:
         #     # ignore attributes
         #     field10: ClassVar[string] = "a regular class variable"
         annotations = attrs.get("__annotations__", {})
+        if not annotations and annotationlib:
+            # Python 3.14+ uses annotationlib
+            annotate = annotationlib.get_annotate_from_class_namespace(attrs)
+            if annotate:
+                annotations = (
+                    annotationlib.call_annotate_function(
+                        annotate, format=annotationlib.Format.VALUE
+                    )
+                    or {}
+                )
         fields = {n for n in attrs if isinstance(attrs[n], Field)}
         fields.update(annotations.keys())
         field_defaults = {}
@@ -343,6 +360,10 @@ class DocumentOptions:
                 # the field has a type annotation, so next we try to figure out
                 # what field type we can use
                 type_ = annotations[name]
+                type_metadata = []
+                if isinstance(type_, _AnnotatedAlias):
+                    type_metadata = type_.__metadata__
+                    type_ = type_.__origin__
                 skip = False
                 required = True
                 multi = False
@@ -389,6 +410,12 @@ class DocumentOptions:
                     # use best field type for the type hint provided
                     field, field_kwargs = self.type_annotation_map[type_]  # type: ignore[assignment]
 
+                # if this field does not have a right-hand value, we look in the metadata
+                # of the annotation to see if we find it there
+                for md in type_metadata:
+                    if isinstance(md, (_FieldMetadataDict, Field)):
+                        attrs[name] = md
+
                 if field:
                     field_kwargs = {
                         "multi": multi,
@@ -401,17 +428,20 @@ class DocumentOptions:
                 # this field has a right-side value, which can be field
                 # instance on its own or wrapped with mapped_field()
                 attr_value = attrs[name]
-                if isinstance(attr_value, dict):
+                if isinstance(attr_value, _FieldMetadataDict):
                     # the mapped_field() wrapper function was used so we need
                     # to look for the field instance and also record any
                     # dataclass-style defaults
+                    if attr_value.get("exclude"):
+                        # skip this field
+                        continue
                     attr_value = attrs[name].get("_field")
                     default_value = attrs[name].get("default") or attrs[name].get(
                         "default_factory"
                     )
                     if default_value:
                         field_defaults[name] = default_value
-                if attr_value:
+                if isinstance(attr_value, Field):
                     value = attr_value
                     if required is not None:
                         value._required = required
@@ -490,12 +520,19 @@ class Mapped(Generic[_FieldType]):
 M = Mapped
 
 
+class _FieldMetadataDict(dict[str, Any]):
+    """This class is used to identify metadata returned by the `mapped_field()` function."""
+
+    pass
+
+
 def mapped_field(
     field: Optional[Field] = None,
     *,
     init: bool = True,
     default: Any = None,
     default_factory: Optional[Callable[[], Any]] = None,
+    exclude: bool = False,
     **kwargs: Any,
 ) -> Any:
     """Construct a field using dataclass behaviors
@@ -505,22 +542,25 @@ def mapped_field(
     options.
 
     :param field: The instance of ``Field`` to use for this field. If not provided,
-    an instance that is appropriate for the type given to the field is used.
+        an instance that is appropriate for the type given to the field is used.
     :param init: a value of ``True`` adds this field to the constructor, and a
-    value of ``False`` omits it from it. The default is ``True``.
+        value of ``False`` omits it from it. The default is ``True``.
     :param default: a default value to use for this field when one is not provided
-    explicitly.
+        explicitly.
     :param default_factory: a callable that returns a default value for the field,
-    when one isn't provided explicitly. Only one of ``factory`` and
-    ``default_factory`` can be used.
+        when one isn't provided explicitly. Only one of ``factory`` and
+        ``default_factory`` can be used.
+    :param exclude: Set to ``True`` to exclude this field from the Elasticsearch
+        index.
     """
-    return {
-        "_field": field,
-        "init": init,
-        "default": default,
-        "default_factory": default_factory,
+    return _FieldMetadataDict(
+        _field=field,
+        init=init,
+        default=default,
+        default_factory=default_factory,
+        exclude=exclude,
         **kwargs,
-    }
+    )
 
 
 @dataclass_transform(field_specifiers=(mapped_field,))
diff -pruN 9.1.1-2/elasticsearch/dsl/field.py 9.2.0-1/elasticsearch/dsl/field.py
--- 9.1.1-2/elasticsearch/dsl/field.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/dsl/field.py	2025-10-28 16:50:53.000000000 +0000
@@ -572,7 +572,11 @@ class Object(Field):
         if isinstance(data, collections.abc.Mapping):
             return data
 
-        return data.to_dict(skip_empty=skip_empty)
+        try:
+            return data.to_dict(skip_empty=skip_empty)
+        except TypeError:
+            # this would only happen if an AttrDict was given instead of an InnerDoc
+            return data.to_dict()
 
     def clean(self, data: Any) -> Any:
         data = super().clean(data)
@@ -3862,14 +3866,21 @@ class SemanticText(Field):
         by using the Update mapping API. Use the Create inference API to
         create the endpoint. If not specified, the inference endpoint
         defined by inference_id will be used at both index and query time.
+    :arg index_options: Settings for index_options that override any
+        defaults used by semantic_text, for example specific quantization
+        settings.
     :arg chunking_settings: Settings for chunking text into smaller
         passages. If specified, these will override the chunking settings
         sent in the inference endpoint associated with inference_id. If
         chunking settings are updated, they will not be applied to
         existing documents until they are reindexed.
+    :arg fields:
     """
 
     name = "semantic_text"
+    _param_defs = {
+        "fields": {"type": "field", "hash": True},
+    }
 
     def __init__(
         self,
@@ -3877,9 +3888,13 @@ class SemanticText(Field):
         meta: Union[Mapping[str, str], "DefaultType"] = DEFAULT,
         inference_id: Union[str, "DefaultType"] = DEFAULT,
         search_inference_id: Union[str, "DefaultType"] = DEFAULT,
+        index_options: Union[
+            "types.SemanticTextIndexOptions", Dict[str, Any], "DefaultType"
+        ] = DEFAULT,
         chunking_settings: Union[
-            "types.ChunkingSettings", Dict[str, Any], "DefaultType"
+            "types.ChunkingSettings", None, Dict[str, Any], "DefaultType"
         ] = DEFAULT,
+        fields: Union[Mapping[str, Field], "DefaultType"] = DEFAULT,
         **kwargs: Any,
     ):
         if meta is not DEFAULT:
@@ -3888,8 +3903,12 @@ class SemanticText(Field):
             kwargs["inference_id"] = inference_id
         if search_inference_id is not DEFAULT:
             kwargs["search_inference_id"] = search_inference_id
+        if index_options is not DEFAULT:
+            kwargs["index_options"] = index_options
         if chunking_settings is not DEFAULT:
             kwargs["chunking_settings"] = chunking_settings
+        if fields is not DEFAULT:
+            kwargs["fields"] = fields
         super().__init__(*args, **kwargs)
 
 
diff -pruN 9.1.1-2/elasticsearch/dsl/pydantic.py 9.2.0-1/elasticsearch/dsl/pydantic.py
--- 9.1.1-2/elasticsearch/dsl/pydantic.py	1970-01-01 00:00:00.000000000 +0000
+++ 9.2.0-1/elasticsearch/dsl/pydantic.py	2025-10-28 16:50:53.000000000 +0000
@@ -0,0 +1,152 @@
+#  Licensed to Elasticsearch B.V. under one or more contributor
+#  license agreements. See the NOTICE file distributed with
+#  this work for additional information regarding copyright
+#  ownership. Elasticsearch B.V. licenses this file to you under
+#  the Apache License, Version 2.0 (the "License"); you may
+#  not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+# 	http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing,
+#  software distributed under the License is distributed on an
+#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#  KIND, either express or implied.  See the License for the
+#  specific language governing permissions and limitations
+#  under the License.
+
+from typing import Any, ClassVar, Dict, List, Optional, Tuple, Type
+
+from pydantic import BaseModel, Field, PrivateAttr
+from typing_extensions import Annotated, Self, dataclass_transform
+
+from elasticsearch import dsl
+
+
+class ESMeta(BaseModel):
+    """Metadata items associated with Elasticsearch documents."""
+
+    id: str = ""
+    index: str = ""
+    primary_term: int = 0
+    seq_no: int = 0
+    version: int = 0
+    score: float = 0
+
+
+class _BaseModel(BaseModel):
+    meta: Annotated[ESMeta, dsl.mapped_field(exclude=True)] = Field(
+        default=ESMeta(),
+        init=False,
+    )
+
+
+class _BaseESModelMetaclass(type(BaseModel)):  # type: ignore[misc]
+    """Generic metaclass methods for BaseEsModel and AsyncBaseESModel."""
+
+    @staticmethod
+    def process_annotations(
+        metacls: Type["_BaseESModelMetaclass"], annotations: Dict[str, Any]
+    ) -> Dict[str, Any]:
+        """Process Pydantic typing annotations and adapt them so that they can
+        be used to create the Elasticsearch document.
+        """
+        updated_annotations = {}
+        for var, ann in annotations.items():
+            if isinstance(ann, type(BaseModel)):
+                # an inner Pydantic model is transformed into an Object field
+                updated_annotations[var] = metacls.make_dsl_class(
+                    metacls, dsl.InnerDoc, ann
+                )
+            elif (
+                hasattr(ann, "__origin__")
+                and ann.__origin__ in [list, List]
+                and isinstance(ann.__args__[0], type(BaseModel))
+            ):
+                # an inner list of Pydantic models is transformed into a Nested field
+                updated_annotations[var] = List[  # type: ignore[assignment,misc]
+                    metacls.make_dsl_class(metacls, dsl.InnerDoc, ann.__args__[0])
+                ]
+            else:
+                updated_annotations[var] = ann
+        return updated_annotations
+
+    @staticmethod
+    def make_dsl_class(
+        metacls: Type["_BaseESModelMetaclass"],
+        dsl_class: type,
+        pydantic_model: type,
+        pydantic_attrs: Optional[Dict[str, Any]] = None,
+    ) -> type:
+        """Create a DSL document class dynamically, using the structure of a
+        Pydantic model."""
+        dsl_attrs = {
+            attr: value
+            for attr, value in dsl_class.__dict__.items()
+            if not attr.startswith("__")
+        }
+        pydantic_attrs = {
+            **(pydantic_attrs or {}),
+            "__annotations__": metacls.process_annotations(
+                metacls, pydantic_model.__annotations__
+            ),
+        }
+        return type(dsl_class)(
+            f"_ES{pydantic_model.__name__}",
+            (dsl_class,),
+            {
+                **pydantic_attrs,
+                **dsl_attrs,
+                "__qualname__": f"_ES{pydantic_model.__name__}",
+            },
+        )
+
+
+class BaseESModelMetaclass(_BaseESModelMetaclass):
+    """Metaclass for the BaseESModel class."""
+
+    def __new__(cls, name: str, bases: Tuple[type, ...], attrs: Dict[str, Any]) -> Any:
+        model = super().__new__(cls, name, bases, attrs)
+        model._doc = cls.make_dsl_class(cls, dsl.Document, model, attrs)
+        return model
+
+
+class AsyncBaseESModelMetaclass(_BaseESModelMetaclass):
+    """Metaclass for the AsyncBaseESModel class."""
+
+    def __new__(cls, name: str, bases: Tuple[type, ...], attrs: Dict[str, Any]) -> Any:
+        model = super().__new__(cls, name, bases, attrs)
+        model._doc = cls.make_dsl_class(cls, dsl.AsyncDocument, model, attrs)
+        return model
+
+
+@dataclass_transform(kw_only_default=True, field_specifiers=(Field, PrivateAttr))
+class BaseESModel(_BaseModel, metaclass=BaseESModelMetaclass):
+    _doc: ClassVar[Type[dsl.Document]]
+
+    def to_doc(self) -> dsl.Document:
+        """Convert this model to an Elasticsearch document."""
+        data = self.model_dump()
+        meta = {f"_{k}": v for k, v in data.pop("meta", {}).items() if v}
+        return self._doc(**meta, **data)
+
+    @classmethod
+    def from_doc(cls, dsl_obj: dsl.Document) -> Self:
+        """Create a model from the given Elasticsearch document."""
+        return cls(meta=ESMeta(**dsl_obj.meta.to_dict()), **dsl_obj.to_dict())
+
+
+@dataclass_transform(kw_only_default=True, field_specifiers=(Field, PrivateAttr))
+class AsyncBaseESModel(_BaseModel, metaclass=AsyncBaseESModelMetaclass):
+    _doc: ClassVar[Type[dsl.AsyncDocument]]
+
+    def to_doc(self) -> dsl.AsyncDocument:
+        """Convert this model to an Elasticsearch document."""
+        data = self.model_dump()
+        meta = {f"_{k}": v for k, v in data.pop("meta", {}).items() if v}
+        return self._doc(**meta, **data)
+
+    @classmethod
+    def from_doc(cls, dsl_obj: dsl.AsyncDocument) -> Self:
+        """Create a model from the given Elasticsearch document."""
+        return cls(meta=ESMeta(**dsl_obj.meta.to_dict()), **dsl_obj.to_dict())
diff -pruN 9.1.1-2/elasticsearch/dsl/query.py 9.2.0-1/elasticsearch/dsl/query.py
--- 9.1.1-2/elasticsearch/dsl/query.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/dsl/query.py	2025-10-28 16:50:53.000000000 +0000
@@ -1079,6 +1079,8 @@ class Knn(Query):
         a query_vector_builder or query_vector, but not both.
     :arg num_candidates: The number of nearest neighbor candidates to
         consider per shard
+    :arg visit_percentage: The percentage of vectors to explore per shard
+        while doing knn search with bbq_disk
     :arg k: The final number of nearest neighbors to return as top hits
     :arg filter: Filters for the kNN search query
     :arg similarity: The minimum similarity for a vector to be considered
@@ -1107,6 +1109,7 @@ class Knn(Query):
             "types.QueryVectorBuilder", Dict[str, Any], "DefaultType"
         ] = DEFAULT,
         num_candidates: Union[int, "DefaultType"] = DEFAULT,
+        visit_percentage: Union[float, "DefaultType"] = DEFAULT,
         k: Union[int, "DefaultType"] = DEFAULT,
         filter: Union[Query, Sequence[Query], "DefaultType"] = DEFAULT,
         similarity: Union[float, "DefaultType"] = DEFAULT,
@@ -1122,6 +1125,7 @@ class Knn(Query):
             query_vector=query_vector,
             query_vector_builder=query_vector_builder,
             num_candidates=num_candidates,
+            visit_percentage=visit_percentage,
             k=k,
             filter=filter,
             similarity=similarity,
@@ -1433,7 +1437,7 @@ class MoreLikeThis(Query):
         ] = DEFAULT,
         version: Union[int, "DefaultType"] = DEFAULT,
         version_type: Union[
-            Literal["internal", "external", "external_gte", "force"], "DefaultType"
+            Literal["internal", "external", "external_gte"], "DefaultType"
         ] = DEFAULT,
         boost: Union[float, "DefaultType"] = DEFAULT,
         _name: Union[str, "DefaultType"] = DEFAULT,
diff -pruN 9.1.1-2/elasticsearch/dsl/response/__init__.py 9.2.0-1/elasticsearch/dsl/response/__init__.py
--- 9.1.1-2/elasticsearch/dsl/response/__init__.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/dsl/response/__init__.py	2025-10-28 16:50:53.000000000 +0000
@@ -233,10 +233,13 @@ AggregateResponseType = Union[
     "types.SimpleValueAggregate",
     "types.DerivativeAggregate",
     "types.BucketMetricValueAggregate",
+    "types.ChangePointAggregate",
     "types.StatsAggregate",
     "types.StatsBucketAggregate",
     "types.ExtendedStatsAggregate",
     "types.ExtendedStatsBucketAggregate",
+    "types.CartesianBoundsAggregate",
+    "types.CartesianCentroidAggregate",
     "types.GeoBoundsAggregate",
     "types.GeoCentroidAggregate",
     "types.HistogramAggregate",
diff -pruN 9.1.1-2/elasticsearch/dsl/search_base.py 9.2.0-1/elasticsearch/dsl/search_base.py
--- 9.1.1-2/elasticsearch/dsl/search_base.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/dsl/search_base.py	2025-10-28 16:50:53.000000000 +0000
@@ -721,14 +721,18 @@ class SearchBase(Request[_R]):
 
         def ensure_strings(
             fields: Union[
+                bool,
                 str,
                 "InstrumentedField",
                 List[Union[str, "InstrumentedField"]],
                 Dict[str, List[Union[str, "InstrumentedField"]]],
             ],
-        ) -> Union[str, List[str], Dict[str, List[str]]]:
+        ) -> Union[bool, str, List[str], Dict[str, List[str]]]:
             if isinstance(fields, dict):
                 return {k: ensure_strings(v) for k, v in fields.items()}
+            elif isinstance(fields, bool):
+                # boolean settings should stay the way they are
+                return fields
             elif not isinstance(fields, (str, InstrumentedField)):
                 # we assume that if `fields` is not a any of [dict, str,
                 # InstrumentedField] then it is an iterable of strings or
diff -pruN 9.1.1-2/elasticsearch/dsl/types.py 9.2.0-1/elasticsearch/dsl/types.py
--- 9.1.1-2/elasticsearch/dsl/types.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/dsl/types.py	2025-10-28 16:50:53.000000000 +0000
@@ -151,9 +151,10 @@ class ChunkingSettings(AttrDict[Any]):
         strategies in the linked documentation. Defaults to `sentence` if
         omitted.
     :arg max_chunk_size: (required) The maximum size of a chunk in words.
-        This value cannot be higher than `300` or lower than `20` (for
-        `sentence` strategy) or `10` (for `word` strategy). Defaults to
-        `250` if omitted.
+        This value cannot be lower than `20` (for `sentence` strategy) or
+        `10` (for `word` strategy). This value should not exceed the
+        window size for the associated model. Defaults to `250` if
+        omitted.
     :arg separator_group: Only applicable to the `recursive` strategy and
         required when using it.  Sets a predefined list of separators in
         the saved chunking settings based on the selected text type.
@@ -397,14 +398,17 @@ class DenseVectorIndexOptions(AttrDict[A
         HNSW graph.  Only applicable to `hnsw`, `int8_hnsw`, `bbq_hnsw`,
         and `int4_hnsw` index types. Defaults to `16` if omitted.
     :arg rescore_vector: The rescore vector options. This is only
-        applicable to `bbq_hnsw`, `int4_hnsw`, `int8_hnsw`, `bbq_flat`,
-        `int4_flat`, and `int8_flat` index types.
+        applicable to `bbq_disk`, `bbq_hnsw`, `int4_hnsw`, `int8_hnsw`,
+        `bbq_flat`, `int4_flat`, and `int8_flat` index types.
+    :arg on_disk_rescore: `true` if vector rescoring should be done on-
+        disk  Only applicable to `bbq_hnsw`
     """
 
     type: Union[
         Literal[
             "bbq_flat",
             "bbq_hnsw",
+            "bbq_disk",
             "flat",
             "hnsw",
             "int4_flat",
@@ -420,6 +424,7 @@ class DenseVectorIndexOptions(AttrDict[A
     rescore_vector: Union[
         "DenseVectorIndexOptionsRescoreVector", Dict[str, Any], DefaultType
     ]
+    on_disk_rescore: Union[bool, DefaultType]
 
     def __init__(
         self,
@@ -428,6 +433,7 @@ class DenseVectorIndexOptions(AttrDict[A
             Literal[
                 "bbq_flat",
                 "bbq_hnsw",
+                "bbq_disk",
                 "flat",
                 "hnsw",
                 "int4_flat",
@@ -443,6 +449,7 @@ class DenseVectorIndexOptions(AttrDict[A
         rescore_vector: Union[
             "DenseVectorIndexOptionsRescoreVector", Dict[str, Any], DefaultType
         ] = DEFAULT,
+        on_disk_rescore: Union[bool, DefaultType] = DEFAULT,
         **kwargs: Any,
     ):
         if type is not DEFAULT:
@@ -455,6 +462,8 @@ class DenseVectorIndexOptions(AttrDict[A
             kwargs["m"] = m
         if rescore_vector is not DEFAULT:
             kwargs["rescore_vector"] = rescore_vector
+        if on_disk_rescore is not DEFAULT:
+            kwargs["on_disk_rescore"] = on_disk_rescore
         super().__init__(kwargs)
 
 
@@ -2326,9 +2335,7 @@ class LikeDocument(AttrDict[Any]):
     per_field_analyzer: Union[Mapping[Union[str, InstrumentedField], str], DefaultType]
     routing: Union[str, DefaultType]
     version: Union[int, DefaultType]
-    version_type: Union[
-        Literal["internal", "external", "external_gte", "force"], DefaultType
-    ]
+    version_type: Union[Literal["internal", "external", "external_gte"], DefaultType]
 
     def __init__(
         self,
@@ -2343,7 +2350,7 @@ class LikeDocument(AttrDict[Any]):
         routing: Union[str, DefaultType] = DEFAULT,
         version: Union[int, DefaultType] = DEFAULT,
         version_type: Union[
-            Literal["internal", "external", "external_gte", "force"], DefaultType
+            Literal["internal", "external", "external_gte"], DefaultType
         ] = DEFAULT,
         **kwargs: Any,
     ):
@@ -2774,6 +2781,31 @@ class NumericFielddata(AttrDict[Any]):
         super().__init__(kwargs)
 
 
+class PValueHeuristic(AttrDict[Any]):
+    """
+    :arg background_is_superset:
+    :arg normalize_above: Should the results be normalized when above the
+        given value. Allows for consistent significance results at various
+        scales. Note: `0` is a special value which means no normalization
+    """
+
+    background_is_superset: Union[bool, DefaultType]
+    normalize_above: Union[int, DefaultType]
+
+    def __init__(
+        self,
+        *,
+        background_is_superset: Union[bool, DefaultType] = DEFAULT,
+        normalize_above: Union[int, DefaultType] = DEFAULT,
+        **kwargs: Any,
+    ):
+        if background_is_superset is not DEFAULT:
+            kwargs["background_is_superset"] = background_is_superset
+        if normalize_above is not DEFAULT:
+            kwargs["normalize_above"] = normalize_above
+        super().__init__(kwargs)
+
+
 class PercentageScoreHeuristic(AttrDict[Any]):
     pass
 
@@ -3164,6 +3196,33 @@ class ScriptedHeuristic(AttrDict[Any]):
         super().__init__(kwargs)
 
 
+class SemanticTextIndexOptions(AttrDict[Any]):
+    """
+    :arg dense_vector:
+    :arg sparse_vector:
+    """
+
+    dense_vector: Union["DenseVectorIndexOptions", Dict[str, Any], DefaultType]
+    sparse_vector: Union["SparseVectorIndexOptions", Dict[str, Any], DefaultType]
+
+    def __init__(
+        self,
+        *,
+        dense_vector: Union[
+            "DenseVectorIndexOptions", Dict[str, Any], DefaultType
+        ] = DEFAULT,
+        sparse_vector: Union[
+            "SparseVectorIndexOptions", Dict[str, Any], DefaultType
+        ] = DEFAULT,
+        **kwargs: Any,
+    ):
+        if dense_vector is not DEFAULT:
+            kwargs["dense_vector"] = dense_vector
+        if sparse_vector is not DEFAULT:
+            kwargs["sparse_vector"] = sparse_vector
+        super().__init__(kwargs)
+
+
 class ShapeFieldQuery(AttrDict[Any]):
     """
     :arg indexed_shape: Queries using a pre-indexed shape.
@@ -4009,24 +4068,25 @@ class TestPopulation(AttrDict[Any]):
 
 class TextEmbedding(AttrDict[Any]):
     """
-    :arg model_id: (required)
     :arg model_text: (required)
+    :arg model_id: Model ID is required for all dense_vector fields but
+        may be inferred for semantic_text fields
     """
 
-    model_id: Union[str, DefaultType]
     model_text: Union[str, DefaultType]
+    model_id: Union[str, DefaultType]
 
     def __init__(
         self,
         *,
-        model_id: Union[str, DefaultType] = DEFAULT,
         model_text: Union[str, DefaultType] = DEFAULT,
+        model_id: Union[str, DefaultType] = DEFAULT,
         **kwargs: Any,
     ):
-        if model_id is not DEFAULT:
-            kwargs["model_id"] = model_id
         if model_text is not DEFAULT:
             kwargs["model_text"] = model_text
+        if model_id is not DEFAULT:
+            kwargs["model_id"] = model_id
         super().__init__(kwargs)
 
 
@@ -4659,6 +4719,82 @@ class CardinalityAggregate(AttrDict[Any]
     meta: Mapping[str, Any]
 
 
+class CartesianBoundsAggregate(AttrDict[Any]):
+    """
+    :arg bounds:
+    :arg meta:
+    """
+
+    bounds: "TopLeftBottomRightGeoBounds"
+    meta: Mapping[str, Any]
+
+
+class CartesianCentroidAggregate(AttrDict[Any]):
+    """
+    :arg count: (required)
+    :arg location:
+    :arg meta:
+    """
+
+    count: int
+    location: "CartesianPoint"
+    meta: Mapping[str, Any]
+
+
+class CartesianPoint(AttrDict[Any]):
+    """
+    :arg x: (required)
+    :arg y: (required)
+    """
+
+    x: float
+    y: float
+
+
+class ChangePointAggregate(AttrDict[Any]):
+    """
+    :arg type: (required)
+    :arg bucket:
+    :arg meta:
+    """
+
+    type: "ChangeType"
+    bucket: "ChangePointBucket"
+    meta: Mapping[str, Any]
+
+
+class ChangePointBucket(AttrDict[Any]):
+    """
+    :arg key: (required)
+    :arg doc_count: (required)
+    """
+
+    key: Union[int, float, str, bool, None]
+    doc_count: int
+
+
+class ChangeType(AttrDict[Any]):
+    """
+    :arg dip:
+    :arg distribution_change:
+    :arg indeterminable:
+    :arg non_stationary:
+    :arg spike:
+    :arg stationary:
+    :arg step_change:
+    :arg trend_change:
+    """
+
+    dip: "Dip"
+    distribution_change: "DistributionChange"
+    indeterminable: "Indeterminable"
+    non_stationary: "NonStationary"
+    spike: "Spike"
+    stationary: "Stationary"
+    step_change: "StepChange"
+    trend_change: "TrendChange"
+
+
 class ChildrenAggregate(AttrDict[Any]):
     """
     :arg doc_count: (required)
@@ -4936,6 +5072,26 @@ class DfsStatisticsProfile(AttrDict[Any]
     children: Sequence["DfsStatisticsProfile"]
 
 
+class Dip(AttrDict[Any]):
+    """
+    :arg p_value: (required)
+    :arg change_point: (required)
+    """
+
+    p_value: float
+    change_point: int
+
+
+class DistributionChange(AttrDict[Any]):
+    """
+    :arg p_value: (required)
+    :arg change_point: (required)
+    """
+
+    p_value: float
+    change_point: int
+
+
 class DoubleTermsAggregate(AttrDict[Any]):
     """
     Result of a `terms` aggregation when the field is some kind of decimal
@@ -5497,6 +5653,14 @@ class HitsMetadata(AttrDict[Any]):
     max_score: Union[float, None]
 
 
+class Indeterminable(AttrDict[Any]):
+    """
+    :arg reason: (required)
+    """
+
+    reason: str
+
+
 class InferenceAggregate(AttrDict[Any]):
     """
     :arg value:
@@ -5899,6 +6063,18 @@ class NestedIdentity(AttrDict[Any]):
     _nested: "NestedIdentity"
 
 
+class NonStationary(AttrDict[Any]):
+    """
+    :arg p_value: (required)
+    :arg r_value: (required)
+    :arg trend: (required)
+    """
+
+    p_value: float
+    r_value: float
+    trend: str
+
+
 class ParentAggregate(AttrDict[Any]):
     """
     :arg doc_count: (required)
@@ -6256,6 +6432,16 @@ class SimpleValueAggregate(AttrDict[Any]
     meta: Mapping[str, Any]
 
 
+class Spike(AttrDict[Any]):
+    """
+    :arg p_value: (required)
+    :arg change_point: (required)
+    """
+
+    p_value: float
+    change_point: int
+
+
 class StandardDeviationBounds(AttrDict[Any]):
     """
     :arg upper: (required)
@@ -6292,6 +6478,10 @@ class StandardDeviationBoundsAsString(At
     lower_sampling: str
 
 
+class Stationary(AttrDict[Any]):
+    pass
+
+
 class StatsAggregate(AttrDict[Any]):
     """
     Statistics aggregation result. `min`, `max` and `avg` are missing if
@@ -6347,6 +6537,16 @@ class StatsBucketAggregate(AttrDict[Any]
     meta: Mapping[str, Any]
 
 
+class StepChange(AttrDict[Any]):
+    """
+    :arg p_value: (required)
+    :arg change_point: (required)
+    """
+
+    p_value: float
+    change_point: int
+
+
 class StringRareTermsAggregate(AttrDict[Any]):
     """
     Result of the `rare_terms` aggregation when the field is a string.
@@ -6578,6 +6778,18 @@ class TotalHits(AttrDict[Any]):
     value: int
 
 
+class TrendChange(AttrDict[Any]):
+    """
+    :arg p_value: (required)
+    :arg r_value: (required)
+    :arg change_point: (required)
+    """
+
+    p_value: float
+    r_value: float
+    change_point: int
+
+
 class UnmappedRareTermsAggregate(AttrDict[Any]):
     """
     Result of a `rare_terms` aggregation when the field is unmapped.
diff -pruN 9.1.1-2/elasticsearch/esql/esql.py 9.2.0-1/elasticsearch/esql/esql.py
--- 9.1.1-2/elasticsearch/esql/esql.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/esql/esql.py	2025-10-28 16:50:53.000000000 +0000
@@ -18,7 +18,7 @@
 import json
 import re
 from abc import ABC, abstractmethod
-from typing import Any, Dict, Optional, Tuple, Type, Union
+from typing import Any, Dict, List, Optional, Tuple, Type, Union
 
 from ..dsl.document_base import DocumentBase, InstrumentedExpression, InstrumentedField
 
@@ -79,6 +79,22 @@ class ESQL(ABC):
         return Show(item)
 
     @staticmethod
+    def ts(*indices: IndexType) -> "TS":
+        """The ``TS`` source command is similar to ``FROM``, but for time series indices.
+
+        :param indices: A list of indices, data streams or aliases. Supports wildcards and date math.
+
+        Examples::
+
+            query = (
+                ESQL.ts("metrics")
+                .where("@timestamp >= now() - 1 day")
+                .stats("SUM(AVG_OVER_TIME(memory_usage)").by("host", "TBUCKET(1 hour)")
+            )
+        """
+        return TS(*indices)
+
+    @staticmethod
     def branch() -> "Branch":
         """This method can only be used inside a ``FORK`` command to create each branch.
 
@@ -143,7 +159,7 @@ class ESQLBase(ABC):
         return False
 
     def change_point(self, value: FieldType) -> "ChangePoint":
-        """`CHANGE_POINT` detects spikes, dips, and change points in a metric.
+        """``CHANGE_POINT`` detects spikes, dips, and change points in a metric.
 
         :param value: The column with the metric in which you want to detect a change point.
 
@@ -163,17 +179,18 @@ class ESQLBase(ABC):
     def completion(
         self, *prompt: ExpressionType, **named_prompt: ExpressionType
     ) -> "Completion":
-        """The `COMPLETION` command allows you to send prompts and context to a Large
+        """The ``COMPLETION`` command allows you to send prompts and context to a Large
         Language Model (LLM) directly within your ES|QL queries, to perform text
         generation tasks.
 
         :param prompt: The input text or expression used to prompt the LLM. This can
                        be a string literal or a reference to a column containing text.
         :param named_prompt: The input text or expresion, given as a keyword argument.
-                             The argument name is used for the column name. If not
-                             specified, the results will be stored in a column named
-                             `completion`. If the specified column already exists, it
-                             will be overwritten with the new results.
+                             The argument name is used for the column name. If the
+                             prompt is given as a positional argument, the results will
+                             be stored in a column named ``completion``. If the
+                             specified column already exists, it will be overwritten
+                             with the new results.
 
         Examples::
 
@@ -283,14 +300,14 @@ class ESQLBase(ABC):
 
     def fork(
         self,
-        fork1: "ESQLBase",
-        fork2: Optional["ESQLBase"] = None,
-        fork3: Optional["ESQLBase"] = None,
-        fork4: Optional["ESQLBase"] = None,
-        fork5: Optional["ESQLBase"] = None,
-        fork6: Optional["ESQLBase"] = None,
-        fork7: Optional["ESQLBase"] = None,
-        fork8: Optional["ESQLBase"] = None,
+        fork1: "Branch",
+        fork2: Optional["Branch"] = None,
+        fork3: Optional["Branch"] = None,
+        fork4: Optional["Branch"] = None,
+        fork5: Optional["Branch"] = None,
+        fork6: Optional["Branch"] = None,
+        fork7: Optional["Branch"] = None,
+        fork8: Optional["Branch"] = None,
     ) -> "Fork":
         """The ``FORK`` processing command creates multiple execution branches to operate on the
         same input data and combines the results in a single output table.
@@ -313,6 +330,51 @@ class ESQLBase(ABC):
             raise ValueError("a query can only have one fork")
         return Fork(self, fork1, fork2, fork3, fork4, fork5, fork6, fork7, fork8)
 
+    def fuse(self, method: Optional[str] = None) -> "Fuse":
+        """The ``FUSE`` processing command merges rows from multiple result sets and assigns
+        new relevance scores.
+
+        :param method: Defaults to ``RRF``. Can be one of ``RRF`` (for Reciprocal Rank Fusion)
+                       or ``LINEAR`` (for linear combination of scores). Designates which
+                       method to use to assign new relevance scores.
+
+        Examples::
+
+            query1 = (
+                ESQL.from_("books").metadata("_id", "_index", "_score")
+                .fork(
+                    ESQL.branch().where('title:"Shakespeare"').sort("_score DESC"),
+                    ESQL.branch().where('semantic_title:"Shakespeare"').sort("_score DESC"),
+                )
+                .fuse()
+            )
+            query2 = (
+                ESQL.from_("books").metadata("_id", "_index", "_score")
+                .fork(
+                    ESQL.branch().where('title:"Shakespeare"').sort("_score DESC"),
+                    ESQL.branch().where('semantic_title:"Shakespeare"').sort("_score DESC"),
+                )
+                .fuse("linear")
+            )
+            query3 = (
+                ESQL.from_("books").metadata("_id", "_index", "_score")
+                .fork(
+                    ESQL.branch().where('title:"Shakespeare"').sort("_score DESC"),
+                    ESQL.branch().where('semantic_title:"Shakespeare"').sort("_score DESC"),
+                )
+                .fuse("linear").by("title", "description")
+            )
+            query4 = (
+                ESQL.from_("books").metadata("_id", "_index", "_score")
+                .fork(
+                    ESQL.branch().where('title:"Shakespeare"').sort("_score DESC"),
+                    ESQL.branch().where('semantic_title:"Shakespeare"').sort("_score DESC"),
+                )
+                .fuse("linear").with_(normalizer="minmax")
+            )
+        """
+        return Fuse(self, method)
+
     def grok(self, input: FieldType, pattern: str) -> "Grok":
         """``GROK`` enables you to extract structured data out of a string.
 
@@ -347,6 +409,58 @@ class ESQLBase(ABC):
         """
         return Grok(self, input, pattern)
 
+    def inline_stats(
+        self, *expressions: ExpressionType, **named_expressions: ExpressionType
+    ) -> "Stats":
+        """The ``INLINE STATS`` processing command groups rows according to a common value
+        and calculates one or more aggregated values over the grouped rows.
+
+        The command is identical to ``STATS`` except that it preserves all the columns from
+        the input table.
+
+        :param expressions: A list of expressions, given as positional arguments.
+        :param named_expressions: A list of expressions, given as keyword arguments. The
+                                  argument names are used for the returned aggregated values.
+
+        Note that only one of ``expressions`` and ``named_expressions`` must be provided.
+
+        Examples::
+
+            query1 = (
+                ESQL.from_("employees")
+                .keep("emp_no", "languages", "salary")
+                .inline_stats(max_salary=functions.max(E("salary"))).by("languages")
+            )
+            query2 = (
+                ESQL.from_("employees")
+                .keep("emp_no", "languages", "salary")
+                .inline_stats(max_salary=functions.max(E("salary")))
+            )
+            query3 = (
+                ESQL.from_("employees")
+                .where("still_hired")
+                .keep("emp_no", "languages", "salary", "hire_date")
+                .eval(tenure=functions.date_diff("year", E("hire_date"), "2025-09-18T00:00:00"))
+                .drop("hire_date")
+                .inline_stats(
+                    avg_salary=functions.avg(E("salary")),
+                    count=functions.count(E("*")),
+                )
+                .by("languages", "tenure")
+            )
+            query4 = (
+                ESQL.from_("employees")
+                .keep("emp_no", "salary")
+                .inline_stats(
+                    avg_lt_50=functions.round(functions.avg(E("salary"))).where(E("salary") < 50000),
+                    avg_lt_60=functions.round(functions.avg(E("salary"))).where(E("salary") >= 50000, E("salary") < 60000),
+                    avg_gt_60=functions.round(functions.avg(E("salary"))).where(E("salary") >= 60000),
+                )
+            )
+
+        """
+        return InlineStats(self, *expressions, **named_expressions)
+
     def keep(self, *columns: FieldType) -> "Keep":
         """The ``KEEP`` processing command enables you to specify what columns are returned
         and the order in which they are returned.
@@ -376,7 +490,7 @@ class ESQLBase(ABC):
         return Limit(self, max_number_of_rows)
 
     def lookup_join(self, lookup_index: IndexType) -> "LookupJoin":
-        """`LOOKUP JOIN` enables you to add data from another index, AKA a 'lookup' index,
+        """``LOOKUP JOIN`` enables you to add data from another index, AKA a 'lookup' index,
         to your ES|QL query results, simplifying data enrichment and analysis workflows.
 
         :param lookup_index: The name of the lookup index. This must be a specific index
@@ -410,7 +524,7 @@ class ESQLBase(ABC):
         return LookupJoin(self, lookup_index)
 
     def mv_expand(self, column: FieldType) -> "MvExpand":
-        """The `MV_EXPAND` processing command expands multivalued columns into one row per
+        """The ``MV_EXPAND`` processing command expands multivalued columns into one row per
         value, duplicating other columns.
 
         :param column: The multivalued column to expand.
@@ -439,6 +553,54 @@ class ESQLBase(ABC):
         """
         return Rename(self, **columns)
 
+    def rerank(self, *query: ExpressionType, **named_query: ExpressionType) -> "Rerank":
+        """The ``RERANK`` command uses an inference model to compute a new relevance score
+        for an initial set of documents, directly within your ES|QL queries.
+
+        :param query: The query text used to rerank the documents. This is typically the
+                      same query used in the initial search.
+        :param named_query: The query text used to rerank the documents, given as a
+                            keyword argument. The argument name is used for the column
+                            name. If the query is given as a positional argument, the
+                            results will be stored in a column named ``_score``. If the
+                            specified column already exists, it will be overwritten with
+                            the new results.
+
+        Examples::
+
+            query1 = (
+                ESQL.from_("books").metadata("_score")
+                .where('MATCH(description, "hobbit")')
+                .sort("_score DESC")
+                .limit(100)
+                .rerank("hobbit").on("description").with_(inference_id="test_reranker")
+                .limit(3)
+                .keep("title", "_score")
+            )
+            query2 = (
+                ESQL.from_("books").metadata("_score")
+                .where('MATCH(description, "hobbit") OR MATCH(author, "Tolkien")')
+                .sort("_score DESC")
+                .limit(100)
+                .rerank(rerank_score="hobbit").on("description", "author").with_(inference_id="test_reranker")
+                .sort("rerank_score")
+                .limit(3)
+                .keep("title", "_score", "rerank_score")
+            )
+            query3 = (
+                ESQL.from_("books").metadata("_score")
+                .where('MATCH(description, "hobbit") OR MATCH(author, "Tolkien")')
+                .sort("_score DESC")
+                .limit(100)
+                .rerank(rerank_score="hobbit").on("description", "author").with_(inference_id="test_reranker")
+                .eval(original_score="_score", _score="rerank_score + original_score")
+                .sort("_score")
+                .limit(3)
+                .keep("title", "original_score", "rerank_score", "_score")
+            )
+        """
+        return Rerank(self, *query, **named_query)
+
     def sample(self, probability: float) -> "Sample":
         """The ``SAMPLE`` command samples a fraction of the table rows.
 
@@ -491,7 +653,7 @@ class ESQLBase(ABC):
         :param named_expressions: A list of expressions, given as keyword arguments. The
                                   argument names are used for the returned aggregated values.
 
-        Note that only one of `expressions` and `named_expressions` must be provided.
+        Note that only one of ``expressions`` and ``named_expressions`` must be provided.
 
         Examples::
 
@@ -547,7 +709,7 @@ class ESQLBase(ABC):
 
     def where(self, *expressions: ExpressionType) -> "Where":
         """The ``WHERE`` processing command produces a table that contains all the rows
-        from the input table for which the provided condition evaluates to `true`.
+        from the input table for which the provided condition evaluates to ``true``.
 
         :param expressions: A list of boolean expressions, given as positional arguments.
                             These expressions are combined with an ``AND`` logical operator.
@@ -580,13 +742,15 @@ class From(ESQLBase):
     in a single expression.
     """
 
+    command_name = "FROM"
+
     def __init__(self, *indices: IndexType):
         super().__init__()
         self._indices = indices
         self._metadata_fields: Tuple[FieldType, ...] = tuple()
 
     def metadata(self, *fields: FieldType) -> "From":
-        """Continuation of the ``FROM`` source command.
+        """Continuation of the ``FROM`` and ``TS`` source commands.
 
         :param fields: metadata fields to retrieve, given as positional arguments.
         """
@@ -595,7 +759,7 @@ class From(ESQLBase):
 
     def _render_internal(self) -> str:
         indices = [self._format_index(index) for index in self._indices]
-        s = f'{self.__class__.__name__.upper()} {", ".join(indices)}'
+        s = f'{self.command_name} {", ".join(indices)}'
         if self._metadata_fields:
             s = (
                 s
@@ -643,6 +807,17 @@ class Show(ESQLBase):
         return f"SHOW {self._format_id(self._item)}"
 
 
+class TS(From):
+    """Implementation of the ``TS`` source command.
+
+    This class inherits from :class:`ESQLBase <elasticsearch.esql.esql.ESQLBase>`,
+    to make it possible to chain all the commands that belong to an ES|QL query
+    in a single expression.
+    """
+
+    command_name = "TS"
+
+
 class Branch(ESQLBase):
     """Implementation of a branch inside a ``FORK`` processing command.
 
@@ -671,21 +846,22 @@ class ChangePoint(ESQLBase):
         self._pvalue_name: Optional[str] = None
 
     def on(self, key: FieldType) -> "ChangePoint":
-        """Continuation of the `CHANGE_POINT` command.
+        """Continuation of the ``CHANGE_POINT`` command.
 
         :param key: The column with the key to order the values by. If not specified,
-                    `@timestamp` is used.
+                    ``@timestamp`` is used.
         """
         self._key = key
         return self
 
     def as_(self, type_name: str, pvalue_name: str) -> "ChangePoint":
-        """Continuation of the `CHANGE_POINT` command.
+        """Continuation of the ``CHANGE_POINT`` command.
 
         :param type_name: The name of the output column with the change point type.
-                          If not specified, `type` is used.
+                          If not specified, ``type`` is used.
         :param pvalue_name: The name of the output column with the p-value that indicates
-                            how extreme the change point is. If not specified, `pvalue` is used.
+                            how extreme the change point is. If not specified, ``pvalue``
+                            is used.
         """
         self._type_name = type_name
         self._pvalue_name = pvalue_name
@@ -722,10 +898,10 @@ class Completion(ESQLBase):
         self._inference_id: Optional[str] = None
 
     def with_(self, inference_id: str) -> "Completion":
-        """Continuation of the `COMPLETION` command.
+        """Continuation of the ``COMPLETION`` command.
 
         :param inference_id: The ID of the inference endpoint to use for the task. The
-                             inference endpoint must be configured with the completion
+                             inference endpoint must be configured with the ``completion``
                              task type.
         """
         self._inference_id = inference_id
@@ -814,7 +990,7 @@ class Enrich(ESQLBase):
         :param match_field: The match field. ``ENRICH`` uses its value to look for records
                             in the enrich index. If not specified, the match will be
                             performed on the column with the same name as the
-                            `match_field` defined in the enrich policy.
+                            ``match_field`` defined in the enrich policy.
         """
         self._match_field = match_field
         return self
@@ -904,14 +1080,14 @@ class Fork(ESQLBase):
     def __init__(
         self,
         parent: ESQLBase,
-        fork1: ESQLBase,
-        fork2: Optional[ESQLBase] = None,
-        fork3: Optional[ESQLBase] = None,
-        fork4: Optional[ESQLBase] = None,
-        fork5: Optional[ESQLBase] = None,
-        fork6: Optional[ESQLBase] = None,
-        fork7: Optional[ESQLBase] = None,
-        fork8: Optional[ESQLBase] = None,
+        fork1: "Branch",
+        fork2: Optional["Branch"] = None,
+        fork3: Optional["Branch"] = None,
+        fork4: Optional["Branch"] = None,
+        fork5: Optional["Branch"] = None,
+        fork6: Optional["Branch"] = None,
+        fork7: Optional["Branch"] = None,
+        fork8: Optional["Branch"] = None,
     ):
         super().__init__(parent)
         self._branches = [fork1, fork2, fork3, fork4, fork5, fork6, fork7, fork8]
@@ -928,6 +1104,39 @@ class Fork(ESQLBase):
         return f"FORK {cmds}"
 
 
+class Fuse(ESQLBase):
+    """Implementation of the ``FUSE`` processing command.
+
+    This class inherits from :class:`ESQLBase <elasticsearch.esql.esql.ESQLBase>`,
+    to make it possible to chain all the commands that belong to an ES|QL query
+    in a single expression.
+    """
+
+    def __init__(self, parent: ESQLBase, method: Optional[str] = None):
+        super().__init__(parent)
+        self.method = method
+        self.by_columns: List[FieldType] = []
+        self.options: Dict[str, Any] = {}
+
+    def by(self, *columns: FieldType) -> "Fuse":
+        self.by_columns += list(columns)
+        return self
+
+    def with_(self, **options: Any) -> "Fuse":
+        self.options = options
+        return self
+
+    def _render_internal(self) -> str:
+        method = f" {self.method.upper()}" if self.method else ""
+        by = (
+            " " + " ".join([f"BY {column}" for column in self.by_columns])
+            if self.by_columns
+            else ""
+        )
+        with_ = " WITH " + json.dumps(self.options) if self.options else ""
+        return f"FUSE{method}{by}{with_}"
+
+
 class Grok(ESQLBase):
     """Implementation of the ``GROK`` processing command.
 
@@ -991,7 +1200,7 @@ class LookupJoin(ESQLBase):
         self._field: Optional[FieldType] = None
 
     def on(self, field: FieldType) -> "LookupJoin":
-        """Continuation of the `LOOKUP_JOIN` command.
+        """Continuation of the ``LOOKUP JOIN`` command.
 
         :param field: The field to join on. This field must exist in both your current query
                       results and in the lookup index. If the field contains multi-valued
@@ -1046,6 +1255,67 @@ class Rename(ESQLBase):
         return f'RENAME {", ".join([f"{self._format_id(old_name)} AS {self._format_id(new_name)}" for old_name, new_name in self._columns.items()])}'
 
 
+class Rerank(ESQLBase):
+    """Implementation of the ``RERANK`` processing command.
+
+    This class inherits from :class:`ESQLBase <elasticsearch.esql.esql.ESQLBase>`,
+    to make it possible to chain all the commands that belong to an ES|QL query
+    in a single expression.
+    """
+
+    def __init__(
+        self, parent: ESQLBase, *query: ExpressionType, **named_query: ExpressionType
+    ):
+        if len(query) + len(named_query) > 1:
+            raise ValueError(
+                "this method requires either one positional or one keyword argument only"
+            )
+        super().__init__(parent)
+        self._query = query
+        self._named_query = named_query
+        self._fields: Optional[Tuple[str, ...]] = None
+        self._inference_id: Optional[str] = None
+
+    def on(self, *fields: str) -> "Rerank":
+        """Continuation of the ``RERANK`` command.
+
+        :param fields: One or more fields to use for reranking. These fields should
+                       contain the text that the reranking model will evaluate.
+        """
+        self._fields = fields
+        return self
+
+    def with_(self, inference_id: str) -> "Rerank":
+        """Continuation of the ``RERANK`` command.
+
+        :param inference_id: The ID of the inference endpoint to use for the task. The
+                             inference endpoint must be configured with the ``rerank``
+                             task type.
+        """
+        self._inference_id = inference_id
+        return self
+
+    def _render_internal(self) -> str:
+        if self._fields is None:
+            raise ValueError(
+                "The rerank command requires one or more fields to rerank on"
+            )
+        if self._inference_id is None:
+            raise ValueError("The completion command requires an inference ID")
+        with_ = {"inference_id": self._inference_id}
+        if self._named_query:
+            column = list(self._named_query.keys())[0]
+            query = list(self._named_query.values())[0]
+            query = f"{self._format_id(column)} = {json.dumps(query)}"
+        else:
+            query = json.dumps(self._query[0])
+        return (
+            f"RERANK {query} "
+            f"ON {', '.join([self._format_id(field) for field in self._fields])} "
+            f"WITH {json.dumps(with_)}"
+        )
+
+
 class Sample(ESQLBase):
     """Implementation of the ``SAMPLE`` processing command.
 
@@ -1090,6 +1360,8 @@ class Stats(ESQLBase):
     in a single expression.
     """
 
+    command_name = "STATS"
+
     def __init__(
         self,
         parent: ESQLBase,
@@ -1105,6 +1377,12 @@ class Stats(ESQLBase):
         self._grouping_expressions: Optional[Tuple[ExpressionType, ...]] = None
 
     def by(self, *grouping_expressions: ExpressionType) -> "Stats":
+        """Continuation of the ``STATS`` and ``INLINE STATS`` commands.
+
+        :param grouping_expressions: Expressions that output the values to group by.
+                                     If their names coincide with one of the computed
+                                     columns, that column will be ignored.
+        """
         self._grouping_expressions = grouping_expressions
         return self
 
@@ -1116,13 +1394,25 @@ class Stats(ESQLBase):
             ]
         else:
             exprs = [f"{self._format_expr(expr)}" for expr in self._expressions]
-        expression_separator = ",\n        "
+        indent = " " * (len(self.command_name) + 3)
+        expression_separator = f",\n{indent}"
         by = (
             ""
             if self._grouping_expressions is None
-            else f'\n        BY {", ".join([f"{self._format_expr(expr)}" for expr in self._grouping_expressions])}'
+            else f'\n{indent}BY {", ".join([f"{self._format_expr(expr)}" for expr in self._grouping_expressions])}'
         )
-        return f'STATS {expression_separator.join([f"{expr}" for expr in exprs])}{by}'
+        return f'{self.command_name} {expression_separator.join([f"{expr}" for expr in exprs])}{by}'
+
+
+class InlineStats(Stats):
+    """Implementation of the ``INLINE STATS`` processing command.
+
+    This class inherits from :class:`ESQLBase <elasticsearch.esql.esql.ESQLBase>`,
+    to make it possible to chain all the commands that belong to an ES|QL query
+    in a single expression.
+    """
+
+    command_name = "INLINE STATS"
 
 
 class Where(ESQLBase):
diff -pruN 9.1.1-2/elasticsearch/esql/functions.py 9.2.0-1/elasticsearch/esql/functions.py
--- 9.1.1-2/elasticsearch/esql/functions.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/esql/functions.py	2025-10-28 16:50:53.000000000 +0000
@@ -38,6 +38,20 @@ def abs(number: ExpressionType) -> Instr
     return InstrumentedExpression(f"ABS({_render(number)})")
 
 
+def absent(field: ExpressionType) -> InstrumentedExpression:
+    """Returns true if the input expression yields no non-null values within the
+    current aggregation context.
+
+    :param field: Expression that outputs values to be checked for absence.
+    """
+    return InstrumentedExpression(f"ABSENT({_render(field)})")
+
+
+def absent_over_time(field: ExpressionType) -> InstrumentedExpression:
+    """Calculates the absence of a field in the output result over time range."""
+    return InstrumentedExpression(f"ABSENT_OVER_TIME({_render(field)})")
+
+
 def acos(number: ExpressionType) -> InstrumentedExpression:
     """Returns the arccosine of `n` as an angle, expressed in radians.
 
@@ -364,6 +378,11 @@ def exp(number: ExpressionType) -> Instr
     return InstrumentedExpression(f"EXP({_render(number)})")
 
 
+def first(value: ExpressionType, sort: ExpressionType) -> InstrumentedExpression:
+    """Calculates the earliest value of a field."""
+    return InstrumentedExpression(f"FIRST({_render(value)}, {_render(sort)})")
+
+
 def first_over_time(field: ExpressionType) -> InstrumentedExpression:
     """The earliest value of a field, where recency determined by the
     `@timestamp` field.
@@ -463,6 +482,11 @@ def kql(query: ExpressionType) -> Instru
     return InstrumentedExpression(f"KQL({_render(query)})")
 
 
+def last(value: ExpressionType, sort: ExpressionType) -> InstrumentedExpression:
+    """Calculates the latest value of a field."""
+    return InstrumentedExpression(f"LAST({_render(value)}, {_render(sort)})")
+
+
 def last_over_time(field: ExpressionType) -> InstrumentedExpression:
     """The latest value of a field, where recency determined by the
     `@timestamp` field.
@@ -697,6 +721,18 @@ def mv_concat(string: ExpressionType, de
     return InstrumentedExpression(f"MV_CONCAT({_render(string)}, {_render(delim)})")
 
 
+def mv_contains(
+    superset: ExpressionType, subset: ExpressionType
+) -> InstrumentedExpression:
+    """Checks if all values yielded by the second multivalue expression are present in the
+    values yielded by the first multivalue expression. Returns a boolean. Null values are
+    treated as an empty set.
+    """
+    return InstrumentedExpression(
+        f"MV_CONTAINS({_render(superset)}, {_render(subset)})"
+    )
+
+
 def mv_count(field: ExpressionType) -> InstrumentedExpression:
     """Converts a multivalued expression into a single valued column containing
     a count of the number of values.
@@ -894,6 +930,18 @@ def pow(base: ExpressionType, exponent:
     return InstrumentedExpression(f"POW({_render(base)}, {_render(exponent)})")
 
 
+def present(field: ExpressionType) -> InstrumentedExpression:
+    """Returns true if the input expression yields any non-null values within the current
+    aggregation context. Otherwise it returns false.
+    """
+    return InstrumentedExpression(f"PRESENT({_render(field)})")
+
+
+def present_over_time(field: ExpressionType) -> InstrumentedExpression:
+    """Calculates the presence of a field in the output result over time range."""
+    return InstrumentedExpression(f"PRESENT_OVER_TIME({_render(field)})")
+
+
 def qstr(
     query: ExpressionType, options: ExpressionType = None
 ) -> InstrumentedExpression:
@@ -1452,6 +1500,11 @@ def sum(number: ExpressionType) -> Instr
     return InstrumentedExpression(f"SUM({_render(number)})")
 
 
+def sum_over_time(field: ExpressionType) -> InstrumentedExpression:
+    """Calculates the sum over time value of a field."""
+    return InstrumentedExpression(f"SUM({_render(field)})")
+
+
 def tan(angle: ExpressionType) -> InstrumentedExpression:
     """Returns the tangent of an angle.
 
@@ -1483,6 +1536,17 @@ def term(field: ExpressionType, query: E
     return InstrumentedExpression(f"TERM({_render(field)}, {_render(query)})")
 
 
+def text_embedding(
+    text: ExpressionType, inference_id: ExpressionType
+) -> InstrumentedExpression:
+    """Generates dense vector embeddings from text input using a specified inference endpoint.
+    Use this function to generate query vectors for KNN searches against your vectorized data
+    or others dense vector based operations."""
+    return InstrumentedExpression(
+        f"TEXT_EMBEDDING({_render(text)}, {_render(inference_id)})"
+    )
+
+
 def top(
     field: ExpressionType, limit: ExpressionType, order: ExpressionType
 ) -> InstrumentedExpression:
@@ -1596,6 +1660,22 @@ def to_double(field: ExpressionType) ->
     return InstrumentedExpression(f"TO_DOUBLE({_render(field)})")
 
 
+def to_geohash(field: ExpressionType) -> InstrumentedExpression:
+    """Converts an input value to a geohash value. A string will only be successfully
+    converted if it respects the geohash format, as described for the geohash grid
+    aggregation.
+    """
+    return InstrumentedExpression(f"TO_GEOHASH({_render(field)})")
+
+
+def to_geohex(field: ExpressionType) -> InstrumentedExpression:
+    """Converts an input value to a geohex value. A string will only be successfully
+    converted if it respects the geohex format, as described for the geohex grid
+    aggregation.
+    """
+    return InstrumentedExpression(f"TO_GEOHEX({_render(field)})")
+
+
 def to_geopoint(field: ExpressionType) -> InstrumentedExpression:
     """Converts an input value to a `geo_point` value. A string will only be
     successfully converted if it respects the WKT Point format.
@@ -1616,6 +1696,14 @@ def to_geoshape(field: ExpressionType) -
     return InstrumentedExpression(f"TO_GEOSHAPE({_render(field)})")
 
 
+def to_geotile(field: ExpressionType) -> InstrumentedExpression:
+    """Converts an input value to a geotile value. A string will only be successfully
+    converted if it respects the geotile format, as described for the geotile grid
+    aggregation.
+    """
+    return InstrumentedExpression(f"TO_GEOTILE({_render(field)})")
+
+
 def to_integer(field: ExpressionType) -> InstrumentedExpression:
     """Converts an input value to an integer value. If the input parameter is
     of a date type, its value will be interpreted as milliseconds since the
diff -pruN 9.1.1-2/elasticsearch/helpers/__init__.py 9.2.0-1/elasticsearch/helpers/__init__.py
--- 9.1.1-2/elasticsearch/helpers/__init__.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/helpers/__init__.py	2025-10-28 16:50:53.000000000 +0000
@@ -19,12 +19,21 @@ from .._async.helpers import async_bulk,
 from .._utils import fixup_module_metadata
 from .actions import _chunk_actions  # noqa: F401
 from .actions import _process_bulk_chunk  # noqa: F401
-from .actions import bulk, expand_action, parallel_bulk, reindex, scan, streaming_bulk
+from .actions import (
+    BULK_FLUSH,
+    bulk,
+    expand_action,
+    parallel_bulk,
+    reindex,
+    scan,
+    streaming_bulk,
+)
 from .errors import BulkIndexError, ScanError
 
 __all__ = [
     "BulkIndexError",
     "ScanError",
+    "BULK_FLUSH",
     "expand_action",
     "streaming_bulk",
     "bulk",
diff -pruN 9.1.1-2/elasticsearch/helpers/actions.py 9.2.0-1/elasticsearch/helpers/actions.py
--- 9.1.1-2/elasticsearch/helpers/actions.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/elasticsearch/helpers/actions.py	2025-10-28 16:50:53.000000000 +0000
@@ -16,9 +16,10 @@
 #  under the License.
 
 import logging
+import queue
 import time
+from enum import Enum
 from operator import methodcaller
-from queue import Queue
 from typing import (
     Any,
     Callable,
@@ -37,13 +38,21 @@ from typing import (
 from elastic_transport import OpenTelemetrySpan
 
 from .. import Elasticsearch
-from ..compat import to_bytes
+from ..compat import safe_thread, to_bytes
 from ..exceptions import ApiError, NotFoundError, TransportError
 from ..serializer import Serializer
 from .errors import BulkIndexError, ScanError
 
 logger = logging.getLogger("elasticsearch.helpers")
 
+
+class BulkMeta(Enum):
+    flush = 1
+    done = 2
+
+
+BULK_FLUSH = BulkMeta.flush
+
 _TYPE_BULK_ACTION = Union[bytes, str, Dict[str, Any]]
 _TYPE_BULK_ACTION_HEADER = Dict[str, Any]
 _TYPE_BULK_ACTION_BODY = Union[None, bytes, Dict[str, Any]]
@@ -51,6 +60,13 @@ _TYPE_BULK_ACTION_HEADER_AND_BODY = Tupl
     _TYPE_BULK_ACTION_HEADER, _TYPE_BULK_ACTION_BODY
 ]
 
+_TYPE_BULK_ACTION_WITH_META = Union[bytes, str, Dict[str, Any], BulkMeta]
+_TYPE_BULK_ACTION_HEADER_WITH_META = Union[Dict[str, Any], BulkMeta]
+_TYPE_BULK_ACTION_HEADER_WITH_META_AND_BODY = Union[
+    Tuple[_TYPE_BULK_ACTION_HEADER, _TYPE_BULK_ACTION_BODY],
+    Tuple[BulkMeta, Any],
+]
+
 
 def expand_action(data: _TYPE_BULK_ACTION) -> _TYPE_BULK_ACTION_HEADER_AND_BODY:
     """
@@ -139,7 +155,9 @@ class _ActionChunker:
         ] = []
 
     def feed(
-        self, action: _TYPE_BULK_ACTION_HEADER, data: _TYPE_BULK_ACTION_BODY
+        self,
+        action: _TYPE_BULK_ACTION_HEADER_WITH_META,
+        data: _TYPE_BULK_ACTION_BODY,
     ) -> Optional[
         Tuple[
             List[
@@ -152,23 +170,25 @@ class _ActionChunker:
         ]
     ]:
         ret = None
-        raw_action = action
-        raw_data = data
-        action_bytes = to_bytes(self.serializer.dumps(action), "utf-8")
-        # +1 to account for the trailing new line character
-        cur_size = len(action_bytes) + 1
-
-        data_bytes: Optional[bytes]
-        if data is not None:
-            data_bytes = to_bytes(self.serializer.dumps(data), "utf-8")
-            cur_size += len(data_bytes) + 1
-        else:
-            data_bytes = None
+        action_bytes = b""
+        data_bytes: Optional[bytes] = None
+        cur_size = 0
+        if not isinstance(action, BulkMeta):
+            action_bytes = to_bytes(self.serializer.dumps(action), "utf-8")
+            # +1 to account for the trailing new line character
+            cur_size = len(action_bytes) + 1
+
+            if data is not None:
+                data_bytes = to_bytes(self.serializer.dumps(data), "utf-8")
+                cur_size += len(data_bytes) + 1
+            else:
+                data_bytes = None
 
         # full chunk, send it and start a new one
         if self.bulk_actions and (
             self.size + cur_size > self.max_chunk_bytes
             or self.action_count == self.chunk_size
+            or (action == BulkMeta.flush and self.bulk_actions)
         ):
             ret = (self.bulk_data, self.bulk_actions)
             self.bulk_actions = []
@@ -176,15 +196,16 @@ class _ActionChunker:
             self.size = 0
             self.action_count = 0
 
-        self.bulk_actions.append(action_bytes)
-        if data_bytes is not None:
-            self.bulk_actions.append(data_bytes)
-            self.bulk_data.append((raw_action, raw_data))
-        else:
-            self.bulk_data.append((raw_action,))
+        if not isinstance(action, BulkMeta):
+            self.bulk_actions.append(action_bytes)
+            if data_bytes is not None:
+                self.bulk_actions.append(data_bytes)
+                self.bulk_data.append((action, data))
+            else:
+                self.bulk_data.append((action,))
 
-        self.size += cur_size
-        self.action_count += 1
+            self.size += cur_size
+            self.action_count += 1
         return ret
 
     def flush(
@@ -209,9 +230,10 @@ class _ActionChunker:
 
 
 def _chunk_actions(
-    actions: Iterable[_TYPE_BULK_ACTION_HEADER_AND_BODY],
+    actions: Iterable[_TYPE_BULK_ACTION_HEADER_WITH_META_AND_BODY],
     chunk_size: int,
     max_chunk_bytes: int,
+    flush_after_seconds: Optional[float],
     serializer: Serializer,
 ) -> Iterable[
     Tuple[
@@ -231,10 +253,41 @@ def _chunk_actions(
     chunker = _ActionChunker(
         chunk_size=chunk_size, max_chunk_bytes=max_chunk_bytes, serializer=serializer
     )
-    for action, data in actions:
-        ret = chunker.feed(action, data)
-        if ret:
-            yield ret
+
+    if not flush_after_seconds:
+        for action, data in actions:
+            ret = chunker.feed(action, data)
+            if ret:
+                yield ret
+    else:
+        item_queue: queue.Queue[_TYPE_BULK_ACTION_HEADER_WITH_META_AND_BODY] = (
+            queue.Queue(maxsize=1)
+        )
+
+        def get_items() -> None:
+            try:
+                for item in actions:
+                    item_queue.put(item)
+            finally:
+                # make sure we signal the end even if there is an exception
+                item_queue.put((BulkMeta.done, None))
+
+        with safe_thread(get_items):
+            timeout: Optional[float] = flush_after_seconds
+            while True:
+                try:
+                    action, data = item_queue.get(timeout=timeout)
+                    timeout = flush_after_seconds
+                except queue.Empty:
+                    action, data = BulkMeta.flush, None
+                    timeout = None
+
+                if action is BulkMeta.done:
+                    break
+                ret = chunker.feed(action, data)
+                if ret:
+                    yield ret
+
     ret = chunker.flush()
     if ret:
         yield ret
@@ -361,9 +414,10 @@ def _process_bulk_chunk(
 
 def streaming_bulk(
     client: Elasticsearch,
-    actions: Iterable[_TYPE_BULK_ACTION],
+    actions: Iterable[_TYPE_BULK_ACTION_WITH_META],
     chunk_size: int = 500,
     max_chunk_bytes: int = 100 * 1024 * 1024,
+    flush_after_seconds: Optional[float] = None,
     raise_on_error: bool = True,
     expand_action_callback: Callable[
         [_TYPE_BULK_ACTION], _TYPE_BULK_ACTION_HEADER_AND_BODY
@@ -397,6 +451,9 @@ def streaming_bulk(
     :arg actions: iterable containing the actions to be executed
     :arg chunk_size: number of docs in one chunk sent to es (default: 500)
     :arg max_chunk_bytes: the maximum size of the request in bytes (default: 100MB)
+    :arg flush_after_seconds: time in seconds after which a chunk is written even
+        if hasn't reached `chunk_size` or `max_chunk_bytes`. Set to 0 to not use a
+        timeout-based flush. (default: 0)
     :arg raise_on_error: raise ``BulkIndexError`` containing errors (as `.errors`)
         from the execution of the last chunk when some occur. By default we raise.
     :arg raise_on_exception: if ``False`` then don't propagate exceptions from
@@ -425,6 +482,13 @@ def streaming_bulk(
 
         serializer = client.transport.serializers.get_serializer("application/json")
 
+        def expand_action_with_meta(
+            data: _TYPE_BULK_ACTION_WITH_META,
+        ) -> _TYPE_BULK_ACTION_HEADER_WITH_META_AND_BODY:
+            if isinstance(data, BulkMeta):
+                return data, None
+            return expand_action_callback(data)
+
         bulk_data: List[
             Union[
                 Tuple[_TYPE_BULK_ACTION_HEADER],
@@ -433,9 +497,10 @@ def streaming_bulk(
         ]
         bulk_actions: List[bytes]
         for bulk_data, bulk_actions in _chunk_actions(
-            map(expand_action_callback, actions),
+            map(expand_action_with_meta, actions),
             chunk_size,
             max_chunk_bytes,
+            flush_after_seconds,
             serializer,
         ):
             for attempt in range(max_retries + 1):
@@ -557,6 +622,7 @@ def parallel_bulk(
     thread_count: int = 4,
     chunk_size: int = 500,
     max_chunk_bytes: int = 100 * 1024 * 1024,
+    flush_after_seconds: Optional[float] = None,
     queue_size: int = 4,
     expand_action_callback: Callable[
         [_TYPE_BULK_ACTION], _TYPE_BULK_ACTION_HEADER_AND_BODY
@@ -573,6 +639,9 @@ def parallel_bulk(
     :arg thread_count: size of the threadpool to use for the bulk requests
     :arg chunk_size: number of docs in one chunk sent to es (default: 500)
     :arg max_chunk_bytes: the maximum size of the request in bytes (default: 100MB)
+    :arg flush_after_seconds: time in seconds after which a chunk is written even
+        if hasn't reached `chunk_size` or `max_chunk_bytes`. Set to 0 to not use a
+        timeout-based flush. (default: 0)
     :arg raise_on_error: raise ``BulkIndexError`` containing errors (as `.errors`)
         from the execution of the last chunk when some occur. By default we raise.
     :arg raise_on_exception: if ``False`` then don't propagate exceptions from
@@ -596,7 +665,7 @@ def parallel_bulk(
             super()._setup_queues()  # type: ignore[misc]
             # The queue must be at least the size of the number of threads to
             # prevent hanging when inserting sentinel values during teardown.
-            self._inqueue: Queue[
+            self._inqueue: queue.Queue[
                 Tuple[
                     List[
                         Union[
@@ -605,7 +674,7 @@ def parallel_bulk(
                     ],
                     List[bytes],
                 ]
-            ] = Queue(max(queue_size, thread_count))
+            ] = queue.Queue(max(queue_size, thread_count))
             self._quick_put = self._inqueue.put
 
     with client._otel.helpers_span("helpers.parallel_bulk") as otel_span:
@@ -625,7 +694,11 @@ def parallel_bulk(
                     )
                 ),
                 _chunk_actions(
-                    expanded_actions, chunk_size, max_chunk_bytes, serializer
+                    expanded_actions,
+                    chunk_size,
+                    max_chunk_bytes,
+                    flush_after_seconds,
+                    serializer,
                 ),
             ):
                 yield from result
diff -pruN 9.1.1-2/examples/fastapi-apm/dockerfiles/Dockerfile.app 9.2.0-1/examples/fastapi-apm/dockerfiles/Dockerfile.app
--- 9.1.1-2/examples/fastapi-apm/dockerfiles/Dockerfile.app	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/examples/fastapi-apm/dockerfiles/Dockerfile.app	2025-10-28 16:50:53.000000000 +0000
@@ -1,4 +1,4 @@
-FROM python:3.9
+FROM python:3.10
 
 EXPOSE 9292
 WORKDIR /
diff -pruN 9.1.1-2/examples/fastapi-apm/dockerfiles/Dockerfile.ping 9.2.0-1/examples/fastapi-apm/dockerfiles/Dockerfile.ping
--- 9.1.1-2/examples/fastapi-apm/dockerfiles/Dockerfile.ping	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/examples/fastapi-apm/dockerfiles/Dockerfile.ping	2025-10-28 16:50:53.000000000 +0000
@@ -1,4 +1,4 @@
-FROM python:3.9
+FROM python:3.10
 WORKDIR /
 RUN python -m pip install \
     --no-cache \
diff -pruN 9.1.1-2/examples/quotes/.gitignore 9.2.0-1/examples/quotes/.gitignore
--- 9.1.1-2/examples/quotes/.gitignore	1970-01-01 00:00:00.000000000 +0000
+++ 9.2.0-1/examples/quotes/.gitignore	2025-10-28 16:50:53.000000000 +0000
@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff -pruN 9.1.1-2/examples/quotes/README.md 9.2.0-1/examples/quotes/README.md
--- 9.1.1-2/examples/quotes/README.md	1970-01-01 00:00:00.000000000 +0000
+++ 9.2.0-1/examples/quotes/README.md	2025-10-28 16:50:53.000000000 +0000
@@ -0,0 +1,107 @@
+# Quotes
+Quotes database example, which demonstrates the Elasticsearch integration with
+Pydantic models. This example features a React frontend and a FastAPI back end.
+
+![Quotes app screenshot](screenshot.png)
+
+## What is this?
+
+This directory contains a small application that demonstrates how easy it is
+to set up a full-text and vector database using [Elasticsearch](https://www.elastic.co/elasticsearch),
+while defining the data model with [Pydantic](https://docs.pydantic.dev/latest/).
+
+The application includes a FastAPI back end and a React front end. It ingests a
+dataset of famous quotes into in an Elasticsearch index, and for each quote it
+generates an embedding using the
+[all-MiniLM-L6-v2](https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2)
+Sentence Transformers model.
+
+The dataset has about 850 famous quotes, each with their author and tags. The
+data is a subset of a
+[Kaggle dataset](https://www.kaggle.com/datasets/akmittal/quotes-dataset) that
+appears to have been generated from quotes that were scraped from the Goodreads
+[popular quotes](https://www.goodreads.com/quotes) page.
+
+## Requirements
+
+Please make sure you have the following installed:
+
+- Python 3.10 or newer
+- Node.js 18 or newer
+
+## How To Run
+
+Follow these steps to install this demo on your computer:
+
+### Clone this repository
+
+Run the following command to install a copy of this project on your computer:
+
+```bash
+git clone https://github.com/elastic/elasticsearch-py
+cd examples/quotes
+```
+
+### Install the Node and Python dependencies
+
+Run the following command to set up the JavaScript and Python environment and
+install all the dependencies:
+
+```bash
+npm install
+```
+
+### Start a development Elasticsearch container
+
+You can use [start-local](https://www.elastic.co/docs/deploy-manage/deploy/self-managed/local-development-installation-quickstart)
+to start a small Elasticsearch instance.
+
+Use this command to launch the instance (Docker and Docker Compose are required):
+
+```bash
+curl -fsSL https://elastic.co/start-local | sh
+```
+
+Once your Elasticsearch instead is deployed, create an environment variable called
+`ELASTICSEARCH_URL`, making sure it includes the password generated by start-local.
+Example:
+
+```bash
+export ELASTICSEARCH_URL=http://elastic:your-password-here@localhost:9200
+```
+
+### Create the quotes database
+
+Run this command in your terminal:
+
+```bash
+npm run ingest
+```
+
+Note that the `ELASTICSEARCH_URL` variable must be defined in the terminal
+session in which you run this command.
+
+This task should take a minute or less. The GPU, if available, is used optimize
+the generation of the embeddings.
+
+### Start the back end
+
+Run this command in your terminal:
+
+```bash
+npm run backend
+```
+
+Note that the `ELASTICSEARCH_URL` variable must be defined in the terminal
+session in which you run this command.
+
+### Start the front end
+
+Open a second terminal window and run this command:
+
+```bash
+npm run dev
+```
+
+You can now navigate to `http://localhost:5173` on your web browser to access
+the application.
diff -pruN 9.1.1-2/examples/quotes/backend/pyproject.toml 9.2.0-1/examples/quotes/backend/pyproject.toml
--- 9.1.1-2/examples/quotes/backend/pyproject.toml	1970-01-01 00:00:00.000000000 +0000
+++ 9.2.0-1/examples/quotes/backend/pyproject.toml	2025-10-28 16:50:53.000000000 +0000
@@ -0,0 +1,18 @@
+[project]
+name = "quotes"
+version = "0.1"
+dependencies = [
+    "elasticsearch[async]>=9,<10",
+    "fastapi",
+    "orjson",
+    "sentence-transformers",
+    "uvicorn",
+]
+
+[project.optional-dependencies]
+dev = [
+]
+
+[build-system]
+requires = ["hatchling"]
+build-backend = "hatchling.build"
diff -pruN 9.1.1-2/examples/quotes/backend/quotes.csv 9.2.0-1/examples/quotes/backend/quotes.csv
--- 9.1.1-2/examples/quotes/backend/quotes.csv	1970-01-01 00:00:00.000000000 +0000
+++ 9.2.0-1/examples/quotes/backend/quotes.csv	2025-10-28 16:50:53.000000000 +0000
@@ -0,0 +1,843 @@
+"quote","author","tags"
+"Two things are infinite: the universe and human stupidity; and I'm not sure about the universe.","Albert Einstein","attributed-no-source,human-nature,humor,infinity,philosophy,science,stupidity,universe"
+"In three words I can sum up everything I've learned about life: it goes on.","Robert Frost","moving-on,learned"
+"If you tell the truth, you don't have to remember anything.","Mark Twain","lies,lying,memory,truth"
+"I've learned that people will forget what you said, people will forget what you did, but people will never forget how you made them feel.","Maya Angelou","61419-likes"
+"There are only two ways to live your life. One is as though nothing is a miracle. The other is as though everything is a miracle.","Albert Einstein","attributed-no-source,inspirational,life,live,miracle,miracles"
+"Good friends, good books, and a sleepy conscience: this is the ideal life.","Mark Twain","books,contentment,friends,friendship,life"
+"Whenever you find yourself on the side of the majority, it is time to reform (or pause and reflect).","Mark Twain","individuality,majority,minority,pause,reflect,wisdom"
+"The man who does not read has no advantage over the man who cannot read.","Mark Twain","aliteracy,attributed-no-source,literacy"
+"Outside of a dog, a book is man's best friend. Inside of a dog it's too dark to read.","Groucho Marx","animals,books,dogs,friends,humor"
+"I am enough of an artist to draw freely upon my imagination. Imagination is more important than knowledge. Knowledge is limited. Imagination encircles the world.","Albert Einstein","1929,imagination,inspirational,viereck-interview"
+"Never put off till tomorrow what may be done day after tomorrow just as well.","Mark Twain","humor,procrastination"
+"If you can't explain it to a six year old, you don't understand it yourself.","Albert Einstein","attributed-no-source,simplicity,understand"
+"Everything you can imagine is real.","Pablo Picasso","art,imagination,inspirational,life"
+"If you want your children to be intelligent, read them fairy tales. If you want them to be more intelligent, read them more fairy tales.","Albert Einstein","attributed-no-source,children,fairy-tales"
+"Logic will get you from A to Z; imagination will get you everywhere.","Albert Einstein","attributed-no-source,imagination"
+"I find television very educating. Every time somebody turns on the set, I go into the other room and read a book.","Groucho Marx","books,humor,reading,television"
+"When one door of happiness closes, another opens; but often we look so long at the closed door that we do not see the one which has been opened for us.","Helen Keller","inspirational"
+"Life is like riding a bicycle. To keep your balance, you must keep moving.","Albert Einstein","balance,moving,bicycle"
+"If everyone is moving forward together, then success takes care of itself.","Henry Ford","together,care,moving"
+"Love is like a beautiful flower which I may not touch, but whose fragrance makes the garden a place of delight just the same.","Helen Keller","flower,beautiful,garden"
+"What's money? A man is a success if he gets up in the morning and goes to bed at night and in between does what he wants to do.","Bob Dylan","morning,money,night"
+"The most beautiful thing we can experience is the mysterious. It is the source of all true art and science.","Albert Einstein","experience,science"
+"You may say I'm a dreamer, but I'm not the only one. I hope someday you'll join us. And the world will live as one.","John Lennon","beatles,connection,dreamers,dreaming,dreams,hope,inspirational,peace"
+"Optimism is the faith that leads to achievement. Nothing can be done without hope and confidence.","Helen Keller","motivational,faith"
+"Love is an irresistible desire to be irresistibly desired.","Robert Frost","love"
+"Love is the flower you've got to let grow.","John Lennon","flower,grow"
+"Success depends upon previous preparation, and without such preparation there is sure to be failure.","Confucius","failure,sure,depends"
+"Imagine all the people living life in peace. You may say I'm a dreamer, but I'm not the only one. I hope someday you'll join us, and the world will be as one.","John Lennon","peace,hope,dreamer"
+"The question isn't who is going to let me; it's who is going to stop me.","Ayn Rand","15880-likes"
+"Coming together is a beginning; keeping together is progress; working together is success.","Henry Ford","together,progress"
+"I have never let my schooling interfere with my education.","Mark Twain","attributed-no-source,education"
+"Try not to become a man of success, but rather try to become a man of value.","Albert Einstein","value,rather"
+"Anyone who has never made a mistake has never tried anything new.","Albert Einstein","attributed-no-source,mistakes"
+"Action is the foundational key to all success.","Pablo Picasso","action,key"
+"The fear of death follows from the fear of life. A man who lives fully is prepared to die at any time.","Mark Twain","death,life"
+"′Classic′ - a book which people praise and don't read.","Mark Twain","books,classic,reading"
+"The biggest adventure you can take is to live the life of your dreams.","Oprah Winfrey","dreams,adventure,biggest"
+"Alcohol may be man's worst enemy, but the bible says love your enemy.","Frank Sinatra","alcohol,bible,drinking,enemies,religion"
+"Happiness lies in the joy of achievement and the thrill of creative effort.","Franklin D. Roosevelt","happiness"
+"All you need in this life is ignorance and confidence, and then success is sure.","Mark Twain","success,ignorance"
+"Love recognizes no barriers. It jumps hurdles, leaps fences, penetrates walls to arrive at its destination full of hope.","Maya Angelou","love"
+"The foundation stones for a balanced success are honesty, character, integrity, faith, love and loyalty.","Zig Ziglar","success,faith,character"
+"Strive not to be a success, but rather to be of value.","Albert Einstein","business,success,value"
+"I've failed over and over and over again in my life and that is why I succeed.","Michael Jordan","success,succeed,again"
+"True art is characterized by an irresistible urge in the creative artist.","Albert Einstein","creative,artist,true"
+"Everyone has inside of him a piece of good news. The good news is that you don't know how great you can be! How much you can love! What you can accomplish! And what your potential is!","Anne Frank","love,good,great"
+"I believe that being successful means having a balance of success stories across the many areas of your life. You can't truly be considered successful in your business life if your home life is in shambles.","Zig Ziglar","home,life,business"
+"I am enough of an artist to draw freely upon my imagination.","Albert Einstein","artist,draw,freely"
+"It is easy to hate and it is difficult to love. This is how the whole scheme of things works. All good things are difficult to achieve; and bad things are very easy to get.","Confucius","good,achieve,hate"
+"Choose a job you love, and you will never have to work a day in your life.","Confucius","work,love,choose"
+"If you have only one smile in you give it to the people you love.","Maya Angelou","valentine's-day"
+"Sculpture is the art of the intelligence.","Pablo Picasso","sculpture"
+"A lie can travel half way around the world while the truth is putting on its shoes.","Mark Twain","misattributed-mark-twain,truth"
+"Only a life lived for others is a life worthwhile.","Albert Einstein","others,worthwhile,lived"
+"Never tell the truth to people who are not worthy of it.","Mark Twain","truth"
+"Success is like reaching an important birthday and finding you're exactly the same.","Audrey Hepburn","birthday,finding,reaching"
+"My great hope is to laugh as much as I cry; to get my work done and try to love somebody and have the courage to accept the love in return.","Maya Angelou","being-loved,courage,laugh,love,loving"
+"The ladder of success is best climbed by stepping on the rungs of opportunity.","Ayn Rand","best,ladder,stepping"
+"Learn from yesterday, live for today, hope for tomorrow. The important thing is not to stop questioning.","Albert Einstein","today,learn,tomorrow"
+"I believe that unarmed truth and unconditional love will have the final word in reality. This is why right, temporarily defeated, is stronger than evil triumphant.","Martin Luther King Jr.","good-and-evil,love,truth"
+"We must accept finite disappointment, but never lose infinite hope.","Martin Luther King Jr.","hope"
+"We have always held to the hope, the belief, the conviction that there is a better life, a better world, beyond the horizon.","Franklin D. Roosevelt","hope,conviction,belief"
+"I simply can't build my hopes on a foundation of confusion, misery and death... I think... peace and tranquillity will return again.","Anne Frank","death,peace,foundation"
+"You can make positive deposits in your own economy every day by reading and listening to powerful, positive, life-changing content and by associating with encouraging and hope-building people.","Zig Ziglar","positive,reading,listening"
+"Youth is easily deceived because it is quick to hope.","Aristotle","youth,deceived,quick"
+"Speak the truth, do not yield to anger; give, if thou art asked for little; by these three steps thou wilt go near the gods.","Confucius","truth,anger,speak"
+"Knowing yourself is the beginning of all wisdom.","Aristotle","introspection,self-discovery,wisdom"
+"Art washes away from the soul the dust of everyday life.","Pablo Picasso","art"
+"A person with a new idea is a crank until the idea succeeds.","Mark Twain","crank,succeeds,until"
+"I would rather walk with a friend in the dark, than alone in the light.","Helen Keller","friendship"
+"Remembering that I'll be dead soon is the most important tool I've ever encountered to help me make the big choices in life. Because almost everything - all external expectations, all pride, all fear of embarrassment or failure - these things just fall away in the face of death, leaving only what is truly important.","Steve Jobs","failure,death,fear"
+"The overwhelming majority of Americans are possessed of two great qualities a sense of humor and a sense of proportion.","Franklin D. Roosevelt","great,qualities,majority"
+"Part of the secret of a success in life is to eat what you like and let the food fight it out inside.","Mark Twain","food,life,fight"
+"Love is a better teacher than duty.","Albert Einstein","teacher,duty"
+"In the flush of love's light, we dare be brave. And suddenly we see that love costs all we are, and will ever be. Yet it is only love which sets us free.","Maya Angelou","light,free,brave"
+"I speak to everyone in the same way, whether he is the garbage man or the president of the university.","Albert Einstein","life,respect"
+"You cannot climb the ladder of success dressed in the costume of failure.","Zig Ziglar","failure,ladder,climb"
+"Keep away from people who try to belittle your ambitions. Small people always do that, but the really great make you feel that you, too, can become great.","Mark Twain","greatness"
+"Your work is going to fill a large part of your life, and the only way to be truly satisfied is to do what you believe is great work. And the only way to do great work is to love what you do. If you haven't found it yet, keep looking. Don't settle. As with all matters of the heart, you'll know when you find it.","Steve Jobs","life,love,work"
+"The beauty of a woman must be seen from in her eyes, because that is the doorway to her heart, the place where love resides.","Audrey Hepburn","beauty,eyes,heart"
+"A person will sometimes devote all his life to the development of one part of his body - the wishbone.","Robert Frost","body,devote,wishbone"
+"People are basically the same the world over. Everybody wants the same things - to be happy, to be healthy, to be at least reasonably prosperous, and to be secure. They want friends, peace of mind, good family relationships, and hope that tomorrow is going to be even better than today.","Zig Ziglar","family,good,peace"
+"How wonderful it is that nobody need wait a single moment before starting to improve the world.","Anne Frank","moment,improve,wait"
+"Nothing is impossible, the word itself says 'I'm possible'!","Audrey Hepburn","impossible,possible"
+"We should measure welfare's success by how many people leave welfare, not by how many are added.","Ronald Reagan","welfare,measure,leave"
+"We've got this gift of love, but love is like a precious plant. You can't just accept it and leave it in the cupboard or just think it's going to get on by itself. You've got to keep watering it. You've got to really look after it and nurture it.","John Lennon","relationship,nurture,gift"
+"I write some country music. There's a song called 'I Hope You Dance.' Incredible. I was going to write that poem; somebody beat me to it.","Maya Angelou","music,dance,song"
+"Painting is just another way of keeping a diary.","Pablo Picasso","painting,diary,keeping"
+"If you find it in your heart to care for somebody else, you will have succeeded.","Maya Angelou","care,heart,succeeded"
+"There is a very fine line between loving life and being greedy for it.","Maya Angelou","greed,life"
+"We love the things we love for what they are.","Robert Frost","love,poetry"
+"I decided, very early on, just to accept life unconditionally; I never expected it to do anything special for me, yet I seemed to accomplish far more than I had ever hoped. Most of the time it just happened to me without my ever seeking it.","Audrey Hepburn","time,accept,special"
+"Count your age by friends, not years. Count your life by smiles, not tears.","John Lennon","happiness,timelessness,wisdom"
+"I remember a specific moment, watching my grandmother hang the clothes on the line, and her saying to me, 'you are going to have to learn to do this,' and me being in that space of awareness and knowing that my life would not be the same as my grandmother's life.","Oprah Winfrey","space,learn,moment"
+"When you're in jail, a good friend will be trying to bail you out. A best friend will be in the cell next to you saying, 'Damn, that was fun'.","Groucho Marx","friends,humor,jail"
+"I believe that a simple and unassuming manner of life is best for everyone, best both for the body and the mind.","Albert Einstein","best,simple,body"
+"When you are courting a nice girl an hour seems like a second. When you sit on a red-hot cinder a second seems like an hour. That's relativity.","Albert Einstein","humor"
+"In a good bookroom you feel in some mysterious way that you are absorbing the wisdom contained in all the books through your skin, without even opening them.","Mark Twain","bookroom,books,libraries,wisdom"
+"Loving someone liberates the lover as well as the beloved. And that kind of love comes with age.","Maya Angelou","age,lover,loving"
+"For the past 33 years, I have looked in the mirror every morning and asked myself: 'If today were the last day of my life, would I want to do what I am about to do today?' And whenever the answer has been 'No' for too many days in a row, I know I need to change something.","Steve Jobs","change,morning,mirror"
+"Never memorize something that you can look up.","Albert Einstein","humor,science"
+"He that lives upon hope will die fasting.","Benjamin Franklin","die,fasting,lives"
+"I always entertain great hopes.","Robert Frost","great,hopes,entertain"
+"Lord save us all from old age and broken health and a hope tree that has lost the faculty of putting out blossoms.","Mark Twain","health,age,tree"
+"Hope is a waking dream.","Aristotle","dreams,hope"
+"In the end, that's what this election is about. Do we participate in a politics of cynicism or a politics of hope?","Barack Obama","politics,election,cynicism"
+"A clever person solves a problem. A wise person avoids it.","Albert Einstein","8292-likes"
+"Reader, suppose you were an idiot. And suppose you were a member of Congress. But I repeat myself.","Mark Twain","humor,politics"
+"Substitute 'damn' every time you're inclined to write 'very;' your editor will delete it and the writing will be just as it should be.","Mark Twain","humor,writing"
+"Science without religion is lame, religion without science is blind.","Albert Einstein","religion,science"
+"I love people who make me laugh. I honestly think it's the thing I like most, to laugh. It cures a multitude of ills. It's probably the most important thing in a person.","Audrey Hepburn","love,honestly,laugh"
+"When someone shows you who they are believe them; the first time.","Maya Angelou","oprah-s-thank-you-game,people"
+"Reality is merely an illusion, albeit a very persistent one.","Albert Einstein","reality"
+"I attribute my success to this - I never gave or took any excuse.","Florence Nightingale","motivational,excuse"
+"Whatever you want to do, if you want to be great at it, you have to love it and be able to make sacrifices for it.","Maya Angelou","great,whatever,sacrifices"
+"Don’t go around saying the world owes you a living. The world owes you nothing. It was here first.","Mark Twain","living,world"
+"I believe in everything until it's disproved. So I believe in fairies, the myths, dragons. It all exists, even if it's in your mind. Who's to say that dreams and nightmares aren't as real as the here and now?","John Lennon","beatles,dragons,dreamers,dreaming,dreams,fairies,faith,mythology,nightmares,reality,truth"
+"Knowledge is love and light and vision.","Helen Keller","knowledge,light,vision"
+"Honesty and integrity are absolutely essential for success in life - all areas of life. The really good news is that anyone can develop both honesty and integrity.","Zig Ziglar","success,good,integrity"
+"Life is what happens while you are busy making other plans.","John Lennon","busy,plans,happens"
+"The more one does and sees and feels, the more one is able to do, and the more genuine may be one's appreciation of fundamental things like home, and love, and understanding companionship.","Amelia Earhart","home,genuine,feels"
+"If we knew what it was we were doing, it would not be called research, would it?","Albert Einstein","science"
+"Don't go around saying the world owes you a living. The world owes you nothing. It was here first.","Mark Twain","owes,living,saying"
+"Faith is taking the first step even when you can't see the whole staircase.","Martin Luther King Jr.","inspirational-faith"
+"The superior man makes the difficulty to be overcome his first interest; success only comes later.","Confucius","overcome,difficulty"
+"I have no special talents. I am only passionately curious.","Albert Einstein","inspirational-life"
+"Good friends, good books and a sleepy conscience: this is the ideal life.","Mark Twain","good,books,conscience"
+"Well, Art is Art, isn't it? Still, on the other hand, water is water. And east is east and west is west and if you take cranberries and stew them like applesauce they taste much more like prunes than rhubarb does. Now you tell me what you know.","Groucho Marx","water,hand,taste"
+"When I was 5 years old, my mother always told me that happiness was the key to life. When I went to school, they asked me what I wanted to be when I grew up. I wrote down ‘happy’. They told me I didn’t understand the assignment, and I told them they didn’t understand life.","John Lennon","inspirational,life"
+"Whether you think you can, or you think you can't--you're right.","Henry Ford","thinking"
+"In the end, we will remember not the words of our enemies, but the silence of our friends.","Martin Luther King Jr.","inspirational"
+"I should have no objection to go over the same life from its beginning to the end: requesting only the advantage authors have, of correcting in a second edition the faults of the first.","Benjamin Franklin","beginning,advantage,second"
+"Think of all the beauty still left around you and be happy.","Anne Frank","anne,beauty,frank,happy"
+"The most important thing is to enjoy your life—to be happy—it's all that matters.","Audrey Hepburn","happiness,life"
+"If a cluttered desk is a sign of a cluttered mind, of what, then, is an empty desk a sign?","Albert Einstein","einstein,human,humor,philosophy,stupidity"
+"Never be bullied into silence. Never allow yourself to be made a victim. Accept no one’s definition of your life; define yourself.","Robert Frost","6617-likes"
+"Everything is clearer when you're in love.","John Lennon","love"
+"I did not attend his funeral, but I sent a nice letter saying I approved of it.","Mark Twain","classic-insult,funeral,funny,humor"
+"What is a friend? A single soul dwelling in two bodies.","Aristotle","friendship,soul"
+"God created war so that Americans would learn geography.","Mark Twain","americans,geography,war"
+"My mission in life is not merely to survive, but to thrive; and to do so with some passion, some compassion, some humor, and some style.","Maya Angelou","life,humor,compassion"
+"Love is the greatest refreshment in life.","Pablo Picasso","life,greatest"
+"We delight in the beauty of the butterfly, but rarely admit the changes it has gone through to achieve that beauty.","Maya Angelou","inspiration"
+"Gravitation is not responsible for people falling in love.","Albert Einstein","love"
+"As usual, there is a great woman behind every idiot.","John Lennon","beatles,men,women"
+"Either write something worth reading or do something worth writing.","Benjamin Franklin","hmmm"
+"If you can't fly then run, if you can't run then walk, if you can't walk then crawl, but whatever you do you have to keep moving forward.","Martin Luther King Jr.","inspirational"
+"If people are good only because they fear punishment, and hope for reward, then we are a sorry lot indeed.","Albert Einstein","good,fear,punishment"
+"I was gratified to be able to answer promptly, and I did. I said I didn’t know.","Mark Twain","humor,knowledge"
+"But who prays for Satan? Who, in eighteen centuries, has had the common humanity to pray for the one sinner that needed it most?","Mark Twain","humor-satan"
+"If money is your hope for independence you will never have it. The only real security that a man will have in this world is a reserve of knowledge, experience, and ability.","Henry Ford","knowledge,money,experience"
+"I love to see a young girl go out and grab the world by the lapels. Life's a bitch. You've got to go out and kick ass.","Maya Angelou","humor,inspirational,life"
+"Never allow someone to be your priority while allowing yourself to be their option.","Mark Twain","heartbreak"
+"The important thing is to not stop questioning. Curiosity has its own reason for existence. One cannot help but be in awe when he contemplates the mysteries of eternity, of life, of the marvelous structure of reality. It is enough if one tries merely to comprehend a little of this mystery each day.—"Old Man's Advice to Youth: 'Never Lose a Holy Curiosity.'"LIFE Magazine (2 May 1955) p. 64","Albert Einstein","1955,curiosity,mystery,physics,science"
+"A youth, when at home, should be filial and, abroad, respectful to his elders. He should be earnest and truthful. He should overflow in love to all and cultivate the friendship of the good. When he has time and opportunity, after the performance of these things, he should employ them in polite studies.","Confucius","love,time,home"
+"No tears in the writer, no tears in the reader. No surprise in the writer, no surprise in the reader.","Robert Frost","reading,writing"
+"Try not to become a man of success. Rather become a man of value.","Albert Einstein","adulthood,success,value"
+"Turn your wounds into wisdom.","Oprah Winfrey","experience,inspirational,pain,wisdom,wounds"
+"I thank God I'm myself and for the life I'm given to live and for friends and lovers and beloveds, and I thank God for knowing that all those people have already paid for me.","Maya Angelou","god,knowing,lovers"
+"Every child is an artist. The problem is how to remain an artist once he grows up.","Pablo Picasso","art,attributed-no-source"
+"Loyalty to country ALWAYS. Loyalty to government, when it deserves it.","Mark Twain","patriotism,politics"
+"Wrinkles should merely indicate where the smiles have been.","Mark Twain","age"
+"Courage is the most important of all the virtues because without courage, you can't practice any other virtue consistently.","Maya Angelou","character,consistency,courage,determination,essence,ethos,fortitude,goodness,inspiration,life-lessons,persistence,resolve,self-reliance,strength,virtue,virtues"
+"Any fool can know. The point is to understand.","Albert Einstein","knowledge,learning,understanding,wisdom"
+"Life would be infinitely happier if we could only be born at the age of eighty and gradually approach eighteen.","Mark Twain","age,born,approach"
+"And I loved Fats Waller. I love his instrumental abilities, his vocal abilities and his sense of humor.","Paul McCartney","humor,loved,ability"
+"The best and most beautiful things in the world cannot be seen or even touched. They must be felt with the heart","Helen Keller","by-anne-sullivan,emotions,feelings"
+"No one wants to die. Even people who want to go to heaven don't want to die to get there. And yet death is the destination we all share. No one has ever escaped it. And that is as it should be, because Death is very likely the single best invention of Life. It is Life's change agent. It clears out the old to make way for the new.","Steve Jobs","death,change,best"
+"Rhetoric may be defined as the faculty of observing in any given case the available means of persuasion. This is not a function of any other art.","Aristotle","persuasion,rhetoric"
+"I don't trust people who don't love themselves and tell me, 'I love you.' ... There is an African saying which is: Be careful when a naked person offers you a shirt.","Maya Angelou","1997,annie-clark-tanner-lecture,inspirational,love,trust"
+"I've missed more than 9000 shots in my career. I've lost almost 300 games. 26 times, I've been trusted to take the game winning shot and missed. I've failed over and over and over again in my life. And that is why I succeed.","Michael Jordan","inspirational"
+"Once you can accept the universe as matter expanding into nothing that is something, wearing stripes with plaid comes easy.","Albert Einstein","funny"
+"Microsoft has had two goals in the last 10 years. One was to copy the Mac, and the other was to copy Lotus' success in the spreadsheet - basically, the applications business. And over the course of the last 10 years, Microsoft accomplished both of those goals. And now they are completely lost.","Steve Jobs","business,goals,lost"
+"Try to look at your weakness and convert it into your strength. That's success.","Zig Ziglar","strength,weakness,convert"
+"A woman's heart should be so hidden in God that a man has to seek Him just to find her.","Maya Angelou","inspirational"
+"What material success does is provide you with the ability to concentrate on other things that really matter. And that is being able to make a difference, not only in your own life, but in other people's lives.","Oprah Winfrey","life,ability,difference"
+"You can't connect the dots looking forward; you can only connect them looking backwards. So you have to trust that the dots will somehow connect in your future. You have to trust in something - your gut, destiny, life, karma, whatever. This approach has never let me down, and it has made all the difference in my life.","Steve Jobs","future,trust,karma"
+"What we have once enjoyed we can never lose. All that we love deeply becomes a part of us.","Helen Keller","lose,becomes,enjoyed"
+"Music was my refuge. I could crawl into the space between the notes and curl my back to loneliness.","Maya Angelou","loneliness,music,refuge"
+"Love many things, for therein lies the true strength, and whosoever loves much performs much, and can accomplish much, and what is done in love is done well.","Vincent Van Gogh","strength,true,accomplish"
+"By three methods we may learn wisdom: First, by reflection, which is noblest; Second, by imitation, which is easiest; and third by experience, which is the bitterest.","Confucius","wisdom"
+"Humor must not professedly teach and it must not professedly preach, but it must do both if it would live forever.","Mark Twain","teach,forever,preach"
+"I met Woz when I was 13, at a friend's garage. He was about 18. He was, like, the first person I met who knew more electronics than I did at that point. We became good friends, because we shared an interest in computers and we had a sense of humor. We pulled all kinds of pranks together.","Steve Jobs","good,computers,together"
+"The purpose of art is washing the dust of daily life off our souls.","Pablo Picasso","life,daily,purpose"
+"If I were not a physicist, I would probably be a musician. I often think in music. I live my daydreams in music. I see my life in terms of music.","Albert Einstein","music"
+"Only in the darkness can you see the stars.","Martin Luther King Jr.","hope,inspirational"
+"No person is your friend who demands your silence, or denies your right to grow.","Alice Walker","silence,friend,grow"
+"The Bush Administration's failure to be consistently involved in helping Israel achieve peace with the Palestinians has been both wrong for our friendship with Israel, as well as badly damaging to our standing in the Arab world.","Barack Obama","failure,peace,achieve"
+"The most difficult thing is the decision to act, the rest is merely tenacity. The fears are paper tigers. You can do anything you decide to do. You can act to change and control your life; and the procedure, the process is its own reward.","Amelia Earhart","change,decision,control"
+"The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.","Albert Einstein","change,deep-thoughts,thinking,world"
+"Be true to the game, because the game will be true to you. If you try to shortcut the game, then the game will shortcut you. If you put forth the effort, good things will be bestowed upon you. That's truly about the game, and in some ways that's about life too.","Michael Jordan","good,effort,game"
+"Art is the lie that enables us to realize the truth.","Pablo Picasso","art,truth"
+"The more I see, the less I know for sure.","John Lennon","beatles,life,perception,truth"
+"I do not fear death. I had been dead for billions and billions of years before I was born, and had not suffered the slightest inconvenience from it.","Mark Twain","death,inspirational"
+"Books are for people who wish they were somewhere else.","Mark Twain","books-reading"
+"Those who educate children well are more to be honored than they who produce them; for these only gave them life, those the art of living well.","Aristotle","greek,mentors,philosophy,teachers"
+"What would men be without women? Scarce, sir...mighty scarce.","Mark Twain","humor,men,women"
+"The secret source of humor is not joy but sorrow; there is no humor in Heaven.","Mark Twain","joy,heaven,sorrow"
+"I know not with what weapons World War III will be fought, but World War IV will be fought with sticks and stones.","Albert Einstein","albert-einstein,future,war,wisdom"
+"Success is liking yourself, liking what you do, and liking how you do it.","Maya Angelou","4051-likes"
+"You never fail until you stop trying.","Albert Einstein","inspirational"
+"We all know that Art is not truth. Art is a lie that makes us realize the truth, at least the truth that is given to us to understand.","Pablo Picasso","truth,lie,understand"
+"Great spirits have always encountered violent opposition from mediocre minds.","Albert Einstein","greatness,opposition,spirit"
+"I did then what I knew how to do. Now that I know better, I do better.","Maya Angelou","attributed,attributed-no-source,education,intelligence,knowledge,unsourced"
+"Some say the world will end in fire,Some say in ice.From what I've tasted of desire,I hold with those who favor fire. But if it had to perish twiceI think I know enough of hateTo say that for destruction iceIs also greatAnd would suffice.","Robert Frost","poetry"
+"Sanity and happiness are an impossible combination.","Mark Twain","happiness,sanity"
+"My mission in life is not merely to survive, but to thrive; and to do so with some passion, some compassion, some humor, and some style","Maya Angelou","3758-likes"
+"A poem begins as a lump in the throat, a sense of wrong, a homesickness, a lovesickness.","Robert Frost","poetry"
+"Clothes make the man. Naked people have little or no influence on society.","Mark Twain","clothing"
+"Don't part with your illusions. When they are gone you may still exist, but you have ceased to live.","Mark Twain","illusions,life"
+"I can shake off everything as I write; my sorrows disappear, my courage is reborn.","Anne Frank","writing"
+"The aim of art is to represent not the outward appearance of things, but their inward significance.","Aristotle","art,philosophy"
+"Our brand of democracy is hard. But I can promise that a year from now, when I no longer hold this office, I'll be right there with you as a citizen - inspired by those voices of fairness and vision, of grit and good humor and kindness that have helped America travel so far.","Barack Obama","travel,good,kindness"
+"If you hear a voice within you say 'you cannot paint,' then by all means paint, and that voice will be silenced.","Vincent Van Gogh","voice,within,paint"
+"From the moment I picked up your book until I put it down, I was convulsed with laughter. Some day I intend reading it.","Groucho Marx","books,humor,reading"
+"The most common way people give up their power is by thinking they don't have any.","Alice Walker","inspirational"
+"I'll always stay connected with Apple. I hope that throughout my life I'll sort of have the thread of my life and the thread of Apple weave in and out of each other, like a tapestry. There may be a few years when I'm not there, but I'll always come back.","Steve Jobs","life,connected,apple"
+"There can be no deep disappointment where there is not deep love.","Martin Luther King Jr.","justice,love,segregation"
+"Have enough courage to trust love one more time and always one more time.","Maya Angelou","courage,love,trust"
+"Achievement of your happiness is the only moral purpose of your life, and that happiness, not pain or mindless self-indulgence, is the proof of your moral integrity, since it is the proof and the result of your loyalty to the achievement of your values.","Ayn Rand","happiness,pain,integrity"
+"If you pick up a starving dog and make him prosperous he will not bite you. This is the principal difference between a dog and man.","Mark Twain","animals,dogs"
+"When I was a boy of 14, my father was so ignorant I could hardly stand to have the old man around. But when I got to be 21, I was astonished at how much the old man had learned in seven years.","Mark Twain","arrogance,humor,ignorance"
+"Everything human is pathetic. The secret source of humor itself is not joy but sorrow. There is no humor in heaven.","Mark Twain","joy,heaven,sorrow"
+"Always do what is right. It will gratify half of mankind and astound the other.","Mark Twain","morals"
+"The artist is a receptacle for emotions that come from all over the place: from the sky, from the earth, from a scrap of paper, from a passing shape, from a spider's web.","Pablo Picasso","sky,earth,emotions"
+"There is more to sex appeal than just measurements. I don't need a bedroom to prove my womanliness. I can convey just as much sex appeal, picking apples off a tree or standing in the rain.","Audrey Hepburn","sex-appeal,women"
+"Education is the ability to listen to almost anything without losing your temper or your self-confidence.","Robert Frost","education"
+"Perfect friendship is the friendship of men who are good, and alike in excellence; for these wish well alike to each other qua good, and they are good in themselves.","Aristotle","good,men,excellence"
+"It is not that I'm so smart. But I stay with the questions much longer.","Albert Einstein","intelligence,learning,wisdom"
+"A woman without a man is like a fish without a bicycle.","Gloria Steinem","feminism,humour"
+"The trouble is not in dying for a friend, but in finding a friend worth dying for.","Mark Twain","3011-likes"
+"The more you praise and celebrate your life, the more there is in life to celebrate.","Oprah Winfrey","happiness,life"
+"One thing you can't hide - is when you're crippled inside.","John Lennon","beatles,emotions,hypocrisy,pain,suffering"
+"Fighting for one's freedom, struggling towards being free, is like struggling to be a poet or a good Christian or a good Jew or a good Muslim or good Zen Buddhist. You work all day long and achieve some kind of level of success by nightfall, go to sleep and wake up the next morning with the job still to be done. So you start all over again.","Maya Angelou","work,morning,freedom"
+"If you don't read the newspaper, you're uninformed. If you read the newspaper, you're mis-informed.","Mark Twain","newspapers"
+"There are millions of Americans outside Washington who are tired of stale political arguments and are moving this country forward. They believe, and I believe, that here in America, our success should depend not on accident of birth, but the strength of our work ethic and the scope of our dreams.","Barack Obama","work,strength,dreams"
+"Creativity is intelligence having fun.","Albert Einstein","2946-likes"
+"Wheresoever you go, go with all your heart.","Confucius","2940-likes"
+"The measure of intelligence is the ability to change.","Albert Einstein","adaptation,flexibility,intelligence,open-mindedness,wisdom"
+"Everything has beauty, but not everyone sees it.","Confucius","beauty,everything,seeing"
+"Learn to value yourself, which means: fight for your happiness.","Ayn Rand","fight,happiness,learn"
+"The world is a dangerous place to live, not because of the people who are evil, but because of the people who don't do anything about it.","Albert Einstein","dangerous,evil,people,world"
+"Courage is resistance to fear, mastery of fear - not absence of fear.","Mark Twain","courage"
+"If we couldn't laugh we would all go insane.","Robert Frost","laughter"
+"You can have it all. Just not all at once.","Oprah Winfrey","dreams,life,time"
+"The best thing to hold onto in life is each other.","Audrey Hepburn","inspirational"
+"Remembering that you are going to die is the best way I know to avoid the trap of thinking you have something to lose. You are already naked. There is no reason not to follow your heart.","Steve Jobs","2740-likes"
+"If A is a success in life, then A equals x plus y plus z. Work is x; y is play; and z is keeping your mouth shut","Albert Einstein","albert,einstein,equations,success"
+"Black holes are where God divided by zero.","Albert Einstein","humor"
+"If I’m honest I have to tell you I still read fairy-tales and I like them best of all.","Audrey Hepburn","fairy-tales"
+"Learn from the mistakes of others. You can never live long enough to make them all yourself.","Groucho Marx","attributed-no-source"
+"Your time is limited, so don't waste it living someone else's life. Don't be trapped by dogma - which is living with the results of other people's thinking. Don't let the noise of others' opinions drown out your own inner voice. And most important, have the courage to follow your heart and intuition.","Steve Jobs","courage,time,heart"
+"You can only become truly accomplished at something you love. Don’t make money your goal. Instead pursue the things you love doing and then do them so well that people can’t take their eyes off of you.","Maya Angelou","2637-likes"
+"Everyone is a moon, and has a dark side which he never shows to anybody.","Mark Twain","darkness,human-nature,moon"
+"Change will not come if we wait for some other person, or if we wait for some other time. We are the ones we've been waiting for. We are the change that we seek.","Barack Obama","change,inspirational"
+"It's not the size of the dog in the fight, it's the size of the fight in the dog.","Mark Twain","bravery,dog,famous,inspirational,valour"
+"Kindness is a language which the deaf can hear and the blind can see.","Mark Twain","inspirational,kindness"
+"There's nowhere you can be that isn't where you're meant to be...","John Lennon","beatles,destiny,fate,life"
+"Never make someone a priority when all you are to them is an option.","Maya Angelou","2570-likes"
+"Nothing in the world is more dangerous than sincere ignorance and conscientious stupidity.","Martin Luther King Jr.","ignorance"
+"The ultimate measure of a man is not where he stands in moments of comfort and convenience, but where he stands at times of challenge and controversy.","Martin Luther King Jr.","challanges"
+"If there is any one secret of success, it lies in the ability to get the other person's point of view and see things from that person's angle as well as from your own.","Henry Ford","ability,view,point"
+"Forgive, O Lord, my little jokes on TheeAnd I'll forgive Thy great big one on me.","Robert Frost","humor,poetry,religion"
+"Procrastination is one of the most common and deadliest of diseases and its toll on success and happiness is heavy.","Wayne Gretzky","happiness,heavy,diseases"
+"Humor is mankind's greatest blessing.","Mark Twain","humor"
+"I've lived through some terrible things in my life, some of which actually happened.","Mark Twain","humor"
+"Tell me and I forget, teach me and I may remember, involve me and I learn.","Benjamin Franklin","learning,mentoring,parenting,teacher"
+"The best way to cheer yourself is to cheer somebody else up.","Albert Einstein","2471-likes"
+"Lack of direction, not lack of time, is the problem. We all have twenty-four hour days.","Zig Ziglar","attention,direction,focus,inspirational,motivational"
+"The secret to humor is surprise.","Aristotle","humor,surprise"
+"Name the greatest of all inventors. Accident.","Mark Twain","inventing-humor"
+"Behind every beautiful thing, there's some kind of pain.","Bob Dylan","beautiful,behind,kind,of,pain,thing"
+"Everything must be made as simple as possible. But not simpler.","Albert Einstein","einstein,paraphrased,science,systems"
+"Humor is the most engaging cowardice.","Robert Frost","cowardice,engaging"
+"Try to be a rainbow in someone's cloud.","Maya Angelou","cloud,rainbow"
+"You believe in a book that has talking animals, wizards, witches, demons, sticks turning into snakes, burning bushes, food falling from the sky, people walking on water, and all sorts of magical, absurd and primitive stories, and you say that we are the ones that need help?","Mark Twain","books-bible"
+"The best way to cheer yourself is to try to cheer someone else up.","Mark Twain","happiness"
+"When you trip over love, it is easy to get up. But when you fall in love, it is impossible to stand again.","Albert Einstein","love"
+"Being the richest man in the cemetery doesn't matter to me. Going to bed at night saying we've done something wonderful... that's what matters to me.","Steve Jobs","2356-likes"
+"I never forget a face, but in your case I'll be glad to make an exception.","Groucho Marx","humor"
+"You may encounter many defeats, but you must not be defeated. In fact, it may be necessary to encounter the defeats, so you can know who you are, what you can rise from, how you can still come out of it.","Maya Angelou","adversity,character,failure,perseverance"
+"Parents can only give good advice or put them on the right paths, but the final forming of a person's character lies in their own hands.","Anne Frank","growing-up,innocence,inspirational,parenting,personal-responsibility,right-of-passage,self-determination,self-responsibility"
+"Humor is reason gone mad.","Groucho Marx","reason,mad,gone"
+"What is right is not always popular and what is popular is not always right.","Albert Einstein","2280-likes"
+"Freedom lies in being bold.","Robert Frost","boldness,courage,freedom"
+"Be thankful for what you have; you'll end up having more. If you concentrate on what you don't have, you will never, ever have enough","Oprah Winfrey","appreciation,contentment,dissatisfaction,life,perception,positivity,thankfulness"
+"Education: the path from cocky ignorance to miserable uncertainty.","Mark Twain","education"
+"If you would be loved, love, and be loveable.","Benjamin Franklin","loved"
+"If I am not good to myself, how can I expect anyone else to be good to me?","Maya Angelou","2202-likes"
+"It does not matter how slowly you go as long as you do not stop.","Confucius","education,inspirational,life,perseverance"
+"Ask for what you want and be prepared to get it!","Maya Angelou","inspirational"
+"You alone are enough. You have nothing to prove to anybody.","Maya Angelou","2179-likes"
+"I was born with an enormous need for affection, and a terrible need to give it.","Audrey Hepburn","born,affection"
+"The easy confidence with which I know another man's religion is folly teaches me to suspect that my own is also.","Mark Twain","humor,philosophy,religion"
+"Adventure is worthwhile in itself.","Amelia Earhart","2126-likes"
+"Intelligence plus character-that is the goal of true education.","Martin Luther King Jr.","education"
+"If everyone demanded peace instead of another television set, then there'd be peace.","John Lennon","activism,beatles,materialism,peace,society,television"
+"The pursuit of truth and beauty is a sphere of activity in which we are permitted to remain children all our lives.","Albert Einstein","wonder"
+"In the middle of difficulty lies opportunity","Albert Einstein","2072-likes"
+"The best way out is always through.","Robert Frost","best"
+"Whoever is careless with the truth in small matters cannot be trusted with important matters","Albert Einstein","character,honesty,integrity"
+"I believe in God, but not as one thing, not as an old man in the sky. I believe that what people call God is something in all of us. I believe that what Jesus and Mohammed and Buddha and all the rest said was right. It's just that the translations have gone wrong.","John Lennon","god,organized-religion,religion,spirituality"
+"I believe in being strong when everything seems to be going wrong. I believe that happy girls are the prettiest girls. I believe that tomorrow is another day, and I believe in miracles","Audrey Hepburn","life"
+"Men marry women with the hope they will never change. Women marry men with the hope they will change. Invariably they are both disappointed.","Albert Einstein","battle-of-the-sexes,gender-stereotypes,marriage,men-and-women"
+"Stepping onto a brand-new path is difficult, but not more difficult than remaining in a situation, which is not nurturing to the whole woman.","Maya Angelou","change,inspirational,self-determination"
+"Poetry is what gets lost in translation.","Robert Frost","poetry"
+"You know you are on the road to success if you would do your job, and not be paid for it.","Oprah Winfrey","road,paid"
+"The secret of life is honesty and fair dealing. If you can fake that, you've got it made.","Groucho Marx","humor,life"
+"The desire to reach for the stars is ambitious. The desire to reach hearts is wise.","Maya Angelou","ambition,inspirational,wisdom"
+"Peace cannot be kept by force; it can only be achieved by understanding.","Albert Einstein","force,peace"
+"Half the world is composed of people who have something to say and can't, and the other half who have nothing to say and keep on saying it.","Robert Frost","new-england-wisdom"
+"He who knows all the answers has not been asked all the questions.","Confucius","wisdom"
+"The secret to getting ahead is getting started.","Mark Twain","starting,working"
+"A question that sometimes drives me hazy: am I or are the others crazy?","Albert Einstein","crazy,question,thought-provoking"
+"If I'm the people's poet, then I ought to be in people's hands - and, I hope, in their heart.","Maya Angelou","heart,hands,ought"
+"Living is Easy with Eyes Closed.","John Lennon","beatles,blindness,ignorance,life"
+"If you make a mistake and do not correct it, this is called a mistake.","Confucius","inspirational,mistake"
+"Happiness depends upon ourselves.","Aristotle","happiness"
+"Two roads diverged in a wood, and I -I took the one less traveled by,And that has made all the difference.","Robert Frost","choice,consequence,individuality,inspirational"
+"You can't blame gravity for falling in love.","Albert Einstein","gravity,blame"
+"All you need in this life is ignorance and confidence; then success is sure.","Mark Twain","humor,success"
+"The best way to not feel hopeless is to get up and do something. Don’t wait for good things to happen to you. If you go out and make some good things happen, you will fill the world with hope, you will fill yourself with hope.","Barack Obama","determination,helping-others,hope,initiative,just-do-it,proactivity,service,volunteerism,work"
+"Imagination is everything. It is the preview of life's coming attractions.","Albert Einstein","creativity,fantasy,imagination,inspirational"
+"Any book that helps a child to form a habit of reading, to make reading one of his deep and continuing needs, is good for him.","Maya Angelou","books,inspirational,library"
+"The highest use of capital is not to make more money, but to make money do more for the betterment of life.","Henry Ford","money,highest,betterment"
+"Educating the mind without educating the heart is no education at all.","Aristotle","education,ethics"
+"It's hard to beat a person who never gives up.","Babe Ruth","hard-work,inspiration,teamwork"
+"Life is really simple, but we insist on making it complicated.","Confucius","simple,insist"
+"Love is composed of a single soul inhabiting two bodies.","Aristotle","bodies,soul,single"
+"There is probably a perverse pride in my administration... that we were going to do the right thing, even if short-term it was unpopular. And I think anybody who's occupied this office has to remember that success is determined by an intersection in policy and politics and that you can't be neglecting of marketing and P.R. and public opinion.","Barack Obama","politics,pride,marketing"
+"It is the supreme art of the teacher to awaken joy in creative expression and knowledge.","Albert Einstein","teacher,knowledge,joy"
+"I am not a teacher, but an awakener.","Robert Frost","carpe-diem,education,inspirational,learning,mentoring"
+"Excellence is an art won by training and habituation. We do not act rightly because we have virtue or excellence, but we rather have those because we have acted rightly. We are what we repeatedly do. Excellence, then, is not an act but a habit.","Aristotle","training,excellence,act"
+"No matter what happens, or how bad it seems today, life does go on, and it will be better tomorrow.","Maya Angelou","inspirational-quotes"
+"Because paper has more patience than people.","Anne Frank","affirming,inspirational,uplifting"
+"Politics is the art of looking for trouble, finding it everywhere, diagnosing it incorrectly and applying the wrong remedies.","Groucho Marx","politics,wrong,looking"
+"Happiness makes up in height for what it lacks in length.","Robert Frost","happiness"
+"Each person must live their life as a model for others.","Rosa Parks","model,others"
+"If the facts don't fit the theory, change the facts.","Albert Einstein","facts,humor,science"
+"The important thing is not to stop questioning. Curiosity has its own reason for existing.","Albert Einstein","curiosity,philosophy,wonder"
+"What I know is, is that if you do work that you love, and the work fulfills you, the rest will come.","Oprah Winfrey","work,rest,fulfills"
+"Eating is so intimate. It's very sensual. When you invite someone to sit at your table and you want to cook for them, you're inviting a person into your life.","Maya Angelou","food,eating,table"
+"A clear conscience is the sure sign of a bad memory.","Mark Twain","conscience,humor,memory"
+"I must be willing to give up what I am in order to become what I will be.","Albert Einstein","inspirational"
+"I haven't any right to criticize books, and I don't do it except when I hate them. I often want to criticize Jane Austen, but her books madden me so that I can't conceal my frenzy from the reader; and therefore I have to stop every time I begin. Every time I read Pride and Prejudice I want to dig her up and beat her over the skull with her own shin-bone.","Mark Twain","austen,criticism,reading,writing"
+"I hope the millions of people I've touched have the optimism and desire to share their goals and hard work and persevere with a positive attitude.","Michael Jordan","attitude,positive,work"
+"There is no abstract art. You must always start with something. Afterward you can remove all traces of reality.","Pablo Picasso","reality,start,abstract"
+"Love is a better master than duty.","Albert Einstein","love"
+"He that can have patience can have what he will.","Benjamin Franklin","determination,inspirational,patience"
+"When I die, I hope to go to Heaven, whatever the Hell that is.","Ayn Rand","death,hell,heaven"
+"Death is no more than passing from one room into another. But there's a difference for me, you know. Because in that other room I shall be able to see.","Helen Keller","blindness,death,faith,inspirational,wisdom"
+"On every front there are clear answers out there that can make this country stronger, but we're going to break through the fear and the frustration people are feeling. Our job is to make sure that even as we make progress, that we are also giving people a sense of hope and vision for the future.","Barack Obama","future,fear,progress"
+"The biggest adventure you can ever take is to live the life of your dreams.","Oprah Winfrey","adventure,bravery,inspirational,life"
+"Why do they always teach us that it's easy and evil to do what we want and that we need discipline to restrain ourselves? It's the hardest thing in the world--to do what we want. And it takes the greatest kind of courage. I mean, what we really want.","Ayn Rand","career,inspiration,life"
+"No one really knows why they are alive until they know what they'd die for.","Martin Luther King Jr.","death,inspirational"
+"A banker is a fellow who lends you his umbrella when the sun is shining, but wants it back the minute it begins to rain.","Mark Twain","bank,bankers,humor"
+"Happiness is the meaning and the purpose of life, the whole aim and end of human existence.","Aristotle","happiness"
+"A Penny Saved is a Penny Earned","Benjamin Franklin","funny,inspirational,money"
+"If someone thinks that peace and love are just a cliche that must have been left behind in the 60s, that's a problem. Peace and love are eternal.","John Lennon","1960s,beatles,love,peace,sixties"
+"It would be possible to describe everything scientifically, but it would make no sense; it would be without meaning, as if you described a Beethoven symphony as a variation of wave pressure.","Albert Einstein","art,cybernetics,science"
+"Your time is limited, so don't waste it living someone else's life. Don't be trapped by dogma - which is living with the results of other people's thinking. Don't let the noise of other's opinions drown out your own inner voice. And most important, have the courage to follow your heart and intuition. They somehow already know what you truly want to become. Everything else is secondary.","Steve Jobs","death,life,r-i-p,steve"
+"The most important thing is to enjoy your life - to be happy - it's all that matters.","Audrey Hepburn","happy,enjoy,matters"
+"Those who are not looking for happiness are the most likely to find it, because those who are searching forget that the surest way to be happy is to seek happiness for others.","Martin Luther King Jr.","happiness"
+"And God help Bruce Springsteen when they decide he's no longer God... They'll turn on him, and I hope he survives it.","John Lennon","god,help,turn"
+"There's a world of difference between truth and facts. Facts can obscure truth.","Maya Angelou","truth"
+"Excellence is never an accident. It is always the result of high intention, sincere effort, and intelligent execution; it represents the wise choice of many alternatives - choice, not chance, determines your destiny.","Aristotle","choice,inspirational"
+"If a man is called to be a street sweeper, he should sweep streets even as a Michaelangelo painted, or Beethoven composed music or Shakespeare wrote poetry. He should sweep streets so well that all the hosts of heaven and earth will pause to say, 'Here lived a great street sweeper who did his job well.","Martin Luther King Jr.","excellence,inspirational"
+"Once I knew only darkness and stillness... my life was without past or future... but a little word from the fingers of another fell into my hand that clutched at emptiness, and my heart leaped to the rapture of living.","Helen Keller","life,future,emptiness"
+"In wine there is wisdom, in beer there is Freedom, in water there is bacteria.","Benjamin Franklin","drinking,humor"
+"A man is a success if he gets up in the morning and gets to bed at night, and in between he does what he wants to do.","Bob Dylan","bob-dylan,music,success"
+"I didn't have time to write a short letter, so I wrote a long one instead.","Mark Twain","humor"
+"The smallest minority on earth is the individual. Those who deny individual rights cannot claim to be defenders of minorities.","Ayn Rand","freedom-of-thought,philosophy,politics,rights"
+"The way a team plays as a whole determines its success. You may have the greatest bunch of individual stars in the world, but if they don't play together, the club won't be worth a dime.","Babe Ruth","sports,team,together"
+"Those are my principles, and if you don't like them...well I have others.","Groucho Marx","humor"
+"Home is the place where, when you have to go there, They have to take you in.","Robert Frost","inspirational-quotes"
+"Many people die at twenty five and aren't buried until they are seventy five.","Benjamin Franklin","death,life,wordplay"
+"Fear not death for the sooner we die, the longer we shall be immortal.","Benjamin Franklin","death"
+"I never made one of my discoveries through the process of rational thinking","Albert Einstein","creativity,epiphany,humor,inspiration"
+"Any emotion, if it is sincere, is involuntary.","Mark Twain","inspirational"
+"I must have a prodigious amount of mind; it takes me as much as a week, sometimes, to make it up!","Mark Twain","decisions,humor,mind"
+"The two most important days in your life are the day you are born and the day you find out why.","Mark Twain","birth,born,day,important,life,reasons-why,true"
+"Once we accept our limits, we go beyond them.","Albert Einstein","inspirational,self-improvement,self-knowledge"
+"Alone we can do so little; together we can do so much","Helen Keller","collaboration,life,teamwork"
+"One morning I shot an elephant in my pajamas. How he got in my pajamas I'll never know.","Groucho Marx","humor"
+"The best revenge is massive success.","Frank Sinatra","best,revenge,massive"
+"My favorite things in life don't cost any money. It's really clear that the most precious resource we all have is time.","Steve Jobs","time,money,precious"
+"We, the People, recognize that we have responsibilities as well as rights; that our destinies are bound together; that a freedom which only asks what's in it for me, a freedom without a commitment to others, a freedom without love or charity or duty or patriotism, is unworthy of our founding ideals, and those who died in their defense.","Barack Obama","patriotism,freedom,died"
+"The rain to the wind said,You push and I'll pelt.'They so smote the garden bedThat the flowers actually knelt,And lay lodged--though not dead.I know how the flowers felt.","Robert Frost","poetry,rain"
+"Our goals can only be reached through a vehicle of a plan, in which we must fervently believe, and upon which we must vigorously act. There is no other route to success.","Pablo Picasso","goals,plan,act"
+"To perceive is to suffer.","Aristotle","empathy,life,suffer,understanding"
+"The funniest people are the saddest ones","Confucius","funny,people,sad"
+"I didn't fail the test, I just found 100 ways to do it wrong.","Benjamin Franklin","examinations,failure,humor"
+"Your time is limited, so don't waste it living someone else's life.","Steve Jobs","life,life-and-living"
+"Don't ever take a fence down until you know why it was put up.","Robert Frost","advice,caution,cautionary,inspirational"
+"Life is a series of experiences, each one of which makes us bigger, even though sometimes it is hard to realize this. For the world was built to develop character, and we must learn that the setbacks and grieves which we endure help us in our marching onward.","Henry Ford","learning,setbacks"
+"Government exists to protect us from each other. Where government has gone beyond its limits is in deciding to protect us from ourselves.","Ronald Reagan","freedom-of-choice,government,inspirational,political-philosophy,politics"
+"Be slow in choosing a friend, slower in changing.","Benjamin Franklin","friend,slow,changing"
+"If a man wants you, nothing can keep him away. If he doesn't want you, nothing can make him stay.","Oprah Winfrey","romance"
+"Well, art is art, isn't it? Still, on the other hand, water is water! And east is east and west is west and if you take cranberries and stew them like applesauce they taste much more like prunes than rhubarb does. Now, uh... now you tell me what you know.","Groucho Marx","art,humor"
+"The educated differ from the uneducated as much as the living differ from the dead.","Aristotle","education"
+"When we remember we are all mad, the mysteries disappear and life stands explained.","Mark Twain","remember,mad,explained"
+"I used to think anyone doing anything weird was weird. Now I know that it is the people that call others weird that are weird.","Paul McCartney","beatles,humor,music,nonjudgemental"
+"I have a dream that my four little children will one day live in a nation where they will not be judged by the color of their skin but by the content of their character.","Martin Luther King Jr.","character,dream,inspirational,prejudice,race"
+"Imagination is the highest form of research.","Albert Einstein","inspiration"
+"Wherever you go, go with all your heart.","Confucius","confucius,inspirational"
+"Life is one grand, sweet song, so start the music.","Ronald Reagan","music,song,start"
+"We must live together as brothers or perish together as fools.","Martin Luther King Jr.","brotherhood,inspirational,wisdom"
+"If a black cat crosses your path, it signifies that the animal is going somewhere.","Groucho Marx","humor,superstition"
+"Science investigates; religion interprets. Science gives man knowledge, which is power; religion gives man wisdom, which is control. Science deals mainly with facts; religion deals mainly with values. The two are not rivals.","Martin Luther King Jr.","religion,science"
+"I heard a definition once: Happiness is health and a short memory! I wish I'd invented it, because it is very true.","Audrey Hepburn","happiness,inspirational"
+"The most incomprehensible thing about the world is that it is at all comprehensible.","Albert Einstein","einstein,philosophy,science"
+"I sustain myself with the love of family.","Maya Angelou","family,inspirational"
+"Some people claim that marriage interferes with romance. There's no doubt about it. Anytime you have a romance, your wife is bound to interfere.","Groucho Marx","marriage,romance,sex"
+"Learn the rules like a pro, so you can break them like an artist.","Pablo Picasso","art,creativity,motivational,picasso,rules,writing"
+"I made my first white women friends in college; they loved me and were loyal to our friendship, but I understood, as they did, that they were white women and that whiteness mattered.","Alice Walker","women,college,loved"
+"I've come to believe that each of us has a personal calling that's as unique as a fingerprint - and that the best way to succeed is to discover what you love and then find a way to offer it to others in the form of service, working hard, and also allowing the energy of the universe to lead you.","Oprah Winfrey","individuality,inspirational,success"
+"Everyone here has the sense that right now is one of those moments when we are influencing the future.","Steve Jobs","future,moments"
+"I trust that everything happens for a reason, even if we are not wise enough to see it.","Oprah Winfrey","inspirational"
+"Anyone who stops learning is old, whether at twenty or eighty. Anyone who keeps learning stays young.","Henry Ford","education,lifelong-learning"
+"All I can be is me- whoever that is.","Bob Dylan","bob-dylan,inspirational"
+"The Bible has noble poetry in it... and some good morals and a wealth of obscenity, and upwards of a thousand lies.","Mark Twain","agnosticism,atheism,bible,christianity,mythology,truth"
+"Only those who attempt the absurd can achieve the impossible.","Albert Einstein","achievement,inspirational,optimism"
+"Limitless undying love which shines around me like a million suns it calls me on and on across the universe.","John Lennon","beatles,love,sun,universe"
+"The people who make art their business are mostly imposters.","Pablo Picasso","business,mostly"
+"First best is falling in love. Second best is being in love. Least best is falling out of love. But any of it is better than never having been in love.","Maya Angelou","falling-in-love,love,lovelessness"
+"Breathe. Let go. And remind yourself that this very moment is the only one you know you have for sure.","Oprah Winfrey","life"
+"I'm happy to be a writer - of prose, poetry, every kind of writing. Every person in the world who isn't a recluse, hermit or mute uses words. I know of no other art form that we always use.","Maya Angelou","poetry,happy,words"
+"The dog is a gentleman; I hope to go to his heaven not man's.","Mark Twain","animals,dogs,heaven,inspirational,man,religion"
+"Every strike brings me closer to the next home run.","Babe Ruth","baseball,perseverance,philosophy,sports"
+"As my sufferings mounted I soon realized that there were two ways in which I could respond to my situation -- either to react with bitterness or seek to transform the suffering into a creative force. I decided to follow the latter course.","Martin Luther King Jr.","activism,healing,inspirational,justice,sacrifice"
+"Don’t let the noise of others’ opinions drown out your own inner voice."[Stanford University commencement speech, 2005]","Steve Jobs","apple-computer-inc,identity,independence,inner-voice,life,steve-jobs"
+"When we give cheerfully and accept gratefully, everyone is blessed.","Maya Angelou","charity,compassion,gratitude,helping-others,inspiration"
+"Reading, after a certain age, diverts the mind too much from its creative pursuits. Any man who reads too much and uses his own brain too little falls into lazy habits of thinking.","Albert Einstein","reading,science"
+"There are two kinds of teachers: the kind that fill you with so much quail shot that you can't move, and the kind that just gives you a little prod behind and you jump to the skies.","Robert Frost","inspirational,teachers"
+"Men should think twice before making widowhood women's only path to power.","Gloria Steinem","death,feminism,men,murder,widowhood,women,womens-rights"
+"To be a poet is a condition, not a profession.","Robert Frost","afflictions,on-writing,poetry"
+"How many observe Christ's birthday! How few, His precepts!","Benjamin Franklin","christian-behavior,christmas,religion"
+"He is free to evade reality, he is free to unfocus his mind and stumble blindly down any road he pleases, but not free to avoid the abyss he refuses to see.","Ayn Rand","inspirational"
+"Memories of our lives, of our works and our deeds will continue in others.","Rosa Parks","memories,others"
+"Do not worry about your difficulties in Mathematics. I can assure you mine are still greater.","Albert Einstein","inspirational"
+"Life is either a great adventure or nothing.","Helen Keller","great,adventure"
+"Hide not your talents, they for use were made,What's a sundial in the shade?","Benjamin Franklin","talent,wisdom,work"
+"Student: Dr. Einstein, Aren't these the same questions as last year's [physics] final exam?Dr. Einstein: Yes; But this year the answers are different.","Albert Einstein","humor,science"
+"You cannot open a book without learning something.","Confucius","books,learning,philosopher"
+"It takes a very long time to become young.","Pablo Picasso","ignorance,innocence,knowledge,wisdom,youth"
+"Without leaps of imagination or dreaming, we lose the excitement of possibilities. Dreaming, after all is a form of planning.","Gloria Steinem","dreaming,dreams,excitement,imagination,inspirational,planning,possibility"
+"A Woman in harmony with her spirit is like a river flowing.She goes where she will without pretense and arrives at her destination prepared to be herself and only herself","Maya Angelou","inspirational"
+"We can't help everyone, but everyone can help someone.","Ronald Reagan","help"
+"Wisdom is not a product of schooling but of the lifelong attempt to acquire it.","Albert Einstein","education,knowledge-wisdom,learning,school,science,wisdom"
+"Well done is better than well said.","Benjamin Franklin","inspirational"
+"Anyone who says he can see through women is missing a lot.","Groucho Marx","funny,innuendo"
+"What the superior man seeks is in himself; what the small man seeks is in others.","Confucius","individuality,inspiration,validation"
+"Surround yourself only with people who are going to take you higher.","Oprah Winfrey","inspirational"
+"Whoever is happy will make others happy too.","Anne Frank","happy,others,whoever"
+"Sometimes it's not enough to know what things mean, sometimes you have to know what things don't mean.","Bob Dylan","understanding,wisdom"
+"When you see a good person, think of becoming like her/him. When you see someone not so good, reflect on your own weak points.","Confucius","helpful,inspirational,introspection,karma,self-improvement"
+"If we ever forget that we're one nation under God, then we will be one nation gone under.","Ronald Reagan","inspirational,religon,separation-of-church-and-state"
+"Close your eyes and I'll kiss you, Tomorrow I'll miss you.","Paul McCartney","beatles,kiss,love,miss-you,music,song-lyrics,tomorrow"
+"We all live with the objective of being happy; our lives are all different and yet the same.","Anne Frank","happiness,literature"
+"the time is always right to do the right thing","Martin Luther King Jr.","inspirational"
+"Rich people have small TVs and big libraries, and poor people have small libraries and big TVs.","Zig Ziglar","intelligence,success,wealth"
+"Deliver me from writers who say the way they live doesn't matter. I'm not sure a bad person can write a good book. If art doesn't make us better, then what on earth is it for.","Alice Walker","art,bad,good,writing"
+"I've been lucky. Opportunities don't often come along. So, when they do, you have to grab them.","Audrey Hepburn","inspirational"
+"The truth is not for all men but only for those who seek it.","Ayn Rand","truth"
+"God is a concept by which we measure our pain.","John Lennon","beatles,god,religion"
+"How can I go forward when I don't know which way I'm facing?","John Lennon","life"
+"Love is a promise, love is a souvenir, once given never forgotten, never let it disappear.","John Lennon","attributed-no-source,love"
+"Two roads diverged in a wood and I - I took the one less traveled by, and that has made all the difference.","Robert Frost","roads,difference"
+"I'm not afraid of death because I don't believe in it.It's just getting out of one car, and into another.","John Lennon","death,spirituality"
+"If there is any religion that could respond to the needs of modern science, it would be Buddhism.","Albert Einstein","attributed,attributed-to-einstein-no-source,buddhism,religion,science,unsourced"
+"Instead of cursing the darkness, light a candle.","Benjamin Franklin","inspirational,proverb"
+"Freedom is never more than one generation away from extinction. We didn't pass it to our children in the bloodstream. It must be fought for, protected, and handed on for them to do the same, or one day we will spend our sunset years telling our children and our children's children what it was once like in the United States where men were free.","Ronald Reagan","freedom,inspirational,personal-freedom"
+"I am always doing that which I can not do, in order that I may learn how to do it.","Pablo Picasso","inspirational"
+"He who hath many friends hath none.","Aristotle","hath,none"
+"When you encourage others, you in the process are encouraged because you're making a commitment and difference in that person's life. Encouragement really does make a difference.","Zig Ziglar","commitment,process"
+"Few people are capable of expressing with equanimity opinions which differ from the prejudices of their social enviroment. Most people are incapable of forming such opinions."(Essay to Leo Baeck, 1953)","Albert Einstein","disagreement,dissent,equanimity,expressing,knowledge,opinions,prejudices,social,society,thought"
+"If you live each day as it was your last, someday you'll most certainly be right","Steve Jobs","death,life,rip,steve"
+"Happy girls are the prettiest","Audrey Hepburn","attractiveness,beauty,happiness"
+"All great achievements require time.","Maya Angelou","inspirational,motivation"
+"Some painters transform the sun into a yellow spot, others transform a yellow spot into the sun.","Pablo Picasso","sun,yellow,others"
+"I want to thank you, Lord, for life and all that's in it. Thank you for the day and for the hour, and the minute.","Maya Angelou","inspirational"
+"Eat a live frog first thing in the morning and nothing worse will happen to you the rest of the day.","Mark Twain","humor"
+"On some positions, cowardice asks the question, is it expedient? And then expedience comes along and asks the question, is it politic? Vanity asks the question, is it popular? Conscience asks the question, is it right?There comes a time when one must take the position that is neither safe nor politic nor popular, but he must do it because conscience tells him it is right.","Martin Luther King Jr.","truth"
+"I cannot imagine a God who rewards and punishes the objects of his creation, whose purposes are modeled after our own -- a God, in short, who is but a reflection of human frailty. Neither can I believe that the individual survives the death of his body, although feeble souls harbor such thoughts through fear or ridiculous egotisms.","Albert Einstein","god,rational,religion,thinking"
+"Nothing will work unless you do.","Maya Angelou","inspirational"
+"The heart can think of no devotionGreater than being shore to the ocean-Holding the curve of one position,Counting an endless repetition.","Robert Frost","devotion,love,poetry"
+"Just give me a comfortable couch, a dog, a good book, and a woman. Then if you can get the dog to go somewhere and read the book, I might have a little fun.","Groucho Marx","dogs,humor,innuendo,naughty"
+"If all printers were determined not to print anything till they were sure it would offend nobody, there would be very little printed.","Benjamin Franklin","books,censorship,reading"
+"I love the song 'I Hope You Dance' by Lee Ann Womack. I was going to write that song, but someone beat me to it.","Maya Angelou","love,dance,song"
+"The way to know life is to love many things.","Vincent Van Gogh","life"
+"I believe in intuitions and inspirations...I sometimes FEEL that I am right. I do not KNOW that I am.","Albert Einstein","certainty,faith,intuition"
+"Yes We Can!","Barack Obama","action,hope,positivity"
+"I've had a lot of worries in my life, most of which never happened.","Mark Twain","inspirational,positive,worries"
+"Never bend your head. Hold it high. Look the world straight in the eye.","Helen Keller","inspirational"
+"I long to accomplish a great and noble task, but it is my chief duty to accomplish small tasks as if they were great and noble.","Helen Keller","inspirational"
+"Life is more or less a lie, but then again, that's exactly the way we want it to be.","Bob Dylan","dylan,life,zen"
+"The high-minded man must care more for the truth than for what people think.","Aristotle","truth"
+"My religion consists of a humble admiration of the illimitable superior spirit who reveals himself in the slight details we are able to perceive with our frail and feeble mind.","Albert Einstein","god,religion,spirit,spirituality"
+"It is not the failure of others to appreciate your abilities that should trouble you, but rather your failure to appreciate theirs.","Confucius","inspirational"
+"The man of wisdom is never of two minds;the man of benevolence never worries;the man of courage is never afraid.","Confucius","wisdom"
+"Success is the maximum utilization of the ability that you have.","Zig Ziglar","ability,maximum"
+"I've learned that you shouldn't go through life with a catcher's mitt on both hands; you need to be able to throw some things back.","Maya Angelou","wisdom"
+"If at first the idea is not absurd, then there is no hope for it.","Albert Einstein","absurd,absurdity,hope,idea"
+"Love is the only force capable of transforming an enemy to a friend.","Martin Luther King Jr.","love"
+"Simple can be harder than complex: You have to work hard to get your thinking clean to make it simple. But it’s worth it in the end because once you get there, you can move mountains.","Steve Jobs","complex,hard,simple,thinking,truth,wisdom,worth"
+"The way out is through the door. Why is it that no one will use this method?","Confucius","tao,wisdom,zen"
+"Stay hungry. Stay foolish.","Steve Jobs","inspirational"
+"When you do something noble and beautiful and nobody noticed, do not be sad. For the sun every morning is a beautiful spectacle and yet most of the audience still sleeps.","John Lennon","beatles,beauty,life,nature,sadness"
+"I have left orders to be awakened at any time during national emergency, even if I'm in a cabinet meeting.","Ronald Reagan","growing-older,humor,napping,politics"
+"The tragedy of life is what dies inside a man while he lives.","Albert Einstein","inspirational,life"
+"One thing I have learned in a long life: that all our science, measured against reality, is primitive and childlike -- and yet it is the most precious thing we have.","Albert Einstein","science"
+"He not busy being born is busy dying.","Bob Dylan","inspirational,lyrics,music,self-discovery,songs"
+"Earl Nightingale has inspired more people toward success and fortune than any other motivational speaker on the planet.","Zig Ziglar","inspired,planet,fortune"
+"People don’t like to think, if one thinks, one must reach conclusions. Conclusions are not always pleasant.","Helen Keller","life,thinking"
+"Life is a whim of several billion cells to be you for a while","Groucho Marx","humor"
+"The first question which the priest and the Levite asked was: 'If I stop to help this man, what will happen to me?' But...the good Samaritan reversed the question: 'If I do not stop to help this man, what will happen to him?","Martin Luther King Jr.","love,neighbor,sacrifice,service"
+"In all the world, there is no heart for me like yours.In all the world, there is no love for you like mine.","Maya Angelou","love,perfect-fit"
+"Give a bowl of rice to a man and you will feed him for a day. Teach him how to grow his own rice and you will save his life.","Confucius","education,enduring-good,generosity,life,wise-advice,work"
+"The Revolution introduced me to art, and in turn, art introduced me to the Revolution!","Albert Einstein","communism,democracy,freedom,history,hope,individualism,philosophy,politics,revolution,socialism"
+"I have gained this by philosophy … I do without being ordered what some are constrained to do by their fear of the law.","Aristotle","law,morality,philosophy,secular-ethics,secular-morality"
+"Intellectual growth should commence at birth and cease only at death.","Albert Einstein","inspirational,lifelong-learning"
+"The hardest thing of all is to find a black cat in a dark room, especially if there is no cat.","Confucius","futility,knowledge,religion"
+"Only the wisest and stupidest of men never change.","Confucius","wisdom"
+"Part of me suspects that I'm a loser, and the other part of me thinks I'm God Almighty.","John Lennon","ego,god,life,loser"
+"Sometimes life hits you in the head with a brick. Don't lose faith.","Steve Jobs","faith,brick,head"
+"We know from daily life that we exist for other people first of all, for whose smiles and well-being our own happiness depends.","Albert Einstein","friendship,life,relationships"
+"Don't find fault, find a remedy; anybody can complain","Henry Ford","common-sense,inspirational"
+"Your success and happiness lies in you. Resolve to keep happy, and your joy and you shall form an invincible host against difficulties.","Helen Keller","new-year's,happiness"
+"What I'm looking for is not out there, it is in me.","Helen Keller","self,truth"
+"There is no limit to the amount of good you can do if you don't care who gets the credit.","Ronald Reagan","accomplishment,achievement,inspirational,misattributed,modesty,recognition"
+"I was married by a judge. I should have asked for a jury.","Groucho Marx","humor,marriage"
+"Even on the most solemn occasions I got away without wearing socks and hid that lack of civilization in high boots","Albert Einstein","fashion,humor"
+"We dance round in a ring and suppose,But the Secret sits in the middle and knows.","Robert Frost","inspirational"
+"The most beautiful thing we can experience is the mysterious. It is the source of all true art and all science. He to whom this emotion is a stranger, who can no longer pause to wonder and stand rapt in awe, is as good as dead: his eyes are closed.","Albert Einstein","art,awe,einstein,emotion,eyes,life,mysterious,reality,science,the-mysterious,truth,vision"
+"The ideals which have always shone before me and filled me with joy are goodness, beauty, and truth.","Albert Einstein","beauty,ideas,kindness,truth"
+"The arc of the moral universe is long, but it bends towards justice.","Martin Luther King Jr.","inspirational,justice,mlk"
+"If I cannot do great things, I can do small things in a great way","Martin Luther King Jr.","excellence,success"
+"You don't need anybody to tell you who you are or what you are. You are what you are!","John Lennon","be-yourself,inspirational,self-awareness,self-determination"
+"The word 'God' is for me nothing more than the expression and product of human weaknesses, the Bible a collection of honorable, but still primitive legends which are nevertheless pretty childish. No interpretation, no matter how subtle, can (for me) change this.","Albert Einstein","bible,god,religion"
+"You can't connect the dots looking forward; you can only connect them looking backwards. So you have to trust that the dots will somehow connect in your future.","Steve Jobs","design,inspirational,life-lessons"
+"God is subtle but he is not malicious.","Albert Einstein","inspirational"
+"To write well, express yourself like the common people, but think like a wise man.","Aristotle","inspirational,philosophy,writing"
+"An individual has not started living until he can rise above the narrow confines of his individualistic concerns to the broader concerns of all humanity.","Martin Luther King Jr.","inspirational"
+"The person who deserves most pity is a lonesome one on a rainy day who doesn't know how to read.","Benjamin Franklin","books,illiteracy,literature,pity,reading,words"
+"No, this trick won't work... How on earth are you ever going to explain in terms of chemistry and physics so important a biological phenomenon as first love?","Albert Einstein","chemistry,first-love,love,physics"
+"Homer has taught all other poets the art of telling lies skillfully.","Aristotle","homer,poets,lies"
+"Let us live so that when we come to die even the undertaker will be sorry.","Mark Twain","inspirational"
+"Next time I see you, remind me not to talk to you.","Groucho Marx","gibe,humor,insult"
+"What is Man? Man is a noisome bacillus whom Our Heavenly Father created because he was disappointed in the monkey.","Mark Twain","creation,evolution,humor,mankind"
+"Information is not knowledge.","Albert Einstein","information,knowledge"
+"Literature is my Utopia","Helen Keller","books,literature,reading,words"
+"I have looked in the mirror every morning and asked myself: "If today were the last day of my life, would I want to do what I am about to do today?"And whenever the answer has been "No"for too many days in a row, I know I need to change something.","Steve Jobs","change,life"
+"We could never learn to be brave and patient if there were only joy in the world","Helen Keller","adversity,inspirational,personal-growth"
+"Challenges are gifts that force us to search for a new center of gravity. Don't fight them. Just find a new way to stand.","Oprah Winfrey","philosophy"
+"In the unlikely story that is America, there has never been anything false about hope.","Barack Obama","america,history,hope"
+"Possessions, outward success, publicity, luxury - to me these have always been contemptible. I believe that a simple and unassuming manner of life is best for everyone, best for both the body and the mind.","Albert Einstein","belongings,simplicity,success,values"
+"I believe that every single event in life happens in an opportunity to choose love over fear.","Oprah Winfrey","fear,love,opportunity"
+"I'm not the smartest fellow in the world, but I can sure pick smart colleagues.","Franklin D. Roosevelt","funny,humor,politics,usa"
+"Writing is the only thing that when I do it, I don't feel I should be doing something else.","Gloria Steinem","writing"
+"Forget injuries, never forget kindnesses.","Confucius","life,principles"
+"Happiness does not come from without, it comes from within","Helen Keller","happiness,life,love"
+"A bend in the road is not the end of the road…Unless you fail to make the turn.","Helen Keller","change,life,perseverance,risk"
+"Dancers are the athletes of God.","Albert Einstein","albert,life"
+"You can never be wise and be in love at the same time.","Bob Dylan","bob-dylan,love"
+"Room service? Send up a larger room."[A Night at the Opera]","Groucho Marx","hotel-rooms,hotels,humor,room-service"
+"Under certain circumstances, profanity provides a relief denied even to prayer."[Mark Twain, a Biography]","Mark Twain","humor,prayer,profanity,relief,you-ll-completely-understand-why"
+"Wit is educated insolence.","Aristotle","definitions,humor"
+"Life isn't worth living, unless it is lived for someone else.","Albert Einstein","einstein,life"
+"Everything is determined, the beginning as well as the end, by forces over which we have no control. It is determined for the insect, as well as for the star. Human beings, vegetables, or cosmic dust, we all dance to a mysterious tune, intoned in the distance by an invisible piper.","Albert Einstein","destiny,einstein,inspirational"
+"Early to bed and early to rise makes a man healthy, wealthy, and wise.","Benjamin Franklin","inspirational"
+"It is, in fact, nothing short of a miracle that the modern methods of instruction have not yet entirely strangled the holy curiosity of inquiry; for this delicate little plant, aside from stimulation, stands mainly in need of freedom. Without this it goes to wrack and ruin without fail.","Albert Einstein","creativity,education,learning,regimentation"
+"Everything has its wonders, even darkness and silence, and I learn, whatever state I may be in, therein to be content","Helen Keller","life"
+"I want to do it because I want to do it. Women must try to do things as men have tried. When they fail, their failure must be but a challenge to others.","Amelia Earhart","failure,success,women,work"
+"I count him braver who overcomes his desires than him who overcomes his enemies.","Aristotle","ethics,philosophy,self-discovery"
+"The reports of my death are greatly exaggerated.","Mark Twain","death,humor"
+"Let us not seek to satisfy our thirst for freedom by drinking from the cup of bitterness and hatred.","Martin Luther King Jr.","communism,democracy,freedom,liberation,love,marxism,peace,radicalism,socialism,theology"
+"A successful book is not made of what is in it, but what is left out of it.","Mark Twain","books,humor,on-writing,wit,writing"
+"We ran as if to meet the moon.","Robert Frost","moon,poetry,robert-frost"
+"We all know that Art is not truth. Art is a lie that makes us realize truth at least the truth that is given us to understand. The artist must know the manner whereby to convince others of the truthfulness of his lies.","Pablo Picasso","art,lies,truth"
+"When I was younger, I could remember anything, whether it had happened or not; but my faculties are decaying now and soon I shall be so I cannot remember any but the things that never happened. It is sad to go to pieces like this but we all have to do it.","Mark Twain","aging,humor"
+"I'm inspired by the people I meet in my travels--hearing their stories, seeing the hardships they overcome, their fundamental optimism and decency. I'm inspired by the love people have for their children. And I'm inspired by my own children, how full they make my heart. They make me want to work to make the world a little bit better. And they make me want to be a better man.","Barack Obama","family,hope,service"
+"You must expect great things of yourself before you can do them.","Michael Jordan","inspirational,success"
+"Many persons have a wrong idea of what constitutes true happiness. It is not attained through self-gratification but through fidelity to a worthy purpose.","Helen Keller","educator,inspirational"
+"The way a crowShook down on meThe dust of snowFrom a hemlock treeHas given my heartA change of moodAnd saved some partOf a day I had rued.","Robert Frost","poetry"
+"God is really only another artist. He invented the giraffe, the elephant and the cat. He has no real style, He just goes on trying other things.","Pablo Picasso","art,god"
+"The thing the sixties did was to show us the possibilities and the responsibility that we all had. It wasn't the answer. It just gave us a glimpse of the possibility.","John Lennon","1960s,beatles,hope,possibility,responsibility"
+"And were an epitaph to be my story I'd have a short one ready for my own. I would have written of me on my stone: I had a lover's quarrel with the world.","Robert Frost","life"
+"When obstacles arise, you change your direction to reach your goal; you do not change your decision to get there.","Zig Ziglar","inspirational"
+"Training is everything. The peach was once a bitter almond; cauliflower is nothing but cabbage with a college education.","Mark Twain","education,food"
+"Love is like a virus. It can happen to anybody at any time.","Maya Angelou","love"
+"Vision without execution is just hallucination.","Henry Ford","dreams,success"
+"My life isn’t theories and formulae. It’s part instinct, part common sense. Logic is as good a word as any, and I’ve absorbed what logic I have from everything and everyone… from my mother, from training as a ballet dancer, from Vogue magazine, from the laws of life and health and nature.","Audrey Hepburn","audrey-hepburn,inspiration,life"
+"Any customer can have a car painted any colour that he wants so long as it is black.","Henry Ford","black,customer,humor,model-t"
+"Play is the highest form of research.","Albert Einstein","childhood,education"
+"We can't become what we need to be by remaining what we are.","Oprah Winfrey","life"
+"It is by the goodness of god that in our country we have those 3 unspeakably precious things: freedom of speech, freedom of conscience, and the prudence never to practice either of them.","Mark Twain","humor,politics"
+"To those who are given much, much is expected.","Maya Angelou","inspirational-quotes"
+"Books can not be killed by fire. People die, but books never die. No man and no force can abolish memory... In this war, we know, books are weapons. And it is a part of your dedication always to make them weapons for man's freedom.","Franklin D. Roosevelt","book-burning,books,censorship,freedom"
+"Relationships are like Rome -- difficult to start out, incredible during the prosperity of the 'golden age', and unbearable during the fall. Then, a new kingdom will come along and the whole process will repeat itself until you come across a kingdom like Egypt... that thrives, and continues to flourish. This kingdom will become your best friend, your soul mate, and your love.","Helen Keller","love,relationship"
+"Our society is run by insane people for insane objectives","John Lennon","truth"
+"I know in my heart that man is good, that what is right will always eventually triumph, and there is purpose and worth to each and every life.","Ronald Reagan","inspirational"
+"Before I speak, I have something important to say.","Groucho Marx","absurdist,humor"
+"If you lose hope, somehow you lose the vitality that keeps moving, you lose that courage to be, that quality that helps you go on in spite of it all. And so today I still have a dream.","Martin Luther King Jr.","hope"
+"Time flows away like the water in the river.","Confucius","wisdom"
+"Self-esteem comes from being able to define the world in your own terms and refusing to abide by the judgments of others.","Oprah Winfrey","inspirational"
+"An empty stomach is not a good political adviser.","Albert Einstein","humor,hunger,poverty"
+"A foolish faith in authority is the worst enemy of truth.","Albert Einstein","dissent,independent-thought,science"
+"My life has been one great big joke,A dance that's walked,A song that's spoke,I laugh so hard I almost choke,When I think about myself.","Maya Angelou","life"
+"When red-headed people are above a certain social grade their hair is auburn.","Mark Twain","class,elitism,humor,redheads"
+"A poem begins with a lump in the throat; a homesickness or a love sickness. It is a reaching-out toward expression; an effort to find fulfillment. A complete poem is one where an emotion has found its thought and the thought has found words.","Robert Frost","poetry,writing"
+"Education breeds confidence. Confidence breeds hope. Hope breeds peace.","Confucius","education"
+"Poetry puts starch in your backbone so you can stand, so you can compose your life.","Maya Angelou","poetry"
+"It frightens me, the awful truth, of how sweet life can be...","Bob Dylan","fear,life,truth"
+"Have you ever felt the longing for someone you could admire? For something, not to look down at, but up to?","Ayn Rand","achievement,admiration,atlas-shrugged,inspirational,love,objectivism"
+"Politics is not a bad profession. If you succeed there are many rewards, if you disgrace yourself you can always write a book.","Ronald Reagan","humor,politics"
+"Shall I teach you what knowledge?When you know a thing, say that you know it;when you do not know a thing,admit that you do not know it.That is knowledge","Confucius","knowledge"
+"My best friend is the man who in wishing me well wishes it for my sake.","Aristotle","best,friend,wishes"
+"Make today worth remembering.","Zig Ziglar","inspirational,motivational"
+"I've heard that hard work never killed anyone, but I say why take the chance?","Ronald Reagan","humor,laziness,sloth,work"
+"I was feeling insecure you might not love me anymore","John Lennon","insecure,insecurity,love"
+"Democracy cannot succeed unless those who express their choice are prepared to choose wisely. The real safeguard of democracy, therefore, is education.","Franklin D. Roosevelt","education,government,political-philosophy,public-duty,voting"
+"Life is very short, and there's no time for fussing and fighting my friends","John Lennon","inspirational"
+"Happiness is not in the mere possession of money; it lies in the joy of achievement, in the thrill of creative effort.","Franklin D. Roosevelt","achievement,happiness,wealth,wisdom"
+"Doing the best at this moment puts you in the best place for the mext moment","Oprah Winfrey","inspirational,life,success"
+"The lack of money is the root of all evil.","Mark Twain","humor"
+"The human spirit must prevail over technology.","Albert Einstein","humanity,science"
+"Status quo, you know, is Latin for 'the mess we're in'.","Ronald Reagan","inspirational,latin,politics"
+"If we bear all this suffering and if there are still Jews left, when it is over, then Jews, instead of being doomed, will be held up as an example.","Anne Frank","holocaust,inspirational,judaism"
+"Teaching should be such that what is offered is perceived as a valuable gift and not as hard duty. Never regard study as duty but as the enviable opportunity to learn to know the liberating influence of beauty in the realm of the spirit for your own personal joy and to the profit of the community to which your later work belongs.","Albert Einstein","education"
+"We'll meet at the theater tonight. I'll hold your seat 'til you get there. Once you get there; you're on your own.","Groucho Marx","humor"
+"It is harder to crack prejudice than an atom.","Albert Einstein","humor,inspirational,science"
+"I can accept anything, except what seems to be the easiest for most people: the half-way, the almost, the just-about, the in-between.","Ayn Rand","compromise,philosophy"
+"A hospital bed is a parked taxi with the meter running.","Groucho Marx","funny"
+"The best and most beautiful things in the world cannot be seen or even touched - they must be felt with the heart.","Helen Keller","best,beautiful,heart"
+"No amount of experimentation can ever prove me right; a single experiment can prove me wrong.","Albert Einstein","science"
+"I don't try to imagine a personal God; it suffices to stand in awe at the structure of the world, insofar as it allows our inadequate senses to appreciate it.","Albert Einstein","atheism,atheist,god,religion"
+"Happiness is a state of activity.","Aristotle","activity,happiness"
+"Although I am a typical loner in my daily life, my awareness of belonging to the invisible community of those who strive for truth, beauty, and justice has prevented me from feelings of isolation.","Albert Einstein","albert-einstein,einstein,inspirational,loner"
+"We may have all come on different ships, but we're in the same boat now.","Martin Luther King Jr.","cultural,inspirational,spiritual"
+"I believe that God is in me as the sun is in the colour and fragrance of a flower - the Light in my darkness, the Voice in my silence.","Helen Keller","inspirational"
+"You see, wire telegraph is a kind of a very, very long cat. You pull his tail in New York and his head is meowing in Los Angeles. Do you understand this? And radio operates exactly the same way: you send signals here, they receive them there. The only difference is that there is no cat.","Albert Einstein","analogy,humor,science"
+"Familiarity breeds contempt and children.","Mark Twain","humor"
+"Learning is an ornament in prosperity, a refuge in adversity, and a provision in old age.","Aristotle","adversity,education,learning,old-age,prosperity"
+"A lot of people have gone further than they thought they could because someone else thought they could","Zig Ziglar","inspirational"
+"Life is a succesion of lessons which must be lived to be understood.","Helen Keller","lessons,life"
+"There are no traffic jams on the extra mile.","Zig Ziglar","inspirational"
+"You're gonna have to serve somebody; well, it may be the devil, or it may be the Lord, but you're gonna have to serve somebody...","Bob Dylan","christianity,faith,god"
+"Small is the number of them that see with their own eyes and feel with their own hearts.","Albert Einstein","heart,inspirational"
+"Act the way you'd like to be and soon you'll be the way you'd like to act.","Bob Dylan","action,change,improvement,misattributed-to-leonard-cohen,motivational,success"
+"It may be true that the law cannot make a man love me, but it can stop him from lynching me, and I think that's pretty important.","Martin Luther King Jr.","law,life,lynchings"
+"Happiness depends more on the inward disposition of mind than on outward circumstances.","Benjamin Franklin","inspirational"
+"A big leather-bound volume makes an ideal razorstrap. A thing book is useful to stick under a table with a broken caster to steady it. A large, flat atlas can be used to cover a window with a broken pane. And a thick, old-fashioned heavy book with a clasp is the finest thing in the world to throw at a noisy cat.","Mark Twain","books,humor"
+"No man's life, liberty, or property are safe while the legislature is in session.","Mark Twain","government,humor,politics"
+"Don't say the old lady screamed. Bring her on and let her scream.","Mark Twain","on-writing,writing"
+"Until justice rolls down like water and righteousness like a mighty stream.","Martin Luther King Jr.","america,freedom,human-rights,inspirational,justice,peace,pride,righteousness,stream,water"
+"Four things to learn in life: To think clearly without hurry or confusion; To love everybody sincerely; To act in everything with the highest motives; To trust God unhesitatingly.","Helen Keller","inspirational"
+"Strange is our situation here on Earth. Each of us comes for a short visit, not knowing why, yet sometimes seeming to divine a purpose. From the standpoint of daily life, however, there is one thing we do know: that man is here for the sake of other men - above all for those upon whose smiles and well-being our own happiness depends.","Albert Einstein","inspirational-quotes"
+"Everything that is really great and inspiring is created by the individual who can labor in freedom.","Albert Einstein","mind"
+"Courage is the price that life exacts for granting peace.","Amelia Earhart","bravery,courage,life,peace"
+"If a man could have half of his wishes, he would double his troubles.","Benjamin Franklin","wisdom"
+"In religion and politics people’s beliefs and convictions are in almost every case gotten at second-hand, and without examination, from authorities who have not themselves examined the questions at issue but have taken them at second-hand from other non-examiners, whose opinions about them were not worth a brass farthing.","Mark Twain","beliefs,politics,religion"
+"What I’ve realized is that life doesn’t count for much unless you’re willing to do your small part to leave our children — all of our children — a better world. Any fool can have a child. That doesn’t make you a father. It’s the courage to raise a child that makes you a father.","Barack Obama","inspirational"
+"A friend to all is a friend to none.","Aristotle","friend,none"
+"It usually takes me two or three days to prepare an impromptu speech.","Mark Twain","humor,preparedness"
+"I define nothing. Not beauty, not patriotism. I take each thing as it is, without prior rules about what it should be.","Bob Dylan","acceptance,bob,define,dylan,life"
+"It does not matter how long you live, but how well you do it.","Martin Luther King Jr.","inspirational"
+"It occurred to me by intuition, and music was the driving force behind that intuition. My discovery was the result of musical perception.","Albert Einstein","inspirational"
+"You look at yourself and you accept yourself for who you are, and once you accept yourself for who you are you become a better person.","Oprah Winfrey","inspirational"
+"Lots of people want to ride with you in the limo, but what you want is someone who will take the bus with you when the limo breaks down.","Oprah Winfrey","ride,bus,breaks"
+"Who is wise? He that learns from everyone. Who is powerful? He that governs his passions. Who is rich? He that is content. Who is that? Nobody.","Benjamin Franklin","philosophy,wisdom"
+"Paying alimony is like feeding hay to a dead horse.","Groucho Marx","divorce,funny"
+"Occasionally in life there are those moments of unutterable fulfillment which cannot be completely explained by those symbols called words. Their meanings can only be articulated by the inaudible language of the heart.","Martin Luther King Jr.","ecstasy,euphoria,fulfillment,life,power-of-words"
+"Learning without thought is labor lost; thought without learning is perilous.","Confucius","education,learning,thinking"
+"I believe that Gandhi’s views were the most enlightened of all the political men in our time. We should strive to do things in his spirit: not to use violence in fighting for our cause, but by non-participation in anything you believe is evil.","Albert Einstein","causes,corporations,gandhi,truth,violence"
+"The game of basketball has been everything to me. My place of refuge, place I've always gone where I needed comfort and peace. It's been the site of intense pain and the most intense feelings of joy and satisfaction. It's a relationship that has evolved over time, given me the greatest respect and love for the game.","Michael Jordan","sports,time,respect"
+"I hate girls that giggle all the time... You hate any girl that David looks at.","Audrey Hepburn","humor"
+"I believe in pink. I believe that laughing is the best calorie burner. I believe in kissing, kissing a lot. I believe in being strong when everything seems to be going wrong. I believe that happy girls are the prettiest girls. I believe that tomorrow is another day and I believe in miracles.","Audrey Hepburn","best,kissing,happy"
+"You say I started out with practically nothing, but that isn't correct. We all start with all there is, it's how we use it that makes things possible.","Henry Ford","inspiration"
+"Anyone who doesn't take truth seriously in small matters cannot be trusted in large ones either.","Albert Einstein","albert-einstein,truth"
+"I wasn't saying whatever they're saying I was saying. I'm sorry I said it really. I never meant it to be a lousy anti-religious thing. I apologize if that will make you happy. I still don't know quite what I've done. I've tried to tell you what I did do but if you want me to apologize, if that will make you happy, then OK, I'm sorry.","John Lennon","apology,beatles,humor,humour,jesus,religion"
+"Success is the doing, not the getting; in the trying, not the triumph. Success is a personal standard, reaching for the highest that is in us, becoming all that we can be. If we do our best, we are a success.","Zig Ziglar","doing,success"
+"I have a great respect for incremental improvement, and I've done that sort of thing in my life, but I've always been attracted to the more revolutionary changes. I don't know why. Because they're harder. They're much more stressful emotionally. And you usually go through a period where everybody tells you that you've completely failed.","Steve Jobs","respect,great,changes"
+"A bank is a place where they lend you an umbrella in fair weather and ask for it back when it begins to rain.","Robert Frost","humor,poetry"
+"A society's competitive advantage will come not from how well its schools teach the multiplication and periodic tables, but from how well they stimulate imagination and creativity.","Albert Einstein","science"
+"There are only a few notes. Just variations on a theme.","John Lennon","life,music"
+"A man is accepted into a church for what he believes and he is turned out for what he knows.","Mark Twain","religion"
+"It is this belief in a power larger than myself and other than myself which allows me to venture into the unknown and even the unknowable.","Maya Angelou","faith,inspirational"
+"A man is never more truthful than when he acknowledges himself a liar.","Mark Twain","truth"
+"What a wee little part of a person's life are his acts and his words! His real life is led in his head, and is known to none but himself.","Mark Twain","words,head,himself"
+"Your success and happiness lie in you.","Helen Keller","happiness,inspirational-quotes,success"
+"Ah, when to the heart of man Was it ever less than a treason To go with the drift of things, To yield with a grace to reason, And bow and accept the end Of a love or a season?","Robert Frost","love,poetry"
+"Never allow the fear of striking out keep you from playing the game!","Babe Ruth","babe-ruth,baseball,cinderella-story,inspiration,motivation,quote,success"
+"The whole secret of a successful life is to find out what is one's destiny to do, and then do it.","Henry Ford","success"
+"The future doesn't belong to the light-hearted. It belongs to the brave.","Ronald Reagan","bravery,inspirational,reagan"
+"An ounce of prevention is worth a pound of cure.","Benjamin Franklin","preparation,prevention,proverb,wisdom"
+"Wishing to be friends is quick work, but friendship is a slow ripening fruit.","Aristotle","work,fruit,slow"
+"One of the strongest motives that lead men to art and science is escape from everyday life with its painful crudity and hopeless dreariness, from the fetters of one's own ever-shifting desires. A finely tempered nature longs to escape from the personal life into the world of objective perception and thought.","Albert Einstein","art,life,science"
+"Making a decision to write was a lot like deciding to jump into a frozen lake.","Maya Angelou","writing"
+"America is too great for small dreams.","Ronald Reagan","inspirational"
+"What I try to do is write. I may write for two weeks ‘the cat sat on the mat, that is that, not a rat,’.... And it might be just the most boring and awful stuff. But I try. When I’m writing, I write. And then it’s as if the muse is convinced that I’m serious and says, ‘Okay. Okay. I’ll come.","Maya Angelou","writing"
+"And the only way to do great work is to love what you do.... Don't settle","Steve Jobs","inspirational"
+"The Master said, “A true teacher is one who, keeping the past alive, is also able to understand the present.”(Analects 2.11)","Confucius","history,teachers,wisdom"
+"I do not want the peace which passeth understanding, I want the understanding which bringeth peace.","Helen Keller","education,ispirational,learning,understanding"
+"If books are not good company, where shall I find it?","Mark Twain","books"
+"Remembering that you are going to die is the best way I know to avoid the trap of thinking you have something to lose.","Steve Jobs","death,hope,inspirational,life,motivatonal"
+"I failed to communicate, that's why I chose to leave","Bob Dylan","life"
+"What affects one in a major way, affects all in a minor way.","Martin Luther King Jr.","inspirational"
+"Poetry is a way of taking life by the throat.","Robert Frost","life,poetry"
+"…Christianity will go. It will vanish and shrink. I don't know what will go first, rock 'n' roll or Christianity. We're more popular than Jesus now. Jesus was all right, but his disciples were thick and ordinary. It's them twisting it that ruins it for me.","John Lennon","beatles,christianity,popular-culture,religion"
+"Great spirits have always encountered opposition from mediocre minds. The mediocre mind is incapable of understanding the man who refuses to bow blindly to conventional prejudices and chooses instead to express his opinions courageously and honestly.","Albert Einstein","inspirational,opposition,wisdom"
+"You better start swimming, or you'll sink like a stone. Because the Time's they are a-changing.","Bob Dylan","life,music"
+"Mr. Right is coming, but he's in Africa and he's walking.","Oprah Winfrey","funny"
+"That's what you want to do? Then nothing beats a trial but a failure. Give it everything you've got. I've told you many times, 'Cant do is like Dont Care.' Neither of them have a home.","Maya Angelou","inspirational"
+"We are faced with the fact, my friends, that tomorrow is today. Procrastination is still the thief of time. Over the bleached bones and jumbled residues of numerous civilizations are written the pathetic words ‘Too Late’.","Martin Luther King Jr.","inspirational,political"
+"I want all my senses engaged. Let me absorb the world's variety and uniqueness.","Maya Angelou","inspirational"
+"Education: that which reveals to the wise, and conceals from the stupid, the vast limits of their knowledge.","Mark Twain","education"
+"It is more shameful to distrust our friends than to be deceived by them.","Confucius","deceived,distrust,shameful"
+"Don't be distracted by criticism. Remember ~ the only taste of success some people have is when they take a bite out of you.","Zig Ziglar","believe,inspiration,motivational,zig-ziglar"
+"Freedom means the supremacy of human rights everywhere. Our support goes to those who struggle to gain those rights and keep them. Our strength is our unity of purpose. To that high concept there can be no end save victory.","Franklin D. Roosevelt","human-rights,truth"
+"Poetry is finer and more philosophical than history; for poetry expresses the universal, and history only the particular.","Aristotle","poetry"
+"No lake so still but it has its wave.No circle so perfect but that it has its blur.I would change things for you if I could; As I can't you must take them as they are.","Confucius","inspirational,life,philosophy"
+"Like anybody, I would like to have a long life. Longevity has its place. But I'm not concerned about that now. I just want to do God's will.","Martin Luther King Jr.","foreboding,life"
+"Rich People plan for three generationsPoor people plan for Saturday night","Gloria Steinem","class-distinction,inspirational"
+"Never contract friendship with a man that is not better than thyself.","Confucius","contract,thyself"
+"Each morning when I open my eyes I say to myself: I, not events, have the power to make me happy or unhappy today.","Groucho Marx","happiness,inspirational"
+"The significant problems we have cannot be solved at the same level of thinking with which we created them.","Albert Einstein","inspirational,problems,science"
+"I am overwhelmed by the grace and persistence of my people.","Maya Angelou","family,inspirational"
+"To plant a garden is to believe in tomorrow.","Audrey Hepburn","hope,inspirational"
+"youth is easily deceived because it is quick to hope.","Aristotle","deceit,gullibility,hope,wisdom,youth"
+"As our circle of knowledge expands, so does the circumference of darkness surrounding it.","Albert Einstein","knowledge"
+"It doesn't matter who you are, where you come from. The ability to triumph begins with you - always.","Oprah Winfrey","inspirational"
+"Knowledge is merely brilliance in organization of ideas and not wisdom. The truly wise person goes beyond knowledge.","Confucius","wisdom"
+"In the view of such harmony in the cosmos which I, with my limited human mind, am able to recognize, there are yet people who says there is no God. But what makes me really angry is that they quote me for support of such views. (The Expanded Quotable Einstein, Princeton University, page 214)","Albert Einstein","creation,god"
+"The Truth is found when men (and Women) are free to pursue it.","Franklin D. Roosevelt","freedom,liberty,truth"
+"Don't be trapped by dogma — which is living with the results of other people's thinking.","Steve Jobs","life,thinking"
+"When You Cease To Exist, Then Who Will You Blame?","Bob Dylan","inspirational"
+"A man's ethical behaviour should be based effectually on sympathy, education, and social ties and needs; no religious basis is necessary. Man would indeed be in a poor way if he had to be restrained by fear of punishment and hope of reward after death.","Albert Einstein","education,ethics,morality,needs,religion,sociality,sympathy"
+"Segregation shaped me; education liberated me.","Maya Angelou","education,inspirational,learning,race"
+"The gods too are fond of a joke.","Aristotle","god,humor,jokes,religion"
+"A war of ideas can no more be won without books than a naval war can be won without ships. Books, like ships, have the toughest armor, the longest cruising range, and mount the most powerful guns.","Franklin D. Roosevelt","boats,books,ideas,sailing,ships"
+"Take one cup of love, two cups of loyalty, three cups of forgiveness, four quarts of faith and one barrel of laughter. Take love and loyalty and mix them thoroughly with faith; blend with tenderness, kindness and understanding. Add friendship and hope. Sprinkle abundantly with laughter. Bake it with sunshine. Wrap it regularly with lots of hugs. Serve generous helpings daily.","Zig Ziglar","happiness,marriage"
+"If I could give you information of my life it would be to show how a woman of very ordinary ability has been led by God in strange and unaccustomed paths to do in His service what He has done in her. And if I could tell you all, you would see how God has done all, and I nothing. I have worked hard, very hard, that is all; and I have never refused God anything.","Florence Nightingale","god,service,work"
+"Life is about becoming more of who you really are....","Oprah Winfrey","inspirational"
+"If God would have wanted us to live in a permissive society He would have given us Ten Suggestions and not Ten Commandments.","Zig Ziglar","religion"
+"Go as far as you can see and you will see further.","Zig Ziglar","inspirational,motivation,success"
+"Without continual growth and progress, such words as improvement, achievement, and success have no meaning.","Benjamin Franklin","growth,progress,words"
+"To avoid being mistaken for a sellout, I chose my friends carefully. The more politically active black students. The foreign students. The Chicanos. The Marxist professors and structural feminists and punk-rock performance poets.","Barack Obama","black,students,active"
+"Anyone who fights for the future, lives in it today.","Ayn Rand","idealism,philosophy"
+"My philosophy, in essence, is the concept of man as a heroic being, with his own happiness as the moral purpose of his life, with productive achievement as his noblest activity, and reason as his only absolute.","Ayn Rand","philosophy"
+"A tyrant must put on the appearance of uncommon devotion to religion. Subjects are less apprehensive of illegal treatment from a ruler whom they consider god-fearing and pious. On the other hand, they do less easily move against him, believing that he has the gods on his side.","Aristotle","morality,politics,religion"
+"Curiosity is more important than knowledge.","Albert Einstein","curiosity,knowledge"
+"I said to my children, 'I'm going to work and do everything that I can do to see that you get a good education. I don't ever want you to forget that there are millions of God's children who will not and cannot get a good education, and I don't want you feeling that you are better than they are. For you will never be what you ought to be until they are what they ought to be.","Martin Luther King Jr.","altruism,education,potential,religion"
+"God made a beauteous garden With lovely flowers strown,But one straight, narrow pathway That was not overgrown.And to this beauteous garden He brought mankind to live,And said "To you, my children, These lovely flowers I give.Prune ye my vines and fig trees, With care my flowers tend,But keep the pathway open Your home is at the end."God's Garden","Robert Frost","frost,gardens,god"
+"Herodotus says, "Very few things happen at the right time, and the rest do not happen at all: the conscientious historian will correct these defects.","Mark Twain","creativity,historians,history,truth"
+"You will find the key to success under the alarm clock.","Benjamin Franklin","success"
+"Character cannot be developed in ease and quiet. Only through experience of trial and suffering can the soul be strengthened, ambition inspired, and success achieved.","Helen Keller","strength,experience"
+"The happiness you feel is in direct proportion to the love you give.","Oprah Winfrey","happiness,life,love"
+"If one tries to navigate unknown waters one runs the risk of shipwreck","Albert Einstein","wisdom"
+"You teach people how to treat you.","Oprah Winfrey","inspirational,oprah"
+"Nothing exists but you. And you are but a thought.","Mark Twain","atheism,inspirational"
+"It's sad if people think that's (homemaking) a dull existance, [but] you can't just buy an apartment and furnish it and walk away. It's the flowers you choose, the music you play, the smile you have waiting. I want it to be gay and cheerful, a haven in this troubled world. I don't want my husband and children to come home and find a rattled woman. Our era is already rattled enough, isn't it?","Audrey Hepburn","homemaking,inspirational,motherhood"
+"They say that patriotism is the last refuge to which a scoundrel clings steal a little and they throw you in jail. Steal a lot and then they make you king.","Bob Dylan","patriotism,scoundrels,truth,wisdom"
+"The test of any good fiction is that you should care something for the characters; the good to succeed, the bad to fail. The trouble with most fiction is that you want them all to land in hell together, as quickly as possible.","Mark Twain","writing"
+"Wit is the sudden marriage of ideas which before their union were not perceived to have any relation.","Mark Twain","cleverness,writing"
+"Learn as if you were not reaching your goal and as though you were scared of missing it","Confucius","confucious,inspirational,learning,life"
+"Walking with a friend in the dark is better than walking alone in the light.","Helen Keller","alone,dark,light"
+"For dear me, why abandon a beliefMerely because it ceases to be true","Robert Frost","faith,truth"
+"The way to wealth is as plain as the way to market. It depends chiefly on two words, industry and frugality: that is, waste neither time nor money, but make the best use of both. Without industry and frugality nothing will do, and with them everything.","Benjamin Franklin","advice-for-daily-living,enterprise,frugality,success"
+"Without feelings of respect, what is there to distinguish men from beasts?","Confucius","philosophical,understanding,wisdom"
+"One should never use exclamation points in writing. It is like laughing at your own joke.","Mark Twain","advice,clever,exclamation-point,writing"
+"Combinatory play seems to be the essential feature in productive thought.","Albert Einstein","education,learning,play"
+"Every form of happiness if one, every desire is driven by the same motor--by our love for a single value, for the highest potentiality of our own existence--and every achievement is an expression of it.","Ayn Rand","galt,objectivism,philosophy,taggart"
+"Economic power is exercised by means of a positive, by offering men a reward, an incentive, a payment, a value; political power is exercised by means of a negative, by the threat of punishment, injury, imprisonment, destruction. The businessman's tool is values; the bureaucrat's tool is fear.","Ayn Rand","businessmen,capitalism,force,government,money,philosophy,profit"
+"That which is impenetrable to us really exists. Behind the secrets of nature remains something subtle, intangible, and inexplicable. Veneration for this force beyond anything that we can comprehend is my religion.","Albert Einstein","religion"
+"he who will not economize will have to agonize","Confucius","frugality,ignorance,knowledge,suffering,wisdom"
+"Art is not the application of a canon of beauty but what the instinct and the brain can conceive beyond any canon. When we love a woman we don't start measuring her limbs.","Pablo Picasso","love,beauty,woman"
+"The best way to see Faith is to shut the eye of Reason.","Benjamin Franklin","wisdom"
+"To do more for the world than the world does for you - that is success.","Henry Ford","success"
+"It makes no difference where you go, there you are. And it makes no difference what you have, there’s always more to want. Until you are happy with who you are, you will never be happy because of what you have.","Zig Ziglar","grateful,happiness"
+"The right to search for the truth implies also a duty; one must not conceal any part of what one has recognized to be the truth.","Albert Einstein","truth"
+"When you have faults, do not fear to abandon them.","Confucius","advice,life,success"
+"I find relief from the questions only when I concede that I am not obliged to know everything. I remind myself it is sufficient to know what I know, and that what I know, may not always be true.","Maya Angelou","death,letter-to-my-daughter"
+"I confess to wincing every so often at a poorly chosen word, a mangled sentence, an expression of emotion that seems indulgent or overly practiced. I have the urge to cut the book by fifty pages or so, possessed as I am with a keener appreciation for brevity.","Barack Obama","writing"
+"He who speaks without modesty will find it difficult to make his words good.","Confucius","inspirational-quotes"
+"An attempt to achieve the good by force is like an attempt to provide a man with a picture gallery at the price of cutting out his eyes.","Ayn Rand","force,good,philosophy"
+"Listen. Pay attention. Treasure every moment.","Oprah Winfrey","wisdom"
+"It is a very grave mistake to think that the enjoyment of seeing and searching can be promoted by means of coercion and a sense of duty. To the contrary, I believe it would be possible to rob even a healthy beast of prey of its voraciousness, if it were possible, with the aid of a whip, to force the beast to devour continuously, even when not hungry.","Albert Einstein","education,learning"
+"Deux choses sont infinies : l’Univers et la bêtise humaine. Mais, en ce qui concerne l’Univers, je n’en ai pas encore acquis la certitude absolue.","Albert Einstein","bêtise-humaine,einstein,french,humour,infini,philosophie,science,universe"
+"La vie est une aventure audacieuse ou alors elle n'est rien.","Helen Keller","aventure,inspiration,vie"
+"All pain is the same.","Oprah Winfrey","pain,wisdom"
+"I couldn't tell fact from fiction,Or if the dream was trueMy only sure predictionIn this world was you.I'd touch your features inchly. Beard love and dared the cost, The sented spiel reeled me unreal And I found my senses lost.","Maya Angelou","inspiration,poetry"
+"It is this mythical, or rather symbolic, content of the religious traditions which is likely to come into conflict with science. This occurs whenever this religious stock of ideas contains dogmatically fixed statements on subjects which belong in the domain of science.","Albert Einstein","religion,science"
+"Try and penetrate with our limited means the secrets of nature and you will find that, behind all the descernible laws and connections, there remains something subtle, intangible and inexplicable. Veneration for this force beyond anything that we can comprehend is my religion. To that extent I am, in fact, religious.","Albert Einstein","science,spirituality"
+"We have not the reverent feeling for the rainbow that the savage has, because we know how it is made. We have lost as much as we gained by prying into that matter.","Mark Twain","awe,science"
+"If you're silent for a long time, people just arrive in your mind.","Alice Walker","characters,mind,people,silence,silent,writers,writing"
+"I speak to the Black experience, but I am always talking about the human condition--about what we can endure, dream, fail at and survive.","Maya Angelou","writing"
+"My best friend is the one who brings out the best in me.","Henry Ford","best,friend,brings"
+"An inventor is a man who asks 'Why?' of the universe and lets nothing stand between the answer and his mind.","Ayn Rand","philosophy"
+"But yield who will to their separation, My object in living is to uniteMy avocation and my vocationAs my two eyes make one in sight.","Robert Frost","goals,inspiration"
+"A moment or an eternity—did it matter? Life, undefeated, existed and could exist.","Ayn Rand","life,philosophy"
+"Faith is taking the first step even when you don't see the whole staircase.","Martin Luther King Jr.","faith"
+"Oh juventud nunca dejes de pensar...","Albert Einstein","science"
+"To study and constantly, is this not a pleasure? To have friends come from far away places, is this not a joy? If people do not recognize your worth, but this does not worry you, are you not a true gentleman?","Confucius","good-things,inspiration,life"
+"In any compromise between food and poison, it is only death that can win. In any compromise between good and evil, it is only evil that can profit.","Ayn Rand","evil,good,philosophy"
+"One more thing...","Steve Jobs","inspiration"
+"Man is here for the sake of other men - above all for those upon whose smiles and well-being our own happiness depends.","Albert Einstein","happiness,purpose"
+"And now I see the face of god, and I raise this god over the earth, this god whom men have sought since men came into being, this god who will grant them joy and peace and pride. This god, this one word: 'I.","Ayn Rand","individualism,philosophy"
+"Definitions are the guardians of rationality, the first line of defense against the chaos of mental disintegration.","Ayn Rand","epistemology,philosophy,reason"
+"The spread of evil is the symptom of a vacuum. Whenever evil wins, it is only by default: by the moral failure of those who evade the fact that there can be no compromise on basic principles.","Ayn Rand","evil,philosophy"
+"A culture is made — or destroyed — by its articulate voices.","Ayn Rand","philosophy"
+"The doorstep to the temple of wisdom is a knowledge of our own ignorance.","Benjamin Franklin","knowledge"
+"First of all, let me assert my firm belief that the only thing we have to fear is fear itself - nameless, unreasoning, unjustified terror which paralyzes needed efforts to convert retreat into advance.","Franklin D. Roosevelt","fear,inspiration"
+"Aristotle may be regarded as the cultural barometer of Western history. Whenever his influence dominated the scene, it paved the way for one of history's brilliant eras; whenever it fell, so did mankind.","Ayn Rand","aristotle,philosophy,reason"
+"It is the kindness to take in a stranger when the levees break; the selflessness of workers who would rather cut their hours than see a friend lose their job which sees us through our darkest hours. It is the firefighter's courage to storm a stairway filled with smoke, but also a parent's willingness to nurture a child, that finally decides our fate.","Barack Obama","america,inauguration,inspiration"
+"One today is worth two tomorrows.","Benjamin Franklin","today,worth,tomorrows"
+"Your success and happiness lies in you. Resolve to keep happy, and your joy and you shall form an invicible host against difficulties.","Helen Keller","happiness,helen-keller,inspirational-life,life,success"
+"But I don't know how to fight. All I know how to do is stay alive.","Alice Walker","faith,life,sad,western"
+"I have an unshaken conviction that democracy can never be undermined if we maintain our library resources and a national intelligence capable of utilizing them."[Letter to Herbert Putnam; in: Waters, Edward N.: Herbert Putnam: the tallest little man in the world; Quarterly Journal of the Library of Congress 33:2 (April 1976), p. 171]","Franklin D. Roosevelt","democracy,education,libraries"
+"Some people get an education without going to college. The rest get it after they get out.","Mark Twain","college,education"
+"Whatever their future, at the dawn of their lives, men seek a noble vision of man's nature and of life's potential.","Ayn Rand","idealism,philosophy"
+"Contrary to the ecologists, nature does not stand still and does not maintain the kind of equilibrium that guarantees the survival of any particular species - least of all the survival of her greatest and most fragile product: man.","Ayn Rand","environmentalism,man,philosophy"
+"Games lubricate the body and mind.","Benjamin Franklin","body,games,invigorate,lubricate,mind,refresh,renew,replenish"
+"In scientific thinking are always present elements of poetry. Science and music requires a thought homogeneous.","Albert Einstein","music,poetry,science"
+"I would not think that philosophy and reason themselves will be man's guide in the foreseeable future; however, they will remain the most beautiful sanctuary they have always been for the select few.","Albert Einstein","philosophy,thought"
+"Man is an end in himself.","Ayn Rand","individualism,life,objectivism,philosophy,success"
+"If a man has not discovered something that he will die for, he isn't fit to live","Martin Luther King Jr.","inspirational-quotes"
+"Fear is the Fatal killer of Desire.","Zig Ziglar","fear,inspiration,iuindia-com,marketing,motivational,rohitdaga"
+"Nor is there wanting in the pressSome spirit to stand simply forth,Heroic in it nakedness,Against the uttermost of earth.The tale of earth's unhonored thingsSounds nobler there than 'neath the sun;And the mind whirls and the heart sings,And a shout greets the daring one.","Robert Frost","life-quotes,poetry,poets,quotes,robert-frost"
+"Joy is the holy fire that keeps our purpose warm and our intelligence aglow.","Helen Keller","happiness,joy,purpose"
+"Try not to become a person of success, but rather try to become a person of value.","Albert Einstein","success"
+"People often say that motivation doesn't last. Well, neither does bathing - that's why we recommend it daily.","Zig Ziglar","daily,last,bathing"
+"Find a beautiful piece of art. If you fall in love with Van Gogh or Matisse or John Oliver Killens, or if you fall love with the music of Coltrane, the music of Aretha Franklin, or the music of Chopin - find some beautiful art and admire it, and realize that that was created by human beings just like you, no more human, no less.","Maya Angelou","love,music,beautiful"
+"The female is, as it were, a mutilated male, and the catamenia are semen, only not pure; for there is only one thing they have not in them, the principle of soul.","Aristotle","female,male,mutilated,soul"
+"When I lose the sense of motivation and the sense to prove something as a basketball player, it's time for me to move away from the game.","Michael Jordan","time,basketball,game"
+"The monotony and solitude of a quiet life stimulates the creative mind.","Albert Einstein","creative,solitude,quiet"
+"Wenn du weißt, behaupte, dass du es weißt. Und wenn du etwas nicht weißt, gib zu, dass du es nicht weißt. Das ist Wissen.","Confucius","knowledge,wisdom"
+"Let it be told to the future world that in the depth of winter, when nothing but hope and virtue could survive, that the city and the country, alarmed at one common danger, came forth to meet it.","Barack Obama","america,inauguration,inspiration"
+"We will restore science to its rightful place and wield technology's wonders to raise health care's quality and lower its cost.","Barack Obama","inspirational,politics,science"
+"Phantasie ist wichtiger als Wissen, denn Wissen ist begrenzt.","Albert Einstein","inspiration"
+"If that which we have found is the corruption of solitude, then what can men wish for save corruption? If this is the great evil of being alone, than what is good and what is evil?","Ayn Rand","dystopian,philosophy"
+"‎Teachers matter. So instead of bashing them, or defending the status quo, let’s offer schools a deal. Give them the resources to keep good teachers on the job, and reward the best ones. In return, grant schools flexibility: To teach with creativity and passion; to stop teaching to the test; and to replace teachers who just aren’t helping kids learn.","Barack Obama","education"
+"If you accept the expectations of others, especially negative ones, then you never will change the outcome.","Michael Jordan","change,negative,accept"
diff -pruN 9.1.1-2/examples/quotes/backend/quotes.py 9.2.0-1/examples/quotes/backend/quotes.py
--- 9.1.1-2/examples/quotes/backend/quotes.py	1970-01-01 00:00:00.000000000 +0000
+++ 9.2.0-1/examples/quotes/backend/quotes.py	2025-10-28 16:50:53.000000000 +0000
@@ -0,0 +1,179 @@
+import asyncio
+import csv
+import os
+from time import time
+from typing import Annotated
+
+from fastapi import FastAPI, HTTPException
+from pydantic import BaseModel, Field, ValidationError
+from sentence_transformers import SentenceTransformer
+
+from elasticsearch import NotFoundError
+from elasticsearch.dsl.pydantic import AsyncBaseESModel
+from elasticsearch import dsl
+
+model = SentenceTransformer("all-MiniLM-L6-v2")
+dsl.async_connections.create_connection(hosts=[os.environ['ELASTICSEARCH_URL']])
+
+
+class Quote(AsyncBaseESModel):
+    quote: str
+    author: Annotated[str, dsl.Keyword()]
+    tags: Annotated[list[str], dsl.Keyword()]
+    embedding: Annotated[list[float], dsl.DenseVector()] = Field(init=False, default=[])
+
+    class Index:
+        name = 'quotes'
+
+
+class Tag(BaseModel):
+    tag: str
+    count: int
+
+
+class SearchRequest(BaseModel):
+    query: str
+    filters: list[str]
+    knn: bool
+    start: int
+
+
+class SearchResponse(BaseModel):
+    quotes: list[Quote]
+    tags: list[Tag]
+    start: int
+    total: int
+
+
+app = FastAPI(
+    title="Quotes API",
+    version="1.0.0",
+)
+
+
+@app.get("/api/quotes/{id}")
+async def get_quote(id: str) -> Quote:
+    doc = None
+    try:
+        doc = await Quote._doc.get(id)
+    except NotFoundError:
+        pass
+    if not doc:
+        raise HTTPException(status_code=404, detail="Item not found")
+    return Quote.from_doc(doc)
+
+
+@app.post("/api/quotes", status_code=201)
+async def create_quote(req: Quote) -> Quote:
+    embed_quotes([req])
+    doc = req.to_doc()
+    doc.meta.id = ""
+    await doc.save(refresh=True)
+    return Quote.from_doc(doc)
+
+
+@app.put("/api/quotes/{id}")
+async def update_quote(id: str, quote: Quote) -> Quote:
+    doc = None
+    try:
+        doc = await Quote._doc.get(id)
+    except NotFoundError:
+        pass
+    if not doc:
+        raise HTTPException(status_code=404, detail="Item not found")
+    if quote.quote:
+        embed_quotes([quote])
+        doc.quote = quote.quote
+        doc.embedding = quote.embedding
+    if quote.author:
+        doc.author = quote.author
+    if quote.tags:
+        doc.tags = quote.tags
+    await doc.save(refresh=True)
+    return Quote.from_doc(doc)
+
+
+@app.delete("/api/quotes/{id}", status_code=204)
+async def delete_quote(id: str) -> None:
+    doc = None
+    try:
+        doc = await Quote._doc.get(id)
+    except NotFoundError:
+        pass
+    if not doc:
+        raise HTTPException(status_code=404, detail="Item not found")
+    await doc.delete(refresh=True)
+
+
+@app.post('/api/search')
+async def search_quotes(req: SearchRequest) -> SearchResponse:
+    s = Quote._doc.search()
+    if req.query == '':
+        s = s.query(dsl.query.MatchAll())
+    elif req.knn:
+        query_vector = model.encode(req.query).tolist()
+        s = s.query(dsl.query.Knn(field=Quote._doc.embedding, query_vector=query_vector))
+    else:
+        s = s.query(dsl.query.Match(quote=req.query))
+    for tag in req.filters:
+        s = s.filter(dsl.query.Terms(tags=[tag]))
+    s.aggs.bucket('tags', dsl.aggs.Terms(field=Quote._doc.tags, size=100))
+
+    r = await s[req.start:req.start + 25].execute()
+    tags = [(tag.key, tag.doc_count) for tag in r.aggs.tags.buckets]
+    quotes = [Quote.from_doc(hit) for hit in r.hits]
+    total = r['hits'].total.value
+    
+    return SearchResponse(
+        quotes=quotes,
+        tags=[Tag(tag=t[0], count=t[1]) for t in tags],
+        start=req.start,
+        total=total
+    )
+
+
+def embed_quotes(quotes):
+    embeddings = model.encode([q.quote for q in quotes])
+    for q, e in zip(quotes, embeddings):
+        q.embedding = e.tolist()
+
+
+async def ingest_quotes():
+    if await Quote._doc._index.exists():
+        await Quote._doc._index.delete()
+    await Quote._doc.init()
+
+    def ingest_progress(count, start):
+        elapsed = time() - start
+        print(f'\rIngested {count} quotes. ({count / elapsed:.0f}/sec)', end='')
+
+    async def get_next_quote():
+        quotes: list[Quote] = []
+        with open('quotes.csv') as f:
+            reader = csv.DictReader(f)
+            count = 0
+            start = time()
+            for row in reader:
+                q = Quote(quote=row['quote'], author=row['author'],
+                             tags=row['tags'].split(','))
+                quotes.append(q)
+                if len(quotes) == 512:
+                    embed_quotes(quotes)
+                    for q in quotes:
+                        yield q.to_doc()
+                    count += len(quotes)
+                    ingest_progress(count, start)
+                    quotes = []
+            if len(quotes) > 0:
+                embed_quotes(quotes)
+                for q in quotes:
+                    yield q.to_doc()
+                count += len(quotes)
+                ingest_progress(count, start)
+
+    await Quote._doc.bulk(get_next_quote())
+    print("\nIngest complete.")
+
+
+if __name__ == "__main__":
+    asyncio.run(ingest_quotes())
diff -pruN 9.1.1-2/examples/quotes/backend/requirements.txt 9.2.0-1/examples/quotes/backend/requirements.txt
--- 9.1.1-2/examples/quotes/backend/requirements.txt	1970-01-01 00:00:00.000000000 +0000
+++ 9.2.0-1/examples/quotes/backend/requirements.txt	2025-10-28 16:50:53.000000000 +0000
@@ -0,0 +1,163 @@
+#
+# This file is autogenerated by pip-compile with Python 3.12
+# by the following command:
+#
+#    pip-compile pyproject.toml
+#
+aiohappyeyeballs==2.6.1
+    # via aiohttp
+aiohttp==3.12.15
+    # via elasticsearch
+aiosignal==1.4.0
+    # via aiohttp
+annotated-types==0.7.0
+    # via pydantic
+anyio==4.11.0
+    # via starlette
+attrs==25.3.0
+    # via aiohttp
+certifi==2025.8.3
+    # via
+    #   elastic-transport
+    #   requests
+charset-normalizer==3.4.3
+    # via requests
+click==8.3.0
+    # via uvicorn
+elastic-transport==8.17.1
+    # via elasticsearch
+elasticsearch[async]==8.19.1
+    # via quotes (pyproject.toml)
+fastapi==0.117.1
+    # via quotes (pyproject.toml)
+filelock==3.19.1
+    # via
+    #   huggingface-hub
+    #   torch
+    #   transformers
+frozenlist==1.7.0
+    # via
+    #   aiohttp
+    #   aiosignal
+fsspec==2025.9.0
+    # via
+    #   huggingface-hub
+    #   torch
+h11==0.16.0
+    # via uvicorn
+hf-xet==1.1.10
+    # via huggingface-hub
+huggingface-hub==0.35.0
+    # via
+    #   sentence-transformers
+    #   tokenizers
+    #   transformers
+idna==3.10
+    # via
+    #   anyio
+    #   requests
+    #   yarl
+jinja2==3.1.6
+    # via torch
+joblib==1.5.2
+    # via scikit-learn
+markupsafe==3.0.2
+    # via jinja2
+mpmath==1.3.0
+    # via sympy
+multidict==6.6.4
+    # via
+    #   aiohttp
+    #   yarl
+networkx==3.5
+    # via torch
+numpy==2.3.3
+    # via
+    #   scikit-learn
+    #   scipy
+    #   transformers
+orjson==3.11.3
+    # via quotes (pyproject.toml)
+packaging==25.0
+    # via
+    #   huggingface-hub
+    #   transformers
+pillow==11.3.0
+    # via sentence-transformers
+propcache==0.3.2
+    # via
+    #   aiohttp
+    #   yarl
+pydantic==2.11.9
+    # via fastapi
+pydantic-core==2.33.2
+    # via pydantic
+python-dateutil==2.9.0.post0
+    # via elasticsearch
+pyyaml==6.0.2
+    # via
+    #   huggingface-hub
+    #   transformers
+regex==2025.9.18
+    # via transformers
+requests==2.32.5
+    # via
+    #   huggingface-hub
+    #   transformers
+safetensors==0.6.2
+    # via transformers
+scikit-learn==1.7.2
+    # via sentence-transformers
+scipy==1.16.2
+    # via
+    #   scikit-learn
+    #   sentence-transformers
+sentence-transformers==5.1.1
+    # via quotes (pyproject.toml)
+six==1.17.0
+    # via python-dateutil
+sniffio==1.3.1
+    # via anyio
+starlette==0.48.0
+    # via fastapi
+sympy==1.14.0
+    # via torch
+threadpoolctl==3.6.0
+    # via scikit-learn
+tokenizers==0.22.1
+    # via transformers
+torch==2.8.0
+    # via sentence-transformers
+tqdm==4.67.1
+    # via
+    #   huggingface-hub
+    #   sentence-transformers
+    #   transformers
+transformers==4.56.2
+    # via sentence-transformers
+typing-extensions==4.15.0
+    # via
+    #   aiosignal
+    #   anyio
+    #   elasticsearch
+    #   fastapi
+    #   huggingface-hub
+    #   pydantic
+    #   pydantic-core
+    #   sentence-transformers
+    #   starlette
+    #   torch
+    #   typing-inspection
+typing-inspection==0.4.1
+    # via pydantic
+urllib3==2.5.0
+    # via
+    #   elastic-transport
+    #   requests
+uvicorn==0.36.0
+    # via quotes (pyproject.toml)
+yarl==1.20.1
+    # via aiohttp
+
+# The following packages are considered to be unsafe in a requirements file:
+# setuptools
diff -pruN 9.1.1-2/examples/quotes/eslint.config.js 9.2.0-1/examples/quotes/eslint.config.js
--- 9.1.1-2/examples/quotes/eslint.config.js	1970-01-01 00:00:00.000000000 +0000
+++ 9.2.0-1/examples/quotes/eslint.config.js	2025-10-28 16:50:53.000000000 +0000
@@ -0,0 +1,23 @@
+import js from '@eslint/js'
+import globals from 'globals'
+import reactHooks from 'eslint-plugin-react-hooks'
+import reactRefresh from 'eslint-plugin-react-refresh'
+import tseslint from 'typescript-eslint'
+import { defineConfig, globalIgnores } from 'eslint/config'
+
+export default defineConfig([
+  globalIgnores(['dist']),
+  {
+    files: ['**/*.{ts,tsx}'],
+    extends: [
+      js.configs.recommended,
+      tseslint.configs.recommended,
+      reactHooks.configs['recommended-latest'],
+      reactRefresh.configs.vite,
+    ],
+    languageOptions: {
+      ecmaVersion: 2020,
+      globals: globals.browser,
+    },
+  },
+])
diff -pruN 9.1.1-2/examples/quotes/index.html 9.2.0-1/examples/quotes/index.html
--- 9.1.1-2/examples/quotes/index.html	1970-01-01 00:00:00.000000000 +0000
+++ 9.2.0-1/examples/quotes/index.html	2025-10-28 16:50:53.000000000 +0000
@@ -0,0 +1,13 @@
+<!doctype html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <title>Elasticsearch + Pydantic Demo</title>
+  </head>
+  <body>
+    <div id="root"></div>
+    <script type="module" src="/src/main.tsx"></script>
+  </body>
+</html>
diff -pruN 9.1.1-2/examples/quotes/package-lock.json 9.2.0-1/examples/quotes/package-lock.json
--- 9.1.1-2/examples/quotes/package-lock.json	1970-01-01 00:00:00.000000000 +0000
+++ 9.2.0-1/examples/quotes/package-lock.json	2025-10-28 16:50:53.000000000 +0000
@@ -0,0 +1,3756 @@
+{
+  "name": "quotes",
+  "version": "0.0.0",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "quotes",
+      "version": "0.0.0",
+      "hasInstallScript": true,
+      "dependencies": {
+        "boostrap": "^2.0.0",
+        "bootstrap": "^5.3.8",
+        "react": "^19.1.1",
+        "react-bootstrap": "^2.10.10",
+        "react-dom": "^19.1.1",
+        "react-router": "^7.9.2"
+      },
+      "devDependencies": {
+        "@eslint/js": "^9.36.0",
+        "@types/react": "^19.1.13",
+        "@types/react-dom": "^19.1.9",
+        "@vitejs/plugin-react": "^5.0.3",
+        "eslint": "^9.36.0",
+        "eslint-plugin-react-hooks": "^5.2.0",
+        "eslint-plugin-react-refresh": "^0.4.20",
+        "globals": "^16.4.0",
+        "typescript": "~5.8.3",
+        "typescript-eslint": "^8.44.0",
+        "vite": "^7.1.7"
+      }
+    },
+    "node_modules/@babel/code-frame": {
+      "version": "7.27.1",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
+      "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-validator-identifier": "^7.27.1",
+        "js-tokens": "^4.0.0",
+        "picocolors": "^1.1.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/compat-data": {
+      "version": "7.28.4",
+      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz",
+      "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/core": {
+      "version": "7.28.4",
+      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz",
+      "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/code-frame": "^7.27.1",
+        "@babel/generator": "^7.28.3",
+        "@babel/helper-compilation-targets": "^7.27.2",
+        "@babel/helper-module-transforms": "^7.28.3",
+        "@babel/helpers": "^7.28.4",
+        "@babel/parser": "^7.28.4",
+        "@babel/template": "^7.27.2",
+        "@babel/traverse": "^7.28.4",
+        "@babel/types": "^7.28.4",
+        "@jridgewell/remapping": "^2.3.5",
+        "convert-source-map": "^2.0.0",
+        "debug": "^4.1.0",
+        "gensync": "^1.0.0-beta.2",
+        "json5": "^2.2.3",
+        "semver": "^6.3.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/babel"
+      }
+    },
+    "node_modules/@babel/generator": {
+      "version": "7.28.3",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz",
+      "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/parser": "^7.28.3",
+        "@babel/types": "^7.28.2",
+        "@jridgewell/gen-mapping": "^0.3.12",
+        "@jridgewell/trace-mapping": "^0.3.28",
+        "jsesc": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-compilation-targets": {
+      "version": "7.27.2",
+      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz",
+      "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/compat-data": "^7.27.2",
+        "@babel/helper-validator-option": "^7.27.1",
+        "browserslist": "^4.24.0",
+        "lru-cache": "^5.1.1",
+        "semver": "^6.3.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-globals": {
+      "version": "7.28.0",
+      "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
+      "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-module-imports": {
+      "version": "7.27.1",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz",
+      "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/traverse": "^7.27.1",
+        "@babel/types": "^7.27.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-module-transforms": {
+      "version": "7.28.3",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz",
+      "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-module-imports": "^7.27.1",
+        "@babel/helper-validator-identifier": "^7.27.1",
+        "@babel/traverse": "^7.28.3"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/helper-plugin-utils": {
+      "version": "7.27.1",
+      "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz",
+      "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-string-parser": {
+      "version": "7.27.1",
+      "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
+      "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-validator-identifier": {
+      "version": "7.27.1",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz",
+      "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-validator-option": {
+      "version": "7.27.1",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
+      "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helpers": {
+      "version": "7.28.4",
+      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz",
+      "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/template": "^7.27.2",
+        "@babel/types": "^7.28.4"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/parser": {
+      "version": "7.28.4",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz",
+      "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/types": "^7.28.4"
+      },
+      "bin": {
+        "parser": "bin/babel-parser.js"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-react-jsx-self": {
+      "version": "7.27.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz",
+      "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.27.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-react-jsx-source": {
+      "version": "7.27.1",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz",
+      "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.27.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/runtime": {
+      "version": "7.28.4",
+      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz",
+      "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/template": {
+      "version": "7.27.2",
+      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz",
+      "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/code-frame": "^7.27.1",
+        "@babel/parser": "^7.27.2",
+        "@babel/types": "^7.27.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/traverse": {
+      "version": "7.28.4",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz",
+      "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/code-frame": "^7.27.1",
+        "@babel/generator": "^7.28.3",
+        "@babel/helper-globals": "^7.28.0",
+        "@babel/parser": "^7.28.4",
+        "@babel/template": "^7.27.2",
+        "@babel/types": "^7.28.4",
+        "debug": "^4.3.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/types": {
+      "version": "7.28.4",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz",
+      "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-string-parser": "^7.27.1",
+        "@babel/helper-validator-identifier": "^7.27.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@esbuild/aix-ppc64": {
+      "version": "0.25.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.10.tgz",
+      "integrity": "sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "aix"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/android-arm": {
+      "version": "0.25.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.10.tgz",
+      "integrity": "sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/android-arm64": {
+      "version": "0.25.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.10.tgz",
+      "integrity": "sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/android-x64": {
+      "version": "0.25.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.10.tgz",
+      "integrity": "sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/darwin-arm64": {
+      "version": "0.25.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.10.tgz",
+      "integrity": "sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/darwin-x64": {
+      "version": "0.25.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.10.tgz",
+      "integrity": "sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/freebsd-arm64": {
+      "version": "0.25.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.10.tgz",
+      "integrity": "sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/freebsd-x64": {
+      "version": "0.25.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.10.tgz",
+      "integrity": "sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-arm": {
+      "version": "0.25.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.10.tgz",
+      "integrity": "sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-arm64": {
+      "version": "0.25.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.10.tgz",
+      "integrity": "sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-ia32": {
+      "version": "0.25.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.10.tgz",
+      "integrity": "sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-loong64": {
+      "version": "0.25.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.10.tgz",
+      "integrity": "sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==",
+      "cpu": [
+        "loong64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-mips64el": {
+      "version": "0.25.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.10.tgz",
+      "integrity": "sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==",
+      "cpu": [
+        "mips64el"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-ppc64": {
+      "version": "0.25.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.10.tgz",
+      "integrity": "sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-riscv64": {
+      "version": "0.25.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.10.tgz",
+      "integrity": "sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==",
+      "cpu": [
+        "riscv64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-s390x": {
+      "version": "0.25.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.10.tgz",
+      "integrity": "sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==",
+      "cpu": [
+        "s390x"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-x64": {
+      "version": "0.25.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.10.tgz",
+      "integrity": "sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/netbsd-arm64": {
+      "version": "0.25.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.10.tgz",
+      "integrity": "sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "netbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/netbsd-x64": {
+      "version": "0.25.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.10.tgz",
+      "integrity": "sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "netbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/openbsd-arm64": {
+      "version": "0.25.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.10.tgz",
+      "integrity": "sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/openbsd-x64": {
+      "version": "0.25.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.10.tgz",
+      "integrity": "sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/openharmony-arm64": {
+      "version": "0.25.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.10.tgz",
+      "integrity": "sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openharmony"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/sunos-x64": {
+      "version": "0.25.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.10.tgz",
+      "integrity": "sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "sunos"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/win32-arm64": {
+      "version": "0.25.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.10.tgz",
+      "integrity": "sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/win32-ia32": {
+      "version": "0.25.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.10.tgz",
+      "integrity": "sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/win32-x64": {
+      "version": "0.25.10",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.10.tgz",
+      "integrity": "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@eslint-community/eslint-utils": {
+      "version": "4.9.0",
+      "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz",
+      "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "eslint-visitor-keys": "^3.4.3"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      },
+      "peerDependencies": {
+        "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+      }
+    },
+    "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": {
+      "version": "3.4.3",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+      "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/@eslint-community/regexpp": {
+      "version": "4.12.1",
+      "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz",
+      "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+      }
+    },
+    "node_modules/@eslint/config-array": {
+      "version": "0.21.0",
+      "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz",
+      "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@eslint/object-schema": "^2.1.6",
+        "debug": "^4.3.1",
+        "minimatch": "^3.1.2"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
+    "node_modules/@eslint/config-helpers": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.1.tgz",
+      "integrity": "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
+    "node_modules/@eslint/core": {
+      "version": "0.15.2",
+      "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz",
+      "integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@types/json-schema": "^7.0.15"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
+    "node_modules/@eslint/eslintrc": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz",
+      "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ajv": "^6.12.4",
+        "debug": "^4.3.2",
+        "espree": "^10.0.1",
+        "globals": "^14.0.0",
+        "ignore": "^5.2.0",
+        "import-fresh": "^3.2.1",
+        "js-yaml": "^4.1.0",
+        "minimatch": "^3.1.2",
+        "strip-json-comments": "^3.1.1"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/@eslint/eslintrc/node_modules/globals": {
+      "version": "14.0.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
+      "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@eslint/js": {
+      "version": "9.36.0",
+      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.36.0.tgz",
+      "integrity": "sha512-uhCbYtYynH30iZErszX78U+nR3pJU3RHGQ57NXy5QupD4SBVwDeU8TNBy+MjMngc1UyIW9noKqsRqfjQTBU2dw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "url": "https://eslint.org/donate"
+      }
+    },
+    "node_modules/@eslint/object-schema": {
+      "version": "2.1.6",
+      "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz",
+      "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
+    "node_modules/@eslint/plugin-kit": {
+      "version": "0.3.5",
+      "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz",
+      "integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@eslint/core": "^0.15.2",
+        "levn": "^0.4.1"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
+    "node_modules/@humanfs/core": {
+      "version": "0.19.1",
+      "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
+      "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=18.18.0"
+      }
+    },
+    "node_modules/@humanfs/node": {
+      "version": "0.16.7",
+      "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz",
+      "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@humanfs/core": "^0.19.1",
+        "@humanwhocodes/retry": "^0.4.0"
+      },
+      "engines": {
+        "node": ">=18.18.0"
+      }
+    },
+    "node_modules/@humanwhocodes/module-importer": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+      "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=12.22"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/nzakas"
+      }
+    },
+    "node_modules/@humanwhocodes/retry": {
+      "version": "0.4.3",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz",
+      "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=18.18"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/nzakas"
+      }
+    },
+    "node_modules/@jridgewell/gen-mapping": {
+      "version": "0.3.13",
+      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+      "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/sourcemap-codec": "^1.5.0",
+        "@jridgewell/trace-mapping": "^0.3.24"
+      }
+    },
+    "node_modules/@jridgewell/remapping": {
+      "version": "2.3.5",
+      "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
+      "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/gen-mapping": "^0.3.5",
+        "@jridgewell/trace-mapping": "^0.3.24"
+      }
+    },
+    "node_modules/@jridgewell/resolve-uri": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+      "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/sourcemap-codec": {
+      "version": "1.5.5",
+      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+      "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@jridgewell/trace-mapping": {
+      "version": "0.3.31",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+      "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/resolve-uri": "^3.1.0",
+        "@jridgewell/sourcemap-codec": "^1.4.14"
+      }
+    },
+    "node_modules/@nodelib/fs.scandir": {
+      "version": "2.1.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+      "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@nodelib/fs.stat": "2.0.5",
+        "run-parallel": "^1.1.9"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.stat": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+      "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.walk": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+      "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@nodelib/fs.scandir": "2.1.5",
+        "fastq": "^1.6.0"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@popperjs/core": {
+      "version": "2.11.8",
+      "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
+      "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
+      "license": "MIT",
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/popperjs"
+      }
+    },
+    "node_modules/@react-aria/ssr": {
+      "version": "3.9.10",
+      "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.10.tgz",
+      "integrity": "sha512-hvTm77Pf+pMBhuBm760Li0BVIO38jv1IBws1xFm1NoL26PU+fe+FMW5+VZWyANR6nYL65joaJKZqOdTQMkO9IQ==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@swc/helpers": "^0.5.0"
+      },
+      "engines": {
+        "node": ">= 12"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1"
+      }
+    },
+    "node_modules/@restart/hooks": {
+      "version": "0.4.16",
+      "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.16.tgz",
+      "integrity": "sha512-f7aCv7c+nU/3mF7NWLtVVr0Ra80RqsO89hO72r+Y/nvQr5+q0UFGkocElTH6MJApvReVh6JHUFYn2cw1WdHF3w==",
+      "license": "MIT",
+      "dependencies": {
+        "dequal": "^2.0.3"
+      },
+      "peerDependencies": {
+        "react": ">=16.8.0"
+      }
+    },
+    "node_modules/@restart/ui": {
+      "version": "1.9.4",
+      "resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.9.4.tgz",
+      "integrity": "sha512-N4C7haUc3vn4LTwVUPlkJN8Ach/+yIMvRuTVIhjilNHqegY60SGLrzud6errOMNJwSnmYFnt1J0H/k8FE3A4KA==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.26.0",
+        "@popperjs/core": "^2.11.8",
+        "@react-aria/ssr": "^3.5.0",
+        "@restart/hooks": "^0.5.0",
+        "@types/warning": "^3.0.3",
+        "dequal": "^2.0.3",
+        "dom-helpers": "^5.2.0",
+        "uncontrollable": "^8.0.4",
+        "warning": "^4.0.3"
+      },
+      "peerDependencies": {
+        "react": ">=16.14.0",
+        "react-dom": ">=16.14.0"
+      }
+    },
+    "node_modules/@restart/ui/node_modules/@restart/hooks": {
+      "version": "0.5.1",
+      "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.5.1.tgz",
+      "integrity": "sha512-EMoH04NHS1pbn07iLTjIjgttuqb7qu4+/EyhAx27MHpoENcB2ZdSsLTNxmKD+WEPnZigo62Qc8zjGnNxoSE/5Q==",
+      "license": "MIT",
+      "dependencies": {
+        "dequal": "^2.0.3"
+      },
+      "peerDependencies": {
+        "react": ">=16.8.0"
+      }
+    },
+    "node_modules/@restart/ui/node_modules/uncontrollable": {
+      "version": "8.0.4",
+      "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-8.0.4.tgz",
+      "integrity": "sha512-ulRWYWHvscPFc0QQXvyJjY6LIXU56f0h8pQFvhxiKk5V1fcI8gp9Ht9leVAhrVjzqMw0BgjspBINx9r6oyJUvQ==",
+      "license": "MIT",
+      "peerDependencies": {
+        "react": ">=16.14.0"
+      }
+    },
+    "node_modules/@rolldown/pluginutils": {
+      "version": "1.0.0-beta.35",
+      "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.35.tgz",
+      "integrity": "sha512-slYrCpoxJUqzFDDNlvrOYRazQUNRvWPjXA17dAOISY3rDMxX6k8K4cj2H+hEYMHF81HO3uNd5rHVigAWRM5dSg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@rollup/rollup-android-arm-eabi": {
+      "version": "4.52.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.2.tgz",
+      "integrity": "sha512-o3pcKzJgSGt4d74lSZ+OCnHwkKBeAbFDmbEm5gg70eA8VkyCuC/zV9TwBnmw6VjDlRdF4Pshfb+WE9E6XY1PoQ==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ]
+    },
+    "node_modules/@rollup/rollup-android-arm64": {
+      "version": "4.52.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.2.tgz",
+      "integrity": "sha512-cqFSWO5tX2vhC9hJTK8WAiPIm4Q8q/cU8j2HQA0L3E1uXvBYbOZMhE2oFL8n2pKB5sOCHY6bBuHaRwG7TkfJyw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ]
+    },
+    "node_modules/@rollup/rollup-darwin-arm64": {
+      "version": "4.52.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.2.tgz",
+      "integrity": "sha512-vngduywkkv8Fkh3wIZf5nFPXzWsNsVu1kvtLETWxTFf/5opZmflgVSeLgdHR56RQh71xhPhWoOkEBvbehwTlVA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@rollup/rollup-darwin-x64": {
+      "version": "4.52.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.2.tgz",
+      "integrity": "sha512-h11KikYrUCYTrDj6h939hhMNlqU2fo/X4NB0OZcys3fya49o1hmFaczAiJWVAFgrM1NCP6RrO7lQKeVYSKBPSQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@rollup/rollup-freebsd-arm64": {
+      "version": "4.52.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.2.tgz",
+      "integrity": "sha512-/eg4CI61ZUkLXxMHyVlmlGrSQZ34xqWlZNW43IAU4RmdzWEx0mQJ2mN/Cx4IHLVZFL6UBGAh+/GXhgvGb+nVxw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ]
+    },
+    "node_modules/@rollup/rollup-freebsd-x64": {
+      "version": "4.52.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.2.tgz",
+      "integrity": "sha512-QOWgFH5X9+p+S1NAfOqc0z8qEpJIoUHf7OWjNUGOeW18Mx22lAUOiA9b6r2/vpzLdfxi/f+VWsYjUOMCcYh0Ng==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+      "version": "4.52.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.2.tgz",
+      "integrity": "sha512-kDWSPafToDd8LcBYd1t5jw7bD5Ojcu12S3uT372e5HKPzQt532vW+rGFFOaiR0opxePyUkHrwz8iWYEyH1IIQA==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+      "version": "4.52.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.2.tgz",
+      "integrity": "sha512-gKm7Mk9wCv6/rkzwCiUC4KnevYhlf8ztBrDRT9g/u//1fZLapSRc+eDZj2Eu2wpJ+0RzUKgtNijnVIB4ZxyL+w==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm64-gnu": {
+      "version": "4.52.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.2.tgz",
+      "integrity": "sha512-66lA8vnj5mB/rtDNwPgrrKUOtCLVQypkyDa2gMfOefXK6rcZAxKLO9Fy3GkW8VkPnENv9hBkNOFfGLf6rNKGUg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm64-musl": {
+      "version": "4.52.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.2.tgz",
+      "integrity": "sha512-s+OPucLNdJHvuZHuIz2WwncJ+SfWHFEmlC5nKMUgAelUeBUnlB4wt7rXWiyG4Zn07uY2Dd+SGyVa9oyLkVGOjA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-loong64-gnu": {
+      "version": "4.52.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.2.tgz",
+      "integrity": "sha512-8wTRM3+gVMDLLDdaT6tKmOE3lJyRy9NpJUS/ZRWmLCmOPIJhVyXwjBo+XbrrwtV33Em1/eCTd5TuGJm4+DmYjw==",
+      "cpu": [
+        "loong64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-ppc64-gnu": {
+      "version": "4.52.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.2.tgz",
+      "integrity": "sha512-6yqEfgJ1anIeuP2P/zhtfBlDpXUb80t8DpbYwXQ3bQd95JMvUaqiX+fKqYqUwZXqdJDd8xdilNtsHM2N0cFm6A==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+      "version": "4.52.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.2.tgz",
+      "integrity": "sha512-sshYUiYVSEI2B6dp4jMncwxbrUqRdNApF2c3bhtLAU0qA8Lrri0p0NauOsTWh3yCCCDyBOjESHMExonp7Nzc0w==",
+      "cpu": [
+        "riscv64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-riscv64-musl": {
+      "version": "4.52.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.2.tgz",
+      "integrity": "sha512-duBLgd+3pqC4MMwBrKkFxaZerUxZcYApQVC5SdbF5/e/589GwVvlRUnyqMFbM8iUSb1BaoX/3fRL7hB9m2Pj8Q==",
+      "cpu": [
+        "riscv64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-s390x-gnu": {
+      "version": "4.52.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.2.tgz",
+      "integrity": "sha512-tzhYJJidDUVGMgVyE+PmxENPHlvvqm1KILjjZhB8/xHYqAGeizh3GBGf9u6WdJpZrz1aCpIIHG0LgJgH9rVjHQ==",
+      "cpu": [
+        "s390x"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-x64-gnu": {
+      "version": "4.52.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.2.tgz",
+      "integrity": "sha512-opH8GSUuVcCSSyHHcl5hELrmnk4waZoVpgn/4FDao9iyE4WpQhyWJ5ryl5M3ocp4qkRuHfyXnGqg8M9oKCEKRA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-x64-musl": {
+      "version": "4.52.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.2.tgz",
+      "integrity": "sha512-LSeBHnGli1pPKVJ79ZVJgeZWWZXkEe/5o8kcn23M8eMKCUANejchJbF/JqzM4RRjOJfNRhKJk8FuqL1GKjF5oQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-openharmony-arm64": {
+      "version": "4.52.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.2.tgz",
+      "integrity": "sha512-uPj7MQ6/s+/GOpolavm6BPo+6CbhbKYyZHUDvZ/SmJM7pfDBgdGisFX3bY/CBDMg2ZO4utfhlApkSfZ92yXw7Q==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openharmony"
+      ]
+    },
+    "node_modules/@rollup/rollup-win32-arm64-msvc": {
+      "version": "4.52.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.2.tgz",
+      "integrity": "sha512-Z9MUCrSgIaUeeHAiNkm3cQyst2UhzjPraR3gYYfOjAuZI7tcFRTOD+4cHLPoS/3qinchth+V56vtqz1Tv+6KPA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@rollup/rollup-win32-ia32-msvc": {
+      "version": "4.52.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.2.tgz",
+      "integrity": "sha512-+GnYBmpjldD3XQd+HMejo+0gJGwYIOfFeoBQv32xF/RUIvccUz20/V6Otdv+57NE70D5pa8W/jVGDoGq0oON4A==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@rollup/rollup-win32-x64-gnu": {
+      "version": "4.52.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.2.tgz",
+      "integrity": "sha512-ApXFKluSB6kDQkAqZOKXBjiaqdF1BlKi+/eqnYe9Ee7U2K3pUDKsIyr8EYm/QDHTJIM+4X+lI0gJc3TTRhd+dA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@rollup/rollup-win32-x64-msvc": {
+      "version": "4.52.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.2.tgz",
+      "integrity": "sha512-ARz+Bs8kY6FtitYM96PqPEVvPXqEZmPZsSkXvyX19YzDqkCaIlhCieLLMI5hxO9SRZ2XtCtm8wxhy0iJ2jxNfw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@swc/helpers": {
+      "version": "0.5.17",
+      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz",
+      "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "tslib": "^2.8.0"
+      }
+    },
+    "node_modules/@types/babel__core": {
+      "version": "7.20.5",
+      "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
+      "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/parser": "^7.20.7",
+        "@babel/types": "^7.20.7",
+        "@types/babel__generator": "*",
+        "@types/babel__template": "*",
+        "@types/babel__traverse": "*"
+      }
+    },
+    "node_modules/@types/babel__generator": {
+      "version": "7.27.0",
+      "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz",
+      "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/types": "^7.0.0"
+      }
+    },
+    "node_modules/@types/babel__template": {
+      "version": "7.4.4",
+      "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
+      "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/parser": "^7.1.0",
+        "@babel/types": "^7.0.0"
+      }
+    },
+    "node_modules/@types/babel__traverse": {
+      "version": "7.28.0",
+      "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz",
+      "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/types": "^7.28.2"
+      }
+    },
+    "node_modules/@types/estree": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
+      "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@types/json-schema": {
+      "version": "7.0.15",
+      "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
+      "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@types/prop-types": {
+      "version": "15.7.15",
+      "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz",
+      "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==",
+      "license": "MIT"
+    },
+    "node_modules/@types/react": {
+      "version": "19.1.13",
+      "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.13.tgz",
+      "integrity": "sha512-hHkbU/eoO3EG5/MZkuFSKmYqPbSVk5byPFa3e7y/8TybHiLMACgI8seVYlicwk7H5K/rI2px9xrQp/C+AUDTiQ==",
+      "license": "MIT",
+      "dependencies": {
+        "csstype": "^3.0.2"
+      }
+    },
+    "node_modules/@types/react-dom": {
+      "version": "19.1.9",
+      "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.9.tgz",
+      "integrity": "sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ==",
+      "dev": true,
+      "license": "MIT",
+      "peerDependencies": {
+        "@types/react": "^19.0.0"
+      }
+    },
+    "node_modules/@types/react-transition-group": {
+      "version": "4.4.12",
+      "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz",
+      "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==",
+      "license": "MIT",
+      "peerDependencies": {
+        "@types/react": "*"
+      }
+    },
+    "node_modules/@types/warning": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.3.tgz",
+      "integrity": "sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q==",
+      "license": "MIT"
+    },
+    "node_modules/@typescript-eslint/eslint-plugin": {
+      "version": "8.44.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.44.1.tgz",
+      "integrity": "sha512-molgphGqOBT7t4YKCSkbasmu1tb1MgrZ2szGzHbclF7PNmOkSTQVHy+2jXOSnxvR3+Xe1yySHFZoqMpz3TfQsw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@eslint-community/regexpp": "^4.10.0",
+        "@typescript-eslint/scope-manager": "8.44.1",
+        "@typescript-eslint/type-utils": "8.44.1",
+        "@typescript-eslint/utils": "8.44.1",
+        "@typescript-eslint/visitor-keys": "8.44.1",
+        "graphemer": "^1.4.0",
+        "ignore": "^7.0.0",
+        "natural-compare": "^1.4.0",
+        "ts-api-utils": "^2.1.0"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "@typescript-eslint/parser": "^8.44.1",
+        "eslint": "^8.57.0 || ^9.0.0",
+        "typescript": ">=4.8.4 <6.0.0"
+      }
+    },
+    "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": {
+      "version": "7.0.5",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz",
+      "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 4"
+      }
+    },
+    "node_modules/@typescript-eslint/parser": {
+      "version": "8.44.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.44.1.tgz",
+      "integrity": "sha512-EHrrEsyhOhxYt8MTg4zTF+DJMuNBzWwgvvOYNj/zm1vnaD/IC5zCXFehZv94Piqa2cRFfXrTFxIvO95L7Qc/cw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/scope-manager": "8.44.1",
+        "@typescript-eslint/types": "8.44.1",
+        "@typescript-eslint/typescript-estree": "8.44.1",
+        "@typescript-eslint/visitor-keys": "8.44.1",
+        "debug": "^4.3.4"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "eslint": "^8.57.0 || ^9.0.0",
+        "typescript": ">=4.8.4 <6.0.0"
+      }
+    },
+    "node_modules/@typescript-eslint/project-service": {
+      "version": "8.44.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.44.1.tgz",
+      "integrity": "sha512-ycSa60eGg8GWAkVsKV4E6Nz33h+HjTXbsDT4FILyL8Obk5/mx4tbvCNsLf9zret3ipSumAOG89UcCs/KRaKYrA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/tsconfig-utils": "^8.44.1",
+        "@typescript-eslint/types": "^8.44.1",
+        "debug": "^4.3.4"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "typescript": ">=4.8.4 <6.0.0"
+      }
+    },
+    "node_modules/@typescript-eslint/scope-manager": {
+      "version": "8.44.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.44.1.tgz",
+      "integrity": "sha512-NdhWHgmynpSvyhchGLXh+w12OMT308Gm25JoRIyTZqEbApiBiQHD/8xgb6LqCWCFcxFtWwaVdFsLPQI3jvhywg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/types": "8.44.1",
+        "@typescript-eslint/visitor-keys": "8.44.1"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      }
+    },
+    "node_modules/@typescript-eslint/tsconfig-utils": {
+      "version": "8.44.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.44.1.tgz",
+      "integrity": "sha512-B5OyACouEjuIvof3o86lRMvyDsFwZm+4fBOqFHccIctYgBjqR3qT39FBYGN87khcgf0ExpdCBeGKpKRhSFTjKQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "typescript": ">=4.8.4 <6.0.0"
+      }
+    },
+    "node_modules/@typescript-eslint/type-utils": {
+      "version": "8.44.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.44.1.tgz",
+      "integrity": "sha512-KdEerZqHWXsRNKjF9NYswNISnFzXfXNDfPxoTh7tqohU/PRIbwTmsjGK6V9/RTYWau7NZvfo52lgVk+sJh0K3g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/types": "8.44.1",
+        "@typescript-eslint/typescript-estree": "8.44.1",
+        "@typescript-eslint/utils": "8.44.1",
+        "debug": "^4.3.4",
+        "ts-api-utils": "^2.1.0"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "eslint": "^8.57.0 || ^9.0.0",
+        "typescript": ">=4.8.4 <6.0.0"
+      }
+    },
+    "node_modules/@typescript-eslint/types": {
+      "version": "8.44.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.44.1.tgz",
+      "integrity": "sha512-Lk7uj7y9uQUOEguiDIDLYLJOrYHQa7oBiURYVFqIpGxclAFQ78f6VUOM8lI2XEuNOKNB7XuvM2+2cMXAoq4ALQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      }
+    },
+    "node_modules/@typescript-eslint/typescript-estree": {
+      "version": "8.44.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.44.1.tgz",
+      "integrity": "sha512-qnQJ+mVa7szevdEyvfItbO5Vo+GfZ4/GZWWDRRLjrxYPkhM+6zYB2vRYwCsoJLzqFCdZT4mEqyJoyzkunsZ96A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/project-service": "8.44.1",
+        "@typescript-eslint/tsconfig-utils": "8.44.1",
+        "@typescript-eslint/types": "8.44.1",
+        "@typescript-eslint/visitor-keys": "8.44.1",
+        "debug": "^4.3.4",
+        "fast-glob": "^3.3.2",
+        "is-glob": "^4.0.3",
+        "minimatch": "^9.0.4",
+        "semver": "^7.6.0",
+        "ts-api-utils": "^2.1.0"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "typescript": ">=4.8.4 <6.0.0"
+      }
+    },
+    "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
+      "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^1.0.0"
+      }
+    },
+    "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
+      "version": "9.0.5",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+      "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
+      "version": "7.7.2",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
+      "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
+      "dev": true,
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@typescript-eslint/utils": {
+      "version": "8.44.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.44.1.tgz",
+      "integrity": "sha512-DpX5Fp6edTlocMCwA+mHY8Mra+pPjRZ0TfHkXI8QFelIKcbADQz1LUPNtzOFUriBB2UYqw4Pi9+xV4w9ZczHFg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@eslint-community/eslint-utils": "^4.7.0",
+        "@typescript-eslint/scope-manager": "8.44.1",
+        "@typescript-eslint/types": "8.44.1",
+        "@typescript-eslint/typescript-estree": "8.44.1"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "eslint": "^8.57.0 || ^9.0.0",
+        "typescript": ">=4.8.4 <6.0.0"
+      }
+    },
+    "node_modules/@typescript-eslint/visitor-keys": {
+      "version": "8.44.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.44.1.tgz",
+      "integrity": "sha512-576+u0QD+Jp3tZzvfRfxon0EA2lzcDt3lhUbsC6Lgzy9x2VR4E+JUiNyGHi5T8vk0TV+fpJ5GLG1JsJuWCaKhw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/types": "8.44.1",
+        "eslint-visitor-keys": "^4.2.1"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      }
+    },
+    "node_modules/@vitejs/plugin-react": {
+      "version": "5.0.3",
+      "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.0.3.tgz",
+      "integrity": "sha512-PFVHhosKkofGH0Yzrw1BipSedTH68BFF8ZWy1kfUpCtJcouXXY0+racG8sExw7hw0HoX36813ga5o3LTWZ4FUg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/core": "^7.28.4",
+        "@babel/plugin-transform-react-jsx-self": "^7.27.1",
+        "@babel/plugin-transform-react-jsx-source": "^7.27.1",
+        "@rolldown/pluginutils": "1.0.0-beta.35",
+        "@types/babel__core": "^7.20.5",
+        "react-refresh": "^0.17.0"
+      },
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      },
+      "peerDependencies": {
+        "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
+      }
+    },
+    "node_modules/acorn": {
+      "version": "8.15.0",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
+      "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "acorn": "bin/acorn"
+      },
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/acorn-jsx": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+      "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+      "dev": true,
+      "license": "MIT",
+      "peerDependencies": {
+        "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+      }
+    },
+    "node_modules/ajv": {
+      "version": "6.12.6",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+      "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "fast-deep-equal": "^3.1.1",
+        "fast-json-stable-stringify": "^2.0.0",
+        "json-schema-traverse": "^0.4.1",
+        "uri-js": "^4.2.2"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/epoberezkin"
+      }
+    },
+    "node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/argparse": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+      "dev": true,
+      "license": "Python-2.0"
+    },
+    "node_modules/balanced-match": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/baseline-browser-mapping": {
+      "version": "2.8.6",
+      "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.6.tgz",
+      "integrity": "sha512-wrH5NNqren/QMtKUEEJf7z86YjfqW/2uw3IL3/xpqZUC95SSVIFXYQeeGjL6FT/X68IROu6RMehZQS5foy2BXw==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "bin": {
+        "baseline-browser-mapping": "dist/cli.js"
+      }
+    },
+    "node_modules/boostrap": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/boostrap/-/boostrap-2.0.0.tgz",
+      "integrity": "sha512-JEeFMOweKeGXEM9rt95eaVISOkluG9aKcl0jQCETOVH9jynCZxuBZe2oWgcWJpj5wqYWZl625SnW7OgHT2Ineg==",
+      "deprecated": "Package no longer supported. Contact support@npmjs.com for more info.",
+      "license": "ISC"
+    },
+    "node_modules/bootstrap": {
+      "version": "5.3.8",
+      "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.8.tgz",
+      "integrity": "sha512-HP1SZDqaLDPwsNiqRqi5NcP0SSXciX2s9E+RyqJIIqGo+vJeN5AJVM98CXmW/Wux0nQ5L7jeWUdplCEf0Ee+tg==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/twbs"
+        },
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/bootstrap"
+        }
+      ],
+      "license": "MIT",
+      "peerDependencies": {
+        "@popperjs/core": "^2.11.8"
+      }
+    },
+    "node_modules/brace-expansion": {
+      "version": "1.1.12",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+      "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/braces": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+      "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "fill-range": "^7.1.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/browserslist": {
+      "version": "4.26.2",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.2.tgz",
+      "integrity": "sha512-ECFzp6uFOSB+dcZ5BK/IBaGWssbSYBHvuMeMt3MMFyhI0Z8SqGgEkBLARgpRH3hutIgPVsALcMwbDrJqPxQ65A==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "baseline-browser-mapping": "^2.8.3",
+        "caniuse-lite": "^1.0.30001741",
+        "electron-to-chromium": "^1.5.218",
+        "node-releases": "^2.0.21",
+        "update-browserslist-db": "^1.1.3"
+      },
+      "bin": {
+        "browserslist": "cli.js"
+      },
+      "engines": {
+        "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+      }
+    },
+    "node_modules/callsites": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+      "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/caniuse-lite": {
+      "version": "1.0.30001743",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001743.tgz",
+      "integrity": "sha512-e6Ojr7RV14Un7dz6ASD0aZDmQPT/A+eZU+nuTNfjqmRrmkmQlnTNWH0SKmqagx9PeW87UVqapSurtAXifmtdmw==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "CC-BY-4.0"
+    },
+    "node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/classnames": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
+      "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==",
+      "license": "MIT"
+    },
+    "node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/convert-source-map": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+      "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/cookie": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
+      "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/cross-spawn": {
+      "version": "7.0.6",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+      "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "path-key": "^3.1.0",
+        "shebang-command": "^2.0.0",
+        "which": "^2.0.1"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/csstype": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
+      "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
+      "license": "MIT"
+    },
+    "node_modules/debug": {
+      "version": "4.4.3",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+      "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ms": "^2.1.3"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/deep-is": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+      "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/dequal": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
+      "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/dom-helpers": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
+      "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.8.7",
+        "csstype": "^3.0.2"
+      }
+    },
+    "node_modules/electron-to-chromium": {
+      "version": "1.5.223",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.223.tgz",
+      "integrity": "sha512-qKm55ic6nbEmagFlTFczML33rF90aU+WtrJ9MdTCThrcvDNdUHN4p6QfVN78U06ZmguqXIyMPyYhw2TrbDUwPQ==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/esbuild": {
+      "version": "0.25.10",
+      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.10.tgz",
+      "integrity": "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==",
+      "dev": true,
+      "hasInstallScript": true,
+      "license": "MIT",
+      "bin": {
+        "esbuild": "bin/esbuild"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "optionalDependencies": {
+        "@esbuild/aix-ppc64": "0.25.10",
+        "@esbuild/android-arm": "0.25.10",
+        "@esbuild/android-arm64": "0.25.10",
+        "@esbuild/android-x64": "0.25.10",
+        "@esbuild/darwin-arm64": "0.25.10",
+        "@esbuild/darwin-x64": "0.25.10",
+        "@esbuild/freebsd-arm64": "0.25.10",
+        "@esbuild/freebsd-x64": "0.25.10",
+        "@esbuild/linux-arm": "0.25.10",
+        "@esbuild/linux-arm64": "0.25.10",
+        "@esbuild/linux-ia32": "0.25.10",
+        "@esbuild/linux-loong64": "0.25.10",
+        "@esbuild/linux-mips64el": "0.25.10",
+        "@esbuild/linux-ppc64": "0.25.10",
+        "@esbuild/linux-riscv64": "0.25.10",
+        "@esbuild/linux-s390x": "0.25.10",
+        "@esbuild/linux-x64": "0.25.10",
+        "@esbuild/netbsd-arm64": "0.25.10",
+        "@esbuild/netbsd-x64": "0.25.10",
+        "@esbuild/openbsd-arm64": "0.25.10",
+        "@esbuild/openbsd-x64": "0.25.10",
+        "@esbuild/openharmony-arm64": "0.25.10",
+        "@esbuild/sunos-x64": "0.25.10",
+        "@esbuild/win32-arm64": "0.25.10",
+        "@esbuild/win32-ia32": "0.25.10",
+        "@esbuild/win32-x64": "0.25.10"
+      }
+    },
+    "node_modules/escalade": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+      "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/escape-string-regexp": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+      "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/eslint": {
+      "version": "9.36.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.36.0.tgz",
+      "integrity": "sha512-hB4FIzXovouYzwzECDcUkJ4OcfOEkXTv2zRY6B9bkwjx/cprAq0uvm1nl7zvQ0/TsUk0zQiN4uPfJpB9m+rPMQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@eslint-community/eslint-utils": "^4.8.0",
+        "@eslint-community/regexpp": "^4.12.1",
+        "@eslint/config-array": "^0.21.0",
+        "@eslint/config-helpers": "^0.3.1",
+        "@eslint/core": "^0.15.2",
+        "@eslint/eslintrc": "^3.3.1",
+        "@eslint/js": "9.36.0",
+        "@eslint/plugin-kit": "^0.3.5",
+        "@humanfs/node": "^0.16.6",
+        "@humanwhocodes/module-importer": "^1.0.1",
+        "@humanwhocodes/retry": "^0.4.2",
+        "@types/estree": "^1.0.6",
+        "@types/json-schema": "^7.0.15",
+        "ajv": "^6.12.4",
+        "chalk": "^4.0.0",
+        "cross-spawn": "^7.0.6",
+        "debug": "^4.3.2",
+        "escape-string-regexp": "^4.0.0",
+        "eslint-scope": "^8.4.0",
+        "eslint-visitor-keys": "^4.2.1",
+        "espree": "^10.4.0",
+        "esquery": "^1.5.0",
+        "esutils": "^2.0.2",
+        "fast-deep-equal": "^3.1.3",
+        "file-entry-cache": "^8.0.0",
+        "find-up": "^5.0.0",
+        "glob-parent": "^6.0.2",
+        "ignore": "^5.2.0",
+        "imurmurhash": "^0.1.4",
+        "is-glob": "^4.0.0",
+        "json-stable-stringify-without-jsonify": "^1.0.1",
+        "lodash.merge": "^4.6.2",
+        "minimatch": "^3.1.2",
+        "natural-compare": "^1.4.0",
+        "optionator": "^0.9.3"
+      },
+      "bin": {
+        "eslint": "bin/eslint.js"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "url": "https://eslint.org/donate"
+      },
+      "peerDependencies": {
+        "jiti": "*"
+      },
+      "peerDependenciesMeta": {
+        "jiti": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/eslint-plugin-react-hooks": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz",
+      "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "peerDependencies": {
+        "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0"
+      }
+    },
+    "node_modules/eslint-plugin-react-refresh": {
+      "version": "0.4.21",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.21.tgz",
+      "integrity": "sha512-MWDWTtNC4voTcWDxXbdmBNe8b/TxfxRFUL6hXgKWJjN9c1AagYEmpiFWBWzDw+5H3SulWUe1pJKTnoSdmk88UA==",
+      "dev": true,
+      "license": "MIT",
+      "peerDependencies": {
+        "eslint": ">=8.40"
+      }
+    },
+    "node_modules/eslint-scope": {
+      "version": "8.4.0",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
+      "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "esrecurse": "^4.3.0",
+        "estraverse": "^5.2.0"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/eslint-visitor-keys": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
+      "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/espree": {
+      "version": "10.4.0",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
+      "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "acorn": "^8.15.0",
+        "acorn-jsx": "^5.3.2",
+        "eslint-visitor-keys": "^4.2.1"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/esquery": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
+      "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "estraverse": "^5.1.0"
+      },
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/esrecurse": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+      "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "estraverse": "^5.2.0"
+      },
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/estraverse": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+      "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/esutils": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+      "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/fast-deep-equal": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+      "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/fast-glob": {
+      "version": "3.3.3",
+      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
+      "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@nodelib/fs.stat": "^2.0.2",
+        "@nodelib/fs.walk": "^1.2.3",
+        "glob-parent": "^5.1.2",
+        "merge2": "^1.3.0",
+        "micromatch": "^4.0.8"
+      },
+      "engines": {
+        "node": ">=8.6.0"
+      }
+    },
+    "node_modules/fast-glob/node_modules/glob-parent": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "is-glob": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/fast-json-stable-stringify": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+      "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/fast-levenshtein": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+      "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/fastq": {
+      "version": "1.19.1",
+      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
+      "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "reusify": "^1.0.4"
+      }
+    },
+    "node_modules/file-entry-cache": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
+      "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "flat-cache": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=16.0.0"
+      }
+    },
+    "node_modules/fill-range": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+      "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "to-regex-range": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/find-up": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+      "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "locate-path": "^6.0.0",
+        "path-exists": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/flat-cache": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
+      "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "flatted": "^3.2.9",
+        "keyv": "^4.5.4"
+      },
+      "engines": {
+        "node": ">=16"
+      }
+    },
+    "node_modules/flatted": {
+      "version": "3.3.3",
+      "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
+      "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/fsevents": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+      "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+      "dev": true,
+      "hasInstallScript": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+      }
+    },
+    "node_modules/gensync": {
+      "version": "1.0.0-beta.2",
+      "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+      "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/glob-parent": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+      "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "is-glob": "^4.0.3"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
+    "node_modules/globals": {
+      "version": "16.4.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz",
+      "integrity": "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/graphemer": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
+      "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/ignore": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+      "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 4"
+      }
+    },
+    "node_modules/import-fresh": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
+      "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "parent-module": "^1.0.0",
+        "resolve-from": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/imurmurhash": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+      "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.8.19"
+      }
+    },
+    "node_modules/invariant": {
+      "version": "2.2.4",
+      "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
+      "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
+      "license": "MIT",
+      "dependencies": {
+        "loose-envify": "^1.0.0"
+      }
+    },
+    "node_modules/is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-glob": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-extglob": "^2.1.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-number": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.12.0"
+      }
+    },
+    "node_modules/isexe": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+      "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/js-tokens": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+      "license": "MIT"
+    },
+    "node_modules/js-yaml": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+      "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "argparse": "^2.0.1"
+      },
+      "bin": {
+        "js-yaml": "bin/js-yaml.js"
+      }
+    },
+    "node_modules/jsesc": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+      "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "jsesc": "bin/jsesc"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/json-buffer": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+      "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/json-schema-traverse": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+      "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/json-stable-stringify-without-jsonify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+      "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/json5": {
+      "version": "2.2.3",
+      "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+      "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "json5": "lib/cli.js"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/keyv": {
+      "version": "4.5.4",
+      "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+      "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "json-buffer": "3.0.1"
+      }
+    },
+    "node_modules/levn": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+      "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "prelude-ls": "^1.2.1",
+        "type-check": "~0.4.0"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/locate-path": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+      "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "p-locate": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/lodash.merge": {
+      "version": "4.6.2",
+      "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+      "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/loose-envify": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+      "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+      "license": "MIT",
+      "dependencies": {
+        "js-tokens": "^3.0.0 || ^4.0.0"
+      },
+      "bin": {
+        "loose-envify": "cli.js"
+      }
+    },
+    "node_modules/lru-cache": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+      "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "yallist": "^3.0.2"
+      }
+    },
+    "node_modules/merge2": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+      "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/micromatch": {
+      "version": "4.0.8",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+      "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "braces": "^3.0.3",
+        "picomatch": "^2.3.1"
+      },
+      "engines": {
+        "node": ">=8.6"
+      }
+    },
+    "node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/ms": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/nanoid": {
+      "version": "3.3.11",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
+      "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "bin": {
+        "nanoid": "bin/nanoid.cjs"
+      },
+      "engines": {
+        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+      }
+    },
+    "node_modules/natural-compare": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+      "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/node-releases": {
+      "version": "2.0.21",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.21.tgz",
+      "integrity": "sha512-5b0pgg78U3hwXkCM8Z9b2FJdPZlr9Psr9V2gQPESdGHqbntyFJKFW4r5TeWGFzafGY3hzs1JC62VEQMbl1JFkw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/object-assign": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+      "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/optionator": {
+      "version": "0.9.4",
+      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
+      "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "deep-is": "^0.1.3",
+        "fast-levenshtein": "^2.0.6",
+        "levn": "^0.4.1",
+        "prelude-ls": "^1.2.1",
+        "type-check": "^0.4.0",
+        "word-wrap": "^1.2.5"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/p-limit": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+      "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "yocto-queue": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/p-locate": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+      "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "p-limit": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/parent-module": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+      "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "callsites": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/path-exists": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/path-key": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+      "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/picocolors": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+      "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/picomatch": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/postcss": {
+      "version": "8.5.6",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
+      "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/postcss/"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/postcss"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "nanoid": "^3.3.11",
+        "picocolors": "^1.1.1",
+        "source-map-js": "^1.2.1"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >=14"
+      }
+    },
+    "node_modules/prelude-ls": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+      "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/prop-types": {
+      "version": "15.8.1",
+      "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
+      "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
+      "license": "MIT",
+      "dependencies": {
+        "loose-envify": "^1.4.0",
+        "object-assign": "^4.1.1",
+        "react-is": "^16.13.1"
+      }
+    },
+    "node_modules/prop-types-extra": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz",
+      "integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==",
+      "license": "MIT",
+      "dependencies": {
+        "react-is": "^16.3.2",
+        "warning": "^4.0.0"
+      },
+      "peerDependencies": {
+        "react": ">=0.14.0"
+      }
+    },
+    "node_modules/punycode": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+      "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/queue-microtask": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+      "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/react": {
+      "version": "19.1.1",
+      "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz",
+      "integrity": "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/react-bootstrap": {
+      "version": "2.10.10",
+      "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.10.10.tgz",
+      "integrity": "sha512-gMckKUqn8aK/vCnfwoBpBVFUGT9SVQxwsYrp9yDHt0arXMamxALerliKBxr1TPbntirK/HGrUAHYbAeQTa9GHQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.24.7",
+        "@restart/hooks": "^0.4.9",
+        "@restart/ui": "^1.9.4",
+        "@types/prop-types": "^15.7.12",
+        "@types/react-transition-group": "^4.4.6",
+        "classnames": "^2.3.2",
+        "dom-helpers": "^5.2.1",
+        "invariant": "^2.2.4",
+        "prop-types": "^15.8.1",
+        "prop-types-extra": "^1.1.0",
+        "react-transition-group": "^4.4.5",
+        "uncontrollable": "^7.2.1",
+        "warning": "^4.0.3"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.14.8",
+        "react": ">=16.14.0",
+        "react-dom": ">=16.14.0"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/react-dom": {
+      "version": "19.1.1",
+      "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz",
+      "integrity": "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==",
+      "license": "MIT",
+      "dependencies": {
+        "scheduler": "^0.26.0"
+      },
+      "peerDependencies": {
+        "react": "^19.1.1"
+      }
+    },
+    "node_modules/react-is": {
+      "version": "16.13.1",
+      "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+      "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
+      "license": "MIT"
+    },
+    "node_modules/react-lifecycles-compat": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
+      "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==",
+      "license": "MIT"
+    },
+    "node_modules/react-refresh": {
+      "version": "0.17.0",
+      "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz",
+      "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/react-router": {
+      "version": "7.9.2",
+      "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.9.2.tgz",
+      "integrity": "sha512-i2TPp4dgaqrOqiRGLZmqh2WXmbdFknUyiCRmSKs0hf6fWXkTKg5h56b+9F22NbGRAMxjYfqQnpi63egzD2SuZA==",
+      "license": "MIT",
+      "dependencies": {
+        "cookie": "^1.0.1",
+        "set-cookie-parser": "^2.6.0"
+      },
+      "engines": {
+        "node": ">=20.0.0"
+      },
+      "peerDependencies": {
+        "react": ">=18",
+        "react-dom": ">=18"
+      },
+      "peerDependenciesMeta": {
+        "react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/react-transition-group": {
+      "version": "4.4.5",
+      "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
+      "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "@babel/runtime": "^7.5.5",
+        "dom-helpers": "^5.0.1",
+        "loose-envify": "^1.4.0",
+        "prop-types": "^15.6.2"
+      },
+      "peerDependencies": {
+        "react": ">=16.6.0",
+        "react-dom": ">=16.6.0"
+      }
+    },
+    "node_modules/resolve-from": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+      "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/reusify": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
+      "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "iojs": ">=1.0.0",
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/rollup": {
+      "version": "4.52.2",
+      "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.2.tgz",
+      "integrity": "sha512-I25/2QgoROE1vYV+NQ1En9T9UFB9Cmfm2CJ83zZOlaDpvz29wGQSZXWKw7MiNXau7wYgB/T9fVIdIuEQ+KbiiA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree": "1.0.8"
+      },
+      "bin": {
+        "rollup": "dist/bin/rollup"
+      },
+      "engines": {
+        "node": ">=18.0.0",
+        "npm": ">=8.0.0"
+      },
+      "optionalDependencies": {
+        "@rollup/rollup-android-arm-eabi": "4.52.2",
+        "@rollup/rollup-android-arm64": "4.52.2",
+        "@rollup/rollup-darwin-arm64": "4.52.2",
+        "@rollup/rollup-darwin-x64": "4.52.2",
+        "@rollup/rollup-freebsd-arm64": "4.52.2",
+        "@rollup/rollup-freebsd-x64": "4.52.2",
+        "@rollup/rollup-linux-arm-gnueabihf": "4.52.2",
+        "@rollup/rollup-linux-arm-musleabihf": "4.52.2",
+        "@rollup/rollup-linux-arm64-gnu": "4.52.2",
+        "@rollup/rollup-linux-arm64-musl": "4.52.2",
+        "@rollup/rollup-linux-loong64-gnu": "4.52.2",
+        "@rollup/rollup-linux-ppc64-gnu": "4.52.2",
+        "@rollup/rollup-linux-riscv64-gnu": "4.52.2",
+        "@rollup/rollup-linux-riscv64-musl": "4.52.2",
+        "@rollup/rollup-linux-s390x-gnu": "4.52.2",
+        "@rollup/rollup-linux-x64-gnu": "4.52.2",
+        "@rollup/rollup-linux-x64-musl": "4.52.2",
+        "@rollup/rollup-openharmony-arm64": "4.52.2",
+        "@rollup/rollup-win32-arm64-msvc": "4.52.2",
+        "@rollup/rollup-win32-ia32-msvc": "4.52.2",
+        "@rollup/rollup-win32-x64-gnu": "4.52.2",
+        "@rollup/rollup-win32-x64-msvc": "4.52.2",
+        "fsevents": "~2.3.2"
+      }
+    },
+    "node_modules/run-parallel": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+      "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "queue-microtask": "^1.2.2"
+      }
+    },
+    "node_modules/scheduler": {
+      "version": "0.26.0",
+      "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz",
+      "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==",
+      "license": "MIT"
+    },
+    "node_modules/semver": {
+      "version": "6.3.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+      "dev": true,
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/set-cookie-parser": {
+      "version": "2.7.1",
+      "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz",
+      "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==",
+      "license": "MIT"
+    },
+    "node_modules/shebang-command": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+      "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "shebang-regex": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/shebang-regex": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+      "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/source-map-js": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+      "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/strip-json-comments": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+      "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/tinyglobby": {
+      "version": "0.2.15",
+      "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
+      "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "fdir": "^6.5.0",
+        "picomatch": "^4.0.3"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/SuperchupuDev"
+      }
+    },
+    "node_modules/tinyglobby/node_modules/fdir": {
+      "version": "6.5.0",
+      "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+      "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12.0.0"
+      },
+      "peerDependencies": {
+        "picomatch": "^3 || ^4"
+      },
+      "peerDependenciesMeta": {
+        "picomatch": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/tinyglobby/node_modules/picomatch": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
+      "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/to-regex-range": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-number": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=8.0"
+      }
+    },
+    "node_modules/ts-api-utils": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz",
+      "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18.12"
+      },
+      "peerDependencies": {
+        "typescript": ">=4.8.4"
+      }
+    },
+    "node_modules/tslib": {
+      "version": "2.8.1",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+      "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+      "license": "0BSD"
+    },
+    "node_modules/type-check": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+      "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "prelude-ls": "^1.2.1"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/typescript": {
+      "version": "5.8.3",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
+      "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "bin": {
+        "tsc": "bin/tsc",
+        "tsserver": "bin/tsserver"
+      },
+      "engines": {
+        "node": ">=14.17"
+      }
+    },
+    "node_modules/typescript-eslint": {
+      "version": "8.44.1",
+      "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.44.1.tgz",
+      "integrity": "sha512-0ws8uWGrUVTjEeN2OM4K1pLKHK/4NiNP/vz6ns+LjT/6sqpaYzIVFajZb1fj/IDwpsrrHb3Jy0Qm5u9CPcKaeg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/eslint-plugin": "8.44.1",
+        "@typescript-eslint/parser": "8.44.1",
+        "@typescript-eslint/typescript-estree": "8.44.1",
+        "@typescript-eslint/utils": "8.44.1"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "eslint": "^8.57.0 || ^9.0.0",
+        "typescript": ">=4.8.4 <6.0.0"
+      }
+    },
+    "node_modules/uncontrollable": {
+      "version": "7.2.1",
+      "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz",
+      "integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.6.3",
+        "@types/react": ">=16.9.11",
+        "invariant": "^2.2.4",
+        "react-lifecycles-compat": "^3.0.4"
+      },
+      "peerDependencies": {
+        "react": ">=15.0.0"
+      }
+    },
+    "node_modules/update-browserslist-db": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
+      "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "escalade": "^3.2.0",
+        "picocolors": "^1.1.1"
+      },
+      "bin": {
+        "update-browserslist-db": "cli.js"
+      },
+      "peerDependencies": {
+        "browserslist": ">= 4.21.0"
+      }
+    },
+    "node_modules/uri-js": {
+      "version": "4.4.1",
+      "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+      "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "punycode": "^2.1.0"
+      }
+    },
+    "node_modules/vite": {
+      "version": "7.1.7",
+      "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.7.tgz",
+      "integrity": "sha512-VbA8ScMvAISJNJVbRDTJdCwqQoAareR/wutevKanhR2/1EkoXVZVkkORaYm/tNVCjP/UDTKtcw3bAkwOUdedmA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "esbuild": "^0.25.0",
+        "fdir": "^6.5.0",
+        "picomatch": "^4.0.3",
+        "postcss": "^8.5.6",
+        "rollup": "^4.43.0",
+        "tinyglobby": "^0.2.15"
+      },
+      "bin": {
+        "vite": "bin/vite.js"
+      },
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      },
+      "funding": {
+        "url": "https://github.com/vitejs/vite?sponsor=1"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.3"
+      },
+      "peerDependencies": {
+        "@types/node": "^20.19.0 || >=22.12.0",
+        "jiti": ">=1.21.0",
+        "less": "^4.0.0",
+        "lightningcss": "^1.21.0",
+        "sass": "^1.70.0",
+        "sass-embedded": "^1.70.0",
+        "stylus": ">=0.54.8",
+        "sugarss": "^5.0.0",
+        "terser": "^5.16.0",
+        "tsx": "^4.8.1",
+        "yaml": "^2.4.2"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        },
+        "jiti": {
+          "optional": true
+        },
+        "less": {
+          "optional": true
+        },
+        "lightningcss": {
+          "optional": true
+        },
+        "sass": {
+          "optional": true
+        },
+        "sass-embedded": {
+          "optional": true
+        },
+        "stylus": {
+          "optional": true
+        },
+        "sugarss": {
+          "optional": true
+        },
+        "terser": {
+          "optional": true
+        },
+        "tsx": {
+          "optional": true
+        },
+        "yaml": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/vite/node_modules/fdir": {
+      "version": "6.5.0",
+      "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+      "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12.0.0"
+      },
+      "peerDependencies": {
+        "picomatch": "^3 || ^4"
+      },
+      "peerDependenciesMeta": {
+        "picomatch": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/vite/node_modules/picomatch": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
+      "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/warning": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
+      "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
+      "license": "MIT",
+      "dependencies": {
+        "loose-envify": "^1.0.0"
+      }
+    },
+    "node_modules/which": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+      "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "isexe": "^2.0.0"
+      },
+      "bin": {
+        "node-which": "bin/node-which"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/word-wrap": {
+      "version": "1.2.5",
+      "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
+      "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/yallist": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+      "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/yocto-queue": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+      "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    }
+  }
+}
diff -pruN 9.1.1-2/examples/quotes/package.json 9.2.0-1/examples/quotes/package.json
--- 9.1.1-2/examples/quotes/package.json	1970-01-01 00:00:00.000000000 +0000
+++ 9.2.0-1/examples/quotes/package.json	2025-10-28 16:50:53.000000000 +0000
@@ -0,0 +1,36 @@
+{
+  "name": "quotes",
+  "private": true,
+  "version": "0.0.0",
+  "type": "module",
+  "scripts": {
+    "dev": "vite",
+    "build": "tsc -b && vite build",
+    "lint": "eslint .",
+    "preview": "vite preview",
+    "postinstall": "cd backend && python -m venv .venv && .venv/bin/pip install -r requirements.txt",
+    "backend": "cd backend && .venv/bin/uvicorn --port 5000 --reload quotes:app",
+    "ingest": "cd backend && .venv/bin/python quotes.py"
+  },
+  "dependencies": {
+    "boostrap": "^2.0.0",
+    "bootstrap": "^5.3.8",
+    "react": "^19.1.1",
+    "react-bootstrap": "^2.10.10",
+    "react-dom": "^19.1.1",
+    "react-router": "^7.9.2"
+  },
+  "devDependencies": {
+    "@eslint/js": "^9.36.0",
+    "@types/react": "^19.1.13",
+    "@types/react-dom": "^19.1.9",
+    "@vitejs/plugin-react": "^5.0.3",
+    "eslint": "^9.36.0",
+    "eslint-plugin-react-hooks": "^5.2.0",
+    "eslint-plugin-react-refresh": "^0.4.20",
+    "globals": "^16.4.0",
+    "typescript": "~5.8.3",
+    "typescript-eslint": "^8.44.0",
+    "vite": "^7.1.7"
+  }
+}
Binary files 9.1.1-2/examples/quotes/screenshot.png and 9.2.0-1/examples/quotes/screenshot.png differ
diff -pruN 9.1.1-2/examples/quotes/src/App.tsx 9.2.0-1/examples/quotes/src/App.tsx
--- 9.1.1-2/examples/quotes/src/App.tsx	1970-01-01 00:00:00.000000000 +0000
+++ 9.2.0-1/examples/quotes/src/App.tsx	2025-10-28 16:50:53.000000000 +0000
@@ -0,0 +1,172 @@
+import React, { useRef, useState, useEffect } from 'react';
+import Container from 'react-bootstrap/Container';
+import { NavLink } from 'react-router';
+import Row from 'react-bootstrap/Row';
+import Col from 'react-bootstrap/Col';
+import Form from 'react-bootstrap/Form';
+import Button from 'react-bootstrap/Button';
+import Spinner from 'react-bootstrap/Spinner';
+import Stack from 'react-bootstrap/Stack';
+import CloseButton from 'react-bootstrap/CloseButton';
+import ToggleButton from 'react-bootstrap/ToggleButton';
+import Pagination from 'react-bootstrap/Pagination';
+import type { Quote, Tag } from './models';
+
+export default function App() {
+  const inputRef = useRef<HTMLInputElement>(null);
+  const [knn, setKnn] = useState<boolean>(true);
+  const [query, setQuery] = useState<string>('');
+  const [filters, setFilters] = useState<string[]>([]);
+  const [tags, setTags] = useState<Tag[] | null>([]);
+  const [results, setResults] = useState<Quote[] | null>(null);
+  const [start, setStart] = useState<number>(0);
+  const [total, setTotal] = useState<number>(0);
+
+  useEffect(() => {
+    if (inputRef.current) {
+      inputRef.current.value = query;
+    }
+  }, [query]);
+    
+  const onSearch = (ev: React.FormEvent) => {
+    ev.preventDefault();
+    setQuery(inputRef.current?.value || '');
+    setStart(0);
+  };
+    
+  const onResetQuery = () => {
+    setQuery('');
+    setStart(0);
+    setTags(null);
+    setResults(null);
+    inputRef.current?.focus();
+  };
+
+  const onResetFilters = () => {
+    setFilters([]);
+    setStart(0);
+    setTags(null);
+    setResults(null);
+    inputRef.current?.focus();
+  };
+
+  const onFilter = ({tag, count}: Tag) => {
+    setFilters([...filters, tag]);
+    setStart(0);
+    setTags(null);
+    setResults(null);
+  };
+
+  useEffect(() => {
+    (async () => {
+      const response = await fetch('/api/search', {
+        method: 'POST',
+        headers: {'Content-Type': 'application/json'},
+        body: JSON.stringify({query, filters, knn, start}),
+      });
+      const data: {quotes: Quote[], tags: Tag[], start: number, total: number} = await response.json();
+      setResults(data.quotes);
+      setTags(data.tags.filter(tag => !filters.includes(tag.tag)));
+      setStart(data.start);
+      setTotal(data.total);
+      window.scrollTo(0, 0);
+    })()
+  }, [query, filters, knn, start, total]);
+
+  return (
+    <Container fluid="md" className="App">
+      <Row>
+        <h1>Elasticsearch + Pydantic Demo</h1>
+        <Form onSubmit={onSearch} className="SearchForm">
+          <Stack direction="horizontal" gap={2}>
+            <Form.Control type="text" placeholder="Search for... ?" ref={inputRef} autoFocus={true} />
+            <CloseButton onClick={onResetQuery} disabled={query === ''} />
+            <ToggleButton id="knn" type="checkbox" variant="outline-secondary" checked={knn} value="1" title={knn ? "Using hybrid search" : "Using full-text search"} onChange={e => setKnn(e.currentTarget.checked)}>
+              <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M192.5,171.47A88.34,88.34,0,0,0,224,101.93c-1-45.71-37.61-83.4-83.24-85.8A88,88,0,0,0,48,102L25.55,145.18c-.09.18-.18.36-.26.54a16,16,0,0,0,7.55,20.62l.25.11L56,176.94V208a16,16,0,0,0,16,16h48a8,8,0,0,0,0-16H72V171.81a8,8,0,0,0-4.67-7.28L40,152l23.07-44.34A7.9,7.9,0,0,0,64,104a72,72,0,0,1,56-70.21V49.38a24,24,0,1,0,16,0V32c1.3,0,2.6,0,3.9.1A72.26,72.26,0,0,1,203.84,80H184a8,8,0,0,0-6.15,2.88L152.34,113.5a24.06,24.06,0,1,0,12.28,10.25L187.75,96h19.79q.36,3.12.44,6.3a72.26,72.26,0,0,1-28.78,59.3,8,8,0,0,0-3.14,7.39l8,64a8,8,0,0,0,7.93,7,8.39,8.39,0,0,0,1-.06,8,8,0,0,0,6.95-8.93ZM128,80a8,8,0,1,1,8-8A8,8,0,0,1,128,80Zm16,64a8,8,0,1,1,8-8A8,8,0,0,1,144,144Z"></path></svg>
+            </ToggleButton>
+            <NavLink to="/quotes/new" className="btn btn-primary">New&nbsp;Quote</NavLink>
+          </Stack>
+        </Form>
+      </Row>
+      <Row>
+        <Col md={3} className="Tags">
+          <>
+            {filters != null && (
+              <>
+                {filters.map(tag => (
+                  <div key={tag} className="Filter">
+                    » {tag}
+                  </div>
+                ))}
+                {(filters.length > 0) && (
+                  <>
+                    <Button variant="link" onClick={onResetFilters}>Reset</Button>
+                    <hr />
+                  </>
+                )}
+              </>
+            )}
+            {(tags === null) ?
+              <Spinner animation="border" role="status">
+                <span className="visually-hidden">Loading...</span>
+              </Spinner>
+            :
+              <>
+                {(tags.length === 0) ?
+                  <p>No tags.</p>
+                :
+                  <>
+                    {tags.map(({tag, count}) => (
+                      <div key={tag} className="Tag">
+                        <Button variant="link" onClick={() => onFilter({tag, count})}>{tag}</Button> ({count})
+                      </div>
+                    ))}
+                  </>
+                }
+              </>
+            }
+          </>
+        </Col>
+        <Col md={9} className="Results">
+          {(results === null) ?
+            <Spinner animation="border" role="status">
+              <span className="visually-hidden">Loading...</span>
+            </Spinner>
+          :
+            <>
+              {(results.length === 0) ?
+                <p>No results. Sorry!</p>
+              :
+                <>
+                  <p className="Summary">Showing results {start + 1}-{start + results.length} of {total}.</p>
+                  {results.map(({quote, author, tags, meta}, index) => (
+                    <div key={index} className="Result">
+                      <p>
+                        <span className="ResultQuote">{quote}</span> — <span className="ResultAuthor">{author}</span>
+                        <br />
+                        <span className="ResultScore">[Score: {meta.score}]</span> <span className="ResultTags">{tags.map(tag => `#${tag}`).join(', ')}</span>
+                        <br />
+                        <small><NavLink to={`/quotes/${meta.id}`}>Edit</NavLink></small>
+                      </p>
+                    </div>
+                  ))}
+                </>
+              }
+              <Pagination>
+                {start > 0 && 
+                  <>
+                    <Pagination.First onClick={() => setStart(0)} />
+                    <Pagination.Prev onClick={() => setStart(start - results.length)} />
+                  </>
+                }
+                {results.length > 0 && start + results.length < total &&
+                  <Pagination.Next onClick={() => setStart(start + results.length)} />
+                }
+              </Pagination>
+            </>
+          }
+        </Col>
+      </Row>
+    </Container>
+  );
+}
diff -pruN 9.1.1-2/examples/quotes/src/Quote.tsx 9.2.0-1/examples/quotes/src/Quote.tsx
--- 9.1.1-2/examples/quotes/src/Quote.tsx	1970-01-01 00:00:00.000000000 +0000
+++ 9.2.0-1/examples/quotes/src/Quote.tsx	2025-10-28 16:50:53.000000000 +0000
@@ -0,0 +1,104 @@
+import { useState, useEffect, useRef } from 'react';
+import type { MouseEvent } from 'react';
+import { useParams, NavLink, useNavigate } from 'react-router';
+import Container from 'react-bootstrap/Container';
+import Stack from 'react-bootstrap/Stack';
+import Form from 'react-bootstrap/Form';
+import Button from 'react-bootstrap/Button';
+import Toast from 'react-bootstrap/Toast';
+import ToastContainer from 'react-bootstrap/ToastContainer';
+import type { Quote } from './models';
+
+export default function Quote() {
+  const [quote, setQuote] = useState<Quote | null | undefined>(undefined);
+  const [status, setStatus] = useState<str>("");
+  const params = useParams();
+  const navigate = useNavigate();
+  const quoteField = useRef<HTMLInputElement>(null);
+  const authorField = useRef<HTMLInputElement>(null);
+  const tagsField = useRef<HTMLInputElement>(null);
+
+  useEffect(() => {
+    (async () => {
+      const response = await fetch(`/api/quotes/${params.id}`);
+      const data = await response.json();
+      setQuote(data);
+    })();
+  }, []);
+
+  const onSubmit = async (ev: MouseEvent<HTMLElement>) => {
+    ev.preventDefault();
+    if (quote) {
+      quote.quote = quoteField.current?.value ?? '';
+      quote.author = authorField.current?.value ?? '';
+      quote.tags = (tagsField.current?.value ?? "").split(',');
+      let url = '/api/quotes';
+      let method = 'POST';
+      if (params.id !== 'new') {
+        url += `/${params.id}`;
+        method = 'PUT';
+      }
+      const response = await fetch(url, {
+        method: method,
+        headers: {'Content-Type': 'application/json'},
+        body: JSON.stringify(quote),
+      });
+      if (response.status == 200 || response.status == 201) {
+        const data = await response.json();
+        navigate(`/quotes/${data.meta.id}`);
+      }
+      else {
+        setStatus('Save error');
+      }
+    }
+  };
+
+  const onDelete = async (ev: MouseEvent<HTMLElement>) => {
+    ev.preventDefault();
+    const response = await fetch(`/api/quotes/${params.id}`, {
+      method: 'DELETE',
+    });
+    if (response.status == 204) {
+      navigate('/');
+    }
+    else {
+      setStatus('Delete error');
+    }
+  };
+
+  return (
+    <Container fluid="md" className="App">
+      <h1>Elasticsearch + Pydantic Demo</h1>
+      <Form className="position-relative">
+        <ToastContainer position="top-end">
+          <Toast bg="primary" onClose={() => setStatus('')} show={status != ''} delay={3000} autohide>
+            <Toast.Body className="text-white">{status}</Toast.Body>
+          </Toast>
+        </ToastContainer>
+        <Form.Group className="mb-3" controlId="formQuote">
+          <Form.Label>Quote</Form.Label>
+          <Form.Control ref={quoteField} type="text" placeholder="Enter quote" defaultValue={quote?.quote} />
+        </Form.Group>
+        <Form.Group className="mb-3" controlId="formAuthor">
+          <Form.Label>Author</Form.Label>
+          <Form.Control ref={authorField} type="text" placeholder="Enter author" defaultValue={quote?.author} />
+        </Form.Group>
+        <Form.Group className="mb-3" controlId="formAuthor">
+          <Form.Label>Tags</Form.Label>
+          <Form.Control ref={tagsField} type="text" placeholder="Enter tags" defaultValue={quote?.tags} />
+        </Form.Group>
+        <Stack direction="horizontal" gap={2}>
+          <Button variant="primary" type="submit" onClick={onSubmit}>
+            {params.id === 'new' ? 'Save' : 'Update'}
+          </Button>
+          {params.id !== 'new' &&
+            <Button variant="danger" type="submit" onClick={onDelete}>
+              Delete
+            </Button>
+          }
+          <NavLink className="btn btn-secondary" to="/">Back</NavLink>        
+        </Stack>
+      </Form>
+    </Container>
+  );
+}
diff -pruN 9.1.1-2/examples/quotes/src/index.css 9.2.0-1/examples/quotes/src/index.css
--- 9.1.1-2/examples/quotes/src/index.css	1970-01-01 00:00:00.000000000 +0000
+++ 9.2.0-1/examples/quotes/src/index.css	2025-10-28 16:50:53.000000000 +0000
@@ -0,0 +1,55 @@
+body {
+  margin: 0;
+  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
+    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
+    sans-serif;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+code {
+  font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
+    monospace;
+}
+
+.SearchForm {
+  margin-bottom: 25px;
+}
+
+.Tags {
+  margin-top: 10px;
+}
+
+.Results {
+  margin-top: 10px;
+}
+
+.Results .Summary {
+  font-size: 0.9em;
+  font-style: italic;
+}
+
+.Filter {
+  font-style: italic;
+}
+
+.Tags button {
+  padding: 0px;
+}
+
+.ResultQuote {
+  font-weight: bold;
+}
+
+.ResultAuthor {
+}
+
+.ResultScore {
+  font-size: 0.8em;
+}
+
+.ResultTags {
+  font-size: 0.8em;
+  font-style: italic;
+}
+
diff -pruN 9.1.1-2/examples/quotes/src/main.tsx 9.2.0-1/examples/quotes/src/main.tsx
--- 9.1.1-2/examples/quotes/src/main.tsx	1970-01-01 00:00:00.000000000 +0000
+++ 9.2.0-1/examples/quotes/src/main.tsx	2025-10-28 16:50:53.000000000 +0000
@@ -0,0 +1,24 @@
+import { StrictMode } from 'react'
+import { createRoot } from 'react-dom/client'
+import { createBrowserRouter, RouterProvider } from 'react-router';
+import 'bootstrap/dist/css/bootstrap.min.css';
+import './index.css'
+import App from './App.tsx'
+import Quote from './Quote.tsx'
+
+const router = createBrowserRouter([
+  {
+    path: '/',
+    element: <App />,
+  },
+  {
+    path: '/quotes/:id',
+    element: <Quote />,
+  },
+]);
+
+createRoot(document.getElementById('root')!).render(
+  <StrictMode>
+    <RouterProvider router={router} />
+  </StrictMode>,
+)
diff -pruN 9.1.1-2/examples/quotes/src/models.tsx 9.2.0-1/examples/quotes/src/models.tsx
--- 9.1.1-2/examples/quotes/src/models.tsx	1970-01-01 00:00:00.000000000 +0000
+++ 9.2.0-1/examples/quotes/src/models.tsx	2025-10-28 16:50:53.000000000 +0000
@@ -0,0 +1,16 @@
+export interface Meta {
+  id: string;
+  score: number;
+}
+
+export interface Quote {
+  meta: Meta;
+  quote: string;
+  author: string;
+  tags: string[];
+};
+
+export interface Tag {
+  tag: string;
+  count: number;
+};
diff -pruN 9.1.1-2/examples/quotes/tsconfig.app.json 9.2.0-1/examples/quotes/tsconfig.app.json
--- 9.1.1-2/examples/quotes/tsconfig.app.json	1970-01-01 00:00:00.000000000 +0000
+++ 9.2.0-1/examples/quotes/tsconfig.app.json	2025-10-28 16:50:53.000000000 +0000
@@ -0,0 +1,28 @@
+{
+  "compilerOptions": {
+    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
+    "target": "ES2022",
+    "useDefineForClassFields": true,
+    "lib": ["ES2022", "DOM", "DOM.Iterable"],
+    "module": "ESNext",
+    "types": ["vite/client"],
+    "skipLibCheck": true,
+
+    /* Bundler mode */
+    "moduleResolution": "bundler",
+    "allowImportingTsExtensions": true,
+    "verbatimModuleSyntax": true,
+    "moduleDetection": "force",
+    "noEmit": true,
+    "jsx": "react-jsx",
+
+    /* Linting */
+    "strict": true,
+    "noUnusedLocals": true,
+    "noUnusedParameters": true,
+    "erasableSyntaxOnly": true,
+    "noFallthroughCasesInSwitch": true,
+    "noUncheckedSideEffectImports": true
+  },
+  "include": ["src"]
+}
diff -pruN 9.1.1-2/examples/quotes/tsconfig.json 9.2.0-1/examples/quotes/tsconfig.json
--- 9.1.1-2/examples/quotes/tsconfig.json	1970-01-01 00:00:00.000000000 +0000
+++ 9.2.0-1/examples/quotes/tsconfig.json	2025-10-28 16:50:53.000000000 +0000
@@ -0,0 +1,7 @@
+{
+  "files": [],
+  "references": [
+    { "path": "./tsconfig.app.json" },
+    { "path": "./tsconfig.node.json" }
+  ]
+}
diff -pruN 9.1.1-2/examples/quotes/tsconfig.node.json 9.2.0-1/examples/quotes/tsconfig.node.json
--- 9.1.1-2/examples/quotes/tsconfig.node.json	1970-01-01 00:00:00.000000000 +0000
+++ 9.2.0-1/examples/quotes/tsconfig.node.json	2025-10-28 16:50:53.000000000 +0000
@@ -0,0 +1,26 @@
+{
+  "compilerOptions": {
+    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
+    "target": "ES2023",
+    "lib": ["ES2023"],
+    "module": "ESNext",
+    "types": [],
+    "skipLibCheck": true,
+
+    /* Bundler mode */
+    "moduleResolution": "bundler",
+    "allowImportingTsExtensions": true,
+    "verbatimModuleSyntax": true,
+    "moduleDetection": "force",
+    "noEmit": true,
+
+    /* Linting */
+    "strict": true,
+    "noUnusedLocals": true,
+    "noUnusedParameters": true,
+    "erasableSyntaxOnly": true,
+    "noFallthroughCasesInSwitch": true,
+    "noUncheckedSideEffectImports": true
+  },
+  "include": ["vite.config.ts"]
+}
diff -pruN 9.1.1-2/examples/quotes/vite.config.ts 9.2.0-1/examples/quotes/vite.config.ts
--- 9.1.1-2/examples/quotes/vite.config.ts	1970-01-01 00:00:00.000000000 +0000
+++ 9.2.0-1/examples/quotes/vite.config.ts	2025-10-28 16:50:53.000000000 +0000
@@ -0,0 +1,15 @@
+import { defineConfig } from 'vite'
+import react from '@vitejs/plugin-react'
+
+// https://vite.dev/config/
+export default defineConfig({
+  plugins: [react()],
+  server: {
+    proxy: {
+      '/api': 'http://localhost:5000',
+      '/docs': 'http://localhost:5000',
+      '/redoc': 'http://localhost:5000',
+      '/openapi.json': 'http://localhost:5000',
+    },
+  },
+})
diff -pruN 9.1.1-2/noxfile.py 9.2.0-1/noxfile.py
--- 9.1.1-2/noxfile.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/noxfile.py	2025-10-28 16:50:53.000000000 +0000
@@ -44,14 +44,14 @@ def pytest_argv():
     ]
 
 
-@nox.session(python=["3.9", "3.10", "3.11", "3.12", "3.13"])
+@nox.session(python=["3.10", "3.11", "3.12", "3.13", "3.14"])
 def test(session):
     session.install("-e", ".[dev]", env=INSTALL_ENV, silent=False)
 
     session.run(*pytest_argv(), *session.posargs)
 
 
-@nox.session(python=["3.9", "3.13"])
+@nox.session(python=["3.10", "3.14"])
 def test_otel(session):
     session.install(
         ".[dev]",
@@ -90,6 +90,7 @@ def lint(session):
         "flake8",
         "black~=25.0",
         "mypy",
+        "pydantic",
         "isort~=6.0",
         "types-requests",
         "types-python-dateutil",
diff -pruN 9.1.1-2/pyproject.toml 9.2.0-1/pyproject.toml
--- 9.1.1-2/pyproject.toml	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/pyproject.toml	2025-10-28 16:50:53.000000000 +0000
@@ -7,7 +7,7 @@ name = "elasticsearch"
 description = "Python client for Elasticsearch"
 readme = "README.md"
 license = "Apache-2.0"
-requires-python = ">=3.9"
+requires-python = ">=3.10"
 authors = [
     { name = "Elastic Client Library Maintainers", email = "client-libs@elastic.co" },
 ]
@@ -21,7 +21,6 @@ classifiers = [
     "Operating System :: OS Independent",
     "Programming Language :: Python",
     "Programming Language :: Python :: 3",
-    "Programming Language :: Python :: 3.9",
     "Programming Language :: Python :: 3.10",
     "Programming Language :: Python :: 3.11",
     "Programming Language :: Python :: 3.12",
@@ -41,9 +40,11 @@ keywords = [
 ]
 dynamic = ["version"]
 dependencies = [
-    "elastic-transport>=9.1.0,<10",
+    "elastic-transport>=9.2.0,<10",
     "python-dateutil",
     "typing-extensions",
+    "sniffio",
+    "anyio",
 ]
 
 [project.optional-dependencies]
@@ -56,6 +57,7 @@ vectorstore_mmr = ["numpy>=1", "simsimd>
 dev = [
     "requests>=2, <3",
     "aiohttp",
+    "httpx",
     "pytest",
     "pytest-cov",
     "pytest-mock",
@@ -65,6 +67,7 @@ dev = [
     "python-dateutil",
     "unasync",
     "pyyaml>=5.4",
+    "pydantic",
     "isort",
     "black",
     "twine",
@@ -73,11 +76,12 @@ dev = [
     "orjson",
     "numpy",
     "simsimd",
-    "pyarrow",
+    "pyarrow; python_version<'3.14'",
     "pandas",
     "mapbox-vector-tile",
     "jinja2",
     "tqdm",
+    "trio",
     "mypy",
     "pyright",
     "types-python-dateutil",
@@ -97,7 +101,7 @@ Homepage = "https://github.com/elastic/e
 
 [tool.hatch.version]
 path = "elasticsearch/_version.py"
-pattern = "__versionstr__ = \"(?P<version>[^']+)\""
+pattern = "__versionstr__ = \"(?P<version>[^']+?)\""
 
 [tool.hatch.build.targets.sdist]
 include = [
@@ -136,4 +140,5 @@ exclude_lines = [
 ]
 
 [tool.mypy]
+plugins = ["pydantic.mypy"]
 ignore_missing_imports = true
diff -pruN 9.1.1-2/test_elasticsearch/test_async/test_server/conftest.py 9.2.0-1/test_elasticsearch/test_async/test_server/conftest.py
--- 9.1.1-2/test_elasticsearch/test_async/test_server/conftest.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/test_elasticsearch/test_async/test_server/conftest.py	2025-10-28 16:50:53.000000000 +0000
@@ -16,27 +16,26 @@
 #  under the License.
 
 import pytest
-import pytest_asyncio
+import sniffio
 
 import elasticsearch
 
 from ...utils import CA_CERTS, wipe_cluster
 
-pytestmark = pytest.mark.asyncio
 
-
-@pytest_asyncio.fixture(scope="function")
+@pytest.fixture(scope="function")
 async def async_client_factory(elasticsearch_url):
-
-    if not hasattr(elasticsearch, "AsyncElasticsearch"):
-        pytest.skip("test requires 'AsyncElasticsearch' and aiohttp to be installed")
-
+    kwargs = {}
+    if sniffio.current_async_library() == "trio":
+        kwargs["node_class"] = "httpxasync"
     # Unfortunately the asyncio client needs to be rebuilt every
     # test execution due to how pytest-asyncio manages
     # event loops (one per test!)
     client = None
     try:
-        client = elasticsearch.AsyncElasticsearch(elasticsearch_url, ca_certs=CA_CERTS)
+        client = elasticsearch.AsyncElasticsearch(
+            elasticsearch_url, ca_certs=CA_CERTS, **kwargs
+        )
         yield client
     finally:
         if client:
diff -pruN 9.1.1-2/test_elasticsearch/test_async/test_server/test_clients.py 9.2.0-1/test_elasticsearch/test_async/test_server/test_clients.py
--- 9.1.1-2/test_elasticsearch/test_async/test_server/test_clients.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/test_elasticsearch/test_async/test_server/test_clients.py	2025-10-28 16:50:53.000000000 +0000
@@ -18,7 +18,7 @@
 
 import pytest
 
-pytestmark = pytest.mark.asyncio
+pytestmark = pytest.mark.anyio
 
 
 @pytest.mark.parametrize("kwargs", [{"body": {"text": "привет"}}, {"text": "привет"}])
diff -pruN 9.1.1-2/test_elasticsearch/test_async/test_server/test_helpers.py 9.2.0-1/test_elasticsearch/test_async/test_server/test_helpers.py
--- 9.1.1-2/test_elasticsearch/test_async/test_server/test_helpers.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/test_elasticsearch/test_async/test_server/test_helpers.py	2025-10-28 16:50:53.000000000 +0000
@@ -15,20 +15,20 @@
 #  specific language governing permissions and limitations
 #  under the License.
 
-import asyncio
 import logging
+import time
 from datetime import datetime, timedelta, timezone
 from unittest.mock import MagicMock, call, patch
 
+import anyio
 import pytest
-import pytest_asyncio
 from elastic_transport import ApiResponseMeta, ObjectApiResponse
 
 from elasticsearch import helpers
 from elasticsearch.exceptions import ApiError
 from elasticsearch.helpers import ScanError
 
-pytestmark = [pytest.mark.asyncio]
+pytestmark = pytest.mark.anyio
 
 
 class AsyncMock(MagicMock):
@@ -92,7 +92,7 @@ class TestStreamingBulk:
     async def test_documents_data_types(self, async_client):
         async def async_gen():
             for x in range(100):
-                await asyncio.sleep(0)
+                await anyio.sleep(0)
                 yield {"answer": x, "_id": x}
 
         def sync_gen():
@@ -123,6 +123,45 @@ class TestStreamingBulk:
             "_source"
         ]
 
+    async def test_explicit_flushes(self, async_client):
+        async def async_gen():
+            yield {"answer": 2, "_id": 0}
+            yield {"answer": 1, "_id": 1}
+            yield helpers.BULK_FLUSH
+            await anyio.sleep(0.5)
+            yield {"answer": 2, "_id": 2}
+
+        timestamps = []
+        async for ok, item in helpers.async_streaming_bulk(
+            async_client, async_gen(), index="test-index", refresh=True
+        ):
+            timestamps.append(time.time())
+            assert ok
+
+        # make sure there is a pause between the writing of the 2nd and 3rd items
+        assert timestamps[2] - timestamps[1] > (timestamps[1] - timestamps[0]) * 2
+
+    async def test_timeout_flushes(self, async_client):
+        async def async_gen():
+            yield {"answer": 2, "_id": 0}
+            yield {"answer": 1, "_id": 1}
+            await anyio.sleep(0.5)
+            yield {"answer": 2, "_id": 2}
+
+        timestamps = []
+        async for ok, item in helpers.async_streaming_bulk(
+            async_client,
+            async_gen(),
+            index="test-index",
+            refresh=True,
+            flush_after_seconds=0.05,
+        ):
+            assert ok
+            timestamps.append(time.time())
+
+        # make sure there is a pause between the writing of the 2nd and 3rd items
+        assert timestamps[2] - timestamps[1] > (timestamps[1] - timestamps[0]) * 2
+
     async def test_all_errors_from_chunk_are_raised_on_failure(self, async_client):
         await async_client.indices.create(
             index="i",
@@ -491,7 +530,7 @@ class MockResponse:
         return self().__await__()
 
 
-@pytest_asyncio.fixture(scope="function")
+@pytest.fixture(scope="function")
 async def scan_teardown(async_client):
     yield
     await async_client.clear_scroll(scroll_id="_all")
@@ -915,7 +954,7 @@ async def test_scan_from_keyword_is_alia
         assert "from" not in search_mock.call_args[1]
 
 
-@pytest_asyncio.fixture(scope="function")
+@pytest.fixture(scope="function")
 async def reindex_setup(async_client):
     bulk = []
     for x in range(100):
@@ -993,7 +1032,7 @@ class TestReindex:
         )["_source"]
 
 
-@pytest_asyncio.fixture(scope="function")
+@pytest.fixture(scope="function")
 async def parent_reindex_setup(async_client):
     body = {
         "settings": {"number_of_shards": 1, "number_of_replicas": 0},
@@ -1054,7 +1093,7 @@ class TestParentChildReindex:
         } == q
 
 
-@pytest_asyncio.fixture(scope="function")
+@pytest.fixture(scope="function")
 async def reindex_data_stream_setup(async_client):
     dt = datetime.now(tz=timezone.utc)
     bulk = []
diff -pruN 9.1.1-2/test_elasticsearch/test_async/test_server/test_mapbox_vector_tile.py 9.2.0-1/test_elasticsearch/test_async/test_server/test_mapbox_vector_tile.py
--- 9.1.1-2/test_elasticsearch/test_async/test_server/test_mapbox_vector_tile.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/test_elasticsearch/test_async/test_server/test_mapbox_vector_tile.py	2025-10-28 16:50:53.000000000 +0000
@@ -16,14 +16,13 @@
 #  under the License.
 
 import pytest
-import pytest_asyncio
 
 from elasticsearch import RequestError
 
-pytestmark = pytest.mark.asyncio
+pytestmark = pytest.mark.anyio
 
 
-@pytest_asyncio.fixture(scope="function")
+@pytest.fixture(scope="function")
 async def mvt_setup(async_client):
     await async_client.indices.create(
         index="museums",
diff -pruN 9.1.1-2/test_elasticsearch/test_async/test_server/test_rest_api_spec.py 9.2.0-1/test_elasticsearch/test_async/test_server/test_rest_api_spec.py
--- 9.1.1-2/test_elasticsearch/test_async/test_server/test_rest_api_spec.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/test_elasticsearch/test_async/test_server/test_rest_api_spec.py	2025-10-28 16:50:53.000000000 +0000
@@ -25,7 +25,6 @@ import json
 import warnings
 
 import pytest
-import pytest_asyncio
 
 from elasticsearch import ElasticsearchWarning, RequestError
 
@@ -39,6 +38,8 @@ from ...test_server.test_rest_api_spec i
 )
 from ...utils import parse_version
 
+# We're not using `pytest.mark.anyio` here because it would run the test suite twice,
+# which does not work as it does not fully clean up after itself.
 pytestmark = pytest.mark.asyncio
 
 XPACK_FEATURES = None
@@ -240,7 +241,7 @@ class AsyncYamlRunner(YamlRunner):
         return name in XPACK_FEATURES
 
 
-@pytest_asyncio.fixture(scope="function")
+@pytest.fixture(scope="function")
 def async_runner(async_client_factory):
     return AsyncYamlRunner(async_client_factory)
 
diff -pruN 9.1.1-2/test_elasticsearch/test_async/test_transport.py 9.2.0-1/test_elasticsearch/test_async/test_transport.py
--- 9.1.1-2/test_elasticsearch/test_async/test_transport.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/test_elasticsearch/test_async/test_transport.py	2025-10-28 16:50:53.000000000 +0000
@@ -16,11 +16,12 @@
 #  under the License.
 
 
-import asyncio
 import re
+import time
 import warnings
 from typing import Any, Dict, Optional
 
+import anyio
 import pytest
 from elastic_transport import (
     ApiResponseMeta,
@@ -40,8 +41,6 @@ from elasticsearch.exceptions import (
     UnsupportedProductError,
 )
 
-pytestmark = pytest.mark.asyncio
-
 
 class DummyNode(BaseAsyncNode):
     def __init__(self, config: NodeConfig):
@@ -175,6 +174,7 @@ CLUSTER_NODES_MASTER_ONLY = """{
 }"""
 
 
+@pytest.mark.anyio
 class TestTransport:
     async def test_request_timeout_extracted_from_params_and_passed(self):
         client = AsyncElasticsearch(
@@ -378,6 +378,9 @@ class TestTransport:
         assert len(client.transport.node_pool._alive_nodes) == 2
         assert len(client.transport.node_pool._dead_consecutive_failures) == 0
 
+
+@pytest.mark.asyncio
+class TestSniffing:
     @pytest.mark.parametrize(
         ["nodes_info_response", "node_host"],
         [(CLUSTER_NODES, "1.1.1.1"), (CLUSTER_NODES_7x_PUBLISH_HOST, "somehost.tld")],
@@ -528,23 +531,22 @@ class TestTransport:
         assert len(client.transport.node_pool) == 3
 
     async def test_sniff_after_n_seconds(self):
-        event_loop = asyncio.get_running_loop()
         client = AsyncElasticsearch(  # noqa: F821
             [NodeConfig("http", "localhost", 9200, _extras={"data": CLUSTER_NODES})],
             node_class=DummyNode,
             min_delay_between_sniffing=5,
         )
-        client.transport._last_sniffed_at = event_loop.time()
+        client.transport._last_sniffed_at = time.monotonic()
 
         await client.info()
 
         for _ in range(4):
             await client.info()
-            await asyncio.sleep(0)
+            await anyio.sleep(0)
 
         assert 1 == len(client.transport.node_pool)
 
-        client.transport._last_sniffed_at = event_loop.time() - 5.1
+        client.transport._last_sniffed_at = time.monotonic() - 5.1
 
         await client.info()
         await client.transport._sniffing_task  # Need to wait for the sniffing task to complete
@@ -554,9 +556,9 @@ class TestTransport:
             node.base_url for node in client.transport.node_pool.all()
         )
         assert (
-            event_loop.time() - 1
+            time.monotonic() - 1
             < client.transport._last_sniffed_at
-            < event_loop.time() + 0.01
+            < time.monotonic() + 0.01
         )
 
     @pytest.mark.parametrize(
@@ -581,7 +583,6 @@ class TestTransport:
         )
 
     async def test_sniff_on_start_close_unlocks_async_calls(self):
-        event_loop = asyncio.get_running_loop()
         client = AsyncElasticsearch(  # noqa: F821
             [
                 NodeConfig(
@@ -596,20 +597,17 @@ class TestTransport:
         )
 
         # Start making _async_calls() before we cancel
-        tasks = []
-        start_time = event_loop.time()
-        for _ in range(3):
-            tasks.append(event_loop.create_task(client.info()))
-            await asyncio.sleep(0)
-
-        # Close the transport while the sniffing task is active! :(
-        await client.transport.close()
-
-        # Now we start waiting on all those _async_calls()
-        await asyncio.gather(*tasks)
-        end_time = event_loop.time()
-        duration = end_time - start_time
+        async with anyio.create_task_group() as tg:
+            start_time = time.monotonic()
+            for _ in range(3):
+                tg.start_soon(client.info)
+            await anyio.sleep(0)
 
+            # Close the transport while the sniffing task is active! :(
+            await client.transport.close()
+
+        end_time = time.monotonic()
+        duration = end_time - start_time
         # A lot quicker than 10 seconds defined in 'delay'
         assert duration < 1
 
@@ -661,6 +659,7 @@ class TestTransport:
         assert ports == {9200, 124}
 
 
+@pytest.mark.anyio
 @pytest.mark.parametrize("headers", [{}, {"X-elastic-product": "BAD HEADER"}])
 async def test_unsupported_product_error(headers):
     client = AsyncElasticsearch(
@@ -690,6 +689,7 @@ async def test_unsupported_product_error
     )
 
 
+@pytest.mark.anyio
 @pytest.mark.parametrize("status", [401, 403, 413, 500])
 async def test_unsupported_product_error_not_raised_on_non_2xx(status):
     client = AsyncElasticsearch(
@@ -709,6 +709,7 @@ async def test_unsupported_product_error
         assert e.meta.status == status
 
 
+@pytest.mark.anyio
 @pytest.mark.parametrize("status", [404, 500])
 async def test_api_error_raised_before_product_error(status):
     client = AsyncElasticsearch(
@@ -737,6 +738,7 @@ async def test_api_error_raised_before_p
     assert calls[0][0] == ("GET", "/")
 
 
+@pytest.mark.anyio
 @pytest.mark.parametrize(
     "headers",
     [
diff -pruN 9.1.1-2/test_elasticsearch/test_dsl/_async/test_document.py 9.2.0-1/test_elasticsearch/test_dsl/_async/test_document.py
--- 9.1.1-2/test_elasticsearch/test_dsl/_async/test_document.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/test_elasticsearch/test_dsl/_async/test_document.py	2025-10-28 16:50:53.000000000 +0000
@@ -27,8 +27,9 @@ import pickle
 import sys
 from datetime import datetime
 from hashlib import md5
-from typing import Any, ClassVar, Dict, List, Optional
+from typing import Annotated, Any, ClassVar, Dict, List, Optional
 
+import pydantic
 import pytest
 from pytest import raises
 
@@ -36,6 +37,7 @@ from elasticsearch.dsl import (
     AsyncDocument,
     Index,
     InnerDoc,
+    Keyword,
     M,
     Mapping,
     MetaField,
@@ -47,6 +49,7 @@ from elasticsearch.dsl import (
 )
 from elasticsearch.dsl.document_base import InstrumentedField
 from elasticsearch.dsl.exceptions import IllegalOperation, ValidationException
+from elasticsearch.dsl.pydantic import AsyncBaseESModel
 
 
 class MyInner(InnerDoc):
@@ -582,21 +585,21 @@ def test_meta_fields_can_be_set_directly
     assert md.meta.id is p
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_save_no_index(async_mock_client: Any) -> None:
     md = MyDoc()
     with raises(ValidationException):
         await md.save(using="mock")
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_delete_no_index(async_mock_client: Any) -> None:
     md = MyDoc()
     with raises(ValidationException):
         await md.delete(using="mock")
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_update_no_fields() -> None:
     md = MyDoc()
     with raises(IllegalOperation):
@@ -678,118 +681,149 @@ def test_doc_with_type_hints() -> None:
         )
         i1: ClassVar
         i2: ClassVar[int]
+        i3: str = mapped_field(exclude=True)
 
-    props = TypedDoc._doc_type.mapping.to_dict()["properties"]
-    assert props == {
-        "st": {"type": "text"},
-        "dt": {"type": "date"},
-        "li": {"type": "integer"},
-        "ob": {
-            "type": "object",
-            "properties": {
-                "st": {"type": "text"},
-                "dt": {"type": "date"},
-                "li": {"type": "integer"},
+    class TypedDocAnnotated(AsyncDocument):
+        st: Annotated[str, "foo"]
+        dt: Annotated[Optional[datetime], "bar"]
+        li: Annotated[List[int], "baz"]
+        ob: Annotated[TypedInnerDoc, "qux"]
+        ns: Annotated[List[TypedInnerDoc], "quux"]
+        ip: Annotated[Optional[str], field.Ip()]
+        k1: Annotated[str, field.Keyword(required=True)]
+        k2: Annotated[M[str], field.Keyword()]
+        k3: Annotated[str, mapped_field(field.Keyword(), default="foo")]
+        k4: Annotated[M[Optional[str]], mapped_field(field.Keyword())]  # type: ignore[misc]
+        s1: Annotated[Secret, SecretField()]
+        s2: Annotated[M[Secret], SecretField()]
+        s3: Annotated[Secret, mapped_field(SecretField())]  # type: ignore[misc]
+        s4: Annotated[
+            M[Optional[Secret]],
+            mapped_field(SecretField(), default_factory=lambda: "foo"),
+        ]
+        if sys.version_info[0] > 3 or (
+            sys.version_info[0] == 3 and sys.version_info[1] >= 11
+        ):
+            i1: Annotated[ClassVar, "classvar"]
+            i2: Annotated[ClassVar[int], "classvar"]
+        else:
+            i1: ClassVar
+            i2: ClassVar[int]
+        i3: Annotated[str, mapped_field(exclude=True)]
+
+    for doc_class in [TypedDoc, TypedDocAnnotated]:
+        props = doc_class._doc_type.mapping.to_dict()["properties"]
+        assert props == {
+            "st": {"type": "text"},
+            "dt": {"type": "date"},
+            "li": {"type": "integer"},
+            "ob": {
+                "type": "object",
+                "properties": {
+                    "st": {"type": "text"},
+                    "dt": {"type": "date"},
+                    "li": {"type": "integer"},
+                },
             },
-        },
-        "ns": {
-            "type": "nested",
-            "properties": {
-                "st": {"type": "text"},
-                "dt": {"type": "date"},
-                "li": {"type": "integer"},
+            "ns": {
+                "type": "nested",
+                "properties": {
+                    "st": {"type": "text"},
+                    "dt": {"type": "date"},
+                    "li": {"type": "integer"},
+                },
             },
-        },
-        "ip": {"type": "ip"},
-        "k1": {"type": "keyword"},
-        "k2": {"type": "keyword"},
-        "k3": {"type": "keyword"},
-        "k4": {"type": "keyword"},
-        "s1": {"type": "text"},
-        "s2": {"type": "text"},
-        "s3": {"type": "text"},
-        "s4": {"type": "text"},
-    }
+            "ip": {"type": "ip"},
+            "k1": {"type": "keyword"},
+            "k2": {"type": "keyword"},
+            "k3": {"type": "keyword"},
+            "k4": {"type": "keyword"},
+            "s1": {"type": "text"},
+            "s2": {"type": "text"},
+            "s3": {"type": "text"},
+            "s4": {"type": "text"},
+        }
 
-    TypedDoc.i1 = "foo"
-    TypedDoc.i2 = 123
+        doc_class.i1 = "foo"
+        doc_class.i2 = 123
+        doc_class.i3 = "bar"
+
+        doc = doc_class()
+        assert doc.k3 == "foo"
+        assert doc.s4 == "foo"
+        with raises(ValidationException) as exc_info:
+            doc.full_clean()
+        assert set(exc_info.value.args[0].keys()) == {
+            "st",
+            "k1",
+            "k2",
+            "ob",
+            "s1",
+            "s2",
+            "s3",
+        }
 
-    doc = TypedDoc()
-    assert doc.k3 == "foo"
-    assert doc.s4 == "foo"
-    with raises(ValidationException) as exc_info:
+        assert doc_class.i1 == "foo"
+        assert doc_class.i2 == 123
+        assert doc_class.i3 == "bar"
+
+        doc.st = "s"
+        doc.li = [1, 2, 3]
+        doc.k1 = "k1"
+        doc.k2 = "k2"
+        doc.ob.st = "s"
+        doc.ob.li = [1]
+        doc.s1 = "s1"
+        doc.s2 = "s2"
+        doc.s3 = "s3"
         doc.full_clean()
-    assert set(exc_info.value.args[0].keys()) == {
-        "st",
-        "k1",
-        "k2",
-        "ob",
-        "s1",
-        "s2",
-        "s3",
-    }
 
-    assert TypedDoc.i1 == "foo"
-    assert TypedDoc.i2 == 123
-
-    doc.st = "s"
-    doc.li = [1, 2, 3]
-    doc.k1 = "k1"
-    doc.k2 = "k2"
-    doc.ob.st = "s"
-    doc.ob.li = [1]
-    doc.s1 = "s1"
-    doc.s2 = "s2"
-    doc.s3 = "s3"
-    doc.full_clean()
-
-    doc.ob = TypedInnerDoc(li=[1])
-    with raises(ValidationException) as exc_info:
-        doc.full_clean()
-    assert set(exc_info.value.args[0].keys()) == {"ob"}
-    assert set(exc_info.value.args[0]["ob"][0].args[0].keys()) == {"st"}
+        doc.ob = TypedInnerDoc(li=[1])
+        with raises(ValidationException) as exc_info:
+            doc.full_clean()
+        assert set(exc_info.value.args[0].keys()) == {"ob"}
+        assert set(exc_info.value.args[0]["ob"][0].args[0].keys()) == {"st"}
+
+        doc.ob.st = "s"
+        doc.ns.append(TypedInnerDoc(li=[1, 2]))
+        with raises(ValidationException) as exc_info:
+            doc.full_clean()
 
-    doc.ob.st = "s"
-    doc.ns.append(TypedInnerDoc(li=[1, 2]))
-    with raises(ValidationException) as exc_info:
+        doc.ns[0].st = "s"
         doc.full_clean()
 
-    doc.ns[0].st = "s"
-    doc.full_clean()
-
-    doc.ip = "1.2.3.4"
-    n = datetime.now()
-    doc.dt = n
-    assert doc.to_dict() == {
-        "st": "s",
-        "li": [1, 2, 3],
-        "dt": n,
-        "ob": {
+        doc.ip = "1.2.3.4"
+        n = datetime.now()
+        doc.dt = n
+        assert doc.to_dict() == {
             "st": "s",
-            "li": [1],
-        },
-        "ns": [
-            {
+            "li": [1, 2, 3],
+            "dt": n,
+            "ob": {
                 "st": "s",
-                "li": [1, 2],
-            }
-        ],
-        "ip": "1.2.3.4",
-        "k1": "k1",
-        "k2": "k2",
-        "k3": "foo",
-        "s1": "s1",
-        "s2": "s2",
-        "s3": "s3",
-        "s4": "foo",
-    }
+                "li": [1],
+            },
+            "ns": [
+                {
+                    "st": "s",
+                    "li": [1, 2],
+                }
+            ],
+            "ip": "1.2.3.4",
+            "k1": "k1",
+            "k2": "k2",
+            "k3": "foo",
+            "s1": "s1",
+            "s2": "s2",
+            "s3": "s3",
+            "s4": "foo",
+        }
 
-    s = TypedDoc.search().sort(TypedDoc.st, -TypedDoc.dt, +TypedDoc.ob.st)
-    s.aggs.bucket("terms_agg", "terms", field=TypedDoc.k1)
-    assert s.to_dict() == {
-        "aggs": {"terms_agg": {"terms": {"field": "k1"}}},
-        "sort": ["st", {"dt": {"order": "desc"}}, "ob.st"],
-    }
+        s = doc_class.search().sort(doc_class.st, -doc_class.dt, +doc_class.ob.st)
+        s.aggs.bucket("terms_agg", "terms", field=doc_class.k1)
+        d = s.to_dict()
+        assert d["aggs"] == {"terms_agg": {"terms": {"field": "k1"}}}
+        assert d["sort"] == ["st", {"dt": {"order": "desc"}}, "ob.st"]
 
 
 @pytest.mark.skipif(sys.version_info < (3, 10), reason="requires Python 3.10")
@@ -881,3 +915,107 @@ def test_instrumented_field() -> None:
         Doc.ns.something
     with raises(AttributeError):
         Doc.ns.st.something
+
+
+def test_pydantic_integration() -> None:
+    class Location(pydantic.BaseModel):
+        city: str
+        country: str
+
+    class Address(pydantic.BaseModel):
+        street: str
+        location: Location
+
+    class Phone(pydantic.BaseModel):
+        type: str
+        number: str
+
+    class User(AsyncBaseESModel):
+        name: Annotated[str, Keyword()] = pydantic.Field(default="Unknown")
+        bio: str
+        age: int = pydantic.Field(strict=True, ge=0)
+        address: Address = pydantic.Field(
+            default=Address(
+                street="Unknown", location=Location(city="Unknown", country="Unknown")
+            )
+        )
+        phones: list[Phone] = pydantic.Field(default=[])
+
+    u = User(
+        name="foo",
+        bio="lorem ipsum",
+        age=30,
+        address=Address(
+            street="123 Main St.",
+            location=Location(city="San Francisco", country="USA"),
+        ),
+    )
+    u.phones.append(Phone(type="Home", number="+12345678900"))
+    assert u.model_dump() == {
+        "name": "foo",
+        "bio": "lorem ipsum",
+        "age": 30,
+        "address": {
+            "street": "123 Main St.",
+            "location": {
+                "city": "San Francisco",
+                "country": "USA",
+            },
+        },
+        "phones": [
+            {
+                "type": "Home",
+                "number": "+12345678900",
+            }
+        ],
+        "meta": {
+            "id": "",
+            "index": "",
+            "primary_term": 0,
+            "score": 0,
+            "seq_no": 0,
+            "version": 0,
+        },
+    }
+    udoc = u.to_doc()
+    assert udoc.name == "foo"
+    assert udoc.bio == "lorem ipsum"
+    assert udoc.age == 30
+    assert udoc.to_dict() == {
+        "name": "foo",
+        "bio": "lorem ipsum",
+        "age": 30,
+        "address": {
+            "street": "123 Main St.",
+            "location": {
+                "city": "San Francisco",
+                "country": "USA",
+            },
+        },
+        "phones": [
+            {
+                "type": "Home",
+                "number": "+12345678900",
+            }
+        ],
+    }
+
+    u2 = User.from_doc(udoc)
+    assert u == u2
+
+    with raises(pydantic.ValidationError):
+        _ = User()
+
+    with raises(pydantic.ValidationError):
+        _ = User(name="foo", bio="lorem ipsum")
+
+    with raises(pydantic.ValidationError):
+        _ = User(name="foo", bio="lorem ipsum", age=-10)
+
+    u3 = User(bio="lorem ipsum", age=30)
+    assert u3.name == "Unknown"
+    assert u3.address.location.country == "Unknown"
+    assert u3.phones == []
+    assert u3.to_doc().name == "Unknown"
+    assert u3.to_doc().address.location.country == "Unknown"
+    assert u3.to_doc().phones == []
diff -pruN 9.1.1-2/test_elasticsearch/test_dsl/_async/test_index.py 9.2.0-1/test_elasticsearch/test_dsl/_async/test_index.py
--- 9.1.1-2/test_elasticsearch/test_dsl/_async/test_index.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/test_elasticsearch/test_dsl/_async/test_index.py	2025-10-28 16:50:53.000000000 +0000
@@ -190,7 +190,7 @@ def test_index_template_can_have_order()
     assert {"index_patterns": ["i-*"], "order": 2} == it.to_dict()
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_index_template_save_result(async_mock_client: Any) -> None:
     it = AsyncIndexTemplate("test-template", "test-*")
 
diff -pruN 9.1.1-2/test_elasticsearch/test_dsl/_async/test_search.py 9.2.0-1/test_elasticsearch/test_dsl/_async/test_search.py
--- 9.1.1-2/test_elasticsearch/test_dsl/_async/test_search.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/test_elasticsearch/test_dsl/_async/test_search.py	2025-10-28 16:50:53.000000000 +0000
@@ -39,7 +39,7 @@ def test_expand__to_dot_is_respected() -
     assert {"query": {"match": {"a__b": 42}}} == s.to_dict()
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_execute_uses_cache() -> None:
     s = AsyncSearch()
     r = object()
@@ -48,7 +48,7 @@ async def test_execute_uses_cache() -> N
     assert r is await s.execute()
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_cache_can_be_ignored(async_mock_client: Any) -> None:
     s = AsyncSearch(using="mock")
     r = object()
@@ -58,7 +58,7 @@ async def test_cache_can_be_ignored(asyn
     async_mock_client.search.assert_awaited_once_with(index=None, body={})
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_iter_iterates_over_hits() -> None:
     s = AsyncSearch()
     s._response = [1, 2, 3]  # type: ignore[assignment]
@@ -612,7 +612,7 @@ def test_from_dict_doesnt_need_query() -
     assert {"size": 5} == s.to_dict()
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_params_being_passed_to_search(async_mock_client: Any) -> None:
     s = AsyncSearch(using="mock")
     s = s.params(routing="42")
@@ -704,7 +704,7 @@ def test_exclude() -> None:
     } == s.to_dict()
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_delete_by_query(async_mock_client: Any) -> None:
     s = AsyncSearch(using="mock", index="i").query("match", lang="java")
     await s.delete()
@@ -789,7 +789,7 @@ def test_rescore_query_to_dict() -> None
     }
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_empty_search() -> None:
     s = AsyncEmptySearch(index="index-name")
     s = s.query("match", lang="java")
diff -pruN 9.1.1-2/test_elasticsearch/test_dsl/_async/test_update_by_query.py 9.2.0-1/test_elasticsearch/test_dsl/_async/test_update_by_query.py
--- 9.1.1-2/test_elasticsearch/test_dsl/_async/test_update_by_query.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/test_elasticsearch/test_dsl/_async/test_update_by_query.py	2025-10-28 16:50:53.000000000 +0000
@@ -144,7 +144,7 @@ def test_from_dict_doesnt_need_query() -
     assert {"script": {"source": "test"}} == ubq.to_dict()
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_params_being_passed_to_search(async_mock_client: Any) -> None:
     ubq = AsyncUpdateByQuery(using="mock", index="i")
     ubq = ubq.params(routing="42")
diff -pruN 9.1.1-2/test_elasticsearch/test_dsl/_sync/test_document.py 9.2.0-1/test_elasticsearch/test_dsl/_sync/test_document.py
--- 9.1.1-2/test_elasticsearch/test_dsl/_sync/test_document.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/test_elasticsearch/test_dsl/_sync/test_document.py	2025-10-28 16:50:53.000000000 +0000
@@ -27,8 +27,9 @@ import pickle
 import sys
 from datetime import datetime
 from hashlib import md5
-from typing import Any, ClassVar, Dict, List, Optional
+from typing import Annotated, Any, ClassVar, Dict, List, Optional
 
+import pydantic
 import pytest
 from pytest import raises
 
@@ -36,6 +37,7 @@ from elasticsearch.dsl import (
     Document,
     Index,
     InnerDoc,
+    Keyword,
     M,
     Mapping,
     MetaField,
@@ -47,6 +49,7 @@ from elasticsearch.dsl import (
 )
 from elasticsearch.dsl.document_base import InstrumentedField
 from elasticsearch.dsl.exceptions import IllegalOperation, ValidationException
+from elasticsearch.dsl.pydantic import BaseESModel
 
 
 class MyInner(InnerDoc):
@@ -678,118 +681,149 @@ def test_doc_with_type_hints() -> None:
         )
         i1: ClassVar
         i2: ClassVar[int]
+        i3: str = mapped_field(exclude=True)
 
-    props = TypedDoc._doc_type.mapping.to_dict()["properties"]
-    assert props == {
-        "st": {"type": "text"},
-        "dt": {"type": "date"},
-        "li": {"type": "integer"},
-        "ob": {
-            "type": "object",
-            "properties": {
-                "st": {"type": "text"},
-                "dt": {"type": "date"},
-                "li": {"type": "integer"},
+    class TypedDocAnnotated(Document):
+        st: Annotated[str, "foo"]
+        dt: Annotated[Optional[datetime], "bar"]
+        li: Annotated[List[int], "baz"]
+        ob: Annotated[TypedInnerDoc, "qux"]
+        ns: Annotated[List[TypedInnerDoc], "quux"]
+        ip: Annotated[Optional[str], field.Ip()]
+        k1: Annotated[str, field.Keyword(required=True)]
+        k2: Annotated[M[str], field.Keyword()]
+        k3: Annotated[str, mapped_field(field.Keyword(), default="foo")]
+        k4: Annotated[M[Optional[str]], mapped_field(field.Keyword())]  # type: ignore[misc]
+        s1: Annotated[Secret, SecretField()]
+        s2: Annotated[M[Secret], SecretField()]
+        s3: Annotated[Secret, mapped_field(SecretField())]  # type: ignore[misc]
+        s4: Annotated[
+            M[Optional[Secret]],
+            mapped_field(SecretField(), default_factory=lambda: "foo"),
+        ]
+        if sys.version_info[0] > 3 or (
+            sys.version_info[0] == 3 and sys.version_info[1] >= 11
+        ):
+            i1: Annotated[ClassVar, "classvar"]
+            i2: Annotated[ClassVar[int], "classvar"]
+        else:
+            i1: ClassVar
+            i2: ClassVar[int]
+        i3: Annotated[str, mapped_field(exclude=True)]
+
+    for doc_class in [TypedDoc, TypedDocAnnotated]:
+        props = doc_class._doc_type.mapping.to_dict()["properties"]
+        assert props == {
+            "st": {"type": "text"},
+            "dt": {"type": "date"},
+            "li": {"type": "integer"},
+            "ob": {
+                "type": "object",
+                "properties": {
+                    "st": {"type": "text"},
+                    "dt": {"type": "date"},
+                    "li": {"type": "integer"},
+                },
             },
-        },
-        "ns": {
-            "type": "nested",
-            "properties": {
-                "st": {"type": "text"},
-                "dt": {"type": "date"},
-                "li": {"type": "integer"},
+            "ns": {
+                "type": "nested",
+                "properties": {
+                    "st": {"type": "text"},
+                    "dt": {"type": "date"},
+                    "li": {"type": "integer"},
+                },
             },
-        },
-        "ip": {"type": "ip"},
-        "k1": {"type": "keyword"},
-        "k2": {"type": "keyword"},
-        "k3": {"type": "keyword"},
-        "k4": {"type": "keyword"},
-        "s1": {"type": "text"},
-        "s2": {"type": "text"},
-        "s3": {"type": "text"},
-        "s4": {"type": "text"},
-    }
+            "ip": {"type": "ip"},
+            "k1": {"type": "keyword"},
+            "k2": {"type": "keyword"},
+            "k3": {"type": "keyword"},
+            "k4": {"type": "keyword"},
+            "s1": {"type": "text"},
+            "s2": {"type": "text"},
+            "s3": {"type": "text"},
+            "s4": {"type": "text"},
+        }
 
-    TypedDoc.i1 = "foo"
-    TypedDoc.i2 = 123
+        doc_class.i1 = "foo"
+        doc_class.i2 = 123
+        doc_class.i3 = "bar"
+
+        doc = doc_class()
+        assert doc.k3 == "foo"
+        assert doc.s4 == "foo"
+        with raises(ValidationException) as exc_info:
+            doc.full_clean()
+        assert set(exc_info.value.args[0].keys()) == {
+            "st",
+            "k1",
+            "k2",
+            "ob",
+            "s1",
+            "s2",
+            "s3",
+        }
 
-    doc = TypedDoc()
-    assert doc.k3 == "foo"
-    assert doc.s4 == "foo"
-    with raises(ValidationException) as exc_info:
+        assert doc_class.i1 == "foo"
+        assert doc_class.i2 == 123
+        assert doc_class.i3 == "bar"
+
+        doc.st = "s"
+        doc.li = [1, 2, 3]
+        doc.k1 = "k1"
+        doc.k2 = "k2"
+        doc.ob.st = "s"
+        doc.ob.li = [1]
+        doc.s1 = "s1"
+        doc.s2 = "s2"
+        doc.s3 = "s3"
         doc.full_clean()
-    assert set(exc_info.value.args[0].keys()) == {
-        "st",
-        "k1",
-        "k2",
-        "ob",
-        "s1",
-        "s2",
-        "s3",
-    }
 
-    assert TypedDoc.i1 == "foo"
-    assert TypedDoc.i2 == 123
-
-    doc.st = "s"
-    doc.li = [1, 2, 3]
-    doc.k1 = "k1"
-    doc.k2 = "k2"
-    doc.ob.st = "s"
-    doc.ob.li = [1]
-    doc.s1 = "s1"
-    doc.s2 = "s2"
-    doc.s3 = "s3"
-    doc.full_clean()
-
-    doc.ob = TypedInnerDoc(li=[1])
-    with raises(ValidationException) as exc_info:
-        doc.full_clean()
-    assert set(exc_info.value.args[0].keys()) == {"ob"}
-    assert set(exc_info.value.args[0]["ob"][0].args[0].keys()) == {"st"}
+        doc.ob = TypedInnerDoc(li=[1])
+        with raises(ValidationException) as exc_info:
+            doc.full_clean()
+        assert set(exc_info.value.args[0].keys()) == {"ob"}
+        assert set(exc_info.value.args[0]["ob"][0].args[0].keys()) == {"st"}
+
+        doc.ob.st = "s"
+        doc.ns.append(TypedInnerDoc(li=[1, 2]))
+        with raises(ValidationException) as exc_info:
+            doc.full_clean()
 
-    doc.ob.st = "s"
-    doc.ns.append(TypedInnerDoc(li=[1, 2]))
-    with raises(ValidationException) as exc_info:
+        doc.ns[0].st = "s"
         doc.full_clean()
 
-    doc.ns[0].st = "s"
-    doc.full_clean()
-
-    doc.ip = "1.2.3.4"
-    n = datetime.now()
-    doc.dt = n
-    assert doc.to_dict() == {
-        "st": "s",
-        "li": [1, 2, 3],
-        "dt": n,
-        "ob": {
+        doc.ip = "1.2.3.4"
+        n = datetime.now()
+        doc.dt = n
+        assert doc.to_dict() == {
             "st": "s",
-            "li": [1],
-        },
-        "ns": [
-            {
+            "li": [1, 2, 3],
+            "dt": n,
+            "ob": {
                 "st": "s",
-                "li": [1, 2],
-            }
-        ],
-        "ip": "1.2.3.4",
-        "k1": "k1",
-        "k2": "k2",
-        "k3": "foo",
-        "s1": "s1",
-        "s2": "s2",
-        "s3": "s3",
-        "s4": "foo",
-    }
+                "li": [1],
+            },
+            "ns": [
+                {
+                    "st": "s",
+                    "li": [1, 2],
+                }
+            ],
+            "ip": "1.2.3.4",
+            "k1": "k1",
+            "k2": "k2",
+            "k3": "foo",
+            "s1": "s1",
+            "s2": "s2",
+            "s3": "s3",
+            "s4": "foo",
+        }
 
-    s = TypedDoc.search().sort(TypedDoc.st, -TypedDoc.dt, +TypedDoc.ob.st)
-    s.aggs.bucket("terms_agg", "terms", field=TypedDoc.k1)
-    assert s.to_dict() == {
-        "aggs": {"terms_agg": {"terms": {"field": "k1"}}},
-        "sort": ["st", {"dt": {"order": "desc"}}, "ob.st"],
-    }
+        s = doc_class.search().sort(doc_class.st, -doc_class.dt, +doc_class.ob.st)
+        s.aggs.bucket("terms_agg", "terms", field=doc_class.k1)
+        d = s.to_dict()
+        assert d["aggs"] == {"terms_agg": {"terms": {"field": "k1"}}}
+        assert d["sort"] == ["st", {"dt": {"order": "desc"}}, "ob.st"]
 
 
 @pytest.mark.skipif(sys.version_info < (3, 10), reason="requires Python 3.10")
@@ -881,3 +915,107 @@ def test_instrumented_field() -> None:
         Doc.ns.something
     with raises(AttributeError):
         Doc.ns.st.something
+
+
+def test_pydantic_integration() -> None:
+    class Location(pydantic.BaseModel):
+        city: str
+        country: str
+
+    class Address(pydantic.BaseModel):
+        street: str
+        location: Location
+
+    class Phone(pydantic.BaseModel):
+        type: str
+        number: str
+
+    class User(BaseESModel):
+        name: Annotated[str, Keyword()] = pydantic.Field(default="Unknown")
+        bio: str
+        age: int = pydantic.Field(strict=True, ge=0)
+        address: Address = pydantic.Field(
+            default=Address(
+                street="Unknown", location=Location(city="Unknown", country="Unknown")
+            )
+        )
+        phones: list[Phone] = pydantic.Field(default=[])
+
+    u = User(
+        name="foo",
+        bio="lorem ipsum",
+        age=30,
+        address=Address(
+            street="123 Main St.",
+            location=Location(city="San Francisco", country="USA"),
+        ),
+    )
+    u.phones.append(Phone(type="Home", number="+12345678900"))
+    assert u.model_dump() == {
+        "name": "foo",
+        "bio": "lorem ipsum",
+        "age": 30,
+        "address": {
+            "street": "123 Main St.",
+            "location": {
+                "city": "San Francisco",
+                "country": "USA",
+            },
+        },
+        "phones": [
+            {
+                "type": "Home",
+                "number": "+12345678900",
+            }
+        ],
+        "meta": {
+            "id": "",
+            "index": "",
+            "primary_term": 0,
+            "score": 0,
+            "seq_no": 0,
+            "version": 0,
+        },
+    }
+    udoc = u.to_doc()
+    assert udoc.name == "foo"
+    assert udoc.bio == "lorem ipsum"
+    assert udoc.age == 30
+    assert udoc.to_dict() == {
+        "name": "foo",
+        "bio": "lorem ipsum",
+        "age": 30,
+        "address": {
+            "street": "123 Main St.",
+            "location": {
+                "city": "San Francisco",
+                "country": "USA",
+            },
+        },
+        "phones": [
+            {
+                "type": "Home",
+                "number": "+12345678900",
+            }
+        ],
+    }
+
+    u2 = User.from_doc(udoc)
+    assert u == u2
+
+    with raises(pydantic.ValidationError):
+        _ = User()
+
+    with raises(pydantic.ValidationError):
+        _ = User(name="foo", bio="lorem ipsum")
+
+    with raises(pydantic.ValidationError):
+        _ = User(name="foo", bio="lorem ipsum", age=-10)
+
+    u3 = User(bio="lorem ipsum", age=30)
+    assert u3.name == "Unknown"
+    assert u3.address.location.country == "Unknown"
+    assert u3.phones == []
+    assert u3.to_doc().name == "Unknown"
+    assert u3.to_doc().address.location.country == "Unknown"
+    assert u3.to_doc().phones == []
diff -pruN 9.1.1-2/test_elasticsearch/test_dsl/async_sleep.py 9.2.0-1/test_elasticsearch/test_dsl/async_sleep.py
--- 9.1.1-2/test_elasticsearch/test_dsl/async_sleep.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/test_elasticsearch/test_dsl/async_sleep.py	2025-10-28 16:50:53.000000000 +0000
@@ -15,10 +15,11 @@
 #  specific language governing permissions and limitations
 #  under the License.
 
-import asyncio
 from typing import Union
 
+import anyio
+
 
 async def sleep(secs: Union[int, float]) -> None:
     """Tests can use this function to sleep."""
-    await asyncio.sleep(secs)
+    await anyio.sleep(secs)
diff -pruN 9.1.1-2/test_elasticsearch/test_dsl/conftest.py 9.2.0-1/test_elasticsearch/test_dsl/conftest.py
--- 9.1.1-2/test_elasticsearch/test_dsl/conftest.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/test_elasticsearch/test_dsl/conftest.py	2025-10-28 16:50:53.000000000 +0000
@@ -16,7 +16,6 @@
 #  under the License.
 
 
-import asyncio
 import os
 import re
 import time
@@ -25,9 +24,10 @@ from typing import Any, AsyncGenerator,
 from unittest import SkipTest
 from unittest.mock import AsyncMock, Mock
 
-import pytest_asyncio
+import anyio
+import pytest
+import sniffio
 from elastic_transport import ObjectApiResponse
-from pytest import fixture, skip
 
 from elasticsearch import AsyncElasticsearch, Elasticsearch
 from elasticsearch.dsl import Search
@@ -86,6 +86,10 @@ async def get_async_test_client(
     if elasticsearch_url.startswith("https://"):
         kw["ca_certs"] = CA_CERTS
 
+    # httpx is the only HTTP client that supports trio
+    if sniffio.current_async_library() == "trio":
+        kw["node_class"] = "httpxasync"
+
     kw.update(kwargs)
     client = AsyncElasticsearch(elasticsearch_url, **kw)
 
@@ -97,7 +101,7 @@ async def get_async_test_client(
         except ConnectionError:
             if wait and tries_left == 1:
                 raise
-            await asyncio.sleep(0.1)
+            await anyio.sleep(0.1)
 
     await client.close()
     raise SkipTest("Elasticsearch failed to start.")
@@ -110,7 +114,7 @@ def _get_version(version_string: str) ->
     return tuple(int(v) if v.isdigit() else 999 for v in version)
 
 
-@fixture
+@pytest.fixture
 def client(elasticsearch_url) -> Elasticsearch:
     try:
         connection = get_test_client(
@@ -121,10 +125,10 @@ def client(elasticsearch_url) -> Elastic
         wipe_cluster(connection)
         connection.close()
     except SkipTest:
-        skip()
+        pytest.skip()
 
 
-@pytest_asyncio.fixture
+@pytest.fixture
 async def async_client(elasticsearch_url) -> AsyncGenerator[AsyncElasticsearch, None]:
     try:
         connection = await get_async_test_client(
@@ -135,10 +139,10 @@ async def async_client(elasticsearch_url
         wipe_cluster(connection)
         await connection.close()
     except SkipTest:
-        skip()
+        pytest.skip()
 
 
-@fixture
+@pytest.fixture
 def es_version(client: Elasticsearch) -> Generator[Tuple[int, ...], None, None]:
     info = client.info()
     yield tuple(
@@ -147,7 +151,7 @@ def es_version(client: Elasticsearch) ->
     )
 
 
-@fixture
+@pytest.fixture
 def write_client(client: Elasticsearch) -> Generator[Elasticsearch, None, None]:
     yield client
     for index_name in client.indices.get(index="test-*", expand_wildcards="all"):
@@ -158,14 +162,14 @@ def write_client(client: Elasticsearch)
     )
 
 
-@pytest_asyncio.fixture
+@pytest.fixture
 async def async_write_client(
     write_client: Elasticsearch, async_client: AsyncElasticsearch
 ) -> AsyncGenerator[AsyncElasticsearch, None]:
     yield async_client
 
 
-@fixture
+@pytest.fixture
 def mock_client(
     dummy_response: ObjectApiResponse[Any],
 ) -> Generator[Elasticsearch, None, None]:
@@ -179,7 +183,7 @@ def mock_client(
     connections._kwargs = {}
 
 
-@fixture
+@pytest.fixture
 def async_mock_client(
     dummy_response: ObjectApiResponse[Any],
 ) -> Generator[Elasticsearch, None, None]:
@@ -195,7 +199,7 @@ def async_mock_client(
     async_connections._kwargs = {}
 
 
-@fixture
+@pytest.fixture
 def data_client(client: Elasticsearch) -> Generator[Elasticsearch, None, None]:
     # create mappings
     create_git_index(client, "git")
@@ -208,14 +212,14 @@ def data_client(client: Elasticsearch) -
     client.options(ignore_status=404).indices.delete(index="flat-git")
 
 
-@pytest_asyncio.fixture
+@pytest.fixture
 async def async_data_client(
     data_client: Elasticsearch, async_client: AsyncElasticsearch
 ) -> AsyncGenerator[AsyncElasticsearch, None]:
     yield async_client
 
 
-@fixture
+@pytest.fixture
 def dummy_response() -> ObjectApiResponse[Any]:
     return ObjectApiResponse(
         meta=None,
@@ -271,7 +275,7 @@ def dummy_response() -> ObjectApiRespons
     )
 
 
-@fixture
+@pytest.fixture
 def aggs_search() -> Search:
     s = Search(index="flat-git")
     s.aggs.bucket("popular_files", "terms", field="files", size=2).metric(
@@ -284,7 +288,7 @@ def aggs_search() -> Search:
     return s
 
 
-@fixture
+@pytest.fixture
 def aggs_data() -> Dict[str, Any]:
     return {
         "took": 4,
@@ -440,7 +444,7 @@ def make_pr(pr_module: Any) -> Any:
     )
 
 
-@fixture
+@pytest.fixture
 def pull_request(write_client: Elasticsearch) -> sync_document.PullRequest:
     sync_document.PullRequest.init()
     pr = cast(sync_document.PullRequest, make_pr(sync_document))
@@ -448,7 +452,7 @@ def pull_request(write_client: Elasticse
     return pr
 
 
-@pytest_asyncio.fixture
+@pytest.fixture
 async def async_pull_request(
     async_write_client: AsyncElasticsearch,
 ) -> async_document.PullRequest:
@@ -458,7 +462,7 @@ async def async_pull_request(
     return pr
 
 
-@fixture
+@pytest.fixture
 def setup_ubq_tests(client: Elasticsearch) -> str:
     index = "test-git"
     create_git_index(client, index)
diff -pruN 9.1.1-2/test_elasticsearch/test_dsl/test_field.py 9.2.0-1/test_elasticsearch/test_dsl/test_field.py
--- 9.1.1-2/test_elasticsearch/test_dsl/test_field.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/test_elasticsearch/test_dsl/test_field.py	2025-10-28 16:50:53.000000000 +0000
@@ -23,7 +23,15 @@ from typing import cast
 import pytest
 from dateutil import tz
 
-from elasticsearch.dsl import InnerDoc, Range, ValidationException, field
+from elasticsearch import dsl
+from elasticsearch.dsl import (
+    AttrDict,
+    AttrList,
+    InnerDoc,
+    Range,
+    ValidationException,
+    field,
+)
 
 
 def test_date_range_deserialization() -> None:
@@ -232,3 +240,46 @@ def test_object_constructor() -> None:
 
     with pytest.raises(ValidationException):
         field.Object(doc_class=Inner, dynamic=False)
+
+
+def test_dynamic_object() -> None:
+    f = field.Object(dynamic=True)
+    assert f.deserialize({"a": "b"}).to_dict() == {"a": "b"}
+    assert f.deserialize(AttrDict({"a": "b"})).to_dict() == {"a": "b"}
+    assert f.serialize({"a": "b"}) == {"a": "b"}
+    assert f.serialize(AttrDict({"a": "b"})) == {"a": "b"}
+
+
+def test_dynamic_nested() -> None:
+    f = field.Nested(dynamic=True)
+    assert f.deserialize([{"a": "b"}, {"c": "d"}]) == [{"a": "b"}, {"c": "d"}]
+    assert f.deserialize([AttrDict({"a": "b"}), {"c": "d"}]) == [
+        {"a": "b"},
+        {"c": "d"},
+    ]
+    assert f.deserialize(AttrList([AttrDict({"a": "b"}), {"c": "d"}])) == [
+        {"a": "b"},
+        {"c": "d"},
+    ]
+    assert f.serialize([{"a": "b"}, {"c": "d"}]) == [{"a": "b"}, {"c": "d"}]
+    assert f.serialize([AttrDict({"a": "b"}), {"c": "d"}]) == [{"a": "b"}, {"c": "d"}]
+    assert f.serialize(AttrList([AttrDict({"a": "b"}), {"c": "d"}])) == [
+        {"a": "b"},
+        {"c": "d"},
+    ]
+
+
+def test_all_fields_exported() -> None:
+    """Make sure that all the generated field classes are exported at the top-level"""
+    fields = [
+        f
+        for f in dir(field)
+        if isinstance(getattr(field, f), type)
+        and issubclass(getattr(field, f), field.Field)
+    ]
+    all = dir(dsl)
+    not_found = []
+    for f in fields:
+        if f not in all:
+            not_found.append(f)
+    assert not_found == []
diff -pruN 9.1.1-2/test_elasticsearch/test_dsl/test_integration/_async/test_analysis.py 9.2.0-1/test_elasticsearch/test_dsl/test_integration/_async/test_analysis.py
--- 9.1.1-2/test_elasticsearch/test_dsl/test_integration/_async/test_analysis.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/test_elasticsearch/test_dsl/test_integration/_async/test_analysis.py	2025-10-28 16:50:53.000000000 +0000
@@ -21,7 +21,7 @@ from elasticsearch import AsyncElasticse
 from elasticsearch.dsl import analyzer, token_filter, tokenizer
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_simulate_with_just__builtin_tokenizer(
     async_client: AsyncElasticsearch,
 ) -> None:
@@ -32,7 +32,7 @@ async def test_simulate_with_just__built
     assert tokens[0].token == "Hello World!"
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_simulate_complex(async_client: AsyncElasticsearch) -> None:
     a = analyzer(
         "my-analyzer",
@@ -46,7 +46,7 @@ async def test_simulate_complex(async_cl
     assert ["this", "works"] == [t.token for t in tokens]
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_simulate_builtin(async_client: AsyncElasticsearch) -> None:
     a = analyzer("my-analyzer", "english")
     tokens = (await a.async_simulate("fixes running")).tokens
diff -pruN 9.1.1-2/test_elasticsearch/test_dsl/test_integration/_async/test_document.py 9.2.0-1/test_elasticsearch/test_dsl/test_integration/_async/test_document.py
--- 9.1.1-2/test_elasticsearch/test_dsl/test_integration/_async/test_document.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/test_elasticsearch/test_dsl/test_integration/_async/test_document.py	2025-10-28 16:50:53.000000000 +0000
@@ -33,6 +33,7 @@ from elasticsearch import AsyncElasticse
 from elasticsearch.dsl import (
     AsyncDocument,
     AsyncSearch,
+    AttrDict,
     Binary,
     Boolean,
     Date,
@@ -141,7 +142,7 @@ class Tags(AsyncDocument):
         name = "tags"
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_serialization(async_write_client: AsyncElasticsearch) -> None:
     await SerializationDoc.init()
     await async_write_client.index(
@@ -173,7 +174,7 @@ async def test_serialization(async_write
     }
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_nested_inner_hits_are_wrapped_properly(async_pull_request: Any) -> None:
     history_query = Q(
         "nested",
@@ -202,7 +203,7 @@ async def test_nested_inner_hits_are_wra
     assert "score" in history.meta
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_nested_inner_hits_are_deserialized_properly(
     async_pull_request: Any,
 ) -> None:
@@ -220,7 +221,7 @@ async def test_nested_inner_hits_are_des
     assert isinstance(pr.comments[0].created_at, datetime)
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_nested_top_hits_are_wrapped_properly(async_pull_request: Any) -> None:
     s = PullRequest.search()
     s.aggs.bucket("comments", "nested", path="comments").metric(
@@ -233,7 +234,7 @@ async def test_nested_top_hits_are_wrapp
     assert isinstance(r.aggregations.comments.hits.hits[0], Comment)
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_update_object_field(async_write_client: AsyncElasticsearch) -> None:
     await Wiki.init()
     w = Wiki(
@@ -254,7 +255,7 @@ async def test_update_object_field(async
     assert w.ranked == {"test1": 0.1, "topic2": 0.2}
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_update_script(async_write_client: AsyncElasticsearch) -> None:
     await Wiki.init()
     w = Wiki(owner=User(name="Honza Kral"), _id="elasticsearch-py", views=42)
@@ -265,7 +266,7 @@ async def test_update_script(async_write
     assert w.views == 47
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_update_script_with_dict(async_write_client: AsyncElasticsearch) -> None:
     await Wiki.init()
     w = Wiki(owner=User(name="Honza Kral"), _id="elasticsearch-py", views=42)
@@ -283,7 +284,7 @@ async def test_update_script_with_dict(a
     assert w.views == 47
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_update_retry_on_conflict(async_write_client: AsyncElasticsearch) -> None:
     await Wiki.init()
     w = Wiki(owner=User(name="Honza Kral"), _id="elasticsearch-py", views=42)
@@ -305,7 +306,7 @@ async def test_update_retry_on_conflict(
     assert w.views == 52
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 @pytest.mark.parametrize("retry_on_conflict", [None, 0])
 async def test_update_conflicting_version(
     async_write_client: AsyncElasticsearch, retry_on_conflict: bool
@@ -329,7 +330,7 @@ async def test_update_conflicting_versio
         )
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_save_and_update_return_doc_meta(
     async_write_client: AsyncElasticsearch,
 ) -> None:
@@ -364,14 +365,14 @@ async def test_save_and_update_return_do
     }
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_init(async_write_client: AsyncElasticsearch) -> None:
     await Repository.init(index="test-git")
 
     assert await async_write_client.indices.exists(index="test-git")
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_get_raises_404_on_index_missing(
     async_data_client: AsyncElasticsearch,
 ) -> None:
@@ -379,7 +380,7 @@ async def test_get_raises_404_on_index_m
         await Repository.get("elasticsearch-dsl-php", index="not-there")
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_get_raises_404_on_non_existent_id(
     async_data_client: AsyncElasticsearch,
 ) -> None:
@@ -387,7 +388,7 @@ async def test_get_raises_404_on_non_exi
         await Repository.get("elasticsearch-dsl-php")
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_get_returns_none_if_404_ignored(
     async_data_client: AsyncElasticsearch,
 ) -> None:
@@ -396,7 +397,7 @@ async def test_get_returns_none_if_404_i
     )
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_get_returns_none_if_404_ignored_and_index_doesnt_exist(
     async_data_client: AsyncElasticsearch,
 ) -> None:
@@ -405,7 +406,7 @@ async def test_get_returns_none_if_404_i
     )
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_get(async_data_client: AsyncElasticsearch) -> None:
     elasticsearch_repo = await Repository.get("elasticsearch-dsl-py")
 
@@ -414,17 +415,17 @@ async def test_get(async_data_client: As
     assert datetime(2014, 3, 3) == elasticsearch_repo.created_at
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_exists_return_true(async_data_client: AsyncElasticsearch) -> None:
     assert await Repository.exists("elasticsearch-dsl-py")
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_exists_false(async_data_client: AsyncElasticsearch) -> None:
     assert not await Repository.exists("elasticsearch-dsl-php")
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_get_with_tz_date(async_data_client: AsyncElasticsearch) -> None:
     first_commit = await Commit.get(
         id="3ca6e1e73a071a705b4babd2f581c91a2a3e5037", routing="elasticsearch-dsl-py"
@@ -438,7 +439,7 @@ async def test_get_with_tz_date(async_da
     )
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_save_with_tz_date(async_data_client: AsyncElasticsearch) -> None:
     tzinfo = timezone("Europe/Prague")
     first_commit = await Commit.get(
@@ -470,7 +471,7 @@ COMMIT_DOCS_WITH_MISSING = [
 ]
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_mget(async_data_client: AsyncElasticsearch) -> None:
     commits = await Commit.mget(COMMIT_DOCS_WITH_MISSING)
     assert commits[0] is None
@@ -481,7 +482,7 @@ async def test_mget(async_data_client: A
     assert commits[3].meta.id == "eb3e543323f189fd7b698e66295427204fff5755"
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_mget_raises_exception_when_missing_param_is_invalid(
     async_data_client: AsyncElasticsearch,
 ) -> None:
@@ -489,7 +490,7 @@ async def test_mget_raises_exception_whe
         await Commit.mget(COMMIT_DOCS_WITH_MISSING, missing="raj")
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_mget_raises_404_when_missing_param_is_raise(
     async_data_client: AsyncElasticsearch,
 ) -> None:
@@ -497,7 +498,7 @@ async def test_mget_raises_404_when_miss
         await Commit.mget(COMMIT_DOCS_WITH_MISSING, missing="raise")
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_mget_ignores_missing_docs_when_missing_param_is_skip(
     async_data_client: AsyncElasticsearch,
 ) -> None:
@@ -508,7 +509,7 @@ async def test_mget_ignores_missing_docs
     assert commits[1].meta.id == "eb3e543323f189fd7b698e66295427204fff5755"
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_update_works_from_search_response(
     async_data_client: AsyncElasticsearch,
 ) -> None:
@@ -523,7 +524,7 @@ async def test_update_works_from_search_
     assert "elasticsearch" == new_version.owner.name
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_update(async_data_client: AsyncElasticsearch) -> None:
     elasticsearch_repo = await Repository.get("elasticsearch-dsl-py")
     assert elasticsearch_repo is not None
@@ -550,7 +551,7 @@ async def test_update(async_data_client:
     assert "primary_term" in new_version.meta
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_save_updates_existing_doc(async_data_client: AsyncElasticsearch) -> None:
     elasticsearch_repo = await Repository.get("elasticsearch-dsl-py")
     assert elasticsearch_repo is not None
@@ -565,7 +566,7 @@ async def test_save_updates_existing_doc
     assert new_repo["_seq_no"] == elasticsearch_repo.meta.seq_no
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_update_empty_field(async_client: AsyncElasticsearch) -> None:
     await Tags._index.delete(ignore_unavailable=True)
     await Tags.init()
@@ -578,7 +579,7 @@ async def test_update_empty_field(async_
     assert r.hits[0].tags == []
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_save_automatically_uses_seq_no_and_primary_term(
     async_data_client: AsyncElasticsearch,
 ) -> None:
@@ -590,7 +591,7 @@ async def test_save_automatically_uses_s
         await elasticsearch_repo.save()
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_delete_automatically_uses_seq_no_and_primary_term(
     async_data_client: AsyncElasticsearch,
 ) -> None:
@@ -608,7 +609,7 @@ def assert_doc_equals(expected: Any, act
         assert actual[f] == expected[f]
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_can_save_to_different_index(
     async_write_client: AsyncElasticsearch,
 ) -> None:
@@ -626,14 +627,18 @@ async def test_can_save_to_different_ind
     )
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
+@pytest.mark.parametrize("validate", (True, False))
 async def test_save_without_skip_empty_will_include_empty_fields(
     async_write_client: AsyncElasticsearch,
+    validate: bool,
 ) -> None:
     test_repo = Repository(
         field_1=[], field_2=None, field_3={}, owner={"name": None}, meta={"id": 42}
     )
-    assert await test_repo.save(index="test-document", skip_empty=False)
+    assert await test_repo.save(
+        index="test-document", skip_empty=False, validate=validate
+    )
 
     assert_doc_equals(
         {
@@ -650,8 +655,25 @@ async def test_save_without_skip_empty_w
         await async_write_client.get(index="test-document", id=42),
     )
 
+    test_repo = Repository(owner=AttrDict({"name": None}), meta={"id": 43})
+    assert await test_repo.save(
+        index="test-document", skip_empty=False, validate=validate
+    )
+
+    assert_doc_equals(
+        {
+            "found": True,
+            "_index": "test-document",
+            "_id": "43",
+            "_source": {
+                "owner": {"name": None},
+            },
+        },
+        await async_write_client.get(index="test-document", id=43),
+    )
+
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_delete(async_write_client: AsyncElasticsearch) -> None:
     await async_write_client.create(
         index="test-document",
@@ -673,12 +695,12 @@ async def test_delete(async_write_client
     )
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_search(async_data_client: AsyncElasticsearch) -> None:
     assert await Repository.search().count() == 1
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_search_returns_proper_doc_classes(
     async_data_client: AsyncElasticsearch,
 ) -> None:
@@ -690,7 +712,7 @@ async def test_search_returns_proper_doc
     assert elasticsearch_repo.owner.name == "elasticsearch"
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_refresh_mapping(async_data_client: AsyncElasticsearch) -> None:
     class Commit(AsyncDocument):
         class Index:
@@ -705,7 +727,7 @@ async def test_refresh_mapping(async_dat
     assert isinstance(Commit._index._mapping["committed_date"], Date)
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_highlight_in_meta(async_data_client: AsyncElasticsearch) -> None:
     commit = (
         await Commit.search()
@@ -720,7 +742,7 @@ async def test_highlight_in_meta(async_d
     assert len(commit.meta.highlight["description"]) > 0
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_bulk(async_data_client: AsyncElasticsearch) -> None:
     class Address(InnerDoc):
         street: str
@@ -808,7 +830,7 @@ async def test_bulk(async_data_client: A
     }
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_legacy_dense_vector(
     async_client: AsyncElasticsearch, es_version: Tuple[int, ...]
 ) -> None:
@@ -832,7 +854,7 @@ async def test_legacy_dense_vector(
     assert docs[0].float_vector == doc.float_vector
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_dense_vector(
     async_client: AsyncElasticsearch, es_version: Tuple[int, ...]
 ) -> None:
@@ -842,7 +864,7 @@ async def test_dense_vector(
     class Doc(AsyncDocument):
         float_vector: List[float] = mapped_field(DenseVector())
         byte_vector: List[int] = mapped_field(DenseVector(element_type="byte"))
-        bit_vector: str = mapped_field(DenseVector(element_type="bit"))
+        bit_vector: List[int] = mapped_field(DenseVector(element_type="bit"))
 
         class Index:
             name = "vectors"
@@ -851,18 +873,20 @@ async def test_dense_vector(
     await Doc.init()
 
     doc = Doc(
-        float_vector=[1.0, 1.2, 2.3], byte_vector=[12, 23, 34, 45], bit_vector="12abf0"
+        float_vector=[1.0, 1.2, 2.3],
+        byte_vector=[12, 23, 34, 45],
+        bit_vector=[18, -43, -112],
     )
     await doc.save(refresh=True)
 
     docs = await Doc.search().execute()
     assert len(docs) == 1
-    assert docs[0].float_vector == doc.float_vector
+    assert [round(v, 1) for v in docs[0].float_vector] == doc.float_vector
     assert docs[0].byte_vector == doc.byte_vector
     assert docs[0].bit_vector == doc.bit_vector
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_copy_to(async_client: AsyncElasticsearch) -> None:
     class Person(AsyncDocument):
         first_name: M[str] = mapped_field(Text(copy_to=["full_name", "all"]))
diff -pruN 9.1.1-2/test_elasticsearch/test_dsl/test_integration/_async/test_esql.py 9.2.0-1/test_elasticsearch/test_dsl/test_integration/_async/test_esql.py
--- 9.1.1-2/test_elasticsearch/test_dsl/test_integration/_async/test_esql.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/test_elasticsearch/test_dsl/test_integration/_async/test_esql.py	2025-10-28 16:50:53.000000000 +0000
@@ -138,7 +138,7 @@ async def load_db():
     await Employee._index.refresh()
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_esql(async_client):
     await load_db()
 
@@ -184,7 +184,7 @@ async def test_esql(async_client):
     assert r.body["values"] == [["Luna"], ["Cannon"]]
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_esql_dsl(async_client):
     await load_db()
 
diff -pruN 9.1.1-2/test_elasticsearch/test_dsl/test_integration/_async/test_faceted_search.py 9.2.0-1/test_elasticsearch/test_dsl/test_integration/_async/test_faceted_search.py
--- 9.1.1-2/test_elasticsearch/test_dsl/test_integration/_async/test_faceted_search.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/test_elasticsearch/test_dsl/test_integration/_async/test_faceted_search.py	2025-10-28 16:50:53.000000000 +0000
@@ -126,7 +126,7 @@ def pr_search_cls(es_version: Tuple[int,
     return PRSearch
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_facet_with_custom_metric(async_data_client: AsyncElasticsearch) -> None:
     ms = MetricSearch()
     r = await ms.execute()
@@ -136,7 +136,7 @@ async def test_facet_with_custom_metric(
     assert dates[0] == 1399038439000
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_nested_facet(
     async_pull_request: PullRequest, pr_search_cls: Type[AsyncFacetedSearch]
 ) -> None:
@@ -147,7 +147,7 @@ async def test_nested_facet(
     assert [(datetime(2018, 1, 1, 0, 0), 1, False)] == r.facets.comments
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_nested_facet_with_filter(
     async_pull_request: PullRequest, pr_search_cls: Type[AsyncFacetedSearch]
 ) -> None:
@@ -162,7 +162,7 @@ async def test_nested_facet_with_filter(
     assert not r.hits
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_datehistogram_facet(
     async_data_client: AsyncElasticsearch, repo_search_cls: Type[AsyncFacetedSearch]
 ) -> None:
@@ -173,7 +173,7 @@ async def test_datehistogram_facet(
     assert [(datetime(2014, 3, 1, 0, 0), 1, False)] == r.facets.created
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_boolean_facet(
     async_data_client: AsyncElasticsearch, repo_search_cls: Type[AsyncFacetedSearch]
 ) -> None:
@@ -186,7 +186,7 @@ async def test_boolean_facet(
     assert value is True
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_empty_search_finds_everything(
     async_data_client: AsyncElasticsearch,
     es_version: Tuple[int, ...],
@@ -236,7 +236,7 @@ async def test_empty_search_finds_everyt
     ] == r.facets.deletions
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_term_filters_are_shown_as_selected_and_data_is_filtered(
     async_data_client: AsyncElasticsearch, commit_search_cls: Type[AsyncFacetedSearch]
 ) -> None:
@@ -283,7 +283,7 @@ async def test_term_filters_are_shown_as
     ] == r.facets.deletions
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_range_filters_are_shown_as_selected_and_data_is_filtered(
     async_data_client: AsyncElasticsearch, commit_search_cls: Type[AsyncFacetedSearch]
 ) -> None:
@@ -294,7 +294,7 @@ async def test_range_filters_are_shown_a
     assert 19 == r.hits.total.value  # type: ignore[attr-defined]
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_pagination(
     async_data_client: AsyncElasticsearch, commit_search_cls: Type[AsyncFacetedSearch]
 ) -> None:
diff -pruN 9.1.1-2/test_elasticsearch/test_dsl/test_integration/_async/test_index.py 9.2.0-1/test_elasticsearch/test_dsl/test_integration/_async/test_index.py
--- 9.1.1-2/test_elasticsearch/test_dsl/test_integration/_async/test_index.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/test_elasticsearch/test_dsl/test_integration/_async/test_index.py	2025-10-28 16:50:53.000000000 +0000
@@ -34,7 +34,7 @@ class Post(AsyncDocument):
     published_from = Date()
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_index_template_works(async_write_client: AsyncElasticsearch) -> None:
     it = AsyncIndexTemplate("test-template", "test-legacy-*")
     it.document(Post)
@@ -56,7 +56,7 @@ async def test_index_template_works(asyn
     } == await async_write_client.indices.get_mapping(index="test-legacy-blog")
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_composable_index_template_works(
     async_write_client: AsyncElasticsearch,
 ) -> None:
@@ -80,7 +80,7 @@ async def test_composable_index_template
     } == await async_write_client.indices.get_mapping(index="test-blog")
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_index_can_be_saved_even_with_settings(
     async_write_client: AsyncElasticsearch,
 ) -> None:
@@ -98,13 +98,13 @@ async def test_index_can_be_saved_even_w
     )
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_index_exists(async_data_client: AsyncElasticsearch) -> None:
     assert await AsyncIndex("git").exists()
     assert not await AsyncIndex("not-there").exists()
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_index_can_be_created_with_settings_and_mappings(
     async_write_client: AsyncElasticsearch,
 ) -> None:
@@ -132,7 +132,7 @@ async def test_index_can_be_created_with
     }
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_delete(async_write_client: AsyncElasticsearch) -> None:
     await async_write_client.indices.create(
         index="test-index",
@@ -144,7 +144,7 @@ async def test_delete(async_write_client
     assert not await async_write_client.indices.exists(index="test-index")
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_multiple_indices_with_same_doc_type_work(
     async_write_client: AsyncElasticsearch,
 ) -> None:
diff -pruN 9.1.1-2/test_elasticsearch/test_dsl/test_integration/_async/test_mapping.py 9.2.0-1/test_elasticsearch/test_dsl/test_integration/_async/test_mapping.py
--- 9.1.1-2/test_elasticsearch/test_dsl/test_integration/_async/test_mapping.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/test_elasticsearch/test_dsl/test_integration/_async/test_mapping.py	2025-10-28 16:50:53.000000000 +0000
@@ -22,7 +22,7 @@ from elasticsearch import AsyncElasticse
 from elasticsearch.dsl import AsyncMapping, analysis, exceptions
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_mapping_saved_into_es(async_write_client: AsyncElasticsearch) -> None:
     m = AsyncMapping()
     m.field(
@@ -43,7 +43,7 @@ async def test_mapping_saved_into_es(asy
     } == await async_write_client.indices.get_mapping(index="test-mapping")
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_mapping_saved_into_es_when_index_already_exists_closed(
     async_write_client: AsyncElasticsearch,
 ) -> None:
@@ -71,7 +71,7 @@ async def test_mapping_saved_into_es_whe
     } == await async_write_client.indices.get_mapping(index="test-mapping")
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_mapping_saved_into_es_when_index_already_exists_with_analysis(
     async_write_client: AsyncElasticsearch,
 ) -> None:
@@ -103,7 +103,7 @@ async def test_mapping_saved_into_es_whe
     } == await async_write_client.indices.get_mapping(index="test-mapping")
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_mapping_gets_updated_from_es(
     async_write_client: AsyncElasticsearch,
 ) -> None:
diff -pruN 9.1.1-2/test_elasticsearch/test_dsl/test_integration/_async/test_search.py 9.2.0-1/test_elasticsearch/test_dsl/test_integration/_async/test_search.py
--- 9.1.1-2/test_elasticsearch/test_dsl/test_integration/_async/test_search.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/test_elasticsearch/test_dsl/test_integration/_async/test_search.py	2025-10-28 16:50:53.000000000 +0000
@@ -52,7 +52,7 @@ class Commit(AsyncDocument):
         name = "flat-git"
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_filters_aggregation_buckets_are_accessible(
     async_data_client: AsyncElasticsearch,
 ) -> None:
@@ -77,7 +77,7 @@ async def test_filters_aggregation_bucke
     )
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_top_hits_are_wrapped_in_response(
     async_data_client: AsyncElasticsearch,
 ) -> None:
@@ -96,7 +96,7 @@ async def test_top_hits_are_wrapped_in_r
     assert isinstance(hits[0], Commit)
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_inner_hits_are_wrapped_in_response(
     async_data_client: AsyncElasticsearch,
 ) -> None:
@@ -112,7 +112,7 @@ async def test_inner_hits_are_wrapped_in
     )
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_inner_hits_are_serialized_to_dict(
     async_data_client: AsyncElasticsearch,
 ) -> None:
@@ -133,7 +133,7 @@ async def test_inner_hits_are_serialized
     assert isinstance(d["hits"]["hits"][0]["inner_hits"]["repo"], dict)
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_scan_respects_doc_types(async_data_client: AsyncElasticsearch) -> None:
     repos = [repo async for repo in Repository.search().scan()]
 
@@ -142,7 +142,7 @@ async def test_scan_respects_doc_types(a
     assert repos[0].organization == "elasticsearch"
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_scan_iterates_through_all_docs(
     async_data_client: AsyncElasticsearch,
 ) -> None:
@@ -154,7 +154,7 @@ async def test_scan_iterates_through_all
     assert {d["_id"] for d in FLAT_DATA} == {c.meta.id for c in commits}
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_search_after(async_data_client: AsyncElasticsearch) -> None:
     page_size = 7
     s = AsyncSearch(index="flat-git")[:page_size].sort("authored_date")
@@ -170,7 +170,7 @@ async def test_search_after(async_data_c
     assert {d["_id"] for d in FLAT_DATA} == {c.meta.id for c in commits}
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_search_after_no_search(async_data_client: AsyncElasticsearch) -> None:
     s = AsyncSearch(index="flat-git")
     with raises(
@@ -184,7 +184,7 @@ async def test_search_after_no_search(as
         s.search_after()
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_search_after_no_sort(async_data_client: AsyncElasticsearch) -> None:
     s = AsyncSearch(index="flat-git")
     r = await s.execute()
@@ -194,7 +194,7 @@ async def test_search_after_no_sort(asyn
         r.search_after()
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_search_after_no_results(async_data_client: AsyncElasticsearch) -> None:
     s = AsyncSearch(index="flat-git")[:100].sort("authored_date")
     r = await s.execute()
@@ -208,7 +208,7 @@ async def test_search_after_no_results(a
         r.search_after()
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_point_in_time(async_data_client: AsyncElasticsearch) -> None:
     page_size = 7
     commits = []
@@ -229,7 +229,7 @@ async def test_point_in_time(async_data_
     assert {d["_id"] for d in FLAT_DATA} == {c.meta.id for c in commits}
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_iterate(async_data_client: AsyncElasticsearch) -> None:
     s = AsyncSearch(index="flat-git")
 
@@ -239,7 +239,7 @@ async def test_iterate(async_data_client
     assert {d["_id"] for d in FLAT_DATA} == {c.meta.id for c in commits}
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_response_is_cached(async_data_client: AsyncElasticsearch) -> None:
     s = Repository.search()
     repos = [repo async for repo in s]
@@ -248,7 +248,7 @@ async def test_response_is_cached(async_
     assert s._response.hits == repos
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_multi_search(async_data_client: AsyncElasticsearch) -> None:
     s1 = Repository.search()
     s2 = AsyncSearch[Repository](index="flat-git")
@@ -266,7 +266,7 @@ async def test_multi_search(async_data_c
     assert r2._search is s2
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_multi_missing(async_data_client: AsyncElasticsearch) -> None:
     s1 = Repository.search()
     s2 = AsyncSearch[Repository](index="flat-git")
@@ -290,7 +290,7 @@ async def test_multi_missing(async_data_
     assert r3 is None
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_raw_subfield_can_be_used_in_aggs(
     async_data_client: AsyncElasticsearch,
 ) -> None:
diff -pruN 9.1.1-2/test_elasticsearch/test_dsl/test_integration/_async/test_update_by_query.py 9.2.0-1/test_elasticsearch/test_dsl/test_integration/_async/test_update_by_query.py
--- 9.1.1-2/test_elasticsearch/test_dsl/test_integration/_async/test_update_by_query.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/test_elasticsearch/test_dsl/test_integration/_async/test_update_by_query.py	2025-10-28 16:50:53.000000000 +0000
@@ -22,7 +22,7 @@ from elasticsearch.dsl import AsyncUpdat
 from elasticsearch.dsl.search import Q
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_update_by_query_no_script(
     async_write_client: AsyncElasticsearch, setup_ubq_tests: str
 ) -> None:
@@ -44,7 +44,7 @@ async def test_update_by_query_no_script
     assert response.success()
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_update_by_query_with_script(
     async_write_client: AsyncElasticsearch, setup_ubq_tests: str
 ) -> None:
@@ -64,7 +64,7 @@ async def test_update_by_query_with_scri
     assert response.version_conflicts == 0
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_delete_by_query_with_script(
     async_write_client: AsyncElasticsearch, setup_ubq_tests: str
 ) -> None:
diff -pruN 9.1.1-2/test_elasticsearch/test_dsl/test_integration/_sync/test_document.py 9.2.0-1/test_elasticsearch/test_dsl/test_integration/_sync/test_document.py
--- 9.1.1-2/test_elasticsearch/test_dsl/test_integration/_sync/test_document.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/test_elasticsearch/test_dsl/test_integration/_sync/test_document.py	2025-10-28 16:50:53.000000000 +0000
@@ -31,6 +31,7 @@ from pytz import timezone
 
 from elasticsearch import ConflictError, Elasticsearch, NotFoundError
 from elasticsearch.dsl import (
+    AttrDict,
     Binary,
     Boolean,
     Date,
@@ -621,13 +622,15 @@ def test_can_save_to_different_index(
 
 
 @pytest.mark.sync
+@pytest.mark.parametrize("validate", (True, False))
 def test_save_without_skip_empty_will_include_empty_fields(
     write_client: Elasticsearch,
+    validate: bool,
 ) -> None:
     test_repo = Repository(
         field_1=[], field_2=None, field_3={}, owner={"name": None}, meta={"id": 42}
     )
-    assert test_repo.save(index="test-document", skip_empty=False)
+    assert test_repo.save(index="test-document", skip_empty=False, validate=validate)
 
     assert_doc_equals(
         {
@@ -644,6 +647,21 @@ def test_save_without_skip_empty_will_in
         write_client.get(index="test-document", id=42),
     )
 
+    test_repo = Repository(owner=AttrDict({"name": None}), meta={"id": 43})
+    assert test_repo.save(index="test-document", skip_empty=False, validate=validate)
+
+    assert_doc_equals(
+        {
+            "found": True,
+            "_index": "test-document",
+            "_id": "43",
+            "_source": {
+                "owner": {"name": None},
+            },
+        },
+        write_client.get(index="test-document", id=43),
+    )
+
 
 @pytest.mark.sync
 def test_delete(write_client: Elasticsearch) -> None:
@@ -834,7 +852,7 @@ def test_dense_vector(client: Elasticsea
     class Doc(Document):
         float_vector: List[float] = mapped_field(DenseVector())
         byte_vector: List[int] = mapped_field(DenseVector(element_type="byte"))
-        bit_vector: str = mapped_field(DenseVector(element_type="bit"))
+        bit_vector: List[int] = mapped_field(DenseVector(element_type="bit"))
 
         class Index:
             name = "vectors"
@@ -843,13 +861,15 @@ def test_dense_vector(client: Elasticsea
     Doc.init()
 
     doc = Doc(
-        float_vector=[1.0, 1.2, 2.3], byte_vector=[12, 23, 34, 45], bit_vector="12abf0"
+        float_vector=[1.0, 1.2, 2.3],
+        byte_vector=[12, 23, 34, 45],
+        bit_vector=[18, -43, -112],
     )
     doc.save(refresh=True)
 
     docs = Doc.search().execute()
     assert len(docs) == 1
-    assert docs[0].float_vector == doc.float_vector
+    assert [round(v, 1) for v in docs[0].float_vector] == doc.float_vector
     assert docs[0].byte_vector == doc.byte_vector
     assert docs[0].bit_vector == doc.bit_vector
 
diff -pruN 9.1.1-2/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_alias_migration.py 9.2.0-1/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_alias_migration.py
--- 9.1.1-2/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_alias_migration.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_alias_migration.py	2025-10-28 16:50:53.000000000 +0000
@@ -23,7 +23,7 @@ from ..async_examples import alias_migra
 from ..async_examples.alias_migration import ALIAS, PATTERN, BlogPost, migrate
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_alias_migration(async_write_client: AsyncElasticsearch) -> None:
     # create the index
     await alias_migration.setup()
diff -pruN 9.1.1-2/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_completion.py 9.2.0-1/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_completion.py
--- 9.1.1-2/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_completion.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_completion.py	2025-10-28 16:50:53.000000000 +0000
@@ -22,7 +22,7 @@ from elasticsearch import AsyncElasticse
 from ..async_examples.completion import Person
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_person_suggests_on_all_variants_of_name(
     async_write_client: AsyncElasticsearch,
 ) -> None:
diff -pruN 9.1.1-2/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_composite_aggs.py 9.2.0-1/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_composite_aggs.py
--- 9.1.1-2/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_composite_aggs.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_composite_aggs.py	2025-10-28 16:50:53.000000000 +0000
@@ -23,7 +23,7 @@ from elasticsearch.dsl import A, AsyncSe
 from ..async_examples.composite_agg import scan_aggs
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_scan_aggs_exhausts_all_files(
     async_data_client: AsyncElasticsearch,
 ) -> None:
@@ -34,7 +34,7 @@ async def test_scan_aggs_exhausts_all_fi
     assert len(file_list) == 26
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_scan_aggs_with_multiple_aggs(
     async_data_client: AsyncElasticsearch,
 ) -> None:
diff -pruN 9.1.1-2/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_parent_child.py 9.2.0-1/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_parent_child.py
--- 9.1.1-2/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_parent_child.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_parent_child.py	2025-10-28 16:50:53.000000000 +0000
@@ -18,7 +18,6 @@
 from datetime import datetime
 
 import pytest
-import pytest_asyncio
 
 from elasticsearch import AsyncElasticsearch
 from elasticsearch.dsl import Q
@@ -42,7 +41,7 @@ nick = User(
 )
 
 
-@pytest_asyncio.fixture
+@pytest.fixture
 async def question(async_write_client: AsyncElasticsearch) -> Question:
     await setup()
     assert await async_write_client.indices.exists_index_template(name="base")
@@ -64,7 +63,7 @@ async def question(async_write_client: A
     return q
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_comment(
     async_write_client: AsyncElasticsearch, question: Question
 ) -> None:
@@ -79,7 +78,7 @@ async def test_comment(
     assert c.author.username == "fxdgear"
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_question_answer(
     async_write_client: AsyncElasticsearch, question: Question
 ) -> None:
diff -pruN 9.1.1-2/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_percolate.py 9.2.0-1/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_percolate.py
--- 9.1.1-2/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_percolate.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_percolate.py	2025-10-28 16:50:53.000000000 +0000
@@ -22,7 +22,7 @@ from elasticsearch import AsyncElasticse
 from ..async_examples.percolate import BlogPost, setup
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_post_gets_tagged_automatically(
     async_write_client: AsyncElasticsearch,
 ) -> None:
diff -pruN 9.1.1-2/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_vectors.py 9.2.0-1/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_vectors.py
--- 9.1.1-2/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_vectors.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/test_elasticsearch/test_dsl/test_integration/test_examples/_async/test_vectors.py	2025-10-28 16:50:53.000000000 +0000
@@ -26,7 +26,7 @@ import pytest
 from elasticsearch import AsyncElasticsearch
 
 
-@pytest.mark.asyncio
+@pytest.mark.anyio
 async def test_vector_search(
     async_write_client: AsyncElasticsearch, es_version: Tuple[int, ...]
 ) -> None:
diff -pruN 9.1.1-2/test_elasticsearch/test_esql.py 9.2.0-1/test_elasticsearch/test_esql.py
--- 9.1.1-2/test_elasticsearch/test_esql.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/test_elasticsearch/test_esql.py	2025-10-28 16:50:53.000000000 +0000
@@ -55,6 +55,22 @@ def test_show():
     assert query.render() == "SHOW INFO"
 
 
+def test_ts():
+    query = (
+        ESQL.ts("metrics")
+        .where("@timestamp >= now() - 1 day")
+        .stats("SUM(AVG_OVER_TIME(memory_usage))")
+        .by("host", "TBUCKET(1 hour)")
+    )
+    assert (
+        query.render()
+        == """TS metrics
+| WHERE @timestamp >= now() - 1 day
+| STATS SUM(AVG_OVER_TIME(memory_usage))
+        BY host, TBUCKET(1 hour)"""
+    )
+
+
 def test_change_point():
     query = (
         ESQL.row(key=list(range(1, 26)))
@@ -276,6 +292,78 @@ def test_fork():
     )
 
 
+def test_fuse():
+    query = (
+        ESQL.from_("books")
+        .metadata("_id", "_index", "_score")
+        .fork(
+            ESQL.branch().where('title:"Shakespeare"').sort("_score DESC"),
+            ESQL.branch().where('semantic_title:"Shakespeare"').sort("_score DESC"),
+        )
+        .fuse()
+    )
+    assert (
+        query.render()
+        == """FROM books METADATA _id, _index, _score
+| FORK ( WHERE title:"Shakespeare" | SORT _score DESC )
+       ( WHERE semantic_title:"Shakespeare" | SORT _score DESC )
+| FUSE"""
+    )
+
+    query = (
+        ESQL.from_("books")
+        .metadata("_id", "_index", "_score")
+        .fork(
+            ESQL.branch().where('title:"Shakespeare"').sort("_score DESC"),
+            ESQL.branch().where('semantic_title:"Shakespeare"').sort("_score DESC"),
+        )
+        .fuse("linear")
+    )
+    assert (
+        query.render()
+        == """FROM books METADATA _id, _index, _score
+| FORK ( WHERE title:"Shakespeare" | SORT _score DESC )
+       ( WHERE semantic_title:"Shakespeare" | SORT _score DESC )
+| FUSE LINEAR"""
+    )
+
+    query = (
+        ESQL.from_("books")
+        .metadata("_id", "_index", "_score")
+        .fork(
+            ESQL.branch().where('title:"Shakespeare"').sort("_score DESC"),
+            ESQL.branch().where('semantic_title:"Shakespeare"').sort("_score DESC"),
+        )
+        .fuse("linear")
+        .by("title", "description")
+    )
+    assert (
+        query.render()
+        == """FROM books METADATA _id, _index, _score
+| FORK ( WHERE title:"Shakespeare" | SORT _score DESC )
+       ( WHERE semantic_title:"Shakespeare" | SORT _score DESC )
+| FUSE LINEAR BY title BY description"""
+    )
+
+    query = (
+        ESQL.from_("books")
+        .metadata("_id", "_index", "_score")
+        .fork(
+            ESQL.branch().where('title:"Shakespeare"').sort("_score DESC"),
+            ESQL.branch().where('semantic_title:"Shakespeare"').sort("_score DESC"),
+        )
+        .fuse("linear")
+        .with_(normalizer="minmax")
+    )
+    assert (
+        query.render()
+        == """FROM books METADATA _id, _index, _score
+| FORK ( WHERE title:"Shakespeare" | SORT _score DESC )
+       ( WHERE semantic_title:"Shakespeare" | SORT _score DESC )
+| FUSE LINEAR WITH {"normalizer": "minmax"}"""
+    )
+
+
 def test_grok():
     query = (
         ESQL.row(a="2023-01-23T12:15:00.000Z 127.0.0.1 some.email@foo.com 42")
@@ -322,6 +410,82 @@ def test_grok():
     )
 
 
+def test_inline_stats():
+    query = (
+        ESQL.from_("employees")
+        .keep("emp_no", "languages", "salary")
+        .inline_stats(max_salary=functions.max(E("salary")))
+        .by("languages")
+    )
+    assert (
+        query.render()
+        == """FROM employees
+| KEEP emp_no, languages, salary
+| INLINE STATS max_salary = MAX(salary)
+               BY languages"""
+    )
+
+    query = (
+        ESQL.from_("employees")
+        .keep("emp_no", "languages", "salary")
+        .inline_stats(max_salary=functions.max(E("salary")))
+    )
+    assert (
+        query.render()
+        == """FROM employees
+| KEEP emp_no, languages, salary
+| INLINE STATS max_salary = MAX(salary)"""
+    )
+
+    query = (
+        ESQL.from_("employees")
+        .where("still_hired")
+        .keep("emp_no", "languages", "salary", "hire_date")
+        .eval(tenure=functions.date_diff("year", E("hire_date"), "2025-09-18T00:00:00"))
+        .drop("hire_date")
+        .inline_stats(
+            avg_salary=functions.avg(E("salary")),
+            count=functions.count(E("*")),
+        )
+        .by("languages", "tenure")
+    )
+    assert (
+        query.render()
+        == """FROM employees
+| WHERE still_hired
+| KEEP emp_no, languages, salary, hire_date
+| EVAL tenure = DATE_DIFF("year", hire_date, "2025-09-18T00:00:00")
+| DROP hire_date
+| INLINE STATS avg_salary = AVG(salary),
+               count = COUNT(*)
+               BY languages, tenure"""
+    )
+
+    query = (
+        ESQL.from_("employees")
+        .keep("emp_no", "salary")
+        .inline_stats(
+            avg_lt_50=functions.round(functions.avg(E("salary"))).where(
+                E("salary") < 50000
+            ),
+            avg_lt_60=functions.round(functions.avg(E("salary"))).where(
+                E("salary") >= 50000, E("salary") < 60000
+            ),
+            avg_gt_60=functions.round(functions.avg(E("salary"))).where(
+                E("salary") >= 60000
+            ),
+        )
+    )
+    assert (
+        query.render()
+        == """FROM employees
+| KEEP emp_no, salary
+| INLINE STATS avg_lt_50 = ROUND(AVG(salary)) WHERE salary < 50000,
+               avg_lt_60 = ROUND(AVG(salary)) WHERE (salary >= 50000) AND (salary < 60000),
+               avg_gt_60 = ROUND(AVG(salary)) WHERE salary >= 60000"""
+    )
+
+
 def test_keep():
     query = ESQL.from_("employees").keep("emp_no", "first_name", "last_name", "height")
     assert (
@@ -422,6 +586,83 @@ def test_rename():
     )
 
 
+def test_rerank():
+    query = (
+        ESQL.from_("books")
+        .metadata("_score")
+        .where('MATCH(description, "hobbit")')
+        .sort("_score DESC")
+        .limit(100)
+        .rerank("hobbit")
+        .on("description")
+        .with_(inference_id="test_reranker")
+        .limit(3)
+        .keep("title", "_score")
+    )
+    assert (
+        query.render()
+        == """FROM books METADATA _score
+| WHERE MATCH(description, "hobbit")
+| SORT _score DESC
+| LIMIT 100
+| RERANK "hobbit" ON description WITH {"inference_id": "test_reranker"}
+| LIMIT 3
+| KEEP title, _score"""
+    )
+
+    query = (
+        ESQL.from_("books")
+        .metadata("_score")
+        .where('MATCH(description, "hobbit") OR MATCH(author, "Tolkien")')
+        .sort("_score DESC")
+        .limit(100)
+        .rerank(rerank_score="hobbit")
+        .on("description", "author")
+        .with_(inference_id="test_reranker")
+        .sort("rerank_score")
+        .limit(3)
+        .keep("title", "_score", "rerank_score")
+    )
+    assert (
+        query.render()
+        == """FROM books METADATA _score
+| WHERE MATCH(description, "hobbit") OR MATCH(author, "Tolkien")
+| SORT _score DESC
+| LIMIT 100
+| RERANK rerank_score = "hobbit" ON description, author WITH {"inference_id": "test_reranker"}
+| SORT rerank_score
+| LIMIT 3
+| KEEP title, _score, rerank_score"""
+    )
+
+    query = (
+        ESQL.from_("books")
+        .metadata("_score")
+        .where('MATCH(description, "hobbit") OR MATCH(author, "Tolkien")')
+        .sort("_score DESC")
+        .limit(100)
+        .rerank(rerank_score="hobbit")
+        .on("description", "author")
+        .with_(inference_id="test_reranker")
+        .eval(original_score="_score", _score="rerank_score + original_score")
+        .sort("_score")
+        .limit(3)
+        .keep("title", "original_score", "rerank_score", "_score")
+    )
+    assert (
+        query.render()
+        == """FROM books METADATA _score
+| WHERE MATCH(description, "hobbit") OR MATCH(author, "Tolkien")
+| SORT _score DESC
+| LIMIT 100
+| RERANK rerank_score = "hobbit" ON description, author WITH {"inference_id": "test_reranker"}
+| EVAL original_score = _score, _score = rerank_score + original_score
+| SORT _score
+| LIMIT 3
+| KEEP title, original_score, rerank_score, _score"""
+    )
+
+
 def test_sample():
     query = ESQL.from_("employees").keep("emp_no").sample(0.05)
     assert (
diff -pruN 9.1.1-2/test_elasticsearch/test_helpers.py 9.2.0-1/test_elasticsearch/test_helpers.py
--- 9.1.1-2/test_elasticsearch/test_helpers.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/test_elasticsearch/test_helpers.py	2025-10-28 16:50:53.000000000 +0000
@@ -18,6 +18,7 @@
 import pickle
 import threading
 import time
+from typing import Optional
 from unittest import mock
 
 import pytest
@@ -156,21 +157,34 @@ class TestChunkActions:
             {"_source": {"key2": "val2"}, "key": "val", "_op_type": "update"}
         ) == ({"update": {}}, {"key2": "val2"})
 
-    def test_chunks_are_chopped_by_byte_size(self):
+    @pytest.mark.parametrize("flush_seconds", [None, 10])
+    def test_chunks_are_chopped_by_byte_size(self, flush_seconds: Optional[float]):
         assert 100 == len(
-            list(helpers._chunk_actions(self.actions, 100000, 1, JSONSerializer()))
+            list(
+                helpers._chunk_actions(
+                    self.actions, 100000, 1, flush_seconds, JSONSerializer()
+                )
+            )
         )
 
-    def test_chunks_are_chopped_by_chunk_size(self):
+    @pytest.mark.parametrize("flush_seconds", [None, 10])
+    def test_chunks_are_chopped_by_chunk_size(self, flush_seconds: Optional[float]):
         assert 10 == len(
-            list(helpers._chunk_actions(self.actions, 10, 99999999, JSONSerializer()))
+            list(
+                helpers._chunk_actions(
+                    self.actions, 10, 99999999, flush_seconds, JSONSerializer()
+                )
+            )
         )
 
-    def test_chunks_are_chopped_by_byte_size_properly(self):
+    @pytest.mark.parametrize("flush_seconds", [None, 10])
+    def test_chunks_are_chopped_by_byte_size_properly(
+        self, flush_seconds: Optional[float]
+    ):
         max_byte_size = 170
         chunks = list(
             helpers._chunk_actions(
-                self.actions, 100000, max_byte_size, JSONSerializer()
+                self.actions, 100000, max_byte_size, flush_seconds, JSONSerializer()
             )
         )
         assert 25 == len(chunks)
@@ -178,6 +192,30 @@ class TestChunkActions:
             chunk = b"".join(chunk_actions)
             assert len(chunk) <= max_byte_size
 
+    @pytest.mark.parametrize("flush_seconds", [None, 10])
+    def test_chunks_are_chopped_by_flush(self, flush_seconds: Optional[float]):
+        flush = (helpers.BULK_FLUSH, None)
+        actions = (
+            self.actions[:3]
+            + [flush] * 2  # two consecutive flushes after 3 items
+            + self.actions[3:4]
+            + [flush]  # flush after one more item
+            + self.actions[4:]
+            + [flush]  # flush at the end
+        )
+        chunks = list(
+            helpers._chunk_actions(
+                actions, 100, 99999999, flush_seconds, JSONSerializer()
+            )
+        )
+        assert 3 == len(chunks)
+        assert len(chunks[0][0]) == 3
+        assert len(chunks[0][1]) == 6
+        assert len(chunks[1][0]) == 1
+        assert len(chunks[1][1]) == 2
+        assert len(chunks[2][0]) == 96
+        assert len(chunks[2][1]) == 192
+
 
 class TestExpandActions:
     @pytest.mark.parametrize("action", ["whatever", b"whatever"])
diff -pruN 9.1.1-2/test_elasticsearch/test_server/test_helpers.py 9.2.0-1/test_elasticsearch/test_server/test_helpers.py
--- 9.1.1-2/test_elasticsearch/test_server/test_helpers.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/test_elasticsearch/test_server/test_helpers.py	2025-10-28 16:50:53.000000000 +0000
@@ -16,6 +16,7 @@
 #  under the License.
 
 import json
+import time
 from datetime import datetime, timedelta
 from unittest.mock import call, patch
 
@@ -75,6 +76,47 @@ def test_bulk_all_documents_get_inserted
     assert {"answer": 42} == sync_client.get(index="test-index", id=42)["_source"]
 
 
+def test_explicit_flushes(sync_client):
+    def sync_gen():
+        yield {"answer": 0, "_id": 0}
+        yield {"answer": 1, "_id": 1}
+        yield helpers.BULK_FLUSH
+        time.sleep(0.5)
+        yield {"answer": 2, "_id": 2}
+
+    timestamps = []
+    for ok, item in helpers.streaming_bulk(
+        sync_client, sync_gen(), index="test-index", refresh=True
+    ):
+        assert ok
+        timestamps.append(time.time())
+
+    # make sure there is a pause between the writing of the 2nd and 3rd items
+    assert timestamps[2] - timestamps[1] > (timestamps[1] - timestamps[0]) * 2
+
+
+def test_timeout_flushes(sync_client):
+    def sync_gen():
+        yield {"answer": 0, "_id": 0}
+        yield {"answer": 1, "_id": 1}
+        time.sleep(0.5)
+        yield {"answer": 2, "_id": 2}
+
+    timestamps = []
+    for ok, item in helpers.streaming_bulk(
+        sync_client,
+        sync_gen(),
+        index="test-index",
+        refresh=True,
+        flush_after_seconds=0.05,
+    ):
+        assert ok
+        timestamps.append(time.time())
+
+    # make sure there is a pause between the writing of the 2nd and 3rd items
+    assert timestamps[2] - timestamps[1] > (timestamps[1] - timestamps[0]) * 2
+
+
 def test_bulk_all_errors_from_chunk_are_raised_on_failure(sync_client):
     sync_client.indices.create(
         index="i",
diff -pruN 9.1.1-2/test_elasticsearch/test_server/test_rest_api_spec.py 9.2.0-1/test_elasticsearch/test_server/test_rest_api_spec.py
--- 9.1.1-2/test_elasticsearch/test_server/test_rest_api_spec.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/test_elasticsearch/test_server/test_rest_api_spec.py	2025-10-28 16:50:53.000000000 +0000
@@ -20,6 +20,7 @@ Dynamically generated set of TestCases b
 some integration tests. These files are shared among all official Elasticsearch
 clients.
 """
+import copy
 import io
 import json
 import os
@@ -117,6 +118,7 @@ class YamlRunner:
         self._state = {}
 
     def use_spec(self, test_spec):
+        test_spec = copy.deepcopy(test_spec)
         self._setup_code = test_spec.pop("setup", None)
         self._run_code = test_spec.pop("run", None)
         self._teardown_code = test_spec.pop("teardown", None)
diff -pruN 9.1.1-2/utils/generate-examples.py 9.2.0-1/utils/generate-examples.py
--- 9.1.1-2/utils/generate-examples.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/utils/generate-examples.py	2025-10-28 16:50:53.000000000 +0000
@@ -198,7 +198,7 @@ ParsedSource = collections.namedtuple("P
 def blacken(filename):
     runner = CliRunner()
     result = runner.invoke(
-        black.main, [str(filename), "--line-length=75", "--target-version=py37"]
+        black.main, [str(filename), "--line-length=75", "--target-version=py310"]
     )
     assert result.exit_code == 0, result.output
 
diff -pruN 9.1.1-2/utils/run-unasync-dsl.py 9.2.0-1/utils/run-unasync-dsl.py
--- 9.1.1-2/utils/run-unasync-dsl.py	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/utils/run-unasync-dsl.py	2025-10-28 16:50:53.000000000 +0000
@@ -62,6 +62,7 @@ def main(check=False):
         "AsyncMapping": "Mapping",
         "AsyncFacetedSearch": "FacetedSearch",
         "AsyncUsingType": "UsingType",
+        "AsyncBaseESModel": "BaseESModel",
         "async_connections": "connections",
         "async_scan": "scan",
         "async_simulate": "simulate",
@@ -74,7 +75,6 @@ def main(check=False):
         "async_examples": "examples",
         "async_sleep": "sleep",
         "assert_awaited_once_with": "assert_called_once_with",
-        "pytest_asyncio": "pytest",
         "asynccontextmanager": "contextmanager",
     }
     rules = [
@@ -101,7 +101,7 @@ def main(check=False):
     output_dirs = []
     for dir in source_dirs:
         output_dirs.append(f"{dir[0]}_sync_check/" if check else dir[1])
-    subprocess.check_call(["black", "--target-version=py38", *output_dirs])
+    subprocess.check_call(["black", "--target-version=py310", *output_dirs])
     subprocess.check_call(["isort", *output_dirs])
     for dir, output_dir in zip(source_dirs, output_dirs):
         for file in glob("*.py", root_dir=dir[0]):
@@ -125,15 +125,16 @@ def main(check=False):
                     f"{output_dir}{file}",
                 ]
             )
-            subprocess.check_call(
-                [
-                    "sed",
-                    "-i.bak",
-                    "s/pytest.mark.asyncio/pytest.mark.sync/",
-                    f"{output_dir}{file}",
-                ]
-            )
-            subprocess.check_call(["rm", f"{output_dir}{file}.bak"])
+            for library in ["asyncio", "trio", "anyio"]:
+                subprocess.check_call(
+                    [
+                        "sed",
+                        "-i.bak",
+                        f"s/pytest.mark.{library}/pytest.mark.sync/",
+                        f"{output_dir}{file}",
+                    ]
+                )
+                subprocess.check_call(["rm", f"{output_dir}{file}.bak"])
 
             if check:
                 # make sure there are no differences between _sync and _sync_check
diff -pruN 9.1.1-2/utils/templates/field.py.tpl 9.2.0-1/utils/templates/field.py.tpl
--- 9.1.1-2/utils/templates/field.py.tpl	2025-09-12 13:23:45.000000000 +0000
+++ 9.2.0-1/utils/templates/field.py.tpl	2025-10-28 16:50:53.000000000 +0000
@@ -334,7 +334,11 @@ class {{ k.name }}({{ k.parent }}):
         if isinstance(data, collections.abc.Mapping):
             return data
 
-        return data.to_dict(skip_empty=skip_empty)
+        try:
+            return data.to_dict(skip_empty=skip_empty)
+        except TypeError:
+            # this would only happen if an AttrDict was given instead of an InnerDoc
+            return data.to_dict()
 
     def clean(self, data: Any) -> Any:
         data = super().clean(data)
