airbyte-cdk 6.33.1.dev1__py3-none-any.whl → 6.33.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of airbyte-cdk might be problematic. Click here for more details.
- airbyte_cdk/sources/declarative/auth/oauth.py +6 -1
- airbyte_cdk/sources/declarative/concurrent_declarative_source.py +15 -1
- airbyte_cdk/sources/declarative/declarative_component_schema.yaml +1 -208
- airbyte_cdk/sources/declarative/manifest_declarative_source.py +0 -4
- airbyte_cdk/sources/declarative/models/declarative_component_schema.py +0 -165
- airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py +17 -141
- airbyte_cdk/sources/declarative/requesters/http_requester.py +0 -3
- airbyte_cdk/sources/streams/call_rate.py +40 -116
- airbyte_cdk/sources/streams/http/requests_native_auth/abstract_oauth.py +3 -0
- {airbyte_cdk-6.33.1.dev1.dist-info → airbyte_cdk-6.33.2.dist-info}/METADATA +1 -1
- {airbyte_cdk-6.33.1.dev1.dist-info → airbyte_cdk-6.33.2.dist-info}/RECORD +15 -15
- {airbyte_cdk-6.33.1.dev1.dist-info → airbyte_cdk-6.33.2.dist-info}/LICENSE.txt +0 -0
- {airbyte_cdk-6.33.1.dev1.dist-info → airbyte_cdk-6.33.2.dist-info}/LICENSE_SHORT +0 -0
- {airbyte_cdk-6.33.1.dev1.dist-info → airbyte_cdk-6.33.2.dist-info}/WHEEL +0 -0
- {airbyte_cdk-6.33.1.dev1.dist-info → airbyte_cdk-6.33.2.dist-info}/entry_points.txt +0 -0
| @@ -3,7 +3,7 @@ | |
| 3 3 | 
             
            #
         | 
| 4 4 |  | 
| 5 5 | 
             
            from dataclasses import InitVar, dataclass, field
         | 
| 6 | 
            -
            from datetime import timedelta
         | 
| 6 | 
            +
            from datetime import datetime, timedelta
         | 
| 7 7 | 
             
            from typing import Any, List, Mapping, MutableMapping, Optional, Union
         | 
| 8 8 |  | 
| 9 9 | 
             
            from airbyte_cdk.sources.declarative.auth.declarative_authenticator import DeclarativeAuthenticator
         | 
| @@ -232,8 +232,13 @@ class DeclarativeOauth2Authenticator(AbstractOauth2Authenticator, DeclarativeAut | |
| 232 232 | 
             
                    return self._refresh_request_headers.eval(self.config)
         | 
| 233 233 |  | 
| 234 234 | 
             
                def get_token_expiry_date(self) -> AirbyteDateTime:
         | 
| 235 | 
            +
                    if not self._has_access_token_been_initialized():
         | 
| 236 | 
            +
                        return AirbyteDateTime.from_datetime(datetime.min)
         | 
| 235 237 | 
             
                    return self._token_expiry_date  # type: ignore # _token_expiry_date is an AirbyteDateTime. It is never None despite what mypy thinks
         | 
| 236 238 |  | 
| 239 | 
            +
                def _has_access_token_been_initialized(self) -> bool:
         | 
| 240 | 
            +
                    return self._access_token is not None
         | 
| 241 | 
            +
             | 
| 237 242 | 
             
                def set_token_expiry_date(self, value: Union[str, int]) -> None:
         | 
| 238 243 | 
             
                    self._token_expiry_date = self._parse_token_expiration_date(value)
         | 
| 239 244 |  | 
| @@ -3,7 +3,7 @@ | |
| 3 3 | 
             
            #
         | 
| 4 4 |  | 
| 5 5 | 
             
            import logging
         | 
| 6 | 
            -
            from typing import Any, Generic, Iterator, List, Mapping, Optional, Tuple
         | 
| 6 | 
            +
            from typing import Any, Generic, Iterator, List, Mapping, MutableMapping, Optional, Tuple
         | 
| 7 7 |  | 
| 8 8 | 
             
            from airbyte_cdk.models import (
         | 
| 9 9 | 
             
                AirbyteCatalog,
         | 
| @@ -224,6 +224,7 @@ class ConcurrentDeclarativeSource(ManifestDeclarativeSource, Generic[TState]): | |
| 224 224 | 
             
                                stream_state = self._connector_state_manager.get_stream_state(
         | 
| 225 225 | 
             
                                    stream_name=declarative_stream.name, namespace=declarative_stream.namespace
         | 
| 226 226 | 
             
                                )
         | 
| 227 | 
            +
                                stream_state = self._migrate_state(declarative_stream, stream_state)
         | 
| 227 228 |  | 
| 228 229 | 
             
                                retriever = self._get_retriever(declarative_stream, stream_state)
         | 
| 229 230 |  | 
| @@ -331,6 +332,8 @@ class ConcurrentDeclarativeSource(ManifestDeclarativeSource, Generic[TState]): | |
| 331 332 | 
             
                                stream_state = self._connector_state_manager.get_stream_state(
         | 
| 332 333 | 
             
                                    stream_name=declarative_stream.name, namespace=declarative_stream.namespace
         | 
| 333 334 | 
             
                                )
         | 
| 335 | 
            +
                                stream_state = self._migrate_state(declarative_stream, stream_state)
         | 
| 336 | 
            +
             | 
| 334 337 | 
             
                                partition_router = declarative_stream.retriever.stream_slicer._partition_router
         | 
| 335 338 |  | 
| 336 339 | 
             
                                perpartition_cursor = (
         | 
| @@ -521,3 +524,14 @@ class ConcurrentDeclarativeSource(ManifestDeclarativeSource, Generic[TState]): | |
| 521 524 | 
             
                            if stream.stream.name not in concurrent_stream_names
         | 
| 522 525 | 
             
                        ]
         | 
| 523 526 | 
             
                    )
         | 
| 527 | 
            +
             | 
| 528 | 
            +
                @staticmethod
         | 
| 529 | 
            +
                def _migrate_state(
         | 
| 530 | 
            +
                    declarative_stream: DeclarativeStream, stream_state: MutableMapping[str, Any]
         | 
| 531 | 
            +
                ) -> MutableMapping[str, Any]:
         | 
| 532 | 
            +
                    for state_migration in declarative_stream.state_migrations:
         | 
| 533 | 
            +
                        if state_migration.should_migrate(stream_state):
         | 
| 534 | 
            +
                            # The state variable is expected to be mutable but the migrate method returns an immutable mapping.
         | 
| 535 | 
            +
                            stream_state = dict(state_migration.migrate(stream_state))
         | 
| 536 | 
            +
             | 
| 537 | 
            +
                    return stream_state
         | 
| @@ -40,12 +40,6 @@ properties: | |
| 40 40 | 
             
                "$ref": "#/definitions/Spec"
         | 
| 41 41 | 
             
              concurrency_level:
         | 
| 42 42 | 
             
                "$ref": "#/definitions/ConcurrencyLevel"
         | 
| 43 | 
            -
              api_budget:
         | 
| 44 | 
            -
                title: API Budget
         | 
| 45 | 
            -
                description: Defines how many requests can be made to the API in a given time frame. This field accepts either a generic APIBudget or an HTTP-specific configuration (HTTPAPIBudget) to be applied across all streams.
         | 
| 46 | 
            -
                anyOf:
         | 
| 47 | 
            -
                  - "$ref": "#/definitions/APIBudget"
         | 
| 48 | 
            -
                  - "$ref": "#/definitions/HTTPAPIBudget"
         | 
| 49 43 | 
             
              metadata:
         | 
| 50 44 | 
             
                type: object
         | 
| 51 45 | 
             
                description: For internal Airbyte use only - DO NOT modify manually. Used by consumers of declarative manifests for storing related metadata.
         | 
| @@ -800,7 +794,7 @@ definitions: | |
| 800 794 | 
             
                    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)
         | 
| 801 795 | 
             
                    type: object
         | 
| 802 796 | 
             
                    required:
         | 
| 803 | 
            -
             | 
| 797 | 
            +
                    - target
         | 
| 804 798 | 
             
                    properties:
         | 
| 805 799 | 
             
                      target:
         | 
| 806 800 | 
             
                        title: Target
         | 
| @@ -1371,207 +1365,6 @@ definitions: | |
| 1371 1365 | 
             
                  $parameters:
         | 
| 1372 1366 | 
             
                    type: object
         | 
| 1373 1367 | 
             
                    additional_properties: true
         | 
| 1374 | 
            -
              APIBudget:
         | 
| 1375 | 
            -
                title: API Budget
         | 
| 1376 | 
            -
                description: >
         | 
| 1377 | 
            -
                  A generic API budget configuration that defines the policies (rate limiting rules)
         | 
| 1378 | 
            -
                  and the maximum number of attempts to acquire a call credit. This budget does not automatically
         | 
| 1379 | 
            -
                  update itself based on HTTP response headers.
         | 
| 1380 | 
            -
                type: object
         | 
| 1381 | 
            -
                required:
         | 
| 1382 | 
            -
                  - type
         | 
| 1383 | 
            -
                  - policies
         | 
| 1384 | 
            -
                properties:
         | 
| 1385 | 
            -
                  type:
         | 
| 1386 | 
            -
                    type: string
         | 
| 1387 | 
            -
                    enum: [APIBudget]
         | 
| 1388 | 
            -
                  policies:
         | 
| 1389 | 
            -
                    title: Policies
         | 
| 1390 | 
            -
                    description: List of call rate policies that define how many calls are allowed.
         | 
| 1391 | 
            -
                    type: array
         | 
| 1392 | 
            -
                    items:
         | 
| 1393 | 
            -
                      anyOf:
         | 
| 1394 | 
            -
                        - "$ref": "#/definitions/FixedWindowCallRatePolicy"
         | 
| 1395 | 
            -
                        - "$ref": "#/definitions/MovingWindowCallRatePolicy"
         | 
| 1396 | 
            -
                        - "$ref": "#/definitions/UnlimitedCallRatePolicy"
         | 
| 1397 | 
            -
                  maximum_attempts_to_acquire:
         | 
| 1398 | 
            -
                    title: Maximum Attempts to Acquire
         | 
| 1399 | 
            -
                    description: The maximum number of attempts to acquire a call before giving up.
         | 
| 1400 | 
            -
                    type: integer
         | 
| 1401 | 
            -
                    default: 100000
         | 
| 1402 | 
            -
                additionalProperties: true
         | 
| 1403 | 
            -
              HTTPAPIBudget:
         | 
| 1404 | 
            -
                title: HTTP API Budget
         | 
| 1405 | 
            -
                description: >
         | 
| 1406 | 
            -
                  An HTTP-specific API budget that extends APIBudget by updating rate limiting information based
         | 
| 1407 | 
            -
                  on HTTP response headers. It extracts available calls and the next reset timestamp from the HTTP responses.
         | 
| 1408 | 
            -
                type: object
         | 
| 1409 | 
            -
                required:
         | 
| 1410 | 
            -
                  - type
         | 
| 1411 | 
            -
                  - policies
         | 
| 1412 | 
            -
                properties:
         | 
| 1413 | 
            -
                  type:
         | 
| 1414 | 
            -
                    type: string
         | 
| 1415 | 
            -
                    enum: [HTTPAPIBudget]
         | 
| 1416 | 
            -
                  policies:
         | 
| 1417 | 
            -
                    title: Policies
         | 
| 1418 | 
            -
                    description: List of call rate policies that define how many calls are allowed.
         | 
| 1419 | 
            -
                    type: array
         | 
| 1420 | 
            -
                    items:
         | 
| 1421 | 
            -
                      anyOf:
         | 
| 1422 | 
            -
                        - "$ref": "#/definitions/FixedWindowCallRatePolicy"
         | 
