airbyte-agent-zendesk-support 0.18.47__py3-none-any.whl → 0.18.57__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.
- airbyte_agent_zendesk_support/__init__.py +130 -2
- airbyte_agent_zendesk_support/_vendored/connector_sdk/auth_strategies.py +55 -4
- airbyte_agent_zendesk_support/_vendored/connector_sdk/connector_model_loader.py +29 -8
- airbyte_agent_zendesk_support/_vendored/connector_sdk/executor/local_executor.py +152 -22
- airbyte_agent_zendesk_support/_vendored/connector_sdk/http_client.py +13 -6
- airbyte_agent_zendesk_support/_vendored/connector_sdk/logging/logger.py +10 -1
- airbyte_agent_zendesk_support/_vendored/connector_sdk/logging/types.py +1 -0
- airbyte_agent_zendesk_support/_vendored/connector_sdk/schema/base.py +7 -2
- airbyte_agent_zendesk_support/_vendored/connector_sdk/schema/security.py +14 -0
- airbyte_agent_zendesk_support/_vendored/connector_sdk/types.py +9 -0
- airbyte_agent_zendesk_support/_vendored/connector_sdk/validation.py +12 -6
- airbyte_agent_zendesk_support/connector.py +920 -1
- airbyte_agent_zendesk_support/connector_model.py +1 -1
- airbyte_agent_zendesk_support/models.py +606 -0
- airbyte_agent_zendesk_support/types.py +3715 -0
- {airbyte_agent_zendesk_support-0.18.47.dist-info → airbyte_agent_zendesk_support-0.18.57.dist-info}/METADATA +35 -22
- {airbyte_agent_zendesk_support-0.18.47.dist-info → airbyte_agent_zendesk_support-0.18.57.dist-info}/RECORD +18 -18
- {airbyte_agent_zendesk_support-0.18.47.dist-info → airbyte_agent_zendesk_support-0.18.57.dist-info}/WHEEL +0 -0
|
@@ -421,10 +421,14 @@ class HTTPClient:
|
|
|
421
421
|
headers: dict[str, str] | None = None,
|
|
422
422
|
*,
|
|
423
423
|
stream: bool = False,
|
|
424
|
-
):
|
|
424
|
+
) -> tuple[dict[str, Any], dict[str, str]]:
|
|
425
425
|
"""Execute a single HTTP request attempt (no retries).
|
|
426
426
|
|
|
427
427
|
This is the core request logic, separated from retry handling.
|
|
428
|
+
|
|
429
|
+
Returns:
|
|
430
|
+
Tuple of (response_data, response_headers) for non-streaming requests.
|
|
431
|
+
For streaming requests, returns (response_object, response_headers).
|
|
428
432
|
"""
|
|
429
433
|
# Ensure auth credentials are initialized (proactive refresh if needed)
|
|
430
434
|
await self._ensure_auth_initialized()
|
|
@@ -474,8 +478,9 @@ class HTTPClient:
|
|
|
474
478
|
request_id=request_id,
|
|
475
479
|
status_code=status_code,
|
|
476
480
|
response_body=f"<binary content, {response.headers.get('content-length', 'unknown')} bytes>",
|
|
481
|
+
response_headers=dict(response.headers),
|
|
477
482
|
)
|
|
478
|
-
return response
|
|
483
|
+
return response, dict(response.headers)
|
|
479
484
|
|
|
480
485
|
# Parse response - handle non-JSON responses gracefully
|
|
481
486
|
content_type = response.headers.get("content-type", "")
|
|
@@ -500,8 +505,9 @@ class HTTPClient:
|
|
|
500
505
|
request_id=request_id,
|
|
501
506
|
status_code=status_code,
|
|
502
507
|
response_body=response_data,
|
|
508
|
+
response_headers=dict(response.headers),
|
|
503
509
|
)
|
|
504
|
-
return response_data
|
|
510
|
+
return response_data, dict(response.headers)
|
|
505
511
|
|
|
506
512
|
except AuthenticationError as e:
|
|
507
513
|
# Auth error (401, 403) - handle token refresh
|
|
@@ -631,7 +637,7 @@ class HTTPClient:
|
|
|
631
637
|
*,
|
|
632
638
|
stream: bool = False,
|
|
633
639
|
_auth_retry_attempted: bool = False,
|
|
634
|
-
):
|
|
640
|
+
) -> tuple[dict[str, Any], dict[str, str]]:
|
|
635
641
|
"""Make an async HTTP request with optional streaming and automatic retries.
|
|
636
642
|
|
|
637
643
|
Args:
|
|
@@ -644,8 +650,9 @@ class HTTPClient:
|
|
|
644
650
|
stream: If True, do not eagerly read the body (useful for downloads)
|
|
645
651
|
|
|
646
652
|
Returns:
|
|
647
|
-
|
|
648
|
-
- If stream=
|
|
653
|
+
Tuple of (response_data, response_headers):
|
|
654
|
+
- If stream=False: (parsed JSON dict or empty dict, response headers dict)
|
|
655
|
+
- If stream=True: (response object suitable for streaming, response headers dict)
|
|
649
656
|
|
|
650
657
|
Raises:
|
|
651
658
|
HTTPStatusError: If request fails with 4xx/5xx status after all retries
|
|
@@ -134,6 +134,7 @@ class RequestLogger:
|
|
|
134
134
|
request_id: str,
|
|
135
135
|
status_code: int,
|
|
136
136
|
response_body: Any | None = None,
|
|
137
|
+
response_headers: Dict[str, str] | None = None,
|
|
137
138
|
) -> None:
|
|
138
139
|
"""
|
|
139
140
|
Log a successful HTTP response.
|
|
@@ -142,6 +143,7 @@ class RequestLogger:
|
|
|
142
143
|
request_id: ID returned from log_request
|
|
143
144
|
status_code: HTTP status code
|
|
144
145
|
response_body: Response body
|
|
146
|
+
response_headers: Response headers
|
|
145
147
|
"""
|
|
146
148
|
if request_id not in self._active_requests:
|
|
147
149
|
return
|
|
@@ -166,6 +168,7 @@ class RequestLogger:
|
|
|
166
168
|
body=request_data["body"],
|
|
167
169
|
response_status=status_code,
|
|
168
170
|
response_body=serializable_body,
|
|
171
|
+
response_headers=response_headers or {},
|
|
169
172
|
timing_ms=timing_ms,
|
|
170
173
|
)
|
|
171
174
|
|
|
@@ -243,7 +246,13 @@ class NullLogger:
|
|
|
243
246
|
"""No-op log_request."""
|
|
244
247
|
return ""
|
|
245
248
|
|
|
246
|
-
def log_response(
|
|
249
|
+
def log_response(
|
|
250
|
+
self,
|
|
251
|
+
request_id: str,
|
|
252
|
+
status_code: int,
|
|
253
|
+
response_body: Any | None = None,
|
|
254
|
+
response_headers: Dict[str, str] | None = None,
|
|
255
|
+
) -> None:
|
|
247
256
|
"""No-op log_response."""
|
|
248
257
|
pass
|
|
249
258
|
|
|
@@ -7,7 +7,7 @@ References:
|
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
9
|
from enum import StrEnum
|
|
10
|
-
from typing import Dict
|
|
10
|
+
from typing import Any, Dict
|
|
11
11
|
from uuid import UUID
|
|
12
12
|
|
|
13
13
|
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
@@ -152,7 +152,12 @@ class Server(BaseModel):
|
|
|
152
152
|
url: str
|
|
153
153
|
description: str | None = None
|
|
154
154
|
variables: Dict[str, ServerVariable] = Field(default_factory=dict)
|
|
155
|
-
|
|
155
|
+
x_airbyte_replication_environment_mapping: Dict[str, str] | None = Field(default=None, alias="x-airbyte-replication-environment-mapping")
|
|
156
|
+
x_airbyte_replication_environment_constants: Dict[str, Any] | None = Field(
|
|
157
|
+
default=None,
|
|
158
|
+
alias="x-airbyte-replication-environment-constants",
|
|
159
|
+
description="Constant values to always inject at environment config paths (e.g., 'region': 'us-east-1')",
|
|
160
|
+
)
|
|
156
161
|
|
|
157
162
|
@field_validator("url")
|
|
158
163
|
@classmethod
|
|
@@ -109,6 +109,20 @@ class AirbyteAuthConfig(BaseModel):
|
|
|
109
109
|
description="Mapping from source config paths (e.g., 'credentials.api_key') to auth config keys for direct connectors",
|
|
110
110
|
)
|
|
111
111
|
|
|
112
|
+
# Additional headers to inject alongside OAuth2 Bearer token
|
|
113
|
+
additional_headers: Dict[str, str] | None = Field(
|
|
114
|
+
None,
|
|
115
|
+
description=(
|
|
116
|
+
"Extra headers to inject with auth. Values support Jinja2 {{ variable }} template syntax "
|
|
117
|
+
"to reference secrets. Example: {'Amazon-Advertising-API-ClientId': '{{ client_id }}'}"
|
|
118
|
+
),
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
# Replication connector auth constants
|
|
122
|
+
replication_auth_key_constants: Dict[str, Any] | None = Field(
|
|
123
|
+
None,
|
|
124
|
+
description="Constant values to always inject at source config paths (e.g., 'credentials.auth_type': 'OAuth2.0')",
|
|
125
|
+
)
|
|
112
126
|
# Multiple options (oneOf)
|
|
113
127
|
one_of: List[AuthConfigOption] | None = Field(None, alias="oneOf")
|
|
114
128
|
|
|
@@ -180,6 +180,15 @@ class EndpointDefinition(BaseModel):
|
|
|
180
180
|
default_factory=dict,
|
|
181
181
|
description="Schema for path params including defaults: {name: {type, default, required}}",
|
|
182
182
|
)
|
|
183
|
+
header_params: list[str] = Field(default_factory=list) # Header parameters from OpenAPI
|
|
184
|
+
header_params_schema: dict[str, dict[str, Any]] = Field(
|
|
185
|
+
default_factory=dict,
|
|
186
|
+
description="Schema for header params including defaults: {name: {type, default, required}}",
|
|
187
|
+
)
|
|
188
|
+
request_body_defaults: dict[str, Any] = Field(
|
|
189
|
+
default_factory=dict,
|
|
190
|
+
description="Default values for request body fields from OpenAPI schema",
|
|
191
|
+
)
|
|
183
192
|
content_type: ContentType = ContentType.JSON
|
|
184
193
|
request_schema: dict[str, Any] | None = None
|
|
185
194
|
response_schema: dict[str, Any] | None = None
|
|
@@ -486,30 +486,36 @@ def validate_meta_extractor_fields(
|
|
|
486
486
|
response_body = spec.captured_response.body
|
|
487
487
|
|
|
488
488
|
# Validate each meta extractor field
|
|
489
|
-
for field_name,
|
|
489
|
+
for field_name, extractor_expr in endpoint.meta_extractor.items():
|
|
490
|
+
# Skip header-based extractors - they extract from headers, not response body
|
|
491
|
+
# @link.next extracts from RFC 5988 Link header
|
|
492
|
+
# @header.X-Name extracts raw header value
|
|
493
|
+
if extractor_expr.startswith("@link.") or extractor_expr.startswith("@header."):
|
|
494
|
+
continue
|
|
495
|
+
|
|
490
496
|
# Check 1: Does the JSONPath find data in the actual response?
|
|
491
497
|
try:
|
|
492
|
-
parsed_expr = parse_jsonpath(
|
|
498
|
+
parsed_expr = parse_jsonpath(extractor_expr)
|
|
493
499
|
matches = [match.value for match in parsed_expr.find(response_body)]
|
|
494
500
|
|
|
495
501
|
if not matches:
|
|
496
502
|
warnings.append(
|
|
497
503
|
f"{entity_name}.{action}: x-airbyte-meta-extractor field '{field_name}' "
|
|
498
|
-
f"with JSONPath '{
|
|
504
|
+
f"with JSONPath '{extractor_expr}' found no matches in cassette response"
|
|
499
505
|
)
|
|
500
506
|
except Exception as e:
|
|
501
507
|
warnings.append(
|
|
502
|
-
f"{entity_name}.{action}: x-airbyte-meta-extractor field '{field_name}' has invalid JSONPath '{
|
|
508
|
+
f"{entity_name}.{action}: x-airbyte-meta-extractor field '{field_name}' has invalid JSONPath '{extractor_expr}': {str(e)}"
|
|
503
509
|
)
|
|
504
510
|
|
|
505
511
|
# Check 2: Is this field path declared in the response schema?
|
|
506
512
|
if endpoint.response_schema:
|
|
507
|
-
field_in_schema = _check_field_in_schema(
|
|
513
|
+
field_in_schema = _check_field_in_schema(extractor_expr, endpoint.response_schema)
|
|
508
514
|
|
|
509
515
|
if not field_in_schema:
|
|
510
516
|
warnings.append(
|
|
511
517
|
f"{entity_name}.{action}: x-airbyte-meta-extractor field '{field_name}' "
|
|
512
|
-
f"extracts from '{
|
|
518
|
+
f"extracts from '{extractor_expr}' but this path is not declared in response schema"
|
|
513
519
|
)
|
|
514
520
|
|
|
515
521
|
except Exception as e:
|