shopify_api 11.1.0 → 12.4.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 (214) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/BUG_REPORT.md +40 -0
  3. data/.github/ISSUE_TEMPLATE/ENHANCEMENT.md +9 -0
  4. data/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md +9 -0
  5. data/.github/workflows/build.yml +0 -3
  6. data/.github/workflows/close-waiting-for-response-issues.yml +20 -0
  7. data/.github/workflows/remove-labels-on-activity.yml +16 -0
  8. data/.github/workflows/stale.yml +33 -0
  9. data/CHANGELOG.md +30 -0
  10. data/Gemfile +1 -0
  11. data/Gemfile.lock +55 -39
  12. data/README.md +12 -14
  13. data/docs/getting_started.md +1 -1
  14. data/docs/usage/oauth.md +3 -4
  15. data/docs/usage/session_storage.md +1 -1
  16. data/lib/shopify_api/admin_versions.rb +3 -2
  17. data/lib/shopify_api/auth/jwt_payload.rb +2 -2
  18. data/lib/shopify_api/auth/oauth/auth_query.rb +1 -1
  19. data/lib/shopify_api/auth/oauth.rb +18 -12
  20. data/lib/shopify_api/auth/session.rb +1 -1
  21. data/lib/shopify_api/clients/graphql/client.rb +3 -3
  22. data/lib/shopify_api/clients/graphql/storefront.rb +2 -2
  23. data/lib/shopify_api/clients/http_client.rb +4 -4
  24. data/lib/shopify_api/clients/rest/admin.rb +10 -10
  25. data/lib/shopify_api/context.rb +57 -16
  26. data/lib/shopify_api/errors/feature_deprecated_error.rb +9 -0
  27. data/lib/shopify_api/errors/http_response_error.rb +7 -3
  28. data/lib/shopify_api/errors/log_level_not_found_error.rb +9 -0
  29. data/lib/shopify_api/logger.rb +82 -0
  30. data/lib/shopify_api/rest/base.rb +14 -7
  31. data/lib/shopify_api/rest/resources/2022_01/abandoned_checkout.rb +4 -3
  32. data/lib/shopify_api/rest/resources/2022_01/assigned_fulfillment_order.rb +7 -0
  33. data/lib/shopify_api/rest/resources/2022_01/customer.rb +35 -1
  34. data/lib/shopify_api/rest/resources/2022_01/draft_order.rb +3 -1
  35. data/lib/shopify_api/rest/resources/2022_01/fulfillment.rb +5 -1
  36. data/lib/shopify_api/rest/resources/2022_01/fulfillment_order.rb +3 -3
  37. data/lib/shopify_api/rest/resources/2022_01/fulfillment_request.rb +5 -1
  38. data/lib/shopify_api/rest/resources/2022_01/gift_card.rb +9 -1
  39. data/lib/shopify_api/rest/resources/2022_01/metafield.rb +12 -5
  40. data/lib/shopify_api/rest/resources/2022_04/abandoned_checkout.rb +4 -3
  41. data/lib/shopify_api/rest/resources/2022_04/assigned_fulfillment_order.rb +7 -0
  42. data/lib/shopify_api/rest/resources/2022_04/customer.rb +35 -1
  43. data/lib/shopify_api/rest/resources/2022_04/draft_order.rb +3 -1
  44. data/lib/shopify_api/rest/resources/2022_04/fulfillment.rb +5 -1
  45. data/lib/shopify_api/rest/resources/2022_04/fulfillment_order.rb +3 -3
  46. data/lib/shopify_api/rest/resources/2022_04/fulfillment_request.rb +5 -1
  47. data/lib/shopify_api/rest/resources/2022_04/gift_card.rb +9 -1
  48. data/lib/shopify_api/rest/resources/2022_04/metafield.rb +10 -8
  49. data/lib/shopify_api/rest/resources/2022_07/abandoned_checkout.rb +4 -3
  50. data/lib/shopify_api/rest/resources/2022_07/assigned_fulfillment_order.rb +7 -0
  51. data/lib/shopify_api/rest/resources/2022_07/customer.rb +29 -1
  52. data/lib/shopify_api/rest/resources/2022_07/dispute_evidence.rb +2 -2
  53. data/lib/shopify_api/rest/resources/2022_07/fulfillment.rb +5 -1
  54. data/lib/shopify_api/rest/resources/2022_07/fulfillment_order.rb +3 -3
  55. data/lib/shopify_api/rest/resources/2022_07/gift_card.rb +9 -1
  56. data/lib/shopify_api/rest/resources/2022_07/metafield.rb +10 -8
  57. data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/abandoned_checkout.rb +4 -3
  58. data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/assigned_fulfillment_order.rb +7 -0
  59. data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/carrier_service.rb +0 -3
  60. data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/customer.rb +38 -1
  61. data/lib/shopify_api/rest/resources/2022_10/dispute_evidence.rb +117 -0
  62. data/lib/shopify_api/rest/resources/2022_10/dispute_file_upload.rb +81 -0
  63. data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/draft_order.rb +3 -1
  64. data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/fulfillment.rb +7 -50
  65. data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/fulfillment_order.rb +33 -4
  66. data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/fulfillment_request.rb +5 -1
  67. data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/fulfillment_service.rb +3 -3
  68. data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/gift_card.rb +9 -1
  69. data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/metafield.rb +10 -8
  70. data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/order.rb +3 -0
  71. data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/price_rule.rb +3 -3
  72. data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/shop.rb +3 -0
  73. data/lib/shopify_api/rest/resources/2023_01/abandoned_checkout.rb +190 -0
  74. data/lib/shopify_api/rest/resources/2023_01/access_scope.rb +58 -0
  75. data/lib/shopify_api/rest/resources/2023_01/apple_pay_certificate.rb +105 -0
  76. data/lib/shopify_api/rest/resources/2023_01/application_charge.rb +104 -0
  77. data/lib/shopify_api/rest/resources/2023_01/application_credit.rb +87 -0
  78. data/lib/shopify_api/rest/resources/2023_01/article.rb +265 -0
  79. data/lib/shopify_api/rest/resources/2023_01/asset.rb +118 -0
  80. data/lib/shopify_api/rest/resources/2023_01/assigned_fulfillment_order.rb +86 -0
  81. data/lib/shopify_api/rest/resources/2023_01/balance.rb +50 -0
  82. data/lib/shopify_api/rest/resources/2023_01/blog.rb +162 -0
  83. data/lib/shopify_api/rest/resources/2023_01/cancellation_request.rb +83 -0
  84. data/lib/shopify_api/rest/resources/2023_01/carrier_service.rb +113 -0
  85. data/lib/shopify_api/rest/resources/2023_01/checkout.rb +209 -0
  86. data/lib/shopify_api/rest/resources/2023_01/collect.rb +142 -0
  87. data/lib/shopify_api/rest/resources/2023_01/collection.rb +110 -0
  88. data/lib/shopify_api/rest/resources/2023_01/collection_listing.rb +155 -0
  89. data/lib/shopify_api/rest/resources/2023_01/comment.rb +283 -0
  90. data/lib/shopify_api/rest/resources/2023_01/country.rb +137 -0
  91. data/lib/shopify_api/rest/resources/2023_01/currency.rb +57 -0
  92. data/lib/shopify_api/rest/resources/2023_01/custom_collection.rb +187 -0
  93. data/lib/shopify_api/rest/resources/2023_01/customer.rb +329 -0
  94. data/lib/shopify_api/rest/resources/2023_01/customer_address.rb +201 -0
  95. data/lib/shopify_api/rest/resources/2023_01/customer_saved_search.rb +169 -0
  96. data/lib/shopify_api/rest/resources/2023_01/deprecated_api_call.rb +57 -0
  97. data/lib/shopify_api/rest/resources/2023_01/discount_code.rb +219 -0
  98. data/lib/shopify_api/rest/resources/2023_01/dispute.rb +111 -0
  99. data/lib/shopify_api/rest/resources/2023_01/draft_order.rb +275 -0
  100. data/lib/shopify_api/rest/resources/2023_01/event.rb +148 -0
  101. data/lib/shopify_api/rest/resources/2023_01/fulfillment.rb +225 -0
  102. data/lib/shopify_api/rest/resources/2023_01/fulfillment_event.rb +166 -0
  103. data/lib/shopify_api/rest/resources/2023_01/fulfillment_order.rb +316 -0
  104. data/lib/shopify_api/rest/resources/2023_01/fulfillment_request.rb +87 -0
  105. data/lib/shopify_api/rest/resources/2023_01/fulfillment_service.rb +130 -0
  106. data/lib/shopify_api/rest/resources/2023_01/gift_card.rb +215 -0
  107. data/lib/shopify_api/rest/resources/2023_01/gift_card_adjustment.rb +118 -0
  108. data/lib/shopify_api/rest/resources/2023_01/image.rb +157 -0
  109. data/lib/shopify_api/rest/resources/2023_01/inventory_item.rb +108 -0
  110. data/lib/shopify_api/rest/resources/2023_01/inventory_level.rb +179 -0
  111. data/lib/shopify_api/rest/resources/2023_01/location.rb +167 -0
  112. data/lib/shopify_api/rest/resources/2023_01/locations_for_move.rb +56 -0
  113. data/lib/shopify_api/rest/resources/2023_01/marketing_event.rb +209 -0
  114. data/lib/shopify_api/rest/resources/2023_01/metafield.rb +344 -0
  115. data/lib/shopify_api/rest/resources/2023_01/mobile_platform_application.rb +110 -0
  116. data/lib/shopify_api/rest/resources/2023_01/order.rb +479 -0
  117. data/lib/shopify_api/rest/resources/2023_01/order_risk.rb +135 -0
  118. data/lib/shopify_api/rest/resources/2023_01/page.rb +194 -0
  119. data/lib/shopify_api/rest/resources/2023_01/payment.rb +140 -0
  120. data/lib/shopify_api/rest/resources/2023_01/payment_gateway.rb +143 -0
  121. data/lib/shopify_api/rest/resources/2023_01/payment_transaction.rb +107 -0
  122. data/lib/shopify_api/rest/resources/2023_01/payout.rb +97 -0
  123. data/lib/shopify_api/rest/resources/2023_01/policy.rb +69 -0
  124. data/lib/shopify_api/rest/resources/2023_01/price_rule.rb +223 -0
  125. data/lib/shopify_api/rest/resources/2023_01/product.rb +223 -0
  126. data/lib/shopify_api/rest/resources/2023_01/product_listing.rb +196 -0
  127. data/lib/shopify_api/rest/resources/2023_01/product_resource_feedback.rb +88 -0
  128. data/lib/shopify_api/rest/resources/2023_01/province.rb +132 -0
  129. data/lib/shopify_api/rest/resources/2023_01/recurring_application_charge.rb +167 -0
  130. data/lib/shopify_api/rest/resources/2023_01/redirect.rb +139 -0
  131. data/lib/shopify_api/rest/resources/2023_01/refund.rb +151 -0
  132. data/lib/shopify_api/rest/resources/2023_01/report.rb +121 -0
  133. data/lib/shopify_api/rest/resources/2023_01/resource_feedback.rb +73 -0
  134. data/lib/shopify_api/rest/resources/2023_01/script_tag.rb +155 -0
  135. data/lib/shopify_api/rest/resources/2023_01/shipping_zone.rb +83 -0
  136. data/lib/shopify_api/rest/resources/2023_01/shop.rb +221 -0
  137. data/lib/shopify_api/rest/resources/2023_01/smart_collection.rb +216 -0
  138. data/lib/shopify_api/rest/resources/2023_01/storefront_access_token.rb +87 -0
  139. data/lib/shopify_api/rest/resources/2023_01/tender_transaction.rb +93 -0
  140. data/lib/shopify_api/rest/resources/2023_01/theme.rb +120 -0
  141. data/lib/shopify_api/rest/resources/2023_01/transaction.rb +181 -0
  142. data/lib/shopify_api/rest/resources/2023_01/usage_charge.rb +97 -0
  143. data/lib/shopify_api/rest/resources/2023_01/user.rb +138 -0
  144. data/lib/shopify_api/rest/resources/2023_01/variant.rb +212 -0
  145. data/lib/shopify_api/rest/resources/2023_01/webhook.rb +168 -0
  146. data/lib/shopify_api/utils/graphql_proxy.rb +2 -2
  147. data/lib/shopify_api/utils/session_utils.rb +42 -25
  148. data/lib/shopify_api/version.rb +1 -1
  149. data/lib/shopify_api/webhooks/registrations/http.rb +7 -1
  150. data/lib/shopify_api/webhooks/registry.rb +8 -8
  151. data/service.yml +0 -1
  152. data/shopify_api.gemspec +4 -2
  153. metadata +195 -78
  154. data/.github/ISSUE_TEMPLATE.md +0 -35
  155. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/access_scope.rb +0 -0
  156. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/android_pay_key.rb +0 -0
  157. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/apple_pay_certificate.rb +0 -0
  158. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/application_charge.rb +0 -0
  159. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/application_credit.rb +0 -0
  160. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/article.rb +0 -0
  161. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/asset.rb +0 -0
  162. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/balance.rb +0 -0
  163. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/blog.rb +0 -0
  164. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/cancellation_request.rb +0 -0
  165. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/checkout.rb +0 -0
  166. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/collect.rb +0 -0
  167. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/collection.rb +0 -0
  168. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/collection_listing.rb +0 -0
  169. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/comment.rb +0 -0
  170. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/country.rb +0 -0
  171. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/currency.rb +0 -0
  172. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/custom_collection.rb +0 -0
  173. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/customer_address.rb +0 -0
  174. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/customer_saved_search.rb +0 -0
  175. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/deprecated_api_call.rb +0 -0
  176. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/discount_code.rb +0 -0
  177. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/dispute.rb +0 -0
  178. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/event.rb +0 -0
  179. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/fulfillment_event.rb +0 -0
  180. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/gift_card_adjustment.rb +0 -0
  181. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/image.rb +0 -0
  182. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/inventory_item.rb +0 -0
  183. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/inventory_level.rb +0 -0
  184. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/location.rb +0 -0
  185. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/locations_for_move.rb +0 -0
  186. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/marketing_event.rb +0 -0
  187. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/mobile_platform_application.rb +0 -0
  188. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/order_risk.rb +0 -0
  189. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/page.rb +0 -0
  190. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/payment.rb +0 -0
  191. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/payment_gateway.rb +0 -0
  192. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/payment_transaction.rb +0 -0
  193. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/payout.rb +0 -0
  194. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/policy.rb +0 -0
  195. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/product.rb +0 -0
  196. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/product_listing.rb +0 -0
  197. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/product_resource_feedback.rb +0 -0
  198. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/province.rb +0 -0
  199. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/recurring_application_charge.rb +0 -0
  200. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/redirect.rb +0 -0
  201. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/refund.rb +0 -0
  202. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/report.rb +0 -0
  203. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/resource_feedback.rb +0 -0
  204. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/script_tag.rb +0 -0
  205. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/shipping_zone.rb +0 -0
  206. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/smart_collection.rb +0 -0
  207. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/storefront_access_token.rb +0 -0
  208. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/tender_transaction.rb +0 -0
  209. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/theme.rb +0 -0
  210. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/transaction.rb +0 -0
  211. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/usage_charge.rb +0 -0
  212. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/user.rb +0 -0
  213. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/variant.rb +0 -0
  214. /data/lib/shopify_api/rest/resources/{2021_10 → 2022_10}/webhook.rb +0 -0
