airbyte-agent-zendesk-support 0.18.18__py3-none-any.whl → 0.18.51__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.
Files changed (37) hide show
  1. airbyte_agent_zendesk_support/__init__.py +239 -18
  2. airbyte_agent_zendesk_support/_vendored/connector_sdk/auth_strategies.py +2 -5
  3. airbyte_agent_zendesk_support/_vendored/connector_sdk/auth_template.py +1 -1
  4. airbyte_agent_zendesk_support/_vendored/connector_sdk/cloud_utils/__init__.py +5 -0
  5. airbyte_agent_zendesk_support/_vendored/connector_sdk/cloud_utils/client.py +213 -0
  6. airbyte_agent_zendesk_support/_vendored/connector_sdk/connector_model_loader.py +35 -8
  7. airbyte_agent_zendesk_support/_vendored/connector_sdk/constants.py +1 -1
  8. airbyte_agent_zendesk_support/_vendored/connector_sdk/executor/hosted_executor.py +92 -84
  9. airbyte_agent_zendesk_support/_vendored/connector_sdk/executor/local_executor.py +274 -54
  10. airbyte_agent_zendesk_support/_vendored/connector_sdk/extensions.py +43 -5
  11. airbyte_agent_zendesk_support/_vendored/connector_sdk/http/response.py +2 -0
  12. airbyte_agent_zendesk_support/_vendored/connector_sdk/http_client.py +63 -49
  13. airbyte_agent_zendesk_support/_vendored/connector_sdk/introspection.py +262 -0
  14. airbyte_agent_zendesk_support/_vendored/connector_sdk/logging/logger.py +19 -10
  15. airbyte_agent_zendesk_support/_vendored/connector_sdk/logging/types.py +11 -10
  16. airbyte_agent_zendesk_support/_vendored/connector_sdk/observability/config.py +179 -0
  17. airbyte_agent_zendesk_support/_vendored/connector_sdk/observability/models.py +6 -6
  18. airbyte_agent_zendesk_support/_vendored/connector_sdk/observability/session.py +41 -32
  19. airbyte_agent_zendesk_support/_vendored/connector_sdk/performance/metrics.py +3 -3
  20. airbyte_agent_zendesk_support/_vendored/connector_sdk/schema/base.py +22 -18
  21. airbyte_agent_zendesk_support/_vendored/connector_sdk/schema/components.py +59 -58
  22. airbyte_agent_zendesk_support/_vendored/connector_sdk/schema/connector.py +22 -33
  23. airbyte_agent_zendesk_support/_vendored/connector_sdk/schema/extensions.py +131 -10
  24. airbyte_agent_zendesk_support/_vendored/connector_sdk/schema/operations.py +32 -32
  25. airbyte_agent_zendesk_support/_vendored/connector_sdk/schema/security.py +44 -34
  26. airbyte_agent_zendesk_support/_vendored/connector_sdk/secrets.py +2 -2
  27. airbyte_agent_zendesk_support/_vendored/connector_sdk/telemetry/events.py +9 -8
  28. airbyte_agent_zendesk_support/_vendored/connector_sdk/telemetry/tracker.py +9 -5
  29. airbyte_agent_zendesk_support/_vendored/connector_sdk/types.py +9 -3
  30. airbyte_agent_zendesk_support/_vendored/connector_sdk/validation.py +12 -6
  31. airbyte_agent_zendesk_support/connector.py +1170 -171
  32. airbyte_agent_zendesk_support/connector_model.py +7 -1
  33. airbyte_agent_zendesk_support/models.py +628 -69
  34. airbyte_agent_zendesk_support/types.py +3717 -1
  35. {airbyte_agent_zendesk_support-0.18.18.dist-info → airbyte_agent_zendesk_support-0.18.51.dist-info}/METADATA +55 -31
  36. {airbyte_agent_zendesk_support-0.18.18.dist-info → airbyte_agent_zendesk_support-0.18.51.dist-info}/RECORD +37 -33
  37. {airbyte_agent_zendesk_support-0.18.18.dist-info → airbyte_agent_zendesk_support-0.18.51.dist-info}/WHEEL +0 -0
