airbyte-cdk 6.13.1.dev4108__py3-none-any.whl → 6.13.1.dev4109__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_cdk/sources/declarative/auth/oauth.py +26 -0
- airbyte_cdk/sources/declarative/declarative_component_schema.yaml +51 -19
- airbyte_cdk/sources/declarative/models/declarative_component_schema.py +64 -22
- airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py +25 -1
- airbyte_cdk/sources/declarative/requesters/README.md +57 -0
- airbyte_cdk/sources/declarative/requesters/http_job_repository.py +33 -4
- airbyte_cdk/sources/file_based/file_types/unstructured_parser.py +10 -7
- airbyte_cdk/sources/streams/http/requests_native_auth/abstract_oauth.py +20 -4
- airbyte_cdk/sources/streams/http/requests_native_auth/oauth.py +34 -4
- airbyte_cdk/sources/types.py +3 -0
- {airbyte_cdk-6.13.1.dev4108.dist-info → airbyte_cdk-6.13.1.dev4109.dist-info}/METADATA +1 -1
- {airbyte_cdk-6.13.1.dev4108.dist-info → airbyte_cdk-6.13.1.dev4109.dist-info}/RECORD +15 -14
- {airbyte_cdk-6.13.1.dev4108.dist-info → airbyte_cdk-6.13.1.dev4109.dist-info}/LICENSE.txt +0 -0
- {airbyte_cdk-6.13.1.dev4108.dist-info → airbyte_cdk-6.13.1.dev4109.dist-info}/WHEEL +0 -0
- {airbyte_cdk-6.13.1.dev4108.dist-info → airbyte_cdk-6.13.1.dev4109.dist-info}/entry_points.txt +0 -0
@@ -56,8 +56,12 @@ class DeclarativeOauth2Authenticator(AbstractOauth2Authenticator, DeclarativeAut
|
|
56
56
|
token_expiry_is_time_of_expiration: bool = False
|
57
57
|
access_token_name: Union[InterpolatedString, str] = "access_token"
|
58
58
|
access_token_value: Optional[Union[InterpolatedString, str]] = None
|
59
|
+
client_id_name: Union[InterpolatedString, str] = "client_id"
|
60
|
+
client_secret_name: Union[InterpolatedString, str] = "client_secret"
|
59
61
|
expires_in_name: Union[InterpolatedString, str] = "expires_in"
|
62
|
+
refresh_token_name: Union[InterpolatedString, str] = "refresh_token"
|
60
63
|
refresh_request_body: Optional[Mapping[str, Any]] = None
|
64
|
+
grant_type_name: Union[InterpolatedString, str] = "grant_type"
|
61
65
|
grant_type: Union[InterpolatedString, str] = "refresh_token"
|
62
66
|
message_repository: MessageRepository = NoopMessageRepository()
|
63
67
|
|
@@ -69,8 +73,15 @@ class DeclarativeOauth2Authenticator(AbstractOauth2Authenticator, DeclarativeAut
|
|
69
73
|
)
|
70
74
|
else:
|
71
75
|
self._token_refresh_endpoint = None
|
76
|
+
self._client_id_name = InterpolatedString.create(self.client_id_name, parameters=parameters)
|
72
77
|
self._client_id = InterpolatedString.create(self.client_id, parameters=parameters)
|
78
|
+
self._client_secret_name = InterpolatedString.create(
|
79
|
+
self.client_secret_name, parameters=parameters
|
80
|
+
)
|
73
81
|
self._client_secret = InterpolatedString.create(self.client_secret, parameters=parameters)
|
82
|
+
self._refresh_token_name = InterpolatedString.create(
|
83
|
+
self.refresh_token_name, parameters=parameters
|
84
|
+
)
|
74
85
|
if self.refresh_token is not None:
|
75
86
|
self._refresh_token: Optional[InterpolatedString] = InterpolatedString.create(
|
76
87
|
self.refresh_token, parameters=parameters
|
@@ -83,6 +94,9 @@ class DeclarativeOauth2Authenticator(AbstractOauth2Authenticator, DeclarativeAut
|
|
83
94
|
self.expires_in_name = InterpolatedString.create(
|
84
95
|
self.expires_in_name, parameters=parameters
|
85
96
|
)
|
97
|
+
self.grant_type_name = InterpolatedString.create(
|
98
|
+
self.grant_type_name, parameters=parameters
|
99
|
+
)
|
86
100
|
self.grant_type = InterpolatedString.create(self.grant_type, parameters=parameters)
|
87
101
|
self._refresh_request_body = InterpolatedMapping(
|
88
102
|
self.refresh_request_body or {}, parameters=parameters
|
@@ -122,18 +136,27 @@ class DeclarativeOauth2Authenticator(AbstractOauth2Authenticator, DeclarativeAut
|
|
122
136
|
return refresh_token_endpoint
|
123
137
|
return None
|
124
138
|
|
139
|
+
def get_client_id_name(self) -> str:
|
140
|
+
return self._client_id_name.eval(self.config) # type: ignore # eval returns a string in this context
|
141
|
+
|
125
142
|
def get_client_id(self) -> str:
|
126
143
|
client_id: str = self._client_id.eval(self.config)
|
127
144
|
if not client_id:
|
128
145
|
raise ValueError("OAuthAuthenticator was unable to evaluate client_id parameter")
|
129
146
|
return client_id
|
130
147
|
|
148
|
+
def get_client_secret_name(self) -> str:
|
149
|
+
return self._client_secret_name.eval(self.config) # type: ignore # eval returns a string in this context
|
150
|
+
|
131
151
|
def get_client_secret(self) -> str:
|
132
152
|
client_secret: str = self._client_secret.eval(self.config)
|
133
153
|
if not client_secret:
|
134
154
|
raise ValueError("OAuthAuthenticator was unable to evaluate client_secret parameter")
|
135
155
|
return client_secret
|
136
156
|
|
157
|
+
def get_refresh_token_name(self) -> str:
|
158
|
+
return self._refresh_token_name.eval(self.config) # type: ignore # eval returns a string in this context
|
159
|
+
|
137
160
|
def get_refresh_token(self) -> Optional[str]:
|
138
161
|
return None if self._refresh_token is None else str(self._refresh_token.eval(self.config))
|
139
162
|
|
@@ -146,6 +169,9 @@ class DeclarativeOauth2Authenticator(AbstractOauth2Authenticator, DeclarativeAut
|
|
146
169
|
def get_expires_in_name(self) -> str:
|
147
170
|
return self.expires_in_name.eval(self.config) # type: ignore # eval returns a string in this context
|
148
171
|
|
172
|
+
def get_grant_type_name(self) -> str:
|
173
|
+
return self.grant_type_name.eval(self.config) # type: ignore # eval returns a string in this context
|
174
|
+
|
149
175
|
def get_grant_type(self) -> str:
|
150
176
|
return self.grant_type.eval(self.config) # type: ignore # eval returns a string in this context
|
151
177
|
|
@@ -1047,6 +1047,13 @@ definitions:
|
|
1047
1047
|
type:
|
1048
1048
|
type: string
|
1049
1049
|
enum: [OAuthAuthenticator]
|
1050
|
+
client_id_name:
|
1051
|
+
title: Client ID Property Name
|
1052
|
+
description: The name of the property to use to refresh the `access_token`.
|
1053
|
+
type: string
|
1054
|
+
default: "client_id"
|
1055
|
+
examples:
|
1056
|
+
- custom_app_id
|
1050
1057
|
client_id:
|
1051
1058
|
title: Client ID
|
1052
1059
|
description: The OAuth client ID. Fill it in the user inputs.
|
@@ -1054,6 +1061,13 @@ definitions:
|
|
1054
1061
|
examples:
|
1055
1062
|
- "{{ config['client_id }}"
|
1056
1063
|
- "{{ config['credentials']['client_id }}"
|
1064
|
+
client_secret_name:
|
1065
|
+
title: Client Secret Property Name
|
1066
|
+
description: The name of the property to use to refresh the `access_token`.
|
1067
|
+
type: string
|
1068
|
+
default: "client_secret"
|
1069
|
+
examples:
|
1070
|
+
- custom_app_secret
|
1057
1071
|
client_secret:
|
1058
1072
|
title: Client Secret
|
1059
1073
|
description: The OAuth client secret. Fill it in the user inputs.
|
@@ -1061,6 +1075,13 @@ definitions:
|
|
1061
1075
|
examples:
|
1062
1076
|
- "{{ config['client_secret }}"
|
1063
1077
|
- "{{ config['credentials']['client_secret }}"
|
1078
|
+
refresh_token_name:
|
1079
|
+
title: Refresh Token Property Name
|
1080
|
+
description: The name of the property to use to refresh the `access_token`.
|
1081
|
+
type: string
|
1082
|
+
default: "refresh_token"
|
1083
|
+
examples:
|
1084
|
+
- custom_app_refresh_value
|
1064
1085
|
refresh_token:
|
1065
1086
|
title: Refresh Token
|
1066
1087
|
description: Credential artifact used to get a new access token.
|
@@ -1094,6 +1115,13 @@ definitions:
|
|
1094
1115
|
default: "expires_in"
|
1095
1116
|
examples:
|
1096
1117
|
- expires_in
|
1118
|
+
grant_type_name:
|
1119
|
+
title: Grant Type Property Name
|
1120
|
+
description: The name of the property to use to refresh the `access_token`.
|
1121
|
+
type: string
|
1122
|
+
default: "grant_type"
|
1123
|
+
examples:
|
1124
|
+
- custom_grant_type
|
1097
1125
|
grant_type:
|
1098
1126
|
title: Grant Type
|
1099
1127
|
description: Specifies the OAuth2 grant type. If set to refresh_token, the refresh_token needs to be provided as well. For client_credentials, only client id and secret are required. Other grant types are not officially supported.
|
@@ -2204,15 +2232,15 @@ definitions:
|
|
2204
2232
|
Pertains to the fields defined by the connector relating to the OAuth flow.
|
2205
2233
|
|
2206
2234
|
Interpolation capabilities:
|
2207
|
-
- The variables placeholders are declared as `{my_var}`.
|
2208
|
-
- The nested resolution variables like `{{my_nested_var}}` is allowed as well.
|
2235
|
+
- The variables placeholders are declared as `{{my_var}}`.
|
2236
|
+
- The nested resolution variables like `{{ {{my_nested_var}} }}` is allowed as well.
|
2209
2237
|
|
2210
2238
|
- The allowed interpolation context is:
|
2211
|
-
+ base64Encoder - encode to `base64`, {
|
2212
|
-
+ base64Decorer - decode from `base64` encoded string, {
|
2213
|
-
+ urlEncoder - encode the input string to URL-like format, {
|
2214
|
-
+ urlDecorer - decode the input url-encoded string into text format, {urlDecoder:https%3A%2F%2Fairbyte.io}
|
2215
|
-
+ codeChallengeS256 - get the `codeChallenge` encoded value to provide additional data-provider specific authorisation values, {
|
2239
|
+
+ base64Encoder - encode to `base64`, {{ {{my_var_a}}:{{my_var_b}} | base64Encoder }}
|
2240
|
+
+ base64Decorer - decode from `base64` encoded string, {{ {{my_string_variable_or_string_value}} | base64Decoder }}
|
2241
|
+
+ urlEncoder - encode the input string to URL-like format, {{ https://test.host.com/endpoint | urlEncoder}}
|
2242
|
+
+ urlDecorer - decode the input url-encoded string into text format, {{ urlDecoder:https%3A%2F%2Fairbyte.io | urlDecoder}}
|
2243
|
+
+ codeChallengeS256 - get the `codeChallenge` encoded value to provide additional data-provider specific authorisation values, {{ {{state_value}} | codeChallengeS256 }}
|
2216
2244
|
|
2217
2245
|
Examples:
|
2218
2246
|
- The TikTok Marketing DeclarativeOAuth spec:
|
@@ -2221,12 +2249,12 @@ definitions:
|
|
2221
2249
|
"type": "object",
|
2222
2250
|
"additionalProperties": false,
|
2223
2251
|
"properties": {
|
2224
|
-
"consent_url": "https://ads.tiktok.com/marketing_api/auth?{client_id_key}={{
|
2252
|
+
"consent_url": "https://ads.tiktok.com/marketing_api/auth?{{client_id_key}}={{client_id_value}}&{{redirect_uri_key}}={{ {{redirect_uri_value}} | urlEncoder}}&{{state_key}}={{state_value}}",
|
2225
2253
|
"access_token_url": "https://business-api.tiktok.com/open_api/v1.3/oauth2/access_token/",
|
2226
2254
|
"access_token_params": {
|
2227
|
-
"{auth_code_key}": "{{
|
2228
|
-
"{client_id_key}": "{{
|
2229
|
-
"{client_secret_key}": "{{
|
2255
|
+
"{{ auth_code_key }}": "{{ auth_code_value }}",
|
2256
|
+
"{{ client_id_key }}": "{{ client_id_value }}",
|
2257
|
+
"{{ client_secret_key }}": "{{ client_secret_value }}"
|
2230
2258
|
},
|
2231
2259
|
"access_token_headers": {
|
2232
2260
|
"Content-Type": "application/json",
|
@@ -2244,7 +2272,6 @@ definitions:
|
|
2244
2272
|
required:
|
2245
2273
|
- consent_url
|
2246
2274
|
- access_token_url
|
2247
|
-
- extract_output
|
2248
2275
|
properties:
|
2249
2276
|
consent_url:
|
2250
2277
|
title: Consent URL
|
@@ -2253,8 +2280,8 @@ definitions:
|
|
2253
2280
|
The DeclarativeOAuth Specific string URL string template to initiate the authentication.
|
2254
2281
|
The placeholders are replaced during the processing to provide neccessary values.
|
2255
2282
|
examples:
|
2256
|
-
- https://domain.host.com/marketing_api/auth?{client_id_key}={{
|
2257
|
-
- https://endpoint.host.com/oauth2/authorize?{client_id_key}={{
|
2283
|
+
- https://domain.host.com/marketing_api/auth?{{client_id_key}}={{client_id_value}}&{{redirect_uri_key}}={{{{redirect_uri_value}} | urlEncoder}}&{{state_key}}={{state_value}}
|
2284
|
+
- https://endpoint.host.com/oauth2/authorize?{{client_id_key}}={{client_id_value}}&{{redirect_uri_key}}={{{{redirect_uri_value}} | urlEncoder}}&{{scope_key}}={{{{scope_value}} | urlEncoder}}&{{state_key}}={{state_value}}&subdomain={{subdomain}}
|
2258
2285
|
scope:
|
2259
2286
|
title: Scopes
|
2260
2287
|
type: string
|
@@ -2269,7 +2296,7 @@ definitions:
|
|
2269
2296
|
The DeclarativeOAuth Specific URL templated string to obtain the `access_token`, `refresh_token` etc.
|
2270
2297
|
The placeholders are replaced during the processing to provide neccessary values.
|
2271
2298
|
examples:
|
2272
|
-
- https://auth.host.com/oauth2/token?{client_id_key}={{
|
2299
|
+
- https://auth.host.com/oauth2/token?{{client_id_key}}={{client_id_value}}&{{client_secret_key}}={{client_secret_value}}&{{auth_code_key}}={{auth_code_value}}&{{redirect_uri_key}}={{{{redirect_uri_value}} | urlEncoder}}
|
2273
2300
|
access_token_headers:
|
2274
2301
|
title: Access Token Headers
|
2275
2302
|
type: object
|
@@ -2278,7 +2305,7 @@ definitions:
|
|
2278
2305
|
The DeclarativeOAuth Specific optional headers to inject while exchanging the `auth_code` to `access_token` during `completeOAuthFlow` step.
|
2279
2306
|
examples:
|
2280
2307
|
- {
|
2281
|
-
"Authorization": "Basic {
|
2308
|
+
"Authorization": "Basic {{ {{ client_id_value }}:{{ client_secret_value }} | base64Encoder }}",
|
2282
2309
|
}
|
2283
2310
|
access_token_params:
|
2284
2311
|
title: Access Token Query Params (Json Encoded)
|
@@ -2289,9 +2316,9 @@ definitions:
|
|
2289
2316
|
When this property is provided, the query params will be encoded as `Json` and included in the outgoing API request.
|
2290
2317
|
examples:
|
2291
2318
|
- {
|
2292
|
-
"{auth_code_key}": "{{
|
2293
|
-
"{client_id_key}": "{{
|
2294
|
-
"{client_secret_key}": "{{
|
2319
|
+
"{{ auth_code_key }}": "{{ auth_code_value }}",
|
2320
|
+
"{{ client_id_key }}": "{{ client_id_value }}",
|
2321
|
+
"{{ client_secret_key }}": "{{ client_secret_value }}",
|
2295
2322
|
}
|
2296
2323
|
extract_output:
|
2297
2324
|
title: Extract Output
|
@@ -2977,6 +3004,11 @@ definitions:
|
|
2977
3004
|
anyOf:
|
2978
3005
|
- "$ref": "#/definitions/CustomRequester"
|
2979
3006
|
- "$ref": "#/definitions/HttpRequester"
|
3007
|
+
url_requester:
|
3008
|
+
description: Requester component that describes how to prepare HTTP requests to send to the source API to extract the url from polling response by the completed async job.
|
3009
|
+
anyOf:
|
3010
|
+
- "$ref": "#/definitions/CustomRequester"
|
3011
|
+
- "$ref": "#/definitions/HttpRequester"
|
2980
3012
|
download_requester:
|
2981
3013
|
description: Requester component that describes how to prepare HTTP requests to send to the source API to download the data provided by the completed async job.
|
2982
3014
|
anyOf:
|
@@ -481,12 +481,24 @@ class RefreshTokenUpdater(BaseModel):
|
|
481
481
|
|
482
482
|
class OAuthAuthenticator(BaseModel):
|
483
483
|
type: Literal["OAuthAuthenticator"]
|
484
|
+
client_id_name: Optional[str] = Field(
|
485
|
+
"client_id",
|
486
|
+
description="The name of the property to use to refresh the `access_token`.",
|
487
|
+
examples=["custom_app_id"],
|
488
|
+
title="Client ID Property Name",
|
489
|
+
)
|
484
490
|
client_id: str = Field(
|
485
491
|
...,
|
486
492
|
description="The OAuth client ID. Fill it in the user inputs.",
|
487
493
|
examples=["{{ config['client_id }}", "{{ config['credentials']['client_id }}"],
|
488
494
|
title="Client ID",
|
489
495
|
)
|
496
|
+
client_secret_name: Optional[str] = Field(
|
497
|
+
"client_secret",
|
498
|
+
description="The name of the property to use to refresh the `access_token`.",
|
499
|
+
examples=["custom_app_secret"],
|
500
|
+
title="Client Secret Property Name",
|
501
|
+
)
|
490
502
|
client_secret: str = Field(
|
491
503
|
...,
|
492
504
|
description="The OAuth client secret. Fill it in the user inputs.",
|
@@ -496,6 +508,12 @@ class OAuthAuthenticator(BaseModel):
|
|
496
508
|
],
|
497
509
|
title="Client Secret",
|
498
510
|
)
|
511
|
+
refresh_token_name: Optional[str] = Field(
|
512
|
+
"refresh_token",
|
513
|
+
description="The name of the property to use to refresh the `access_token`.",
|
514
|
+
examples=["custom_app_refresh_value"],
|
515
|
+
title="Refresh Token Property Name",
|
516
|
+
)
|
499
517
|
refresh_token: Optional[str] = Field(
|
500
518
|
None,
|
501
519
|
description="Credential artifact used to get a new access token.",
|
@@ -529,6 +547,12 @@ class OAuthAuthenticator(BaseModel):
|
|
529
547
|
examples=["expires_in"],
|
530
548
|
title="Token Expiry Property Name",
|
531
549
|
)
|
550
|
+
grant_type_name: Optional[str] = Field(
|
551
|
+
"grant_type",
|
552
|
+
description="The name of the property to use to refresh the `access_token`.",
|
553
|
+
examples=["custom_grant_type"],
|
554
|
+
title="Grant Type Property Name",
|
555
|
+
)
|
532
556
|
grant_type: Optional[str] = Field(
|
533
557
|
"refresh_token",
|
534
558
|
description="Specifies the OAuth2 grant type. If set to refresh_token, the refresh_token needs to be provided as well. For client_credentials, only client id and secret are required. Other grant types are not officially supported.",
|
@@ -737,33 +761,43 @@ class KeysToSnakeCase(BaseModel):
|
|
737
761
|
parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")
|
738
762
|
|
739
763
|
|
764
|
+
class FlattenFields(BaseModel):
|
765
|
+
type: Literal["FlattenFields"]
|
766
|
+
flatten_lists: Optional[bool] = Field(
|
767
|
+
True,
|
768
|
+
description="Whether to flatten lists or leave it as is. Default is True.",
|
769
|
+
title="Flatten Lists",
|
770
|
+
)
|
771
|
+
parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")
|
772
|
+
|
773
|
+
|
740
774
|
class KeysReplace(BaseModel):
|
741
775
|
type: Literal["KeysReplace"]
|
742
776
|
old: str = Field(
|
743
777
|
...,
|
744
778
|
description="Old value to replace.",
|
745
|
-
examples=[
|
779
|
+
examples=[
|
780
|
+
" ",
|
781
|
+
"{{ record.id }}",
|
782
|
+
"{{ config['id'] }}",
|
783
|
+
"{{ stream_slice['id'] }}",
|
784
|
+
],
|
746
785
|
title="Old value",
|
747
786
|
)
|
748
787
|
new: str = Field(
|
749
788
|
...,
|
750
789
|
description="New value to set.",
|
751
|
-
examples=[
|
790
|
+
examples=[
|
791
|
+
"_",
|
792
|
+
"{{ record.id }}",
|
793
|
+
"{{ config['id'] }}",
|
794
|
+
"{{ stream_slice['id'] }}",
|
795
|
+
],
|
752
796
|
title="New value",
|
753
797
|
)
|
754
798
|
parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")
|
755
799
|
|
756
800
|
|
757
|
-
class FlattenFields(BaseModel):
|
758
|
-
type: Literal["FlattenFields"]
|
759
|
-
flatten_lists: Optional[bool] = Field(
|
760
|
-
True,
|
761
|
-
description="Whether to flatten lists or leave it as is. Default is True.",
|
762
|
-
title="Flatten Lists",
|
763
|
-
)
|
764
|
-
parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")
|
765
|
-
|
766
|
-
|
767
801
|
class IterableDecoder(BaseModel):
|
768
802
|
type: Literal["IterableDecoder"]
|
769
803
|
|
@@ -849,8 +883,8 @@ class OauthConnectorInputSpecification(BaseModel):
|
|
849
883
|
...,
|
850
884
|
description="The DeclarativeOAuth Specific string URL string template to initiate the authentication.\nThe placeholders are replaced during the processing to provide neccessary values.",
|
851
885
|
examples=[
|
852
|
-
"https://domain.host.com/marketing_api/auth?{client_id_key}={{
|
853
|
-
"https://endpoint.host.com/oauth2/authorize?{client_id_key}={{
|
886
|
+
"https://domain.host.com/marketing_api/auth?{{client_id_key}}={{client_id_value}}&{{redirect_uri_key}}={{{{redirect_uri_value}} | urlEncoder}}&{{state_key}}={{state_value}}",
|
887
|
+
"https://endpoint.host.com/oauth2/authorize?{{client_id_key}}={{client_id_value}}&{{redirect_uri_key}}={{{{redirect_uri_value}} | urlEncoder}}&{{scope_key}}={{{{scope_value}} | urlEncoder}}&{{state_key}}={{state_value}}&subdomain={{subdomain}}",
|
854
888
|
],
|
855
889
|
title="Consent URL",
|
856
890
|
)
|
@@ -864,14 +898,18 @@ class OauthConnectorInputSpecification(BaseModel):
|
|
864
898
|
...,
|
865
899
|
description="The DeclarativeOAuth Specific URL templated string to obtain the `access_token`, `refresh_token` etc.\nThe placeholders are replaced during the processing to provide neccessary values.",
|
866
900
|
examples=[
|
867
|
-
"https://auth.host.com/oauth2/token?{client_id_key}={{
|
901
|
+
"https://auth.host.com/oauth2/token?{{client_id_key}}={{client_id_value}}&{{client_secret_key}}={{client_secret_value}}&{{auth_code_key}}={{auth_code_value}}&{{redirect_uri_key}}={{{{redirect_uri_value}} | urlEncoder}}"
|
868
902
|
],
|
869
903
|
title="Access Token URL",
|
870
904
|
)
|
871
905
|
access_token_headers: Optional[Dict[str, Any]] = Field(
|
872
906
|
None,
|
873
907
|
description="The DeclarativeOAuth Specific optional headers to inject while exchanging the `auth_code` to `access_token` during `completeOAuthFlow` step.",
|
874
|
-
examples=[
|
908
|
+
examples=[
|
909
|
+
{
|
910
|
+
"Authorization": "Basic {{ {{ client_id_value }}:{{ client_secret_value }} | base64Encoder }}"
|
911
|
+
}
|
912
|
+
],
|
875
913
|
title="Access Token Headers",
|
876
914
|
)
|
877
915
|
access_token_params: Optional[Dict[str, Any]] = Field(
|
@@ -879,15 +917,15 @@ class OauthConnectorInputSpecification(BaseModel):
|
|
879
917
|
description="The DeclarativeOAuth Specific optional query parameters to inject while exchanging the `auth_code` to `access_token` during `completeOAuthFlow` step.\nWhen this property is provided, the query params will be encoded as `Json` and included in the outgoing API request.",
|
880
918
|
examples=[
|
881
919
|
{
|
882
|
-
"{auth_code_key}": "{{
|
883
|
-
"{client_id_key}": "{{
|
884
|
-
"{client_secret_key}": "{{
|
920
|
+
"{{ auth_code_key }}": "{{ auth_code_value }}",
|
921
|
+
"{{ client_id_key }}": "{{ client_id_value }}",
|
922
|
+
"{{ client_secret_key }}": "{{ client_secret_value }}",
|
885
923
|
}
|
886
924
|
],
|
887
925
|
title="Access Token Query Params (Json Encoded)",
|
888
926
|
)
|
889
|
-
extract_output: List[str] = Field(
|
890
|
-
|
927
|
+
extract_output: Optional[List[str]] = Field(
|
928
|
+
None,
|
891
929
|
description="The DeclarativeOAuth Specific list of strings to indicate which keys should be extracted and returned back to the input config.",
|
892
930
|
examples=[["access_token", "refresh_token", "other_field"]],
|
893
931
|
title="Extract Output",
|
@@ -956,7 +994,7 @@ class OAuthConfigSpecification(BaseModel):
|
|
956
994
|
)
|
957
995
|
oauth_connector_input_specification: Optional[OauthConnectorInputSpecification] = Field(
|
958
996
|
None,
|
959
|
-
description='The DeclarativeOAuth specific blob.\nPertains to the fields defined by the connector relating to the OAuth flow.\n\nInterpolation capabilities:\n- The variables placeholders are declared as `{my_var}`.\n- The nested resolution variables like `{{my_nested_var}}` is allowed as well.\n\n- The allowed interpolation context is:\n + base64Encoder - encode to `base64`, {
|
997
|
+
description='The DeclarativeOAuth specific blob.\nPertains to the fields defined by the connector relating to the OAuth flow.\n\nInterpolation capabilities:\n- The variables placeholders are declared as `{{my_var}}`.\n- The nested resolution variables like `{{ {{my_nested_var}} }}` is allowed as well.\n\n- The allowed interpolation context is:\n + base64Encoder - encode to `base64`, {{ {{my_var_a}}:{{my_var_b}} | base64Encoder }}\n + base64Decorer - decode from `base64` encoded string, {{ {{my_string_variable_or_string_value}} | base64Decoder }}\n + urlEncoder - encode the input string to URL-like format, {{ https://test.host.com/endpoint | urlEncoder}}\n + urlDecorer - decode the input url-encoded string into text format, {{ urlDecoder:https%3A%2F%2Fairbyte.io | urlDecoder}}\n + codeChallengeS256 - get the `codeChallenge` encoded value to provide additional data-provider specific authorisation values, {{ {{state_value}} | codeChallengeS256 }}\n\nExamples:\n - The TikTok Marketing DeclarativeOAuth spec:\n {\n "oauth_connector_input_specification": {\n "type": "object",\n "additionalProperties": false,\n "properties": {\n "consent_url": "https://ads.tiktok.com/marketing_api/auth?{{client_id_key}}={{client_id_value}}&{{redirect_uri_key}}={{ {{redirect_uri_value}} | urlEncoder}}&{{state_key}}={{state_value}}",\n "access_token_url": "https://business-api.tiktok.com/open_api/v1.3/oauth2/access_token/",\n "access_token_params": {\n "{{ auth_code_key }}": "{{ auth_code_value }}",\n "{{ client_id_key }}": "{{ client_id_value }}",\n "{{ client_secret_key }}": "{{ client_secret_value }}"\n },\n "access_token_headers": {\n "Content-Type": "application/json",\n "Accept": "application/json"\n },\n "extract_output": ["data.access_token"],\n "client_id_key": "app_id",\n "client_secret_key": "secret",\n "auth_code_key": "auth_code"\n }\n }\n }',
|
960
998
|
title="DeclarativeOAuth Connector Specification",
|
961
999
|
)
|
962
1000
|
complete_oauth_output_specification: Optional[Dict[str, Any]] = Field(
|
@@ -2040,6 +2078,10 @@ class AsyncRetriever(BaseModel):
|
|
2040
2078
|
...,
|
2041
2079
|
description="Requester component that describes how to prepare HTTP requests to send to the source API to fetch the status of the running async job.",
|
2042
2080
|
)
|
2081
|
+
url_requester: Optional[Union[CustomRequester, HttpRequester]] = Field(
|
2082
|
+
None,
|
2083
|
+
description="Requester component that describes how to prepare HTTP requests to send to the source API to extract the url from polling response by the completed async job.",
|
2084
|
+
)
|
2043
2085
|
download_requester: Union[CustomRequester, HttpRequester] = Field(
|
2044
2086
|
...,
|
2045
2087
|
description="Requester component that describes how to prepare HTTP requests to send to the source API to download the data provided by the completed async job.",
|
@@ -1885,15 +1885,24 @@ class ModelToComponentFactory:
|
|
1885
1885
|
expires_in_name=InterpolatedString.create(
|
1886
1886
|
model.expires_in_name or "expires_in", parameters=model.parameters or {}
|
1887
1887
|
).eval(config),
|
1888
|
+
client_id_name=InterpolatedString.create(
|
1889
|
+
model.client_id_name or "client_id", parameters=model.parameters or {}
|
1890
|
+
).eval(config),
|
1888
1891
|
client_id=InterpolatedString.create(
|
1889
1892
|
model.client_id, parameters=model.parameters or {}
|
1890
1893
|
).eval(config),
|
1894
|
+
client_secret_name=InterpolatedString.create(
|
1895
|
+
model.client_secret_name or "client_secret", parameters=model.parameters or {}
|
1896
|
+
).eval(config),
|
1891
1897
|
client_secret=InterpolatedString.create(
|
1892
1898
|
model.client_secret, parameters=model.parameters or {}
|
1893
1899
|
).eval(config),
|
1894
1900
|
access_token_config_path=model.refresh_token_updater.access_token_config_path,
|
1895
1901
|
refresh_token_config_path=model.refresh_token_updater.refresh_token_config_path,
|
1896
1902
|
token_expiry_date_config_path=model.refresh_token_updater.token_expiry_date_config_path,
|
1903
|
+
grant_type_name=InterpolatedString.create(
|
1904
|
+
model.grant_type_name or "grant_type", parameters=model.parameters or {}
|
1905
|
+
).eval(config),
|
1897
1906
|
grant_type=InterpolatedString.create(
|
1898
1907
|
model.grant_type or "refresh_token", parameters=model.parameters or {}
|
1899
1908
|
).eval(config),
|
@@ -1911,11 +1920,15 @@ class ModelToComponentFactory:
|
|
1911
1920
|
return DeclarativeOauth2Authenticator( # type: ignore
|
1912
1921
|
access_token_name=model.access_token_name or "access_token",
|
1913
1922
|
access_token_value=model.access_token_value,
|
1923
|
+
client_id_name=model.client_id_name or "client_id",
|
1914
1924
|
client_id=model.client_id,
|
1925
|
+
client_secret_name=model.client_secret_name or "client_secret",
|
1915
1926
|
client_secret=model.client_secret,
|
1916
1927
|
expires_in_name=model.expires_in_name or "expires_in",
|
1928
|
+
grant_type_name=model.grant_type_name or "grant_type",
|
1917
1929
|
grant_type=model.grant_type or "refresh_token",
|
1918
1930
|
refresh_request_body=model.refresh_request_body,
|
1931
|
+
refresh_token_name=model.refresh_token_name or "refresh_token",
|
1919
1932
|
refresh_token=model.refresh_token,
|
1920
1933
|
scopes=model.scopes,
|
1921
1934
|
token_expiry_date=model.token_expiry_date,
|
@@ -2287,7 +2300,7 @@ class ModelToComponentFactory:
|
|
2287
2300
|
extractor=download_extractor,
|
2288
2301
|
name=name,
|
2289
2302
|
record_filter=None,
|
2290
|
-
transformations=
|
2303
|
+
transformations=transformations,
|
2291
2304
|
schema_normalization=TypeTransformer(TransformConfig.NoTransform),
|
2292
2305
|
config=config,
|
2293
2306
|
parameters={},
|
@@ -2324,6 +2337,16 @@ class ModelToComponentFactory:
|
|
2324
2337
|
if model.delete_requester
|
2325
2338
|
else None
|
2326
2339
|
)
|
2340
|
+
url_requester = (
|
2341
|
+
self._create_component_from_model(
|
2342
|
+
model=model.url_requester,
|
2343
|
+
decoder=decoder,
|
2344
|
+
config=config,
|
2345
|
+
name=f"job extract_url - {name}",
|
2346
|
+
)
|
2347
|
+
if model.url_requester
|
2348
|
+
else None
|
2349
|
+
)
|
2327
2350
|
status_extractor = self._create_component_from_model(
|
2328
2351
|
model=model.status_extractor, decoder=decoder, config=config, name=name
|
2329
2352
|
)
|
@@ -2334,6 +2357,7 @@ class ModelToComponentFactory:
|
|
2334
2357
|
creation_requester=creation_requester,
|
2335
2358
|
polling_requester=polling_requester,
|
2336
2359
|
download_retriever=download_retriever,
|
2360
|
+
url_requester=url_requester,
|
2337
2361
|
abort_requester=abort_requester,
|
2338
2362
|
delete_requester=delete_requester,
|
2339
2363
|
status_extractor=status_extractor,
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# AsyncHttpJobRepository sequence diagram
|
2
|
+
|
3
|
+
- Components marked as optional are not required and can be ignored.
|
4
|
+
- if `url_requester` is not provided, `urls_extractor` will get urls from the `polling_job_response`
|
5
|
+
- interpolation_context, e.g. `create_job_response` or `polling_job_response` can be obtained from stream_slice
|
6
|
+
|
7
|
+
|
8
|
+
```mermaid
|
9
|
+
---
|
10
|
+
title: AsyncHttpJobRepository Sequence Diagram
|
11
|
+
---
|
12
|
+
sequenceDiagram
|
13
|
+
participant AsyncHttpJobRepository as AsyncOrchestrator
|
14
|
+
participant CreationRequester as creation_requester
|
15
|
+
participant PollingRequester as polling_requester
|
16
|
+
participant UrlRequester as url_requester (Optional)
|
17
|
+
participant DownloadRetriever as download_retriever
|
18
|
+
participant AbortRequester as abort_requester (Optional)
|
19
|
+
participant DeleteRequester as delete_requester (Optional)
|
20
|
+
participant Reporting Server as Async Reporting Server
|
21
|
+
|
22
|
+
AsyncHttpJobRepository ->> CreationRequester: Initiate job creation
|
23
|
+
CreationRequester ->> Reporting Server: Create job request
|
24
|
+
Reporting Server -->> CreationRequester: Job ID response
|
25
|
+
CreationRequester -->> AsyncHttpJobRepository: Job ID
|
26
|
+
|
27
|
+
loop Poll for job status
|
28
|
+
AsyncHttpJobRepository ->> PollingRequester: Check job status
|
29
|
+
PollingRequester ->> Reporting Server: Status request (interpolation_context: `create_job_response`)
|
30
|
+
Reporting Server -->> PollingRequester: Status response
|
31
|
+
PollingRequester -->> AsyncHttpJobRepository: Job status
|
32
|
+
end
|
33
|
+
|
34
|
+
alt Status: Ready
|
35
|
+
AsyncHttpJobRepository ->> UrlRequester: Request download URLs (if applicable)
|
36
|
+
UrlRequester ->> Reporting Server: URL request (interpolation_context: `polling_job_response`)
|
37
|
+
Reporting Server -->> UrlRequester: Download URLs
|
38
|
+
UrlRequester -->> AsyncHttpJobRepository: Download URLs
|
39
|
+
|
40
|
+
AsyncHttpJobRepository ->> DownloadRetriever: Download reports
|
41
|
+
DownloadRetriever ->> Reporting Server: Retrieve report data (interpolation_context: `url`)
|
42
|
+
Reporting Server -->> DownloadRetriever: Report data
|
43
|
+
DownloadRetriever -->> AsyncHttpJobRepository: Report data
|
44
|
+
else Status: Failed
|
45
|
+
AsyncHttpJobRepository ->> AbortRequester: Send abort request
|
46
|
+
AbortRequester ->> Reporting Server: Abort job
|
47
|
+
Reporting Server -->> AbortRequester: Abort confirmation
|
48
|
+
AbortRequester -->> AsyncHttpJobRepository: Confirmation
|
49
|
+
end
|
50
|
+
|
51
|
+
AsyncHttpJobRepository ->> DeleteRequester: Send delete job request
|
52
|
+
DeleteRequester ->> Reporting Server: Delete job
|
53
|
+
Reporting Server -->> DeleteRequester: Deletion confirmation
|
54
|
+
DeleteRequester -->> AsyncHttpJobRepository: Confirmation
|
55
|
+
|
56
|
+
|
57
|
+
```
|
@@ -31,6 +31,10 @@ LOGGER = logging.getLogger("airbyte")
|
|
31
31
|
|
32
32
|
@dataclass
|
33
33
|
class AsyncHttpJobRepository(AsyncJobRepository):
|
34
|
+
"""
|
35
|
+
See Readme file for more details about flow.
|
36
|
+
"""
|
37
|
+
|
34
38
|
creation_requester: Requester
|
35
39
|
polling_requester: Requester
|
36
40
|
download_retriever: SimpleRetriever
|
@@ -44,6 +48,9 @@ class AsyncHttpJobRepository(AsyncJobRepository):
|
|
44
48
|
record_extractor: RecordExtractor = field(
|
45
49
|
init=False, repr=False, default_factory=lambda: ResponseToFileExtractor({})
|
46
50
|
)
|
51
|
+
url_requester: Optional[Requester] = (
|
52
|
+
None # use it in case polling_requester provides some <id> and extra request is needed to obtain list of urls to download from
|
53
|
+
)
|
47
54
|
|
48
55
|
def __post_init__(self) -> None:
|
49
56
|
self._create_job_response_by_id: Dict[str, Response] = {}
|
@@ -186,10 +193,13 @@ class AsyncHttpJobRepository(AsyncJobRepository):
|
|
186
193
|
|
187
194
|
"""
|
188
195
|
|
189
|
-
for url in self.
|
190
|
-
|
191
|
-
|
192
|
-
|
196
|
+
for url in self._get_download_url(job):
|
197
|
+
job_slice = job.job_parameters()
|
198
|
+
stream_slice = StreamSlice(
|
199
|
+
partition=job_slice.partition,
|
200
|
+
cursor_slice=job_slice.cursor_slice,
|
201
|
+
extra_fields={**job_slice.extra_fields, "url": url},
|
202
|
+
)
|
193
203
|
for message in self.download_retriever.read_records({}, stream_slice):
|
194
204
|
if isinstance(message, Record):
|
195
205
|
yield message.data
|
@@ -226,3 +236,22 @@ class AsyncHttpJobRepository(AsyncJobRepository):
|
|
226
236
|
cursor_slice={},
|
227
237
|
)
|
228
238
|
return stream_slice
|
239
|
+
|
240
|
+
def _get_download_url(self, job: AsyncJob) -> Iterable[str]:
|
241
|
+
if not self.url_requester:
|
242
|
+
url_response = self._polling_job_response_by_id[job.api_job_id()]
|
243
|
+
else:
|
244
|
+
stream_slice: StreamSlice = StreamSlice(
|
245
|
+
partition={
|
246
|
+
"polling_job_response": self._polling_job_response_by_id[job.api_job_id()]
|
247
|
+
},
|
248
|
+
cursor_slice={},
|
249
|
+
)
|
250
|
+
url_response = self.url_requester.send_request(stream_slice=stream_slice) # type: ignore # we expect url_requester to always be presented, otherwise raise an exception as we cannot proceed with the report
|
251
|
+
if not url_response:
|
252
|
+
raise AirbyteTracedException(
|
253
|
+
internal_message="Always expect a response or an exception from url_requester",
|
254
|
+
failure_type=FailureType.system_error,
|
255
|
+
)
|
256
|
+
|
257
|
+
yield from self.urls_extractor.extract_records(url_response) # type: ignore # we expect urls_extractor to always return list of strings
|
@@ -43,31 +43,34 @@ unstructured_partition_pdf = None
|
|
43
43
|
unstructured_partition_docx = None
|
44
44
|
unstructured_partition_pptx = None
|
45
45
|
|
46
|
+
AIRBYTE_NLTK_DATA_DIR = "/airbyte/nltk_data"
|
47
|
+
TMP_NLTK_DATA_DIR = "/tmp/nltk_data"
|
46
48
|
|
47
|
-
|
49
|
+
|
50
|
+
def get_nltk_temp_folder() -> str:
|
48
51
|
"""
|
49
52
|
For non-root connectors /tmp is not currently writable, but we should allow it in the future.
|
50
53
|
It's safe to use /airbyte for now. Fallback to /tmp for local development.
|
51
54
|
"""
|
52
55
|
try:
|
53
|
-
nltk_data_dir =
|
56
|
+
nltk_data_dir = AIRBYTE_NLTK_DATA_DIR
|
54
57
|
os.makedirs(nltk_data_dir, exist_ok=True)
|
55
58
|
except OSError:
|
56
|
-
nltk_data_dir =
|
59
|
+
nltk_data_dir = TMP_NLTK_DATA_DIR
|
57
60
|
os.makedirs(nltk_data_dir, exist_ok=True)
|
58
61
|
return nltk_data_dir
|
59
62
|
|
60
63
|
|
61
64
|
try:
|
62
|
-
nltk_data_dir =
|
65
|
+
nltk_data_dir = get_nltk_temp_folder()
|
63
66
|
nltk.data.path.append(nltk_data_dir)
|
64
67
|
nltk.data.find("tokenizers/punkt.zip")
|
65
68
|
nltk.data.find("tokenizers/punkt_tab.zip")
|
66
69
|
nltk.data.find("tokenizers/averaged_perceptron_tagger_eng.zip")
|
67
70
|
except LookupError:
|
68
|
-
nltk.download("punkt", download_dir=nltk_data_dir)
|
69
|
-
nltk.download("punkt_tab", download_dir=nltk_data_dir)
|
70
|
-
nltk.download("averaged_perceptron_tagger_eng", download_dir=nltk_data_dir)
|
71
|
+
nltk.download("punkt", download_dir=nltk_data_dir, quiet=True)
|
72
|
+
nltk.download("punkt_tab", download_dir=nltk_data_dir, quiet=True)
|
73
|
+
nltk.download("averaged_perceptron_tagger_eng", download_dir=nltk_data_dir, quiet=True)
|
71
74
|
|
72
75
|
|
73
76
|
def optional_decode(contents: Union[str, bytes]) -> str:
|
@@ -81,10 +81,10 @@ class AbstractOauth2Authenticator(AuthBase):
|
|
81
81
|
Override to define additional parameters
|
82
82
|
"""
|
83
83
|
payload: MutableMapping[str, Any] = {
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
84
|
+
self.get_grant_type_name(): self.get_grant_type(),
|
85
|
+
self.get_client_id_name(): self.get_client_id(),
|
86
|
+
self.get_client_secret_name(): self.get_client_secret(),
|
87
|
+
self.get_refresh_token_name(): self.get_refresh_token(),
|
88
88
|
}
|
89
89
|
|
90
90
|
if self.get_scopes():
|
@@ -206,14 +206,26 @@ class AbstractOauth2Authenticator(AuthBase):
|
|
206
206
|
def get_token_refresh_endpoint(self) -> Optional[str]:
|
207
207
|
"""Returns the endpoint to refresh the access token"""
|
208
208
|
|
209
|
+
@abstractmethod
|
210
|
+
def get_client_id_name(self) -> str:
|
211
|
+
"""The client id name to authenticate"""
|
212
|
+
|
209
213
|
@abstractmethod
|
210
214
|
def get_client_id(self) -> str:
|
211
215
|
"""The client id to authenticate"""
|
212
216
|
|
217
|
+
@abstractmethod
|
218
|
+
def get_client_secret_name(self) -> str:
|
219
|
+
"""The client secret name to authenticate"""
|
220
|
+
|
213
221
|
@abstractmethod
|
214
222
|
def get_client_secret(self) -> str:
|
215
223
|
"""The client secret to authenticate"""
|
216
224
|
|
225
|
+
@abstractmethod
|
226
|
+
def get_refresh_token_name(self) -> str:
|
227
|
+
"""The refresh token name to authenticate"""
|
228
|
+
|
217
229
|
@abstractmethod
|
218
230
|
def get_refresh_token(self) -> Optional[str]:
|
219
231
|
"""The token used to refresh the access token when it expires"""
|
@@ -246,6 +258,10 @@ class AbstractOauth2Authenticator(AuthBase):
|
|
246
258
|
def get_grant_type(self) -> str:
|
247
259
|
"""Returns grant_type specified for requesting access_token"""
|
248
260
|
|
261
|
+
@abstractmethod
|
262
|
+
def get_grant_type_name(self) -> str:
|
263
|
+
"""Returns grant_type specified name for requesting access_token"""
|
264
|
+
|
249
265
|
@property
|
250
266
|
@abstractmethod
|
251
267
|
def access_token(self) -> str:
|
@@ -30,12 +30,16 @@ class Oauth2Authenticator(AbstractOauth2Authenticator):
|
|
30
30
|
client_id: str,
|
31
31
|
client_secret: str,
|
32
32
|
refresh_token: str,
|
33
|
+
client_id_name: str = "client_id",
|
34
|
+
client_secret_name: str = "client_secret",
|
35
|
+
refresh_token_name: str = "refresh_token",
|
33
36
|
scopes: List[str] | None = None,
|
34
37
|
token_expiry_date: pendulum.DateTime | None = None,
|
35
38
|
token_expiry_date_format: str | None = None,
|
36
39
|
access_token_name: str = "access_token",
|
37
40
|
expires_in_name: str = "expires_in",
|
38
41
|
refresh_request_body: Mapping[str, Any] | None = None,
|
42
|
+
grant_type_name: str = "grant_type",
|
39
43
|
grant_type: str = "refresh_token",
|
40
44
|
token_expiry_is_time_of_expiration: bool = False,
|
41
45
|
refresh_token_error_status_codes: Tuple[int, ...] = (),
|
@@ -43,13 +47,17 @@ class Oauth2Authenticator(AbstractOauth2Authenticator):
|
|
43
47
|
refresh_token_error_values: Tuple[str, ...] = (),
|
44
48
|
):
|
45
49
|
self._token_refresh_endpoint = token_refresh_endpoint
|
50
|
+
self._client_secret_name = client_secret_name
|
46
51
|
self._client_secret = client_secret
|
52
|
+
self._client_id_name = client_id_name
|
47
53
|
self._client_id = client_id
|
54
|
+
self._refresh_token_name = refresh_token_name
|
48
55
|
self._refresh_token = refresh_token
|
49
56
|
self._scopes = scopes
|
50
57
|
self._access_token_name = access_token_name
|
51
58
|
self._expires_in_name = expires_in_name
|
52
59
|
self._refresh_request_body = refresh_request_body
|
60
|
+
self._grant_type_name = grant_type_name
|
53
61
|
self._grant_type = grant_type
|
54
62
|
|
55
63
|
self._token_expiry_date = token_expiry_date or pendulum.now().subtract(days=1) # type: ignore [no-untyped-call]
|
@@ -63,12 +71,21 @@ class Oauth2Authenticator(AbstractOauth2Authenticator):
|
|
63
71
|
def get_token_refresh_endpoint(self) -> str:
|
64
72
|
return self._token_refresh_endpoint
|
65
73
|
|
74
|
+
def get_client_id_name(self) -> str:
|
75
|
+
return self._client_id_name
|
76
|
+
|
66
77
|
def get_client_id(self) -> str:
|
67
78
|
return self._client_id
|
68
79
|
|
80
|
+
def get_client_secret_name(self) -> str:
|
81
|
+
return self._client_secret_name
|
82
|
+
|
69
83
|
def get_client_secret(self) -> str:
|
70
84
|
return self._client_secret
|
71
85
|
|
86
|
+
def get_refresh_token_name(self) -> str:
|
87
|
+
return self._refresh_token_name
|
88
|
+
|
72
89
|
def get_refresh_token(self) -> str:
|
73
90
|
return self._refresh_token
|
74
91
|
|
@@ -84,6 +101,9 @@ class Oauth2Authenticator(AbstractOauth2Authenticator):
|
|
84
101
|
def get_refresh_request_body(self) -> Mapping[str, Any]:
|
85
102
|
return self._refresh_request_body # type: ignore [return-value]
|
86
103
|
|
104
|
+
def get_grant_type_name(self) -> str:
|
105
|
+
return self._grant_type_name
|
106
|
+
|
87
107
|
def get_grant_type(self) -> str:
|
88
108
|
return self._grant_type
|
89
109
|
|
@@ -129,8 +149,11 @@ class SingleUseRefreshTokenOauth2Authenticator(Oauth2Authenticator):
|
|
129
149
|
expires_in_name: str = "expires_in",
|
130
150
|
refresh_token_name: str = "refresh_token",
|
131
151
|
refresh_request_body: Mapping[str, Any] | None = None,
|
152
|
+
grant_type_name: str = "grant_type",
|
132
153
|
grant_type: str = "refresh_token",
|
154
|
+
client_id_name: str = "client_id",
|
133
155
|
client_id: Optional[str] = None,
|
156
|
+
client_secret_name: str = "client_secret",
|
134
157
|
client_secret: Optional[str] = None,
|
135
158
|
access_token_config_path: Sequence[str] = ("credentials", "access_token"),
|
136
159
|
refresh_token_config_path: Sequence[str] = ("credentials", "refresh_token"),
|
@@ -174,23 +197,30 @@ class SingleUseRefreshTokenOauth2Authenticator(Oauth2Authenticator):
|
|
174
197
|
("credentials", "client_secret"),
|
175
198
|
)
|
176
199
|
)
|
200
|
+
self._client_id_name = client_id_name
|
201
|
+
self._client_secret_name = client_secret_name
|
177
202
|
self._access_token_config_path = access_token_config_path
|
178
203
|
self._refresh_token_config_path = refresh_token_config_path
|
179
204
|
self._token_expiry_date_config_path = token_expiry_date_config_path
|
180
205
|
self._token_expiry_date_format = token_expiry_date_format
|
181
206
|
self._refresh_token_name = refresh_token_name
|
207
|
+
self._grant_type_name = grant_type_name
|
182
208
|
self._connector_config = connector_config
|
183
209
|
self.__message_repository = message_repository
|
184
210
|
super().__init__(
|
185
|
-
token_refresh_endpoint,
|
186
|
-
self.
|
187
|
-
self.
|
188
|
-
self.
|
211
|
+
token_refresh_endpoint=token_refresh_endpoint,
|
212
|
+
client_id_name=self._client_id_name,
|
213
|
+
client_id=self.get_client_id(),
|
214
|
+
client_secret_name=self._client_secret_name,
|
215
|
+
client_secret=self.get_client_secret(),
|
216
|
+
refresh_token=self.get_refresh_token(),
|
217
|
+
refresh_token_name=self._refresh_token_name,
|
189
218
|
scopes=scopes,
|
190
219
|
token_expiry_date=self.get_token_expiry_date(),
|
191
220
|
access_token_name=access_token_name,
|
192
221
|
expires_in_name=expires_in_name,
|
193
222
|
refresh_request_body=refresh_request_body,
|
223
|
+
grant_type_name=self._grant_type_name,
|
194
224
|
grant_type=grant_type,
|
195
225
|
token_expiry_date_format=token_expiry_date_format,
|
196
226
|
token_expiry_is_time_of_expiration=token_expiry_is_time_of_expiration,
|
airbyte_cdk/sources/types.py
CHANGED
@@ -53,7 +53,7 @@ airbyte_cdk/sources/declarative/async_job/timer.py,sha256=Fb8P72CQ7jIzJyzMSSNuBf
|
|
53
53
|
airbyte_cdk/sources/declarative/auth/__init__.py,sha256=e2CRrcBWGhz3sQu3Oh34d1riEIwXipGS8hrSB1pu0Oo,284
|
54
54
|
airbyte_cdk/sources/declarative/auth/declarative_authenticator.py,sha256=nf-OmRUHYG4ORBwyb5CANzuHEssE-oNmL-Lccn41Td8,1099
|
55
55
|
airbyte_cdk/sources/declarative/auth/jwt.py,sha256=7r5q1zOekjw8kEmEk1oUyovzVt3cbD6BuFnRILeLZi8,8250
|
56
|
-
airbyte_cdk/sources/declarative/auth/oauth.py,sha256=
|
56
|
+
airbyte_cdk/sources/declarative/auth/oauth.py,sha256=EDx-tY0ZhBXe6yVHkqjUAqMWJAl4rQXjQbr4rElt_Ds,10555
|
57
57
|
airbyte_cdk/sources/declarative/auth/selective_authenticator.py,sha256=qGwC6YsCldr1bIeKG6Qo-A9a5cTdHw-vcOn3OtQrS4c,1540
|
58
58
|
airbyte_cdk/sources/declarative/auth/token.py,sha256=r4u3WXyVa7WmiSZ9-eZXlrUI-pS0D4YWJnwjLzwV-Fk,11210
|
59
59
|
airbyte_cdk/sources/declarative/auth/token_provider.py,sha256=9oq3dcBPAPwXSfkISjhA05dMhIzxaDQTmwOydBrnsMk,3028
|
@@ -66,7 +66,7 @@ airbyte_cdk/sources/declarative/concurrent_declarative_source.py,sha256=tSTCSmyM
|
|
66
66
|
airbyte_cdk/sources/declarative/datetime/__init__.py,sha256=l9LG7Qm6e5r_qgqfVKnx3mXYtg1I9MmMjomVIPfU4XA,177
|
67
67
|
airbyte_cdk/sources/declarative/datetime/datetime_parser.py,sha256=SX9JjdesN1edN2WVUVMzU_ptqp2QB1OnsnjZ4mwcX7w,2579
|
68
68
|
airbyte_cdk/sources/declarative/datetime/min_max_datetime.py,sha256=0BHBtDNQZfvwM45-tY5pNlTcKAFSGGNxemoi0Jic-0E,5785
|
69
|
-
airbyte_cdk/sources/declarative/declarative_component_schema.yaml,sha256=
|
69
|
+
airbyte_cdk/sources/declarative/declarative_component_schema.yaml,sha256=00X3palFmBp9WqQugXgtzFVn7s17KYWKTrn83ObmBzc,134673
|
70
70
|
airbyte_cdk/sources/declarative/declarative_source.py,sha256=nF7wBqFd3AQmEKAm4CnIo29CJoQL562cJGSCeL8U8bA,1531
|
71
71
|
airbyte_cdk/sources/declarative/declarative_stream.py,sha256=JRyNeOIpsFu4ztVZsN6sncqUEIqIE-bUkD2TPgbMgk0,10375
|
72
72
|
airbyte_cdk/sources/declarative/decoders/__init__.py,sha256=edGj4fGxznBk4xzRQyCA1rGfbpqe7z-RE0K3kQQWbgA,858
|
@@ -106,12 +106,12 @@ airbyte_cdk/sources/declarative/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW
|
|
106
106
|
airbyte_cdk/sources/declarative/migrations/legacy_to_per_partition_state_migration.py,sha256=iemy3fKLczcU0-Aor7tx5jcT6DRedKMqyK7kCOp01hg,3924
|
107
107
|
airbyte_cdk/sources/declarative/migrations/state_migration.py,sha256=KWPjealMLKSMtajXgkdGgKg7EmTLR-CqqD7UIh0-eDU,794
|
108
108
|
airbyte_cdk/sources/declarative/models/__init__.py,sha256=nUFxNCiKeYRVXuZEKA7GD-lTHxsiKcQ8FitZjKhPIvE,100
|
109
|
-
airbyte_cdk/sources/declarative/models/declarative_component_schema.py,sha256=
|
109
|
+
airbyte_cdk/sources/declarative/models/declarative_component_schema.py,sha256=1wrAW9XeEq2xdUAAkmHcelka-LOwyYb-izRcACkNPKM,94915
|
110
110
|
airbyte_cdk/sources/declarative/parsers/__init__.py,sha256=ZnqYNxHsKCgO38IwB34RQyRMXTs4GTvlRi3ImKnIioo,61
|
111
111
|
airbyte_cdk/sources/declarative/parsers/custom_exceptions.py,sha256=Rir9_z3Kcd5Es0-LChrzk-0qubAsiK_RSEnLmK2OXm8,553
|
112
112
|
airbyte_cdk/sources/declarative/parsers/manifest_component_transformer.py,sha256=CXwTfD3wSQq3okcqwigpprbHhSURUokh4GK2OmOyKC8,9132
|
113
113
|
airbyte_cdk/sources/declarative/parsers/manifest_reference_resolver.py,sha256=IWUOdF03o-aQn0Occo1BJCxU0Pz-QILk5L67nzw2thw,6803
|
114
|
-
airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py,sha256=
|
114
|
+
airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py,sha256=NElLb7eLDVmxDgtTX9fQ-ZPrpfH3d7RpMDaQiLtvuuQ,110550
|
115
115
|
airbyte_cdk/sources/declarative/partition_routers/__init__.py,sha256=HJ-Syp3p7RpyR_OK0X_a2kSyISfu3W-PKrRI16iY0a8,957
|
116
116
|
airbyte_cdk/sources/declarative/partition_routers/async_job_partition_router.py,sha256=n82J15S8bjeMZ5uROu--P3hnbQoxkY5v7RPHYx7g7ro,2929
|
117
117
|
airbyte_cdk/sources/declarative/partition_routers/cartesian_product_stream_slicer.py,sha256=c5cuVFM6NFkuQqG8Z5IwkBuwDrvXZN1CunUOM_L0ezg,6892
|
@@ -119,6 +119,7 @@ airbyte_cdk/sources/declarative/partition_routers/list_partition_router.py,sha25
|
|
119
119
|
airbyte_cdk/sources/declarative/partition_routers/partition_router.py,sha256=YyEIzdmLd1FjbVP3QbQ2VFCLW_P-OGbVh6VpZShp54k,2218
|
120
120
|
airbyte_cdk/sources/declarative/partition_routers/single_partition_router.py,sha256=SKzKjSyfccq4dxGIh-J6ejrgkCHzaiTIazmbmeQiRD4,1942
|
121
121
|
airbyte_cdk/sources/declarative/partition_routers/substream_partition_router.py,sha256=5bgXoJfBg_6i53krQMptAGb50XB5XoVfqQxKQhlLtBA,15383
|
122
|
+
airbyte_cdk/sources/declarative/requesters/README.md,sha256=WabtHlwHg_J34aL1Kwm8vboYqBaSgsFjq10qR-P2sx8,2658
|
122
123
|
airbyte_cdk/sources/declarative/requesters/__init__.py,sha256=d7a3OoHbqaJDyyPli3nqqJ2yAW_SLX6XDaBAKOwvpxw,364
|
123
124
|
airbyte_cdk/sources/declarative/requesters/error_handlers/__init__.py,sha256=SkEDcJxlT1683rNx93K9whoS0OyUukkuOfToGtgpF58,776
|
124
125
|
airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/__init__.py,sha256=1WZdpFmWL6W_Dko0qjflTaKIWeqt8jHT-D6HcujIp3s,884
|
@@ -133,7 +134,7 @@ airbyte_cdk/sources/declarative/requesters/error_handlers/default_error_handler.
|
|
133
134
|
airbyte_cdk/sources/declarative/requesters/error_handlers/default_http_response_filter.py,sha256=q0YkeYUUWO6iErUy0vjqiOkhg8_9d5YcCmtlpXAJJ9E,1314
|
134
135
|
airbyte_cdk/sources/declarative/requesters/error_handlers/error_handler.py,sha256=Tan66odx8VHzfdyyXMQkXz2pJYksllGqvxmpoajgcK4,669
|
135
136
|
airbyte_cdk/sources/declarative/requesters/error_handlers/http_response_filter.py,sha256=vhWsEKNTYEzZ4gerhHqnDNKu4wGIP485NAzpSQ5DRZg,7941
|
136
|
-
airbyte_cdk/sources/declarative/requesters/http_job_repository.py,sha256=
|
137
|
+
airbyte_cdk/sources/declarative/requesters/http_job_repository.py,sha256=3GtOefPH08evlSUxaILkiKLTHbIspFY4qd5B3ZqNE60,10063
|
137
138
|
airbyte_cdk/sources/declarative/requesters/http_requester.py,sha256=RqYPkgJFAWfcZBTc-JBcGHPm4JL1ZQOhs9GKU4MP2eE,14723
|
138
139
|
airbyte_cdk/sources/declarative/requesters/paginators/__init__.py,sha256=uArbKs9JKNCt7t9tZoeWwjDpyI1HoPp29FNW0JzvaEM,644
|
139
140
|
airbyte_cdk/sources/declarative/requesters/paginators/default_paginator.py,sha256=FnSl3qPvv5wD6ieAI2Ic5c4dqBk-3fRe4tCaWzq3YwM,11840
|
@@ -217,7 +218,7 @@ airbyte_cdk/sources/file_based/file_types/file_transfer.py,sha256=HyGRihJxcb_lEs
|
|
217
218
|
airbyte_cdk/sources/file_based/file_types/file_type_parser.py,sha256=JgpH21PrbRqwK92BJklZWvh2TndA6xZ-eP1LPMo44oQ,2832
|
218
219
|
airbyte_cdk/sources/file_based/file_types/jsonl_parser.py,sha256=GwyNyxmST4RX-XpXy7xVH0D-znYWWBmGv_pVAu95oHQ,5886
|
219
220
|
airbyte_cdk/sources/file_based/file_types/parquet_parser.py,sha256=XenFg5sJ-UBnIkSmsiNJRou11NO0zZXx-RXgPHMT2NA,10487
|
220
|
-
airbyte_cdk/sources/file_based/file_types/unstructured_parser.py,sha256=
|
221
|
+
airbyte_cdk/sources/file_based/file_types/unstructured_parser.py,sha256=2TYOQl62FQPCa8otLbkDIk_j01EP3oWaKSfXGhCjCHg,19492
|
221
222
|
airbyte_cdk/sources/file_based/remote_file.py,sha256=yqRz93vPe8PBXLIMJ5W5u2JRlZRhg6sBrAjn3pPjJ8A,315
|
222
223
|
airbyte_cdk/sources/file_based/schema_helpers.py,sha256=Cf8FH1bDFP0qCDDfEYir_WjP4exXUnikz8hZ40y1Ek0,9601
|
223
224
|
airbyte_cdk/sources/file_based/schema_validation_policies/__init__.py,sha256=FkByIyEy56x2_awYnxGPqGaOp7zAzpAoRkPZHKySI9M,536
|
@@ -287,12 +288,12 @@ airbyte_cdk/sources/streams/http/http.py,sha256=JAMpiTdS9HFNOlwayWNvQdxoqs2rpW9w
|
|
287
288
|
airbyte_cdk/sources/streams/http/http_client.py,sha256=tDE0ROtxjGMVphvsw8INvGMtZ97hIF-v47pZ3jIyiwc,23011
|
288
289
|
airbyte_cdk/sources/streams/http/rate_limiting.py,sha256=IwdjrHKUnU97XO4qONgYRv4YYW51xQ8SJm4WLafXDB8,6351
|
289
290
|
airbyte_cdk/sources/streams/http/requests_native_auth/__init__.py,sha256=RN0D3nOX1xLgwEwKWu6pkGy3XqBFzKSNZ8Lf6umU2eY,413
|
290
|
-
airbyte_cdk/sources/streams/http/requests_native_auth/abstract_oauth.py,sha256=
|
291
|
+
airbyte_cdk/sources/streams/http/requests_native_auth/abstract_oauth.py,sha256=xX-qKbMVN-OTwNda-B6cVQqnQrNDGBnvavAcSvXK2wU,11179
|
291
292
|
airbyte_cdk/sources/streams/http/requests_native_auth/abstract_token.py,sha256=Y3n7J-sk5yGjv_OxtY6Z6k0PEsFZmtIRi-x0KCbaHdA,1010
|
292
|
-
airbyte_cdk/sources/streams/http/requests_native_auth/oauth.py,sha256=
|
293
|
+
airbyte_cdk/sources/streams/http/requests_native_auth/oauth.py,sha256=wjsp4Xf8u3AnY7ZmTTGfLnfj6ztDBogR5biURkqcwCA,16156
|
293
294
|
airbyte_cdk/sources/streams/http/requests_native_auth/token.py,sha256=h5PTzcdH-RQLeCg7xZ45w_484OPUDSwNWl_iMJQmZoI,2526
|
294
295
|
airbyte_cdk/sources/streams/utils/__init__.py,sha256=4Hw-PX1-VgESLF16cDdvuYCzGJtHntThLF4qIiULWeo,61
|
295
|
-
airbyte_cdk/sources/types.py,sha256=
|
296
|
+
airbyte_cdk/sources/types.py,sha256=nLPkTpyfGV4E6e99qcBWX4r8C3fE4I8Fvgx2EjvT9ic,5005
|
296
297
|
airbyte_cdk/sources/utils/__init__.py,sha256=TTN6VUxVy6Is8BhYQZR5pxJGQh8yH4duXh4O1TiMiEY,118
|
297
298
|
airbyte_cdk/sources/utils/casing.py,sha256=QC-gV1O4e8DR4-bhdXieUPKm_JamzslVyfABLYYRSXA,256
|
298
299
|
airbyte_cdk/sources/utils/record_helper.py,sha256=jeB0mucudzna7Zvj-pCBbwFrbLJ36SlAWZTh5O4Fb9Y,2168
|
@@ -342,8 +343,8 @@ airbyte_cdk/utils/slice_hasher.py,sha256=-pHexlNYoWYPnXNH-M7HEbjmeJe9Zk7SJijdQ7d
|
|
342
343
|
airbyte_cdk/utils/spec_schema_transformations.py,sha256=-5HTuNsnDBAhj-oLeQXwpTGA0HdcjFOf2zTEMUTTg_Y,816
|
343
344
|
airbyte_cdk/utils/stream_status_utils.py,sha256=ZmBoiy5HVbUEHAMrUONxZvxnvfV9CesmQJLDTAIWnWw,1171
|
344
345
|
airbyte_cdk/utils/traced_exception.py,sha256=C8uIBuCL_E4WnBAOPSxBicD06JAldoN9fGsQDp463OY,6292
|
345
|
-
airbyte_cdk-6.13.1.
|
346
|
-
airbyte_cdk-6.13.1.
|
347
|
-
airbyte_cdk-6.13.1.
|
348
|
-
airbyte_cdk-6.13.1.
|
349
|
-
airbyte_cdk-6.13.1.
|
346
|
+
airbyte_cdk-6.13.1.dev4109.dist-info/LICENSE.txt,sha256=Wfe61S4BaGPj404v8lrAbvhjYR68SHlkzeYrg3_bbuM,1051
|
347
|
+
airbyte_cdk-6.13.1.dev4109.dist-info/METADATA,sha256=bNfMD2mpLZlEXjIuHgUNfYoUfAsWyTe8PF6635ClwrE,6008
|
348
|
+
airbyte_cdk-6.13.1.dev4109.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
|
349
|
+
airbyte_cdk-6.13.1.dev4109.dist-info/entry_points.txt,sha256=fj-e3PAQvsxsQzyyq8UkG1k8spunWnD4BAH2AwlR6NM,95
|
350
|
+
airbyte_cdk-6.13.1.dev4109.dist-info/RECORD,,
|
File without changes
|
File without changes
|
{airbyte_cdk-6.13.1.dev4108.dist-info → airbyte_cdk-6.13.1.dev4109.dist-info}/entry_points.txt
RENAMED
File without changes
|