| 1423 | 
            -
                        - "$ref": "#/definitions/MovingWindowCallRatePolicy"
         | 
| 1424 | 
            -
                        - "$ref": "#/definitions/UnlimitedCallRatePolicy"
         | 
| 1425 | 
            -
                  ratelimit_reset_header:
         | 
| 1426 | 
            -
                    title: Rate Limit Reset Header
         | 
| 1427 | 
            -
                    description: The HTTP response header name that indicates when the rate limit resets.
         | 
| 1428 | 
            -
                    type: string
         | 
| 1429 | 
            -
                    default: "ratelimit-reset"
         | 
| 1430 | 
            -
                  ratelimit_remaining_header:
         | 
| 1431 | 
            -
                    title: Rate Limit Remaining Header
         | 
| 1432 | 
            -
                    description: The HTTP response header name that indicates the number of remaining allowed calls.
         | 
| 1433 | 
            -
                    type: string
         | 
| 1434 | 
            -
                    default: "ratelimit-remaining"
         | 
| 1435 | 
            -
                  status_codes_for_ratelimit_hit:
         | 
| 1436 | 
            -
                    title: Status Codes for Rate Limit Hit
         | 
| 1437 | 
            -
                    description: List of HTTP status codes that indicate a rate limit has been hit.
         | 
| 1438 | 
            -
                    type: array
         | 
| 1439 | 
            -
                    items:
         | 
| 1440 | 
            -
                      type: integer
         | 
| 1441 | 
            -
                    default: [429]
         | 
| 1442 | 
            -
                  maximum_attempts_to_acquire:
         | 
| 1443 | 
            -
                    title: Maximum Attempts to Acquire
         | 
| 1444 | 
            -
                    description: The maximum number of attempts to acquire a call before giving up.
         | 
| 1445 | 
            -
                    type: integer
         | 
| 1446 | 
            -
                    default: 100000
         | 
| 1447 | 
            -
                additionalProperties: true
         | 
| 1448 | 
            -
              FixedWindowCallRatePolicy:
         | 
| 1449 | 
            -
                title: Fixed Window Call Rate Policy
         | 
| 1450 | 
            -
                description: A policy that allows a fixed number of calls within a specific time window.
         | 
| 1451 | 
            -
                type: object
         | 
| 1452 | 
            -
                required:
         | 
| 1453 | 
            -
                  - type
         | 
| 1454 | 
            -
                  - next_reset_ts
         | 
| 1455 | 
            -
                  - period
         | 
| 1456 | 
            -
                  - call_limit
         | 
| 1457 | 
            -
                  - matchers
         | 
| 1458 | 
            -
                properties:
         | 
| 1459 | 
            -
                  type:
         | 
| 1460 | 
            -
                    type: string
         | 
| 1461 | 
            -
                    enum: [FixedWindowCallRatePolicy]
         | 
| 1462 | 
            -
                  next_reset_ts:
         | 
| 1463 | 
            -
                    title: Next Reset Timestamp
         | 
| 1464 | 
            -
                    description: The timestamp when the rate limit will reset.
         | 
| 1465 | 
            -
                    type: string
         | 
| 1466 | 
            -
                    format: date-time
         | 
| 1467 | 
            -
                  period:
         | 
| 1468 | 
            -
                    title: Period
         | 
| 1469 | 
            -
                    description: The time interval for the rate limit window.
         | 
| 1470 | 
            -
                    type: string
         | 
| 1471 | 
            -
                    format: duration
         | 
| 1472 | 
            -
                  call_limit:
         | 
| 1473 | 
            -
                    title: Call Limit
         | 
| 1474 | 
            -
                    description: The maximum number of calls allowed within the period.
         | 
| 1475 | 
            -
                    type: integer
         | 
| 1476 | 
            -
                  matchers:
         | 
| 1477 | 
            -
                    title: Matchers
         | 
| 1478 | 
            -
                    description: List of matchers that define which requests this policy applies to.
         | 
| 1479 | 
            -
                    type: array
         | 
| 1480 | 
            -
                    items:
         | 
| 1481 | 
            -
                      "$ref": "#/definitions/HttpRequestRegexMatcher"
         | 
| 1482 | 
            -
                additionalProperties: true
         | 
| 1483 | 
            -
              MovingWindowCallRatePolicy:
         | 
| 1484 | 
            -
                title: Moving Window Call Rate Policy
         | 
| 1485 | 
            -
                description: A policy that allows a fixed number of calls within a moving time window.
         | 
| 1486 | 
            -
                type: object
         | 
| 1487 | 
            -
                required:
         | 
| 1488 | 
            -
                  - type
         | 
| 1489 | 
            -
                  - rates
         | 
| 1490 | 
            -
                  - matchers
         | 
| 1491 | 
            -
                properties:
         | 
| 1492 | 
            -
                  type:
         | 
| 1493 | 
            -
                    type: string
         | 
| 1494 | 
            -
                    enum: [MovingWindowCallRatePolicy]
         | 
| 1495 | 
            -
                  rates:
         | 
| 1496 | 
            -
                    title: Rates
         | 
| 1497 | 
            -
                    description: List of rates that define the call limits for different time intervals.
         | 
| 1498 | 
            -
                    type: array
         | 
| 1499 | 
            -
                    items:
         | 
| 1500 | 
            -
                      "$ref": "#/definitions/Rate"
         | 
| 1501 | 
            -
                  matchers:
         | 
| 1502 | 
            -
                    title: Matchers
         | 
| 1503 | 
            -
                    description: List of matchers that define which requests this policy applies to.
         | 
| 1504 | 
            -
                    type: array
         | 
| 1505 | 
            -
                    items:
         | 
| 1506 | 
            -
                      "$ref": "#/definitions/HttpRequestRegexMatcher"
         | 
| 1507 | 
            -
                additionalProperties: true
         | 
| 1508 | 
            -
              UnlimitedCallRatePolicy:
         | 
| 1509 | 
            -
                title: Unlimited Call Rate Policy
         | 
| 1510 | 
            -
                description: A policy that allows unlimited calls for specific requests.
         | 
| 1511 | 
            -
                type: object
         | 
| 1512 | 
            -
                required:
         | 
| 1513 | 
            -
                  - type
         | 
| 1514 | 
            -
                  - matchers
         | 
| 1515 | 
            -
                properties:
         | 
| 1516 | 
            -
                  type:
         | 
| 1517 | 
            -
                    type: string
         | 
| 1518 | 
            -
                    enum: [UnlimitedCallRatePolicy]
         | 
| 1519 | 
            -
                  matchers:
         | 
| 1520 | 
            -
                    title: Matchers
         | 
| 1521 | 
            -
                    description: List of matchers that define which requests this policy applies to.
         | 
| 1522 | 
            -
                    type: array
         | 
| 1523 | 
            -
                    items:
         | 
| 1524 | 
            -
                      "$ref": "#/definitions/HttpRequestRegexMatcher"
         | 
| 1525 | 
            -
                additionalProperties: true
         | 
| 1526 | 
            -
              Rate:
         | 
| 1527 | 
            -
                title: Rate
         | 
| 1528 | 
            -
                description: Defines a rate limit with a specific number of calls allowed within a time interval.
         | 
| 1529 | 
            -
                type: object
         | 
| 1530 | 
            -
                required:
         | 
| 1531 | 
            -
                  - limit
         | 
| 1532 | 
            -
                  - interval
         | 
| 1533 | 
            -
                properties:
         | 
| 1534 | 
            -
                  limit:
         | 
| 1535 | 
            -
                    title: Limit
         | 
| 1536 | 
            -
                    description: The maximum number of calls allowed within the interval.
         | 
| 1537 | 
            -
                    type: integer
         | 
| 1538 | 
            -
                  interval:
         | 
| 1539 | 
            -
                    title: Interval
         | 
| 1540 | 
            -
                    description: The time interval for the rate limit.
         | 
| 1541 | 
            -
                    type: string
         | 
| 1542 | 
            -
                    format: duration
         | 
| 1543 | 
            -
                additionalProperties: true
         | 
| 1544 | 
            -
              HttpRequestRegexMatcher:
         | 
| 1545 | 
            -
                title: HTTP Request Matcher
         | 
| 1546 | 
            -
                description: >
         | 
| 1547 | 
            -
                  Matches HTTP requests based on method, base URL, URL path pattern, query parameters, and headers.
         | 
| 1548 | 
            -
                  Use `url_base` to specify the scheme and host (without trailing slash) and
         | 
| 1549 | 
            -
                  `url_path_pattern` to apply a regex to the request path.
         | 
| 1550 | 
            -
                type: object
         | 
| 1551 | 
            -
                properties:
         | 
| 1552 | 
            -
                  method:
         | 
| 1553 | 
            -
                    title: Method
         | 
| 1554 | 
            -
                    description: The HTTP method to match (e.g., GET, POST).
         | 
| 1555 | 
            -
                    type: string
         | 
| 1556 | 
            -
                  url_base:
         | 
| 1557 | 
            -
                    title: URL Base
         | 
| 1558 | 
            -
                    description: The base URL (scheme and host, e.g. "https://api.example.com") to match.
         | 
| 1559 | 
            -
                    type: string
         | 
| 1560 | 
            -
                  url_path_pattern:
         | 
| 1561 | 
            -
                    title: URL Path Pattern
         | 
| 1562 | 
            -
                    description: A regular expression pattern to match the URL path.
         | 
| 1563 | 
            -
                    type: string
         | 
| 1564 | 
            -
                  params:
         | 
| 1565 | 
            -
                    title: Parameters
         | 
| 1566 | 
            -
                    description: The query parameters to match.
         | 
| 1567 | 
            -
                    type: object
         | 
| 1568 | 
            -
                    additionalProperties: true
         | 
| 1569 | 
            -
                  headers:
         | 
| 1570 | 
            -
                    title: Headers
         | 
| 1571 | 
            -
                    description: The headers to match.
         | 
| 1572 | 
            -
                    type: object
         | 
| 1573 | 
            -
                    additionalProperties: true
         | 
| 1574 | 
            -
                additionalProperties: true
         | 
| 1575 1368 | 
             
              DefaultErrorHandler:
         | 
| 1576 1369 | 
             
                title: Default Error Handler
         | 
| 1577 1370 | 
             
                description: Component defining how to handle errors. Default behavior includes only retrying server errors (HTTP 5XX) and too many requests (HTTP 429) with an exponential backoff.
         | 
| @@ -137,10 +137,6 @@ class ManifestDeclarativeSource(DeclarativeSource): | |
| 137 137 | 
             
                        self._source_config, config
         | 
| 138 138 | 
             
                    )
         | 
| 139 139 |  | 
| 140 | 
            -
                    api_budget_model = self._source_config.get("api_budget")
         | 
| 141 | 
            -
                    if api_budget_model:
         | 
| 142 | 
            -
                        self._constructor.set_api_budget(api_budget_model, config)
         | 
| 143 | 
            -
             | 
