shopify_api 13.1.0 → 13.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CODEOWNERS +1 -1
  3. data/.github/workflows/build.yml +4 -0
  4. data/BREAKING_CHANGES_FOR_V10.md +231 -0
  5. data/CHANGELOG.md +14 -1
  6. data/CONTRIBUTING.md +25 -0
  7. data/Gemfile.lock +8 -15
  8. data/README.md +10 -34
  9. data/ROADMAP.md +10 -0
  10. data/docs/README.md +0 -1
  11. data/docs/getting_started.md +20 -3
  12. data/docs/usage/custom_apps.md +75 -0
  13. data/docs/usage/graphql.md +63 -18
  14. data/docs/usage/oauth.md +160 -27
  15. data/docs/usage/rest.md +204 -62
  16. data/docs/usage/webhooks.md +22 -4
  17. data/lib/shopify_api/admin_versions.rb +2 -1
  18. data/lib/shopify_api/auth/jwt_payload.rb +2 -2
  19. data/lib/shopify_api/auth/oauth.rb +15 -5
  20. data/lib/shopify_api/clients/http_client.rb +5 -1
  21. data/lib/shopify_api/context.rb +11 -5
  22. data/lib/shopify_api/rest/base.rb +22 -14
  23. data/lib/shopify_api/rest/resources/2022_10/assigned_fulfillment_order.rb +5 -3
  24. data/lib/shopify_api/rest/resources/2022_10/customer_address.rb +10 -0
  25. data/lib/shopify_api/rest/resources/2022_10/fulfillment_request.rb +10 -0
  26. data/lib/shopify_api/rest/resources/2022_10/order_risk.rb +5 -3
  27. data/lib/shopify_api/rest/resources/2023_01/assigned_fulfillment_order.rb +5 -3
  28. data/lib/shopify_api/rest/resources/2023_01/balance.rb +4 -0
  29. data/lib/shopify_api/rest/resources/2023_01/customer_address.rb +10 -0
  30. data/lib/shopify_api/rest/resources/2023_01/fulfillment_request.rb +10 -0
  31. data/lib/shopify_api/rest/resources/2023_01/order.rb +3 -0
  32. data/lib/shopify_api/rest/resources/2023_01/order_risk.rb +5 -3
  33. data/lib/shopify_api/rest/resources/2023_01/shop.rb +0 -3
  34. data/lib/shopify_api/rest/resources/2023_01/variant.rb +1 -5
  35. data/lib/shopify_api/rest/resources/2023_04/assigned_fulfillment_order.rb +5 -3
  36. data/lib/shopify_api/rest/resources/2023_04/balance.rb +4 -0
  37. data/lib/shopify_api/rest/resources/2023_04/customer_address.rb +10 -0
  38. data/lib/shopify_api/rest/resources/2023_04/fulfillment_request.rb +10 -0
  39. data/lib/shopify_api/rest/resources/2023_04/order.rb +3 -0
  40. data/lib/shopify_api/rest/resources/2023_04/order_risk.rb +5 -3
  41. data/lib/shopify_api/rest/resources/2023_04/shop.rb +0 -3
  42. data/lib/shopify_api/rest/resources/2023_04/variant.rb +1 -5
  43. data/lib/shopify_api/rest/resources/2023_07/assigned_fulfillment_order.rb +5 -3
  44. data/lib/shopify_api/rest/resources/2023_07/balance.rb +4 -0
  45. data/lib/shopify_api/rest/resources/2023_07/customer_address.rb +10 -0
  46. data/lib/shopify_api/rest/resources/2023_07/fulfillment_request.rb +10 -0
  47. data/lib/shopify_api/rest/resources/2023_07/order.rb +3 -0
  48. data/lib/shopify_api/rest/resources/2023_07/order_risk.rb +5 -3
  49. data/lib/shopify_api/rest/resources/2023_07/report.rb +121 -0
  50. data/lib/shopify_api/rest/resources/2023_07/shop.rb +0 -3
  51. data/lib/shopify_api/rest/resources/2023_07/variant.rb +1 -5
  52. data/lib/shopify_api/rest/resources/2023_10/abandoned_checkout.rb +190 -0
  53. data/lib/shopify_api/rest/resources/2023_10/access_scope.rb +58 -0
  54. data/lib/shopify_api/rest/resources/2023_10/apple_pay_certificate.rb +105 -0
  55. data/lib/shopify_api/rest/resources/2023_10/application_charge.rb +109 -0
  56. data/lib/shopify_api/rest/resources/2023_10/application_credit.rb +91 -0
  57. data/lib/shopify_api/rest/resources/2023_10/article.rb +265 -0
  58. data/lib/shopify_api/rest/resources/2023_10/asset.rb +118 -0
  59. data/lib/shopify_api/rest/resources/2023_10/assigned_fulfillment_order.rb +88 -0
  60. data/lib/shopify_api/rest/resources/2023_10/balance.rb +54 -0
  61. data/lib/shopify_api/rest/resources/2023_10/blog.rb +162 -0
  62. data/lib/shopify_api/rest/resources/2023_10/cancellation_request.rb +83 -0
  63. data/lib/shopify_api/rest/resources/2023_10/carrier_service.rb +116 -0
  64. data/lib/shopify_api/rest/resources/2023_10/checkout.rb +209 -0
  65. data/lib/shopify_api/rest/resources/2023_10/collect.rb +142 -0
  66. data/lib/shopify_api/rest/resources/2023_10/collection.rb +110 -0
  67. data/lib/shopify_api/rest/resources/2023_10/collection_listing.rb +155 -0
  68. data/lib/shopify_api/rest/resources/2023_10/comment.rb +283 -0
  69. data/lib/shopify_api/rest/resources/2023_10/country.rb +137 -0
  70. data/lib/shopify_api/rest/resources/2023_10/currency.rb +57 -0
  71. data/lib/shopify_api/rest/resources/2023_10/custom_collection.rb +187 -0
  72. data/lib/shopify_api/rest/resources/2023_10/customer.rb +329 -0
  73. data/lib/shopify_api/rest/resources/2023_10/customer_address.rb +211 -0
  74. data/lib/shopify_api/rest/resources/2023_10/deprecated_api_call.rb +57 -0
  75. data/lib/shopify_api/rest/resources/2023_10/discount_code.rb +222 -0
  76. data/lib/shopify_api/rest/resources/2023_10/dispute.rb +111 -0
  77. data/lib/shopify_api/rest/resources/2023_10/dispute_evidence.rb +117 -0
  78. data/lib/shopify_api/rest/resources/2023_10/dispute_file_upload.rb +81 -0
  79. data/lib/shopify_api/rest/resources/2023_10/draft_order.rb +275 -0
  80. data/lib/shopify_api/rest/resources/2023_10/event.rb +148 -0
  81. data/lib/shopify_api/rest/resources/2023_10/fulfillment.rb +231 -0
  82. data/lib/shopify_api/rest/resources/2023_10/fulfillment_event.rb +166 -0
  83. data/lib/shopify_api/rest/resources/2023_10/fulfillment_order.rb +312 -0
  84. data/lib/shopify_api/rest/resources/2023_10/fulfillment_request.rb +97 -0
  85. data/lib/shopify_api/rest/resources/2023_10/fulfillment_service.rb +130 -0
  86. data/lib/shopify_api/rest/resources/2023_10/gift_card.rb +218 -0
  87. data/lib/shopify_api/rest/resources/2023_10/gift_card_adjustment.rb +118 -0
  88. data/lib/shopify_api/rest/resources/2023_10/image.rb +157 -0
  89. data/lib/shopify_api/rest/resources/2023_10/inventory_item.rb +108 -0
  90. data/lib/shopify_api/rest/resources/2023_10/inventory_level.rb +179 -0
  91. data/lib/shopify_api/rest/resources/2023_10/location.rb +167 -0
  92. data/lib/shopify_api/rest/resources/2023_10/locations_for_move.rb +56 -0
  93. data/lib/shopify_api/rest/resources/2023_10/marketing_event.rb +209 -0
  94. data/lib/shopify_api/rest/resources/2023_10/metafield.rb +344 -0
  95. data/lib/shopify_api/rest/resources/2023_10/mobile_platform_application.rb +110 -0
  96. data/lib/shopify_api/rest/resources/2023_10/order.rb +491 -0
  97. data/lib/shopify_api/rest/resources/2023_10/order_risk.rb +144 -0
  98. data/lib/shopify_api/rest/resources/2023_10/page.rb +194 -0
  99. data/lib/shopify_api/rest/resources/2023_10/payment.rb +140 -0
  100. data/lib/shopify_api/rest/resources/2023_10/payment_gateway.rb +143 -0
  101. data/lib/shopify_api/rest/resources/2023_10/payment_transaction.rb +107 -0
  102. data/lib/shopify_api/rest/resources/2023_10/payout.rb +97 -0
  103. data/lib/shopify_api/rest/resources/2023_10/policy.rb +69 -0
  104. data/lib/shopify_api/rest/resources/2023_10/price_rule.rb +223 -0
  105. data/lib/shopify_api/rest/resources/2023_10/product.rb +223 -0
  106. data/lib/shopify_api/rest/resources/2023_10/product_listing.rb +196 -0
  107. data/lib/shopify_api/rest/resources/2023_10/product_resource_feedback.rb +88 -0
  108. data/lib/shopify_api/rest/resources/2023_10/province.rb +132 -0
  109. data/lib/shopify_api/rest/resources/2023_10/recurring_application_charge.rb +172 -0
  110. data/lib/shopify_api/rest/resources/2023_10/redirect.rb +139 -0
  111. data/lib/shopify_api/rest/resources/2023_10/refund.rb +151 -0
  112. data/lib/shopify_api/rest/resources/2023_10/report.rb +121 -0
  113. data/lib/shopify_api/rest/resources/2023_10/resource_feedback.rb +73 -0
  114. data/lib/shopify_api/rest/resources/2023_10/script_tag.rb +155 -0
  115. data/lib/shopify_api/rest/resources/2023_10/shipping_zone.rb +83 -0
  116. data/lib/shopify_api/rest/resources/2023_10/shop.rb +218 -0
  117. data/lib/shopify_api/rest/resources/2023_10/smart_collection.rb +216 -0
  118. data/lib/shopify_api/rest/resources/2023_10/storefront_access_token.rb +87 -0
  119. data/lib/shopify_api/rest/resources/2023_10/tender_transaction.rb +93 -0
  120. data/lib/shopify_api/rest/resources/2023_10/theme.rb +123 -0
  121. data/lib/shopify_api/rest/resources/2023_10/transaction.rb +184 -0
  122. data/lib/shopify_api/rest/resources/2023_10/usage_charge.rb +102 -0
  123. data/lib/shopify_api/rest/resources/2023_10/user.rb +138 -0
  124. data/lib/shopify_api/rest/resources/2023_10/variant.rb +208 -0
  125. data/lib/shopify_api/rest/resources/2023_10/webhook.rb +168 -0
  126. data/lib/shopify_api/version.rb +1 -1
  127. data/lib/shopify_api/webhooks/registration.rb +19 -4
  128. data/lib/shopify_api/webhooks/registrations/event_bridge.rb +1 -1
  129. data/lib/shopify_api/webhooks/registrations/http.rb +1 -1
  130. data/lib/shopify_api/webhooks/registrations/pub_sub.rb +2 -1
  131. data/lib/shopify_api/webhooks/registry.rb +25 -5
  132. data/shopify_api.gemspec +0 -1
  133. metadata +81 -20
  134. data/.github/workflows/stale.yml +0 -43
  135. data/docs/issues.md +0 -39
  136. data/docs/usage/session_storage.md +0 -46