@@ -11,7 +11,7 @@ module ShopifyAPI
11
11
  id: shop,
12
12
  shop: shop,
13
13
  access_token: "",
14
- is_online: false
14
+ is_online: false,
15
15
  )
16
16
  super(session: session, base_path: "/api")
17
17
  @storefront_access_token = storefront_access_token
@@ -22,7 +22,7 @@ module ShopifyAPI
22
22
  query: String,
23
23
  variables: T.nilable(T::Hash[T.any(Symbol, String), T.untyped]),
24
24
  headers: T.nilable(T::Hash[T.any(Symbol, String), T.untyped]),
25
- tries: Integer
25
+ tries: Integer,
26
26
  ).returns(HttpResponse)
27
27
  end
28
28
  def query(query:, variables: nil, headers: {}, tries: 1)
@@ -45,7 +45,7 @@ module ShopifyAPI
45
45
  request_url(request),
46
46
  headers: headers,
47
47
  query: request.query,
48
- body: request.body.class == Hash ? T.unsafe(request.body).to_json : request.body
48
+ body: request.body.class == Hash ? T.unsafe(request.body).to_json : request.body,
49
49
  ), HTTParty::Response)
50
50
 
51
51
  body = res.body.empty? ? {} : JSON.parse(res.body)
@@ -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(code: response.code.to_i), error_message
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(code: response.code), error_message if request.tries == 1
76
+ raise ShopifyAPI::Errors::HttpResponseError.new(response: response), error_message if request.tries == 1
77
77
 