| 144 140 | 
             
                    source_streams = [
         | 
| 145 141 | 
             
                        self._constructor.create_component(
         | 
| 146 142 | 
             
                            DeclarativeStreamModel,
         | 
| @@ -3,7 +3,6 @@ | |
| 3 3 |  | 
| 4 4 | 
             
            from __future__ import annotations
         | 
| 5 5 |  | 
| 6 | 
            -
            from datetime import datetime, timedelta
         | 
| 7 6 | 
             
            from enum import Enum
         | 
| 8 7 | 
             
            from typing import Any, Dict, List, Literal, Optional, Union
         | 
| 9 8 |  | 
| @@ -643,45 +642,6 @@ class OAuthAuthenticator(BaseModel): | |
| 643 642 | 
             
                parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")
         | 
| 644 643 |  | 
| 645 644 |  | 
| 646 | 
            -
            class Rate(BaseModel):
         | 
| 647 | 
            -
                class Config:
         | 
| 648 | 
            -
                    extra = Extra.allow
         | 
| 649 | 
            -
             | 
| 650 | 
            -
                limit: int = Field(
         | 
| 651 | 
            -
                    ...,
         | 
| 652 | 
            -
                    description="The maximum number of calls allowed within the interval.",
         | 
| 653 | 
            -
                    title="Limit",
         | 
| 654 | 
            -
                )
         | 
| 655 | 
            -
                interval: timedelta = Field(
         | 
| 656 | 
            -
                    ..., description="The time interval for the rate limit.", title="Interval"
         | 
| 657 | 
            -
                )
         | 
| 658 | 
            -
             | 
| 659 | 
            -
             | 
| 660 | 
            -
            class HttpRequestRegexMatcher(BaseModel):
         | 
| 661 | 
            -
                class Config:
         | 
| 662 | 
            -
                    extra = Extra.allow
         | 
| 663 | 
            -
             | 
| 664 | 
            -
                method: Optional[str] = Field(
         | 
| 665 | 
            -
                    None, description="The HTTP method to match (e.g., GET, POST).", title="Method"
         | 
| 666 | 
            -
                )
         | 
| 667 | 
            -
                url_base: Optional[str] = Field(
         | 
| 668 | 
            -
                    None,
         | 
| 669 | 
            -
                    description='The base URL (scheme and host, e.g. "https://api.example.com") to match.',
         | 
| 670 | 
            -
                    title="URL Base",
         | 
| 671 | 
            -
                )
         | 
| 672 | 
            -
                url_path_pattern: Optional[str] = Field(
         | 
| 673 | 
            -
                    None,
         | 
| 674 | 
            -
                    description="A regular expression pattern to match the URL path.",
         | 
| 675 | 
            -
                    title="URL Path Pattern",
         | 
| 676 | 
            -
                )
         | 
| 677 | 
            -
                params: Optional[Dict[str, Any]] = Field(
         | 
| 678 | 
            -
                    None, description="The query parameters to match.", title="Parameters"
         | 
| 679 | 
            -
                )
         | 
| 680 | 
            -
                headers: Optional[Dict[str, Any]] = Field(
         | 
| 681 | 
            -
                    None, description="The headers to match.", title="Headers"
         | 
| 682 | 
            -
                )
         | 
| 683 | 
            -
             | 
| 684 | 
            -
             | 
| 685 645 | 
             
            class DpathExtractor(BaseModel):
         | 
| 686 646 | 
             
                type: Literal["DpathExtractor"]
         | 
| 687 647 | 
             
                field_path: List[str] = Field(
         | 
| @@ -1624,60 +1584,6 @@ class DatetimeBasedCursor(BaseModel): | |
| 1624 1584 | 
             
                parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")
         | 
| 1625 1585 |  | 
| 1626 1586 |  | 
| 1627 | 
            -
            class FixedWindowCallRatePolicy(BaseModel):
         | 
| 1628 | 
            -
                class Config:
         | 
| 1629 | 
            -
                    extra = Extra.allow
         | 
| 1630 | 
            -
             | 
| 1631 | 
            -
                type: Literal["FixedWindowCallRatePolicy"]
         | 
| 1632 | 
            -
                next_reset_ts: datetime = Field(
         | 
| 1633 | 
            -
                    ...,
         | 
| 1634 | 
            -
                    description="The timestamp when the rate limit will reset.",
         | 
| 1635 | 
            -
                    title="Next Reset Timestamp",
         | 
| 1636 | 
            -
                )
         | 
| 1637 | 
            -
                period: timedelta = Field(
         | 
| 1638 | 
            -
                    ..., description="The time interval for the rate limit window.", title="Period"
         | 
| 1639 | 
            -
                )
         | 
| 1640 | 
            -
                call_limit: int = Field(
         | 
| 1641 | 
            -
                    ...,
         | 
| 1642 | 
            -
                    description="The maximum number of calls allowed within the period.",
         | 
| 1643 | 
            -
                    title="Call Limit",
         | 
| 1644 | 
            -
                )
         | 
| 1645 | 
            -
                matchers: List[HttpRequestRegexMatcher] = Field(
         | 
| 1646 | 
            -
                    ...,
         | 
| 1647 | 
            -
                    description="List of matchers that define which requests this policy applies to.",
         | 
| 1648 | 
            -
                    title="Matchers",
         | 
| 1649 | 
            -
                )
         | 
| 1650 | 
            -
             | 
| 1651 | 
            -
             | 
| 1652 | 
            -
            class MovingWindowCallRatePolicy(BaseModel):
         | 
| 1653 | 
            -
                class Config:
         | 
| 1654 | 
            -
                    extra = Extra.allow
         | 
| 1655 | 
            -
             | 
| 1656 | 
            -
                type: Literal["MovingWindowCallRatePolicy"]
         | 
| 1657 | 
            -
                rates: List[Rate] = Field(
         | 
| 1658 | 
            -
                    ...,
         | 
| 1659 | 
            -
                    description="List of rates that define the call limits for different time intervals.",
         | 
| 1660 | 
            -
                    title="Rates",
         | 
| 1661 | 
            -
                )
         | 
| 1662 | 
            -
                matchers: List[HttpRequestRegexMatcher] = Field(
         | 
| 1663 | 
            -
                    ...,
         | 
| 1664 | 
            -
                    description="List of matchers that define which requests this policy applies to.",
         | 
| 1665 | 
            -
                    title="Matchers",
         | 
| 1666 | 
            -
                )
         | 
| 1667 | 
            -
             | 
| 1668 | 
            -
             | 
| 1669 | 
            -
            class UnlimitedCallRatePolicy(BaseModel):
         | 
| 1670 | 
            -
                class Config:
         | 
| 1671 | 
            -
                    extra = Extra.allow
         | 
| 1672 | 
            -
             | 
| 1673 | 
            -
                type: Literal["UnlimitedCallRatePolicy"]
         | 
| 1674 | 
            -
                matchers: List[HttpRequestRegexMatcher] = Field(
         | 
| 1675 | 
            -
                    ...,
         | 
| 1676 | 
            -
                    description="List of matchers that define which requests this policy applies to.",
         | 
| 1677 | 
            -
                    title="Matchers",
         | 
| 1678 | 
            -
                )
         | 
| 1679 | 
            -
             | 
| 1680 | 
            -
             | 
| 1681 1587 | 
             
            class DefaultErrorHandler(BaseModel):
         | 
| 1682 1588 | 
             
                type: Literal["DefaultErrorHandler"]
         | 
| 1683 1589 | 
             
                backoff_strategies: Optional[
         | 
| @@ -1809,67 +1715,6 @@ class CompositeErrorHandler(BaseModel): | |
| 1809 1715 | 
             
                parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")
         | 
| 1810 1716 |  | 
| 1811 1717 |  | 
| 1812 | 
            -
            class APIBudget(BaseModel):
         | 
| 1813 | 
            -
                class Config:
         | 
| 1814 | 
            -
                    extra = Extra.allow
         | 
| 1815 | 
            -
             | 
| 1816 | 
            -
                type: Literal["APIBudget"]
         | 
| 1817 | 
            -
                policies: List[
         | 
| 1818 | 
            -
                    Union[
         | 
| 1819 | 
            -
                        FixedWindowCallRatePolicy,
         | 
| 1820 | 
            -
                        MovingWindowCallRatePolicy,
         | 
| 1821 | 
            -
                        UnlimitedCallRatePolicy,
         | 
| 1822 | 
            -
                    ]
         | 
| 1823 | 
            -
                ] = Field(
         | 
| 1824 | 
            -
                    ...,
         | 
| 1825 | 
            -
                    description="List of call rate policies that define how many calls are allowed.",
         | 
| 1826 | 
            -
                    title="Policies",
         | 
| 1827 | 
            -
                )
         | 
| 1828 | 
            -
                maximum_attempts_to_acquire: Optional[int] = Field(
         | 
| 1829 | 
            -
                    100000,
         | 
| 1830 | 
            -
                    description="The maximum number of attempts to acquire a call before giving up.",
         | 
| 1831 | 
            -
                    title="Maximum Attempts to Acquire",
         | 
| 1832 | 
            -
                )
         | 
| 1833 | 
            -
             | 
| 1834 | 
            -
             | 
| 1835 | 
            -
            class HTTPAPIBudget(BaseModel):
         | 
| 1836 | 
            -
                class Config:
         | 
| 1837 | 
            -
                    extra = Extra.allow
         | 
| 1838 | 
            -
             | 
| 1839 | 
            -
                type: Literal["HTTPAPIBudget"]
         | 
| 1840 | 
            -
                policies: List[
         | 
| 1841 | 
            -
                    Union[
         | 
| 1842 | 
            -
                        FixedWindowCallRatePolicy,
         | 
| 1843 | 
            -
                        MovingWindowCallRatePolicy,
         | 
| 1844 | 
            -
                        UnlimitedCallRatePolicy,
         | 
| 1845 | 
            -
                    ]
         | 
| 1846 | 
            -
                ] = Field(
         | 
| 1847 | 
            -
                    ...,
         | 
| 1848 | 
            -
                    description="List of call rate policies that define how many calls are allowed.",
         | 
| 1849 | 
            -
                    title="Policies",
         | 
| 1850 | 
            -
                )
         | 
| 1851 | 
            -
                ratelimit_reset_header: Optional[str] = Field(
         | 
| 1852 | 
            -
                    "ratelimit-reset",
         | 
| 1853 | 
            -
                    description="The HTTP response header name that indicates when the rate limit resets.",
         | 
| 1854 | 
            -
                    title="Rate Limit Reset Header",
         | 
| 1855 | 
            -
                )
         | 
| 1856 | 
            -
                ratelimit_remaining_header: Optional[str] = Field(
         | 
| 1857 | 
            -
                    "ratelimit-remaining",
         | 
| 1858 | 
            -
                    description="The HTTP response header name that indicates the number of remaining allowed calls.",
         | 
| 1859 | 
            -
                    title="Rate Limit Remaining Header",
         | 
| 1860 | 
            -
                )
         | 
| 1861 | 
            -
                status_codes_for_ratelimit_hit: Optional[List[int]] = Field(
         | 
| 1862 | 
            -
                    [429],
         | 
| 1863 | 
            -
                    description="List of HTTP status codes that indicate a rate limit has been hit.",
         | 
| 1864 | 
            -
                    title="Status Codes for Rate Limit Hit",
         | 
| 1865 | 
            -
                )
         | 
| 1866 | 
            -
                maximum_attempts_to_acquire: Optional[int] = Field(
         | 
| 1867 | 
            -
                    100000,
         | 
| 1868 | 
            -
                    description="The maximum number of attempts to acquire a call before giving up.",
         | 
| 1869 | 
            -
                    title="Maximum Attempts to Acquire",
         | 
| 1870 | 
            -
                )
         | 
| 1871 | 
            -
             | 
| 1872 | 
            -
             | 
| 1873 1718 | 
             
            class ZipfileDecoder(BaseModel):
         | 
| 1874 1719 | 
             
                class Config:
         | 
| 1875 1720 | 
             
                    extra = Extra.allow
         | 
| @@ -1903,11 +1748,6 @@ class DeclarativeSource1(BaseModel): | |
| 1903 1748 | 
             
                definitions: Optional[Dict[str, Any]] = None
         | 
| 1904 1749 | 
             
                spec: Optional[Spec] = None
         | 
| 1905 1750 | 
             
                concurrency_level: Optional[ConcurrencyLevel] = None
         | 
| 1906 | 
            -
                api_budget: Optional[Union[APIBudget, HTTPAPIBudget]] = Field(
         | 
| 1907 | 
            -
                    None,
         | 
| 1908 | 
            -
                    description="Defines how many requests can be made to the API in a given time frame. This field accepts either a generic APIBudget or an HTTP-specific configuration (HTTPAPIBudget) to be applied across all streams.",
         | 
| 1909 | 
            -
                    title="API Budget",
         | 
| 1910 | 
            -
                )
         | 
| 1911 1751 | 
             
                metadata: Optional[Dict[str, Any]] = Field(
         | 
| 1912 1752 | 
             
                    None,
         | 
| 1913 1753 | 
             
                    description="For internal Airbyte use only - DO NOT modify manually. Used by consumers of declarative manifests for storing related metadata.",
         | 
| @@ -1934,11 +1774,6 @@ class DeclarativeSource2(BaseModel): | |
| 1934 1774 | 
             
                definitions: Optional[Dict[str, Any]] = None
         | 
| 1935 1775 | 
             
                spec: Optional[Spec] = None
         | 
| 1936 1776 | 
             
                concurrency_level: Optional[ConcurrencyLevel] = None
         | 
| 1937 | 
            -
                api_budget: Optional[Union[APIBudget, HTTPAPIBudget]] = Field(
         | 
| 1938 | 
            -
                    None,
         | 
| 1939 | 
            -
                    description="Defines how many requests can be made to the API in a given time frame. This field accepts either a generic APIBudget or an HTTP-specific configuration (HTTPAPIBudget) to be applied across all streams.",
         | 
| 1940 | 
            -
                    title="API Budget",
         | 
| 1941 | 
            -
                )
         | 
| 1942 1777 | 
             
                metadata: Optional[Dict[str, Any]] = Field(
         | 
| 1943 1778 | 
             
                    None,
         | 
| 1944 1779 | 
             
                    description="For internal Airbyte use only - DO NOT modify manually. Used by consumers of declarative manifests for storing related metadata.",
         | 
| @@ -112,9 +112,6 @@ from airbyte_cdk.sources.declarative.models.declarative_component_schema import | |
| 112 112 | 
             
            from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
         | 
| 113 113 | 
             
                AddFields as AddFieldsModel,
         | 
| 114 114 | 
             
            )
         | 
| 115 | 
            -
            from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
         | 
| 116 | 
            -
                APIBudget as APIBudgetModel,
         | 
| 117 | 
            -
            )
         | 
| 118 115 | 
             
            from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
         | 
| 119 116 | 
             
                ApiKeyAuthenticator as ApiKeyAuthenticatorModel,
         | 
| 120 117 | 
             
            )
         | 
| @@ -229,9 +226,6 @@ from airbyte_cdk.sources.declarative.models.declarative_component_schema import | |
| 229 226 | 
             
            from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
         | 
| 230 227 | 
             
                ExponentialBackoffStrategy as ExponentialBackoffStrategyModel,
         | 
| 231 228 | 
             
            )
         | 
| 232 | 
            -
            from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
         | 
| 233 | 
            -
                FixedWindowCallRatePolicy as FixedWindowCallRatePolicyModel,
         | 
| 234 | 
            -
            )
         | 
| 235 229 | 
             
            from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
         | 
| 236 230 | 
             
                FlattenFields as FlattenFieldsModel,
         | 
| 237 231 | 
             
            )
         | 
