workato-connector-sdk 1.0.1 → 1.0.2
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.
- checksums.yaml +5 -5
- data/lib/workato/cli/edit_command.rb +4 -3
- data/lib/workato/cli/exec_command.rb +24 -35
- data/lib/workato/cli/generate_command.rb +1 -0
- data/lib/workato/cli/generators/connector_generator.rb +1 -0
- data/lib/workato/cli/generators/master_key_generator.rb +1 -0
- data/lib/workato/cli/main.rb +1 -0
- data/lib/workato/cli/oauth2_command.rb +6 -5
- data/lib/workato/cli/push_command.rb +5 -4
- data/lib/workato/cli/schema_command.rb +4 -3
- data/lib/workato/connector/sdk/account_properties.rb +1 -0
- data/lib/workato/connector/sdk/action.rb +78 -20
- data/lib/workato/connector/sdk/block_invocation_refinements.rb +1 -0
- data/lib/workato/connector/sdk/connection.rb +202 -44
- data/lib/workato/connector/sdk/connector.rb +200 -65
- data/lib/workato/connector/sdk/dsl/account_property.rb +1 -0
- data/lib/workato/connector/sdk/dsl/aws.rb +23 -27
- data/lib/workato/connector/sdk/dsl/call.rb +1 -0
- data/lib/workato/connector/sdk/dsl/error.rb +1 -0
- data/lib/workato/connector/sdk/dsl/http.rb +2 -7
- data/lib/workato/connector/sdk/dsl/lookup_table.rb +1 -0
- data/lib/workato/connector/sdk/dsl/time.rb +6 -0
- data/lib/workato/connector/sdk/dsl/workato_code_lib.rb +38 -0
- data/lib/workato/connector/sdk/dsl/workato_schema.rb +1 -0
- data/lib/workato/connector/sdk/dsl.rb +19 -4
- data/lib/workato/connector/sdk/errors.rb +4 -3
- data/lib/workato/connector/sdk/lookup_tables.rb +1 -0
- data/lib/workato/connector/sdk/object_definitions.rb +7 -8
- data/lib/workato/connector/sdk/operation.rb +127 -88
- data/lib/workato/connector/sdk/request.rb +45 -17
- data/lib/workato/connector/sdk/schema/field/array.rb +1 -0
- data/lib/workato/connector/sdk/schema/field/convertors.rb +1 -0
- data/lib/workato/connector/sdk/schema/field/date.rb +1 -0
- data/lib/workato/connector/sdk/schema/field/date_time.rb +1 -0
- data/lib/workato/connector/sdk/schema/field/integer.rb +1 -0
- data/lib/workato/connector/sdk/schema/field/number.rb +1 -0
- data/lib/workato/connector/sdk/schema/field/object.rb +1 -0
- data/lib/workato/connector/sdk/schema/field/string.rb +1 -0
- data/lib/workato/connector/sdk/schema/type/time.rb +1 -0
- data/lib/workato/connector/sdk/schema/type/unicode_string.rb +1 -0
- data/lib/workato/connector/sdk/schema.rb +1 -0
- data/lib/workato/connector/sdk/settings.rb +9 -4
- data/lib/workato/connector/sdk/summarize.rb +3 -2
- data/lib/workato/connector/sdk/trigger.rb +81 -7
- data/lib/workato/connector/sdk/version.rb +2 -1
- data/lib/workato/connector/sdk/workato_schemas.rb +1 -0
- data/lib/workato/connector/sdk/xml.rb +1 -0
- data/lib/workato/connector/sdk.rb +4 -0
- data/lib/workato/extension/array.rb +1 -0
- data/lib/workato/extension/case_sensitive_headers.rb +1 -0
- data/lib/workato/extension/currency.rb +1 -0
- data/lib/workato/extension/date.rb +1 -0
- data/lib/workato/extension/enumerable.rb +1 -0
- data/lib/workato/extension/extra_chain_cert.rb +1 -0
- data/lib/workato/extension/hash.rb +1 -0
- data/lib/workato/extension/integer.rb +1 -0
- data/lib/workato/extension/nil_class.rb +1 -0
- data/lib/workato/extension/object.rb +1 -0
- data/lib/workato/extension/phone.rb +1 -0
- data/lib/workato/extension/string.rb +2 -1
- data/lib/workato/extension/symbol.rb +1 -0
- data/lib/workato/extension/time.rb +1 -0
- data/lib/workato/testing/vcr_encrypted_cassette_serializer.rb +5 -0
- data/lib/workato/testing/vcr_multipart_body_matcher.rb +1 -0
- data/lib/workato/web/app.rb +1 -0
- data/lib/workato-connector-sdk.rb +1 -0
- metadata +64 -7
@@ -1,3 +1,4 @@
|
|
1
|
+
# typed: strict
|
1
2
|
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require_relative './block_invocation_refinements'
|
@@ -6,95 +7,174 @@ module Workato
|
|
6
7
|
module Connector
|
7
8
|
module Sdk
|
8
9
|
class Connection
|
10
|
+
extend T::Sig
|
11
|
+
|
9
12
|
using BlockInvocationRefinements
|
10
13
|
|
14
|
+
sig { returns(HashWithIndifferentAccess) }
|
11
15
|
attr_reader :source
|
12
16
|
|
17
|
+
cattr_accessor :on_settings_update
|
18
|
+
|
19
|
+
sig do
|
20
|
+
params(
|
21
|
+
connection: SorbetTypes::SourceHash,
|
22
|
+
methods: SorbetTypes::SourceHash,
|
23
|
+
settings: SorbetTypes::SettingsHash
|
24
|
+
).void
|
25
|
+
end
|
13
26
|
def initialize(connection: {}, methods: {}, settings: {})
|
14
|
-
@methods_source = methods.with_indifferent_access
|
15
|
-
@source = connection.with_indifferent_access
|
16
|
-
@settings = settings
|
27
|
+
@methods_source = T.let(methods.with_indifferent_access, HashWithIndifferentAccess)
|
28
|
+
@source = T.let(connection.with_indifferent_access, HashWithIndifferentAccess)
|
29
|
+
@settings = T.let(settings, SorbetTypes::SettingsHash)
|
30
|
+
end
|
31
|
+
|
32
|
+
sig { returns(SorbetTypes::SettingsHash) }
|
33
|
+
def settings!
|
34
|
+
@settings
|
35
|
+
end
|
36
|
+
|
37
|
+
sig { returns(HashWithIndifferentAccess) }
|
38
|
+
def settings
|
39
|
+
# we can't freeze or memoise because some developers modify it for storing something temporary in it.
|
40
|
+
@settings.with_indifferent_access
|
41
|
+
end
|
42
|
+
|
43
|
+
sig { params(settings: SorbetTypes::SettingsHash).returns(SorbetTypes::SettingsHash) }
|
44
|
+
def merge_settings!(settings)
|
45
|
+
@settings.merge!(settings)
|
17
46
|
end
|
18
47
|
|
48
|
+
sig { returns(T::Boolean) }
|
49
|
+
def authorization?
|
50
|
+
source[:authorization].present?
|
51
|
+
end
|
52
|
+
|
53
|
+
sig { returns(Authorization) }
|
19
54
|
def authorization
|
55
|
+
raise ::NotImplementedError, 'define authorization: before use' if source[:authorization].blank?
|
56
|
+
|
57
|
+
@authorization = T.let(@authorization, T.nilable(Authorization))
|
20
58
|
@authorization ||= Authorization.new(
|
21
|
-
connection:
|
22
|
-
|
23
|
-
|
59
|
+
connection: self,
|
60
|
+
authorization: source[:authorization],
|
61
|
+
methods: methods_source
|
24
62
|
)
|
25
63
|
end
|
26
64
|
|
27
|
-
|
28
|
-
|
65
|
+
sig { params(settings: T.nilable(SorbetTypes::SettingsHash)).returns(T.nilable(String)) }
|
66
|
+
def base_uri(settings = nil)
|
67
|
+
source[:base_uri]&.call(settings ? settings.with_indifferent_access.freeze : self.settings)
|
68
|
+
end
|
69
|
+
|
70
|
+
sig do
|
71
|
+
params(
|
72
|
+
message: String,
|
73
|
+
refresher: T.proc.returns(T.nilable(SorbetTypes::SettingsHash))
|
74
|
+
).returns(T::Boolean)
|
75
|
+
end
|
76
|
+
def update_settings!(message, &refresher)
|
77
|
+
updater = lambda do
|
78
|
+
new_settings = refresher.call
|
79
|
+
next unless new_settings
|
80
|
+
|
81
|
+
settings.merge(new_settings)
|
82
|
+
end
|
83
|
+
|
84
|
+
new_settings = if on_settings_update
|
85
|
+
on_settings_update.call(message, &updater)
|
86
|
+
else
|
87
|
+
updater.call
|
88
|
+
end
|
89
|
+
return false unless new_settings
|
90
|
+
|
91
|
+
merge_settings!(new_settings)
|
92
|
+
|
93
|
+
true
|
29
94
|
end
|
30
95
|
|
31
96
|
private
|
32
97
|
|
98
|
+
sig { returns(HashWithIndifferentAccess) }
|
33
99
|
attr_reader :methods_source
|
34
100
|
|
35
101
|
class Authorization
|
36
|
-
|
37
|
-
|
38
|
-
def initialize(connection: {}, methods: {}, settings: {})
|
39
|
-
@connection_source = connection.with_indifferent_access
|
40
|
-
@source = (connection[:authorization] || {}).with_indifferent_access
|
41
|
-
@methods_source = methods.with_indifferent_access
|
42
|
-
@settings = settings
|
43
|
-
end
|
102
|
+
extend T::Sig
|
44
103
|
|
45
|
-
|
46
|
-
|
47
|
-
end
|
104
|
+
sig { returns(HashWithIndifferentAccess) }
|
105
|
+
attr_reader :source
|
48
106
|
|
49
|
-
|
50
|
-
|
107
|
+
sig do
|
108
|
+
params(
|
109
|
+
connection: Connection,
|
110
|
+
authorization: HashWithIndifferentAccess,
|
111
|
+
methods: HashWithIndifferentAccess
|
112
|
+
).void
|
51
113
|
end
|
52
|
-
|
53
|
-
|
54
|
-
source
|
114
|
+
def initialize(connection:, authorization:, methods:)
|
115
|
+
@connection = T.let(connection, Connection)
|
116
|
+
@connection_source = T.let(connection.source, HashWithIndifferentAccess)
|
117
|
+
@source = T.let(authorization, HashWithIndifferentAccess)
|
118
|
+
@methods_source = T.let(methods, HashWithIndifferentAccess)
|
55
119
|
end
|
56
120
|
|
121
|
+
sig { returns(String) }
|
57
122
|
def type
|
58
|
-
source[:type]
|
123
|
+
(source[:type].presence || 'none').to_s
|
59
124
|
end
|
60
125
|
|
126
|
+
sig { returns(T::Array[T.any(String, Symbol, Regexp, Integer)]) }
|
61
127
|
def refresh_on
|
62
128
|
Array.wrap(source[:refresh_on]).compact
|
63
129
|
end
|
64
130
|
|
131
|
+
sig { returns(T::Array[T.any(String, Symbol, Regexp, Integer)]) }
|
65
132
|
def detect_on
|
66
133
|
Array.wrap(source[:detect_on]).compact
|
67
134
|
end
|
68
135
|
|
69
|
-
|
136
|
+
sig { params(settings: T.nilable(SorbetTypes::SettingsHash)).returns(T.nilable(String)) }
|
137
|
+
def client_id(settings = nil)
|
70
138
|
client_id = source[:client_id]
|
71
139
|
|
72
140
|
if client_id.is_a?(Proc)
|
73
|
-
|
141
|
+
@connection.merge_settings!(settings) if settings
|
142
|
+
Dsl::WithDsl.execute(@connection, @connection.settings, &client_id)
|
74
143
|
else
|
75
144
|
client_id
|
76
145
|
end
|
77
146
|
end
|
78
147
|
|
79
|
-
|
148
|
+
sig { params(settings: T.nilable(SorbetTypes::SettingsHash)).returns(T.nilable(String)) }
|
149
|
+
def client_secret(settings = nil)
|
80
150
|
client_secret_source = source[:client_secret]
|
81
151
|
|
82
152
|
if client_secret_source.is_a?(Proc)
|
83
|
-
|
153
|
+
@connection.merge_settings!(settings) if settings
|
154
|
+
Dsl::WithDsl.execute(@connection, @connection.settings, &client_secret_source)
|
84
155
|
else
|
85
156
|
client_secret_source
|
86
157
|
end
|
87
158
|
end
|
88
159
|
|
89
|
-
|
90
|
-
|
160
|
+
sig { params(settings: T.nilable(SorbetTypes::SettingsHash)).returns(T.nilable(String)) }
|
161
|
+
def authorization_url(settings = nil)
|
162
|
+
source[:authorization_url]&.call(settings&.with_indifferent_access || @connection.settings)
|
91
163
|
end
|
92
164
|
|
93
|
-
|
94
|
-
|
165
|
+
sig { params(settings: T.nilable(SorbetTypes::SettingsHash)).returns(T.nilable(String)) }
|
166
|
+
def token_url(settings = nil)
|
167
|
+
source[:token_url]&.call(settings&.with_indifferent_access || @connection.settings)
|
95
168
|
end
|
96
169
|
|
97
|
-
|
170
|
+
sig do
|
171
|
+
params(
|
172
|
+
settings: T.nilable(SorbetTypes::SettingsHash),
|
173
|
+
oauth2_code: T.nilable(String),
|
174
|
+
redirect_url: T.nilable(String)
|
175
|
+
).returns(HashWithIndifferentAccess)
|
176
|
+
end
|
177
|
+
def acquire(settings = nil, oauth2_code = nil, redirect_url = nil)
|
98
178
|
acquire_proc = source[:acquire]
|
99
179
|
raise InvalidDefinitionError, "Expect 'acquire' block" unless acquire_proc
|
100
180
|
|
@@ -102,30 +182,61 @@ module Workato
|
|
102
182
|
connection: Connection.new(
|
103
183
|
connection: connection_source.merge(
|
104
184
|
authorization: source.merge(
|
105
|
-
apply: nil
|
185
|
+
apply: nil # only skip apply authorization for re-authorization request
|
106
186
|
)
|
107
187
|
),
|
108
188
|
methods: methods_source,
|
109
|
-
settings: @settings
|
189
|
+
settings: @connection.settings!
|
110
190
|
),
|
111
|
-
methods: methods_source
|
112
|
-
settings: @settings
|
191
|
+
methods: methods_source
|
113
192
|
).execute(settings, { auth_code: oauth2_code, redirect_url: redirect_url }) do |connection, input|
|
114
193
|
instance_exec(connection, input[:auth_code], input[:redirect_url], &acquire_proc)
|
115
194
|
end
|
116
195
|
end
|
117
196
|
|
118
|
-
|
197
|
+
sig do
|
198
|
+
params(
|
199
|
+
http_code: T.nilable(Integer),
|
200
|
+
http_body: T.nilable(String),
|
201
|
+
exception: T.nilable(String)
|
202
|
+
).returns(T::Boolean)
|
203
|
+
end
|
204
|
+
def refresh?(http_code, http_body, exception)
|
205
|
+
refresh_on = self.refresh_on
|
206
|
+
refresh_on.blank? || refresh_on.any? do |pattern|
|
207
|
+
pattern.is_a?(::Integer) && pattern == http_code ||
|
208
|
+
pattern === exception&.to_s ||
|
209
|
+
pattern === http_body
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
sig { params(settings: HashWithIndifferentAccess).returns(T.nilable(HashWithIndifferentAccess)) }
|
214
|
+
def refresh!(settings)
|
215
|
+
if /oauth2/i =~ type
|
216
|
+
refresh_oauth2_token(settings)
|
217
|
+
elsif source[:acquire].present?
|
218
|
+
acquire(settings)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
sig do
|
223
|
+
params(
|
224
|
+
settings: T.nilable(SorbetTypes::SettingsHash),
|
225
|
+
refresh_token: T.nilable(String)
|
226
|
+
).returns(
|
227
|
+
T.any([HashWithIndifferentAccess, T.nilable(String)], HashWithIndifferentAccess)
|
228
|
+
)
|
229
|
+
end
|
230
|
+
def refresh(settings = nil, refresh_token = nil)
|
119
231
|
refresh_proc = source[:refresh]
|
120
232
|
raise InvalidDefinitionError, "Expect 'refresh' block" unless refresh_proc
|
121
233
|
|
122
234
|
Workato::Connector::Sdk::Operation.new(
|
123
235
|
connection: Connection.new(
|
124
236
|
methods: methods_source,
|
125
|
-
settings: @settings
|
237
|
+
settings: @connection.settings!
|
126
238
|
),
|
127
|
-
methods: methods_source
|
128
|
-
settings: @settings
|
239
|
+
methods: methods_source
|
129
240
|
).execute(settings, { refresh_token: refresh_token }) do |connection, input|
|
130
241
|
instance_exec(connection, input[:refresh_token], &refresh_proc)
|
131
242
|
end
|
@@ -133,8 +244,55 @@ module Workato
|
|
133
244
|
|
134
245
|
private
|
135
246
|
|
136
|
-
|
137
|
-
|
247
|
+
sig { returns(HashWithIndifferentAccess) }
|
248
|
+
attr_reader :connection_source
|
249
|
+
|
250
|
+
sig { returns(HashWithIndifferentAccess) }
|
251
|
+
attr_reader :methods_source
|
252
|
+
|
253
|
+
sig { params(settings: HashWithIndifferentAccess).returns(HashWithIndifferentAccess) }
|
254
|
+
def refresh_oauth2_token(settings)
|
255
|
+
if source[:refresh].present?
|
256
|
+
refresh_oauth2_token_using_refresh(settings)
|
257
|
+
elsif source[:token_url].present?
|
258
|
+
refresh_oauth2_token_using_token_url(settings)
|
259
|
+
else
|
260
|
+
raise InvalidDefinitionError, "'refresh' block or 'token_url' is required for refreshing the token"
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
sig { params(settings: HashWithIndifferentAccess).returns(HashWithIndifferentAccess) }
|
265
|
+
def refresh_oauth2_token_using_refresh(settings)
|
266
|
+
new_tokens, new_settings = refresh(settings, settings[:refresh_token])
|
267
|
+
new_tokens.with_indifferent_access.merge(new_settings || {})
|
268
|
+
end
|
269
|
+
|
270
|
+
sig { params(settings: HashWithIndifferentAccess).returns(HashWithIndifferentAccess) }
|
271
|
+
def refresh_oauth2_token_using_token_url(settings)
|
272
|
+
if settings[:refresh_token].blank?
|
273
|
+
raise NotImplementedError, 'refresh_token is empty. ' \
|
274
|
+
'Use workato oauth2 command to acquire access_token and refresh_token'
|
275
|
+
end
|
276
|
+
|
277
|
+
response = RestClient::Request.execute(
|
278
|
+
url: token_url(settings),
|
279
|
+
method: :post,
|
280
|
+
payload: {
|
281
|
+
client_id: client_id(settings),
|
282
|
+
client_secret: client_secret(settings),
|
283
|
+
grant_type: :refresh_token,
|
284
|
+
refresh_token: settings[:refresh_token]
|
285
|
+
},
|
286
|
+
headers: {
|
287
|
+
accept: :json
|
288
|
+
}
|
289
|
+
)
|
290
|
+
tokens = JSON.parse(response.body)
|
291
|
+
{
|
292
|
+
access_token: tokens['access_token'],
|
293
|
+
refresh_token: tokens['refresh_token'].presence || settings[:refresh_token]
|
294
|
+
}.with_indifferent_access
|
295
|
+
end
|
138
296
|
end
|
139
297
|
|
140
298
|
private_constant :Authorization
|