@@ -53,42 +53,52 @@ from .models import (
53
53
  ZendeskSupportExecuteResult,
54
54
  ZendeskSupportExecuteResultWithMeta,
55
55
  TicketsListResult,
56
- TicketsGetResult,
57
56
  UsersListResult,
58
- UsersGetResult,
59
57
  OrganizationsListResult,
60
- OrganizationsGetResult,
61
58
  GroupsListResult,
62
- GroupsGetResult,
63
59
  TicketCommentsListResult,
64
- AttachmentsGetResult,
65
60
  TicketAuditsListResult,
66
61
  TicketMetricsListResult,
67
62
  TicketFieldsListResult,
68
- TicketFieldsGetResult,
69
63
  BrandsListResult,
70
- BrandsGetResult,
71
64
  ViewsListResult,
72
- ViewsGetResult,
73
65
  MacrosListResult,
74
- MacrosGetResult,
75
66
  TriggersListResult,
76
- TriggersGetResult,
77
67
  AutomationsListResult,
78
- AutomationsGetResult,
79
68
  TagsListResult,
80
69
  SatisfactionRatingsListResult,
81
- SatisfactionRatingsGetResult,
82
70
  GroupMembershipsListResult,
83
71
  OrganizationMembershipsListResult,
84
72
  SlaPoliciesListResult,
85
- SlaPoliciesGetResult,
86
73
  TicketFormsListResult,
87
- TicketFormsGetResult,
88
74
  ArticlesListResult,
89
- ArticlesGetResult,
90
75
  ArticleAttachmentsListResult,
91
- ArticleAttachmentsGetResult
76
+ AirbyteSearchHit,
77
+ AirbyteSearchResult,
78
+ BrandsSearchData,
79
+ BrandsSearchResult,
80
+ GroupsSearchData,
81
+ GroupsSearchResult,
82
+ OrganizationsSearchData,
83
+ OrganizationsSearchResult,
84
+ SatisfactionRatingsSearchData,
85
+ SatisfactionRatingsSearchResult,
86
+ TagsSearchData,
87
+ TagsSearchResult,
88
+ TicketAuditsSearchData,
89
+ TicketAuditsSearchResult,
90
+ TicketCommentsSearchData,
91
+ TicketCommentsSearchResult,
92
+ TicketFieldsSearchData,
93
+ TicketFieldsSearchResult,
94
+ TicketFormsSearchData,
95
+ TicketFormsSearchResult,
96
+ TicketMetricsSearchData,
97
+ TicketMetricsSearchResult,
98
+ TicketsSearchData,
99
+ TicketsSearchResult,
100
+ UsersSearchData,
101
+ UsersSearchResult
92
102
  )