| @@ -241,18 +235,12 @@ from airbyte_cdk.sources.declarative.models.declarative_component_schema import | |
| 241 235 | 
             
            from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
         | 
| 242 236 | 
             
                GzipParser as GzipParserModel,
         | 
| 243 237 | 
             
            )
         | 
| 244 | 
            -
            from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
         | 
| 245 | 
            -
                HTTPAPIBudget as HTTPAPIBudgetModel,
         | 
| 246 | 
            -
            )
         | 
| 247 238 | 
             
            from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
         | 
| 248 239 | 
             
                HttpComponentsResolver as HttpComponentsResolverModel,
         | 
| 249 240 | 
             
            )
         | 
| 250 241 | 
             
            from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
         | 
| 251 242 | 
             
                HttpRequester as HttpRequesterModel,
         | 
| 252 243 | 
             
            )
         | 
| 253 | 
            -
            from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
         | 
| 254 | 
            -
                HttpRequestRegexMatcher as HttpRequestRegexMatcherModel,
         | 
| 255 | 
            -
            )
         | 
| 256 244 | 
             
            from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
         | 
| 257 245 | 
             
                HttpResponseFilter as HttpResponseFilterModel,
         | 
| 258 246 | 
             
            )
         | 
| @@ -307,9 +295,6 @@ from airbyte_cdk.sources.declarative.models.declarative_component_schema import | |
| 307 295 | 
             
            from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
         | 
| 308 296 | 
             
                MinMaxDatetime as MinMaxDatetimeModel,
         | 
| 309 297 | 
             
            )
         | 
| 310 | 
            -
            from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
         | 
| 311 | 
            -
                MovingWindowCallRatePolicy as MovingWindowCallRatePolicyModel,
         | 
| 312 | 
            -
            )
         | 
| 313 298 | 
             
            from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
         | 
| 314 299 | 
             
                NoAuth as NoAuthModel,
         | 
| 315 300 | 
             
            )
         | 
| @@ -328,9 +313,6 @@ from airbyte_cdk.sources.declarative.models.declarative_component_schema import | |
| 328 313 | 
             
            from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
         | 
| 329 314 | 
             
                ParentStreamConfig as ParentStreamConfigModel,
         | 
| 330 315 | 
             
            )
         | 
| 331 | 
            -
            from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
         | 
| 332 | 
            -
                Rate as RateModel,
         | 
| 333 | 
            -
            )
         | 
| 334 316 | 
             
            from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
         | 
| 335 317 | 
             
                RecordFilter as RecordFilterModel,
         | 
| 336 318 | 
             
            )
         | 
| @@ -374,9 +356,6 @@ from airbyte_cdk.sources.declarative.models.declarative_component_schema import | |
| 374 356 | 
             
            from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
         | 
| 375 357 | 
             
                TypesMap as TypesMapModel,
         | 
| 376 358 | 
             
            )
         | 
| 377 | 
            -
            from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
         | 
| 378 | 
            -
                UnlimitedCallRatePolicy as UnlimitedCallRatePolicyModel,
         | 
| 379 | 
            -
            )
         | 
| 380 359 | 
             
            from airbyte_cdk.sources.declarative.models.declarative_component_schema import ValueType
         | 
| 381 360 | 
             
            from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
         | 
| 382 361 | 
             
                WaitTimeFromHeader as WaitTimeFromHeaderModel,
         | 
| @@ -490,15 +469,6 @@ from airbyte_cdk.sources.message import ( | |
| 490 469 | 
             
                MessageRepository,
         | 
| 491 470 | 
             
                NoopMessageRepository,
         | 
| 492 471 | 
             
            )
         | 
| 493 | 
            -
            from airbyte_cdk.sources.streams.call_rate import (
         | 
| 494 | 
            -
                APIBudget,
         | 
| 495 | 
            -
                FixedWindowCallRatePolicy,
         | 
| 496 | 
            -
                HttpAPIBudget,
         | 
| 497 | 
            -
                HttpRequestRegexMatcher,
         | 
| 498 | 
            -
                MovingWindowCallRatePolicy,
         | 
| 499 | 
            -
                Rate,
         | 
| 500 | 
            -
                UnlimitedCallRatePolicy,
         | 
| 501 | 
            -
            )
         | 
| 502 472 | 
             
            from airbyte_cdk.sources.streams.concurrent.clamping import (
         | 
| 503 473 | 
             
                ClampingEndProvider,
         | 
| 504 474 | 
             
                ClampingStrategy,
         | 
| @@ -550,7 +520,6 @@ class ModelToComponentFactory: | |
| 550 520 | 
             
                        self._evaluate_log_level(emit_connector_builder_messages)
         | 
| 551 521 | 
             
                    )
         | 
| 552 522 | 
             
                    self._connector_state_manager = connector_state_manager or ConnectorStateManager()
         | 
| 553 | 
            -
                    self._api_budget: Optional[Union[APIBudget, HttpAPIBudget]] = None
         | 
| 554 523 |  | 
| 555 524 | 
             
                def _init_mappings(self) -> None:
         | 
| 556 525 | 
             
                    self.PYDANTIC_MODEL_TO_CONSTRUCTOR: Mapping[Type[BaseModel], Callable[..., Any]] = {
         | 
| @@ -638,13 +607,6 @@ class ModelToComponentFactory: | |
| 638 607 | 
             
                        StreamConfigModel: self.create_stream_config,
         | 
| 639 608 | 
             
                        ComponentMappingDefinitionModel: self.create_components_mapping_definition,
         | 
| 640 609 | 
             
                        ZipfileDecoderModel: self.create_zipfile_decoder,
         | 
| 641 | 
            -
                        APIBudgetModel: self.create_api_budget,
         | 
| 642 | 
            -
                        HTTPAPIBudgetModel: self.create_http_api_budget,
         | 
| 643 | 
            -
                        FixedWindowCallRatePolicyModel: self.create_fixed_window_call_rate_policy,
         | 
| 644 | 
            -
                        MovingWindowCallRatePolicyModel: self.create_moving_window_call_rate_policy,
         | 
| 645 | 
            -
                        UnlimitedCallRatePolicyModel: self.create_unlimited_call_rate_policy,
         | 
| 646 | 
            -
                        RateModel: self.create_rate,
         | 
| 647 | 
            -
                        HttpRequestRegexMatcherModel: self.create_http_request_matcher,
         | 
| 648 610 | 
             
                    }
         | 
| 649 611 |  | 
| 650 612 | 
             
                    # Needed for the case where we need to perform a second parse on the fields of a custom component
         | 
| @@ -972,6 +934,17 @@ class ModelToComponentFactory: | |
| 972 934 | 
             
                        parameters={},
         | 
| 973 935 | 
             
                    )
         | 
| 974 936 |  | 
| 937 | 
            +
                @staticmethod
         | 
| 938 | 
            +
                def apply_stream_state_migrations(
         | 
| 939 | 
            +
                    stream_state_migrations: List[Any] | None, stream_state: MutableMapping[str, Any]
         | 
| 940 | 
            +
                ) -> MutableMapping[str, Any]:
         | 
| 941 | 
            +
                    if stream_state_migrations:
         | 
| 942 | 
            +
                        for state_migration in stream_state_migrations:
         | 
| 943 | 
            +
                            if state_migration.should_migrate(stream_state):
         | 
| 944 | 
            +
                                # The state variable is expected to be mutable but the migrate method returns an immutable mapping.
         | 
| 945 | 
            +
                                stream_state = dict(state_migration.migrate(stream_state))
         | 
| 946 | 
            +
                    return stream_state
         | 
| 947 | 
            +
             | 
| 975 948 | 
             
                def create_concurrent_cursor_from_datetime_based_cursor(
         | 
| 976 949 | 
             
                    self,
         | 
| 977 950 | 
             
                    model_type: Type[BaseModel],
         | 
| @@ -981,6 +954,7 @@ class ModelToComponentFactory: | |
| 981 954 | 
             
                    config: Config,
         | 
| 982 955 | 
             
                    message_repository: Optional[MessageRepository] = None,
         | 
| 983 956 | 
             
                    runtime_lookback_window: Optional[datetime.timedelta] = None,
         | 
| 957 | 
            +
                    stream_state_migrations: Optional[List[Any]] = None,
         | 
| 984 958 | 
             
                    **kwargs: Any,
         | 
| 985 959 | 
             
                ) -> ConcurrentCursor:
         | 
| 986 960 | 
             
                    # Per-partition incremental streams can dynamically create child cursors which will pass their current
         | 
| @@ -991,6 +965,7 @@ class ModelToComponentFactory: | |
| 991 965 | 
             
                        if "stream_state" not in kwargs
         | 
