airbyte-agent-zendesk-support 0.18.18__py3-none-any.whl → 0.18.21__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/_vendored/connector_sdk/cloud_utils/__init__.py +5 -0
- airbyte_agent_zendesk_support/_vendored/connector_sdk/cloud_utils/client.py +213 -0
- airbyte_agent_zendesk_support/_vendored/connector_sdk/connector_model_loader.py +21 -2
- airbyte_agent_zendesk_support/_vendored/connector_sdk/executor/hosted_executor.py +93 -84
- airbyte_agent_zendesk_support/_vendored/connector_sdk/http_client.py +50 -43
- airbyte_agent_zendesk_support/_vendored/connector_sdk/schema/base.py +2 -1
- airbyte_agent_zendesk_support/_vendored/connector_sdk/types.py +2 -0
- airbyte_agent_zendesk_support/connector.py +9 -11
- airbyte_agent_zendesk_support/connector_model.py +4 -0
- {airbyte_agent_zendesk_support-0.18.18.dist-info → airbyte_agent_zendesk_support-0.18.21.dist-info}/METADATA +14 -14
- {airbyte_agent_zendesk_support-0.18.18.dist-info → airbyte_agent_zendesk_support-0.18.21.dist-info}/RECORD +12 -10
- {airbyte_agent_zendesk_support-0.18.18.dist-info → airbyte_agent_zendesk_support-0.18.21.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"""AirbyteCloudClient for Airbyte Platform API integration."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from datetime import datetime, timedelta
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
import httpx
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class AirbyteCloudClient:
|
|
12
|
+
"""Client for interacting with Airbyte Platform APIs.
|
|
13
|
+
|
|
14
|
+
Handles authentication, token caching, and API calls to:
|
|
15
|
+
- Get bearer tokens for authentication
|
|
16
|
+
- Look up connector instances for users
|
|
17
|
+
- Execute connectors via the cloud API
|
|
18
|
+
|
|
19
|
+
Example:
|
|
20
|
+
client = AirbyteCloudClient(
|
|
21
|
+
client_id="your-client-id",
|
|
22
|
+
client_secret="your-client-secret"
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
# Get a connector instance
|
|
26
|
+
instance_id = await client.get_connector_instance_id(
|
|
27
|
+
external_user_id="user-123",
|
|
28
|
+
connector_definition_id="stripe-def-456"
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# Execute the connector
|
|
32
|
+
result = await client.execute_connector(
|
|
33
|
+
instance_id=instance_id,
|
|
34
|
+
entity="customers",
|
|
35
|
+
action="list",
|
|
36
|
+
params={"limit": 10}
|
|
37
|
+
)
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
AUTH_BASE_URL = "https://cloud.airbyte.com" # For token endpoint
|
|
41
|
+
API_BASE_URL = "https://api.airbyte.ai" # For instance lookup & execution
|
|
42
|
+
|
|
43
|
+
def __init__(self, client_id: str, client_secret: str):
|
|
44
|
+
"""Initialize AirbyteCloudClient.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
client_id: Airbyte client ID for authentication
|
|
48
|
+
client_secret: Airbyte client secret for authentication
|
|
49
|
+
"""
|
|
50
|
+
self._client_id = client_id
|
|
51
|
+
self._client_secret = client_secret
|
|
52
|
+
|
|
53
|
+
# Token cache (instance-level)
|
|
54
|
+
self._cached_token: str | None = None
|
|
55
|
+
self._token_expires_at: datetime | None = None
|
|
56
|
+
self._http_client = httpx.AsyncClient(
|
|
57
|
+
timeout=httpx.Timeout(300.0), # 5 minute timeout
|
|
58
|
+
follow_redirects=True,
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
async def get_bearer_token(self) -> str:
|
|
62
|
+
"""Get bearer token for API authentication.
|
|
63
|
+
|
|
64
|
+
Caches the token and only requests a new one when the cached token
|
|
65
|
+
is expired or missing. Adds a 60-second buffer before expiration
|
|
66
|
+
to avoid edge cases.
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
Bearer token string
|
|
70
|
+
|
|
71
|
+
Raises:
|
|
72
|
+
httpx.HTTPStatusError: If the token request fails with 4xx/5xx
|
|
73
|
+
httpx.RequestError: If the network request fails
|
|
74
|
+
|
|
75
|
+
Example:
|
|
76
|
+
token = await client.get_bearer_token()
|
|
77
|
+
# Use token in Authorization header: f"Bearer {token}"
|
|
78
|
+
"""
|
|
79
|
+
# Check if we have a cached token that hasn't expired
|
|
80
|
+
if self._cached_token and self._token_expires_at:
|
|
81
|
+
# Add 60 second buffer before expiration to avoid edge cases
|
|
82
|
+
now = datetime.now()
|
|
83
|
+
if now < self._token_expires_at:
|
|
84
|
+
# Token is still valid, return cached version
|
|
85
|
+
return self._cached_token
|
|
86
|
+
|
|
87
|
+
# Token is missing or expired, fetch a new one
|
|
88
|
+
url = f"{self.AUTH_BASE_URL}/api/v1/applications/token"
|
|
89
|
+
request_body = {
|
|
90
|
+
"client_id": self._client_id,
|
|
91
|
+
"client_secret": self._client_secret,
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
response = await self._http_client.post(url, json=request_body)
|
|
95
|
+
response.raise_for_status()
|
|
96
|
+
|
|
97
|
+
data = response.json()
|
|
98
|
+
access_token = data["access_token"]
|
|
99
|
+
expires_in = 15 * 60 # default 15 min expiry time * 60 seconds
|
|
100
|
+
|
|
101
|
+
# Calculate expiration time with 60 second buffer
|
|
102
|
+
expires_at = datetime.now() + timedelta(seconds=expires_in - 60)
|
|
103
|
+
self._cached_token = access_token
|
|
104
|
+
self._token_expires_at = expires_at
|
|
105
|
+
|
|
106
|
+
return access_token
|
|
107
|
+
|
|
108
|
+
async def get_connector_instance_id(
|
|
109
|
+
self,
|
|
110
|
+
external_user_id: str,
|
|
111
|
+
connector_definition_id: str,
|
|
112
|
+
) -> str:
|
|
113
|
+
"""Get connector instance ID for a user.
|
|
114
|
+
|
|
115
|
+
Looks up the connector instance that belongs to the specified user
|
|
116
|
+
and connector definition. Validates that exactly one instance exists.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
external_user_id: User identifier in the Airbyte system
|
|
120
|
+
connector_definition_id: UUID of the connector definition
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
Connector instance ID (UUID string)
|
|
124
|
+
|
|
125
|
+
Raises:
|
|
126
|
+
ValueError: If 0 or more than 1 instance is found
|
|
127
|
+
httpx.HTTPStatusError: If API returns 4xx/5xx status code
|
|
128
|
+
httpx.RequestError: If network request fails
|
|
129
|
+
|
|
130
|
+
Example:
|
|
131
|
+
instance_id = await client.get_connector_instance_id(
|
|
132
|
+
external_user_id="user-123",
|
|
133
|
+
connector_definition_id="550e8400-e29b-41d4-a716-446655440000"
|
|
134
|
+
)
|
|
135
|
+
"""
|
|
136
|
+
|
|
137
|
+
token = await self.get_bearer_token()
|
|
138
|
+
url = f"{self.API_BASE_URL}/api/v1/connectors/instances_for_user"
|
|
139
|
+
params = {
|
|
140
|
+
"external_user_id": external_user_id,
|
|
141
|
+
"definition_id": connector_definition_id,
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
headers = {"Authorization": f"Bearer {token}"}
|
|
145
|
+
response = await self._http_client.get(url, params=params, headers=headers)
|
|
146
|
+
response.raise_for_status()
|
|
147
|
+
|
|
148
|
+
data = response.json()
|
|
149
|
+
instances = data["instances"]
|
|
150
|
+
|
|
151
|
+
if len(instances) == 0:
|
|
152
|
+
raise ValueError(f"No connector instance found for user '{external_user_id}' " f"and connector '{connector_definition_id}'")
|
|
153
|
+
|
|
154
|
+
if len(instances) > 1:
|
|
155
|
+
raise ValueError(
|
|
156
|
+
f"Multiple connector instances found for user '{external_user_id}' "
|
|
157
|
+
f"and connector '{connector_definition_id}'. Expected exactly 1, "
|
|
158
|
+
f"found {len(instances)}"
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
instance_id = instances[0]["id"]
|
|
162
|
+
return instance_id
|
|
163
|
+
|
|
164
|
+
async def execute_connector(
|
|
165
|
+
self,
|
|
166
|
+
instance_id: str,
|
|
167
|
+
entity: str,
|
|
168
|
+
action: str,
|
|
169
|
+
params: dict[str, Any] | None,
|
|
170
|
+
) -> dict[str, Any]:
|
|
171
|
+
"""Execute a connector operation.
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
instance_id: Connector instance UUID
|
|
175
|
+
entity: Entity name (e.g., "customers", "invoices")
|
|
176
|
+
action: Operation action (e.g., "list", "get", "create")
|
|
177
|
+
params: Optional parameters for the operation
|
|
178
|
+
|
|
179
|
+
Returns:
|
|
180
|
+
Raw JSON response dict from the API
|
|
181
|
+
|
|
182
|
+
Raises:
|
|
183
|
+
httpx.HTTPStatusError: If API returns 4xx/5xx status code
|
|
184
|
+
httpx.RequestError: If network request fails
|
|
185
|
+
|
|
186
|
+
Example:
|
|
187
|
+
result = await client.execute_connector(
|
|
188
|
+
instance_id="inst-123",
|
|
189
|
+
entity="customers",
|
|
190
|
+
action="list",
|
|
191
|
+
params={"limit": 10}
|
|
192
|
+
)
|
|
193
|
+
"""
|
|
194
|
+
token = await self.get_bearer_token()
|
|
195
|
+
url = f"{self.API_BASE_URL}/api/v1/connectors/instances/{instance_id}/execute"
|
|
196
|
+
headers = {"Authorization": f"Bearer {token}"}
|
|
197
|
+
request_body = {
|
|
198
|
+
"entity": entity,
|
|
199
|
+
"action": action,
|
|
200
|
+
"params": params,
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
response = await self._http_client.post(url, json=request_body, headers=headers)
|
|
204
|
+
response.raise_for_status()
|
|
205
|
+
|
|
206
|
+
return response.json()
|
|
207
|
+
|
|
208
|
+
async def close(self):
|
|
209
|
+
"""Close the HTTP client.
|
|
210
|
+
|
|
211
|
+
Call this when you're done using the client to clean up resources.
|
|
212
|
+
"""
|
|
213
|
+
await self._http_client.aclose()
|
|
@@ -5,6 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
import re
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
from typing import Any
|
|
8
|
+
from uuid import UUID
|
|
8
9
|
|
|
9
10
|
import jsonref
|
|
10
11
|
import yaml
|
|
@@ -105,7 +106,7 @@ def resolve_schema_refs(schema: Any, spec_dict: dict) -> dict[str, Any]:
|
|
|
105
106
|
|
|
106
107
|
try:
|
|
107
108
|
# Resolve all references
|
|
108
|
-
resolved_spec = jsonref.replace_refs(
|
|
109
|
+
resolved_spec = jsonref.replace_refs( # type: ignore[union-attr]
|
|
109
110
|
temp_spec,
|
|
110
111
|
base_uri="",
|
|
111
112
|
jsonschema=True, # Use JSONSchema draft 7 semantics
|
|
@@ -117,9 +118,11 @@ def resolve_schema_refs(schema: Any, spec_dict: dict) -> dict[str, Any]:
|
|
|
117
118
|
|
|
118
119
|
# Remove any remaining jsonref proxy objects by converting to plain dict
|
|
119
120
|
return _deproxy_schema(resolved_schema)
|
|
120
|
-
except (
|
|
121
|
+
except (AttributeError, KeyError, RecursionError, Exception):
|
|
121
122
|
# If resolution fails, return the original schema
|
|
122
123
|
# This allows the system to continue even with malformed $refs
|
|
124
|
+
# AttributeError covers the case where jsonref might be None
|
|
125
|
+
# Exception catches jsonref.JsonRefError and other jsonref exceptions
|
|
123
126
|
return schema_dict
|
|
124
127
|
|
|
125
128
|
|
|
@@ -404,9 +407,13 @@ def convert_openapi_to_connector_model(spec: OpenAPIConnector) -> ConnectorModel
|
|
|
404
407
|
|
|
405
408
|
# Extract retry config from x-airbyte-retry-config extension
|
|
406
409
|
retry_config = spec.info.x_airbyte_retry_config
|
|
410
|
+
connector_id = spec.info.x_airbyte_connector_id
|
|
411
|
+
if not connector_id:
|
|
412
|
+
raise InvalidOpenAPIError("Missing required x-airbyte-connector-id field")
|
|
407
413
|
|
|
408
414
|
# Create ConnectorModel
|
|
409
415
|
model = ConnectorModel(
|
|
416
|
+
id=connector_id,
|
|
410
417
|
name=name,
|
|
411
418
|
version=version,
|
|
412
419
|
base_url=base_url,
|
|
@@ -926,8 +933,20 @@ def load_connector_model(definition_path: str | Path) -> ConnectorModel:
|
|
|
926
933
|
)
|
|
927
934
|
entities.append(entity)
|
|
928
935
|
|
|
936
|
+
# Get connector ID
|
|
937
|
+
connector_id_value = connector_meta.get("id")
|
|
938
|
+
if connector_id_value:
|
|
939
|
+
# Try to parse as UUID (handles string UUIDs)
|
|
940
|
+
if isinstance(connector_id_value, str):
|
|
941
|
+
connector_id = UUID(connector_id_value)
|
|
942
|
+
else:
|
|
943
|
+
connector_id = connector_id_value
|
|
944
|
+
else:
|
|
945
|
+
raise ValueError
|
|
946
|
+
|
|
929
947
|
# Build ConnectorModel
|
|
930
948
|
model = ConnectorModel(
|
|
949
|
+
id=connector_id,
|
|
931
950
|
name=connector_meta["name"],
|
|
932
951
|
version=connector_meta.get("version", OPENAPI_DEFAULT_VERSION),
|
|
933
952
|
base_url=raw_definition.get("base_url", connector_meta.get("base_url", "")),
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
"""Hosted executor for proxying operations through the
|
|
1
|
+
"""Hosted executor for proxying operations through the cloud API."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
import os
|
|
6
|
-
|
|
7
|
-
import httpx
|
|
8
5
|
from opentelemetry import trace
|
|
9
6
|
|
|
7
|
+
from ..cloud_utils import AirbyteCloudClient
|
|
8
|
+
|
|
10
9
|
from .models import (
|
|
11
10
|
ExecutionConfig,
|
|
12
11
|
ExecutionResult,
|
|
@@ -14,30 +13,36 @@ from .models import (
|
|
|
14
13
|
|
|
15
14
|
|
|
16
15
|
class HostedExecutor:
|
|
17
|
-
"""Executor that proxies execution through the
|
|
16
|
+
"""Executor that proxies execution through the Airbyte Cloud API.
|
|
18
17
|
|
|
19
|
-
This is the "hosted mode" executor that makes HTTP calls to the
|
|
20
|
-
instead of directly calling external services. The
|
|
18
|
+
This is the "hosted mode" executor that makes HTTP calls to the cloud API
|
|
19
|
+
instead of directly calling external services. The cloud API handles all
|
|
21
20
|
connector logic, secrets management, and execution.
|
|
22
21
|
|
|
23
|
-
The
|
|
24
|
-
|
|
22
|
+
The executor takes an external_user_id and uses the AirbyteCloudClient to:
|
|
23
|
+
1. Authenticate with the Airbyte Platform (bearer token with caching)
|
|
24
|
+
2. Look up the user's connector instance
|
|
25
|
+
3. Execute the connector operation via the cloud API
|
|
25
26
|
|
|
26
27
|
Implements ExecutorProtocol.
|
|
27
28
|
|
|
28
29
|
Example:
|
|
30
|
+
# Create executor with user ID, credentials, and connector definition ID
|
|
29
31
|
executor = HostedExecutor(
|
|
30
|
-
|
|
32
|
+
external_user_id="user-123",
|
|
31
33
|
airbyte_client_id="client_abc123",
|
|
32
|
-
airbyte_client_secret="secret_xyz789"
|
|
34
|
+
airbyte_client_secret="secret_xyz789",
|
|
35
|
+
connector_definition_id="abc123-def456-ghi789",
|
|
33
36
|
)
|
|
34
37
|
|
|
35
|
-
|
|
38
|
+
# Execute an operation
|
|
39
|
+
execution_config = ExecutionConfig(
|
|
36
40
|
entity="customers",
|
|
37
|
-
action="list"
|
|
41
|
+
action="list",
|
|
42
|
+
params={"limit": 10}
|
|
38
43
|
)
|
|
39
44
|
|
|
40
|
-
result = await executor.execute(
|
|
45
|
+
result = await executor.execute(execution_config)
|
|
41
46
|
if result.success:
|
|
42
47
|
print(f"Data: {result.data}")
|
|
43
48
|
else:
|
|
@@ -46,53 +51,45 @@ class HostedExecutor:
|
|
|
46
51
|
|
|
47
52
|
def __init__(
|
|
48
53
|
self,
|
|
49
|
-
|
|
54
|
+
external_user_id: str,
|
|
50
55
|
airbyte_client_id: str,
|
|
51
56
|
airbyte_client_secret: str,
|
|
52
|
-
|
|
57
|
+
connector_definition_id: str,
|
|
53
58
|
):
|
|
54
59
|
"""Initialize hosted executor.
|
|
55
60
|
|
|
56
61
|
Args:
|
|
57
|
-
|
|
62
|
+
external_user_id: User identifier in the Airbyte system
|
|
58
63
|
airbyte_client_id: Airbyte client ID for authentication
|
|
59
64
|
airbyte_client_secret: Airbyte client secret for authentication
|
|
60
|
-
|
|
61
|
-
|
|
65
|
+
connector_definition_id: Connector definition ID used to look up
|
|
66
|
+
the user's connector instance.
|
|
62
67
|
|
|
63
68
|
Example:
|
|
64
69
|
executor = HostedExecutor(
|
|
65
|
-
|
|
66
|
-
airbyte_client_id="client_abc123",
|
|
67
|
-
airbyte_client_secret="secret_xyz789"
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
# Or with custom API URL:
|
|
71
|
-
executor = HostedExecutor(
|
|
72
|
-
connector_id="my-connector-id",
|
|
70
|
+
external_user_id="user-123",
|
|
73
71
|
airbyte_client_id="client_abc123",
|
|
74
72
|
airbyte_client_secret="secret_xyz789",
|
|
75
|
-
|
|
73
|
+
connector_definition_id="abc123-def456-ghi789",
|
|
76
74
|
)
|
|
77
75
|
"""
|
|
78
|
-
self.
|
|
79
|
-
self.
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
# The async wrapper allows it to work with the protocol
|
|
86
|
-
self.client = httpx.Client(
|
|
87
|
-
timeout=httpx.Timeout(300.0), # 5 minute timeout
|
|
88
|
-
follow_redirects=True,
|
|
76
|
+
self._external_user_id = external_user_id
|
|
77
|
+
self._connector_definition_id = connector_definition_id
|
|
78
|
+
|
|
79
|
+
# Create AirbyteCloudClient for API interactions
|
|
80
|
+
self._cloud_client = AirbyteCloudClient(
|
|
81
|
+
client_id=airbyte_client_id,
|
|
82
|
+
client_secret=airbyte_client_secret,
|
|
89
83
|
)
|
|
90
84
|
|
|
91
85
|
async def execute(self, config: ExecutionConfig) -> ExecutionResult:
|
|
92
|
-
"""Execute connector via
|
|
86
|
+
"""Execute connector via cloud API (ExecutorProtocol implementation).
|
|
93
87
|
|
|
94
|
-
|
|
95
|
-
|
|
88
|
+
Flow:
|
|
89
|
+
1. Get connector id from connector model
|
|
90
|
+
2. Look up the user's connector instance ID
|
|
91
|
+
3. Execute the connector operation via the cloud API
|
|
92
|
+
4. Parse the response into ExecutionResult
|
|
96
93
|
|
|
97
94
|
Args:
|
|
98
95
|
config: Execution configuration (entity, action, params)
|
|
@@ -101,88 +98,100 @@ class HostedExecutor:
|
|
|
101
98
|
ExecutionResult with success/failure status
|
|
102
99
|
|
|
103
100
|
Raises:
|
|
101
|
+
ValueError: If no instance or multiple instances found for user
|
|
104
102
|
httpx.HTTPStatusError: If API returns 4xx/5xx status code
|
|
105
103
|
httpx.RequestError: If network request fails
|
|
106
104
|
|
|
107
105
|
Example:
|
|
108
106
|
config = ExecutionConfig(
|
|
109
107
|
entity="customers",
|
|
110
|
-
action="list"
|
|
108
|
+
action="list",
|
|
109
|
+
params={"limit": 10}
|
|
111
110
|
)
|
|
112
111
|
result = await executor.execute(config)
|
|
113
112
|
"""
|
|
114
113
|
tracer = trace.get_tracer("airbyte.connector-sdk.executor.hosted")
|
|
115
114
|
|
|
116
115
|
with tracer.start_as_current_span("airbyte.hosted_executor.execute") as span:
|
|
117
|
-
# Add span attributes
|
|
118
|
-
span.set_attribute("connector.
|
|
116
|
+
# Add span attributes for observability
|
|
117
|
+
span.set_attribute("connector.definition_id", self._connector_definition_id)
|
|
119
118
|
span.set_attribute("connector.entity", config.entity)
|
|
120
119
|
span.set_attribute("connector.action", config.action)
|
|
121
|
-
span.set_attribute("
|
|
120
|
+
span.set_attribute("user.external_id", self._external_user_id)
|
|
122
121
|
if config.params:
|
|
123
122
|
# Only add non-sensitive param keys
|
|
124
123
|
span.set_attribute("connector.param_keys", list(config.params.keys()))
|
|
125
124
|
|
|
126
|
-
# Build API URL from instance api_url
|
|
127
|
-
url = f"{self.api_url}/connectors/{self.connector_id}/execute"
|
|
128
|
-
span.set_attribute("http.url", url)
|
|
129
|
-
|
|
130
|
-
# Build request body matching ExecutionRequest model
|
|
131
|
-
# Extract entity, action, and params from config attributes
|
|
132
|
-
request_body = {
|
|
133
|
-
"entity": config.entity,
|
|
134
|
-
"action": config.action,
|
|
135
|
-
"params": config.params,
|
|
136
|
-
}
|
|
137
|
-
|
|
138
125
|
try:
|
|
139
|
-
#
|
|
140
|
-
|
|
141
|
-
|
|
126
|
+
# Step 1: Get connector definition id
|
|
127
|
+
connector_definition_id = self._connector_definition_id
|
|
128
|
+
|
|
129
|
+
# Step 2: Get the connector instance ID for this user
|
|
130
|
+
instance_id = await self._cloud_client.get_connector_instance_id(
|
|
131
|
+
external_user_id=self._external_user_id,
|
|
132
|
+
connector_definition_id=connector_definition_id,
|
|
133
|
+
)
|
|
142
134
|
|
|
143
|
-
|
|
144
|
-
span.set_attribute("http.status_code", response.status_code)
|
|
135
|
+
span.set_attribute("connector.instance_id", instance_id)
|
|
145
136
|
|
|
146
|
-
#
|
|
147
|
-
response.
|
|
137
|
+
# Step 3: Execute the connector via the cloud API
|
|
138
|
+
response = await self._cloud_client.execute_connector(
|
|
139
|
+
instance_id=instance_id,
|
|
140
|
+
entity=config.entity,
|
|
141
|
+
action=config.action,
|
|
142
|
+
params=config.params,
|
|
143
|
+
)
|
|
148
144
|
|
|
149
|
-
# Parse
|
|
150
|
-
|
|
145
|
+
# Step 4: Parse the response into ExecutionResult
|
|
146
|
+
# The response_data is a dict from the API
|
|
147
|
+
result = self._parse_execution_result(response)
|
|
151
148
|
|
|
152
149
|
# Mark span as successful
|
|
153
|
-
span.set_attribute("connector.success",
|
|
150
|
+
span.set_attribute("connector.success", result.success)
|
|
154
151
|
|
|
155
|
-
|
|
156
|
-
return ExecutionResult(success=True, data=result_data, error=None)
|
|
152
|
+
return result
|
|
157
153
|
|
|
158
|
-
except
|
|
159
|
-
#
|
|
154
|
+
except ValueError as e:
|
|
155
|
+
# Instance lookup validation error (0 or >1 instances)
|
|
160
156
|
span.set_attribute("connector.success", False)
|
|
161
|
-
span.set_attribute("connector.error_type", "
|
|
162
|
-
span.set_attribute("http.status_code", e.response.status_code)
|
|
157
|
+
span.set_attribute("connector.error_type", "ValueError")
|
|
163
158
|
span.record_exception(e)
|
|
164
159
|
raise
|
|
165
160
|
|
|
166
161
|
except Exception as e:
|
|
167
|
-
#
|
|
162
|
+
# HTTP errors and other exceptions
|
|
168
163
|
span.set_attribute("connector.success", False)
|
|
169
164
|
span.set_attribute("connector.error_type", type(e).__name__)
|
|
170
165
|
span.record_exception(e)
|
|
171
166
|
raise
|
|
172
167
|
|
|
173
|
-
def
|
|
174
|
-
"""
|
|
168
|
+
def _parse_execution_result(self, response: dict) -> ExecutionResult:
|
|
169
|
+
"""Parse API response into ExecutionResult.
|
|
175
170
|
|
|
176
|
-
|
|
171
|
+
Args:
|
|
172
|
+
response_data: Raw JSON response from the cloud API
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
ExecutionResult with parsed data
|
|
176
|
+
"""
|
|
177
|
+
|
|
178
|
+
return ExecutionResult(
|
|
179
|
+
success=True,
|
|
180
|
+
data=response["result"],
|
|
181
|
+
meta=response.get("connector_metadata"),
|
|
182
|
+
error=None,
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
async def close(self):
|
|
186
|
+
"""Close the cloud client and cleanup resources.
|
|
187
|
+
|
|
188
|
+
Call this when you're done using the executor to clean up HTTP connections.
|
|
177
189
|
|
|
178
190
|
Example:
|
|
179
|
-
executor = HostedExecutor(
|
|
180
|
-
workspace_id="workspace-123",
|
|
181
|
-
connector_id="my-connector"
|
|
182
|
-
)
|
|
191
|
+
executor = HostedExecutor(...)
|
|
183
192
|
try:
|
|
184
193
|
result = await executor.execute(config)
|
|
185
194
|
finally:
|
|
186
|
-
executor.close()
|
|
195
|
+
await executor.close()
|
|
187
196
|
"""
|
|
188
|
-
self.
|
|
197
|
+
await self._cloud_client.close()
|
|
@@ -147,6 +147,9 @@ class HTTPClient:
|
|
|
147
147
|
self.base_url = self.base_url.replace(f"{{{var_name}}}", var_value)
|
|
148
148
|
|
|
149
149
|
self.auth_config = auth_config
|
|
150
|
+
assert (
|
|
151
|
+
self.auth_config.type is not None
|
|
152
|
+
), "auth_config.type cannot be None" # Should never be None when instantiated via the local executor flow
|
|
150
153
|
self.secrets = secrets
|
|
151
154
|
self.logger = logger or NullLogger()
|
|
152
155
|
self.metrics = HTTPMetrics()
|
|
@@ -296,12 +299,12 @@ class HTTPClient:
|
|
|
296
299
|
|
|
297
300
|
# Support both sync and async callbacks
|
|
298
301
|
callback_result = self.on_token_refresh(callback_data)
|
|
299
|
-
if hasattr(callback_result, "__await__"):
|
|
302
|
+
if callback_result is not None and hasattr(callback_result, "__await__"):
|
|
300
303
|
await callback_result
|
|
301
304
|
except Exception as callback_error:
|
|
302
305
|
self.logger.log_error(
|
|
303
306
|
request_id=None,
|
|
304
|
-
error=("Token refresh callback failed during initialization:
|
|
307
|
+
error=(f"Token refresh callback failed during initialization: {callback_error!s}"),
|
|
305
308
|
status_code=None,
|
|
306
309
|
)
|
|
307
310
|
|
|
@@ -485,7 +488,7 @@ class HTTPClient:
|
|
|
485
488
|
elif "application/json" in content_type or not content_type:
|
|
486
489
|
response_data = await response.json()
|
|
487
490
|
else:
|
|
488
|
-
error_msg = f"Expected JSON response for {method.upper()} {url},
|
|
491
|
+
error_msg = f"Expected JSON response for {method.upper()} {url}, got content-type: {content_type}"
|
|
489
492
|
raise HTTPClientError(error_msg)
|
|
490
493
|
|
|
491
494
|
except ValueError as e:
|
|
@@ -556,6 +559,7 @@ class HTTPClient:
|
|
|
556
559
|
current_token = self.secrets.get("access_token")
|
|
557
560
|
strategy = AuthStrategyFactory.get_strategy(self.auth_config.type)
|
|
558
561
|
|
|
562
|
+
# Try to refresh credentials
|
|
559
563
|
try:
|
|
560
564
|
result = await strategy.handle_auth_error(
|
|
561
565
|
status_code=status_code,
|
|
@@ -564,53 +568,56 @@ class HTTPClient:
|
|
|
564
568
|
config_values=self.config_values,
|
|
565
569
|
http_client=None, # Let strategy create its own client
|
|
566
570
|
)
|
|
567
|
-
|
|
568
|
-
if result:
|
|
569
|
-
# Notify callback if provided (for persistence)
|
|
570
|
-
# Include both tokens AND extracted values for full persistence
|
|
571
|
-
if self.on_token_refresh is not None:
|
|
572
|
-
try:
|
|
573
|
-
# Build callback data with both tokens and extracted values
|
|
574
|
-
callback_data = dict(result.tokens)
|
|
575
|
-
if result.extracted_values:
|
|
576
|
-
callback_data.update(result.extracted_values)
|
|
577
|
-
|
|
578
|
-
# Support both sync and async callbacks
|
|
579
|
-
callback_result = self.on_token_refresh(callback_data)
|
|
580
|
-
if hasattr(callback_result, "__await__"):
|
|
581
|
-
await callback_result
|
|
582
|
-
except Exception as callback_error:
|
|
583
|
-
self.logger.log_error(
|
|
584
|
-
request_id=request_id,
|
|
585
|
-
error=f"Token refresh callback failed: {str(callback_error)}",
|
|
586
|
-
status_code=status_code,
|
|
587
|
-
)
|
|
588
|
-
|
|
589
|
-
# Update secrets with new tokens (in-memory)
|
|
590
|
-
self.secrets.update(result.tokens)
|
|
591
|
-
|
|
592
|
-
# Update config_values and re-render base_url with extracted values
|
|
593
|
-
if result.extracted_values:
|
|
594
|
-
self._apply_token_extract(result.extracted_values)
|
|
595
|
-
|
|
596
|
-
if self.secrets.get("access_token") != current_token:
|
|
597
|
-
# Retry with new token - this will go through full retry logic
|
|
598
|
-
return await self.request(
|
|
599
|
-
method=method,
|
|
600
|
-
path=path,
|
|
601
|
-
params=params,
|
|
602
|
-
json=json,
|
|
603
|
-
data=data,
|
|
604
|
-
headers=headers,
|
|
605
|
-
)
|
|
606
|
-
|
|
607
571
|
except Exception as refresh_error:
|
|
608
572
|
self.logger.log_error(
|
|
609
573
|
request_id=request_id,
|
|
610
574
|
error=f"Credential refresh failed: {str(refresh_error)}",
|
|
611
575
|
status_code=status_code,
|
|
612
576
|
)
|
|
577
|
+
result = None
|
|
578
|
+
|
|
579
|
+
# If refresh succeeded, update tokens and retry
|
|
580
|
+
if result:
|
|
581
|
+
# Notify callback if provided (for persistence)
|
|
582
|
+
# Include both tokens AND extracted values for full persistence
|
|
583
|
+
if self.on_token_refresh is not None:
|
|
584
|
+
try:
|
|
585
|
+
# Build callback data with both tokens and extracted values
|
|
586
|
+
callback_data = dict(result.tokens)
|
|
587
|
+
if result.extracted_values:
|
|
588
|
+
callback_data.update(result.extracted_values)
|
|
589
|
+
|
|
590
|
+
# Support both sync and async callbacks
|
|
591
|
+
callback_result = self.on_token_refresh(callback_data)
|
|
592
|
+
if callback_result is not None and hasattr(callback_result, "__await__"):
|
|
593
|
+
await callback_result
|
|
594
|
+
except Exception as callback_error:
|
|
595
|
+
self.logger.log_error(
|
|
596
|
+
request_id=request_id,
|
|
597
|
+
error=f"Token refresh callback failed: {str(callback_error)}",
|
|
598
|
+
status_code=status_code,
|
|
599
|
+
)
|
|
600
|
+
|
|
601
|
+
# Update secrets with new tokens (in-memory)
|
|
602
|
+
self.secrets.update(result.tokens)
|
|
603
|
+
|
|
604
|
+
# Update config_values and re-render base_url with extracted values
|
|
605
|
+
if result.extracted_values:
|
|
606
|
+
self._apply_token_extract(result.extracted_values)
|
|
613
607
|
|
|
608
|
+
if self.secrets.get("access_token") != current_token:
|
|
609
|
+
# Retry with new token - this will go through full retry logic
|
|
610
|
+
# Any errors from this retry will propagate to the caller
|
|
611
|
+
return await self.request(
|
|
612
|
+
method=method,
|
|
613
|
+
path=path,
|
|
614
|
+
params=params,
|
|
615
|
+
json=json,
|
|
616
|
+
data=data,
|
|
617
|
+
headers=headers,
|
|
618
|
+
)
|
|
619
|
+
|
|
620
|
+
# Refresh failed or token didn't change, log and let original error propagate
|
|
614
621
|
self.logger.log_error(request_id=request_id, error=str(error), status_code=status_code)
|
|
615
622
|
|
|
616
623
|
async def request(
|
|
@@ -8,6 +8,7 @@ References:
|
|
|
8
8
|
|
|
9
9
|
from enum import StrEnum
|
|
10
10
|
from typing import Dict, Optional
|
|
11
|
+
from uuid import UUID
|
|
11
12
|
|
|
12
13
|
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
13
14
|
from pydantic_core import Url
|
|
@@ -117,7 +118,7 @@ class Info(BaseModel):
|
|
|
117
118
|
|
|
118
119
|
# Airbyte extension
|
|
119
120
|
x_airbyte_connector_name: Optional[str] = Field(None, alias="x-airbyte-connector-name")
|
|
120
|
-
x_airbyte_connector_id: Optional[
|
|
121
|
+
x_airbyte_connector_id: Optional[UUID] = Field(None, alias="x-airbyte-connector-id")
|
|
121
122
|
x_airbyte_external_documentation_urls: list[DocUrl] = Field(..., alias="x-airbyte-external-documentation-urls")
|
|
122
123
|
x_airbyte_retry_config: Optional[RetryConfig] = Field(None, alias="x-airbyte-retry-config")
|
|
123
124
|
x_airbyte_example_questions: Optional[ExampleQuestions] = Field(None, alias="x-airbyte-example-questions")
|
|
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
from enum import Enum
|
|
6
6
|
from typing import Any
|
|
7
|
+
from uuid import UUID
|
|
7
8
|
|
|
8
9
|
from pydantic import BaseModel, ConfigDict, Field
|
|
9
10
|
|
|
@@ -230,6 +231,7 @@ class ConnectorModel(BaseModel):
|
|
|
230
231
|
|
|
231
232
|
model_config = ConfigDict(use_enum_values=True)
|
|
232
233
|
|
|
234
|
+
id: UUID
|
|
233
235
|
name: str
|
|
234
236
|
version: str = OPENAPI_DEFAULT_VERSION
|
|
235
237
|
base_url: str
|
|
@@ -205,10 +205,9 @@ class ZendeskSupportConnector:
|
|
|
205
205
|
def __init__(
|
|
206
206
|
self,
|
|
207
207
|
auth_config: ZendeskSupportAuthConfig | None = None,
|
|
208
|
-
|
|
208
|
+
external_user_id: str | None = None,
|
|
209
209
|
airbyte_client_id: str | None = None,
|
|
210
210
|
airbyte_client_secret: str | None = None,
|
|
211
|
-
airbyte_connector_api_url: str | None = None,
|
|
212
211
|
on_token_refresh: Any | None = None,
|
|
213
212
|
subdomain: str | None = None ):
|
|
214
213
|
"""
|
|
@@ -216,14 +215,13 @@ class ZendeskSupportConnector:
|
|
|
216
215
|
|
|
217
216
|
Supports both local and hosted execution modes:
|
|
218
217
|
- Local mode: Provide `auth_config` for direct API calls
|
|
219
|
-
- Hosted mode: Provide `
|
|
218
|
+
- Hosted mode: Provide `external_user_id`, `airbyte_client_id`, and `airbyte_client_secret` for hosted execution
|
|
220
219
|
|
|
221
220
|
Args:
|
|
222
221
|
auth_config: Typed authentication configuration (required for local mode)
|
|
223
|
-
|
|
222
|
+
external_user_id: External user ID (required for hosted mode)
|
|
224
223
|
airbyte_client_id: Airbyte OAuth client ID (required for hosted mode)
|
|
225
224
|
airbyte_client_secret: Airbyte OAuth client secret (required for hosted mode)
|
|
226
|
-
airbyte_connector_api_url: Airbyte connector API URL (defaults to Airbyte Cloud API URL)
|
|
227
225
|
on_token_refresh: Optional callback for OAuth2 token refresh persistence.
|
|
228
226
|
Called with new_tokens dict when tokens are refreshed. Can be sync or async.
|
|
229
227
|
Example: lambda tokens: save_to_database(tokens) subdomain: Your Zendesk subdomain
|
|
@@ -232,7 +230,7 @@ class ZendeskSupportConnector:
|
|
|
232
230
|
connector = ZendeskSupportConnector(auth_config=ZendeskSupportAuthConfig(access_token="...", refresh_token="..."))
|
|
233
231
|
# Hosted mode (executed on Airbyte cloud)
|
|
234
232
|
connector = ZendeskSupportConnector(
|
|
235
|
-
|
|
233
|
+
external_user_id="user-123",
|
|
236
234
|
airbyte_client_id="client_abc123",
|
|
237
235
|
airbyte_client_secret="secret_xyz789"
|
|
238
236
|
)
|
|
@@ -248,20 +246,20 @@ class ZendeskSupportConnector:
|
|
|
248
246
|
on_token_refresh=save_tokens
|
|
249
247
|
)
|
|
250
248
|
"""
|
|
251
|
-
# Hosted mode:
|
|
252
|
-
if
|
|
249
|
+
# Hosted mode: external_user_id, airbyte_client_id, and airbyte_client_secret provided
|
|
250
|
+
if external_user_id and airbyte_client_id and airbyte_client_secret:
|
|
253
251
|
from ._vendored.connector_sdk.executor import HostedExecutor
|
|
254
252
|
self._executor = HostedExecutor(
|
|
255
|
-
|
|
253
|
+
external_user_id=external_user_id,
|
|
256
254
|
airbyte_client_id=airbyte_client_id,
|
|
257
255
|
airbyte_client_secret=airbyte_client_secret,
|
|
258
|
-
|
|
256
|
+
connector_definition_id=str(ZendeskSupportConnectorModel.id),
|
|
259
257
|
)
|
|
260
258
|
else:
|
|
261
259
|
# Local mode: auth_config required
|
|
262
260
|
if not auth_config:
|
|
263
261
|
raise ValueError(
|
|
264
|
-
"Either provide (
|
|
262
|
+
"Either provide (external_user_id, airbyte_client_id, airbyte_client_secret) for hosted mode "
|
|
265
263
|
"or auth_config for local mode"
|
|
266
264
|
)
|
|
267
265
|
|
|
@@ -23,8 +23,12 @@ from ._vendored.connector_sdk.schema.security import (
|
|
|
23
23
|
from ._vendored.connector_sdk.schema.components import (
|
|
24
24
|
PathOverrideConfig,
|
|
25
25
|
)
|
|
26
|
+
from uuid import (
|
|
27
|
+
UUID,
|
|
28
|
+
)
|
|
26
29
|
|
|
27
30
|
ZendeskSupportConnectorModel: ConnectorModel = ConnectorModel(
|
|
31
|
+
id=UUID('79c1aa37-dae3-42ae-b333-d1c105477715'),
|
|
28
32
|
name='zendesk-support',
|
|
29
33
|
version='0.1.3',
|
|
30
34
|
base_url='https://{subdomain}.zendesk.com/api/v2',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: airbyte-agent-zendesk-support
|
|
3
|
-
Version: 0.18.
|
|
3
|
+
Version: 0.18.21
|
|
4
4
|
Summary: Airbyte Zendesk-Support Connector for AI platforms
|
|
5
5
|
Project-URL: Homepage, https://github.com/airbytehq/airbyte-embedded
|
|
6
6
|
Project-URL: Documentation, https://github.com/airbytehq/airbyte-embedded/tree/main/integrations
|
|
@@ -32,7 +32,7 @@ Requires-Dist: pyyaml>=6.0
|
|
|
32
32
|
Requires-Dist: segment-analytics-python>=2.2.0
|
|
33
33
|
Description-Content-Type: text/markdown
|
|
34
34
|
|
|
35
|
-
#
|
|
35
|
+
# Zendesk-Support agent connector
|
|
36
36
|
|
|
37
37
|
Zendesk Support is a customer service platform that helps businesses manage support
|
|
38
38
|
tickets, customer interactions, and help center content. This connector provides
|
|
@@ -41,7 +41,7 @@ triggers, macros, views, satisfaction ratings, SLA policies, and help center art
|
|
|
41
41
|
for customer support analytics and service performance insights.
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
## Example
|
|
44
|
+
## Example questions
|
|
45
45
|
|
|
46
46
|
- Show me the tickets assigned to me last week
|
|
47
47
|
- What are the top 5 support issues our organization has faced this month?
|
|
@@ -52,7 +52,7 @@ for customer support analytics and service performance insights.
|
|
|
52
52
|
- Identify the most common ticket fields used in our support workflow
|
|
53
53
|
- Summarize the performance of our SLA policies this quarter
|
|
54
54
|
|
|
55
|
-
## Unsupported
|
|
55
|
+
## Unsupported questions
|
|
56
56
|
|
|
57
57
|
- Create a new support ticket for [customerX]
|
|
58
58
|
- Update the priority of this ticket
|
|
@@ -77,10 +77,12 @@ connector = ZendeskSupportConnector(
|
|
|
77
77
|
refresh_token="..."
|
|
78
78
|
)
|
|
79
79
|
)
|
|
80
|
-
result = connector.tickets.list()
|
|
80
|
+
result = await connector.tickets.list()
|
|
81
81
|
```
|
|
82
82
|
|
|
83
|
-
##
|
|
83
|
+
## Full documentation
|
|
84
|
+
|
|
85
|
+
This connector supports the following entities and actions.
|
|
84
86
|
|
|
85
87
|
| Entity | Actions |
|
|
86
88
|
|--------|---------|
|
|
@@ -108,14 +110,12 @@ result = connector.tickets.list()
|
|
|
108
110
|
| Article Attachments | [List](./REFERENCE.md#article-attachments-list), [Get](./REFERENCE.md#article-attachments-get), [Download](./REFERENCE.md#article-attachments-download) |
|
|
109
111
|
|
|
110
112
|
|
|
111
|
-
For detailed documentation on available actions and parameters, see [
|
|
112
|
-
|
|
113
|
-
For the service's official API docs, see [Zendesk-Support API Reference](https://developer.zendesk.com/api-reference/ticketing/introduction/).
|
|
114
|
-
|
|
115
|
-
## Version Information
|
|
113
|
+
For detailed documentation on available actions and parameters, see this connector's [full reference documentation](./REFERENCE.md).
|
|
116
114
|
|
|
117
|
-
|
|
115
|
+
For the service's official API docs, see the [Zendesk-Support API reference](https://developer.zendesk.com/api-reference/ticketing/introduction/).
|
|
118
116
|
|
|
119
|
-
|
|
117
|
+
## Version information
|
|
120
118
|
|
|
121
|
-
**
|
|
119
|
+
- **Package version:** 0.18.21
|
|
120
|
+
- **Connector version:** 0.1.3
|
|
121
|
+
- **Generated with Connector SDK commit SHA:** f7c55d3e3cdc7568cab2da9d736285eec58f044b
|
|
@@ -1,23 +1,25 @@
|
|
|
1
1
|
airbyte_agent_zendesk_support/__init__.py,sha256=MPz4HU055DRA3-1qgbGXh2E0YHmhcexQCFl-Tz21gm4,6227
|
|
2
|
-
airbyte_agent_zendesk_support/connector.py,sha256
|
|
3
|
-
airbyte_agent_zendesk_support/connector_model.py,sha256=
|
|
2
|
+
airbyte_agent_zendesk_support/connector.py,sha256=7AYDMDbkygncAVYtxo0q880C6SrVZQhaCvK8p0bKiOQ,63878
|
|
3
|
+
airbyte_agent_zendesk_support/connector_model.py,sha256=q-rn6aRvFt4H-neQ1HQRX7oq2MDEJY7MMuSaEAhGYCk,241131
|
|
4
4
|
airbyte_agent_zendesk_support/models.py,sha256=31bsOmf4nBdf8EXN3JpYzXW8mx6gv1xaZjeuEBgSzws,36399
|
|
5
5
|
airbyte_agent_zendesk_support/types.py,sha256=3CxJ8HosRMyzNEbVmRbybNCTVj9Ycxr7io25TP3YcCQ,6337
|
|
6
6
|
airbyte_agent_zendesk_support/_vendored/__init__.py,sha256=ILl7AHXMui__swyrjxrh9yRa4dLiwBvV6axPWFWty80,38
|
|
7
7
|
airbyte_agent_zendesk_support/_vendored/connector_sdk/__init__.py,sha256=T5o7roU6NSpH-lCAGZ338sE5dlh4ZU6i6IkeG1zpems,1949
|
|
8
8
|
airbyte_agent_zendesk_support/_vendored/connector_sdk/auth_strategies.py,sha256=0BfIISVzuvZTAYZjQFOOhKTpw0QuKDlLQBQ1PQo-V2M,39967
|
|
9
9
|
airbyte_agent_zendesk_support/_vendored/connector_sdk/auth_template.py,sha256=vKnyA21Jp33EuDjkIUAf1PGicwk4t9kZAPJuAgAZKzU,4458
|
|
10
|
-
airbyte_agent_zendesk_support/_vendored/connector_sdk/connector_model_loader.py,sha256=
|
|
10
|
+
airbyte_agent_zendesk_support/_vendored/connector_sdk/connector_model_loader.py,sha256=BeX4QykMUQZk5qY--WuwxXClI7FBDxxbGguqcztAd8A,34663
|
|
11
11
|
airbyte_agent_zendesk_support/_vendored/connector_sdk/constants.py,sha256=uH4rjBX6WsBP8M0jt7AUJI9w5Adn4wvJwib7Gdfkr1M,2736
|
|
12
12
|
airbyte_agent_zendesk_support/_vendored/connector_sdk/exceptions.py,sha256=ss5MGv9eVPmsbLcLWetuu3sDmvturwfo6Pw3M37Oq5k,481
|
|
13
13
|
airbyte_agent_zendesk_support/_vendored/connector_sdk/extensions.py,sha256=iWA2i0kiiGZY84H8P25A6QmfbuZwu7euMcj4-Vx2DOQ,20185
|
|
14
|
-
airbyte_agent_zendesk_support/_vendored/connector_sdk/http_client.py,sha256=
|
|
14
|
+
airbyte_agent_zendesk_support/_vendored/connector_sdk/http_client.py,sha256=NdccrrBHI5rW56XnXcP54arCwywIVKnMeSQPas6KlOM,27466
|
|
15
15
|
airbyte_agent_zendesk_support/_vendored/connector_sdk/secrets.py,sha256=UWcO9fP-vZwcfkAuvlZahlOCTOwdNN860BIwe8X4jxw,6868
|
|
16
|
-
airbyte_agent_zendesk_support/_vendored/connector_sdk/types.py,sha256=
|
|
16
|
+
airbyte_agent_zendesk_support/_vendored/connector_sdk/types.py,sha256=sS9olOyT-kVemHmcFll2ePFRhTdGMbWcz7bSgV-MuSw,8114
|
|
17
17
|
airbyte_agent_zendesk_support/_vendored/connector_sdk/utils.py,sha256=G4LUXOC2HzPoND2v4tQW68R9uuPX9NQyCjaGxb7Kpl0,1958
|
|
18
18
|
airbyte_agent_zendesk_support/_vendored/connector_sdk/validation.py,sha256=CDjCux1eg35a0Y4BegSivzIwZjiTqOxYWotWNLqTSVU,31792
|
|
19
|
+
airbyte_agent_zendesk_support/_vendored/connector_sdk/cloud_utils/__init__.py,sha256=4799Hv9f2zxDVj1aLyQ8JpTEuFTp_oOZMRz-NZCdBJg,134
|
|
20
|
+
airbyte_agent_zendesk_support/_vendored/connector_sdk/cloud_utils/client.py,sha256=HoDgZuEgGHj78P-BGwUf6HGPVWynbdKjGOmjb-JDk58,7188
|
|
19
21
|
airbyte_agent_zendesk_support/_vendored/connector_sdk/executor/__init__.py,sha256=EmG9YQNAjSuYCVB4D5VoLm4qpD1KfeiiOf7bpALj8p8,702
|
|
20
|
-
airbyte_agent_zendesk_support/_vendored/connector_sdk/executor/hosted_executor.py,sha256=
|
|
22
|
+
airbyte_agent_zendesk_support/_vendored/connector_sdk/executor/hosted_executor.py,sha256=YQ-qfT7PZh9izNFHHe7SAcETiZOKrWjTU-okVb0_VL8,7079
|
|
21
23
|
airbyte_agent_zendesk_support/_vendored/connector_sdk/executor/local_executor.py,sha256=hHlBTtvykrUcfypzyW0e61fU4e3vlxc90mypCFzgSl0,61879
|
|
22
24
|
airbyte_agent_zendesk_support/_vendored/connector_sdk/executor/models.py,sha256=lYVT_bNcw-PoIks4WHNyl2VY-lJVf2FntzINSOBIheE,5845
|
|
23
25
|
airbyte_agent_zendesk_support/_vendored/connector_sdk/http/__init__.py,sha256=y8fbzZn-3yV9OxtYz8Dy6FFGI5v6TOqADd1G3xHH3Hw,911
|
|
@@ -38,7 +40,7 @@ airbyte_agent_zendesk_support/_vendored/connector_sdk/performance/__init__.py,sh
|
|
|
38
40
|
airbyte_agent_zendesk_support/_vendored/connector_sdk/performance/instrumentation.py,sha256=_dXvNiqdndIBwDjeDKNViWzn_M5FkSUsMmJtFldrmsM,1504
|
|
39
41
|
airbyte_agent_zendesk_support/_vendored/connector_sdk/performance/metrics.py,sha256=3-wPwlJyfVLUIG3y7ESxk0avhkILk3z8K7zSrnlZf5U,2833
|
|
40
42
|
airbyte_agent_zendesk_support/_vendored/connector_sdk/schema/__init__.py,sha256=Uymu-QuzGJuMxexBagIvUxpVAigIuIhz3KeBl_Vu4Ko,1638
|
|
41
|
-
airbyte_agent_zendesk_support/_vendored/connector_sdk/schema/base.py,sha256=
|
|
43
|
+
airbyte_agent_zendesk_support/_vendored/connector_sdk/schema/base.py,sha256=eN6YfHwsYNz_0CE-S715Me8x3gQWTtaRk1vhFjEZF8I,4799
|
|
42
44
|
airbyte_agent_zendesk_support/_vendored/connector_sdk/schema/components.py,sha256=2ivMNhUAcovw88qvDkW221ILf1L63eXteztTDZL46us,7989
|
|
43
45
|
airbyte_agent_zendesk_support/_vendored/connector_sdk/schema/connector.py,sha256=VFBOzIkLgYBR1XUTmyrPGqBkX8PP-zsG8avQcdJUqXs,3864
|
|
44
46
|
airbyte_agent_zendesk_support/_vendored/connector_sdk/schema/extensions.py,sha256=LdoCuMLNdCj68O47qAL4v8xmqGz5tJgRiNZL5JnL9uw,3311
|
|
@@ -48,6 +50,6 @@ airbyte_agent_zendesk_support/_vendored/connector_sdk/telemetry/__init__.py,sha2
|
|
|
48
50
|
airbyte_agent_zendesk_support/_vendored/connector_sdk/telemetry/config.py,sha256=tLmQwAFD0kP1WyBGWBS3ysaudN9H3e-3EopKZi6cGKg,885
|
|
49
51
|
airbyte_agent_zendesk_support/_vendored/connector_sdk/telemetry/events.py,sha256=NvqjlUbkm6cbGh4ffKxYxtjdwwgzfPF4MKJ2GfgWeFg,1285
|
|
50
52
|
airbyte_agent_zendesk_support/_vendored/connector_sdk/telemetry/tracker.py,sha256=KacNdbHatvPPhnNrycp5YUuD5xpkp56AFcHd-zguBgk,5247
|
|
51
|
-
airbyte_agent_zendesk_support-0.18.
|
|
52
|
-
airbyte_agent_zendesk_support-0.18.
|
|
53
|
-
airbyte_agent_zendesk_support-0.18.
|
|
53
|
+
airbyte_agent_zendesk_support-0.18.21.dist-info/METADATA,sha256=h_eKn-nbGYB3MCSchx0bZNgcJcpCCSKAImsE8EQwnSA,5629
|
|
54
|
+
airbyte_agent_zendesk_support-0.18.21.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
55
|
+
airbyte_agent_zendesk_support-0.18.21.dist-info/RECORD,,
|
|
File without changes
|