@@ -0,0 +1,208 @@
1
+ # typed: false
2
+ # frozen_string_literal: true
3
+
4
+ ########################################################################################################################
5
+ # This file is auto-generated. If you have an issue, please create a GitHub issue. #
6
+ ########################################################################################################################
7
+
8
+ module ShopifyAPI
9
+ class Variant < ShopifyAPI::Rest::Base
10
+ extend T::Sig
11
+
12
+ @prev_page_info = T.let(Concurrent::ThreadLocalVar.new { nil }, Concurrent::ThreadLocalVar)
13
+ @next_page_info = T.let(Concurrent::ThreadLocalVar.new { nil }, Concurrent::ThreadLocalVar)
14
+
15
+ sig { params(session: T.nilable(ShopifyAPI::Auth::Session)).void }
16
+ def initialize(session: ShopifyAPI::Context.active_session)
17
+ super(session: session)
18
+
19
+ @barcode = T.let(nil, T.nilable(String))
20
+ @compare_at_price = T.let(nil, T.nilable(String))
21
+ @created_at = T.let(nil, T.nilable(String))
22
+ @fulfillment_service = T.let(nil, T.nilable(String))
23
+ @grams = T.let(nil, T.nilable(Integer))
24
+ @id = T.let(nil, T.nilable(Integer))
25
+ @image_id = T.let(nil, T.nilable(Integer))
26
+ @inventory_item_id = T.let(nil, T.nilable(Integer))
27
+ @inventory_management = T.let(nil, T.nilable(String))
28
+ @inventory_policy = T.let(nil, T.nilable(String))
29
+ @inventory_quantity = T.let(nil, T.nilable(Integer))
30
+ @old_inventory_quantity = T.let(nil, T.nilable(Integer))
31
+ @option = T.let(nil, T.nilable(T::Hash[T.untyped, T.untyped]))
32
+ @position = T.let(nil, T.nilable(Integer))
33
+ @presentment_prices = T.let(nil, T.nilable(T::Array[T.untyped]))
34
+ @price = T.let(nil, T.nilable(String))
35
+ @product_id = T.let(nil, T.nilable(Integer))
36
+ @requires_shipping = T.let(nil, T.nilable(T::Boolean))
37
+ @sku = T.let(nil, T.nilable(String))
38
+ @tax_code = T.let(nil, T.nilable(String))
39
+ @taxable = T.let(nil, T.nilable(T::Boolean))
40
+ @title = T.let(nil, T.nilable(String))
41
+ @updated_at = T.let(nil, T.nilable(String))
42
+ @weight = T.let(nil, T.nilable(Float))
43
+ @weight_unit = T.let(nil, T.nilable(String))
44
+ end
45
+
46
+ @has_one = T.let({}, T::Hash[Symbol, Class])
47
+ @has_many = T.let({}, T::Hash[Symbol, Class])
48
+ @paths = T.let([
49
+ {http_method: :delete, operation: :delete, ids: [:product_id, :id], path: "products/<product_id>/variants/<id>.json"},
50
+ {http_method: :get, operation: :count, ids: [:product_id], path: "products/<product_id>/variants/count.json"},
51
+ {http_method: :get, operation: :get, ids: [:product_id], path: "products/<product_id>/variants.json"},
52
+ {http_method: :get, operation: :get, ids: [:id], path: "variants/<id>.json"},
53
+ {http_method: :post, operation: :post, ids: [:product_id], path: "products/<product_id>/variants.json"},
54
+ {http_method: :put, operation: :put, ids: [:id], path: "variants/<id>.json"}
55
+ ], T::Array[T::Hash[String, T.any(T::Array[Symbol], String, Symbol)]])
56
+ @read_only_attributes = T.let([
57
+ :inventory_quantity
58
+ ], T::Array[Symbol])
59
+
60
+ sig { returns(T.nilable(String)) }
61
+ attr_reader :barcode
62
+ sig { returns(T.nilable(String)) }
63
+ attr_reader :compare_at_price
64
+ sig { returns(T.nilable(String)) }
65
+ attr_reader :created_at
66
+ sig { returns(T.nilable(String)) }
67
+ attr_reader :fulfillment_service
68
+ sig { returns(T.nilable(Integer)) }
69
+ attr_reader :grams
70
+ sig { returns(T.nilable(Integer)) }
71
+ attr_reader :id
72
+ sig { returns(T.nilable(Integer)) }
73
+ attr_reader :image_id
74
+ sig { returns(T.nilable(Integer)) }
75
+ attr_reader :inventory_item_id
76
+ sig { returns(T.nilable(String)) }
77
+ attr_reader :inventory_management
78
+ sig { returns(T.nilable(String)) }
79
+ attr_reader :inventory_policy
80
+ sig { returns(T.nilable(Integer)) }
81
+ attr_reader :inventory_quantity
82
+ sig { returns(T.nilable(Integer)) }
83
+ attr_reader :old_inventory_quantity
84
+ sig { returns(T.nilable(T::Hash[T.untyped, T.untyped])) }
85
+ attr_reader :option
86
+ sig { returns(T.nilable(Integer)) }
87
+ attr_reader :position
88
+ sig { returns(T.nilable(T::Array[T::Hash[T.untyped, T.untyped]])) }
89
+ attr_reader :presentment_prices
90
+ sig { returns(T.nilable(String)) }
91
+ attr_reader :price
92
+ sig { returns(T.nilable(Integer)) }
93
+ attr_reader :product_id
94
+ sig { returns(T.nilable(T::Boolean)) }
95
+ attr_reader :requires_shipping
96
+ sig { returns(T.nilable(String)) }
97
+ attr_reader :sku
98
+ sig { returns(T.nilable(String)) }
99
+ attr_reader :tax_code
100
+ sig { returns(T.nilable(T::Boolean)) }
101
+ attr_reader :taxable
102
+ sig { returns(T.nilable(String)) }
103
+ attr_reader :title
104
+ sig { returns(T.nilable(String)) }
105
+ attr_reader :updated_at
106
+ sig { returns(T.nilable(Float)) }
107
+ attr_reader :weight
108
+ sig { returns(T.nilable(String)) }
109
+ attr_reader :weight_unit
110
+
111
+ class << self
112
+ sig do
113
+ params(
114
+ id: T.any(Integer, String),
115
+ fields: T.untyped,
116
+ session: Auth::Session
117
+ ).returns(T.nilable(Variant))
118
+ end
119
+ def find(
120
+ id:,
121
+ fields: nil,
122
+ session: ShopifyAPI::Context.active_session
123
+ )
124
+ result = base_find(
125
+ session: session,
126
+ ids: {id: id},
127
+ params: {fields: fields},
128
+ )
129
+ T.cast(result[0], T.nilable(Variant))
130
+ end
131
+
132
+ sig do
133
+ params(
134
+ id: T.any(Integer, String),
135
+ product_id: T.nilable(T.any(Integer, String)),
136
+ session: Auth::Session
137
+ ).returns(T.untyped)
138
+ end
139
+ def delete(
140
+ id:,
141
+ product_id: nil,
142
+ session: ShopifyAPI::Context.active_session
143
+ )
144
+ request(
145
+ http_method: :delete,
146
+ operation: :delete,
147
+ session: session,
148
+ ids: {id: id, product_id: product_id},
149
+ params: {},
150
+ )
151
+ end
152
+
153
+ sig do
154
+ params(
155
+ product_id: T.nilable(T.any(Integer, String)),
156
+ limit: T.untyped,
157
+ presentment_currencies: T.untyped,
158
+ since_id: T.untyped,
159
+ fields: T.untyped,
160
+ session: Auth::Session,
161
+ kwargs: T.untyped
162
+ ).returns(T::Array[Variant])
163
+ end
164
+ def all(
165
+ product_id: nil,
166
+ limit: nil,
167
+ presentment_currencies: nil,
168
+ since_id: nil,
169
+ fields: nil,
170
+ session: ShopifyAPI::Context.active_session,
171
+ **kwargs
172
+ )
173
+ response = base_find(
174
+ session: session,
175
+ ids: {product_id: product_id},
176
+ params: {limit: limit, presentment_currencies: presentment_currencies, since_id: since_id, fields: fields}.merge(kwargs).compact,
177
+ )
178
+
179
+ T.cast(response, T::Array[Variant])
180
+ end
181
+
182
+ sig do
183
+ params(
184
+ product_id: T.nilable(T.any(Integer, String)),
185
+ session: Auth::Session,
186
+ kwargs: T.untyped
187
+ ).returns(T.untyped)
188
+ end
189
+ def count(
190
+ product_id: nil,
191
+ session: ShopifyAPI::Context.active_session,
192
+ **kwargs
193
+ )
194
+ request(
195
+ http_method: :get,
196
+ operation: :count,
197
+ session: session,
198
+ ids: {product_id: product_id},
199
+ params: {}.merge(kwargs).compact,
200
+ body: {},
201
+ entity: nil,
202
+ )
203
+ end
204
+
205
+ end
206
+
207
+ end
208
+ end
@@ -0,0 +1,168 @@
1
+ # typed: false
2
+ # frozen_string_literal: true
3
+
4
+ ########################################################################################################################
5
+ # This file is auto-generated. If you have an issue, please create a GitHub issue. #
6
+ ########################################################################################################################
7
+
8
+ module ShopifyAPI
9
+ class Webhook < ShopifyAPI::Rest::Base
10
+ extend T::Sig
11
+
12
+ @prev_page_info = T.let(Concurrent::ThreadLocalVar.new { nil }, Concurrent::ThreadLocalVar)
13
+ @next_page_info = T.let(Concurrent::ThreadLocalVar.new { nil }, Concurrent::ThreadLocalVar)
14
+
15
+ sig { params(session: T.nilable(ShopifyAPI::Auth::Session)).void }
16
+ def initialize(session: ShopifyAPI::Context.active_session)
17
+ super(session: session)
18
+
19
+ @address = T.let(nil, T.nilable(String))
20
+ @topic = T.let(nil, T.nilable(String))
21
+ @api_version = T.let(nil, T.nilable(String))
22
+ @created_at = T.let(nil, T.nilable(String))
23
+ @fields = T.let(nil, T.nilable(T::Array[T.untyped]))
24
+ @format = T.let(nil, T.nilable(String))
25
+ @id = T.let(nil, T.nilable(Integer))
26
+ @metafield_namespaces = T.let(nil, T.nilable(T::Array[T.untyped]))
27
+ @private_metafield_namespaces = T.let(nil, T.nilable(T::Array[T.untyped]))
28
+ @updated_at = T.let(nil, T.nilable(String))
29
+ end
30
+
31
+ @has_one = T.let({}, T::Hash[Symbol, Class])
32
+ @has_many = T.let({}, T::Hash[Symbol, Class])
33
+ @paths = T.let([
34
+ {http_method: :delete, operation: :delete, ids: [:id], path: "webhooks/<id>.json"},
35
+ {http_method: :get, operation: :count, ids: [], path: "webhooks/count.json"},
36
+ {http_method: :get, operation: :get, ids: [], path: "webhooks.json"},
37
+ {http_method: :get, operation: :get, ids: [:id], path: "webhooks/<id>.json"},
38
+ {http_method: :post, operation: :post, ids: [], path: "webhooks.json"},
39
+ {http_method: :put, operation: :put, ids: [:id], path: "webhooks/<id>.json"}
40
+ ], T::Array[T::Hash[String, T.any(T::Array[Symbol], String, Symbol)]])
41
+
42
+ sig { returns(T.nilable(String)) }
43
+ attr_reader :address
44
+ sig { returns(T.nilable(String)) }
45
+ attr_reader :topic
46
+ sig { returns(T.nilable(String)) }
47
+ attr_reader :api_version
48
+ sig { returns(T.nilable(String)) }
49
+ attr_reader :created_at
50
+ sig { returns(T.nilable(T::Array[String])) }
51
+ attr_reader :fields
52
+ sig { returns(T.nilable(String)) }
53
+ attr_reader :format
54
+ sig { returns(T.nilable(Integer)) }
55
+ attr_reader :id
56
+ sig { returns(T.nilable(T::Array[String])) }
57
+ attr_reader :metafield_namespaces
58
+ sig { returns(T.nilable(T::Array[String])) }
59
+ attr_reader :private_metafield_namespaces
60
+ sig { returns(T.nilable(String)) }
61
+ attr_reader :updated_at
62
+
63
+ class << self
64
+ sig do
65
+ params(
66
+ id: T.any(Integer, String),
67
+ fields: T.untyped,
68
+ session: Auth::Session
69
+ ).returns(T.nilable(Webhook))
70
+ end
71
+ def find(
72
+ id:,
73
+ fields: nil,
74
+ session: ShopifyAPI::Context.active_session
75
+ )
76
+ result = base_find(
77
+ session: session,
78
+ ids: {id: id},
79
+ params: {fields: fields},
80
+ )
81
+ T.cast(result[0], T.nilable(Webhook))
82
+ end
83
+
84
+ sig do
85
+ params(
86
+ id: T.any(Integer, String),
87
+ session: Auth::Session
88
+ ).returns(T.untyped)
89
+ end
90
+ def delete(
91
+ id:,
92
+ session: ShopifyAPI::Context.active_session
93
+ )
94
+ request(
95
+ http_method: :delete,
96
+ operation: :delete,
97
+ session: session,
98
+ ids: {id: id},
99
+ params: {},
100
+ )
101
+ end
102
+
103
+ sig do
104
+ params(
105
+ address: T.untyped,
106
+ created_at_max: T.untyped,
107
+ created_at_min: T.untyped,
108
+ fields: T.untyped,
109
+ limit: T.untyped,
110
+ since_id: T.untyped,
111
+ topic: T.untyped,
112
+ updated_at_min: T.untyped,
113
+ updated_at_max: T.untyped,
114
+ session: Auth::Session,
115
+ kwargs: T.untyped
116
+ ).returns(T::Array[Webhook])
117
+ end
118
+ def all(
119
+ address: nil,
120
+ created_at_max: nil,
121
+ created_at_min: nil,
122
+ fields: nil,
123
+ limit: nil,
124
+ since_id: nil,
125
+ topic: nil,
126
+ updated_at_min: nil,
127
+ updated_at_max: nil,
128
+ session: ShopifyAPI::Context.active_session,
129
+ **kwargs
130
+ )
131
+ response = base_find(
132
+ session: session,
133
+ ids: {},
134
+ params: {address: address, created_at_max: created_at_max, created_at_min: created_at_min, fields: fields, limit: limit, since_id: since_id, topic: topic, updated_at_min: updated_at_min, updated_at_max: updated_at_max}.merge(kwargs).compact,
135
+ )
136
+
137
+ T.cast(response, T::Array[Webhook])
138
+ end
139
+
140
+ sig do
141
+ params(
142
+ address: T.untyped,
143
+ topic: T.untyped,
144
+ session: Auth::Session,
145
+ kwargs: T.untyped
146
+ ).returns(T.untyped)
147
+ end
148
+ def count(
149
+ address: nil,
150
+ topic: nil,
151
+ session: ShopifyAPI::Context.active_session,
152
+ **kwargs
153
+ )
154
+ request(
155
+ http_method: :get,
156
+ operation: :count,
157
+ session: session,
158
+ ids: {},
159
+ params: {address: address, topic: topic}.merge(kwargs).compact,
160
+ body: {},
161
+ entity: nil,
162
+ )
163
+ end
164
+
165
+ end
166
+
167
+ end
168
+ end
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module ShopifyAPI
5
- VERSION = "13.1.0"
5
+ VERSION = "13.3.0"
6
6
  end