| 992 966 | 
             
                        else kwargs["stream_state"]
         | 
| 993 967 | 
             
                    )
         | 
| 968 | 
            +
                    stream_state = self.apply_stream_state_migrations(stream_state_migrations, stream_state)
         | 
| 994 969 |  | 
| 995 970 | 
             
                    component_type = component_definition.get("type")
         | 
| 996 971 | 
             
                    if component_definition.get("type") != model_type.__name__:
         | 
| @@ -1226,6 +1201,7 @@ class ModelToComponentFactory: | |
| 1226 1201 | 
             
                    config: Config,
         | 
| 1227 1202 | 
             
                    stream_state: MutableMapping[str, Any],
         | 
| 1228 1203 | 
             
                    partition_router: PartitionRouter,
         | 
| 1204 | 
            +
                    stream_state_migrations: Optional[List[Any]] = None,
         | 
| 1229 1205 | 
             
                    **kwargs: Any,
         | 
| 1230 1206 | 
             
                ) -> ConcurrentPerPartitionCursor:
         | 
| 1231 1207 | 
             
                    component_type = component_definition.get("type")
         | 
| @@ -1274,8 +1250,10 @@ class ModelToComponentFactory: | |
| 1274 1250 | 
             
                            stream_namespace=stream_namespace,
         | 
| 1275 1251 | 
             
                            config=config,
         | 
| 1276 1252 | 
             
                            message_repository=NoopMessageRepository(),
         | 
| 1253 | 
            +
                            stream_state_migrations=stream_state_migrations,
         | 
| 1277 1254 | 
             
                        )
         | 
| 1278 1255 | 
             
                    )
         | 
| 1256 | 
            +
                    stream_state = self.apply_stream_state_migrations(stream_state_migrations, stream_state)
         | 
| 1279 1257 |  | 
| 1280 1258 | 
             
                    # Return the concurrent cursor and state converter
         | 
| 1281 1259 | 
             
                    return ConcurrentPerPartitionCursor(
         | 
| @@ -1784,6 +1762,7 @@ class ModelToComponentFactory: | |
| 1784 1762 | 
             
                                stream_name=model.name or "",
         | 
| 1785 1763 | 
             
                                stream_namespace=None,
         | 
| 1786 1764 | 
             
                                config=config or {},
         | 
| 1765 | 
            +
                                stream_state_migrations=model.state_migrations,
         | 
| 1787 1766 | 
             
                            )
         | 
| 1788 1767 | 
             
                        return (
         | 
| 1789 1768 | 
             
                            self._create_component_from_model(model=model.incremental_sync, config=config)
         | 
| @@ -1940,8 +1919,6 @@ class ModelToComponentFactory: | |
| 1940 1919 | 
             
                        )
         | 
| 1941 1920 | 
             
                    )
         | 
| 1942 1921 |  | 
| 1943 | 
            -
                    api_budget = self._api_budget
         | 
| 1944 | 
            -
             | 
| 1945 1922 | 
             
                    request_options_provider = InterpolatedRequestOptionsProvider(
         | 
| 1946 1923 | 
             
                        request_body_data=model.request_body_data,
         | 
| 1947 1924 | 
             
                        request_body_json=model.request_body_json,
         | 
| @@ -1962,7 +1939,6 @@ class ModelToComponentFactory: | |
| 1962 1939 | 
             
                        path=model.path,
         | 
| 1963 1940 | 
             
                        authenticator=authenticator,
         | 
| 1964 1941 | 
             
                        error_handler=error_handler,
         | 
| 1965 | 
            -
                        api_budget=api_budget,
         | 
| 1966 1942 | 
             
                        http_method=HttpMethod[model.http_method.value],
         | 
| 1967 1943 | 
             
                        request_options_provider=request_options_provider,
         | 
| 1968 1944 | 
             
                        config=config,
         | 
| @@ -2964,103 +2940,3 @@ class ModelToComponentFactory: | |
| 2964 2940 | 
             
                        return isinstance(parser.inner_parser, JsonParser)
         | 
| 2965 2941 | 
             
                    else:
         | 
| 2966 2942 | 
             
                        return False
         | 
| 2967 | 
            -
             | 
| 2968 | 
            -
                def create_api_budget(self, model: APIBudgetModel, config: Config, **kwargs: Any) -> APIBudget:
         | 
| 2969 | 
            -
                    policies = [
         | 
| 2970 | 
            -
                        self._create_component_from_model(model=policy, config=config)
         | 
| 2971 | 
            -
                        for policy in model.policies
         | 
| 2972 | 
            -
                    ]
         | 
| 2973 | 
            -
             | 
| 2974 | 
            -
                    return APIBudget(
         | 
| 2975 | 
            -
                        policies=policies,
         | 
| 2976 | 
            -
                        maximum_attempts_to_acquire=model.maximum_attempts_to_acquire or 100000,
         | 
| 2977 | 
            -
                    )
         | 
| 2978 | 
            -
             | 
| 2979 | 
            -
                def create_http_api_budget(
         | 
| 2980 | 
            -
                    self, model: HTTPAPIBudgetModel, config: Config, **kwargs: Any
         | 
| 2981 | 
            -
                ) -> HttpAPIBudget:
         | 
| 2982 | 
            -
                    policies = [
         | 
| 2983 | 
            -
                        self._create_component_from_model(model=policy, config=config)
         | 
| 2984 | 
            -
                        for policy in model.policies
         | 
| 2985 | 
            -
                    ]
         | 
| 2986 | 
            -
             | 
| 2987 | 
            -
                    return HttpAPIBudget(
         | 
| 2988 | 
            -
                        policies=policies,
         | 
| 2989 | 
            -
                        maximum_attempts_to_acquire=model.maximum_attempts_to_acquire or 100000,
         | 
| 2990 | 
            -
                        ratelimit_reset_header=model.ratelimit_reset_header or "ratelimit-reset",
         | 
| 2991 | 
            -
                        ratelimit_remaining_header=model.ratelimit_remaining_header or "ratelimit-remaining",
         | 
| 2992 | 
            -
                        status_codes_for_ratelimit_hit=model.status_codes_for_ratelimit_hit or (429,),
         | 
| 2993 | 
            -
                    )
         | 
| 2994 | 
            -
             | 
| 2995 | 
            -
                def create_fixed_window_call_rate_policy(
         | 
| 2996 | 
            -
                    self, model: FixedWindowCallRatePolicyModel, config: Config, **kwargs: Any
         | 
| 2997 | 
            -
                ) -> FixedWindowCallRatePolicy:
         | 
| 2998 | 
            -
                    matchers = [
         | 
| 2999 | 
            -
                        self._create_component_from_model(model=matcher, config=config)
         | 
| 3000 | 
            -
                        for matcher in model.matchers
         | 
| 3001 | 
            -
                    ]
         | 
| 3002 | 
            -
                    return FixedWindowCallRatePolicy(
         | 
| 3003 | 
            -
                        next_reset_ts=model.next_reset_ts,
         | 
| 3004 | 
            -
                        period=model.period,
         | 
| 3005 | 
            -
                        call_limit=model.call_limit,
         | 
| 3006 | 
            -
                        matchers=matchers,
         | 
| 3007 | 
            -
                    )
         | 
| 3008 | 
            -
             | 
| 3009 | 
            -
                def create_moving_window_call_rate_policy(
         | 
| 3010 | 
            -
                    self, model: MovingWindowCallRatePolicyModel, config: Config, **kwargs: Any
         | 
| 3011 | 
            -
                ) -> MovingWindowCallRatePolicy:
         | 
| 3012 | 
            -
                    rates = [
         | 
| 3013 | 
            -
                        self._create_component_from_model(model=rate, config=config) for rate in model.rates
         | 
| 3014 | 
            -
                    ]
         | 
| 3015 | 
            -
                    matchers = [
         | 
| 3016 | 
            -
                        self._create_component_from_model(model=matcher, config=config)
         | 
| 3017 | 
            -
                        for matcher in model.matchers
         | 
| 3018 | 
            -
                    ]
         | 
| 3019 | 
            -
                    return MovingWindowCallRatePolicy(
         | 
| 3020 | 
            -
                        rates=rates,
         | 
| 3021 | 
            -
                        matchers=matchers,
         | 
| 3022 | 
            -
                    )
         | 
| 3023 | 
            -
             | 
| 3024 | 
            -
                def create_unlimited_call_rate_policy(
         | 
| 3025 | 
            -
                    self, model: UnlimitedCallRatePolicyModel, config: Config, **kwargs: Any
         | 
| 3026 | 
            -
                ) -> UnlimitedCallRatePolicy:
         | 
| 3027 | 
            -
                    matchers = [
         | 
| 3028 | 
            -
                        self._create_component_from_model(model=matcher, config=config)
         | 
| 3029 | 
            -
                        for matcher in model.matchers
         | 
| 3030 | 
            -
                    ]
         | 
| 3031 | 
            -
             | 
| 3032 | 
            -
                    return UnlimitedCallRatePolicy(
         | 
| 3033 | 
            -
                        matchers=matchers,
         | 
| 3034 | 
            -
                    )
         | 
| 3035 | 
            -
             | 
| 3036 | 
            -
                def create_rate(self, model: RateModel, config: Config, **kwargs: Any) -> Rate:
         | 
| 3037 | 
            -
                    return Rate(
         | 
| 3038 | 
            -
                        limit=model.limit,
         | 
| 3039 | 
            -
                        interval=model.interval,
         | 
| 3040 | 
            -
                    )
         | 
| 3041 | 
            -
             | 
| 3042 | 
            -
                def create_http_request_matcher(
         | 
| 3043 | 
            -
                    self, model: HttpRequestRegexMatcherModel, config: Config, **kwargs: Any
         | 
| 3044 | 
            -
                ) -> HttpRequestRegexMatcher:
         | 
| 3045 | 
            -
                    return HttpRequestRegexMatcher(
         | 
| 3046 | 
            -
                        method=model.method,
         | 
| 3047 | 
            -
                        url_base=model.url_base,
         | 
| 3048 | 
            -
                        url_path_pattern=model.url_path_pattern,
         | 
| 3049 | 
            -
                        params=model.params,
         | 
| 3050 | 
            -
                        headers=model.headers,
         | 
| 3051 | 
            -
                    )
         | 
| 3052 | 
            -
             | 
| 3053 | 
            -
                def set_api_budget(self, component_definition: ComponentDefinition, config: Config) -> None:
         | 
| 3054 | 
            -
                    model_str = component_definition.get("type")
         | 
| 3055 | 
            -
                    if model_str == "APIBudget":
         | 
| 3056 | 
            -
                        # Annotate model_type as a type that is a subclass of BaseModel
         | 
| 3057 | 
            -
                        model_type: Union[Type[APIBudgetModel], Type[HTTPAPIBudgetModel]] = APIBudgetModel
         | 
| 3058 | 
            -
                    elif model_str == "HTTPAPIBudget":
         | 
| 3059 | 
            -
                        model_type = HTTPAPIBudgetModel
         | 
| 3060 | 
            -
                    else:
         | 
| 3061 | 
            -
                        raise ValueError(f"Unknown API Budget type: {model_str}")
         | 
| 3062 | 
            -
             | 
| 3063 | 
            -
                    # create_component expects a type[BaseModel] and returns an instance of that model.
         | 
| 3064 | 
            -
                    self._api_budget = self.create_component(
         | 
| 3065 | 
            -
                        model_type=model_type, component_definition=component_definition, config=config
         | 
| 3066 | 
            -
                    )
         | 
| @@ -22,7 +22,6 @@ from airbyte_cdk.sources.declarative.requesters.request_options.interpolated_req | |
| 22 22 | 
             
            )
         | 
| 23 23 | 
             
            from airbyte_cdk.sources.declarative.requesters.requester import HttpMethod, Requester
         | 