78
- raise ShopifyAPI::Errors::MaxHttpRetriesExceededError.new(code: response.code),
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
 
@@ -18,13 +18,13 @@ module ShopifyAPI
18
18
  body: T.nilable(T::Hash[T.any(Symbol, String), T.untyped]),
19
19
  query: T.nilable(T::Hash[T.any(Symbol, String), T.untyped]),
20
20
  headers: T.nilable(T::Hash[T.any(Symbol, String), T.untyped]),
21
- tries: T.nilable(Integer)
21
+ tries: T.nilable(Integer),
22
22
  ).returns(HttpResponse)
23
23
  end
24
24
  def get(path:, body: nil, query: nil, headers: nil, tries: 1)
25
25
  request(
26
26
  make_request(http_method: :get, path: path, body: body, query: query, headers: headers,
27
- tries: T.must(tries))
27
+ tries: T.must(tries)),
28
28
  )
29
29
  end
30
30
 
@@ -34,13 +34,13 @@ module ShopifyAPI
34
34
  body: T.nilable(T::Hash[T.any(Symbol, String), T.untyped]),
35
35
  query: T.nilable(T::Hash[T.any(Symbol, String), T.untyped]),
36
36
  headers: T.nilable(T::Hash[T.any(Symbol, String), T.untyped]),
