shopify_api 12.2.0 → 12.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +15 -10
- data/README.md +10 -11
- data/docs/getting_started.md +1 -1
- data/docs/usage/oauth.md +3 -4
- data/lib/shopify_api/auth/oauth.rb +1 -4
- data/lib/shopify_api/clients/http_client.rb +3 -3
- data/lib/shopify_api/context.rb +47 -14
- data/lib/shopify_api/errors/feature_deprecated_error.rb +9 -0
- data/lib/shopify_api/errors/http_response_error.rb +7 -3
- data/lib/shopify_api/errors/log_level_not_found_error.rb +9 -0
- data/lib/shopify_api/logger.rb +82 -0
- data/lib/shopify_api/utils/session_utils.rb +38 -21
- data/lib/shopify_api/version.rb +1 -1
- data/shopify_api.gemspec +3 -2
- metadata +26 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 60567c4e9da3da8eb19c903b704297d4cb194a3f63d0644e3273357554e86321
|
4
|
+
data.tar.gz: 19ec21a447be21e2f88ca5e4d3bb2978c587857f63976264bcaf998f7dddce47
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a09451f3182e19d125d662dad337b737377622079e23c03de6949999812bfdbee83fb319bc6ada35d202343a535536b7dc0622fe9d28a66a04465dca0074187a
|
7
|
+
data.tar.gz: 5c1ad7e58afebc440aa712f881c60823c070603b171d1eb80fcb2b3c703b2f0730c1a942d5e3a237cca1adef1d997d087bad716244baca716fd131e4ce8c935b
|
data/CHANGELOG.md
CHANGED
@@ -3,6 +3,15 @@
|
|
3
3
|
Note: For changes to the API, see https://shopify.dev/changelog?filter=api
|
4
4
|
|
5
5
|
## Unreleased
|
6
|
+
## Version 12.3.0
|
7
|
+
|
8
|
+
- [#1040](https://github.com/Shopify/shopify-api-ruby/pull/1040) `ShopifyAPI::Clients::HttpResponse` as argument for `ShopifyAPI::Errors::HttpResponseError`
|
9
|
+
- [#1055](https://github.com/Shopify/shopify-api-ruby/pull/1055) Makes session_storage optional. Configuring the API with session_storage is now deprecated. Session persistence is handled by the [shopify_app gem](https://github.com/Shopify/shopify_app) if using Rails.
|
10
|
+
- [#1063](https://github.com/Shopify/shopify-api-ruby/pull/1063) Fix ActiveSupport inflector dependency
|
11
|
+
- [#1069](https://github.com/Shopify/shopify-api-ruby/pull/1069) Adds a custom Logger to help write uniform logs across the api and the [shopify_app gem](https://github.com/Shopify/shopify_app)
|
12
|
+
|
13
|
+
## Version 12.2.1
|
14
|
+
- [#1045](https://github.com/Shopify/shopify-api-ruby/pull/1045) Fixes bug with host/host_name requirement.
|
6
15
|
|
7
16
|
## Version 12.2.0
|
8
17
|
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
shopify_api (12.
|
4
|
+
shopify_api (12.3.0)
|
5
|
+
activesupport
|
5
6
|
concurrent-ruby
|
6
7
|
hash_diff
|
7
8
|
httparty
|
@@ -10,12 +11,12 @@ PATH
|
|
10
11
|
openssl
|
11
12
|
securerandom
|
12
13
|
sorbet-runtime
|
13
|
-
zeitwerk (~> 2.5)
|
14
|
+
zeitwerk (~> 2.5, < 2.6.5)
|
14
15
|
|
15
16
|
GEM
|
16
17
|
remote: https://rubygems.org/
|
17
18
|
specs:
|
18
|
-
activesupport (7.0.
|
19
|
+
activesupport (7.0.4)
|
19
20
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
20
21
|
i18n (>= 1.6, < 2)
|
21
22
|
minitest (>= 5.1)
|
@@ -23,8 +24,9 @@ GEM
|
|
23
24
|
addressable (2.8.0)
|
24
25
|
public_suffix (>= 2.0.2, < 5.0)
|
25
26
|
ast (2.4.2)
|
27
|
+
byebug (11.1.3)
|
26
28
|
coderay (1.1.3)
|
27
|
-
concurrent-ruby (1.1.
|
29
|
+
concurrent-ruby (1.1.10)
|
28
30
|
crack (0.4.5)
|
29
31
|
rexml
|
30
32
|
diff-lcs (1.5.0)
|
@@ -34,7 +36,7 @@ GEM
|
|
34
36
|
httparty (0.20.0)
|
35
37
|
mime-types (~> 3.0)
|
36
38
|
multi_xml (>= 0.5.2)
|
37
|
-
i18n (1.
|
39
|
+
i18n (1.12.0)
|
38
40
|
concurrent-ruby (~> 1.0)
|
39
41
|
json (2.6.2)
|
40
42
|
jwt (2.5.0)
|
@@ -47,7 +49,7 @@ GEM
|
|
47
49
|
mocha (1.13.0)
|
48
50
|
multi_xml (0.6.0)
|
49
51
|
netrc (0.11.0)
|
50
|
-
oj (3.13.
|
52
|
+
oj (3.13.23)
|
51
53
|
openssl (3.0.1)
|
52
54
|
parallel (1.22.1)
|
53
55
|
parser (3.1.2.1)
|
@@ -56,6 +58,9 @@ GEM
|
|
56
58
|
pry (0.14.1)
|
57
59
|
coderay (~> 1.1)
|
58
60
|
method_source (~> 1.0)
|
61
|
+
pry-byebug (3.10.1)
|
62
|
+
byebug (~> 11.0)
|
63
|
+
pry (>= 0.13, < 0.15)
|
59
64
|
public_suffix (4.0.6)
|
60
65
|
rainbow (3.1.1)
|
61
66
|
rake (13.0.6)
|
@@ -87,7 +92,7 @@ GEM
|
|
87
92
|
sorbet-runtime
|
88
93
|
syntax_tree (>= 3.4)
|
89
94
|
ruby-progressbar (1.11.0)
|
90
|
-
securerandom (0.2.
|
95
|
+
securerandom (0.2.1)
|
91
96
|
sorbet (0.5.10438)
|
92
97
|
sorbet-static (= 0.5.10438)
|
93
98
|
sorbet-runtime (0.5.10438)
|
@@ -113,7 +118,7 @@ GEM
|
|
113
118
|
thor (>= 1.2.0)
|
114
119
|
yard-sorbet
|
115
120
|
thor (1.2.1)
|
116
|
-
tzinfo (2.0.
|
121
|
+
tzinfo (2.0.5)
|
117
122
|
concurrent-ruby (~> 1.0)
|
118
123
|
unicode-display_width (2.3.0)
|
119
124
|
unparser (0.6.5)
|
@@ -129,17 +134,17 @@ GEM
|
|
129
134
|
yard-sorbet (0.7.0)
|
130
135
|
sorbet-runtime (>= 0.5)
|
131
136
|
yard (>= 0.9)
|
132
|
-
zeitwerk (2.6.
|
137
|
+
zeitwerk (2.6.4)
|
133
138
|
|
134
139
|
PLATFORMS
|
135
140
|
arm64-darwin-21
|
136
141
|
x86_64-linux
|
137
142
|
|
138
143
|
DEPENDENCIES
|
139
|
-
activesupport
|
140
144
|
fakefs
|
141
145
|
minitest
|
142
146
|
mocha
|
147
|
+
pry-byebug
|
143
148
|
rake
|
144
149
|
rubocop
|
145
150
|
rubocop-shopify
|
data/README.md
CHANGED
@@ -23,7 +23,6 @@ To follow these usage guides, you will need to:
|
|
23
23
|
|
24
24
|
- have a working knowledge of ruby and a web framework such as Rails or Sinatra
|
25
25
|
- have a Shopify Partner account and development store
|
26
|
-
- _OR_ have a test store where you can create a private app
|
27
26
|
- have an app already set up in your test store or partner account
|
28
27
|
- add the URL and the appropriate redirect for your OAuth callback route to your app settings
|
29
28
|
|
@@ -51,12 +50,12 @@ Start by initializing the `ShopifyAPI::Context` with the parameters of your app
|
|
51
50
|
ShopifyAPI::Context.setup(
|
52
51
|
api_key: "<api-key>",
|
53
52
|
api_secret_key: "<api-secret-key>",
|
54
|
-
|
53
|
+
host: "<https://application-host-name.com>",
|
55
54
|
scope: "read_orders,read_products,etc",
|
56
55
|
session_storage: ShopifyAPI::Auth::FileSessionStorage.new, # See more details below
|
57
56
|
is_embedded: true, # Set to true if you are building an embedded app
|
58
|
-
is_private: false, # Set to true if you are building a private app
|
59
57
|
api_version: "2022-01" # The version of the API you would like to use
|
58
|
+
is_private: false, # Set to true if you have an existing private app
|
60
59
|
)
|
61
60
|
```
|
62
61
|
|
@@ -68,7 +67,7 @@ Session information would is typically stored in cookies on the browser. However
|
|
68
67
|
|
69
68
|
### Performing OAuth
|
70
69
|
|
71
|
-
|
70
|
+
You need to go through OAuth as described [here](https://shopify.dev/apps/auth/oauth) to create sessions for shops using your app.
|
72
71
|
The Shopify API gem tries to make this easy by providing functions to begin and complete the OAuth process. See the [Oauth doc](docs/usage/oauth.md) for instructions on how to use these.
|
73
72
|
|
74
73
|
### Register Webhooks and a Webhook Handler
|
@@ -83,7 +82,7 @@ Once your app can perform OAuth, it can now make authenticated Shopify API calls
|
|
83
82
|
|
84
83
|
### Breaking change notice for version 10.0.0
|
85
84
|
|
86
|
-
We've rewritten this library for v10, so that it provides all essential features for a Shopify app without
|
85
|
+
We've rewritten this library for v10, so that it provides all essential features for a Shopify app without depending on the [Active Resource](https://github.com/rails/activeresource) or [graphql-client](https://github.com/github/graphql-client) libraries.
|
87
86
|
|
88
87
|
Here are the main features it provides:
|
89
88
|
|
@@ -107,12 +106,12 @@ With this, a lot changed in how apps access the library. Here are the updates yo
|
|
107
106
|
|
108
107
|
Please see below a (non-exhaustive) list of common replacements to guide you in your updates, using the `Order` resource as an example.
|
109
108
|
|
110
|
-
| Before
|
111
|
-
| ---
|
112
|
-
| `Order.find(:all, params: {param1: value1})`
|
113
|
-
| `Order.find(<id>)`
|
114
|
-
| `order = Order.new(<id>)`<br/>`order.post(:close)` | `order = Order.new
|
115
|
-
| `order = Order.new(<id>)`<br/>`order.delete`
|
109
|
+
| Before | After |
|
110
|
+
| --- | --- |
|
111
|
+
| `Order.find(:all, params: {param1: value1})` | `Order.all(param1: value1)` |
|
112
|
+
| `Order.find(<id>)` | `Order.find(id: <id>)` |
|
113
|
+
| `order = Order.new(<id>)`<br/>`order.post(:close)` | `order = Order.new`<br/>`order.close` |
|
114
|
+
| `order = Order.new(<id>)`<br/>`order.delete` | `Order.delete(id: <id>)` |
|
116
115
|
|
117
116
|
## Breaking changes for older versions
|
118
117
|
|
data/docs/getting_started.md
CHANGED
@@ -5,7 +5,7 @@ This page will outline everything you need to know and the steps you need to fol
|
|
5
5
|
## Requirements
|
6
6
|
|
7
7
|
- A working knowledge of ruby and a web framework such as Rails or Sinatra
|
8
|
-
- A
|
8
|
+
- A custom app already set up in your test store or partner account
|
9
9
|
- We recommend `ngrok` to tunnel traffic to your localhost for testing
|
10
10
|
|
11
11
|
## Installation
|
data/docs/usage/oauth.md
CHANGED
@@ -3,8 +3,7 @@
|
|
3
3
|
Once the library is set up for your project, you'll be able to use it to start adding functionality to your app. The first thing your app will need to do is to obtain an access token to the Admin API by performing the OAuth process.
|
4
4
|
|
5
5
|
To do this, you can follow the steps below.
|
6
|
-
|
7
|
-
**Note:** You do not need to go through the OAuth process if you are creating a private app. In this case you can simply set your `<key+password>` as the `api_secret_key` in `ShopifyAPI::Context.setup`. For more information on authenticating a Shopify app please see the [Types of Authentication](https://shopify.dev/apps/auth#types-of-authentication) page.
|
6
|
+
For more information on authenticating a Shopify app please see the [Types of Authentication](https://shopify.dev/apps/auth#types-of-authentication) page.
|
8
7
|
|
9
8
|
## Add a route to start OAuth
|
10
9
|
|
@@ -53,7 +52,7 @@ def callback
|
|
53
52
|
cookies: cookies.to_h,
|
54
53
|
auth_query: ShopifyAPI::Auth::Oauth::AuthQuery.new(request.parameters.symbolize_keys.except(:controller, :action))
|
55
54
|
)
|
56
|
-
|
55
|
+
|
57
56
|
cookies[auth_result[:cookie].name] = {
|
58
57
|
expires: auth_result[:cookie].expires,
|
59
58
|
secure: true,
|
@@ -66,7 +65,7 @@ def callback
|
|
66
65
|
head 307
|
67
66
|
response.set_header("Location", "<some-redirect-url>")
|
68
67
|
rescue => e
|
69
|
-
puts(e.message)
|
68
|
+
puts(e.message)
|
70
69
|
head 500
|
71
70
|
end
|
72
71
|
end
|
@@ -93,10 +93,7 @@ module ShopifyAPI
|
|
93
93
|
)
|
94
94
|
end
|
95
95
|
|
96
|
-
|
97
|
-
raise Errors::SessionStorageError,
|
98
|
-
"Session could not be saved. Please check your session storage implementation."
|
99
|
-
end
|
96
|
+
Context.session_storage&.store_session(session)
|
100
97
|
|
101
98
|
{ session: session, cookie: cookie }
|
102
99
|
end
|
@@ -69,13 +69,13 @@ module ShopifyAPI
|
|
69
69
|
error_message = error_messages.join("\n")
|
70
70
|
|
71
71
|
unless [429, 500].include?(response.code)
|
72
|
-
raise ShopifyAPI::Errors::HttpResponseError.new(
|
72
|
+
raise ShopifyAPI::Errors::HttpResponseError.new(response: response), error_message
|
73
73
|
end
|
74
74
|
|
75
75
|
if tries == request.tries
|
76
|
-
raise ShopifyAPI::Errors::HttpResponseError.new(
|
76
|
+
raise ShopifyAPI::Errors::HttpResponseError.new(response: response), error_message if request.tries == 1
|
77
77
|
|
78
|
-
raise ShopifyAPI::Errors::MaxHttpRetriesExceededError.new(
|
78
|
+
raise ShopifyAPI::Errors::MaxHttpRetriesExceededError.new(response: response),
|
79
79
|
"Exceeded maximum retry count of #{request.tries}. Last message: #{error_message}"
|
80
80
|
end
|
81
81
|
|
data/lib/shopify_api/context.rb
CHANGED
@@ -8,15 +8,15 @@ module ShopifyAPI
|
|
8
8
|
@api_key = T.let("", String)
|
9
9
|
@api_secret_key = T.let("", String)
|
10
10
|
@api_version = T.let(LATEST_SUPPORTED_ADMIN_VERSION, String)
|
11
|
-
@host_name = T.let("", String)
|
12
11
|
@scope = T.let(Auth::AuthScopes.new, Auth::AuthScopes)
|
13
|
-
@session_storage = T.let(ShopifyAPI::Auth::FileSessionStorage.new, ShopifyAPI::Auth::SessionStorage)
|
14
12
|
@is_private = T.let(false, T::Boolean)
|
15
13
|
@private_shop = T.let(nil, T.nilable(String))
|
16
14
|
@is_embedded = T.let(true, T::Boolean)
|
17
|
-
@logger = T.let(Logger.new($stdout), Logger)
|
15
|
+
@logger = T.let(::Logger.new($stdout), ::Logger)
|
16
|
+
@log_level = T.let(:info, Symbol)
|
18
17
|
@notified_missing_resources_folder = T.let({}, T::Hash[String, T::Boolean])
|
19
18
|
@active_session = T.let(Concurrent::ThreadLocalVar.new { nil }, Concurrent::ThreadLocalVar)
|
19
|
+
@session_storage = T.let(nil, T.nilable(ShopifyAPI::Auth::SessionStorage))
|
20
20
|
@user_agent_prefix = T.let(nil, T.nilable(String))
|
21
21
|
@old_api_secret_key = T.let(nil, T.nilable(String))
|
22
22
|
|
@@ -30,12 +30,13 @@ module ShopifyAPI
|
|
30
30
|
api_key: String,
|
31
31
|
api_secret_key: String,
|
32
32
|
api_version: String,
|
33
|
-
host_name: String,
|
34
33
|
scope: T.any(T::Array[String], String),
|
35
34
|
is_private: T::Boolean,
|
36
35
|
is_embedded: T::Boolean,
|
37
|
-
|
38
|
-
logger: Logger,
|
36
|
+
log_level: T.any(String, Symbol),
|
37
|
+
logger: ::Logger,
|
38
|
+
session_storage: T.nilable(ShopifyAPI::Auth::SessionStorage),
|
39
|
+
host_name: T.nilable(String),
|
39
40
|
host: T.nilable(String),
|
40
41
|
private_shop: T.nilable(String),
|
41
42
|
user_agent_prefix: T.nilable(String),
|
@@ -46,12 +47,13 @@ module ShopifyAPI
|
|
46
47
|
api_key:,
|
47
48
|
api_secret_key:,
|
48
49
|
api_version:,
|
49
|
-
host_name:,
|
50
50
|
scope:,
|
51
51
|
is_private:,
|
52
52
|
is_embedded:,
|
53
|
-
|
54
|
-
logger: Logger.new($stdout),
|
53
|
+
log_level: :info,
|
54
|
+
logger: ::Logger.new($stdout),
|
55
|
+
session_storage: nil,
|
56
|
+
host_name: nil,
|
55
57
|
host: ENV["HOST"] || "https://#{host_name}",
|
56
58
|
private_shop: nil,
|
57
59
|
user_agent_prefix: nil,
|
@@ -65,7 +67,6 @@ module ShopifyAPI
|
|
65
67
|
@api_key = api_key
|
66
68
|
@api_secret_key = api_secret_key
|
67
69
|
@api_version = api_version
|
68
|
-
@host_name = host_name
|
69
70
|
@host = T.let(host, T.nilable(String))
|
70
71
|
@is_private = is_private
|
71
72
|
@scope = Auth::AuthScopes.new(scope)
|
@@ -75,6 +76,18 @@ module ShopifyAPI
|
|
75
76
|
@private_shop = private_shop
|
76
77
|
@user_agent_prefix = user_agent_prefix
|
77
78
|
@old_api_secret_key = old_api_secret_key
|
79
|
+
@log_level = if valid_log_level?(log_level)
|
80
|
+
log_level.to_sym
|
81
|
+
else
|
82
|
+
:info
|
83
|
+
end
|
84
|
+
|
85
|
+
if @session_storage
|
86
|
+
::ShopifyAPI::Logger.deprecated("The use of SessionStorage in the API library has been deprecated. " \
|
87
|
+
"The ShopifyAPI will no longer have responsibility for session persistence. " \
|
88
|
+
"Upgrading to `shopify_app` 21.3 will allow you to remove session_storage" \
|
89
|
+
" from the API library Context configuration.", "13.0.0")
|
90
|
+
end
|
78
91
|
|
79
92
|
load_rest_resources(api_version: api_version)
|
80
93
|
end
|
@@ -108,17 +121,20 @@ module ShopifyAPI
|
|
108
121
|
end
|
109
122
|
|
110
123
|
sig { returns(String) }
|
111
|
-
attr_reader :api_key, :api_secret_key, :api_version
|
124
|
+
attr_reader :api_key, :api_secret_key, :api_version
|
112
125
|
|
113
126
|
sig { returns(Auth::AuthScopes) }
|
114
127
|
attr_reader :scope
|
115
128
|
|
116
|
-
sig { returns(ShopifyAPI::Auth::SessionStorage) }
|
129
|
+
sig { returns(T.nilable(ShopifyAPI::Auth::SessionStorage)) }
|
117
130
|
attr_reader :session_storage
|
118
131
|
|
119
|
-
sig { returns(Logger) }
|
132
|
+
sig { returns(::Logger) }
|
120
133
|
attr_reader :logger
|
121
134
|
|
135
|
+
sig { returns(Symbol) }
|
136
|
+
attr_reader :log_level
|
137
|
+
|
122
138
|
sig { returns(T::Boolean) }
|
123
139
|
def private?
|
124
140
|
@is_private
|
@@ -134,7 +150,7 @@ module ShopifyAPI
|
|
134
150
|
|
135
151
|
sig { returns(T::Boolean) }
|
136
152
|
def setup?
|
137
|
-
[api_key, api_secret_key,
|
153
|
+
[api_key, api_secret_key, T.must(host)].none?(&:empty?)
|
138
154
|
end
|
139
155
|
|
140
156
|
sig { returns(T.nilable(Auth::Session)) }
|
@@ -158,6 +174,23 @@ module ShopifyAPI
|
|
158
174
|
def host_scheme
|
159
175
|
T.must(URI.parse(T.must(host)).scheme)
|
160
176
|
end
|
177
|
+
|
178
|
+
sig { returns(String) }
|
179
|
+
def host_name
|
180
|
+
T.must(URI(T.must(host)).host)
|
181
|
+
end
|
182
|
+
|
183
|
+
private
|
184
|
+
|
185
|
+
sig { params(log_level: T.any(Symbol, String)).returns(T::Boolean) }
|
186
|
+
def valid_log_level?(log_level)
|
187
|
+
return true if ::ShopifyAPI::Logger.levels.include?(log_level.to_sym)
|
188
|
+
|
189
|
+
ShopifyAPI::Logger.warn("#{log_level} is not a valid log_level. "\
|
190
|
+
"Valid options are #{::ShopifyAPI::Logger.levels.join(", ")}")
|
191
|
+
|
192
|
+
false
|
193
|
+
end
|
161
194
|
end
|
162
195
|
end
|
163
196
|
end
|
@@ -9,10 +9,14 @@ module ShopifyAPI
|
|
9
9
|
sig { returns(Integer) }
|
10
10
|
attr_reader :code
|
11
11
|
|
12
|
-
sig {
|
13
|
-
|
12
|
+
sig { returns(ShopifyAPI::Clients::HttpResponse) }
|
13
|
+
attr_reader :response
|
14
|
+
|
15
|
+
sig { params(response: ShopifyAPI::Clients::HttpResponse).void }
|
16
|
+
def initialize(response:)
|
14
17
|
super
|
15
|
-
@code = code
|
18
|
+
@code = T.let(response.code, Integer)
|
19
|
+
@response = response
|
16
20
|
end
|
17
21
|
end
|
18
22
|
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module ShopifyAPI
|
5
|
+
class Logger
|
6
|
+
LOG_LEVELS = T.let({ debug: 0, info: 1, warn: 2, error: 3, off: 6 }, T::Hash[Symbol, Integer])
|
7
|
+
DEFAULT_LOG_LEVEL = :info
|
8
|
+
|
9
|
+
class << self
|
10
|
+
extend T::Sig
|
11
|
+
|
12
|
+
sig { params(message: String).void }
|
13
|
+
def debug(message)
|
14
|
+
send_to_logger(:debug, message)
|
15
|
+
end
|
16
|
+
|
17
|
+
sig { params(message: String).void }
|
18
|
+
def info(message)
|
19
|
+
send_to_logger(:info, message)
|
20
|
+
end
|
21
|
+
|
22
|
+
sig { params(message: String).void }
|
23
|
+
def warn(message)
|
24
|
+
send_to_logger(:warn, message)
|
25
|
+
end
|
26
|
+
|
27
|
+
sig { params(message: String).void }
|
28
|
+
def error(message)
|
29
|
+
send_to_logger(:error, message)
|
30
|
+
end
|
31
|
+
|
32
|
+
sig { params(message: String, version: String).void }
|
33
|
+
def deprecated(message, version)
|
34
|
+
return unless enabled_for_log_level?(:warn)
|
35
|
+
|
36
|
+
raise Errors::FeatureDeprecatedError unless valid_version(version)
|
37
|
+
|
38
|
+
send_to_logger(:warn, message)
|
39
|
+
end
|
40
|
+
|
41
|
+
sig { returns(T::Array[Symbol]) }
|
42
|
+
def levels
|
43
|
+
LOG_LEVELS.keys
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
sig { params(log_level: Symbol).returns(String) }
|
49
|
+
def context(log_level)
|
50
|
+
current_shop = ShopifyAPI::Context.active_session&.shop
|
51
|
+
|
52
|
+
if current_shop.nil?
|
53
|
+
"[ ShopifyAPI | #{log_level.to_s.upcase} ]"
|
54
|
+
else
|
55
|
+
"[ ShopifyAPI | #{log_level.to_s.upcase} | #{current_shop} ]"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
sig { params(log_level: Symbol, message: String).void }
|
60
|
+
def send_to_logger(log_level, message)
|
61
|
+
return unless enabled_for_log_level?(log_level)
|
62
|
+
|
63
|
+
full_message = "#{context(log_level)} #{message}"
|
64
|
+
|
65
|
+
ShopifyAPI::Context.logger.public_send(log_level, full_message)
|
66
|
+
end
|
67
|
+
|
68
|
+
sig { params(log_level: Symbol).returns(T::Boolean) }
|
69
|
+
def enabled_for_log_level?(log_level)
|
70
|
+
T.must(LOG_LEVELS[log_level]) >= T.must(LOG_LEVELS[ShopifyAPI::Context.log_level] ||
|
71
|
+
LOG_LEVELS[DEFAULT_LOG_LEVEL])
|
72
|
+
end
|
73
|
+
|
74
|
+
sig { params(version: String).returns(T::Boolean) }
|
75
|
+
def valid_version(version)
|
76
|
+
current_version = Gem::Version.create(ShopifyAPI::VERSION)
|
77
|
+
deprecate_version = Gem::Version.create(version)
|
78
|
+
current_version < deprecate_version
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -17,12 +17,13 @@ module ShopifyAPI
|
|
17
17
|
).returns(T.nilable(Auth::Session))
|
18
18
|
end
|
19
19
|
def load_current_session(auth_header: nil, cookies: nil, is_online: false)
|
20
|
+
validate_session_storage_for_deprecated_utils
|
20
21
|
return load_private_session if Context.private?
|
21
22
|
|
22
23
|
session_id = current_session_id(auth_header, cookies, is_online)
|
23
24
|
return nil unless session_id
|
24
25
|
|
25
|
-
Context.session_storage.load_session(session_id)
|
26
|
+
T.must(Context.session_storage).load_session(session_id)
|
26
27
|
end
|
27
28
|
|
28
29
|
sig do
|
@@ -33,10 +34,12 @@ module ShopifyAPI
|
|
33
34
|
).returns(T::Boolean)
|
34
35
|
end
|
35
36
|
def delete_current_session(auth_header: nil, cookies: nil, is_online: false)
|
37
|
+
validate_session_storage_for_deprecated_utils
|
38
|
+
|
36
39
|
session_id = current_session_id(auth_header, cookies, is_online)
|
37
40
|
return false unless session_id
|
38
41
|
|
39
|
-
Context.session_storage.delete_session(session_id)
|
42
|
+
T.must(Context.session_storage).delete_session(session_id)
|
40
43
|
end
|
41
44
|
|
42
45
|
sig do
|
@@ -46,8 +49,10 @@ module ShopifyAPI
|
|
46
49
|
).returns(T.nilable(Auth::Session))
|
47
50
|
end
|
48
51
|
def load_offline_session(shop:, include_expired: false)
|
52
|
+
validate_session_storage_for_deprecated_utils
|
53
|
+
|
49
54
|
session_id = offline_session_id(shop)
|
50
|
-
session = Context.session_storage.load_session(session_id)
|
55
|
+
session = T.must(Context.session_storage).load_session(session_id)
|
51
56
|
return nil if session && !include_expired && session.expires && T.must(session.expires) < Time.now
|
52
57
|
|
53
58
|
session
|
@@ -59,23 +64,10 @@ module ShopifyAPI
|
|
59
64
|
).returns(T::Boolean)
|
60
65
|
end
|
61
66
|
def delete_offline_session(shop:)
|
62
|
-
|
63
|
-
Context.session_storage.delete_session(session_id)
|
64
|
-
end
|
65
|
-
|
66
|
-
private
|
67
|
+
validate_session_storage_for_deprecated_utils
|
67
68
|
|
68
|
-
|
69
|
-
|
70
|
-
unless Context.private_shop
|
71
|
-
raise Errors::SessionNotFoundError, "Could not load private shop, Context.private_shop is nil."
|
72
|
-
end
|
73
|
-
|
74
|
-
Auth::Session.new(
|
75
|
-
shop: T.must(Context.private_shop),
|
76
|
-
access_token: Context.api_secret_key,
|
77
|
-
scope: Context.scope.to_a,
|
78
|
-
)
|
69
|
+
session_id = offline_session_id(shop)
|
70
|
+
T.must(Context.session_storage).delete_session(session_id)
|
79
71
|
end
|
80
72
|
|
81
73
|
sig do
|
@@ -89,8 +81,10 @@ module ShopifyAPI
|
|
89
81
|
if Context.embedded?
|
90
82
|
if auth_header
|
91
83
|
matches = auth_header.match(/^Bearer (.+)$/)
|
92
|
-
|
93
|
-
"Missing Bearer token in authorization header"
|
84
|
+
unless matches
|
85
|
+
ShopifyAPI::Logger.warn("Missing Bearer token in authorization header")
|
86
|
+
raise Errors::MissingJwtTokenError, "Missing Bearer token in authorization header"
|
87
|
+
end
|
94
88
|
|
95
89
|
jwt_payload = Auth::JwtPayload.new(T.must(matches[1]))
|
96
90
|
shop = jwt_payload.shop
|
@@ -129,6 +123,29 @@ module ShopifyAPI
|
|
129
123
|
def cookie_session_id(cookies)
|
130
124
|
cookies[Auth::Oauth::SessionCookie::SESSION_COOKIE_NAME]
|
131
125
|
end
|
126
|
+
|
127
|
+
private
|
128
|
+
|
129
|
+
sig { void }
|
130
|
+
def validate_session_storage_for_deprecated_utils
|
131
|
+
unless Context.session_storage
|
132
|
+
raise ShopifyAPI::Errors::SessionStorageError,
|
133
|
+
"session_storage is required in ShopifyAPI::Context when using deprecated Session utility methods."
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
sig { returns(Auth::Session) }
|
138
|
+
def load_private_session
|
139
|
+
unless Context.private_shop
|
140
|
+
raise Errors::SessionNotFoundError, "Could not load private shop, Context.private_shop is nil."
|
141
|
+
end
|
142
|
+
|
143
|
+
Auth::Session.new(
|
144
|
+
shop: T.must(Context.private_shop),
|
145
|
+
access_token: Context.api_secret_key,
|
146
|
+
scope: Context.scope.to_a,
|
147
|
+
)
|
148
|
+
end
|
132
149
|
end
|
133
150
|
end
|
134
151
|
end
|
data/lib/shopify_api/version.rb
CHANGED
data/shopify_api.gemspec
CHANGED
@@ -32,6 +32,7 @@ Gem::Specification.new do |s|
|
|
32
32
|
|
33
33
|
s.required_ruby_version = ">= 2.6"
|
34
34
|
|
35
|
+
s.add_runtime_dependency("activesupport")
|
35
36
|
s.add_runtime_dependency("concurrent-ruby")
|
36
37
|
s.add_runtime_dependency("hash_diff")
|
37
38
|
s.add_runtime_dependency("httparty")
|
@@ -40,9 +41,9 @@ Gem::Specification.new do |s|
|
|
40
41
|
s.add_runtime_dependency("openssl")
|
41
42
|
s.add_runtime_dependency("securerandom")
|
42
43
|
s.add_runtime_dependency("sorbet-runtime")
|
43
|
-
s.add_runtime_dependency("zeitwerk", "~> 2.5")
|
44
|
+
s.add_runtime_dependency("zeitwerk", "~> 2.5", "< 2.6.5") # https://github.com/Shopify/shopify-api-ruby/issues/1058
|
44
45
|
|
45
|
-
s.add_development_dependency("
|
46
|
+
s.add_development_dependency("pry-byebug")
|
46
47
|
s.add_development_dependency("rake")
|
47
48
|
s.add_development_dependency("rubocop")
|
48
49
|
s.add_development_dependency("rubocop-shopify")
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shopify_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 12.
|
4
|
+
version: 12.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-12-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: concurrent-ruby
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -129,6 +143,9 @@ dependencies:
|
|
129
143
|
- - "~>"
|
130
144
|
- !ruby/object:Gem::Version
|
131
145
|
version: '2.5'
|
146
|
+
- - "<"
|
147
|
+
- !ruby/object:Gem::Version
|
148
|
+
version: 2.6.5
|
132
149
|
type: :runtime
|
133
150
|
prerelease: false
|
134
151
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -136,8 +153,11 @@ dependencies:
|
|
136
153
|
- - "~>"
|
137
154
|
- !ruby/object:Gem::Version
|
138
155
|
version: '2.5'
|
156
|
+
- - "<"
|
157
|
+
- !ruby/object:Gem::Version
|
158
|
+
version: 2.6.5
|
139
159
|
- !ruby/object:Gem::Dependency
|
140
|
-
name:
|
160
|
+
name: pry-byebug
|
141
161
|
requirement: !ruby/object:Gem::Requirement
|
142
162
|
requirements:
|
143
163
|
- - ">="
|
@@ -311,6 +331,7 @@ files:
|
|
311
331
|
- lib/shopify_api/context.rb
|
312
332
|
- lib/shopify_api/errors/context_not_setup_error.rb
|
313
333
|
- lib/shopify_api/errors/cookie_not_found_error.rb
|
334
|
+
- lib/shopify_api/errors/feature_deprecated_error.rb
|
314
335
|
- lib/shopify_api/errors/http_response_error.rb
|
315
336
|
- lib/shopify_api/errors/invalid_graphql_request_error.rb
|
316
337
|
- lib/shopify_api/errors/invalid_http_request_error.rb
|
@@ -318,6 +339,7 @@ files:
|
|
318
339
|
- lib/shopify_api/errors/invalid_oauth_error.rb
|
319
340
|
- lib/shopify_api/errors/invalid_webhook_error.rb
|
320
341
|
- lib/shopify_api/errors/invalid_webhook_registration_error.rb
|
342
|
+
- lib/shopify_api/errors/log_level_not_found_error.rb
|
321
343
|
- lib/shopify_api/errors/max_http_retries_exceeded_error.rb
|
322
344
|
- lib/shopify_api/errors/missing_jwt_token_error.rb
|
323
345
|
- lib/shopify_api/errors/missing_required_argument_error.rb
|
@@ -332,6 +354,7 @@ files:
|
|
332
354
|
- lib/shopify_api/errors/unsupported_version_error.rb
|
333
355
|
- lib/shopify_api/errors/webhook_registration_error.rb
|
334
356
|
- lib/shopify_api/inflector.rb
|
357
|
+
- lib/shopify_api/logger.rb
|
335
358
|
- lib/shopify_api/rest/base.rb
|
336
359
|
- lib/shopify_api/rest/base_errors.rb
|
337
360
|
- lib/shopify_api/rest/resources/2022_01/abandoned_checkout.rb
|