| 24 24 | 
             
            from airbyte_cdk.sources.message import MessageRepository, NoopMessageRepository
         | 
| 25 | 
            -
            from airbyte_cdk.sources.streams.call_rate import APIBudget
         | 
| 26 25 | 
             
            from airbyte_cdk.sources.streams.http import HttpClient
         | 
| 27 26 | 
             
            from airbyte_cdk.sources.streams.http.error_handlers import ErrorHandler
         | 
| 28 27 | 
             
            from airbyte_cdk.sources.types import Config, StreamSlice, StreamState
         | 
| @@ -56,7 +55,6 @@ class HttpRequester(Requester): | |
| 56 55 | 
             
                http_method: Union[str, HttpMethod] = HttpMethod.GET
         | 
| 57 56 | 
             
                request_options_provider: Optional[InterpolatedRequestOptionsProvider] = None
         | 
| 58 57 | 
             
                error_handler: Optional[ErrorHandler] = None
         | 
| 59 | 
            -
                api_budget: Optional[APIBudget] = None
         | 
| 60 58 | 
             
                disable_retries: bool = False
         | 
| 61 59 | 
             
                message_repository: MessageRepository = NoopMessageRepository()
         | 
| 62 60 | 
             
                use_cache: bool = False
         | 
| @@ -93,7 +91,6 @@ class HttpRequester(Requester): | |
| 93 91 | 
             
                        name=self.name,
         | 
| 94 92 | 
             
                        logger=self.logger,
         | 
| 95 93 | 
             
                        error_handler=self.error_handler,
         | 
| 96 | 
            -
                        api_budget=self.api_budget,
         | 
| 97 94 | 
             
                        authenticator=self._authenticator,
         | 
| 98 95 | 
             
                        use_cache=self.use_cache,
         | 
| 99 96 | 
             
                        backoff_strategy=backoff_strategies,
         | 
| @@ -6,12 +6,10 @@ import abc | |
| 6 6 | 
             
            import dataclasses
         | 
| 7 7 | 
             
            import datetime
         | 
| 8 8 | 
             
            import logging
         | 
| 9 | 
            -
            import re
         | 
| 10 9 | 
             
            import time
         | 
| 11 | 
            -
            from dataclasses import InitVar, dataclass, field
         | 
| 12 10 | 
             
            from datetime import timedelta
         | 
| 13 11 | 
             
            from threading import RLock
         | 
| 14 | 
            -
            from typing import TYPE_CHECKING, Any, Mapping, Optional | 
| 12 | 
            +
            from typing import TYPE_CHECKING, Any, Mapping, Optional
         | 
| 15 13 | 
             
            from urllib import parse
         | 
| 16 14 |  | 
| 17 15 | 
             
            import requests
         | 
| @@ -162,100 +160,6 @@ class HttpRequestMatcher(RequestMatcher): | |
| 162 160 | 
             
                    return True
         | 
| 163 161 |  | 
| 164 162 |  | 
| 165 | 
            -
            class HttpRequestRegexMatcher(RequestMatcher):
         | 
| 166 | 
            -
                """
         | 
| 167 | 
            -
                Extended RequestMatcher for HTTP requests that supports matching on:
         | 
| 168 | 
            -
                  - HTTP method (case-insensitive)
         | 
| 169 | 
            -
                  - URL base (scheme + netloc) optionally
         | 
| 170 | 
            -
                  - URL path pattern (a regex applied to the path portion of the URL)
         | 
| 171 | 
            -
                  - Query parameters (must be present)
         | 
| 172 | 
            -
                  - Headers (header names compared case-insensitively)
         | 
| 173 | 
            -
                """
         | 
| 174 | 
            -
             | 
| 175 | 
            -
                def __init__(
         | 
| 176 | 
            -
                    self,
         | 
| 177 | 
            -
                    method: Optional[str] = None,
         | 
| 178 | 
            -
                    url_base: Optional[str] = None,
         | 
| 179 | 
            -
                    url_path_pattern: Optional[str] = None,
         | 
| 180 | 
            -
                    params: Optional[Mapping[str, Any]] = None,
         | 
| 181 | 
            -
                    headers: Optional[Mapping[str, Any]] = None,
         | 
| 182 | 
            -
                ):
         | 
| 183 | 
            -
                    """
         | 
| 184 | 
            -
                    :param method: HTTP method (e.g. "GET", "POST"); compared case-insensitively.
         | 
| 185 | 
            -
                    :param url_base: Base URL (scheme://host) that must match.
         | 
| 186 | 
            -
                    :param url_path_pattern: A regex pattern that will be applied to the path portion of the URL.
         | 
| 187 | 
            -
                    :param params: Dictionary of query parameters that must be present in the request.
         | 
| 188 | 
            -
                    :param headers: Dictionary of headers that must be present (header keys are compared case-insensitively).
         | 
| 189 | 
            -
                    """
         | 
| 190 | 
            -
                    self._method = method.upper() if method else None
         | 
| 191 | 
            -
             | 
| 192 | 
            -
                    # Normalize the url_base if provided: remove trailing slash.
         | 
| 193 | 
            -
                    self._url_base = url_base.rstrip("/") if url_base else None
         | 
| 194 | 
            -
             | 
| 195 | 
            -
                    # Compile the URL path pattern if provided.
         | 
| 196 | 
            -
                    self._url_path_pattern = re.compile(url_path_pattern) if url_path_pattern else None
         | 
| 197 | 
            -
             | 
| 198 | 
            -
                    # Normalize query parameters to strings.
         | 
| 199 | 
            -
                    self._params = {str(k): str(v) for k, v in (params or {}).items()}
         | 
| 200 | 
            -
             | 
| 201 | 
            -
                    # Normalize header keys to lowercase.
         | 
| 202 | 
            -
                    self._headers = {str(k).lower(): str(v) for k, v in (headers or {}).items()}
         | 
| 203 | 
            -
             | 
| 204 | 
            -
                @staticmethod
         | 
| 205 | 
            -
                def _match_dict(obj: Mapping[str, Any], pattern: Mapping[str, Any]) -> bool:
         | 
| 206 | 
            -
                    """Check that every key/value in the pattern exists in the object."""
         | 
| 207 | 
            -
                    return pattern.items() <= obj.items()
         | 
| 208 | 
            -
             | 
| 209 | 
            -
                def __call__(self, request: Any) -> bool:
         | 
| 210 | 
            -
                    """
         | 
| 211 | 
            -
                    :param request: A requests.Request or requests.PreparedRequest instance.
         | 
| 212 | 
            -
                    :return: True if the request matches all provided criteria; False otherwise.
         | 
| 213 | 
            -
                    """
         | 
| 214 | 
            -
                    # Prepare the request (if needed) and extract the URL details.
         | 
| 215 | 
            -
                    if isinstance(request, requests.Request):
         | 
| 216 | 
            -
                        prepared_request = request.prepare()
         | 
| 217 | 
            -
                    elif isinstance(request, requests.PreparedRequest):
         | 
| 218 | 
            -
                        prepared_request = request
         | 
| 219 | 
            -
                    else:
         | 
| 220 | 
            -
                        return False
         | 
| 221 | 
            -
             | 
| 222 | 
            -
                    # Check HTTP method.
         | 
| 223 | 
            -
                    if self._method is not None and prepared_request.method is not None:
         | 
| 224 | 
            -
                        if prepared_request.method.upper() != self._method:
         | 
| 225 | 
            -
                            return False
         | 
| 226 | 
            -
             | 
| 227 | 
            -
                    # Parse the URL.
         | 
| 228 | 
            -
                    parsed_url = parse.urlsplit(prepared_request.url)
         | 
| 229 | 
            -
                    # Reconstruct the base: scheme://netloc
         | 
| 230 | 
            -
                    request_url_base = f"{str(parsed_url.scheme)}://{str(parsed_url.netloc)}"
         | 
| 231 | 
            -
                    # The path (without query parameters)
         | 
| 232 | 
            -
                    request_path = str(parsed_url.path).rstrip("/")
         | 
| 233 | 
            -
             | 
| 234 | 
            -
                    # If a base URL is provided, check that it matches.
         | 
| 235 | 
            -
                    if self._url_base is not None:
         | 
| 236 | 
            -
                        if request_url_base != self._url_base:
         | 
| 237 | 
            -
                            return False
         | 
| 238 | 
            -
             | 
| 239 | 
            -
                    # If a URL path pattern is provided, ensure the path matches the regex.
         | 
| 240 | 
            -
                    if self._url_path_pattern is not None:
         | 
| 241 | 
            -
                        if not self._url_path_pattern.search(request_path):
         | 
| 242 | 
            -
                            return False
         | 
| 243 | 
            -
             | 
| 244 | 
            -
                    # Check query parameters.
         | 
| 245 | 
            -
                    if self._params:
         | 
| 246 | 
            -
                        query_params = dict(parse.parse_qsl(str(parsed_url.query)))
         | 
| 247 | 
            -
                        if not self._match_dict(query_params, self._params):
         | 
| 248 | 
            -
                            return False
         | 
| 249 | 
            -
             | 
| 250 | 
            -
                    # Check headers (normalize keys to lower-case).
         | 
| 251 | 
            -
                    if self._headers:
         | 
| 252 | 
            -
                        req_headers = {k.lower(): v for k, v in prepared_request.headers.items()}
         | 
| 253 | 
            -
                        if not self._match_dict(req_headers, self._headers):
         | 
| 254 | 
            -
                            return False
         | 
| 255 | 
            -
             | 
| 256 | 
            -
                    return True
         | 
| 257 | 
            -
             | 
| 258 | 
            -
             | 
| 259 163 | 
             
            class BaseCallRatePolicy(AbstractCallRatePolicy, abc.ABC):
         | 
| 260 164 | 
             
                def __init__(self, matchers: list[RequestMatcher]):
         | 
| 261 165 | 
             
                    self._matchers = matchers
         | 
| @@ -495,17 +399,24 @@ class AbstractAPIBudget(abc.ABC): | |
| 495 399 | 
             
                    """
         | 
| 496 400 |  | 
| 497 401 |  | 
| 498 | 
            -
            @dataclass
         | 
| 499 402 | 
             
            class APIBudget(AbstractAPIBudget):
         | 
| 500 | 
            -
                """
         | 
| 501 | 
            -
             | 
| 502 | 
            -
                 | 
| 403 | 
            +
                """Default APIBudget implementation"""
         | 
| 404 | 
            +
             | 
| 405 | 
            +
                def __init__(
         | 
| 406 | 
            +
                    self, policies: list[AbstractCallRatePolicy], maximum_attempts_to_acquire: int = 100000
         | 
| 407 | 
            +
                ) -> None:
         | 
| 408 | 
            +
                    """Constructor
         | 
| 409 | 
            +
             | 
| 410 | 
            +
                    :param policies: list of policies in this budget
         | 
| 411 | 
            +
                    :param maximum_attempts_to_acquire: number of attempts before throwing hit ratelimit exception, we put some big number here
         | 
| 412 | 
            +
                     to avoid situations when many threads compete with each other for a few lots over a significant amount of time
         | 
| 413 | 
            +
                    """
         | 
| 503 414 |  | 
| 504 | 
            -
             | 
| 505 | 
            -
             | 
| 415 | 
            +
                    self._policies = policies
         | 
| 416 | 
            +
                    self._maximum_attempts_to_acquire = maximum_attempts_to_acquire
         | 
| 506 417 |  | 
| 507 418 | 
             
                def get_matching_policy(self, request: Any) -> Optional[AbstractCallRatePolicy]:
         | 
| 508 | 
            -
                    for policy in self. | 
| 419 | 
            +
                    for policy in self._policies:
         | 
| 509 420 | 
             
                        if policy.matches(request):
         | 