@@ -19,16 +19,21 @@ module ShopifyAPI
19
19
  sig { returns(T.nilable(T::Array[String])) }
20
20
  attr_reader :fields
21
21
 
22
+ sig { returns(T.nilable(T::Array[String])) }
23
+ attr_reader :metafield_namespaces
24
+
22
25
  sig do
23
26
  params(topic: String, path: String, handler: T.nilable(Handler),
24
- fields: T.nilable(T.any(String, T::Array[String]))).void
27
+ fields: T.nilable(T.any(String, T::Array[String])),
28
+ metafield_namespaces: T.nilable(T::Array[String])).void
25
29
  end
26
- def initialize(topic:, path:, handler: nil, fields: nil)
30
+ def initialize(topic:, path:, handler: nil, fields: nil, metafield_namespaces: nil)
27
31
  @topic = T.let(topic.gsub("/", "_").upcase, String)
28
32
  @path = path
29
33
  @handler = handler
30
34
  fields_array = fields.is_a?(String) ? fields.split(FIELDS_DELIMITER) : fields
31
35
  @fields = T.let(fields_array&.map(&:strip)&.compact, T.nilable(T::Array[String]))
36
+ @metafield_namespaces = T.let(metafield_namespaces&.map(&:strip)&.compact, T.nilable(T::Array[String]))
32
37
  end