37
- tries: T.nilable(Integer)
37
+ tries: T.nilable(Integer),
38
38
  ).returns(HttpResponse)
39
39
  end
40
40
  def delete(path:, body: nil, query: nil, headers: nil, tries: 1)
41
41
  request(
42
42
  make_request(http_method: :delete, path: path, body: body, query: query, headers: headers,
43
- tries: T.must(tries))
43
+ tries: T.must(tries)),
44
44
  )
45
45
  end
46
46
 
@@ -50,13 +50,13 @@ module ShopifyAPI
50
50
  body: T::Hash[T.any(Symbol, String), T.untyped],
51
51
  query: T.nilable(T::Hash[T.any(Symbol, String), T.untyped]),
52
52
  headers: T.nilable(T::Hash[T.any(Symbol, String), T.untyped]),
53
- tries: T.nilable(Integer)
53
+ tries: T.nilable(Integer),
54
54
  ).returns(HttpResponse)
55
55
  end
56
56
  def put(path:, body:, query: nil, headers: nil, tries: 1)
57
57
  request(
58
58
  make_request(http_method: :put, path: path, body: body, query: query, headers: headers,
59
- tries: T.must(tries))
59
+ tries: T.must(tries)),
60
60
  )
61
61
  end
62
62
 
@@ -66,13 +66,13 @@ module ShopifyAPI
66
66
  body: T::Hash[T.any(Symbol, String), T.untyped],