| 510 421 | 
             
                            return policy
         | 
| 511 422 | 
             
                    return None
         | 
| @@ -526,7 +437,7 @@ class APIBudget(AbstractAPIBudget): | |
| 526 437 | 
             
                    policy = self.get_matching_policy(request)
         | 
| 527 438 | 
             
                    if policy:
         | 
| 528 439 | 
             
                        self._do_acquire(request=request, policy=policy, block=block, timeout=timeout)
         | 
| 529 | 
            -
                    elif self. | 
| 440 | 
            +
                    elif self._policies:
         | 
| 530 441 | 
             
                        logger.info("no policies matched with requests, allow call by default")
         | 
| 531 442 |  | 
| 532 443 | 
             
                def update_from_response(self, request: Any, response: Any) -> None:
         | 
| @@ -549,7 +460,7 @@ class APIBudget(AbstractAPIBudget): | |
| 549 460 | 
             
                    """
         | 
| 550 461 | 
             
                    last_exception = None
         | 
| 551 462 | 
             
                    # sometimes we spend all budget before a second attempt, so we have few more here
         | 
| 552 | 
            -
                    for attempt in range(1, self. | 
| 463 | 
            +
                    for attempt in range(1, self._maximum_attempts_to_acquire):
         | 
| 553 464 | 
             
                        try:
         | 
| 554 465 | 
             
                            policy.try_acquire(request, weight=1)
         | 
| 555 466 | 
             
                            return
         | 
| @@ -573,18 +484,31 @@ class APIBudget(AbstractAPIBudget): | |
| 573 484 |  | 
| 574 485 | 
             
                    if last_exception:
         | 
| 575 486 | 
             
                        logger.info(
         | 
| 576 | 
            -
                            "we used all %s attempts to acquire and failed", self. | 
| 487 | 
            +
                            "we used all %s attempts to acquire and failed", self._maximum_attempts_to_acquire
         | 
| 577 488 | 
             
                        )
         | 
| 578 489 | 
             
                        raise last_exception
         | 
| 579 490 |  | 
| 580 491 |  | 
| 581 | 
            -
            @dataclass
         | 
| 582 492 | 
             
            class HttpAPIBudget(APIBudget):
         | 
| 583 493 | 
             
                """Implementation of AbstractAPIBudget for HTTP"""
         | 
| 584 494 |  | 
| 585 | 
            -
                 | 
| 586 | 
            -
             | 
| 587 | 
            -
             | 
| 495 | 
            +
                def __init__(
         | 
| 496 | 
            +
                    self,
         | 
| 497 | 
            +
                    ratelimit_reset_header: str = "ratelimit-reset",
         | 
| 498 | 
            +
                    ratelimit_remaining_header: str = "ratelimit-remaining",
         | 
| 499 | 
            +
                    status_codes_for_ratelimit_hit: tuple[int] = (429,),
         | 
| 500 | 
            +
                    **kwargs: Any,
         | 
| 501 | 
            +
                ):
         | 
| 502 | 
            +
                    """Constructor
         | 
| 503 | 
            +
             | 
| 504 | 
            +
                    :param ratelimit_reset_header: name of the header that has a timestamp of the next reset of call budget
         | 
| 505 | 
            +
                    :param ratelimit_remaining_header: name of the header that has the number of calls left
         | 
| 506 | 
            +
                    :param status_codes_for_ratelimit_hit: list of HTTP status codes that signal about rate limit being hit
         | 
| 507 | 
            +
                    """
         | 
| 508 | 
            +
                    self._ratelimit_reset_header = ratelimit_reset_header
         | 
| 509 | 
            +
                    self._ratelimit_remaining_header = ratelimit_remaining_header
         | 
| 510 | 
            +
                    self._status_codes_for_ratelimit_hit = status_codes_for_ratelimit_hit
         | 
| 511 | 
            +
                    super().__init__(**kwargs)
         | 
| 588 512 |  | 
| 589 513 | 
             
                def update_from_response(self, request: Any, response: Any) -> None:
         | 
| 590 514 | 
             
                    policy = self.get_matching_policy(request)
         | 
| @@ -599,17 +523,17 @@ class HttpAPIBudget(APIBudget): | |
| 599 523 | 
             
                def get_reset_ts_from_response(
         | 
| 600 524 | 
             
                    self, response: requests.Response
         | 
| 601 525 | 
             
                ) -> Optional[datetime.datetime]:
         | 
| 602 | 
            -
                    if response.headers.get(self. | 
| 526 | 
            +
                    if response.headers.get(self._ratelimit_reset_header):
         | 
| 603 527 | 
             
                        return datetime.datetime.fromtimestamp(
         | 
| 604 | 
            -
                            int(response.headers[self. | 
| 528 | 
            +
                            int(response.headers[self._ratelimit_reset_header])
         | 
| 605 529 | 
             
                        )
         | 
| 606 530 | 
             
                    return None
         | 
| 607 531 |  | 
| 608 532 | 
             
                def get_calls_left_from_response(self, response: requests.Response) -> Optional[int]:
         | 
| 609 | 
            -
                    if response.headers.get(self. | 
| 610 | 
            -
                        return int(response.headers[self. | 
| 533 | 
            +
                    if response.headers.get(self._ratelimit_remaining_header):
         | 
| 534 | 
            +
                        return int(response.headers[self._ratelimit_remaining_header])
         | 
| 611 535 |  | 
| 612 | 
            -
                    if response.status_code in self. | 
| 536 | 
            +
                    if response.status_code in self._status_codes_for_ratelimit_hit:
         | 
| 613 537 | 
             
                        return 0
         | 
| 614 538 |  | 
| 615 539 | 
             
                    return None
         | 
| @@ -261,6 +261,9 @@ class AbstractOauth2Authenticator(AuthBase): | |
| 261 261 |  | 
| 262 262 | 
             
                    :return: expiration datetime
         | 
| 263 263 | 
             
                    """
         | 
| 264 | 
            +
                    if not value and not self.token_has_expired():
         | 
| 265 | 
            +
                        # No expiry token was provided but the previous one is not expired so it's fine
         | 
| 266 | 
            +
                        return self.get_token_expiry_date()
         | 
| 264 267 |  | 
| 265 268 | 
             
                    if self.token_expiry_is_time_of_expiration:
         | 
| 266 269 | 
             
                        if not self.token_expiry_date_format:
         | 
| @@ -53,7 +53,7 @@ airbyte_cdk/sources/declarative/async_job/timer.py,sha256=Fb8P72CQ7jIzJyzMSSNuBf | |
| 53 53 | 
             
            airbyte_cdk/sources/declarative/auth/__init__.py,sha256=e2CRrcBWGhz3sQu3Oh34d1riEIwXipGS8hrSB1pu0Oo,284
         | 
| 54 54 | 
             
            airbyte_cdk/sources/declarative/auth/declarative_authenticator.py,sha256=nf-OmRUHYG4ORBwyb5CANzuHEssE-oNmL-Lccn41Td8,1099
         | 
| 55 55 | 
             
            airbyte_cdk/sources/declarative/auth/jwt.py,sha256=SICqNsN2Cn_EgKadIgWuZpQxuMHyzrMZD_2-Uwy10rY,8539
         | 
| 56 | 
            -
            airbyte_cdk/sources/declarative/auth/oauth.py,sha256= | 
| 56 | 
            +
            airbyte_cdk/sources/declarative/auth/oauth.py,sha256=SUfib1oSzlyRRnOSg8Bui73mfyrcyr9OssdchbKdu4s,14162
         | 
| 57 57 | 
             
            airbyte_cdk/sources/declarative/auth/selective_authenticator.py,sha256=qGwC6YsCldr1bIeKG6Qo-A9a5cTdHw-vcOn3OtQrS4c,1540
         | 
| 58 58 | 
             
            airbyte_cdk/sources/declarative/auth/token.py,sha256=2EnE78EhBOY9hbeZnQJ9AuFaM-G7dccU-oKo_LThRQk,11070
         | 
| 59 59 | 
             
            airbyte_cdk/sources/declarative/auth/token_provider.py,sha256=9CuSsmOoHkvlc4k-oZ3Jx5luAgfTMm1I_5HOZxw7wMU,3075
         | 
| @@ -63,11 +63,11 @@ airbyte_cdk/sources/declarative/checks/check_stream.py,sha256=dAA-UhmMj0WLXCkRQr | |
| 63 63 | 
             
            airbyte_cdk/sources/declarative/checks/connection_checker.py,sha256=MBRJo6WJlZQHpIfOGaNOkkHUmgUl_4wDM6VPo41z5Ss,1383
         | 
| 64 64 | 
             
            airbyte_cdk/sources/declarative/concurrency_level/__init__.py,sha256=5XUqrmlstYlMM0j6crktlKQwALek0uiz2D3WdM46MyA,191
         | 
| 65 65 | 
             
            airbyte_cdk/sources/declarative/concurrency_level/concurrency_level.py,sha256=YIwCTCpOr_QSNW4ltQK0yUGWInI8PKNY216HOOegYLk,2101
         | 
| 66 | 
            -
            airbyte_cdk/sources/declarative/concurrent_declarative_source.py,sha256= | 
| 66 | 
            +
            airbyte_cdk/sources/declarative/concurrent_declarative_source.py,sha256=ThOqmaaqPykS2gTDKnlLSPy0p7djjV1Svazes58Rmic,28844
         | 
| 67 67 | 
             
            airbyte_cdk/sources/declarative/datetime/__init__.py,sha256=l9LG7Qm6e5r_qgqfVKnx3mXYtg1I9MmMjomVIPfU4XA,177
         | 
| 68 68 | 
             
            airbyte_cdk/sources/declarative/datetime/datetime_parser.py,sha256=SX9JjdesN1edN2WVUVMzU_ptqp2QB1OnsnjZ4mwcX7w,2579
         | 
| 69 69 | 
             
            airbyte_cdk/sources/declarative/datetime/min_max_datetime.py,sha256=0BHBtDNQZfvwM45-tY5pNlTcKAFSGGNxemoi0Jic-0E,5785
         | 
| 70 | 
            -
            airbyte_cdk/sources/declarative/declarative_component_schema.yaml,sha256= | 
| 70 | 
            +
            airbyte_cdk/sources/declarative/declarative_component_schema.yaml,sha256=51R-WLE1Xhrk57DoiHFxWZSP8V9HtCEi1UE8_KtEOuM,140375
         | 
| 71 71 | 
             
            airbyte_cdk/sources/declarative/declarative_source.py,sha256=nF7wBqFd3AQmEKAm4CnIo29CJoQL562cJGSCeL8U8bA,1531
         | 
| 72 72 | 
             
            airbyte_cdk/sources/declarative/declarative_stream.py,sha256=venZjfpvtqr3oFSuvMBWtn4h9ayLhD4L65ACuXCDZ64,10445
         | 
| 73 73 | 
             
            airbyte_cdk/sources/declarative/decoders/__init__.py,sha256=KSpQetKGqPCv-38QgcVJ5kzM5nzbFldTSsYDCS3Xf0Y,1035
         | 
| @@ -104,18 +104,18 @@ airbyte_cdk/sources/declarative/interpolation/interpolated_string.py,sha256=LYEZ | |
| 104 104 | 
             
            airbyte_cdk/sources/declarative/interpolation/interpolation.py,sha256=-V5UddGm69UKEB6o_O1EIES9kfY8FV_X4Ji8w1yOuSA,981
         | 
| 105 105 | 
             
            airbyte_cdk/sources/declarative/interpolation/jinja.py,sha256=BtsY_jtT4MihFqeQgc05HXj3Ndt-e2ESQgGwbg3Sdxc,6430
         | 
| 106 106 | 
             
            airbyte_cdk/sources/declarative/interpolation/macros.py,sha256=Y5AWYxbJTUtJ_Jm7DV9qrZDiymFR9LST7fBt4piT2-U,4585
         | 
