# generated by datamodel-codegen:
#   filename:  declarative_component_schema.yaml

from __future__ import annotations

from enum import Enum
from typing import Any, Dict, List, Literal, Optional, Union

from pydantic.v1 import BaseModel, Extra, Field

from airbyte_cdk.sources.declarative.models.base_model_with_deprecations import (
    BaseModelWithDeprecations,
)


class AuthFlowType(Enum):
    oauth2_0 = "oauth2.0"
    oauth1_0 = "oauth1.0"


class BasicHttpAuthenticator(BaseModel):
    type: Literal["BasicHttpAuthenticator"]
    username: str = Field(
        ...,
        description="The username that will be combined with the password, base64 encoded and used to make requests. Fill it in the user inputs.",
        examples=["{{ config['username'] }}", "{{ config['api_key'] }}"],
        title="Username",
    )
    password: Optional[str] = Field(
        "",
        description="The password that will be combined with the username, base64 encoded and used to make requests. Fill it in the user inputs.",
        examples=["{{ config['password'] }}", ""],
        title="Password",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class BearerAuthenticator(BaseModel):
    type: Literal["BearerAuthenticator"]
    api_token: str = Field(
        ...,
        description="Token to inject as request header for authenticating with the API.",
        examples=["{{ config['api_key'] }}", "{{ config['token'] }}"],
        title="Bearer Token",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class DynamicStreamCheckConfig(BaseModel):
    type: Literal["DynamicStreamCheckConfig"]
    dynamic_stream_name: str = Field(
        ..., description="The dynamic stream name.", title="Dynamic Stream Name"
    )
    stream_count: Optional[int] = Field(
        0,
        description="The number of streams to attempt reading from during a check operation. If `stream_count` exceeds the total number of available streams, the minimum of the two values will be used.",
        title="Stream Count",
    )


class CheckDynamicStream(BaseModel):
    type: Literal["CheckDynamicStream"]
    stream_count: int = Field(
        ...,
        description="Numbers of the streams to try reading from when running a check operation.",
        title="Stream Count",
    )
    use_check_availability: Optional[bool] = Field(
        True,
        description="Enables stream check availability. This field is automatically set by the CDK.",
        title="Use Check Availability",
    )


class ConcurrencyLevel(BaseModel):
    type: Optional[Literal["ConcurrencyLevel"]] = None
    default_concurrency: Union[int, str] = Field(
        ...,
        description="The amount of concurrency that will applied during a sync. This value can be hardcoded or user-defined in the config if different users have varying volume thresholds in the target API.",
        examples=[10, "{{ config['num_workers'] or 10 }}"],
        title="Default Concurrency",
    )
    max_concurrency: Optional[int] = Field(
        None,
        description="The maximum level of concurrency that will be used during a sync. This becomes a required field when the default_concurrency derives from the config, because it serves as a safeguard against a user-defined threshold that is too high.",
        examples=[20, 100],
        title="Max Concurrency",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class ConstantBackoffStrategy(BaseModel):
    type: Literal["ConstantBackoffStrategy"]
    backoff_time_in_seconds: Union[float, str] = Field(
        ...,
        description="Backoff time in seconds.",
        examples=[30, 30.5, "{{ config['backoff_time'] }}"],
        title="Backoff Time",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class CursorPagination(BaseModel):
    type: Literal["CursorPagination"]
    cursor_value: str = Field(
        ...,
        description="Value of the cursor defining the next page to fetch.",
        examples=[
            "{{ headers.link.next.cursor }}",
            "{{ last_record['key'] }}",
            "{{ response['nextPage'] }}",
        ],
        title="Cursor Value",
    )
    page_size: Optional[int] = Field(
        None,
        description="The number of records to include in each pages.",
        examples=[100],
        title="Page Size",
    )
    stop_condition: Optional[str] = Field(
        None,
        description="Template string evaluating when to stop paginating.",
        examples=[
            "{{ response.data.has_more is false }}",
            "{{ 'next' not in headers['link'] }}",
        ],
        title="Stop Condition",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class CustomAuthenticator(BaseModel):
    class Config:
        extra = Extra.allow

    type: Literal["CustomAuthenticator"]
    class_name: str = Field(
        ...,
        description="Fully-qualified name of the class that will be implementing the custom authentication strategy. Has to be a sub class of DeclarativeAuthenticator. The format is `source_<name>.<package>.<class_name>`.",
        examples=["source_railz.components.ShortLivedTokenAuthenticator"],
        title="Class Name",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class CustomBackoffStrategy(BaseModel):
    class Config:
        extra = Extra.allow

    type: Literal["CustomBackoffStrategy"]
    class_name: str = Field(
        ...,
        description="Fully-qualified name of the class that will be implementing the custom backoff strategy. The format is `source_<name>.<package>.<class_name>`.",
        examples=["source_railz.components.MyCustomBackoffStrategy"],
        title="Class Name",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class CustomErrorHandler(BaseModel):
    class Config:
        extra = Extra.allow

    type: Literal["CustomErrorHandler"]
    class_name: str = Field(
        ...,
        description="Fully-qualified name of the class that will be implementing the custom error handler. The format is `source_<name>.<package>.<class_name>`.",
        examples=["source_railz.components.MyCustomErrorHandler"],
        title="Class Name",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class CustomIncrementalSync(BaseModel):
    class Config:
        extra = Extra.allow

    type: Literal["CustomIncrementalSync"]
    class_name: str = Field(
        ...,
        description="Fully-qualified name of the class that will be implementing the custom incremental sync. The format is `source_<name>.<package>.<class_name>`.",
        examples=["source_railz.components.MyCustomIncrementalSync"],
        title="Class Name",
    )
    cursor_field: str = Field(
        ...,
        description="The location of the value on a record that will be used as a bookmark during sync.",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class CustomPaginationStrategy(BaseModel):
    class Config:
        extra = Extra.allow

    type: Literal["CustomPaginationStrategy"]
    class_name: str = Field(
        ...,
        description="Fully-qualified name of the class that will be implementing the custom pagination strategy. The format is `source_<name>.<package>.<class_name>`.",
        examples=["source_railz.components.MyCustomPaginationStrategy"],
        title="Class Name",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class CustomRecordExtractor(BaseModel):
    class Config:
        extra = Extra.allow

    type: Literal["CustomRecordExtractor"]
    class_name: str = Field(
        ...,
        description="Fully-qualified name of the class that will be implementing the custom record extraction strategy. The format is `source_<name>.<package>.<class_name>`.",
        examples=["source_railz.components.MyCustomRecordExtractor"],
        title="Class Name",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class CustomRecordFilter(BaseModel):
    class Config:
        extra = Extra.allow

    type: Literal["CustomRecordFilter"]
    class_name: str = Field(
        ...,
        description="Fully-qualified name of the class that will be implementing the custom record filter strategy. The format is `source_<name>.<package>.<class_name>`.",
        examples=["source_railz.components.MyCustomCustomRecordFilter"],
        title="Class Name",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class CustomRequester(BaseModel):
    class Config:
        extra = Extra.allow

    type: Literal["CustomRequester"]
    class_name: str = Field(
        ...,
        description="Fully-qualified name of the class that will be implementing the custom requester strategy. The format is `source_<name>.<package>.<class_name>`.",
        examples=["source_railz.components.MyCustomRecordExtractor"],
        title="Class Name",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class CustomRetriever(BaseModel):
    class Config:
        extra = Extra.allow

    type: Literal["CustomRetriever"]
    class_name: str = Field(
        ...,
        description="Fully-qualified name of the class that will be implementing the custom retriever strategy. The format is `source_<name>.<package>.<class_name>`.",
        examples=["source_railz.components.MyCustomRetriever"],
        title="Class Name",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class CustomPartitionRouter(BaseModel):
    class Config:
        extra = Extra.allow

    type: Literal["CustomPartitionRouter"]
    class_name: str = Field(
        ...,
        description="Fully-qualified name of the class that will be implementing the custom partition router. The format is `source_<name>.<package>.<class_name>`.",
        examples=["source_railz.components.MyCustomPartitionRouter"],
        title="Class Name",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class CustomSchemaLoader(BaseModel):
    class Config:
        extra = Extra.allow

    type: Literal["CustomSchemaLoader"]
    class_name: str = Field(
        ...,
        description="Fully-qualified name of the class that will be implementing the custom schema loader. The format is `source_<name>.<package>.<class_name>`.",
        examples=["source_railz.components.MyCustomSchemaLoader"],
        title="Class Name",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class CustomSchemaNormalization(BaseModel):
    class Config:
        extra = Extra.allow

    type: Literal["CustomSchemaNormalization"]
    class_name: str = Field(
        ...,
        description="Fully-qualified name of the class that will be implementing the custom normalization. The format is `source_<name>.<package>.<class_name>`.",
        examples=[
            "source_amazon_seller_partner.components.LedgerDetailedViewReportsTypeTransformer"
        ],
        title="Class Name",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class CustomStateMigration(BaseModel):
    class Config:
        extra = Extra.allow

    type: Literal["CustomStateMigration"]
    class_name: str = Field(
        ...,
        description="Fully-qualified name of the class that will be implementing the custom state migration. The format is `source_<name>.<package>.<class_name>`.",
        examples=["source_railz.components.MyCustomStateMigration"],
        title="Class Name",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class CustomTransformation(BaseModel):
    class Config:
        extra = Extra.allow

    type: Literal["CustomTransformation"]
    class_name: str = Field(
        ...,
        description="Fully-qualified name of the class that will be implementing the custom transformation. The format is `source_<name>.<package>.<class_name>`.",
        examples=["source_railz.components.MyCustomTransformation"],
        title="Class Name",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class LegacyToPerPartitionStateMigration(BaseModel):
    class Config:
        extra = Extra.allow

    type: Optional[Literal["LegacyToPerPartitionStateMigration"]] = None


class Clamping(BaseModel):
    target: str = Field(
        ...,
        description="The period of time that datetime windows will be clamped by",
        examples=["DAY", "WEEK", "MONTH", "{{ config['target'] }}"],
        title="Target",
    )
    target_details: Optional[Dict[str, Any]] = None


class Algorithm(Enum):
    HS256 = "HS256"
    HS384 = "HS384"
    HS512 = "HS512"
    ES256 = "ES256"
    ES256K = "ES256K"
    ES384 = "ES384"
    ES512 = "ES512"
    RS256 = "RS256"
    RS384 = "RS384"
    RS512 = "RS512"
    PS256 = "PS256"
    PS384 = "PS384"
    PS512 = "PS512"
    EdDSA = "EdDSA"


class JwtHeaders(BaseModel):
    class Config:
        extra = Extra.forbid

    kid: Optional[str] = Field(
        None,
        description="Private key ID for user account.",
        examples=["{{ config['kid'] }}"],
        title="Key Identifier",
    )
    typ: Optional[str] = Field(
        "JWT",
        description="The media type of the complete JWT.",
        examples=["JWT"],
        title="Type",
    )
    cty: Optional[str] = Field(
        None,
        description="Content type of JWT header.",
        examples=["JWT"],
        title="Content Type",
    )


class JwtPayload(BaseModel):
    class Config:
        extra = Extra.forbid

    iss: Optional[str] = Field(
        None,
        description="The user/principal that issued the JWT. Commonly a value unique to the user.",
        examples=["{{ config['iss'] }}"],
        title="Issuer",
    )
    sub: Optional[str] = Field(
        None,
        description="The subject of the JWT. Commonly defined by the API.",
        title="Subject",
    )
    aud: Optional[str] = Field(
        None,
        description="The recipient that the JWT is intended for. Commonly defined by the API.",
        examples=["appstoreconnect-v1"],
        title="Audience",
    )


class JwtAuthenticator(BaseModel):
    type: Literal["JwtAuthenticator"]
    secret_key: str = Field(
        ...,
        description="Secret used to sign the JSON web token.",
        examples=["{{ config['secret_key'] }}"],
        title="Secret Key",
    )
    base64_encode_secret_key: Optional[bool] = Field(
        False,
        description='When set to true, the secret key will be base64 encoded prior to being encoded as part of the JWT. Only set to "true" when required by the API.',
        title="Base64-encode Secret Key",
    )
    algorithm: Algorithm = Field(
        ...,
        description="Algorithm used to sign the JSON web token.",
        examples=["ES256", "HS256", "RS256", "{{ config['algorithm'] }}"],
        title="Algorithm",
    )
    token_duration: Optional[int] = Field(
        1200,
        description="The amount of time in seconds a JWT token can be valid after being issued.",
        examples=[1200, 3600],
        title="Token Duration",
    )
    header_prefix: Optional[str] = Field(
        None,
        description="The prefix to be used within the Authentication header.",
        examples=["Bearer", "Basic"],
        title="Header Prefix",
    )
    jwt_headers: Optional[JwtHeaders] = Field(
        None,
        description="JWT headers used when signing JSON web token.",
        title="JWT Headers",
    )
    additional_jwt_headers: Optional[Dict[str, Any]] = Field(
        None,
        description="Additional headers to be included with the JWT headers object.",
        title="Additional JWT Headers",
    )
    jwt_payload: Optional[JwtPayload] = Field(
        None,
        description="JWT Payload used when signing JSON web token.",
        title="JWT Payload",
    )
    additional_jwt_payload: Optional[Dict[str, Any]] = Field(
        None,
        description="Additional properties to be added to the JWT payload.",
        title="Additional JWT Payload Properties",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class RefreshTokenUpdater(BaseModel):
    refresh_token_name: Optional[str] = Field(
        "refresh_token",
        description="The name of the property which contains the updated refresh token in the response from the token refresh endpoint.",
        examples=["refresh_token"],
        title="Refresh Token Property Name",
    )
    access_token_config_path: Optional[List[str]] = Field(
        ["credentials", "access_token"],
        description="Config path to the access token. Make sure the field actually exists in the config.",
        examples=[["credentials", "access_token"], ["access_token"]],
        title="Config Path To Access Token",
    )
    refresh_token_config_path: Optional[List[str]] = Field(
        ["credentials", "refresh_token"],
        description="Config path to the access token. Make sure the field actually exists in the config.",
        examples=[["credentials", "refresh_token"], ["refresh_token"]],
        title="Config Path To Refresh Token",
    )
    token_expiry_date_config_path: Optional[List[str]] = Field(
        ["credentials", "token_expiry_date"],
        description="Config path to the expiry date. Make sure actually exists in the config.",
        examples=[["credentials", "token_expiry_date"]],
        title="Config Path To Expiry Date",
    )
    refresh_token_error_status_codes: Optional[List[int]] = Field(
        [],
        description="Status Codes to Identify refresh token error in response (Refresh Token Error Key and Refresh Token Error Values should be also specified). Responses with one of the error status code and containing an error value will be flagged as a config error",
        examples=[[400, 500]],
        title="Refresh Token Error Status Codes",
    )
    refresh_token_error_key: Optional[str] = Field(
        "",
        description="Key to Identify refresh token error in response (Refresh Token Error Status Codes and Refresh Token Error Values should be also specified).",
        examples=["error"],
        title="Refresh Token Error Key",
    )
    refresh_token_error_values: Optional[List[str]] = Field(
        [],
        description='List of values to check for exception during token refresh process. Used to check if the error found in the response matches the key from the Refresh Token Error Key field (e.g. response={"error": "invalid_grant"}). Only responses with one of the error status code and containing an error value will be flagged as a config error',
        examples=[["invalid_grant", "invalid_permissions"]],
        title="Refresh Token Error Values",
    )


class OAuthAuthenticator(BaseModel):
    type: Literal["OAuthAuthenticator"]
    client_id_name: Optional[str] = Field(
        "client_id",
        description="The name of the property to use to refresh the `access_token`.",
        examples=["custom_app_id"],
        title="Client ID Property Name",
    )
    client_id: Optional[str] = Field(
        None,
        description="The OAuth client ID. Fill it in the user inputs.",
        examples=["{{ config['client_id }}", "{{ config['credentials']['client_id }}"],
        title="Client ID",
    )
    client_secret_name: Optional[str] = Field(
        "client_secret",
        description="The name of the property to use to refresh the `access_token`.",
        examples=["custom_app_secret"],
        title="Client Secret Property Name",
    )
    client_secret: Optional[str] = Field(
        None,
        description="The OAuth client secret. Fill it in the user inputs.",
        examples=[
            "{{ config['client_secret }}",
            "{{ config['credentials']['client_secret }}",
        ],
        title="Client Secret",
    )
    refresh_token_name: Optional[str] = Field(
        "refresh_token",
        description="The name of the property to use to refresh the `access_token`.",
        examples=["custom_app_refresh_value"],
        title="Refresh Token Property Name",
    )
    refresh_token: Optional[str] = Field(
        None,
        description="Credential artifact used to get a new access token.",
        examples=[
            "{{ config['refresh_token'] }}",
            "{{ config['credentials]['refresh_token'] }}",
        ],
        title="Refresh Token",
    )
    token_refresh_endpoint: Optional[str] = Field(
        None,
        description="The full URL to call to obtain a new access token.",
        examples=["https://connect.squareup.com/oauth2/token"],
        title="Token Refresh Endpoint",
    )
    access_token_name: Optional[str] = Field(
        "access_token",
        description="The name of the property which contains the access token in the response from the token refresh endpoint.",
        examples=["access_token"],
        title="Access Token Property Name",
    )
    access_token_value: Optional[str] = Field(
        None,
        description="The value of the access_token to bypass the token refreshing using `refresh_token`.",
        examples=["secret_access_token_value"],
        title="Access Token Value",
    )
    expires_in_name: Optional[str] = Field(
        "expires_in",
        description="The name of the property which contains the expiry date in the response from the token refresh endpoint.",
        examples=["expires_in"],
        title="Token Expiry Property Name",
    )
    grant_type_name: Optional[str] = Field(
        "grant_type",
        description="The name of the property to use to refresh the `access_token`.",
        examples=["custom_grant_type"],
        title="Grant Type Property Name",
    )
    grant_type: Optional[str] = Field(
        "refresh_token",
        description="Specifies the OAuth2 grant type. If set to refresh_token, the refresh_token needs to be provided as well. For client_credentials, only client id and secret are required. Other grant types are not officially supported.",
        examples=["refresh_token", "client_credentials"],
        title="Grant Type",
    )
    refresh_request_body: Optional[Dict[str, Any]] = Field(
        None,
        description="Body of the request sent to get a new access token.",
        examples=[
            {
                "applicationId": "{{ config['application_id'] }}",
                "applicationSecret": "{{ config['application_secret'] }}",
                "token": "{{ config['token'] }}",
            }
        ],
        title="Refresh Request Body",
    )
    refresh_request_headers: Optional[Dict[str, Any]] = Field(
        None,
        description="Headers of the request sent to get a new access token.",
        examples=[
            {
                "Authorization": "<AUTH_TOKEN>",
                "Content-Type": "application/x-www-form-urlencoded",
            }
        ],
        title="Refresh Request Headers",
    )
    scopes: Optional[List[str]] = Field(
        None,
        description="List of scopes that should be granted to the access token.",
        examples=[["crm.list.read", "crm.objects.contacts.read", "crm.schema.contacts.read"]],
        title="Scopes",
    )
    token_expiry_date: Optional[str] = Field(
        None,
        description="The access token expiry date.",
        examples=["2023-04-06T07:12:10.421833+00:00", 1680842386],
        title="Token Expiry Date",
    )
    token_expiry_date_format: Optional[str] = Field(
        None,
        description="The format of the time to expiration datetime. Provide it if the time is returned as a date-time string instead of seconds.",
        examples=["%Y-%m-%d %H:%M:%S.%f+00:00"],
        title="Token Expiry Date Format",
    )
    refresh_token_updater: Optional[RefreshTokenUpdater] = Field(
        None,
        description="When the token updater is defined, new refresh tokens, access tokens and the access token expiry date are written back from the authentication response to the config object. This is important if the refresh token can only used once.",
        title="Token Updater",
    )
    profile_assertion: Optional[JwtAuthenticator] = Field(
        None,
        description="The authenticator being used to authenticate the client authenticator.",
        title="Profile Assertion",
    )
    use_profile_assertion: Optional[bool] = Field(
        False,
        description="Enable using profile assertion as a flow for OAuth authorization.",
        title="Use Profile Assertion",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class Rate(BaseModel):
    class Config:
        extra = Extra.allow

    limit: Union[int, str] = Field(
        ...,
        description="The maximum number of calls allowed within the interval.",
        title="Limit",
    )
    interval: str = Field(
        ...,
        description="The time interval for the rate limit.",
        examples=["PT1H", "P1D"],
        title="Interval",
    )


class HttpRequestRegexMatcher(BaseModel):
    class Config:
        extra = Extra.allow

    method: Optional[str] = Field(
        None, description="The HTTP method to match (e.g., GET, POST).", title="Method"
    )
    url_base: Optional[str] = Field(
        None,
        description='The base URL (scheme and host, e.g. "https://api.example.com") to match.',
        title="URL Base",
    )
    url_path_pattern: Optional[str] = Field(
        None,
        description="A regular expression pattern to match the URL path.",
        title="URL Path Pattern",
    )
    params: Optional[Dict[str, Any]] = Field(
        None, description="The query parameters to match.", title="Parameters"
    )
    headers: Optional[Dict[str, Any]] = Field(
        None, description="The headers to match.", title="Headers"
    )


class DpathExtractor(BaseModel):
    type: Literal["DpathExtractor"]
    field_path: List[str] = Field(
        ...,
        description='List of potentially nested fields describing the full path of the field to extract. Use "*" to extract all values from an array. See more info in the [docs](https://docs.airbyte.com/connector-development/config-based/understanding-the-yaml-file/record-selector).',
        examples=[
            ["data"],
            ["data", "records"],
            ["data", "{{ parameters.name }}"],
            ["data", "*", "record"],
        ],
        title="Field Path",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class ResponseToFileExtractor(BaseModel):
    type: Literal["ResponseToFileExtractor"]
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class ExponentialBackoffStrategy(BaseModel):
    type: Literal["ExponentialBackoffStrategy"]
    factor: Optional[Union[float, str]] = Field(
        5,
        description="Multiplicative constant applied on each retry.",
        examples=[5, 5.5, "10"],
        title="Factor",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class GroupByKeyMergeStrategy(BaseModel):
    type: Literal["GroupByKeyMergeStrategy"]
    key: Union[str, List[str]] = Field(
        ...,
        description="The name of the field on the record whose value will be used to group properties that were retrieved through multiple API requests.",
        examples=["id", ["parent_id", "end_date"]],
        title="Key",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class SessionTokenRequestBearerAuthenticator(BaseModel):
    type: Literal["Bearer"]


class HttpMethod(Enum):
    GET = "GET"
    POST = "POST"


class Action(Enum):
    SUCCESS = "SUCCESS"
    FAIL = "FAIL"
    RETRY = "RETRY"
    IGNORE = "IGNORE"
    RATE_LIMITED = "RATE_LIMITED"


class FailureType(Enum):
    system_error = "system_error"
    config_error = "config_error"
    transient_error = "transient_error"


class HttpResponseFilter(BaseModel):
    type: Literal["HttpResponseFilter"]
    action: Optional[Action] = Field(
        None,
        description="Action to execute if a response matches the filter.",
        examples=["SUCCESS", "FAIL", "RETRY", "IGNORE", "RATE_LIMITED"],
        title="Action",
    )
    failure_type: Optional[FailureType] = Field(
        None,
        description="Failure type of traced exception if a response matches the filter.",
        examples=["system_error", "config_error", "transient_error"],
        title="Failure Type",
    )
    error_message: Optional[str] = Field(
        None,
        description="Error Message to display if the response matches the filter.",
        title="Error Message",
    )
    error_message_contains: Optional[str] = Field(
        None,
        description="Match the response if its error message contains the substring.",
        example=["This API operation is not enabled for this site"],
        title="Error Message Substring",
    )
    http_codes: Optional[List[int]] = Field(
        None,
        description="Match the response if its HTTP code is included in this list.",
        examples=[[420, 429], [500]],
        title="HTTP Codes",
        unique_items=True,
    )
    predicate: Optional[str] = Field(
        None,
        description="Match the response if the predicate evaluates to true.",
        examples=[
            "{{ 'Too much requests' in response }}",
            "{{ 'error_code' in response and response['error_code'] == 'ComplexityException' }}",
        ],
        title="Predicate",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class ComplexFieldType(BaseModel):
    field_type: str
    items: Optional[Union[str, ComplexFieldType]] = None


class TypesMap(BaseModel):
    target_type: Union[str, List[str], ComplexFieldType]
    current_type: Union[str, List[str]]
    condition: Optional[str] = None


class SchemaTypeIdentifier(BaseModel):
    type: Optional[Literal["SchemaTypeIdentifier"]] = None
    schema_pointer: Optional[List[str]] = Field(
        [],
        description="List of nested fields defining the schema field path to extract. Defaults to [].",
        title="Schema Path",
    )
    key_pointer: List[str] = Field(
        ...,
        description="List of potentially nested fields describing the full path of the field key to extract.",
        title="Key Path",
    )
    type_pointer: Optional[List[str]] = Field(
        None,
        description="List of potentially nested fields describing the full path of the field type to extract.",
        title="Type Path",
    )
    types_mapping: Optional[List[TypesMap]] = None
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class InlineSchemaLoader(BaseModel):
    type: Literal["InlineSchemaLoader"]
    schema_: Optional[Dict[str, Any]] = Field(
        None,
        alias="schema",
        description='Describes a streams\' schema. Refer to the <a href="https://docs.airbyte.com/understanding-airbyte/supported-data-types/">Data Types documentation</a> for more details on which types are valid.',
        title="Schema",
    )


class JsonFileSchemaLoader(BaseModel):
    type: Literal["JsonFileSchemaLoader"]
    file_path: Optional[str] = Field(
        None,
        description="Path to the JSON file defining the schema. The path is relative to the connector module's root.",
        example=["./schemas/users.json"],
        title="File Path",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class JsonDecoder(BaseModel):
    type: Literal["JsonDecoder"]


class JsonlDecoder(BaseModel):
    type: Literal["JsonlDecoder"]


class KeysToLower(BaseModel):
    type: Literal["KeysToLower"]
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class KeysToSnakeCase(BaseModel):
    type: Literal["KeysToSnakeCase"]
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class FlattenFields(BaseModel):
    type: Literal["FlattenFields"]
    flatten_lists: Optional[bool] = Field(
        True,
        description="Whether to flatten lists or leave it as is. Default is True.",
        title="Flatten Lists",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class KeyTransformation(BaseModel):
    type: Literal["KeyTransformation"]
    prefix: Optional[str] = Field(
        None,
        description="Prefix to add for object keys. If not provided original keys remain unchanged.",
        examples=["flattened_"],
        title="Key Prefix",
    )
    suffix: Optional[str] = Field(
        None,
        description="Suffix to add for object keys. If not provided original keys remain unchanged.",
        examples=["_flattened"],
        title="Key Suffix",
    )


class DpathFlattenFields(BaseModel):
    type: Literal["DpathFlattenFields"]
    field_path: List[str] = Field(
        ...,
        description="A path to field that needs to be flattened.",
        examples=[["data"], ["data", "*", "field"]],
        title="Field Path",
    )
    delete_origin_value: Optional[bool] = Field(
        None,
        description="Whether to delete the origin value or keep it. Default is False.",
        title="Delete Origin Value",
    )
    replace_record: Optional[bool] = Field(
        None,
        description="Whether to replace the origin record or not. Default is False.",
        title="Replace Origin Record",
    )
    key_transformation: Optional[KeyTransformation] = Field(
        None,
        description="Transformation for object keys. If not provided, original key will be used.",
        title="Key transformation",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class KeysReplace(BaseModel):
    type: Literal["KeysReplace"]
    old: str = Field(
        ...,
        description="Old value to replace.",
        examples=[
            " ",
            "{{ record.id }}",
            "{{ config['id'] }}",
            "{{ stream_slice['id'] }}",
        ],
        title="Old value",
    )
    new: str = Field(
        ...,
        description="New value to set.",
        examples=[
            "_",
            "{{ record.id }}",
            "{{ config['id'] }}",
            "{{ stream_slice['id'] }}",
        ],
        title="New value",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class IterableDecoder(BaseModel):
    type: Literal["IterableDecoder"]


class XmlDecoder(BaseModel):
    type: Literal["XmlDecoder"]


class CustomDecoder(BaseModel):
    class Config:
        extra = Extra.allow

    type: Literal["CustomDecoder"]
    class_name: str = Field(
        ...,
        description="Fully-qualified name of the class that will be implementing the custom decoding. Has to be a sub class of Decoder. The format is `source_<name>.<package>.<class_name>`.",
        examples=["source_amazon_ads.components.GzipJsonlDecoder"],
        title="Class Name",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class MinMaxDatetime(BaseModel):
    type: Literal["MinMaxDatetime"]
    datetime: str = Field(
        ...,
        description="Datetime value.",
        examples=["2021-01-01", "2021-01-01T00:00:00Z", "{{ config['start_time'] }}"],
        title="Datetime",
    )
    datetime_format: Optional[str] = Field(
        "",
        description='Format of the datetime value. Defaults to "%Y-%m-%dT%H:%M:%S.%f%z" if left empty. Use placeholders starting with "%" to describe the format the API is using. The following placeholders are available:\n  * **%s**: Epoch unix timestamp - `1686218963`\n  * **%s_as_float**: Epoch unix timestamp in seconds as float with microsecond precision - `1686218963.123456`\n  * **%ms**: Epoch unix timestamp - `1686218963123`\n  * **%a**: Weekday (abbreviated) - `Sun`\n  * **%A**: Weekday (full) - `Sunday`\n  * **%w**: Weekday (decimal) - `0` (Sunday), `6` (Saturday)\n  * **%d**: Day of the month (zero-padded) - `01`, `02`, ..., `31`\n  * **%b**: Month (abbreviated) - `Jan`\n  * **%B**: Month (full) - `January`\n  * **%m**: Month (zero-padded) - `01`, `02`, ..., `12`\n  * **%y**: Year (without century, zero-padded) - `00`, `01`, ..., `99`\n  * **%Y**: Year (with century) - `0001`, `0002`, ..., `9999`\n  * **%H**: Hour (24-hour, zero-padded) - `00`, `01`, ..., `23`\n  * **%I**: Hour (12-hour, zero-padded) - `01`, `02`, ..., `12`\n  * **%p**: AM/PM indicator\n  * **%M**: Minute (zero-padded) - `00`, `01`, ..., `59`\n  * **%S**: Second (zero-padded) - `00`, `01`, ..., `59`\n  * **%f**: Microsecond (zero-padded to 6 digits) - `000000`, `000001`, ..., `999999`\n  * **%_ms**: Millisecond (zero-padded to 3 digits) - `000`, `001`, ..., `999`\n  * **%z**: UTC offset - `(empty)`, `+0000`, `-04:00`\n  * **%Z**: Time zone name - `(empty)`, `UTC`, `GMT`\n  * **%j**: Day of the year (zero-padded) - `001`, `002`, ..., `366`\n  * **%U**: Week number of the year (Sunday as first day) - `00`, `01`, ..., `53`\n  * **%W**: Week number of the year (Monday as first day) - `00`, `01`, ..., `53`\n  * **%c**: Date and time representation - `Tue Aug 16 21:30:00 1988`\n  * **%x**: Date representation - `08/16/1988`\n  * **%X**: Time representation - `21:30:00`\n  * **%%**: Literal \'%\' character\n\n  Some placeholders depend on the locale of the underlying system - in most cases this locale is configured as en/US. For more information see the [Python documentation](https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes).\n',
        examples=["%Y-%m-%dT%H:%M:%S.%f%z", "%Y-%m-%d", "%s"],
        title="Datetime Format",
    )
    max_datetime: Optional[str] = Field(
        None,
        description="Ceiling applied on the datetime value. Must be formatted with the datetime_format field.",
        examples=["2021-01-01T00:00:00Z", "2021-01-01"],
        title="Max Datetime",
    )
    min_datetime: Optional[str] = Field(
        None,
        description="Floor applied on the datetime value. Must be formatted with the datetime_format field.",
        examples=["2010-01-01T00:00:00Z", "2010-01-01"],
        title="Min Datetime",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class NoAuth(BaseModel):
    type: Literal["NoAuth"]
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class NoPagination(BaseModel):
    type: Literal["NoPagination"]


class State(BaseModel):
    class Config:
        extra = Extra.allow

    min: int
    max: int


class OauthConnectorInputSpecification(BaseModel):
    class Config:
        extra = Extra.allow

    consent_url: str = Field(
        ...,
        description="The DeclarativeOAuth Specific string URL string template to initiate the authentication.\nThe placeholders are replaced during the processing to provide neccessary values.",
        examples=[
            "https://domain.host.com/marketing_api/auth?{{client_id_key}}={{client_id_value}}&{{redirect_uri_key}}={{{{redirect_uri_value}} | urlEncoder}}&{{state_key}}={{state_value}}",
            "https://endpoint.host.com/oauth2/authorize?{{client_id_key}}={{client_id_value}}&{{redirect_uri_key}}={{{{redirect_uri_value}} | urlEncoder}}&{{scope_key}}={{{{scope_value}} | urlEncoder}}&{{state_key}}={{state_value}}&subdomain={{subdomain}}",
        ],
        title="Consent URL",
    )
    scope: Optional[str] = Field(
        None,
        description="The DeclarativeOAuth Specific string of the scopes needed to be grant for authenticated user.",
        examples=["user:read user:read_orders workspaces:read"],
        title="Scopes",
    )
    access_token_url: str = Field(
        ...,
        description="The DeclarativeOAuth Specific URL templated string to obtain the `access_token`, `refresh_token` etc.\nThe placeholders are replaced during the processing to provide neccessary values.",
        examples=[
            "https://auth.host.com/oauth2/token?{{client_id_key}}={{client_id_value}}&{{client_secret_key}}={{client_secret_value}}&{{auth_code_key}}={{auth_code_value}}&{{redirect_uri_key}}={{{{redirect_uri_value}} | urlEncoder}}"
        ],
        title="Access Token URL",
    )
    access_token_headers: Optional[Dict[str, Any]] = Field(
        None,
        description="The DeclarativeOAuth Specific optional headers to inject while exchanging the `auth_code` to `access_token` during `completeOAuthFlow` step.",
        examples=[
            {
                "Authorization": "Basic {{ {{ client_id_value }}:{{ client_secret_value }} | base64Encoder }}"
            }
        ],
        title="Access Token Headers",
    )
    access_token_params: Optional[Dict[str, Any]] = Field(
        None,
        description="The DeclarativeOAuth Specific optional query parameters to inject while exchanging the `auth_code` to `access_token` during `completeOAuthFlow` step.\nWhen this property is provided, the query params will be encoded as `Json` and included in the outgoing API request.",
        examples=[
            {
                "{{ auth_code_key }}": "{{ auth_code_value }}",
                "{{ client_id_key }}": "{{ client_id_value }}",
                "{{ client_secret_key }}": "{{ client_secret_value }}",
            }
        ],
        title="Access Token Query Params (Json Encoded)",
    )
    extract_output: Optional[List[str]] = Field(
        None,
        description="The DeclarativeOAuth Specific list of strings to indicate which keys should be extracted and returned back to the input config.",
        examples=[["access_token", "refresh_token", "other_field"]],
        title="Extract Output",
    )
    state: Optional[State] = Field(
        None,
        description="The DeclarativeOAuth Specific object to provide the criteria of how the `state` query param should be constructed,\nincluding length and complexity.",
        examples=[{"min": 7, "max": 128}],
        title="Configurable State Query Param",
    )
    client_id_key: Optional[str] = Field(
        None,
        description="The DeclarativeOAuth Specific optional override to provide the custom `client_id` key name, if required by data-provider.",
        examples=["my_custom_client_id_key_name"],
        title="Client ID Key Override",
    )
    client_secret_key: Optional[str] = Field(
        None,
        description="The DeclarativeOAuth Specific optional override to provide the custom `client_secret` key name, if required by data-provider.",
        examples=["my_custom_client_secret_key_name"],
        title="Client Secret Key Override",
    )
    scope_key: Optional[str] = Field(
        None,
        description="The DeclarativeOAuth Specific optional override to provide the custom `scope` key name, if required by data-provider.",
        examples=["my_custom_scope_key_key_name"],
        title="Scopes Key Override",
    )
    state_key: Optional[str] = Field(
        None,
        description="The DeclarativeOAuth Specific optional override to provide the custom `state` key name, if required by data-provider.",
        examples=["my_custom_state_key_key_name"],
        title="State Key Override",
    )
    auth_code_key: Optional[str] = Field(
        None,
        description="The DeclarativeOAuth Specific optional override to provide the custom `code` key name to something like `auth_code` or `custom_auth_code`, if required by data-provider.",
        examples=["my_custom_auth_code_key_name"],
        title="Auth Code Key Override",
    )
    redirect_uri_key: Optional[str] = Field(
        None,
        description="The DeclarativeOAuth Specific optional override to provide the custom `redirect_uri` key name to something like `callback_uri`, if required by data-provider.",
        examples=["my_custom_redirect_uri_key_name"],
        title="Redirect URI Key Override",
    )


class OAuthConfigSpecification(BaseModel):
    class Config:
        extra = Extra.allow

    oauth_user_input_from_connector_config_specification: Optional[Dict[str, Any]] = Field(
        None,
        description="OAuth specific blob. This is a Json Schema used to validate Json configurations used as input to OAuth.\nMust be a valid non-nested JSON that refers to properties from ConnectorSpecification.connectionSpecification\nusing special annotation 'path_in_connector_config'.\nThese are input values the user is entering through the UI to authenticate to the connector, that might also shared\nas inputs for syncing data via the connector.\nExamples:\nif no connector values is shared during oauth flow, oauth_user_input_from_connector_config_specification=[]\nif connector values such as 'app_id' inside the top level are used to generate the API url for the oauth flow,\n  oauth_user_input_from_connector_config_specification={\n    app_id: {\n      type: string\n      path_in_connector_config: ['app_id']\n    }\n  }\nif connector values such as 'info.app_id' nested inside another object are used to generate the API url for the oauth flow,\n  oauth_user_input_from_connector_config_specification={\n    app_id: {\n      type: string\n      path_in_connector_config: ['info', 'app_id']\n    }\n  }",
        examples=[
            {"app_id": {"type": "string", "path_in_connector_config": ["app_id"]}},
            {
                "app_id": {
                    "type": "string",
                    "path_in_connector_config": ["info", "app_id"],
                }
            },
        ],
        title="OAuth user input",
    )
    oauth_connector_input_specification: Optional[OauthConnectorInputSpecification] = Field(
        None,
        description='The DeclarativeOAuth specific blob.\nPertains to the fields defined by the connector relating to the OAuth flow.\n\nInterpolation capabilities:\n- The variables placeholders are declared as `{{my_var}}`.\n- The nested resolution variables like `{{ {{my_nested_var}} }}` is allowed as well.\n\n- The allowed interpolation context is:\n  + base64Encoder - encode to `base64`, {{ {{my_var_a}}:{{my_var_b}} | base64Encoder }}\n  + base64Decorer - decode from `base64` encoded string, {{ {{my_string_variable_or_string_value}} | base64Decoder }}\n  + urlEncoder - encode the input string to URL-like format, {{ https://test.host.com/endpoint | urlEncoder}}\n  + urlDecorer - decode the input url-encoded string into text format, {{ urlDecoder:https%3A%2F%2Fairbyte.io | urlDecoder}}\n  + codeChallengeS256 - get the `codeChallenge` encoded value to provide additional data-provider specific authorisation values, {{ {{state_value}} | codeChallengeS256 }}\n\nExamples:\n  - The TikTok Marketing DeclarativeOAuth spec:\n  {\n    "oauth_connector_input_specification": {\n      "type": "object",\n      "additionalProperties": false,\n      "properties": {\n          "consent_url": "https://ads.tiktok.com/marketing_api/auth?{{client_id_key}}={{client_id_value}}&{{redirect_uri_key}}={{ {{redirect_uri_value}} | urlEncoder}}&{{state_key}}={{state_value}}",\n          "access_token_url": "https://business-api.tiktok.com/open_api/v1.3/oauth2/access_token/",\n          "access_token_params": {\n              "{{ auth_code_key }}": "{{ auth_code_value }}",\n              "{{ client_id_key }}": "{{ client_id_value }}",\n              "{{ client_secret_key }}": "{{ client_secret_value }}"\n          },\n          "access_token_headers": {\n              "Content-Type": "application/json",\n              "Accept": "application/json"\n          },\n          "extract_output": ["data.access_token"],\n          "client_id_key": "app_id",\n          "client_secret_key": "secret",\n          "auth_code_key": "auth_code"\n      }\n    }\n  }',
        title="DeclarativeOAuth Connector Specification",
    )
    complete_oauth_output_specification: Optional[Dict[str, Any]] = Field(
        None,
        description="OAuth specific blob. This is a Json Schema used to validate Json configurations produced by the OAuth flows as they are\nreturned by the distant OAuth APIs.\nMust be a valid JSON describing the fields to merge back to `ConnectorSpecification.connectionSpecification`.\nFor each field, a special annotation `path_in_connector_config` can be specified to determine where to merge it,\nExamples:\n    complete_oauth_output_specification={\n      refresh_token: {\n        type: string,\n        path_in_connector_config: ['credentials', 'refresh_token']\n      }\n    }",
        examples=[
            {
                "refresh_token": {
                    "type": "string,",
                    "path_in_connector_config": ["credentials", "refresh_token"],
                }
            }
        ],
        title="OAuth output specification",
    )
    complete_oauth_server_input_specification: Optional[Dict[str, Any]] = Field(
        None,
        description="OAuth specific blob. This is a Json Schema used to validate Json configurations persisted as Airbyte Server configurations.\nMust be a valid non-nested JSON describing additional fields configured by the Airbyte Instance or Workspace Admins to be used by the\nserver when completing an OAuth flow (typically exchanging an auth code for refresh token).\nExamples:\n    complete_oauth_server_input_specification={\n      client_id: {\n        type: string\n      },\n      client_secret: {\n        type: string\n      }\n    }",
        examples=[{"client_id": {"type": "string"}, "client_secret": {"type": "string"}}],
        title="OAuth input specification",
    )
    complete_oauth_server_output_specification: Optional[Dict[str, Any]] = Field(
        None,
        description="OAuth specific blob. This is a Json Schema used to validate Json configurations persisted as Airbyte Server configurations that\nalso need to be merged back into the connector configuration at runtime.\nThis is a subset configuration of `complete_oauth_server_input_specification` that filters fields out to retain only the ones that\nare necessary for the connector to function with OAuth. (some fields could be used during oauth flows but not needed afterwards, therefore\nthey would be listed in the `complete_oauth_server_input_specification` but not `complete_oauth_server_output_specification`)\nMust be a valid non-nested JSON describing additional fields configured by the Airbyte Instance or Workspace Admins to be used by the\nconnector when using OAuth flow APIs.\nThese fields are to be merged back to `ConnectorSpecification.connectionSpecification`.\nFor each field, a special annotation `path_in_connector_config` can be specified to determine where to merge it,\nExamples:\n      complete_oauth_server_output_specification={\n        client_id: {\n          type: string,\n          path_in_connector_config: ['credentials', 'client_id']\n        },\n        client_secret: {\n          type: string,\n          path_in_connector_config: ['credentials', 'client_secret']\n        }\n      }",
        examples=[
            {
                "client_id": {
                    "type": "string,",
                    "path_in_connector_config": ["credentials", "client_id"],
                },
                "client_secret": {
                    "type": "string,",
                    "path_in_connector_config": ["credentials", "client_secret"],
                },
            }
        ],
        title="OAuth server output specification",
    )


class OffsetIncrement(BaseModel):
    type: Literal["OffsetIncrement"]
    page_size: Optional[Union[int, str]] = Field(
        None,
        description="The number of records to include in each pages.",
        examples=[100, "{{ config['page_size'] }}"],
        title="Limit",
    )
    inject_on_first_request: Optional[bool] = Field(
        False,
        description="Using the `offset` with value `0` during the first request",
        title="Inject Offset",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class PageIncrement(BaseModel):
    type: Literal["PageIncrement"]
    page_size: Optional[Union[int, str]] = Field(
        None,
        description="The number of records to include in each pages.",
        examples=[100, "100", "{{ config['page_size'] }}"],
        title="Page Size",
    )
    start_from_page: Optional[int] = Field(
        0,
        description="Index of the first page to request.",
        examples=[0, 1],
        title="Start From Page",
    )
    inject_on_first_request: Optional[bool] = Field(
        False,
        description="Using the `page number` with value defined by `start_from_page` during the first request",
        title="Inject Page Number",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class PrimaryKey(BaseModel):
    __root__: Union[str, List[str], List[List[str]]] = Field(
        ...,
        description="The stream field to be used to distinguish unique records. Can either be a single field, an array of fields representing a composite key, or an array of arrays representing a composite key where the fields are nested fields.",
        examples=["id", ["code", "type"]],
        title="Primary Key",
    )


class PropertyLimitType(Enum):
    characters = "characters"
    property_count = "property_count"


class PropertyChunking(BaseModel):
    type: Literal["PropertyChunking"]
    property_limit_type: PropertyLimitType = Field(
        ...,
        description="The type used to determine the maximum number of properties per chunk",
        title="Property Limit Type",
    )
    property_limit: Optional[int] = Field(
        None,
        description="The maximum amount of properties that can be retrieved per request according to the limit type.",
        title="Property Limit",
    )
    record_merge_strategy: Optional[GroupByKeyMergeStrategy] = Field(
        None,
        description="Dictates how to records that require multiple requests to get all properties should be emitted to the destination",
        title="Record Merge Strategy",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class RecordFilter(BaseModel):
    type: Literal["RecordFilter"]
    condition: Optional[str] = Field(
        "",
        description="The predicate to filter a record. Records will be removed if evaluated to False.",
        examples=[
            "{{ record['created_at'] >= stream_interval['start_time'] }}",
            "{{ record.status in ['active', 'expired'] }}",
        ],
        title="Condition",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class SchemaNormalization(Enum):
    Default = "Default"
    None_ = "None"


class RemoveFields(BaseModel):
    type: Literal["RemoveFields"]
    condition: Optional[str] = Field(
        "",
        description="The predicate to filter a property by a property value. Property will be removed if it is empty OR expression is evaluated to True.,",
        examples=[
            "{{ property|string == '' }}",
            "{{ property is integer }}",
            "{{ property|length > 5 }}",
            "{{ property == 'some_string_to_match' }}",
        ],
    )
    field_pointers: List[List[str]] = Field(
        ...,
        description="Array of paths defining the field to remove. Each item is an array whose field describe the path of a field to remove.",
        examples=[["tags"], [["content", "html"], ["content", "plain_text"]]],
        title="Field Paths",
    )


class RequestPath(BaseModel):
    type: Literal["RequestPath"]


class InjectInto(Enum):
    request_parameter = "request_parameter"
    header = "header"
    body_data = "body_data"
    body_json = "body_json"


class RequestOption(BaseModel):
    type: Literal["RequestOption"]
    field_name: Optional[str] = Field(
        None,
        description="Configures which key should be used in the location that the descriptor is being injected into. We hope to eventually deprecate this field in favor of `field_path` for all request_options, but must currently maintain it for backwards compatibility in the Builder.",
        examples=["segment_id"],
        title="Field Name",
    )
    field_path: Optional[List[str]] = Field(
        None,
        description="Configures a path to be used for nested structures in JSON body requests (e.g. GraphQL queries)",
        examples=[["data", "viewer", "id"]],
        title="Field Path",
    )
    inject_into: InjectInto = Field(
        ...,
        description="Configures where the descriptor should be set on the HTTP requests. Note that request parameters that are already encoded in the URL path will not be duplicated.",
        examples=["request_parameter", "header", "body_data", "body_json"],
        title="Inject Into",
    )


class Schemas(BaseModel):
    pass

    class Config:
        extra = Extra.allow


class LegacySessionTokenAuthenticator(BaseModel):
    type: Literal["LegacySessionTokenAuthenticator"]
    header: str = Field(
        ...,
        description="The name of the session token header that will be injected in the request",
        examples=["X-Session"],
        title="Session Request Header",
    )
    login_url: str = Field(
        ...,
        description="Path of the login URL (do not include the base URL)",
        examples=["session"],
        title="Login Path",
    )
    session_token: Optional[str] = Field(
        None,
        description="Session token to use if using a pre-defined token. Not needed if authenticating with username + password pair",
        example=["{{ config['session_token'] }}"],
        title="Session Token",
    )
    session_token_response_key: str = Field(
        ...,
        description="Name of the key of the session token to be extracted from the response",
        examples=["id"],
        title="Response Token Response Key",
    )
    username: Optional[str] = Field(
        None,
        description="Username used to authenticate and obtain a session token",
        examples=[" {{ config['username'] }}"],
        title="Username",
    )
    password: Optional[str] = Field(
        "",
        description="Password used to authenticate and obtain a session token",
        examples=["{{ config['password'] }}", ""],
        title="Password",
    )
    validate_session_url: str = Field(
        ...,
        description="Path of the URL to use to validate that the session token is valid (do not include the base URL)",
        examples=["user/current"],
        title="Validate Session Path",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class CsvDecoder(BaseModel):
    type: Literal["CsvDecoder"]
    encoding: Optional[str] = "utf-8"
    delimiter: Optional[str] = ","
    set_values_to_none: Optional[List[str]] = None


class AsyncJobStatusMap(BaseModel):
    type: Optional[Literal["AsyncJobStatusMap"]] = None
    running: List[str]
    completed: List[str]
    failed: List[str]
    timeout: List[str]


class ValueType(Enum):
    string = "string"
    number = "number"
    integer = "integer"
    boolean = "boolean"


class WaitTimeFromHeader(BaseModel):
    type: Literal["WaitTimeFromHeader"]
    header: str = Field(
        ...,
        description="The name of the response header defining how long to wait before retrying.",
        examples=["Retry-After"],
        title="Response Header Name",
    )
    regex: Optional[str] = Field(
        None,
        description="Optional regex to apply on the header to extract its value. The regex should define a capture group defining the wait time.",
        examples=["([-+]?\\d+)"],
        title="Extraction Regex",
    )
    max_waiting_time_in_seconds: Optional[float] = Field(
        None,
        description="Given the value extracted from the header is greater than this value, stop the stream.",
        examples=[3600],
        title="Max Waiting Time in Seconds",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class WaitUntilTimeFromHeader(BaseModel):
    type: Literal["WaitUntilTimeFromHeader"]
    header: str = Field(
        ...,
        description="The name of the response header defining how long to wait before retrying.",
        examples=["wait_time"],
        title="Response Header",
    )
    min_wait: Optional[Union[float, str]] = Field(
        None,
        description="Minimum time to wait before retrying.",
        examples=[10, "60"],
        title="Minimum Wait Time",
    )
    regex: Optional[str] = Field(
        None,
        description="Optional regex to apply on the header to extract its value. The regex should define a capture group defining the wait time.",
        examples=["([-+]?\\d+)"],
        title="Extraction Regex",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class ComponentMappingDefinition(BaseModel):
    type: Literal["ComponentMappingDefinition"]
    field_path: List[str] = Field(
        ...,
        description="A list of potentially nested fields indicating the full path where value will be added or updated.",
        examples=[
            ["data"],
            ["data", "records"],
            ["data", 1, "name"],
            ["data", "{{ components_values.name }}"],
            ["data", "*", "record"],
            ["*", "**", "name"],
        ],
        title="Field Path",
    )
    value: str = Field(
        ...,
        description="The dynamic or static value to assign to the key. Interpolated values can be used to dynamically determine the value during runtime.",
        examples=[
            "{{ components_values['updates'] }}",
            "{{ components_values['MetaData']['LastUpdatedTime'] }}",
            "{{ config['segment_id'] }}",
            "{{ stream_slice['parent_id'] }}",
            "{{ stream_slice['extra_fields']['name'] }}",
        ],
        title="Value",
    )
    value_type: Optional[ValueType] = Field(
        None,
        description="The expected data type of the value. If omitted, the type will be inferred from the value provided.",
        title="Value Type",
    )
    create_or_update: Optional[bool] = Field(
        False,
        description="Determines whether to create a new path if it doesn't exist (true) or only update existing paths (false). When set to true, the resolver will create new paths in the stream template if they don't exist. When false (default), it will only update existing paths.",
        title="Create or Update",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class StreamConfig(BaseModel):
    type: Literal["StreamConfig"]
    configs_pointer: List[str] = Field(
        ...,
        description="A list of potentially nested fields indicating the full path in source config file where streams configs located.",
        examples=[["data"], ["data", "streams"], ["data", "{{ parameters.name }}"]],
        title="Configs Pointer",
    )
    default_values: Optional[List[Dict[str, Any]]] = Field(
        None,
        description="A list of default values, each matching the structure expected from the parsed component value.",
        title="Default Values",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class ConfigComponentsResolver(BaseModel):
    type: Literal["ConfigComponentsResolver"]
    stream_config: Union[List[StreamConfig], StreamConfig]
    components_mapping: List[ComponentMappingDefinition]
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class RequestBodyPlainText(BaseModel):
    type: Literal["RequestBodyPlainText"]
    value: str


class RequestBodyUrlEncodedForm(BaseModel):
    type: Literal["RequestBodyUrlEncodedForm"]
    value: Dict[str, str]


class RequestBodyJsonObject(BaseModel):
    type: Literal["RequestBodyJsonObject"]
    value: Dict[str, Any]


class RequestBodyGraphQlQuery(BaseModel):
    class Config:
        extra = Extra.allow

    query: Dict[str, Any] = Field(..., description="The GraphQL query to be executed")


class ValidateAdheresToSchema(BaseModel):
    type: Literal["ValidateAdheresToSchema"]
    base_schema: Union[str, Dict[str, Any]] = Field(
        ...,
        description="The base JSON schema against which the user-provided schema will be validated.",
        examples=[
            "{{ config['report_validation_schema'] }}",
            '\'{\n  "$schema": "http://json-schema.org/draft-07/schema#",\n  "title": "Person",\n  "type": "object",\n  "properties": {\n    "name": {\n      "type": "string",\n      "description": "The person\'s name"\n    },\n    "age": {\n      "type": "integer",\n      "minimum": 0,\n      "description": "The person\'s age"\n    }\n  },\n  "required": ["name", "age"]\n}\'\n',
            {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "title": "Person",
                "type": "object",
                "properties": {
                    "name": {"type": "string", "description": "The person's name"},
                    "age": {
                        "type": "integer",
                        "minimum": 0,
                        "description": "The person's age",
                    },
                },
                "required": ["name", "age"],
            },
        ],
        title="Base JSON Schema",
    )


class ConfigRemapField(BaseModel):
    type: Literal["ConfigRemapField"]
    map: Union[Dict[str, Any], str] = Field(
        ...,
        description="A mapping of original values to new values. When a field value matches a key in this map, it will be replaced with the corresponding value.",
        examples=[
            {"pending": "in_progress", "done": "completed", "cancelled": "terminated"},
            "{{ config['status_mapping'] }}",
        ],
        title="Value Mapping",
    )
    field_path: List[str] = Field(
        ...,
        description="The path to the field whose value should be remapped. Specified as a list of path components to navigate through nested objects.",
        examples=[
            ["status"],
            ["data", "status"],
            ["data", "{{ config.name }}", "status"],
            ["data", "*", "status"],
        ],
        title="Field Path",
    )


class ConfigRemoveFields(BaseModel):
    type: Literal["ConfigRemoveFields"]
    field_pointers: List[List[str]] = Field(
        ...,
        description="A list of field pointers to be removed from the config.",
        examples=[["tags"], [["content", "html"], ["content", "plain_text"]]],
        title="Field Pointers",
    )
    condition: Optional[str] = Field(
        "",
        description="Fields will be removed if expression is evaluated to True.",
        examples=[
            "{{ config['environemnt'] == 'sandbox' }}",
            "{{ property is integer }}",
            "{{ property|length > 5 }}",
            "{{ property == 'some_string_to_match' }}",
        ],
    )


class AddedFieldDefinition(BaseModel):
    type: Literal["AddedFieldDefinition"]
    path: List[str] = Field(
        ...,
        description="List of strings defining the path where to add the value on the record.",
        examples=[["segment_id"], ["metadata", "segment_id"]],
        title="Path",
    )
    value: str = Field(
        ...,
        description="Value of the new field. Use {{ record['existing_field'] }} syntax to refer to other fields in the record.",
        examples=[
            "{{ record['updates'] }}",
            "{{ record['MetaData']['LastUpdatedTime'] }}",
            "{{ stream_partition['segment_id'] }}",
        ],
        title="Value",
    )
    value_type: Optional[ValueType] = Field(
        None,
        description="Type of the value. If not specified, the type will be inferred from the value.",
        title="Value Type",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class AddFields(BaseModel):
    type: Literal["AddFields"]
    fields: List[AddedFieldDefinition] = Field(
        ...,
        description="List of transformations (path and corresponding value) that will be added to the record.",
        title="Fields",
    )
    condition: Optional[str] = Field(
        "",
        description="Fields will be added if expression is evaluated to True.",
        examples=[
            "{{ property|string == '' }}",
            "{{ property is integer }}",
            "{{ property|length > 5 }}",
            "{{ property == 'some_string_to_match' }}",
        ],
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class ApiKeyAuthenticator(BaseModel):
    type: Literal["ApiKeyAuthenticator"]
    api_token: Optional[str] = Field(
        None,
        description="The API key to inject in the request. Fill it in the user inputs.",
        examples=["{{ config['api_key'] }}", "Token token={{ config['api_key'] }}"],
        title="API Key",
    )
    header: Optional[str] = Field(
        None,
        description="The name of the HTTP header that will be set to the API key. This setting is deprecated, use inject_into instead. Header and inject_into can not be defined at the same time.",
        examples=["Authorization", "Api-Token", "X-Auth-Token"],
        title="Header Name",
    )
    inject_into: Optional[RequestOption] = Field(
        None,
        description="Configure how the API Key will be sent in requests to the source API. Either inject_into or header has to be defined.",
        examples=[
            {"inject_into": "header", "field_name": "Authorization"},
            {"inject_into": "request_parameter", "field_name": "authKey"},
        ],
        title="Inject API Key Into Outgoing HTTP Request",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class AuthFlow(BaseModel):
    auth_flow_type: Optional[AuthFlowType] = Field(
        None, description="The type of auth to use", title="Auth flow type"
    )
    predicate_key: Optional[List[str]] = Field(
        None,
        description="JSON path to a field in the connectorSpecification that should exist for the advanced auth to be applicable.",
        examples=[["credentials", "auth_type"]],
        title="Predicate key",
    )
    predicate_value: Optional[str] = Field(
        None,
        description="Value of the predicate_key fields for the advanced auth to be applicable.",
        examples=["Oauth"],
        title="Predicate value",
    )
    oauth_config_specification: Optional[OAuthConfigSpecification] = None


class CheckStream(BaseModel):
    type: Literal["CheckStream"]
    stream_names: Optional[List[str]] = Field(
        None,
        description="Names of the streams to try reading from when running a check operation.",
        examples=[["users"], ["users", "contacts"]],
        title="Stream Names",
    )
    dynamic_streams_check_configs: Optional[List[DynamicStreamCheckConfig]] = None


class IncrementingCountCursor(BaseModel):
    type: Literal["IncrementingCountCursor"]
    cursor_field: str = Field(
        ...,
        description="The location of the value on a record that will be used as a bookmark during sync. To ensure no data loss, the API must return records in ascending order based on the cursor field. Nested fields are not supported, so the field must be at the top level of the record. You can use a combination of Add Field and Remove Field transformations to move the nested field to the top.",
        examples=["created_at", "{{ config['record_cursor'] }}"],
        title="Cursor Field",
    )
    start_value: Optional[Union[str, int]] = Field(
        None,
        description="The value that determines the earliest record that should be synced.",
        examples=[0, "{{ config['start_value'] }}"],
        title="Start Value",
    )
    start_value_option: Optional[RequestOption] = Field(
        None,
        description="Optionally configures how the start value will be sent in requests to the source API.",
        title="Inject Start Value Into Outgoing HTTP Request",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class DatetimeBasedCursor(BaseModel):
    type: Literal["DatetimeBasedCursor"]
    clamping: Optional[Clamping] = Field(
        None,
        description="This option is used to adjust the upper and lower boundaries of each datetime window to beginning and end of the provided target period (day, week, month)",
        title="Date Range Clamping",
    )
    cursor_field: str = Field(
        ...,
        description="The location of the value on a record that will be used as a bookmark during sync. To ensure no data loss, the API must return records in ascending order based on the cursor field. Nested fields are not supported, so the field must be at the top level of the record. You can use a combination of Add Field and Remove Field transformations to move the nested field to the top.",
        examples=["created_at", "{{ config['record_cursor'] }}"],
        title="Cursor Field",
    )
    datetime_format: str = Field(
        ...,
        description="The datetime format used to format the datetime values that are sent in outgoing requests to the API. Use placeholders starting with \"%\" to describe the format the API is using. The following placeholders are available:\n  * **%s**: Epoch unix timestamp - `1686218963`\n  * **%s_as_float**: Epoch unix timestamp in seconds as float with microsecond precision - `1686218963.123456`\n  * **%ms**: Epoch unix timestamp (milliseconds) - `1686218963123`\n  * **%a**: Weekday (abbreviated) - `Sun`\n  * **%A**: Weekday (full) - `Sunday`\n  * **%w**: Weekday (decimal) - `0` (Sunday), `6` (Saturday)\n  * **%d**: Day of the month (zero-padded) - `01`, `02`, ..., `31`\n  * **%b**: Month (abbreviated) - `Jan`\n  * **%B**: Month (full) - `January`\n  * **%m**: Month (zero-padded) - `01`, `02`, ..., `12`\n  * **%y**: Year (without century, zero-padded) - `00`, `01`, ..., `99`\n  * **%Y**: Year (with century) - `0001`, `0002`, ..., `9999`\n  * **%H**: Hour (24-hour, zero-padded) - `00`, `01`, ..., `23`\n  * **%I**: Hour (12-hour, zero-padded) - `01`, `02`, ..., `12`\n  * **%p**: AM/PM indicator\n  * **%M**: Minute (zero-padded) - `00`, `01`, ..., `59`\n  * **%S**: Second (zero-padded) - `00`, `01`, ..., `59`\n  * **%f**: Microsecond (zero-padded to 6 digits) - `000000`\n  * **%_ms**: Millisecond (zero-padded to 3 digits) - `000`\n  * **%z**: UTC offset - `(empty)`, `+0000`, `-04:00`\n  * **%Z**: Time zone name - `(empty)`, `UTC`, `GMT`\n  * **%j**: Day of the year (zero-padded) - `001`, `002`, ..., `366`\n  * **%U**: Week number of the year (starting Sunday) - `00`, ..., `53`\n  * **%W**: Week number of the year (starting Monday) - `00`, ..., `53`\n  * **%c**: Date and time - `Tue Aug 16 21:30:00 1988`\n  * **%x**: Date standard format - `08/16/1988`\n  * **%X**: Time standard format - `21:30:00`\n  * **%%**: Literal '%' character\n\n  Some placeholders depend on the locale of the underlying system - in most cases this locale is configured as en/US. For more information see the [Python documentation](https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes).\n",
        examples=["%Y-%m-%dT%H:%M:%S.%f%z", "%Y-%m-%d", "%s", "%ms", "%s_as_float"],
        title="Outgoing Datetime Format",
    )
    start_datetime: Union[str, MinMaxDatetime] = Field(
        ...,
        description="The datetime that determines the earliest record that should be synced.",
        examples=["2020-01-1T00:00:00Z", "{{ config['start_time'] }}"],
        title="Start Datetime",
    )
    cursor_datetime_formats: Optional[List[str]] = Field(
        None,
        description="The possible formats for the cursor field, in order of preference. The first format that matches the cursor field value will be used to parse it. If not provided, the `datetime_format` will be used.",
        title="Cursor Datetime Formats",
    )
    cursor_granularity: Optional[str] = Field(
        None,
        description="Smallest increment the datetime_format has (ISO 8601 duration) that is used to ensure the start of a slice does not overlap with the end of the previous one, e.g. for %Y-%m-%d the granularity should be P1D, for %Y-%m-%dT%H:%M:%SZ the granularity should be PT1S. Given this field is provided, `step` needs to be provided as well.",
        examples=["PT1S"],
        title="Cursor Granularity",
    )
    end_datetime: Optional[Union[str, MinMaxDatetime]] = Field(
        None,
        description="The datetime that determines the last record that should be synced. If not provided, `{{ now_utc() }}` will be used.",
        examples=["2021-01-1T00:00:00Z", "{{ now_utc() }}", "{{ day_delta(-1) }}"],
        title="End Datetime",
    )
    end_time_option: Optional[RequestOption] = Field(
        None,
        description="Optionally configures how the end datetime will be sent in requests to the source API.",
        title="Inject End Time Into Outgoing HTTP Request",
    )
    is_data_feed: Optional[bool] = Field(
        None,
        description="A data feed API is an API that does not allow filtering and paginates the content from the most recent to the least recent. Given this, the CDK needs to know when to stop paginating and this field will generate a stop condition for pagination.",
        title="Whether the target API is formatted as a data feed",
    )
    is_client_side_incremental: Optional[bool] = Field(
        None,
        description="If the target API endpoint does not take cursor values to filter records and returns all records anyway, the connector with this cursor will filter out records locally, and only emit new records from the last sync, hence incremental. This means that all records would be read from the API, but only new records will be emitted to the destination.",
        title="Whether the target API does not support filtering and returns all data (the cursor filters records in the client instead of the API side)",
    )
    is_compare_strictly: Optional[bool] = Field(
        False,
        description="Set to True if the target API does not accept queries where the start time equal the end time.",
        title="Whether to skip requests if the start time equals the end time",
    )
    global_substream_cursor: Optional[bool] = Field(
        False,
        description="This setting optimizes performance when the parent stream has thousands of partitions by storing the cursor as a single value rather than per partition. Notably, the substream state is updated only at the end of the sync, which helps prevent data loss in case of a sync failure. See more info in the [docs](https://docs.airbyte.com/connector-development/config-based/understanding-the-yaml-file/incremental-syncs).",
        title="Whether to store cursor as one value instead of per partition",
    )
    lookback_window: Optional[str] = Field(
        None,
        description="Time interval before the start_datetime to read data for, e.g. P1M for looking back one month.",
        examples=["P1D", "P{{ config['lookback_days'] }}D"],
        title="Lookback Window",
    )
    partition_field_end: Optional[str] = Field(
        None,
        description="Name of the partition start time field.",
        examples=["ending_time"],
        title="Partition Field End",
    )
    partition_field_start: Optional[str] = Field(
        None,
        description="Name of the partition end time field.",
        examples=["starting_time"],
        title="Partition Field Start",
    )
    start_time_option: Optional[RequestOption] = Field(
        None,
        description="Optionally configures how the start datetime will be sent in requests to the source API.",
        title="Inject Start Time Into Outgoing HTTP Request",
    )
    step: Optional[str] = Field(
        None,
        description="The size of the time window (ISO8601 duration). Given this field is provided, `cursor_granularity` needs to be provided as well.",
        examples=["P1W", "{{ config['step_increment'] }}"],
        title="Step",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class FixedWindowCallRatePolicy(BaseModel):
    class Config:
        extra = Extra.allow

    type: Literal["FixedWindowCallRatePolicy"]
    period: str = Field(
        ..., description="The time interval for the rate limit window.", title="Period"
    )
    call_limit: int = Field(
        ...,
        description="The maximum number of calls allowed within the period.",
        title="Call Limit",
    )
    matchers: List[HttpRequestRegexMatcher] = Field(
        ...,
        description="List of matchers that define which requests this policy applies to.",
        title="Matchers",
    )


class MovingWindowCallRatePolicy(BaseModel):
    class Config:
        extra = Extra.allow

    type: Literal["MovingWindowCallRatePolicy"]
    rates: List[Rate] = Field(
        ...,
        description="List of rates that define the call limits for different time intervals.",
        title="Rates",
    )
    matchers: List[HttpRequestRegexMatcher] = Field(
        ...,
        description="List of matchers that define which requests this policy applies to.",
        title="Matchers",
    )


class UnlimitedCallRatePolicy(BaseModel):
    class Config:
        extra = Extra.allow

    type: Literal["UnlimitedCallRatePolicy"]
    matchers: List[HttpRequestRegexMatcher] = Field(
        ...,
        description="List of matchers that define which requests this policy applies to.",
        title="Matchers",
    )


class DefaultErrorHandler(BaseModel):
    type: Literal["DefaultErrorHandler"]
    backoff_strategies: Optional[
        List[
            Union[
                ConstantBackoffStrategy,
                CustomBackoffStrategy,
                ExponentialBackoffStrategy,
                WaitTimeFromHeader,
                WaitUntilTimeFromHeader,
            ]
        ]
    ] = Field(
        None,
        description="List of backoff strategies to use to determine how long to wait before retrying a retryable request.",
        title="Backoff Strategies",
    )
    max_retries: Optional[int] = Field(
        5,
        description="The maximum number of time to retry a retryable request before giving up and failing.",
        examples=[5, 0, 10],
        title="Max Retry Count",
    )
    response_filters: Optional[List[HttpResponseFilter]] = Field(
        None,
        description="List of response filters to iterate on when deciding how to handle an error. When using an array of multiple filters, the filters will be applied sequentially and the response will be selected if it matches any of the filter's predicate.",
        title="Response Filters",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class DefaultPaginator(BaseModel):
    type: Literal["DefaultPaginator"]
    pagination_strategy: Union[
        PageIncrement, OffsetIncrement, CursorPagination, CustomPaginationStrategy
    ] = Field(
        ...,
        description="Strategy defining how records are paginated.",
        title="Pagination Strategy",
    )
    page_size_option: Optional[RequestOption] = Field(
        None, title="Inject Page Size Into Outgoing HTTP Request"
    )
    page_token_option: Optional[Union[RequestOption, RequestPath]] = Field(
        None, title="Inject Page Token Into Outgoing HTTP Request"
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class SessionTokenRequestApiKeyAuthenticator(BaseModel):
    type: Literal["ApiKey"]
    inject_into: RequestOption = Field(
        ...,
        description="Configure how the API Key will be sent in requests to the source API.",
        examples=[
            {"inject_into": "header", "field_name": "Authorization"},
            {"inject_into": "request_parameter", "field_name": "authKey"},
        ],
        title="Inject API Key Into Outgoing HTTP Request",
    )


class ListPartitionRouter(BaseModel):
    type: Literal["ListPartitionRouter"]
    cursor_field: str = Field(
        ...,
        description='While iterating over list values, the name of field used to reference a list value. The partition value can be accessed with string interpolation. e.g. "{{ stream_partition[\'my_key\'] }}" where "my_key" is the value of the cursor_field.',
        examples=["section", "{{ config['section_key'] }}"],
        title="Current Partition Value Identifier",
    )
    values: Union[str, List[str]] = Field(
        ...,
        description="The list of attributes being iterated over and used as input for the requests made to the source API.",
        examples=[["section_a", "section_b", "section_c"], "{{ config['sections'] }}"],
        title="Partition Values",
    )
    request_option: Optional[RequestOption] = Field(
        None,
        description="A request option describing where the list value should be injected into and under what field name if applicable.",
        title="Inject Partition Value Into Outgoing HTTP Request",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class RecordSelector(BaseModel):
    type: Literal["RecordSelector"]
    extractor: Union[DpathExtractor, CustomRecordExtractor]
    record_filter: Optional[Union[RecordFilter, CustomRecordFilter]] = Field(
        None,
        description="Responsible for filtering records to be emitted by the Source.",
        title="Record Filter",
    )
    schema_normalization: Optional[Union[SchemaNormalization, CustomSchemaNormalization]] = Field(
        None,
        description="Responsible for normalization according to the schema.",
        title="Schema Normalization",
    )
    transform_before_filtering: Optional[bool] = Field(
        None,
        description="If true, transformation will be applied before record filtering.",
        title="Transform Before Filtering",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class GzipDecoder(BaseModel):
    type: Literal["GzipDecoder"]
    decoder: Union[CsvDecoder, GzipDecoder, JsonDecoder, JsonlDecoder]


class RequestBodyGraphQL(BaseModel):
    type: Literal["RequestBodyGraphQL"]
    value: RequestBodyGraphQlQuery


class DpathValidator(BaseModel):
    type: Literal["DpathValidator"]
    field_path: List[str] = Field(
        ...,
        description='List of potentially nested fields describing the full path of the field to validate. Use "*" to validate all values from an array.',
        examples=[
            ["data"],
            ["data", "records"],
            ["data", "{{ parameters.name }}"],
            ["data", "*", "record"],
        ],
        title="Field Path",
    )
    validation_strategy: ValidateAdheresToSchema = Field(
        ...,
        description="The condition that the specified config value will be evaluated against",
        title="Validation Strategy",
    )


class PredicateValidator(BaseModel):
    type: Literal["PredicateValidator"]
    value: Optional[Union[str, float, Dict[str, Any], List[Any], bool]] = Field(
        ...,
        description="The value to be validated. Can be a literal value or interpolated from configuration.",
        examples=[
            "test-value",
            "{{ config['api_version'] }}",
            "{{ config['tenant_id'] }}",
            123,
        ],
        title="Value",
    )
    validation_strategy: ValidateAdheresToSchema = Field(
        ...,
        description="The validation strategy to apply to the value.",
        title="Validation Strategy",
    )


class ConfigAddFields(BaseModel):
    type: Literal["ConfigAddFields"]
    fields: List[AddedFieldDefinition] = Field(
        ...,
        description="A list of transformations (path and corresponding value) that will be added to the config.",
        title="Fields",
    )
    condition: Optional[str] = Field(
        "",
        description="Fields will be added if expression is evaluated to True.",
        examples=[
            "{{ config['environemnt'] == 'sandbox' }}",
            "{{ property is integer }}",
            "{{ property|length > 5 }}",
            "{{ property == 'some_string_to_match' }}",
        ],
    )


class CompositeErrorHandler(BaseModel):
    type: Literal["CompositeErrorHandler"]
    error_handlers: List[Union[CompositeErrorHandler, DefaultErrorHandler]] = Field(
        ...,
        description="List of error handlers to iterate on to determine how to handle a failed response.",
        title="Error Handlers",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class HTTPAPIBudget(BaseModel):
    class Config:
        extra = Extra.allow

    type: Literal["HTTPAPIBudget"]
    policies: List[
        Union[
            FixedWindowCallRatePolicy,
            MovingWindowCallRatePolicy,
            UnlimitedCallRatePolicy,
        ]
    ] = Field(
        ...,
        description="List of call rate policies that define how many calls are allowed.",
        title="Policies",
    )
    ratelimit_reset_header: Optional[str] = Field(
        "ratelimit-reset",
        description="The HTTP response header name that indicates when the rate limit resets.",
        title="Rate Limit Reset Header",
    )
    ratelimit_remaining_header: Optional[str] = Field(
        "ratelimit-remaining",
        description="The HTTP response header name that indicates the number of remaining allowed calls.",
        title="Rate Limit Remaining Header",
    )
    status_codes_for_ratelimit_hit: Optional[List[int]] = Field(
        [429],
        description="List of HTTP status codes that indicate a rate limit has been hit.",
        title="Status Codes for Rate Limit Hit",
    )


class ZipfileDecoder(BaseModel):
    class Config:
        extra = Extra.allow

    type: Literal["ZipfileDecoder"]
    decoder: Union[CsvDecoder, GzipDecoder, JsonDecoder, JsonlDecoder] = Field(
        ...,
        description="Parser to parse the decompressed data from the zipfile(s).",
        title="Parser",
    )


class ConfigMigration(BaseModel):
    type: Literal["ConfigMigration"]
    description: Optional[str] = Field(
        None, description="The description/purpose of the config migration."
    )
    transformations: List[Union[ConfigRemapField, ConfigAddFields, ConfigRemoveFields]] = Field(
        ...,
        description="The list of transformations that will attempt to be applied on an incoming unmigrated config. The transformations will be applied in the order they are defined.",
        title="Transformations",
    )


class ConfigNormalizationRules(BaseModel):
    class Config:
        extra = Extra.forbid

    config_migrations: Optional[List[ConfigMigration]] = Field(
        [],
        description="The discrete migrations that will be applied on the incoming config. Each migration will be applied in the order they are defined.",
        title="Config Migrations",
    )
    transformations: Optional[
        List[Union[ConfigRemapField, ConfigAddFields, ConfigRemoveFields]]
    ] = Field(
        [],
        description="The list of transformations that will be applied on the incoming config at the start of each sync. The transformations will be applied in the order they are defined.",
        title="Transformations",
    )
    validations: Optional[List[Union[DpathValidator, PredicateValidator]]] = Field(
        [],
        description="The list of validations that will be performed on the incoming config at the start of each sync.",
        title="Validations",
    )


class Spec(BaseModel):
    type: Literal["Spec"]
    connection_specification: Dict[str, Any] = Field(
        ...,
        description="A connection specification describing how a the connector can be configured.",
        title="Connection Specification",
    )
    documentation_url: Optional[str] = Field(
        None,
        description="URL of the connector's documentation page.",
        examples=["https://docs.airbyte.com/integrations/sources/dremio"],
        title="Documentation URL",
    )
    advanced_auth: Optional[AuthFlow] = Field(
        None,
        description="Advanced specification for configuring the authentication flow.",
        title="Advanced Auth",
    )
    config_normalization_rules: Optional[ConfigNormalizationRules] = Field(
        None, title="Config Normalization Rules"
    )


class DeclarativeSource1(BaseModel):
    class Config:
        extra = Extra.forbid

    type: Literal["DeclarativeSource"]
    check: Union[CheckStream, CheckDynamicStream]
    streams: List[Union[DeclarativeStream, StateDelegatingStream]]
    dynamic_streams: Optional[List[DynamicDeclarativeStream]] = None
    version: str = Field(
        ...,
        description="The version of the Airbyte CDK used to build and test the source.",
    )
    schemas: Optional[Schemas] = None
    definitions: Optional[Dict[str, Any]] = None
    spec: Optional[Spec] = None
    concurrency_level: Optional[ConcurrencyLevel] = None
    api_budget: Optional[HTTPAPIBudget] = None
    max_concurrent_async_job_count: Optional[Union[int, str]] = Field(
        None,
        description="Maximum number of concurrent asynchronous jobs to run. This property is only relevant for sources/streams that support asynchronous job execution through the AsyncRetriever (e.g. a report-based stream that initiates a job, polls the job status, and then fetches the job results). This is often set by the API's maximum number of concurrent jobs on the account level. Refer to the API's documentation for this information.",
        examples=[3, "{{ config['max_concurrent_async_job_count'] }}"],
        title="Maximum Concurrent Asynchronous Jobs",
    )
    metadata: Optional[Dict[str, Any]] = Field(
        None,
        description="For internal Airbyte use only - DO NOT modify manually. Used by consumers of declarative manifests for storing related metadata.",
    )
    description: Optional[str] = Field(
        None,
        description="A description of the connector. It will be presented on the Source documentation page.",
    )


class DeclarativeSource2(BaseModel):
    class Config:
        extra = Extra.forbid

    type: Literal["DeclarativeSource"]
    check: Union[CheckStream, CheckDynamicStream]
    streams: Optional[List[Union[DeclarativeStream, StateDelegatingStream]]] = None
    dynamic_streams: List[DynamicDeclarativeStream]
    version: str = Field(
        ...,
        description="The version of the Airbyte CDK used to build and test the source.",
    )
    schemas: Optional[Schemas] = None
    definitions: Optional[Dict[str, Any]] = None
    spec: Optional[Spec] = None
    concurrency_level: Optional[ConcurrencyLevel] = None
    api_budget: Optional[HTTPAPIBudget] = None
    max_concurrent_async_job_count: Optional[Union[int, str]] = Field(
        None,
        description="Maximum number of concurrent asynchronous jobs to run. This property is only relevant for sources/streams that support asynchronous job execution through the AsyncRetriever (e.g. a report-based stream that initiates a job, polls the job status, and then fetches the job results). This is often set by the API's maximum number of concurrent jobs on the account level. Refer to the API's documentation for this information.",
        examples=[3, "{{ config['max_concurrent_async_job_count'] }}"],
        title="Maximum Concurrent Asynchronous Jobs",
    )
    metadata: Optional[Dict[str, Any]] = Field(
        None,
        description="For internal Airbyte use only - DO NOT modify manually. Used by consumers of declarative manifests for storing related metadata.",
    )
    description: Optional[str] = Field(
        None,
        description="A description of the connector. It will be presented on the Source documentation page.",
    )


class DeclarativeSource(BaseModel):
    class Config:
        extra = Extra.forbid

    __root__: Union[DeclarativeSource1, DeclarativeSource2] = Field(
        ...,
        description="An API source that extracts data according to its declarative components.",
        title="DeclarativeSource",
    )


class SelectiveAuthenticator(BaseModel):
    class Config:
        extra = Extra.allow

    type: Literal["SelectiveAuthenticator"]
    authenticator_selection_path: List[str] = Field(
        ...,
        description="Path of the field in config with selected authenticator name",
        examples=[["auth"], ["auth", "type"]],
        title="Authenticator Selection Path",
    )
    authenticators: Dict[
        str,
        Union[
            ApiKeyAuthenticator,
            BasicHttpAuthenticator,
            BearerAuthenticator,
            CustomAuthenticator,
            OAuthAuthenticator,
            JwtAuthenticator,
            SessionTokenAuthenticator,
            NoAuth,
            LegacySessionTokenAuthenticator,
        ],
    ] = Field(
        ...,
        description="Authenticators to select from.",
        examples=[
            {
                "authenticators": {
                    "token": "#/definitions/ApiKeyAuthenticator",
                    "oauth": "#/definitions/OAuthAuthenticator",
                    "jwt": "#/definitions/JwtAuthenticator",
                }
            }
        ],
        title="Authenticators",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class FileUploader(BaseModel):
    type: Literal["FileUploader"]
    requester: Union[HttpRequester, CustomRequester] = Field(
        ...,
        description="Requester component that describes how to prepare HTTP requests to send to the source API.",
    )
    download_target_extractor: Union[DpathExtractor, CustomRecordExtractor] = Field(
        ...,
        description="Responsible for fetching the url where the file is located. This is applied on each records and not on the HTTP response",
    )
    file_extractor: Optional[Union[DpathExtractor, CustomRecordExtractor]] = Field(
        None,
        description="Responsible for fetching the content of the file. If not defined, the assumption is that the whole response body is the file content",
    )
    filename_extractor: Optional[str] = Field(
        None,
        description="Defines the name to store the file. Stream name is automatically added to the file path. File unique ID can be used to avoid overwriting files. Random UUID will be used if the extractor is not provided.",
        examples=[
            "{{ record.id }}/{{ record.file_name }}/",
            "{{ record.id }}_{{ record.file_name }}/",
        ],
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class DeclarativeStream(BaseModel):
    class Config:
        extra = Extra.allow

    type: Literal["DeclarativeStream"]
    name: Optional[str] = Field("", description="The stream name.", example=["Users"], title="Name")
    retriever: Union[SimpleRetriever, AsyncRetriever, CustomRetriever] = Field(
        ...,
        description="Component used to coordinate how records are extracted across stream slices and request pages.",
        title="Retriever",
    )
    incremental_sync: Optional[
        Union[DatetimeBasedCursor, IncrementingCountCursor, CustomIncrementalSync]
    ] = Field(
        None,
        description="Component used to fetch data incrementally based on a time field in the data.",
        title="Incremental Sync",
    )
    primary_key: Optional[PrimaryKey] = Field("", title="Primary Key")
    schema_loader: Optional[
        Union[
            InlineSchemaLoader,
            DynamicSchemaLoader,
            JsonFileSchemaLoader,
            CustomSchemaLoader,
            List[
                Union[
                    InlineSchemaLoader,
                    DynamicSchemaLoader,
                    JsonFileSchemaLoader,
                    CustomSchemaLoader,
                ]
            ],
        ]
    ] = Field(
        None,
        description="One or many schema loaders can be used to retrieve the schema for the current stream. When multiple schema loaders are defined, schema properties will be merged together. Schema loaders defined first taking precedence in the event of a conflict.",
        title="Schema Loader",
    )
    transformations: Optional[
        List[
            Union[
                AddFields,
                CustomTransformation,
                RemoveFields,
                KeysToLower,
                KeysToSnakeCase,
                FlattenFields,
                DpathFlattenFields,
                KeysReplace,
            ]
        ]
    ] = Field(
        None,
        description="A list of transformations to be applied to each output record.",
        title="Transformations",
    )
    state_migrations: Optional[
        List[Union[LegacyToPerPartitionStateMigration, CustomStateMigration]]
    ] = Field(
        [],
        description="Array of state migrations to be applied on the input state",
        title="State Migrations",
    )
    file_uploader: Optional[FileUploader] = Field(
        None,
        description="(experimental) Describes how to fetch a file",
        title="File Uploader",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class SessionTokenAuthenticator(BaseModel):
    type: Literal["SessionTokenAuthenticator"]
    login_requester: HttpRequester = Field(
        ...,
        description="Description of the request to perform to obtain a session token to perform data requests. The response body is expected to be a JSON object with a session token property.",
        examples=[
            {
                "type": "HttpRequester",
                "url_base": "https://my_api.com",
                "path": "/login",
                "authenticator": {
                    "type": "BasicHttpAuthenticator",
                    "username": "{{ config.username }}",
                    "password": "{{ config.password }}",
                },
            }
        ],
        title="Login Requester",
    )
    session_token_path: List[str] = Field(
        ...,
        description="The path in the response body returned from the login requester to the session token.",
        examples=[["access_token"], ["result", "token"]],
        title="Session Token Path",
    )
    expiration_duration: Optional[str] = Field(
        None,
        description="The duration in ISO 8601 duration notation after which the session token expires, starting from the time it was obtained. Omitting it will result in the session token being refreshed for every request.",
        examples=["PT1H", "P1D"],
        title="Expiration Duration",
    )
    request_authentication: Union[
        SessionTokenRequestApiKeyAuthenticator, SessionTokenRequestBearerAuthenticator
    ] = Field(
        ...,
        description="Authentication method to use for requests sent to the API, specifying how to inject the session token.",
        title="Data Request Authentication",
    )
    decoder: Optional[Union[JsonDecoder, XmlDecoder]] = Field(
        None, description="Component used to decode the response.", title="Decoder"
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class HttpRequester(BaseModelWithDeprecations):
    type: Literal["HttpRequester"]
    url_base: Optional[str] = Field(
        None,
        deprecated=True,
        deprecation_message="Use `url` field instead.",
        description="Deprecated, use the `url` instead. Base URL of the API source. Do not put sensitive information (e.g. API tokens) into this field - Use the Authenticator component for this.",
        examples=[
            "https://connect.squareup.com/v2",
            "{{ config['base_url'] or 'https://app.posthog.com'}}/api",
            "https://connect.squareup.com/v2/quotes/{{ stream_partition['id'] }}/quote_line_groups",
            "https://example.com/api/v1/resource/{{ next_page_token['id'] }}",
        ],
        title="API Base URL",
    )
    url: Optional[str] = Field(
        None,
        description="The URL of the source API endpoint. Do not put sensitive information (e.g. API tokens) into this field - Use the Authenticator component for this.",
        examples=[
            "https://connect.squareup.com/v2",
            "{{ config['url'] or 'https://app.posthog.com'}}/api",
            "https://connect.squareup.com/v2/quotes/{{ stream_partition['id'] }}/quote_line_groups",
            "https://example.com/api/v1/resource/{{ next_page_token['id'] }}",
        ],
        title="API Endpoint URL",
    )
    path: Optional[str] = Field(
        None,
        deprecated=True,
        deprecation_message="Use `url` field instead.",
        description="Deprecated, use the `url` instead. Path the specific API endpoint that this stream represents. Do not put sensitive information (e.g. API tokens) into this field - Use the Authenticator component for this.",
        examples=[
            "/products",
            "/quotes/{{ stream_partition['id'] }}/quote_line_groups",
            "/trades/{{ config['symbol_id'] }}/history",
        ],
        title="URL Path",
    )
    http_method: Optional[HttpMethod] = Field(
        HttpMethod.GET,
        description="The HTTP method used to fetch data from the source (can be GET or POST).",
        examples=["GET", "POST"],
        title="HTTP Method",
    )
    authenticator: Optional[
        Union[
            ApiKeyAuthenticator,
            BasicHttpAuthenticator,
            BearerAuthenticator,
            OAuthAuthenticator,
            JwtAuthenticator,
            SessionTokenAuthenticator,
            SelectiveAuthenticator,
            CustomAuthenticator,
            NoAuth,
            LegacySessionTokenAuthenticator,
        ]
    ] = Field(
        None,
        description="Authentication method to use for requests sent to the API.",
        title="Authenticator",
    )
    fetch_properties_from_endpoint: Optional[PropertiesFromEndpoint] = Field(
        None,
        description="Allows for retrieving a dynamic set of properties from an API endpoint which can be injected into outbound request using the stream_partition.extra_fields.",
        title="Fetch Properties from Endpoint",
    )
    request_parameters: Optional[Union[Dict[str, Union[str, QueryProperties]], str]] = Field(
        None,
        description="Specifies the query parameters that should be set on an outgoing HTTP request given the inputs.",
        examples=[
            {"unit": "day"},
            {
                "query": 'last_event_time BETWEEN TIMESTAMP "{{ stream_interval.start_time }}" AND TIMESTAMP "{{ stream_interval.end_time }}"'
            },
            {"searchIn": "{{ ','.join(config.get('search_in', [])) }}"},
            {"sort_by[asc]": "updated_at"},
        ],
        title="Query Parameters",
    )
    request_headers: Optional[Union[Dict[str, str], str]] = Field(
        None,
        description="Return any non-auth headers. Authentication headers will overwrite any overlapping headers returned from this method.",
        examples=[{"Output-Format": "JSON"}, {"Version": "{{ config['version'] }}"}],
        title="Request Headers",
    )
    request_body_data: Optional[Union[Dict[str, str], str]] = Field(
        None,
        deprecated=True,
        deprecation_message="Use `request_body` field instead.",
        description="Specifies how to populate the body of the request with a non-JSON payload. Plain text will be sent as is, whereas objects will be converted to a urlencoded form.",
        examples=[
            '[{"clause": {"type": "timestamp", "operator": 10, "parameters":\n    [{"value": {{ stream_interval[\'start_time\'] | int * 1000 }} }]\n  }, "orderBy": 1, "columnName": "Timestamp"}]/\n'
        ],
        title="Request Body Payload (Non-JSON)",
    )
    request_body_json: Optional[Union[Dict[str, Any], str]] = Field(
        None,
        deprecated=True,
        deprecation_message="Use `request_body` field instead.",
        description="Specifies how to populate the body of the request with a JSON payload. Can contain nested objects.",
        examples=[
            {"sort_order": "ASC", "sort_field": "CREATED_AT"},
            {"key": "{{ config['value'] }}"},
            {"sort": {"field": "updated_at", "order": "ascending"}},
        ],
        title="Request Body JSON Payload",
    )
    request_body: Optional[
        Union[
            RequestBodyPlainText,
            RequestBodyUrlEncodedForm,
            RequestBodyJsonObject,
            RequestBodyGraphQL,
        ]
    ] = Field(
        None,
        description="Specifies how to populate the body of the request with a payload. Can contain nested objects.",
        examples=[
            {
                "type": "RequestBodyJsonObject",
                "value": {"sort_order": "ASC", "sort_field": "CREATED_AT"},
            },
            {
                "type": "RequestBodyJsonObject",
                "value": {"key": "{{ config['value'] }}"},
            },
            {
                "type": "RequestBodyJsonObject",
                "value": {"sort": {"field": "updated_at", "order": "ascending"}},
            },
            {"type": "RequestBodyPlainText", "value": "plain_text_body"},
            {
                "type": "RequestBodyUrlEncodedForm",
                "value": {"param1": "value1", "param2": "{{ config['param2_value'] }}"},
            },
            {
                "type": "RequestBodyGraphQL",
                "value": {
                    "query": {
                        "param1": "value1",
                        "param2": "{{ config['param2_value'] }}",
                    }
                },
            },
        ],
        title="Request Body",
    )
    error_handler: Optional[
        Union[DefaultErrorHandler, CompositeErrorHandler, CustomErrorHandler]
    ] = Field(
        None,
        description="Error handler component that defines how to handle errors.",
        title="Error Handler",
    )
    use_cache: Optional[bool] = Field(
        False,
        description="Enables stream requests caching. This field is automatically set by the CDK.",
        title="Use Cache",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class DynamicSchemaLoader(BaseModel):
    type: Literal["DynamicSchemaLoader"]
    retriever: Union[AsyncRetriever, CustomRetriever, SimpleRetriever] = Field(
        ...,
        description="Component used to coordinate how records are extracted across stream slices and request pages.",
        title="Retriever",
    )
    schema_filter: Optional[Union[RecordFilter, CustomRecordFilter]] = Field(
        None,
        description="Responsible for filtering fields to be added to json schema.",
        title="Schema Filter",
    )
    schema_transformations: Optional[
        List[
            Union[
                AddFields,
                CustomTransformation,
                RemoveFields,
                KeysToLower,
                KeysToSnakeCase,
                FlattenFields,
                DpathFlattenFields,
                KeysReplace,
            ]
        ]
    ] = Field(
        None,
        description="A list of transformations to be applied to the schema.",
        title="Schema Transformations",
    )
    schema_type_identifier: SchemaTypeIdentifier
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class ParentStreamConfig(BaseModel):
    type: Literal["ParentStreamConfig"]
    lazy_read_pointer: Optional[List[str]] = Field(
        [],
        description="If set, this will enable lazy reading, using the initial read of parent records to extract child records.",
        title="Lazy Read Pointer",
    )
    parent_key: str = Field(
        ...,
        description="The primary key of records from the parent stream that will be used during the retrieval of records for the current substream. This parent identifier field is typically a characteristic of the child records being extracted from the source API.",
        examples=["id", "{{ config['parent_record_id'] }}"],
        title="Parent Key",
    )
    stream: Union[DeclarativeStream, StateDelegatingStream] = Field(
        ..., description="Reference to the parent stream.", title="Parent Stream"
    )
    partition_field: str = Field(
        ...,
        description="While iterating over parent records during a sync, the parent_key value can be referenced by using this field.",
        examples=["parent_id", "{{ config['parent_partition_field'] }}"],
        title="Current Parent Key Value Identifier",
    )
    request_option: Optional[RequestOption] = Field(
        None,
        description="A request option describing where the parent key value should be injected into and under what field name if applicable.",
        title="Request Option",
    )
    incremental_dependency: Optional[bool] = Field(
        False,
        description="Indicates whether the parent stream should be read incrementally based on updates in the child stream.",
        title="Incremental Dependency",
    )
    extra_fields: Optional[List[List[str]]] = Field(
        None,
        description="Array of field paths to include as additional fields in the stream slice. Each path is an array of strings representing keys to access fields in the respective parent record. Accessible via `stream_slice.extra_fields`. Missing fields are set to `None`.",
        title="Extra Fields",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class PropertiesFromEndpoint(BaseModel):
    type: Literal["PropertiesFromEndpoint"]
    property_field_path: List[str] = Field(
        ...,
        description="Describes the path to the field that should be extracted",
        examples=[["name"]],
    )
    retriever: Union[SimpleRetriever, CustomRetriever] = Field(
        ...,
        description="Requester component that describes how to fetch the properties to query from a remote API endpoint.",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class QueryProperties(BaseModel):
    type: Literal["QueryProperties"]
    property_list: Union[List[str], PropertiesFromEndpoint] = Field(
        ...,
        description="The set of properties that will be queried for in the outbound request. This can either be statically defined or dynamic based on an API endpoint",
        title="Property List",
    )
    always_include_properties: Optional[List[str]] = Field(
        None,
        description="The list of properties that should be included in every set of properties when multiple chunks of properties are being requested.",
        title="Always Include Properties",
    )
    property_chunking: Optional[PropertyChunking] = Field(
        None,
        description="Defines how query properties will be grouped into smaller sets for APIs with limitations on the number of properties fetched per API request.",
        title="Property Chunking",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class StateDelegatingStream(BaseModel):
    type: Literal["StateDelegatingStream"]
    name: str = Field(..., description="The stream name.", example=["Users"], title="Name")
    full_refresh_stream: DeclarativeStream = Field(
        ...,
        description="Component used to coordinate how records are extracted across stream slices and request pages when the state is empty or not provided.",
        title="Full Refresh Stream",
    )
    incremental_stream: DeclarativeStream = Field(
        ...,
        description="Component used to coordinate how records are extracted across stream slices and request pages when the state provided.",
        title="Incremental Stream",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class SimpleRetriever(BaseModel):
    type: Literal["SimpleRetriever"]
    requester: Union[HttpRequester, CustomRequester] = Field(
        ...,
        description="Requester component that describes how to prepare HTTP requests to send to the source API.",
    )
    decoder: Optional[
        Union[
            JsonDecoder,
            XmlDecoder,
            CsvDecoder,
            JsonlDecoder,
            GzipDecoder,
            IterableDecoder,
            ZipfileDecoder,
            CustomDecoder,
        ]
    ] = Field(
        None,
        description="Component decoding the response so records can be extracted.",
        title="HTTP Response Format",
    )
    record_selector: RecordSelector = Field(
        ...,
        description="Component that describes how to extract records from a HTTP response.",
    )
    paginator: Optional[Union[DefaultPaginator, NoPagination]] = Field(
        None,
        description="Paginator component that describes how to navigate through the API's pages.",
    )
    ignore_stream_slicer_parameters_on_paginated_requests: Optional[bool] = Field(
        False,
        description="If true, the partition router and incremental request options will be ignored when paginating requests. Request options set directly on the requester will not be ignored.",
    )
    partition_router: Optional[
        Union[
            ListPartitionRouter,
            SubstreamPartitionRouter,
            GroupingPartitionRouter,
            CustomPartitionRouter,
            List[
                Union[
                    ListPartitionRouter,
                    SubstreamPartitionRouter,
                    GroupingPartitionRouter,
                    CustomPartitionRouter,
                ]
            ],
        ]
    ] = Field(
        [],
        description="PartitionRouter component that describes how to partition the stream, enabling incremental syncs and checkpointing.",
        title="Partition Router",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class AsyncRetriever(BaseModel):
    type: Literal["AsyncRetriever"]
    record_selector: RecordSelector = Field(
        ...,
        description="Component that describes how to extract records from a HTTP response.",
    )
    status_mapping: AsyncJobStatusMap = Field(
        ..., description="Async Job Status to Airbyte CDK Async Job Status mapping."
    )
    status_extractor: Union[DpathExtractor, CustomRecordExtractor] = Field(
        ..., description="Responsible for fetching the actual status of the async job."
    )
    download_target_extractor: Union[DpathExtractor, CustomRecordExtractor] = Field(
        ...,
        description="Responsible for fetching the final result `urls` provided by the completed / finished / ready async job.",
    )
    download_extractor: Optional[
        Union[DpathExtractor, CustomRecordExtractor, ResponseToFileExtractor]
    ] = Field(None, description="Responsible for fetching the records from provided urls.")
    creation_requester: Union[HttpRequester, CustomRequester] = Field(
        ...,
        description="Requester component that describes how to prepare HTTP requests to send to the source API to create the async server-side job.",
    )
    polling_requester: Union[HttpRequester, CustomRequester] = Field(
        ...,
        description="Requester component that describes how to prepare HTTP requests to send to the source API to fetch the status of the running async job.",
    )
    polling_job_timeout: Optional[Union[int, str]] = Field(
        None,
        description="The time in minutes after which the single Async Job should be considered as Timed Out.",
    )
    download_target_requester: Optional[Union[HttpRequester, CustomRequester]] = Field(
        None,
        description="Requester component that describes how to prepare HTTP requests to send to the source API to extract the url from polling response by the completed async job.",
    )
    download_requester: Union[HttpRequester, CustomRequester] = Field(
        ...,
        description="Requester component that describes how to prepare HTTP requests to send to the source API to download the data provided by the completed async job.",
    )
    download_paginator: Optional[Union[DefaultPaginator, NoPagination]] = Field(
        None,
        description="Paginator component that describes how to navigate through the API's pages during download.",
    )
    abort_requester: Optional[Union[HttpRequester, CustomRequester]] = Field(
        None,
        description="Requester component that describes how to prepare HTTP requests to send to the source API to abort a job once it is timed out from the source's perspective.",
    )
    delete_requester: Optional[Union[HttpRequester, CustomRequester]] = Field(
        None,
        description="Requester component that describes how to prepare HTTP requests to send to the source API to delete a job once the records are extracted.",
    )
    partition_router: Optional[
        Union[
            ListPartitionRouter,
            SubstreamPartitionRouter,
            GroupingPartitionRouter,
            CustomPartitionRouter,
            List[
                Union[
                    ListPartitionRouter,
                    SubstreamPartitionRouter,
                    GroupingPartitionRouter,
                    CustomPartitionRouter,
                ]
            ],
        ]
    ] = Field(
        [],
        description="PartitionRouter component that describes how to partition the stream, enabling incremental syncs and checkpointing.",
        title="Partition Router",
    )
    decoder: Optional[
        Union[
            CsvDecoder,
            GzipDecoder,
            JsonDecoder,
            JsonlDecoder,
            IterableDecoder,
            XmlDecoder,
            ZipfileDecoder,
            CustomDecoder,
        ]
    ] = Field(
        None,
        description="Component decoding the response so records can be extracted.",
        title="Decoder",
    )
    download_decoder: Optional[
        Union[
            CsvDecoder,
            GzipDecoder,
            JsonDecoder,
            JsonlDecoder,
            IterableDecoder,
            XmlDecoder,
            ZipfileDecoder,
            CustomDecoder,
        ]
    ] = Field(
        None,
        description="Component decoding the download response so records can be extracted.",
        title="Download Decoder",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class SubstreamPartitionRouter(BaseModel):
    type: Literal["SubstreamPartitionRouter"]
    parent_stream_configs: List[ParentStreamConfig] = Field(
        ...,
        description="Specifies which parent streams are being iterated over and how parent records should be used to partition the child stream data set.",
        title="Parent Stream Configs",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class GroupingPartitionRouter(BaseModel):
    type: Literal["GroupingPartitionRouter"]
    group_size: int = Field(
        ...,
        description="The number of partitions to include in each group. This determines how many partition values are batched together in a single slice.",
        examples=[10, 50],
        title="Group Size",
    )
    underlying_partition_router: Union[
        CustomPartitionRouter, ListPartitionRouter, SubstreamPartitionRouter
    ] = Field(
        ...,
        description="The partition router whose output will be grouped. This can be any valid partition router component.",
        title="Underlying Partition Router",
    )
    deduplicate: Optional[bool] = Field(
        True,
        description="If true, ensures that partitions are unique within each group by removing duplicates based on the partition key.",
        title="Deduplicate Partitions",
    )
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class HttpComponentsResolver(BaseModel):
    type: Literal["HttpComponentsResolver"]
    retriever: Union[AsyncRetriever, CustomRetriever, SimpleRetriever] = Field(
        ...,
        description="Component used to coordinate how records are extracted across stream slices and request pages.",
        title="Retriever",
    )
    components_mapping: List[ComponentMappingDefinition]
    parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")


class DynamicDeclarativeStream(BaseModel):
    type: Literal["DynamicDeclarativeStream"]
    name: Optional[str] = Field(
        "", description="The dynamic stream name.", example=["Tables"], title="Name"
    )
    stream_template: Union[DeclarativeStream, StateDelegatingStream] = Field(
        ..., description="Reference to the stream template.", title="Stream Template"
    )
    components_resolver: Union[HttpComponentsResolver, ConfigComponentsResolver] = Field(
        ...,
        description="Component resolve and populates stream templates with components values.",
        title="Components Resolver",
    )


ComplexFieldType.update_forward_refs()
GzipDecoder.update_forward_refs()
CompositeErrorHandler.update_forward_refs()
DeclarativeSource1.update_forward_refs()
DeclarativeSource2.update_forward_refs()
SelectiveAuthenticator.update_forward_refs()
FileUploader.update_forward_refs()
DeclarativeStream.update_forward_refs()
SessionTokenAuthenticator.update_forward_refs()
HttpRequester.update_forward_refs()
DynamicSchemaLoader.update_forward_refs()
ParentStreamConfig.update_forward_refs()
PropertiesFromEndpoint.update_forward_refs()
SimpleRetriever.update_forward_refs()
AsyncRetriever.update_forward_refs()