67
67
  query: T.nilable(T::Hash[T.any(Symbol, String), T.untyped]),
68
68
  headers: T.nilable(T::Hash[T.any(Symbol, String), T.untyped]),
69
- tries: T.nilable(Integer)
69
+ tries: T.nilable(Integer),
70
70
  ).returns(HttpResponse)
71
71
  end
72
72
  def post(path:, body:, query: nil, headers: nil, tries: 1)
73
73
  request(
74
74
  make_request(http_method: :post, path: path, body: body, query: query, headers: headers,
75
- tries: T.must(tries))
75
+ tries: T.must(tries)),
76
76
  )
77
77
  end
78
78
 
@@ -98,7 +98,7 @@ module ShopifyAPI
98
98
  body: T.nilable(T::Hash[T.any(Symbol, String), T.untyped]),
99
99
  query: T.nilable(T::Hash[T.any(Symbol, String), T.untyped]),
100
100
  headers: T.nilable(T::Hash[T.any(Symbol, String), T.untyped]),
101
- tries: Integer
101
+ tries: Integer,
102
102
  ).returns(HttpRequest)
103
103
  end
104
104
  def make_request(http_method:, path:, body:, query:, headers:, tries:)
@@ -109,7 +109,7 @@ module ShopifyAPI
109
109
  query: query,
110
110
  extra_headers: headers,
111
111
  body_type: body.nil? ? nil : "application/json",
112
- tries: tries
112
+ tries: tries,
113
113
  )
114
114
  end
115
115
  end
@@ -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,14 @@ 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
- session_storage: ShopifyAPI::Auth::SessionStorage,
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),
40
+ host: T.nilable(String),
39
41
  private_shop: T.nilable(String),
40
42
  user_agent_prefix: T.nilable(String),
41
43
  old_api_secret_key: T.nilable(String),
@@ -45,25 +47,27 @@ module ShopifyAPI
45
47
  api_key:,
46
48
  api_secret_key:,
47
49
  api_version:,
48
- host_name:,
49
50
  scope:,
50
51
  is_private:,
51
52
  is_embedded:,
52
- session_storage:,
53
- logger: Logger.new($stdout),
53
+ log_level: :info,
54
+ logger: ::Logger.new($stdout),
55
+ session_storage: nil,
56
+ host_name: nil,
57
+ host: ENV["HOST"] || "https://#{host_name}",
54
58
  private_shop: nil,
55
59
  user_agent_prefix: nil,
56
60
  old_api_secret_key: nil
57
61
  )
58
62
  unless ShopifyAPI::AdminVersions::SUPPORTED_ADMIN_VERSIONS.include?(api_version)
59
63
  raise Errors::UnsupportedVersionError,
60
- "Invalid vession #{api_version}, supported versions: #{ShopifyAPI::AdminVersions::SUPPORTED_ADMIN_VERSIONS}"
64
+ "Invalid version #{api_version}, supported versions: #{ShopifyAPI::AdminVersions::SUPPORTED_ADMIN_VERSIONS}"
61
65
  end
62
66
 
63
67
  @api_key = api_key
64
68
  @api_secret_key = api_secret_key
65
69
  @api_version = api_version
66
- @host_name = host_name
70
+ @host = T.let(host, T.nilable(String))
67
71
  @is_private = is_private
68
72
  @scope = Auth::AuthScopes.new(scope)
69
73
  @is_embedded = is_embedded
@@ -72,6 +76,18 @@ module ShopifyAPI
72
76
  @private_shop = private_shop
73
77
  @user_agent_prefix = user_agent_prefix
74
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
75
91
 
76
92
  load_rest_resources(api_version: api_version)
77
93
  end
@@ -105,24 +121,27 @@ module ShopifyAPI
105
121
  end
106
122
 
107
123
  sig { returns(String) }