33
38
 
34
39
  sig { abstract.returns(String) }
@@ -51,7 +56,7 @@ module ShopifyAPI
51
56
  identifier = webhook_id ? "id: \"#{webhook_id}\"" : "topic: #{@topic}"
52
57
 
53
58
  subscription_args_string = subscription_args.map do |k, v|
54
- "#{k}: #{k == :includeFields ? v : '"' + v + '"'}"
59
+ "#{k}: #{[:includeFields, :metafieldNamespaces].include?(k) ? v : %("#{v}")}"
55
60
  end.join(", ")
56
61
 
57
62
  <<~QUERY
@@ -62,12 +67,22 @@ module ShopifyAPI
62
67
  message
63
68
  }
64
69
  webhookSubscription {
65
- id#{@fields.nil? ? "" : "\n includeFields"}
70
+ #{subscription_response_attributes.join("\n ")}
66
71
  }
67
72
  }
68
73
  }
69
74
  QUERY
70
75
  end
76
+
77
+ private
78
+
79
+ sig { returns(T::Array[String]) }
80
+ def subscription_response_attributes
81
+ attributes = ["id"]
82
+ attributes << "includeFields" if @fields
83
+ attributes << "metafieldNamespaces" if @metafield_namespaces
84
+ attributes
85
+ end
71
86
  end