93
103
  from .types import (
94
104
  TicketsListParams,
@@ -130,7 +140,218 @@ from .types import (
130
140
  ArticlesGetParams,
131
141
  ArticleAttachmentsListParams,
132
142
  ArticleAttachmentsGetParams,
133
- ArticleAttachmentsDownloadParams
143
+ ArticleAttachmentsDownloadParams,
144
+ AirbyteSearchParams,
145
+ AirbyteSortOrder,
146
+ BrandsSearchFilter,
147
+ BrandsSearchQuery,
148
+ BrandsCondition,
149
+ GroupsSearchFilter,
150
+ GroupsSearchQuery,
151
+ GroupsCondition,
152
+ OrganizationsSearchFilter,
153
+ OrganizationsSearchQuery,
154
+ OrganizationsCondition,
155
+ SatisfactionRatingsSearchFilter,
156
+ SatisfactionRatingsSearchQuery,
157
+ SatisfactionRatingsCondition,
158
+ TagsSearchFilter,
159
+ TagsSearchQuery,
160
+ TagsCondition,
161
+ TicketAuditsSearchFilter,
162
+ TicketAuditsSearchQuery,
163
+ TicketAuditsCondition,
164
+ TicketCommentsSearchFilter,
165
+ TicketCommentsSearchQuery,
166
+ TicketCommentsCondition,
167
+ TicketFieldsSearchFilter,
168
+ TicketFieldsSearchQuery,
169
+ TicketFieldsCondition,
170
+ TicketFormsSearchFilter,
171
+ TicketFormsSearchQuery,
172
+ TicketFormsCondition,
173
+ TicketMetricsSearchFilter,
174
+ TicketMetricsSearchQuery,
175
+ TicketMetricsCondition,
176
+ TicketsSearchFilter,
177
+ TicketsSearchQuery,
178
+ TicketsCondition,
179
+ UsersSearchFilter,
180
+ UsersSearchQuery,
181
+ UsersCondition
134
182
  )
135
183
 
136
- __all__ = ["ZendeskSupportConnector", "ZendeskSupportAuthConfig", "Ticket", "User", "Organization", "Group", "TicketComment", "Attachment", "TicketAudit", "TicketMetric", "TicketField", "Brand", "View", "Macro", "Trigger", "Automation", "Tag", "SatisfactionRating", "GroupMembership", "OrganizationMembership", "SLAPolicy", "TicketForm", "Article", "ArticleAttachment", "TicketsListResultMeta", "UsersListResultMeta", "OrganizationsListResultMeta", "GroupsListResultMeta", "TicketCommentsListResultMeta", "TicketAuditsListResultMeta", "TicketMetricsListResultMeta", "TicketFieldsListResultMeta", "BrandsListResultMeta", "ViewsListResultMeta", "MacrosListResultMeta", "TriggersListResultMeta", "AutomationsListResultMeta", "TagsListResultMeta", "SatisfactionRatingsListResultMeta", "GroupMembershipsListResultMeta", "OrganizationMembershipsListResultMeta", "SlaPoliciesListResultMeta", "TicketFormsListResultMeta", "ArticlesListResultMeta", "ArticleAttachmentsListResultMeta", "ZendeskSupportExecuteResult", "ZendeskSupportExecuteResultWithMeta", "TicketsListResult", "TicketsGetResult", "UsersListResult", "UsersGetResult", "OrganizationsListResult", "OrganizationsGetResult", "GroupsListResult", "GroupsGetResult", "TicketCommentsListResult", "AttachmentsGetResult", "TicketAuditsListResult", "TicketMetricsListResult", "TicketFieldsListResult", "TicketFieldsGetResult", "BrandsListResult", "BrandsGetResult", "ViewsListResult", "ViewsGetResult", "MacrosListResult", "MacrosGetResult", "TriggersListResult", "TriggersGetResult", "AutomationsListResult", "AutomationsGetResult", "TagsListResult", "SatisfactionRatingsListResult", "SatisfactionRatingsGetResult", "GroupMembershipsListResult", "OrganizationMembershipsListResult", "SlaPoliciesListResult", "SlaPoliciesGetResult", "TicketFormsListResult", "TicketFormsGetResult", "ArticlesListResult", "ArticlesGetResult", "ArticleAttachmentsListResult", "ArticleAttachmentsGetResult", "TicketsListParams", "TicketsGetParams", "UsersListParams", "UsersGetParams", "OrganizationsListParams", "OrganizationsGetParams", "GroupsListParams", "GroupsGetParams", "TicketCommentsListParams", "AttachmentsGetParams", "AttachmentsDownloadParams", "TicketAuditsListParams", "TicketAuditsListParams", "TicketMetricsListParams", "TicketFieldsListParams", "TicketFieldsGetParams", "BrandsListParams", "BrandsGetParams", "ViewsListParams", "ViewsGetParams", "MacrosListParams", "MacrosGetParams", "TriggersListParams", "TriggersGetParams", "AutomationsListParams", "AutomationsGetParams", "TagsListParams", "SatisfactionRatingsListParams", "SatisfactionRatingsGetParams", "GroupMembershipsListParams", "OrganizationMembershipsListParams", "SlaPoliciesListParams", "SlaPoliciesGetParams", "TicketFormsListParams", "TicketFormsGetParams", "ArticlesListParams", "ArticlesGetParams", "ArticleAttachmentsListParams", "ArticleAttachmentsGetParams", "ArticleAttachmentsDownloadParams"]
184
+ __all__ = [
185
+ "ZendeskSupportConnector",
186
+ "ZendeskSupportAuthConfig",
187
+ "Ticket",
188
+ "User",
189
+ "Organization",
190
+ "Group",
191
+ "TicketComment",
192
+ "Attachment",
193
+ "TicketAudit",
194
+ "TicketMetric",
195
+ "TicketField",
196
+ "Brand",
197
+ "View",
198
+ "Macro",
199
+ "Trigger",
200
+ "Automation",
201
+ "Tag",
202
+ "SatisfactionRating",
203
+ "GroupMembership",
204
+ "OrganizationMembership",
205
+ "SLAPolicy",
206
+ "TicketForm",
207
+ "Article",
208
+ "ArticleAttachment",
209
+ "TicketsListResultMeta",
210
+ "UsersListResultMeta",
211
+ "OrganizationsListResultMeta",
212
+ "GroupsListResultMeta",
213
+ "TicketCommentsListResultMeta",
214
+ "TicketAuditsListResultMeta",
215
+ "TicketMetricsListResultMeta",
216
+ "TicketFieldsListResultMeta",
217
+ "BrandsListResultMeta",
218
+ "ViewsListResultMeta",
219
+ "MacrosListResultMeta",
220
+ "TriggersListResultMeta",
221
+ "AutomationsListResultMeta",
222
+ "TagsListResultMeta",
223
+ "SatisfactionRatingsListResultMeta",
224
+ "GroupMembershipsListResultMeta",
225
+ "OrganizationMembershipsListResultMeta",
226
+ "SlaPoliciesListResultMeta",
227
+ "TicketFormsListResultMeta",
228
+ "ArticlesListResultMeta",
229
+ "ArticleAttachmentsListResultMeta",
230
+ "ZendeskSupportExecuteResult",
231
+ "ZendeskSupportExecuteResultWithMeta",
232
+ "TicketsListResult",
233
+ "UsersListResult",
234
+ "OrganizationsListResult",
235
+ "GroupsListResult",
236
+ "TicketCommentsListResult",
237
+ "TicketAuditsListResult",
238
+ "TicketMetricsListResult",
239
+ "TicketFieldsListResult",
240
+ "BrandsListResult",
241
+ "ViewsListResult",
242
+ "MacrosListResult",
243
+ "TriggersListResult",
244
+ "AutomationsListResult",
245
+ "TagsListResult",
246
+ "SatisfactionRatingsListResult",
247
+ "GroupMembershipsListResult",
248
+ "OrganizationMembershipsListResult",
249
+ "SlaPoliciesListResult",
250
+ "TicketFormsListResult",
251
+ "ArticlesListResult",
252
+ "ArticleAttachmentsListResult",
253
+ "AirbyteSearchHit",
254
+ "AirbyteSearchResult",
255
+ "BrandsSearchData",
256
+ "BrandsSearchResult",
257
+ "GroupsSearchData",
258
+ "GroupsSearchResult",
259
+ "OrganizationsSearchData",
260
+ "OrganizationsSearchResult",
261
+ "SatisfactionRatingsSearchData",
262
+ "SatisfactionRatingsSearchResult",
263
+ "TagsSearchData",
264
+ "TagsSearchResult",
265
+ "TicketAuditsSearchData",
266
+ "TicketAuditsSearchResult",
267
+ "TicketCommentsSearchData",
268
+ "TicketCommentsSearchResult",
269
+ "TicketFieldsSearchData",
270
+ "TicketFieldsSearchResult",
271
+ "TicketFormsSearchData",
272
+ "TicketFormsSearchResult",
273
+ "TicketMetricsSearchData",
274
+ "TicketMetricsSearchResult",
275
+ "TicketsSearchData",
276
+ "TicketsSearchResult",
277
+ "UsersSearchData",
278
+ "UsersSearchResult",
279
+ "TicketsListParams",
280
+ "TicketsGetParams",
281
+ "UsersListParams",
282
+ "UsersGetParams",
283
+ "OrganizationsListParams",
284
+ "OrganizationsGetParams",
285
+ "GroupsListParams",
286
+ "GroupsGetParams",
287
+ "TicketCommentsListParams",
288
+ "AttachmentsGetParams",
289
+ "AttachmentsDownloadParams",
290
+ "TicketAuditsListParams",
291
+ "TicketAuditsListParams",
292
+ "TicketMetricsListParams",
293
+ "TicketFieldsListParams",
294
+ "TicketFieldsGetParams",
295
+ "BrandsListParams",
296
+ "BrandsGetParams",
297
+ "ViewsListParams",
298
+ "ViewsGetParams",
299
+ "MacrosListParams",
300
+ "MacrosGetParams",
301
+ "TriggersListParams",
302
+ "TriggersGetParams",
303
+ "AutomationsListParams",
304
+ "AutomationsGetParams",
305
+ "TagsListParams",
306
+ "SatisfactionRatingsListParams",
307
+ "SatisfactionRatingsGetParams",
308
+ "GroupMembershipsListParams",
309
+ "OrganizationMembershipsListParams",
310
+ "SlaPoliciesListParams",
311
+ "SlaPoliciesGetParams",
312
+ "TicketFormsListParams",
313
+ "TicketFormsGetParams",
314
+ "ArticlesListParams",
315
+ "ArticlesGetParams",
316
+ "ArticleAttachmentsListParams",
317
+ "ArticleAttachmentsGetParams",
318
+ "ArticleAttachmentsDownloadParams",
319
+ "AirbyteSearchParams",
320
+ "AirbyteSortOrder",
321
+ "BrandsSearchFilter",
322
+ "BrandsSearchQuery",
323
+ "BrandsCondition",
324
+ "GroupsSearchFilter",
325
+ "GroupsSearchQuery",
326
+ "GroupsCondition",
327
+ "OrganizationsSearchFilter",
328
+ "OrganizationsSearchQuery",
329
+ "OrganizationsCondition",
330
+ "SatisfactionRatingsSearchFilter",
331
+ "SatisfactionRatingsSearchQuery",
332
+ "SatisfactionRatingsCondition",
333
+ "TagsSearchFilter",
334
+ "TagsSearchQuery",
335
+ "TagsCondition",
336
+ "TicketAuditsSearchFilter",
337
+ "TicketAuditsSearchQuery",
338
+ "TicketAuditsCondition",
339
+ "TicketCommentsSearchFilter",
340
+ "TicketCommentsSearchQuery",
341
+ "TicketCommentsCondition",
342
+ "TicketFieldsSearchFilter",
343
+ "TicketFieldsSearchQuery",
344
+ "TicketFieldsCondition",
345
+ "TicketFormsSearchFilter",
346
+ "TicketFormsSearchQuery",
347
+ "TicketFormsCondition",
348
+ "TicketMetricsSearchFilter",
349
+ "TicketMetricsSearchQuery",
350
+ "TicketMetricsCondition",
351
+ "TicketsSearchFilter",
352
+ "TicketsSearchQuery",
353
+ "TicketsCondition",
354
+ "UsersSearchFilter",
355
+ "UsersSearchQuery",
356
+ "UsersCondition",
357
+ ]
@@ -610,9 +610,7 @@ class OAuth2AuthStrategy(AuthStrategy):
610
610
  has_refresh_token = bool(secrets.get("refresh_token"))
611
611
 
612
612
  if not has_access_token and not has_refresh_token:
613
- raise AuthenticationError(
614
- "Missing OAuth2 credentials. Provide either 'access_token' " "or 'refresh_token' (for refresh-token-only mode)."
615
- )
613
+ raise AuthenticationError("Missing OAuth2 credentials. Provide either 'access_token' or 'refresh_token' (for refresh-token-only mode).")
616
614
 
617
615
  def can_refresh(self, secrets: OAuth2RefreshSecrets) -> bool:
618
616
  """Check if token refresh is possible.
@@ -1106,8 +1104,7 @@ class AuthStrategyFactory:
1106
1104
  strategy = cls._strategies.get(auth_type)
1107
1105
  if strategy is None:
1108
1106
  raise AuthenticationError(
1109
- f"Authentication type '{auth_type.value}' is not implemented. "
1110
- f"Supported types: {', '.join(s.value for s in cls._strategies.keys())}"
1107
+ f"Authentication type '{auth_type.value}' is not implemented. Supported types: {', '.join(s.value for s in cls._strategies.keys())}"
1111
1108
  )
1112
1109
  return strategy
1113
1110
 
@@ -17,7 +17,7 @@ class MissingVariableError(ValueError):
17
17
  def __init__(self, var_name: str, available_fields: list):
18
18
  self.var_name = var_name
19
19
  self.available_fields = available_fields
20
- super().__init__(f"Template variable '${{{var_name}}}' not found in config. " f"Available fields: {available_fields}")
20
+ super().__init__(f"Template variable '${{{var_name}}}' not found in config. Available fields: {available_fields}")
21
21
 
22
22
 
23
23
  def apply_template(template: str, values: Dict[str, str]) -> str:
@@ -0,0 +1,5 @@
1
+ """Cloud API utilities for Airbyte Platform integration."""
2
+
3
+ from .client import AirbyteCloudClient
4
+
5
+ __all__ = ["AirbyteCloudClient"]
@@ -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 connectors 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 ID
26
+ connector_id = await client.get_connector_id(
27
+ external_user_id="user-123",
28
+ connector_definition_id="550e8400-e29b-41d4-a716-446655440000"
29
+ )
30
+
31
+ # Execute the connector
32
+ result = await client.execute_connector(
33
+ connector_id=connector_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_id(
109
+ self,
110
+ external_user_id: str,
111
+ connector_definition_id: str,
112
+ ) -> str:
113
+ """Get connector ID for a user.
114
+
115
+ Looks up the connector that belongs to the specified user
116
+ and connector definition. Validates that exactly one connector 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 ID (UUID string)
124
+
125
+ Raises:
126
+ ValueError: If 0 or more than 1 connector is found
127
+ httpx.HTTPStatusError: If API returns 4xx/5xx status code
128
+ httpx.RequestError: If network request fails
129
+
130
+ Example:
131
+ connector_id = await client.get_connector_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/connectors_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
+ connectors = data["connectors"]
150
+
151
+ if len(connectors) == 0:
152
+ raise ValueError(f"No connector found for user '{external_user_id}' and connector definition '{connector_definition_id}'")
153
+
154
+ if len(connectors) > 1:
155
+ raise ValueError(
156
+ f"Multiple connectors found for user '{external_user_id}' "
157
+ f"and connector definition '{connector_definition_id}'. Expected exactly 1, "
158
+ f"found {len(connectors)}"
159
+ )
160
+
161
+ connector_id = connectors[0]["id"]
162
+ return connector_id
163
+
164
+ async def execute_connector(
165
+ self,
166
+ connector_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
+ connector_id: Connector UUID (source ID)
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
+ connector_id="550e8400-e29b-41d4-a716-446655440000",
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/sources/{connector_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()
@@ -2,9 +2,11 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import logging
5
6
  import re
6
7
  from pathlib import Path
7
8
  from typing import Any
9
+ from uuid import UUID
8
10
 
9
11
  import jsonref
10
12
  import yaml
@@ -105,7 +107,7 @@ def resolve_schema_refs(schema: Any, spec_dict: dict) -> dict[str, Any]:
105
107
 
106
108
  try:
107
109
  # Resolve all references
108
- resolved_spec = jsonref.replace_refs(
110
+ resolved_spec = jsonref.replace_refs( # type: ignore[union-attr]
109
111
  temp_spec,
110
112
  base_uri="",
111
113
  jsonschema=True, # Use JSONSchema draft 7 semantics
@@ -117,9 +119,11 @@ def resolve_schema_refs(schema: Any, spec_dict: dict) -> dict[str, Any]:
117
119
 
118
120
  # Remove any remaining jsonref proxy objects by converting to plain dict
119
121
  return _deproxy_schema(resolved_schema)
120
- except (jsonref.JsonRefError, KeyError, RecursionError):
122
+ except (AttributeError, KeyError, RecursionError, Exception):
121
123
  # If resolution fails, return the original schema
122
124
  # This allows the system to continue even with malformed $refs
125
+ # AttributeError covers the case where jsonref might be None
126
+ # Exception catches jsonref.JsonRefError and other jsonref exceptions
123
127
  return schema_dict
124
128
 
125
129
 
@@ -390,23 +394,35 @@ def convert_openapi_to_connector_model(spec: OpenAPIConnector) -> ConnectorModel
390
394
  for entity_name, endpoints_dict in entities_map.items():
391
395
  actions = list(endpoints_dict.keys())
392
396
 
393
- # Get schema from components if available
397
+ # Get schema and stream_name from components if available
394
398
  schema = None
399
+ entity_stream_name = None
395
400
  if spec.components:
396
401
  # Look for a schema matching the entity name
397
402
  for schema_name, schema_def in spec.components.schemas.items():
398
403
  if schema_def.x_airbyte_entity_name == entity_name or schema_name.lower() == entity_name.lower():
399
404
  schema = schema_def.model_dump(by_alias=True)
405
+ entity_stream_name = schema_def.x_airbyte_stream_name
400
406
  break
401
407
 
402
- entity = EntityDefinition(name=entity_name, actions=actions, endpoints=endpoints_dict, schema=schema)
408
+ entity = EntityDefinition(
409
+ name=entity_name,
410
+ stream_name=entity_stream_name,
411
+ actions=actions,
412
+ endpoints=endpoints_dict,
413
+ schema=schema,
414
+ )
403
415
  entities.append(entity)
404
416
 
405
417
  # Extract retry config from x-airbyte-retry-config extension
406
418
  retry_config = spec.info.x_airbyte_retry_config
419
+ connector_id = spec.info.x_airbyte_connector_id
420
+ if not connector_id:
421
+ raise InvalidOpenAPIError("Missing required x-airbyte-connector-id field")
407
422
 
408
423
  # Create ConnectorModel
409
424
  model = ConnectorModel(
425
+ id=connector_id,
410
426
  name=name,
411
427
  version=version,
412
428
  base_url=base_url,
@@ -503,13 +519,14 @@ def _parse_oauth2_config(scheme: Any) -> dict[str, str]:
503
519
  config["refresh_url"] = refresh_url
504
520
 
505
521
  # Extract custom refresh configuration from x-airbyte-token-refresh extension
522
+ # Note: x_token_refresh is a Dict[str, Any], not a Pydantic model, so use .get()
506
523
  x_token_refresh = getattr(scheme, "x_token_refresh", None)
507
524
  if x_token_refresh:
508
- auth_style = getattr(x_token_refresh, "auth_style", None)
525
+ auth_style = x_token_refresh.get("auth_style")
509
526
  if auth_style:
510
527
  config["auth_style"] = auth_style
511
528
 
512
- body_format = getattr(x_token_refresh, "body_format", None)
529
+ body_format = x_token_refresh.get("body_format")
513
530
  if body_format:
514
531
  config["body_format"] = body_format
515
532
 
@@ -753,8 +770,6 @@ def _parse_auth_from_openapi(spec: OpenAPIConnector) -> AuthConfig:
753
770
  options.append(auth_option)
754
771
  except Exception as e:
755
772
  # Log warning but continue - skip invalid schemes
756
- import logging
757
-
758
773
  logger = logging.getLogger(__name__)
759
774
  logger.warning(f"Skipping invalid security scheme '{scheme_name}': {e}")
760
775
  continue
@@ -926,8 +941,20 @@ def load_connector_model(definition_path: str | Path) -> ConnectorModel:
926
941
  )
927
942
  entities.append(entity)
928
943
 
944
+ # Get connector ID
945
+ connector_id_value = connector_meta.get("id")
946
+ if connector_id_value:
947
+ # Try to parse as UUID (handles string UUIDs)
948
+ if isinstance(connector_id_value, str):
949
+ connector_id = UUID(connector_id_value)
950
+ else:
951
+ connector_id = connector_id_value
952
+ else:
953
+ raise ValueError
954
+
929
955
  # Build ConnectorModel
930
956
  model = ConnectorModel(
957
+ id=connector_id,
931
958
  name=connector_meta["name"],
932
959
  version=connector_meta.get("version", OPENAPI_DEFAULT_VERSION),
933
960
  base_url=raw_definition.get("base_url", connector_meta.get("base_url", "")),
@@ -74,5 +74,5 @@ except PackageNotFoundError:
74
74
  SDK_VERSION = "0.0.0-dev"
75
75
  """Current version of the Airbyte SDK."""
76
76
 
77
- MINIMUM_PYTHON_VERSION = "3.9"
77
+ MINIMUM_PYTHON_VERSION = "3.13"
78
78
  """Minimum Python version required to run the SDK."""