108
- attr_reader :api_key, :api_secret_key, :api_version, :host_name
124
+ attr_reader :api_key, :api_secret_key, :api_version
109
125
 
110
126
  sig { returns(Auth::AuthScopes) }
111
127
  attr_reader :scope
112
128
 
113
- sig { returns(ShopifyAPI::Auth::SessionStorage) }
129
+ sig { returns(T.nilable(ShopifyAPI::Auth::SessionStorage)) }
114
130
  attr_reader :session_storage
115
131
 
116
- sig { returns(Logger) }
132
+ sig { returns(::Logger) }
117
133
  attr_reader :logger
118
134
 
135
+ sig { returns(Symbol) }
136
+ attr_reader :log_level
137
+
119
138
  sig { returns(T::Boolean) }
120
139
  def private?
121
140
  @is_private
122
141
  end
123
142
 
124
143
  sig { returns(T.nilable(String)) }
125
- attr_reader :private_shop, :user_agent_prefix, :old_api_secret_key
144
+ attr_reader :private_shop, :user_agent_prefix, :old_api_secret_key, :host
126
145
 
127
146
  sig { returns(T::Boolean) }
128
147
  def embedded?
@@ -131,7 +150,7 @@ module ShopifyAPI
131
150
 
132
151
  sig { returns(T::Boolean) }
133
152
  def setup?
134
- !(api_key.empty? || api_secret_key.empty? || host_name.empty?)
153
+ [api_key, api_secret_key, T.must(host)].none?(&:empty?)
135
154
  end
136
155
 
137
156
  sig { returns(T.nilable(Auth::Session)) }
@@ -150,6 +169,28 @@ module ShopifyAPI
150
169
  def deactivate_session
151
170
  @active_session.value = nil
152
171
  end
172
+
173
+ sig { returns(String) }
174
+ def host_scheme
175
+ T.must(URI.parse(T.must(host)).scheme)
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
153
194
  end
154
195
  end
155
196
  end
@@ -0,0 +1,9 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module ShopifyAPI
5
+ module Errors
6
+ class FeatureDeprecatedError < StandardError
7
+ end
8
+ end
9
+ end
@@ -9,10 +9,14 @@ module ShopifyAPI
9
9
  sig { returns(Integer) }
10
10
  attr_reader :code
11
11
 
12
- sig { params(code: Integer).void }
13
- def initialize(code:)
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,9 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module ShopifyAPI
5
+ module Errors
6
+ class LogLevelNotFoundError < StandardError
7
+ end
8
+ end
9
+ 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
@@ -97,6 +97,11 @@ module ShopifyAPI
97
97
  class_name.underscore
98
98
  end
99
99
 
100
+ sig { returns(String) }
101
+ def json_response_body_name
102
+ class_name
103
+ end
104
+
100
105
  sig { returns(T.nilable(String)) }
101
106
  def prev_page_info
102
107
  instance_variable_get(:"@prev_page_info").value
@@ -137,7 +142,7 @@ module ShopifyAPI
137
142
  http_method: Symbol,
138
143
  operation: Symbol,
139
144
  entity: T.nilable(Base),
140
- ids: T::Hash[Symbol, T.any(Integer, String)]
145
+ ids: T::Hash[Symbol, T.any(Integer, String)],
141
146
  ).returns(T.nilable(String))
142
147
  end
143
148
  def get_path(http_method:, operation:, entity: nil, ids: {})
@@ -205,12 +210,14 @@ module ShopifyAPI
205
210
 
206
211
  body = T.cast(response.body, T::Hash[String, T.untyped])
207
212
 
208
- if body.key?(class_name.pluralize) || (body.key?(class_name) && body[class_name].is_a?(Array))
209
- (body[class_name.pluralize] || body[class_name]).each do |entry|
213
+ response_name = json_response_body_name
214
+
215
+ if body.key?(response_name.pluralize) || (body.key?(response_name) && body[response_name].is_a?(Array))
216
+ (body[response_name.pluralize] || body[response_name]).each do |entry|
210
217
  objects << create_instance(data: entry, session: session)
211
218
  end
212
- elsif body.key?(class_name)
213
- objects << create_instance(data: body[class_name], session: session)
219
+ elsif body.key?(response_name)
220
+ objects << create_instance(data: body[response_name], session: session)
214
221
  end
215
222
 
216
223
  objects
@@ -297,7 +304,7 @@ module ShopifyAPI
297
304
  element_hash = get_element_hash(
298
305
  get_property(attribute),
299
306
  T.unsafe(self.class.has_one[attribute]),
300
- saving
307
+ saving,
301
308
  )
302
309
  hash[attribute.to_s] = element_hash if element_hash || @forced_nils[attribute.to_s]
303
310
  elsif !get_property(attribute).nil? || @forced_nils[attribute.to_s]