72
87
  end
73
88
  end
@@ -14,7 +14,7 @@ module ShopifyAPI
14
14
 
15
15
  sig { override.returns(T::Hash[Symbol, String]) }
16
16
  def subscription_args
17
- { arn: callback_address, includeFields: fields }.compact
17
+ { arn: callback_address, includeFields: fields, metafieldNamespaces: metafield_namespaces }.compact
18
18
  end
19
19
 
20
20
  sig { override.params(webhook_id: T.nilable(String)).returns(String) }
@@ -20,7 +20,7 @@ module ShopifyAPI
20
20
 
21
21
  sig { override.returns(T::Hash[Symbol, String]) }
22
22
  def subscription_args
23
- { callbackUrl: callback_address, includeFields: fields }.compact
23
+ { callbackUrl: callback_address, includeFields: fields, metafieldNamespaces: metafield_namespaces }.compact
24
24
  end
25
25
 
26
26
  sig { override.params(webhook_id: T.nilable(String)).returns(String) }
@@ -17,7 +17,8 @@ module ShopifyAPI
17
17
  project_topic_pair = callback_address.gsub(%r{^pubsub://}, "").split(":")
18
18
  project = project_topic_pair[0]
19
19
  topic = project_topic_pair[1]
20
- { pubSubProject: project, pubSubTopic: topic, includeFields: fields }.compact
20
+ { pubSubProject: project, pubSubTopic: topic, includeFields: fields,
21
+ metafieldNamespaces: metafield_namespaces, }.compact
21
22
  end
22
23
 
23
24
  sig { override.params(webhook_id: T.nilable(String)).returns(String) }
@@ -5,6 +5,11 @@ module ShopifyAPI
5
5
  module Webhooks
6
6
  class Registry
7
7
  @registry = T.let({}, T::Hash[String, Registration])
8
+ MANDATORY_TOPICS = T.let([
9
+ "shop/redact",
10
+ "customers/redact",
11
+ "customers/data_request",
12
+ ].freeze, T::Array[String])
8
13
 
9
14
  class << self
10
15
  extend T::Sig
@@ -13,20 +18,26 @@ module ShopifyAPI
13
18
  delivery_method: Symbol,
14
19
  path: String,
15
20
  handler: T.nilable(Handler),
16
- fields: T.nilable(String)).void
21
+ fields: T.nilable(T.any(String, T::Array[String])),
22
+ metafield_namespaces: T.nilable(T::Array[String])).void
17
23
  end