| 107 | 
            -
            airbyte_cdk/sources/declarative/manifest_declarative_source.py,sha256= | 
| 107 | 
            +
            airbyte_cdk/sources/declarative/manifest_declarative_source.py,sha256=26qMXRugdPAd3zyYRH6YpNi--TorGZVOtxzY5O6muL0,16912
         | 
| 108 108 | 
             
            airbyte_cdk/sources/declarative/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         | 
| 109 109 | 
             
            airbyte_cdk/sources/declarative/migrations/legacy_to_per_partition_state_migration.py,sha256=iemy3fKLczcU0-Aor7tx5jcT6DRedKMqyK7kCOp01hg,3924
         | 
| 110 110 | 
             
            airbyte_cdk/sources/declarative/migrations/state_migration.py,sha256=KWPjealMLKSMtajXgkdGgKg7EmTLR-CqqD7UIh0-eDU,794
         | 
| 111 111 | 
             
            airbyte_cdk/sources/declarative/models/__init__.py,sha256=nUFxNCiKeYRVXuZEKA7GD-lTHxsiKcQ8FitZjKhPIvE,100
         | 
| 112 | 
            -
            airbyte_cdk/sources/declarative/models/declarative_component_schema.py,sha256= | 
| 112 | 
            +
            airbyte_cdk/sources/declarative/models/declarative_component_schema.py,sha256=7qzq5ZV3V90uYRMa_-CGTbJ7aVv5jyPqGGjpJb9zdHk,98706
         | 
| 113 113 | 
             
            airbyte_cdk/sources/declarative/parsers/__init__.py,sha256=ZnqYNxHsKCgO38IwB34RQyRMXTs4GTvlRi3ImKnIioo,61
         | 
| 114 114 | 
             
            airbyte_cdk/sources/declarative/parsers/custom_code_compiler.py,sha256=958MMX6_ZOJUlDDdNr9Krosgi2bCKGx2Z765M2Woz18,5505
         | 
| 115 115 | 
             
            airbyte_cdk/sources/declarative/parsers/custom_exceptions.py,sha256=Rir9_z3Kcd5Es0-LChrzk-0qubAsiK_RSEnLmK2OXm8,553
         | 
| 116 116 | 
             
            airbyte_cdk/sources/declarative/parsers/manifest_component_transformer.py,sha256=CXwTfD3wSQq3okcqwigpprbHhSURUokh4GK2OmOyKC8,9132
         | 
| 117 117 | 
             
            airbyte_cdk/sources/declarative/parsers/manifest_reference_resolver.py,sha256=IWUOdF03o-aQn0Occo1BJCxU0Pz-QILk5L67nzw2thw,6803
         | 
| 118 | 
            -
            airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py,sha256= | 
| 118 | 
            +
            airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py,sha256=MuzhEy8ST0-VijWck1VEeO7NTFRW4BpJ9LafFHxOTwo,129444
         | 
| 119 119 | 
             
            airbyte_cdk/sources/declarative/partition_routers/__init__.py,sha256=HJ-Syp3p7RpyR_OK0X_a2kSyISfu3W-PKrRI16iY0a8,957
         | 
| 120 120 | 
             
            airbyte_cdk/sources/declarative/partition_routers/async_job_partition_router.py,sha256=VelO7zKqKtzMJ35jyFeg0ypJLQC0plqqIBNXoBW1G2E,3001
         | 
| 121 121 | 
             
            airbyte_cdk/sources/declarative/partition_routers/cartesian_product_stream_slicer.py,sha256=c5cuVFM6NFkuQqG8Z5IwkBuwDrvXZN1CunUOM_L0ezg,6892
         | 
| @@ -139,7 +139,7 @@ airbyte_cdk/sources/declarative/requesters/error_handlers/default_http_response_ | |
| 139 139 | 
             
            airbyte_cdk/sources/declarative/requesters/error_handlers/error_handler.py,sha256=Tan66odx8VHzfdyyXMQkXz2pJYksllGqvxmpoajgcK4,669
         | 
| 140 140 | 
             
            airbyte_cdk/sources/declarative/requesters/error_handlers/http_response_filter.py,sha256=E-fQbt4ShfxZVoqfnmOx69C6FUPWZz8BIqI3DN9Kcjs,7935
         | 
| 141 141 | 
             
            airbyte_cdk/sources/declarative/requesters/http_job_repository.py,sha256=3GtOefPH08evlSUxaILkiKLTHbIspFY4qd5B3ZqNE60,10063
         | 
| 142 | 
            -
            airbyte_cdk/sources/declarative/requesters/http_requester.py,sha256= | 
| 142 | 
            +
            airbyte_cdk/sources/declarative/requesters/http_requester.py,sha256=C6YT7t4UZMfarFeQ9fc362R5TbQ2jNSew8ESP-9yuZQ,14851
         | 
| 143 143 | 
             
            airbyte_cdk/sources/declarative/requesters/paginators/__init__.py,sha256=uArbKs9JKNCt7t9tZoeWwjDpyI1HoPp29FNW0JzvaEM,644
         | 
| 144 144 | 
             
            airbyte_cdk/sources/declarative/requesters/paginators/default_paginator.py,sha256=dSm_pKGOZjzvg-X_Vif-MjrnlUG23fCa69bocq8dVIs,11693
         | 
| 145 145 | 
             
            airbyte_cdk/sources/declarative/requesters/paginators/no_pagination.py,sha256=j6j9QRPaTbKQ2N661RFVKthhkWiodEp6ut0tKeEd0Ng,2019
         | 
| @@ -249,7 +249,7 @@ airbyte_cdk/sources/message/repository.py,sha256=SG7avgti_-dj8FcRHTTrhgLLGJbElv1 | |
| 249 249 | 
             
            airbyte_cdk/sources/source.py,sha256=KIBBH5VLEb8BZ8B9aROlfaI6OLoJqKDPMJ10jkAR7nk,3611
         | 
| 250 250 | 
             
            airbyte_cdk/sources/streams/__init__.py,sha256=8fzTKpRTnSx5PggXgQPKJzHNZUV2BCA40N-dI6JM1xI,256
         | 
| 251 251 | 
             
            airbyte_cdk/sources/streams/availability_strategy.py,sha256=_RU4JITrxMEN36g1RDHMu0iSw0I_3yWGfo5N8_YRvOg,3247
         | 
| 252 | 
            -
            airbyte_cdk/sources/streams/call_rate.py,sha256= | 
| 252 | 
            +
            airbyte_cdk/sources/streams/call_rate.py,sha256=Um_Ny8R7WZ2B0PWoxr-wrWPsgc5we7HrHalaMcozuVs,21052
         | 
| 253 253 | 
             
            airbyte_cdk/sources/streams/checkpoint/__init__.py,sha256=3oy7Hd4ivVWTZlN6dKAf4Fv_G7U5iZrvhO9hT871UIo,712
         | 
| 254 254 | 
             
            airbyte_cdk/sources/streams/checkpoint/checkpoint_reader.py,sha256=6HMT2NI-FQuaW0nt95NcyWrt5rZN4gF-Arx0sxdgbv4,15221
         | 
| 255 255 | 
             
            airbyte_cdk/sources/streams/checkpoint/cursor.py,sha256=3e-3c-54k8U7Awno7DMmAD9ndbnl9OM48EnbEgeDUO0,3499
         | 
| @@ -295,7 +295,7 @@ airbyte_cdk/sources/streams/http/http.py,sha256=0uariNq8OFnlX7iqOHwBhecxA-Hfd5hS | |
| 295 295 | 
             
            airbyte_cdk/sources/streams/http/http_client.py,sha256=tDE0ROtxjGMVphvsw8INvGMtZ97hIF-v47pZ3jIyiwc,23011
         | 
| 296 296 | 
             
            airbyte_cdk/sources/streams/http/rate_limiting.py,sha256=IwdjrHKUnU97XO4qONgYRv4YYW51xQ8SJm4WLafXDB8,6351
         | 
| 297 297 | 
             
            airbyte_cdk/sources/streams/http/requests_native_auth/__init__.py,sha256=RN0D3nOX1xLgwEwKWu6pkGy3XqBFzKSNZ8Lf6umU2eY,413
         | 
| 298 | 
            -
            airbyte_cdk/sources/streams/http/requests_native_auth/abstract_oauth.py,sha256= | 
| 298 | 
            +
            airbyte_cdk/sources/streams/http/requests_native_auth/abstract_oauth.py,sha256=cM5CM1mnbTEMiY6gKHblGXr9KTS5VEziGoc-TXC302k,18791
         | 
| 299 299 | 
             
            airbyte_cdk/sources/streams/http/requests_native_auth/abstract_token.py,sha256=Y3n7J-sk5yGjv_OxtY6Z6k0PEsFZmtIRi-x0KCbaHdA,1010
         | 
| 300 300 | 
             
            airbyte_cdk/sources/streams/http/requests_native_auth/oauth.py,sha256=C2j2uVfi9d-3KgHO3NGxIiFdfASjHOtsd6g_LWPYOAs,20311
         | 
| 301 301 | 
             
            airbyte_cdk/sources/streams/http/requests_native_auth/token.py,sha256=h5PTzcdH-RQLeCg7xZ45w_484OPUDSwNWl_iMJQmZoI,2526
         | 
| @@ -351,9 +351,9 @@ airbyte_cdk/utils/slice_hasher.py,sha256=EDxgROHDbfG-QKQb59m7h_7crN1tRiawdf5uU7G | |
| 351 351 | 
             
            airbyte_cdk/utils/spec_schema_transformations.py,sha256=-5HTuNsnDBAhj-oLeQXwpTGA0HdcjFOf2zTEMUTTg_Y,816
         | 
| 352 352 | 
             
            airbyte_cdk/utils/stream_status_utils.py,sha256=ZmBoiy5HVbUEHAMrUONxZvxnvfV9CesmQJLDTAIWnWw,1171
         | 
| 353 353 | 
             
            airbyte_cdk/utils/traced_exception.py,sha256=C8uIBuCL_E4WnBAOPSxBicD06JAldoN9fGsQDp463OY,6292
         | 
| 354 | 
            -
            airbyte_cdk-6.33. | 
| 355 | 
            -
            airbyte_cdk-6.33. | 
| 356 | 
            -
            airbyte_cdk-6.33. | 
| 357 | 
            -
            airbyte_cdk-6.33. | 
| 358 | 
            -
            airbyte_cdk-6.33. | 
| 359 | 
            -
            airbyte_cdk-6.33. | 
| 354 | 
            +
            airbyte_cdk-6.33.2.dist-info/LICENSE.txt,sha256=Wfe61S4BaGPj404v8lrAbvhjYR68SHlkzeYrg3_bbuM,1051
         | 
| 355 | 
            +
            airbyte_cdk-6.33.2.dist-info/LICENSE_SHORT,sha256=aqF6D1NcESmpn-cqsxBtszTEnHKnlsp8L4x9wAh3Nxg,55
         | 
| 356 | 
            +
            airbyte_cdk-6.33.2.dist-info/METADATA,sha256=8_7_yrHWUow7tK9vqk_hqRiXhf9geY_kN_N1cU1XpLY,6010
         | 
| 357 | 
            +
            airbyte_cdk-6.33.2.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
         | 
| 358 | 
            +
            airbyte_cdk-6.33.2.dist-info/entry_points.txt,sha256=fj-e3PAQvsxsQzyyq8UkG1k8spunWnD4BAH2AwlR6NM,95
         | 
| 359 | 
            +
            airbyte_cdk-6.33.2.dist-info/RECORD,,
         | 
| 
            File without changes
         | 
| 
            File without changes
         | 
| 
            File without changes
         | 
| 
            File without changes
         |