@@ -312,7 +319,7 @@ module ShopifyAPI
312
319
  def delete(params: {})
313
320
  @client.delete(
314
321
  path: T.must(self.class.get_path(http_method: :delete, operation: :delete, entity: self)),
315
- query: params.compact
322
+ query: params.compact,
316
323
  )
317
324
  rescue ShopifyAPI::Errors::HttpResponseError => e
318
325
  @errors.errors << e
@@ -65,6 +65,7 @@ module ShopifyAPI
65
65
  discount_codes: DiscountCode
66
66
  }, T::Hash[Symbol, Class])
67
67
  @paths = T.let([
68
+ {http_method: :get, operation: :checkouts, ids: [], path: "checkouts.json"},
68
69
  {http_method: :get, operation: :checkouts, ids: [], path: "checkouts.json"}
69
70
  ], T::Array[T::Hash[String, T.any(T::Array[Symbol], String, Symbol)]])
70
71
 
@@ -150,25 +151,25 @@ module ShopifyAPI
150
151
  class << self
151
152
  sig do
152
153
  params(
153
- limit: T.untyped,
154
154
  since_id: T.untyped,
155
155
  created_at_min: T.untyped,
156
156
  created_at_max: T.untyped,
157
157
  updated_at_min: T.untyped,
158
158
  updated_at_max: T.untyped,
159
159
  status: T.untyped,
160
+ limit: T.untyped,
160
161
  session: Auth::Session,
161
162
  kwargs: T.untyped
162
163
  ).returns(T.untyped)
163
164
  end
164
165
  def checkouts(
165
- limit: nil,
166
166
  since_id: nil,
167
167
  created_at_min: nil,
168
168
  created_at_max: nil,
169
169
  updated_at_min: nil,
170
170
  updated_at_max: nil,
171
171
  status: nil,
172
+ limit: nil,
172
173
  session: ShopifyAPI::Context.active_session,
173
174
  **kwargs
174
175
  )
@@ -177,7 +178,7 @@ module ShopifyAPI
177
178
  operation: :checkouts,
178
179
  session: session,
179
180
  ids: {},
180
- params: {limit: limit, since_id: since_id, created_at_min: created_at_min, created_at_max: created_at_max, updated_at_min: updated_at_min, updated_at_max: updated_at_max, status: status}.merge(kwargs).compact,
181
+ params: {since_id: since_id, created_at_min: created_at_min, created_at_max: created_at_max, updated_at_min: updated_at_min, updated_at_max: updated_at_max, status: status, limit: limit}.merge(kwargs).compact,
181
182
  body: {},
182
183
  entity: nil,
183
184
  )
@@ -50,6 +50,13 @@ module ShopifyAPI
50
50
  attr_reader :status
51
51
 
52
52
  class << self
53
+ sig do
54
+ returns(String)
55
+ end
56
+ def json_response_body_name()
57
+ "fulfillment_order"
58
+ end
59
+
53
60
  sig do
54
61
  params(
55
62
  assignment_status: T.untyped,
@@ -33,6 +33,8 @@ module ShopifyAPI
33
33
  @multipass_identifier = T.let(nil, T.nilable(String))
34
34
  @note = T.let(nil, T.nilable(String))
35
35
  @orders_count = T.let(nil, T.nilable(Integer))
36
+ @password = T.let(nil, T.nilable(String))
37
+ @password_confirmation = T.let(nil, T.nilable(String))
36
38
  @phone = T.let(nil, T.nilable(String))
37
39
  @sms_marketing_consent = T.let(nil, T.nilable(T::Hash[T.untyped, T.untyped]))
38
40
  @state = T.let(nil, T.nilable(String))
@@ -49,6 +51,7 @@ module ShopifyAPI
49
51
  }, T::Hash[Symbol, Class])
50
52
  @has_many = T.let({}, T::Hash[Symbol, Class])