18
- def add_registration(topic:, delivery_method:, path:, handler: nil, fields: nil)
24
+ def add_registration(topic:, delivery_method:, path:, handler: nil, fields: nil, metafield_namespaces: nil)
25
+ return if mandatory_webhook_topic?(topic)
26
+
19
27
  @registry[topic] = case delivery_method
20
28
  when :pub_sub
21
- Registrations::PubSub.new(topic: topic, path: path, fields: fields)
29
+ Registrations::PubSub.new(topic: topic, path: path, fields: fields,
30
+ metafield_namespaces: metafield_namespaces)
22
31
  when :event_bridge
23
- Registrations::EventBridge.new(topic: topic, path: path, fields: fields)
32
+ Registrations::EventBridge.new(topic: topic, path: path, fields: fields,
33
+ metafield_namespaces: metafield_namespaces)
24
34
  when :http
25
35
  unless handler
26
36
  raise Errors::InvalidWebhookRegistrationError, "Cannot create an Http registration without a handler."
27
37
  end
28
38
 
29
- Registrations::Http.new(topic: topic, path: path, handler: handler, fields: fields)
39
+ Registrations::Http.new(topic: topic, path: path, handler: handler,
40
+ fields: fields, metafield_namespaces: metafield_namespaces)
30
41
  else
