airbyte-agent-slack 0.1.1__tar.gz → 0.1.7__tar.gz
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_slack-0.1.7/CHANGELOG.md +41 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/PKG-INFO +3 -3
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/README.md +2 -2
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/REFERENCE.md +12 -10
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/__init__.py +4 -4
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/connector_model_loader.py +3 -2
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/executor/local_executor.py +112 -21
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/http_client.py +13 -6
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/logging/logger.py +10 -1
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/logging/types.py +1 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/schema/base.py +1 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/schema/extensions.py +28 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/validation.py +12 -6
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/connector.py +1 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/models.py +24 -23
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/types.py +1 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/pyproject.toml +1 -1
- airbyte_agent_slack-0.1.1/CHANGELOG.md +0 -11
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/.gitignore +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/__init__.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/__init__.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/auth_strategies.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/auth_template.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/cloud_utils/__init__.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/cloud_utils/client.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/constants.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/exceptions.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/executor/__init__.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/executor/hosted_executor.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/executor/models.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/extensions.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/http/__init__.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/http/adapters/__init__.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/http/adapters/httpx_adapter.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/http/config.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/http/exceptions.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/http/protocols.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/http/response.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/introspection.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/logging/__init__.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/observability/__init__.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/observability/config.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/observability/models.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/observability/redactor.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/observability/session.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/performance/__init__.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/performance/instrumentation.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/performance/metrics.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/schema/__init__.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/schema/components.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/schema/connector.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/schema/operations.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/schema/security.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/secrets.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/telemetry/__init__.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/telemetry/config.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/telemetry/events.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/telemetry/tracker.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/types.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/connector_sdk/utils.py +0 -0
- {airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/connector_model.py +0 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Slack changelog
|
|
2
|
+
|
|
3
|
+
## [0.1.7] - 2026-01-19
|
|
4
|
+
- Updated connector definition (YAML version 0.1.1)
|
|
5
|
+
- Source commit: 529cebb7
|
|
6
|
+
- SDK version: 0.1.0
|
|
7
|
+
|
|
8
|
+
## [0.1.6] - 2026-01-16
|
|
9
|
+
- Updated connector definition (YAML version 0.1.1)
|
|
10
|
+
- Source commit: a50c8f71
|
|
11
|
+
- SDK version: 0.1.0
|
|
12
|
+
|
|
13
|
+
## [0.1.5] - 2026-01-16
|
|
14
|
+
- Updated connector definition (YAML version 0.1.1)
|
|
15
|
+
- Source commit: 49673b7b
|
|
16
|
+
- SDK version: 0.1.0
|
|
17
|
+
|
|
18
|
+
## [0.1.4] - 2026-01-16
|
|
19
|
+
- Updated connector definition (YAML version 0.1.1)
|
|
20
|
+
- Source commit: ca5acdda
|
|
21
|
+
- SDK version: 0.1.0
|
|
22
|
+
|
|
23
|
+
## [0.1.3] - 2026-01-15
|
|
24
|
+
- Updated connector definition (YAML version 0.1.1)
|
|
25
|
+
- Source commit: fa9a3b02
|
|
26
|
+
- SDK version: 0.1.0
|
|
27
|
+
|
|
28
|
+
## [0.1.2] - 2026-01-15
|
|
29
|
+
- Updated connector definition (YAML version 0.1.1)
|
|
30
|
+
- Source commit: 61a2e822
|
|
31
|
+
- SDK version: 0.1.0
|
|
32
|
+
|
|
33
|
+
## [0.1.1] - 2026-01-15
|
|
34
|
+
- Updated connector definition (YAML version 0.1.1)
|
|
35
|
+
- Source commit: 35211193
|
|
36
|
+
- SDK version: 0.1.0
|
|
37
|
+
|
|
38
|
+
## [0.1.0] - 2026-01-15
|
|
39
|
+
- Updated connector definition (YAML version 0.1.1)
|
|
40
|
+
- Source commit: 8b64ece5
|
|
41
|
+
- SDK version: 0.1.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: airbyte-agent-slack
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.7
|
|
4
4
|
Summary: Airbyte Slack Connector for AI platforms
|
|
5
5
|
Project-URL: Homepage, https://github.com/airbytehq/airbyte-agent-connectors
|
|
6
6
|
Project-URL: Documentation, https://docs.airbyte.com/ai-agents/
|
|
@@ -123,6 +123,6 @@ For the service's official API docs, see the [Slack API reference](https://api.s
|
|
|
123
123
|
|
|
124
124
|
## Version information
|
|
125
125
|
|
|
126
|
-
- **Package version:** 0.1.
|
|
126
|
+
- **Package version:** 0.1.7
|
|
127
127
|
- **Connector version:** 0.1.1
|
|
128
|
-
- **Generated with Connector SDK commit SHA:**
|
|
128
|
+
- **Generated with Connector SDK commit SHA:** c46670b9e4ca5238c0372e143b44088a0d1a68ee
|
|
@@ -90,6 +90,6 @@ For the service's official API docs, see the [Slack API reference](https://api.s
|
|
|
90
90
|
|
|
91
91
|
## Version information
|
|
92
92
|
|
|
93
|
-
- **Package version:** 0.1.
|
|
93
|
+
- **Package version:** 0.1.7
|
|
94
94
|
- **Connector version:** 0.1.1
|
|
95
|
-
- **Generated with Connector SDK commit SHA:**
|
|
95
|
+
- **Generated with Connector SDK commit SHA:** c46670b9e4ca5238c0372e143b44088a0d1a68ee
|
|
@@ -28,7 +28,7 @@ await slack.users.list()
|
|
|
28
28
|
**API**
|
|
29
29
|
|
|
30
30
|
```bash
|
|
31
|
-
curl --location 'https://api.airbyte.ai/api/v1/connectors/
|
|
31
|
+
curl --location 'https://api.airbyte.ai/api/v1/connectors/sources/{your_source_id}/execute' \
|
|
32
32
|
--header 'Content-Type: application/json' \
|
|
33
33
|
--header 'Authorization: Bearer {your_auth_token}' \
|
|
34
34
|
--data '{
|
|
@@ -98,7 +98,7 @@ await slack.users.get(
|
|
|
98
98
|
**API**
|
|
99
99
|
|
|
100
100
|
```bash
|
|
101
|
-
curl --location 'https://api.airbyte.ai/api/v1/connectors/
|
|
101
|
+
curl --location 'https://api.airbyte.ai/api/v1/connectors/sources/{your_source_id}/execute' \
|
|
102
102
|
--header 'Content-Type: application/json' \
|
|
103
103
|
--header 'Authorization: Bearer {your_auth_token}' \
|
|
104
104
|
--data '{
|
|
@@ -164,7 +164,7 @@ await slack.channels.list()
|
|
|
164
164
|
**API**
|
|
165
165
|
|
|
166
166
|
```bash
|
|
167
|
-
curl --location 'https://api.airbyte.ai/api/v1/connectors/
|
|
167
|
+
curl --location 'https://api.airbyte.ai/api/v1/connectors/sources/{your_source_id}/execute' \
|
|
168
168
|
--header 'Content-Type: application/json' \
|
|
169
169
|
--header 'Authorization: Bearer {your_auth_token}' \
|
|
170
170
|
--data '{
|
|
@@ -247,7 +247,7 @@ await slack.channels.get(
|
|
|
247
247
|
**API**
|
|
248
248
|
|
|
249
249
|
```bash
|
|
250
|
-
curl --location 'https://api.airbyte.ai/api/v1/connectors/
|
|
250
|
+
curl --location 'https://api.airbyte.ai/api/v1/connectors/sources/{your_source_id}/execute' \
|
|
251
251
|
--header 'Content-Type: application/json' \
|
|
252
252
|
--header 'Authorization: Bearer {your_auth_token}' \
|
|
253
253
|
--data '{
|
|
@@ -326,7 +326,7 @@ await slack.channel_messages.list(
|
|
|
326
326
|
**API**
|
|
327
327
|
|
|
328
328
|
```bash
|
|
329
|
-
curl --location 'https://api.airbyte.ai/api/v1/connectors/
|
|
329
|
+
curl --location 'https://api.airbyte.ai/api/v1/connectors/sources/{your_source_id}/execute' \
|
|
330
330
|
--header 'Content-Type: application/json' \
|
|
331
331
|
--header 'Authorization: Bearer {your_auth_token}' \
|
|
332
332
|
--data '{
|
|
@@ -445,7 +445,7 @@ await slack.threads.list(
|
|
|
445
445
|
**API**
|
|
446
446
|
|
|
447
447
|
```bash
|
|
448
|
-
curl --location 'https://api.airbyte.ai/api/v1/connectors/
|
|
448
|
+
curl --location 'https://api.airbyte.ai/api/v1/connectors/sources/{your_source_id}/execute' \
|
|
449
449
|
--header 'Content-Type: application/json' \
|
|
450
450
|
--header 'Authorization: Bearer {your_auth_token}' \
|
|
451
451
|
--data '{
|
|
@@ -577,11 +577,12 @@ SlackConnector(
|
|
|
577
577
|
**API**
|
|
578
578
|
|
|
579
579
|
```bash
|
|
580
|
-
curl --location 'https://api.airbyte.ai/api/v1/
|
|
580
|
+
curl --location 'https://api.airbyte.ai/api/v1/integrations/sources' \
|
|
581
581
|
--header 'Content-Type: application/json' \
|
|
582
582
|
--header 'Authorization: Bearer {your_auth_token}' \
|
|
583
583
|
--data '{
|
|
584
|
-
"
|
|
584
|
+
"workspace_id": "{your_workspace_id}",
|
|
585
|
+
"source_template_id": "{source_template_id}",
|
|
585
586
|
"auth_config": {
|
|
586
587
|
"access_token": "<Your Slack Bot Token (xoxb-) or User Token (xoxp-)>"
|
|
587
588
|
},
|
|
@@ -615,11 +616,12 @@ SlackConnector(
|
|
|
615
616
|
**API**
|
|
616
617
|
|
|
617
618
|
```bash
|
|
618
|
-
curl --location 'https://api.airbyte.ai/api/v1/
|
|
619
|
+
curl --location 'https://api.airbyte.ai/api/v1/integrations/sources' \
|
|
619
620
|
--header 'Content-Type: application/json' \
|
|
620
621
|
--header 'Authorization: Bearer {your_auth_token}' \
|
|
621
622
|
--data '{
|
|
622
|
-
"
|
|
623
|
+
"workspace_id": "{your_workspace_id}",
|
|
624
|
+
"source_template_id": "{source_template_id}",
|
|
623
625
|
"auth_config": {
|
|
624
626
|
"client_id": "<Your Slack App's Client ID>",
|
|
625
627
|
"client_secret": "<Your Slack App's Client Secret>",
|
|
@@ -17,9 +17,9 @@ from .models import (
|
|
|
17
17
|
ChannelPurpose,
|
|
18
18
|
ChannelsListResponse,
|
|
19
19
|
ChannelResponse,
|
|
20
|
-
Reaction,
|
|
21
|
-
File,
|
|
22
20
|
Attachment,
|
|
21
|
+
File,
|
|
22
|
+
Reaction,
|
|
23
23
|
Message,
|
|
24
24
|
Thread,
|
|
25
25
|
EditedInfo,
|
|
@@ -59,9 +59,9 @@ __all__ = [
|
|
|
59
59
|
"ChannelPurpose",
|
|
60
60
|
"ChannelsListResponse",
|
|
61
61
|
"ChannelResponse",
|
|
62
|
-
"Reaction",
|
|
63
|
-
"File",
|
|
64
62
|
"Attachment",
|
|
63
|
+
"File",
|
|
64
|
+
"Reaction",
|
|
65
65
|
"Message",
|
|
66
66
|
"Thread",
|
|
67
67
|
"EditedInfo",
|
|
@@ -519,13 +519,14 @@ def _parse_oauth2_config(scheme: Any) -> dict[str, str]:
|
|
|
519
519
|
config["refresh_url"] = refresh_url
|
|
520
520
|
|
|
521
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()
|
|
522
523
|
x_token_refresh = getattr(scheme, "x_token_refresh", None)
|
|
523
524
|
if x_token_refresh:
|
|
524
|
-
auth_style =
|
|
525
|
+
auth_style = x_token_refresh.get("auth_style")
|
|
525
526
|
if auth_style:
|
|
526
527
|
config["auth_style"] = auth_style
|
|
527
528
|
|
|
528
|
-
body_format =
|
|
529
|
+
body_format = x_token_refresh.get("body_format")
|
|
529
530
|
if body_format:
|
|
530
531
|
config["body_format"] = body_format
|
|
531
532
|
|
|
@@ -495,6 +495,14 @@ class LocalExecutor:
|
|
|
495
495
|
print(result.data)
|
|
496
496
|
"""
|
|
497
497
|
try:
|
|
498
|
+
# Check for hosted-only actions before converting to Action enum
|
|
499
|
+
if config.action == "search":
|
|
500
|
+
raise NotImplementedError(
|
|
501
|
+
"search is only available in hosted execution mode. "
|
|
502
|
+
"Initialize the connector with external_user_id, airbyte_client_id, "
|
|
503
|
+
"and airbyte_client_secret to use this feature."
|
|
504
|
+
)
|
|
505
|
+
|
|
498
506
|
# Convert config to internal format
|
|
499
507
|
action = Action(config.action) if isinstance(config.action, str) else config.action
|
|
500
508
|
params = config.params or {}
|
|
@@ -979,7 +987,9 @@ class LocalExecutor:
|
|
|
979
987
|
|
|
980
988
|
# Substitute variables from params
|
|
981
989
|
if "variables" in graphql_config and graphql_config["variables"]:
|
|
982
|
-
|
|
990
|
+
variables = self._interpolate_variables(graphql_config["variables"], params, param_defaults)
|
|
991
|
+
# Filter out None values (optional fields not provided) - matches REST _extract_body() behavior
|
|
992
|
+
body["variables"] = {k: v for k, v in variables.items() if v is not None}
|
|
983
993
|
|
|
984
994
|
# Add operation name if specified
|
|
985
995
|
if "operationName" in graphql_config:
|
|
@@ -1214,15 +1224,22 @@ class LocalExecutor:
|
|
|
1214
1224
|
def _extract_metadata(
|
|
1215
1225
|
self,
|
|
1216
1226
|
response_data: dict[str, Any],
|
|
1227
|
+
response_headers: dict[str, str],
|
|
1217
1228
|
endpoint: EndpointDefinition,
|
|
1218
1229
|
) -> dict[str, Any] | None:
|
|
1219
1230
|
"""Extract metadata from response using meta extractor.
|
|
1220
1231
|
|
|
1221
|
-
Each field in meta_extractor dict is independently extracted using JSONPath
|
|
1232
|
+
Each field in meta_extractor dict is independently extracted using JSONPath
|
|
1233
|
+
for body extraction, or special prefixes for header extraction:
|
|
1234
|
+
- @link.{rel}: Extract URL from RFC 5988 Link header by rel type
|
|
1235
|
+
- @header.{name}: Extract raw header value by header name
|
|
1236
|
+
- Otherwise: JSONPath expression for body extraction
|
|
1237
|
+
|
|
1222
1238
|
Missing or invalid paths result in None for that field (no crash).
|
|
1223
1239
|
|
|
1224
1240
|
Args:
|
|
1225
1241
|
response_data: Full API response (before record extraction)
|
|
1242
|
+
response_headers: HTTP response headers
|
|
1226
1243
|
endpoint: Endpoint with optional meta extractor configuration
|
|
1227
1244
|
|
|
1228
1245
|
Returns:
|
|
@@ -1233,11 +1250,15 @@ class LocalExecutor:
|
|
|
1233
1250
|
Example:
|
|
1234
1251
|
meta_extractor = {
|
|
1235
1252
|
"pagination": "$.records",
|
|
1236
|
-
"request_id": "$.requestId"
|
|
1253
|
+
"request_id": "$.requestId",
|
|
1254
|
+
"next_page_url": "@link.next",
|
|
1255
|
+
"rate_limit": "@header.X-RateLimit-Remaining"
|
|
1237
1256
|
}
|
|
1238
1257
|
Returns: {
|
|
1239
1258
|
"pagination": {"cursor": "abc", "total": 100},
|
|
1240
|
-
"request_id": "xyz123"
|
|
1259
|
+
"request_id": "xyz123",
|
|
1260
|
+
"next_page_url": "https://api.example.com/data?cursor=abc",
|
|
1261
|
+
"rate_limit": "99"
|
|
1241
1262
|
}
|
|
1242
1263
|
"""
|
|
1243
1264
|
# Check if endpoint has meta extractor
|
|
@@ -1247,26 +1268,96 @@ class LocalExecutor:
|
|
|
1247
1268
|
extracted_meta: dict[str, Any] = {}
|
|
1248
1269
|
|
|
1249
1270
|
# Extract each field independently
|
|
1250
|
-
for field_name,
|
|
1271
|
+
for field_name, extractor_expr in endpoint.meta_extractor.items():
|
|
1251
1272
|
try:
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
#
|
|
1258
|
-
|
|
1273
|
+
if extractor_expr.startswith("@link."):
|
|
1274
|
+
# RFC 5988 Link header extraction
|
|
1275
|
+
rel = extractor_expr[6:]
|
|
1276
|
+
extracted_meta[field_name] = self._extract_link_url(response_headers, rel)
|
|
1277
|
+
elif extractor_expr.startswith("@header."):
|
|
1278
|
+
# Raw header value extraction (case-insensitive lookup)
|
|
1279
|
+
header_name = extractor_expr[8:]
|
|
1280
|
+
extracted_meta[field_name] = self._get_header_value(response_headers, header_name)
|
|
1259
1281
|
else:
|
|
1260
|
-
#
|
|
1261
|
-
|
|
1282
|
+
# JSONPath body extraction
|
|
1283
|
+
jsonpath_expr = parse_jsonpath(extractor_expr)
|
|
1284
|
+
matches = [match.value for match in jsonpath_expr.find(response_data)]
|
|
1285
|
+
|
|
1286
|
+
if matches:
|
|
1287
|
+
# Return first match (most common case)
|
|
1288
|
+
extracted_meta[field_name] = matches[0]
|
|
1289
|
+
else:
|
|
1290
|
+
# Path not found - set to None
|
|
1291
|
+
extracted_meta[field_name] = None
|
|
1262
1292
|
|
|
1263
1293
|
except Exception as e:
|
|
1264
1294
|
# Log error but continue with other fields
|
|
1265
|
-
logging.warning(f"Failed to apply meta extractor for field '{field_name}' with
|
|
1295
|
+
logging.warning(f"Failed to apply meta extractor for field '{field_name}' with expression '{extractor_expr}': {e}. Setting to None.")
|
|
1266
1296
|
extracted_meta[field_name] = None
|
|
1267
1297
|
|
|
1268
1298
|
return extracted_meta
|
|
1269
1299
|
|
|
1300
|
+
@staticmethod
|
|
1301
|
+
def _extract_link_url(headers: dict[str, str], rel: str) -> str | None:
|
|
1302
|
+
"""Extract URL from RFC 5988 Link header by rel type.
|
|
1303
|
+
|
|
1304
|
+
Parses Link header format: <url>; param1="value1"; rel="next"; param2="value2"
|
|
1305
|
+
|
|
1306
|
+
Supports:
|
|
1307
|
+
- Multiple parameters per link in any order
|
|
1308
|
+
- Both quoted and unquoted rel values
|
|
1309
|
+
- Multiple links separated by commas
|
|
1310
|
+
|
|
1311
|
+
Args:
|
|
1312
|
+
headers: Response headers dict
|
|
1313
|
+
rel: The rel type to extract (e.g., "next", "prev", "first", "last")
|
|
1314
|
+
|
|
1315
|
+
Returns:
|
|
1316
|
+
The URL for the specified rel type, or None if not found
|
|
1317
|
+
"""
|
|
1318
|
+
link_header = headers.get("Link") or headers.get("link", "")
|
|
1319
|
+
if not link_header:
|
|
1320
|
+
return None
|
|
1321
|
+
|
|
1322
|
+
for link_segment in re.split(r",(?=\s*<)", link_header):
|
|
1323
|
+
link_segment = link_segment.strip()
|
|
1324
|
+
|
|
1325
|
+
url_match = re.match(r"<([^>]+)>", link_segment)
|
|
1326
|
+
if not url_match:
|
|
1327
|
+
continue
|
|
1328
|
+
|
|
1329
|
+
url = url_match.group(1)
|
|
1330
|
+
params_str = link_segment[url_match.end() :]
|
|
1331
|
+
|
|
1332
|
+
rel_match = re.search(r';\s*rel="?([^";,]+)"?', params_str, re.IGNORECASE)
|
|
1333
|
+
if rel_match and rel_match.group(1).strip() == rel:
|
|
1334
|
+
return url
|
|
1335
|
+
|
|
1336
|
+
return None
|
|
1337
|
+
|
|
1338
|
+
@staticmethod
|
|
1339
|
+
def _get_header_value(headers: dict[str, str], header_name: str) -> str | None:
|
|
1340
|
+
"""Get header value with case-insensitive lookup.
|
|
1341
|
+
|
|
1342
|
+
Args:
|
|
1343
|
+
headers: Response headers dict
|
|
1344
|
+
header_name: Header name to look up
|
|
1345
|
+
|
|
1346
|
+
Returns:
|
|
1347
|
+
Header value or None if not found
|
|
1348
|
+
"""
|
|
1349
|
+
# Try exact match first
|
|
1350
|
+
if header_name in headers:
|
|
1351
|
+
return headers[header_name]
|
|
1352
|
+
|
|
1353
|
+
# Case-insensitive lookup
|
|
1354
|
+
header_name_lower = header_name.lower()
|
|
1355
|
+
for key, value in headers.items():
|
|
1356
|
+
if key.lower() == header_name_lower:
|
|
1357
|
+
return value
|
|
1358
|
+
|
|
1359
|
+
return None
|
|
1360
|
+
|
|
1270
1361
|
def _validate_required_body_fields(self, endpoint: Any, params: dict[str, Any], action: Action, entity: str) -> None:
|
|
1271
1362
|
"""Validate that required body fields are present for CREATE/UPDATE operations.
|
|
1272
1363
|
|
|
@@ -1394,7 +1485,7 @@ class _StandardOperationHandler:
|
|
|
1394
1485
|
request_kwargs = self.ctx.determine_request_format(endpoint, body)
|
|
1395
1486
|
|
|
1396
1487
|
# Execute async HTTP request
|
|
1397
|
-
|
|
1488
|
+
response_data, response_headers = await self.ctx.http_client.request(
|
|
1398
1489
|
method=endpoint.method,
|
|
1399
1490
|
path=path,
|
|
1400
1491
|
params=query_params if query_params else None,
|
|
@@ -1403,10 +1494,10 @@ class _StandardOperationHandler:
|
|
|
1403
1494
|
)
|
|
1404
1495
|
|
|
1405
1496
|
# Extract metadata from original response (before record extraction)
|
|
1406
|
-
metadata = self.ctx.executor._extract_metadata(
|
|
1497
|
+
metadata = self.ctx.executor._extract_metadata(response_data, response_headers, endpoint)
|
|
1407
1498
|
|
|
1408
1499
|
# Extract records if extractor configured
|
|
1409
|
-
response = self.ctx.extract_records(
|
|
1500
|
+
response = self.ctx.extract_records(response_data, endpoint)
|
|
1410
1501
|
|
|
1411
1502
|
# Assume success with 200 status code if no exception raised
|
|
1412
1503
|
status_code = 200
|
|
@@ -1532,7 +1623,7 @@ class _DownloadOperationHandler:
|
|
|
1532
1623
|
request_format = self.ctx.determine_request_format(operation, request_body)
|
|
1533
1624
|
self.ctx.validate_required_body_fields(operation, params, action, entity)
|
|
1534
1625
|
|
|
1535
|
-
metadata_response = await self.ctx.http_client.request(
|
|
1626
|
+
metadata_response, _ = await self.ctx.http_client.request(
|
|
1536
1627
|
method=operation.method,
|
|
1537
1628
|
path=path,
|
|
1538
1629
|
params=query_params,
|
|
@@ -1547,7 +1638,7 @@ class _DownloadOperationHandler:
|
|
|
1547
1638
|
)
|
|
1548
1639
|
|
|
1549
1640
|
# Step 3: Stream file from extracted URL
|
|
1550
|
-
file_response = await self.ctx.http_client.request(
|
|
1641
|
+
file_response, _ = await self.ctx.http_client.request(
|
|
1551
1642
|
method="GET",
|
|
1552
1643
|
path=file_url,
|
|
1553
1644
|
headers=headers,
|
|
@@ -1555,7 +1646,7 @@ class _DownloadOperationHandler:
|
|
|
1555
1646
|
)
|
|
1556
1647
|
else:
|
|
1557
1648
|
# One-step direct download: stream file directly from endpoint
|
|
1558
|
-
file_response = await self.ctx.http_client.request(
|
|
1649
|
+
file_response, _ = await self.ctx.http_client.request(
|
|
1559
1650
|
method=operation.method,
|
|
1560
1651
|
path=path,
|
|
1561
1652
|
params=query_params,
|
|
@@ -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
|
|
|
@@ -152,6 +152,7 @@ class Server(BaseModel):
|
|
|
152
152
|
url: str
|
|
153
153
|
description: str | None = None
|
|
154
154
|
variables: Dict[str, ServerVariable] = Field(default_factory=dict)
|
|
155
|
+
x_airbyte_replication_user_config_mapping: Dict[str, str] | None = Field(default=None, alias="x-airbyte-replication-user-config-mapping")
|
|
155
156
|
|
|
156
157
|
@field_validator("url")
|
|
157
158
|
@classmethod
|
|
@@ -109,6 +109,30 @@ class RetryConfig(BaseModel):
|
|
|
109
109
|
retry_after_format: Literal["seconds", "milliseconds", "unix_timestamp"] = "seconds"
|
|
110
110
|
|
|
111
111
|
|
|
112
|
+
class CacheFieldProperty(BaseModel):
|
|
113
|
+
"""
|
|
114
|
+
Nested property definition for object-type cache fields.
|
|
115
|
+
|
|
116
|
+
Supports recursive nesting to represent complex nested schemas in cache field definitions.
|
|
117
|
+
Used when a cache field has type 'object' and needs to define its internal structure.
|
|
118
|
+
|
|
119
|
+
Example YAML usage:
|
|
120
|
+
- name: collaboration
|
|
121
|
+
type: ['null', 'object']
|
|
122
|
+
description: "Collaboration data"
|
|
123
|
+
properties:
|
|
124
|
+
brief:
|
|
125
|
+
type: ['null', 'string']
|
|
126
|
+
comments:
|
|
127
|
+
type: ['null', 'array']
|
|
128
|
+
"""
|
|
129
|
+
|
|
130
|
+
model_config = ConfigDict(populate_by_name=True, extra="forbid")
|
|
131
|
+
|
|
132
|
+
type: str | list[str]
|
|
133
|
+
properties: dict[str, "CacheFieldProperty"] | None = None
|
|
134
|
+
|
|
135
|
+
|
|
112
136
|
class CacheFieldConfig(BaseModel):
|
|
113
137
|
"""
|
|
114
138
|
Field configuration for cache mapping.
|
|
@@ -116,6 +140,9 @@ class CacheFieldConfig(BaseModel):
|
|
|
116
140
|
Defines a single field in a cache entity, with optional name aliasing
|
|
117
141
|
to map between user-facing field names and cache storage names.
|
|
118
142
|
|
|
143
|
+
For object-type fields, supports nested properties to define the internal structure
|
|
144
|
+
of complex nested schemas.
|
|
145
|
+
|
|
119
146
|
Used in x-airbyte-cache extension for api_search operations.
|
|
120
147
|
"""
|
|
121
148
|
|
|
@@ -125,6 +152,7 @@ class CacheFieldConfig(BaseModel):
|
|
|
125
152
|
x_airbyte_name: str | None = Field(default=None, alias="x-airbyte-name")
|
|
126
153
|
type: str | list[str]
|
|
127
154
|
description: str
|
|
155
|
+
properties: dict[str, CacheFieldProperty] | None = None
|
|
128
156
|
|
|
129
157
|
@property
|
|
130
158
|
def cache_name(self) -> str:
|
|
@@ -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:
|
|
@@ -176,13 +176,26 @@ class ChannelResponse(BaseModel):
|
|
|
176
176
|
ok: Union[bool, Any] = Field(default=None)
|
|
177
177
|
channel: Union[Channel, Any] = Field(default=None)
|
|
178
178
|
|
|
179
|
-
class
|
|
180
|
-
"""Message
|
|
179
|
+
class Attachment(BaseModel):
|
|
180
|
+
"""Message attachment"""
|
|
181
181
|
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
|
182
182
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
183
|
+
id: Union[int | None, Any] = Field(default=None)
|
|
184
|
+
fallback: Union[str | None, Any] = Field(default=None)
|
|
185
|
+
color: Union[str | None, Any] = Field(default=None)
|
|
186
|
+
pretext: Union[str | None, Any] = Field(default=None)
|
|
187
|
+
author_name: Union[str | None, Any] = Field(default=None)
|
|
188
|
+
author_link: Union[str | None, Any] = Field(default=None)
|
|
189
|
+
author_icon: Union[str | None, Any] = Field(default=None)
|
|
190
|
+
title: Union[str | None, Any] = Field(default=None)
|
|
191
|
+
title_link: Union[str | None, Any] = Field(default=None)
|
|
192
|
+
text: Union[str | None, Any] = Field(default=None)
|
|
193
|
+
fields: Union[list[dict[str, Any]] | None, Any] = Field(default=None)
|
|
194
|
+
image_url: Union[str | None, Any] = Field(default=None)
|
|
195
|
+
thumb_url: Union[str | None, Any] = Field(default=None)
|
|
196
|
+
footer: Union[str | None, Any] = Field(default=None)
|
|
197
|
+
footer_icon: Union[str | None, Any] = Field(default=None)
|
|
198
|
+
ts: Union[Any, Any] = Field(default=None)
|
|
186
199
|
|
|
187
200
|
class File(BaseModel):
|
|
188
201
|
"""File object"""
|
|
@@ -208,26 +221,13 @@ class File(BaseModel):
|
|
|
208
221
|
created: Union[int | None, Any] = Field(default=None)
|
|
209
222
|
timestamp: Union[int | None, Any] = Field(default=None)
|
|
210
223
|
|
|
211
|
-
class
|
|
212
|
-
"""Message
|
|
224
|
+
class Reaction(BaseModel):
|
|
225
|
+
"""Message reaction"""
|
|
213
226
|
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
|
214
227
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
pretext: Union[str | None, Any] = Field(default=None)
|
|
219
|
-
author_name: Union[str | None, Any] = Field(default=None)
|
|
220
|
-
author_link: Union[str | None, Any] = Field(default=None)
|
|
221
|
-
author_icon: Union[str | None, Any] = Field(default=None)
|
|
222
|
-
title: Union[str | None, Any] = Field(default=None)
|
|
223
|
-
title_link: Union[str | None, Any] = Field(default=None)
|
|
224
|
-
text: Union[str | None, Any] = Field(default=None)
|
|
225
|
-
fields: Union[list[dict[str, Any]] | None, Any] = Field(default=None)
|
|
226
|
-
image_url: Union[str | None, Any] = Field(default=None)
|
|
227
|
-
thumb_url: Union[str | None, Any] = Field(default=None)
|
|
228
|
-
footer: Union[str | None, Any] = Field(default=None)
|
|
229
|
-
footer_icon: Union[str | None, Any] = Field(default=None)
|
|
230
|
-
ts: Union[Any, Any] = Field(default=None)
|
|
228
|
+
name: Union[str | None, Any] = Field(default=None)
|
|
229
|
+
users: Union[list[str] | None, Any] = Field(default=None)
|
|
230
|
+
count: Union[int | None, Any] = Field(default=None)
|
|
231
231
|
|
|
232
232
|
class Message(BaseModel):
|
|
233
233
|
"""Slack message object"""
|
|
@@ -375,6 +375,7 @@ class SlackExecuteResultWithMeta(SlackExecuteResult[T], Generic[T, S]):
|
|
|
375
375
|
"""Metadata about the response (e.g., pagination cursors, record counts)."""
|
|
376
376
|
|
|
377
377
|
|
|
378
|
+
|
|
378
379
|
# ===== OPERATION RESULT TYPE ALIASES =====
|
|
379
380
|
|
|
380
381
|
# Concrete type aliases for each operation result.
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
# Slack changelog
|
|
2
|
-
|
|
3
|
-
## [0.1.1] - 2026-01-15
|
|
4
|
-
- Updated connector definition (YAML version 0.1.1)
|
|
5
|
-
- Source commit: 35211193
|
|
6
|
-
- SDK version: 0.1.0
|
|
7
|
-
|
|
8
|
-
## [0.1.0] - 2026-01-15
|
|
9
|
-
- Updated connector definition (YAML version 0.1.1)
|
|
10
|
-
- Source commit: 8b64ece5
|
|
11
|
-
- SDK version: 0.1.0
|
|
File without changes
|
{airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/_vendored/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{airbyte_agent_slack-0.1.1 → airbyte_agent_slack-0.1.7}/airbyte_agent_slack/connector_model.py
RENAMED
|
File without changes
|