51
53
  @paths = T.let([
54
+ {http_method: :delete, operation: :delete, ids: [:id], path: "customers/<id>.json"},
52
55
  {http_method: :get, operation: :count, ids: [], path: "customers/count.json"},
53
56
  {http_method: :get, operation: :get, ids: [], path: "customers.json"},
54
57
  {http_method: :get, operation: :get, ids: [:id], path: "customers/<id>.json"},
@@ -95,6 +98,10 @@ module ShopifyAPI
95
98
  sig { returns(T.nilable(Integer)) }
96
99
  attr_reader :orders_count
97
100
  sig { returns(T.nilable(String)) }
101
+ attr_reader :password
102
+ sig { returns(T.nilable(String)) }
103
+ attr_reader :password_confirmation
104
+ sig { returns(T.nilable(String)) }
98
105
  attr_reader :phone
99
106
  sig { returns(T.nilable(T::Hash[T.untyped, T.untyped])) }
100
107
  attr_reader :sms_marketing_consent
@@ -134,6 +141,25 @@ module ShopifyAPI
134
141
  T.cast(result[0], T.nilable(Customer))
135
142
  end
136
143
 
144
+ sig do
145
+ params(
146
+ id: T.any(Integer, String),
147
+ session: Auth::Session
148
+ ).returns(T.untyped)
149
+ end
150
+ def delete(
151
+ id:,
152
+ session: ShopifyAPI::Context.active_session
153
+ )
154
+ request(
155
+ http_method: :delete,
156
+ operation: :delete,
157
+ session: session,
158
+ ids: {id: id},
159
+ params: {},
160
+ )
161
+ end
162
+
137
163
  sig do
138
164
  params(
139
165
  ids: T.untyped,
@@ -171,11 +197,19 @@ module ShopifyAPI
171
197
 
172
198
  sig do
173
199
  params(
200
+ created_at_min: T.untyped,
201
+ created_at_max: T.untyped,
202
+ updated_at_min: T.untyped,
203
+ updated_at_max: T.untyped,
174
204
  session: Auth::Session,
175
205
  kwargs: T.untyped
176
206
  ).returns(T.untyped)
177
207
  end
178
208
  def count(
209
+ created_at_min: nil,
210
+ created_at_max: nil,
211
+ updated_at_min: nil,
212
+ updated_at_max: nil,
179
213
  session: ShopifyAPI::Context.active_session,
180
214
  **kwargs
181
215
  )
@@ -184,7 +218,7 @@ module ShopifyAPI
184
218
  operation: :count,
185
219
  session: session,
186
220
  ids: {},
187
- params: {}.merge(kwargs).compact,
221
+ params: {created_at_min: created_at_min, created_at_max: created_at_max, updated_at_min: updated_at_min, updated_at_max: updated_at_max}.merge(kwargs).compact,
188
222
  body: {},
189
223
  entity: nil,
190
224
  )
@@ -248,12 +248,14 @@ module ShopifyAPI
248
248
 
249
249
  sig do
250
250
  params(
251
+ payment_gateway_id: T.untyped,
251
252
  payment_pending: T.untyped,
252
253
  body: T.untyped,
253
254
  kwargs: T.untyped
254
255
  ).returns(T.untyped)
255
256
  end
256
257
  def complete(
258
+ payment_gateway_id: nil,
257
259
  payment_pending: nil,
258
260
  body: nil,
259
261
  **kwargs
@@ -263,7 +265,7 @@ module ShopifyAPI
263
265
  operation: :complete,
264
266
  session: @session,
265
267
  ids: {id: @id},
266
- params: {payment_pending: payment_pending}.merge(kwargs).compact,
268
+ params: {payment_gateway_id: payment_gateway_id, payment_pending: payment_pending}.merge(kwargs).compact,
267
269
  body: body,
268
270
  entity: self,
269
271
  )
@@ -245,11 +245,15 @@ module ShopifyAPI
245
245
 
246
246
  sig do
247
247
  params(
248
+ notify_customer: T.untyped,
249
+ tracking_info: T.untyped,
248
250
  body: T.untyped,
249
251
  kwargs: T.untyped
250
252
  ).returns(T.untyped)
251
253
  end
252
254
  def update_tracking(
255
+ notify_customer: nil,
256
+ tracking_info: nil,
253
257
  body: nil,
254
258
  **kwargs
255
259
  )
@@ -258,7 +262,7 @@ module ShopifyAPI
258
262
  operation: :update_tracking,
259
263
  session: @session,
260
264
  ids: {id: @id},
261
- params: {}.merge(kwargs).compact,
265
+ params: {notify_customer: notify_customer, tracking_info: tracking_info}.merge(kwargs).compact,
262
266
  body: body,
263
267
  entity: self,
264
268
  )
@@ -193,13 +193,13 @@ module ShopifyAPI
193
193
 
194
194
  sig do
195
195
  params(
196
- new_location_id: T.untyped,
196
+ fulfillment_order: T.untyped,
197
197
  body: T.untyped,
198
198
  kwargs: T.untyped
199
199
  ).returns(T.untyped)
200
200
  end
201
201
  def move(
202
- new_location_id: nil,
202
+ fulfillment_order: nil,
203
203
  body: nil,
204
204
  **kwargs
205
205
  )
@@ -208,7 +208,7 @@ module ShopifyAPI
208
208
  operation: :move,
209
209
  session: @session,
210
210
  ids: {id: @id},
211
- params: {new_location_id: new_location_id}.merge(kwargs).compact,
211
+ params: {fulfillment_order: fulfillment_order}.merge(kwargs).compact,
212
212
  body: body,
213
213
  entity: self,
214
214
  )