31
42
  raise Errors::InvalidWebhookRegistrationError,
32
43
  "Unsupported delivery method #{delivery_method}. Allowed values: {:http, :pub_sub, :event_bridge}."
@@ -97,6 +108,8 @@ module ShopifyAPI
97
108
  ).returns(T::Hash[String, T.untyped])
98
109
  end
99
110
  def unregister(topic:, session:)
111
+ return { "response": nil } if mandatory_webhook_topic?(topic)
112
+
100
113
  client = Clients::Graphql::Admin.new(session: session)
101
114
 
102
115
  webhook_id = get_webhook_id(topic: topic, client: client)
@@ -209,6 +222,13 @@ module ShopifyAPI
209
222
  def registration_sucessful?(body, mutation_name)
210
223
  !body.dig("data", mutation_name, "webhookSubscription").nil?
211
224
  end
225
+
226
+ # Mandatory webhooks are subscribed to via the partner dashboard not the API
227
+ # https://shopify.dev/docs/apps/webhooks/configuration/mandatory-webhooks
228
+ sig { params(topic: String).returns(T::Boolean) }
229
+ def mandatory_webhook_topic?(topic)
230
+ MANDATORY_TOPICS.include?(topic)
231
+ end
212
232
  end
213
233
  end
214
234
  end
data/shopify_api.gemspec CHANGED
@@ -48,7 +48,6 @@ Gem::Specification.new do |s|
48
48
  s.add_development_dependency("rubocop")
49
49
  s.add_development_dependency("rubocop-shopify")
50
50
  s.add_development_dependency("rubocop-sorbet")
51
- s.add_development_dependency("ruby-lsp")
52
51
  s.add_development_dependency("sorbet")
53
52
  s.add_development_dependency("tapioca")
54
53
  end