spree_api 5.4.3 → 5.5.0.rc1

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 (146) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +19 -0
  3. data/app/controllers/concerns/spree/api/v3/admin/auth_cookies.rb +62 -0
  4. data/app/controllers/concerns/spree/api/v3/admin/subclassed_resource.rb +149 -0
  5. data/app/controllers/concerns/spree/api/v3/admin_authentication.rb +54 -0
  6. data/app/controllers/concerns/spree/api/v3/bulk_operations.rb +103 -0
  7. data/app/controllers/concerns/spree/api/v3/channel_resolution.rb +60 -0
  8. data/app/controllers/concerns/spree/api/v3/error_handler.rb +4 -0
  9. data/app/controllers/concerns/spree/api/v3/params_normalizer.rb +84 -0
  10. data/app/controllers/concerns/spree/api/v3/scoped_authorization.rb +88 -0
  11. data/app/controllers/concerns/spree/api/v3/store/search_provider_support.rb +35 -1
  12. data/app/controllers/spree/api/v3/admin/admin_users_controller.rb +97 -0
  13. data/app/controllers/spree/api/v3/admin/allowed_origins_controller.rb +25 -0
  14. data/app/controllers/spree/api/v3/admin/api_keys_controller.rb +55 -0
  15. data/app/controllers/spree/api/v3/admin/auth_controller.rb +134 -0
  16. data/app/controllers/spree/api/v3/admin/base_controller.rb +3 -17
  17. data/app/controllers/spree/api/v3/admin/categories_controller.rb +25 -0
  18. data/app/controllers/spree/api/v3/admin/channels_controller.rb +65 -0
  19. data/app/controllers/spree/api/v3/admin/countries_controller.rb +38 -0
  20. data/app/controllers/spree/api/v3/admin/coupon_codes_controller.rb +33 -0
  21. data/app/controllers/spree/api/v3/admin/custom_field_definitions_controller.rb +34 -0
  22. data/app/controllers/spree/api/v3/admin/custom_fields_controller.rb +108 -0
  23. data/app/controllers/spree/api/v3/admin/customer_groups_controller.rb +31 -0
  24. data/app/controllers/spree/api/v3/admin/customers/addresses_controller.rb +88 -0
  25. data/app/controllers/spree/api/v3/admin/customers/credit_cards_controller.rb +31 -0
  26. data/app/controllers/spree/api/v3/admin/customers/store_credits_controller.rb +93 -0
  27. data/app/controllers/spree/api/v3/admin/customers_controller.rb +119 -0
  28. data/app/controllers/spree/api/v3/admin/dashboard_controller.rb +44 -0
  29. data/app/controllers/spree/api/v3/admin/direct_uploads_controller.rb +40 -0
  30. data/app/controllers/spree/api/v3/admin/exports_controller.rb +89 -0
  31. data/app/controllers/spree/api/v3/admin/gift_card_batches_controller.rb +31 -0
  32. data/app/controllers/spree/api/v3/admin/gift_cards_controller.rb +33 -0
  33. data/app/controllers/spree/api/v3/admin/invitation_acceptances_controller.rb +138 -0
  34. data/app/controllers/spree/api/v3/admin/invitations_controller.rb +70 -0
  35. data/app/controllers/spree/api/v3/admin/markets_controller.rb +42 -0
  36. data/app/controllers/spree/api/v3/admin/me_controller.rb +69 -0
  37. data/app/controllers/spree/api/v3/admin/media_controller.rb +119 -0
  38. data/app/controllers/spree/api/v3/admin/option_types_controller.rb +34 -0
  39. data/app/controllers/spree/api/v3/admin/orders/adjustments_controller.rb +27 -0
  40. data/app/controllers/spree/api/v3/admin/orders/base_controller.rb +26 -0
  41. data/app/controllers/spree/api/v3/admin/orders/fulfillments_controller.rb +104 -0
  42. data/app/controllers/spree/api/v3/admin/orders/gift_cards_controller.rb +79 -0
  43. data/app/controllers/spree/api/v3/admin/orders/items_controller.rb +92 -0
  44. data/app/controllers/spree/api/v3/admin/orders/payments_controller.rb +90 -0
  45. data/app/controllers/spree/api/v3/admin/orders/refunds_controller.rb +53 -0
  46. data/app/controllers/spree/api/v3/admin/orders/store_credits_controller.rb +59 -0
  47. data/app/controllers/spree/api/v3/admin/orders_controller.rb +190 -0
  48. data/app/controllers/spree/api/v3/admin/payment_methods_controller.rb +73 -0
  49. data/app/controllers/spree/api/v3/admin/price_lists_controller.rb +156 -0
  50. data/app/controllers/spree/api/v3/admin/prices_controller.rb +129 -0
  51. data/app/controllers/spree/api/v3/admin/products/variants_controller.rb +48 -0
  52. data/app/controllers/spree/api/v3/admin/products_controller.rb +237 -0
  53. data/app/controllers/spree/api/v3/admin/promotion_actions_controller.rb +78 -0
  54. data/app/controllers/spree/api/v3/admin/promotion_rules_controller.rb +56 -0
  55. data/app/controllers/spree/api/v3/admin/promotions_controller.rb +78 -0
  56. data/app/controllers/spree/api/v3/admin/resource_controller.rb +29 -11
  57. data/app/controllers/spree/api/v3/admin/roles_controller.rb +29 -0
  58. data/app/controllers/spree/api/v3/admin/stock_items_controller.rb +35 -0
  59. data/app/controllers/spree/api/v3/admin/stock_locations_controller.rb +36 -0
  60. data/app/controllers/spree/api/v3/admin/stock_reservations_controller.rb +29 -0
  61. data/app/controllers/spree/api/v3/admin/stock_transfers_controller.rb +75 -0
  62. data/app/controllers/spree/api/v3/admin/store_controller.rb +53 -0
  63. data/app/controllers/spree/api/v3/admin/store_credit_categories_controller.rb +21 -0
  64. data/app/controllers/spree/api/v3/admin/tags_controller.rb +51 -0
  65. data/app/controllers/spree/api/v3/admin/tax_categories_controller.rb +21 -0
  66. data/app/controllers/spree/api/v3/admin/variants_controller.rb +33 -0
  67. data/app/controllers/spree/api/v3/admin/webhook_deliveries_controller.rb +49 -0
  68. data/app/controllers/spree/api/v3/admin/webhook_endpoints_controller.rb +75 -0
  69. data/app/controllers/spree/api/v3/resource_controller.rb +90 -8
  70. data/app/controllers/spree/api/v3/store/auth_controller.rb +8 -28
  71. data/app/controllers/spree/api/v3/store/base_controller.rb +6 -0
  72. data/app/controllers/spree/api/v3/store/carts_controller.rb +1 -0
  73. data/app/controllers/spree/api/v3/store/customers_controller.rb +6 -0
  74. data/app/controllers/spree/api/v3/store/newsletter_subscribers_controller.rb +77 -0
  75. data/app/controllers/spree/api/v3/store/products/filters_controller.rb +2 -2
  76. data/app/controllers/spree/api/v3/store/products_controller.rb +3 -3
  77. data/app/controllers/spree/api/v3/store/resource_controller.rb +10 -2
  78. data/app/jobs/spree/webhook_delivery_job.rb +5 -0
  79. data/app/models/spree/api_key_ability.rb +16 -0
  80. data/app/serializers/spree/api/v3/admin/address_serializer.rb +2 -6
  81. data/app/serializers/spree/api/v3/admin/adjustment_serializer.rb +3 -15
  82. data/app/serializers/spree/api/v3/admin/admin_user_serializer.rb +19 -3
  83. data/app/serializers/spree/api/v3/admin/allowed_origin_serializer.rb +2 -6
  84. data/app/serializers/spree/api/v3/admin/api_key_serializer.rb +42 -0
  85. data/app/serializers/spree/api/v3/admin/category_serializer.rb +4 -3
  86. data/app/serializers/spree/api/v3/admin/channel_serializer.rb +15 -0
  87. data/app/serializers/spree/api/v3/admin/country_serializer.rb +1 -1
  88. data/app/serializers/spree/api/v3/admin/coupon_code_serializer.rb +30 -0
  89. data/app/serializers/spree/api/v3/admin/credit_card_serializer.rb +4 -2
  90. data/app/serializers/spree/api/v3/admin/custom_field_definition_serializer.rb +21 -0
  91. data/app/serializers/spree/api/v3/admin/custom_field_serializer.rb +8 -3
  92. data/app/serializers/spree/api/v3/admin/customer_group_serializer.rb +27 -0
  93. data/app/serializers/spree/api/v3/admin/customer_serializer.rb +58 -2
  94. data/app/serializers/spree/api/v3/admin/dashboard_analytics_serializer.rb +143 -0
  95. data/app/serializers/spree/api/v3/admin/export_serializer.rb +40 -0
  96. data/app/serializers/spree/api/v3/admin/fulfillment_serializer.rb +2 -6
  97. data/app/serializers/spree/api/v3/admin/{asset_serializer.rb → gift_card_batch_serializer.rb} +1 -1
  98. data/app/serializers/spree/api/v3/admin/gift_card_serializer.rb +39 -4
  99. data/app/serializers/spree/api/v3/admin/invitation_serializer.rb +64 -0
  100. data/app/serializers/spree/api/v3/admin/line_item_serializer.rb +4 -16
  101. data/app/serializers/spree/api/v3/admin/media_serializer.rb +24 -2
  102. data/app/serializers/spree/api/v3/admin/option_type_serializer.rb +4 -1
  103. data/app/serializers/spree/api/v3/admin/option_value_serializer.rb +4 -1
  104. data/app/serializers/spree/api/v3/admin/order_serializer.rb +21 -6
  105. data/app/serializers/spree/api/v3/admin/payment_method_serializer.rb +11 -2
  106. data/app/serializers/spree/api/v3/admin/payment_serializer.rb +2 -6
  107. data/app/serializers/spree/api/v3/admin/payment_source_serializer.rb +4 -1
  108. data/app/serializers/spree/api/v3/admin/price_list_serializer.rb +51 -0
  109. data/app/serializers/spree/api/v3/admin/price_rule_serializer.rb +55 -0
  110. data/app/serializers/spree/api/v3/admin/price_serializer.rb +4 -0
  111. data/app/serializers/spree/api/v3/admin/product_publication_serializer.rb +11 -0
  112. data/app/serializers/spree/api/v3/admin/product_serializer.rb +34 -10
  113. data/app/serializers/spree/api/v3/admin/promotion_action_serializer.rb +71 -0
  114. data/app/serializers/spree/api/v3/admin/promotion_rule_serializer.rb +85 -0
  115. data/app/serializers/spree/api/v3/admin/promotion_serializer.rb +41 -0
  116. data/app/serializers/spree/api/v3/admin/refund_serializer.rb +4 -2
  117. data/app/serializers/spree/api/v3/admin/role_serializer.rb +17 -0
  118. data/app/serializers/spree/api/v3/admin/stock_item_serializer.rb +16 -1
  119. data/app/serializers/spree/api/v3/admin/stock_location_serializer.rb +11 -2
  120. data/app/serializers/spree/api/v3/admin/stock_reservation_serializer.rb +46 -0
  121. data/app/serializers/spree/api/v3/admin/stock_transfer_serializer.rb +37 -0
  122. data/app/serializers/spree/api/v3/admin/store_credit_category_serializer.rb +19 -0
  123. data/app/serializers/spree/api/v3/admin/store_credit_serializer.rb +11 -5
  124. data/app/serializers/spree/api/v3/admin/store_serializer.rb +55 -0
  125. data/app/serializers/spree/api/v3/admin/tax_category_serializer.rb +4 -2
  126. data/app/serializers/spree/api/v3/admin/variant_serializer.rb +37 -6
  127. data/app/serializers/spree/api/v3/admin/webhook_delivery_serializer.rb +45 -0
  128. data/app/serializers/spree/api/v3/admin/webhook_endpoint_serializer.rb +69 -0
  129. data/app/serializers/spree/api/v3/channel_serializer.rb +14 -0
  130. data/app/serializers/spree/api/v3/custom_field_serializer.rb +9 -10
  131. data/app/serializers/spree/api/v3/customer_serializer.rb +5 -0
  132. data/app/serializers/spree/api/v3/market_serializer.rb +2 -1
  133. data/app/serializers/spree/api/v3/media_serializer.rb +8 -6
  134. data/app/serializers/spree/api/v3/order_serializer.rb +6 -1
  135. data/app/serializers/spree/api/v3/payment_method_serializer.rb +11 -2
  136. data/app/serializers/spree/api/v3/product_publication_serializer.rb +22 -0
  137. data/app/serializers/spree/api/v3/product_serializer.rb +6 -1
  138. data/app/serializers/spree/api/v3/stock_reservation_serializer.rb +10 -0
  139. data/config/locales/en.yml +2 -0
  140. data/config/routes.rb +235 -1
  141. data/lib/spree/api/configuration.rb +2 -2
  142. data/lib/spree/api/dependencies.rb +25 -1
  143. data/lib/spree/api/openapi/path_sorter.rb +126 -0
  144. data/lib/spree/api/openapi/schema_helper.rb +185 -6
  145. metadata +96 -8
  146. data/app/serializers/spree/api/v3/admin/shipping_category_serializer.rb +0 -14
data/config/routes.rb CHANGED
@@ -6,7 +6,6 @@ Spree::Core::Engine.add_routes do
6
6
  post 'auth/login', to: 'auth#create'
7
7
  post 'auth/refresh', to: 'auth#refresh'
8
8
  post 'auth/logout', to: 'auth#logout'
9
- post 'auth/oauth/callback', to: 'auth#oauth_callback'
10
9
 
11
10
  # Markets
12
11
  resources :markets, only: [:index, :show] do
@@ -60,6 +59,13 @@ Spree::Core::Engine.add_routes do
60
59
  # Customers
61
60
  resources :customers, only: [:create]
62
61
 
62
+ # Newsletter Subscriptions (guest-accessible: subscribe + verify by token)
63
+ resources :newsletter_subscribers, only: [:create] do
64
+ collection do
65
+ post :verify
66
+ end
67
+ end
68
+
63
69
  # Current customer profile and nested resources (/customers/me/...)
64
70
  namespace :customer, path: 'customers/me' do
65
71
  get '/', action: :show, controller: '/spree/api/v3/store/customers'
@@ -90,6 +96,234 @@ Spree::Core::Engine.add_routes do
90
96
  resources :feeds, only: [:show], controller: 'data_feeds', param: :slug
91
97
  end
92
98
 
99
+ namespace :admin do
100
+ # Mounts a nested `custom_fields` resource on parents that include
101
+ # Spree::Metafields. See docs/plans/5.4-6.0-custom-fields-rename.md.
102
+ concern :custom_fieldable do
103
+ resources :custom_fields
104
+ end
105
+
106
+ # Definitions are per resource type, not per instance.
107
+ resources :custom_field_definitions
108
+
109
+ # Authentication
110
+ post 'auth/login', to: 'auth#create'
111
+ post 'auth/refresh', to: 'auth#refresh'
112
+ post 'auth/logout', to: 'auth#logout'
113
+
114
+ # Public invitation acceptance — unauthenticated; the prefixed ID +
115
+ # token in the URL act as the credential. Mounted under `auth/` so
116
+ # the issued refresh-token cookie's path matches `/auth/refresh`.
117
+ get 'auth/invitations/:id/lookup', to: 'invitation_acceptances#lookup'
118
+ post 'auth/invitations/:id/accept', to: 'invitation_acceptances#accept'
119
+
120
+ # Dashboard
121
+ namespace :dashboard do
122
+ get :analytics
123
+ end
124
+
125
+ # Current admin user + permissions (for UI permission checks)
126
+ get 'me', to: 'me#show'
127
+
128
+ # Store Settings
129
+ resource :store, only: [:show, :update], controller: 'store'
130
+
131
+ # Staff & access (invitations, admin users, roles, API keys)
132
+ resources :admin_users, only: [:index, :show, :update, :destroy]
133
+ resources :invitations, only: [:index, :show, :create, :destroy] do
134
+ member do
135
+ patch :resend
136
+ end
137
+ end
138
+ resources :api_keys, only: [:index, :show, :create, :destroy] do
139
+ member do
140
+ patch :revoke
141
+ end
142
+ end
143
+ resources :allowed_origins
144
+ resources :webhook_endpoints do
145
+ member do
146
+ post :send_test
147
+ patch :enable
148
+ patch :disable
149
+ end
150
+ resources :deliveries, controller: 'webhook_deliveries', only: [:index, :show] do
151
+ member do
152
+ post :redeliver
153
+ end
154
+ end
155
+ end
156
+ resources :roles, only: [:index, :show]
157
+
158
+ # Direct Uploads (Active Storage)
159
+ resources :direct_uploads, only: [:create]
160
+
161
+ # CSV Exports — see docs/plans/5.5-admin-spa-csv-export.md
162
+ resources :exports, only: [:index, :show, :create, :destroy] do
163
+ member do
164
+ get :download
165
+ end
166
+ end
167
+
168
+ # Products
169
+ resources :products, concerns: :custom_fieldable do
170
+ member do
171
+ post :clone
172
+ end
173
+ collection do
174
+ post :bulk_status_update
175
+ post :bulk_add_to_categories
176
+ post :bulk_remove_from_categories
177
+ post :bulk_add_to_channels
178
+ post :bulk_remove_from_channels
179
+ post :bulk_add_tags
180
+ post :bulk_remove_tags
181
+ delete :bulk_destroy
182
+ end
183
+ resources :variants, controller: 'products/variants' do
184
+ resources :media, controller: 'media', only: [:index, :create, :update, :destroy]
185
+ end
186
+ resources :media, controller: 'media', only: [:index, :create, :update, :destroy]
187
+ end
188
+
189
+ # Categories
190
+ resources :categories, only: [:index, :show], concerns: :custom_fieldable
191
+
192
+ # Option Types (with nested option_values in payload)
193
+ resources :option_types, concerns: :custom_fieldable
194
+
195
+ # Tax Categories
196
+ resources :tax_categories
197
+
198
+ # Markets
199
+ resources :markets
200
+
201
+ # Store Credit Categories (read-only — for store credit dropdowns)
202
+ resources :store_credit_categories, only: [:index, :show]
203
+
204
+ # Inventory
205
+ resources :stock_locations
206
+ resources :stock_reservations, only: [:index, :show]
207
+ resources :stock_items, only: [:index, :show, :update, :destroy]
208
+ resources :stock_transfers, only: [:index, :show, :create, :destroy]
209
+
210
+ # Payment Methods
211
+ resources :payment_methods do
212
+ collection do
213
+ get :types
214
+ end
215
+ end
216
+
217
+ # Promotions, with nested actions/rules/coupon codes.
218
+ resources :promotions do
219
+ resources :promotion_actions, only: [:index, :show, :create, :update, :destroy]
220
+ resources :promotion_rules, only: [:index, :show, :create, :update, :destroy]
221
+ resources :coupon_codes, only: [:index, :show]
222
+ end
223
+
224
+ # Subclass discovery for the promotion editor: `/promotion_actions/types`
225
+ # and `/promotion_rules/types` enumerate registered subclasses with
226
+ # their preference schemas. Top-level so the SPA can build the
227
+ # "Add action / Add rule" pickers without a parent promotion.
228
+ get 'promotion_actions/types', to: 'promotion_actions#types'
229
+ get 'promotion_rules/types', to: 'promotion_rules#types'
230
+
231
+ # Calculator catalog for actions that include CalculatedAdjustments
232
+ # (CreateAdjustment, CreateItemAdjustments). Returns the registered
233
+ # calculator subclasses for the given action type along with each
234
+ # calculator's preference schema, so the SPA can render the picker
235
+ # + nested calculator preferences.
236
+ get 'promotion_actions/calculators', to: 'promotion_actions#calculators'
237
+
238
+ # Tags (autocomplete for product/order/user tag inputs)
239
+ resources :tags, only: [:index]
240
+
241
+ # Customers
242
+ resources :customers, concerns: :custom_fieldable do
243
+ resources :addresses, controller: 'customers/addresses'
244
+ resources :credit_cards, controller: 'customers/credit_cards', only: [:index, :show, :destroy]
245
+ resources :store_credits, controller: 'customers/store_credits'
246
+
247
+ collection do
248
+ post :bulk_add_to_groups
249
+ post :bulk_remove_from_groups
250
+ post :bulk_add_tags
251
+ post :bulk_remove_tags
252
+ end
253
+ end
254
+
255
+ # Customer groups (segmentation; used by promotion rules + bulk customer ops)
256
+ resources :customer_groups
257
+
258
+ # Price lists
259
+ resources :price_lists do
260
+ collection do
261
+ get :price_rule_types
262
+ end
263
+ member do
264
+ patch :activate
265
+ patch :deactivate
266
+ end
267
+ end
268
+
269
+ # Prices (generic — covers base prices AND price-list overrides).
270
+ resources :prices do
271
+ collection do
272
+ post :bulk_upsert
273
+ delete :bulk_destroy
274
+ end
275
+ end
276
+
277
+ # Gift cards
278
+ resources :gift_cards
279
+ resources :gift_card_batches, only: [:index, :show, :create]
280
+
281
+ # Channels (per-store distribution surfaces)
282
+ resources :channels do
283
+ member do
284
+ post :add_products
285
+ post :remove_products
286
+ end
287
+ end
288
+
289
+ # Variants (top-level, for search/autocomplete across all products)
290
+ resources :variants, only: [:index, :show], concerns: :custom_fieldable
291
+
292
+ # Countries (with ?expand=states for state/province dropdown)
293
+ resources :countries, only: [:index, :show]
294
+
295
+ # Orders
296
+ resources :orders, concerns: :custom_fieldable do
297
+ member do
298
+ patch :complete
299
+ patch :cancel
300
+ patch :approve
301
+ patch :resume
302
+ post :resend_confirmation
303
+ end
304
+
305
+ resources :items, only: [:index, :show, :create, :update, :destroy], controller: 'orders/items'
306
+ resources :fulfillments, controller: 'orders/fulfillments', only: [:index, :show, :update] do
307
+ member do
308
+ patch :fulfill
309
+ patch :cancel
310
+ patch :resume
311
+ patch :split
312
+ end
313
+ end
314
+ resources :payments, controller: 'orders/payments', only: [:index, :show, :create] do
315
+ member do
316
+ patch :capture
317
+ patch :void
318
+ end
319
+ end
320
+ resources :refunds, controller: 'orders/refunds', only: [:index, :create]
321
+ resources :adjustments, controller: 'orders/adjustments', only: [:index, :show]
322
+ resources :gift_cards, controller: 'orders/gift_cards', only: [:create, :destroy]
323
+ resource :store_credits, controller: 'orders/store_credits', only: [:create, :destroy]
324
+ end
325
+ end
326
+
93
327
  # Webhooks (outside of store namespace — no API key authentication)
94
328
  namespace :webhooks do
95
329
  post 'payments/:payment_method_id', to: 'payments#create', as: :payment_webhook
@@ -9,7 +9,8 @@ module Spree
9
9
  preference :api_v2_content_type, :string, default: 'application/vnd.api+json'
10
10
  preference :api_v2_per_page_limit, :integer, default: 500
11
11
 
12
- preference :jwt_expiration, :integer, default: 3600 # 1 hour in seconds
12
+ preference :jwt_expiration, :integer, default: 3600 # 1 hour in seconds (customer/store JWT default)
13
+ preference :admin_jwt_expiration, :integer, default: 300 # 5 minutes — admin tokens have higher blast radius
13
14
  preference :jwt_secret_key, :string, default: nil
14
15
  preference :refresh_token_expiry, :integer, default: 2_592_000 # 30 days in seconds
15
16
 
@@ -19,7 +20,6 @@ module Spree
19
20
  preference :rate_limit_login, :integer, default: 5 # per IP
20
21
  preference :rate_limit_register, :integer, default: 3 # per IP
21
22
  preference :rate_limit_refresh, :integer, default: 10 # per IP
22
- preference :rate_limit_oauth, :integer, default: 5 # per IP
23
23
  preference :rate_limit_password_reset, :integer, default: 3 # per IP
24
24
 
25
25
  # Request body size limit in bytes
@@ -113,6 +113,8 @@ module Spree
113
113
  address_serializer: 'Spree::Api::V3::AddressSerializer',
114
114
  customer_serializer: 'Spree::Api::V3::CustomerSerializer',
115
115
  country_serializer: 'Spree::Api::V3::CountrySerializer',
116
+ channel_serializer: 'Spree::Api::V3::ChannelSerializer',
117
+ product_publication_serializer: 'Spree::Api::V3::ProductPublicationSerializer',
116
118
  market_serializer: 'Spree::Api::V3::MarketSerializer',
117
119
  state_serializer: 'Spree::Api::V3::StateSerializer',
118
120
  wishlist_serializer: 'Spree::Api::V3::WishlistSerializer',
@@ -153,6 +155,7 @@ module Spree
153
155
  return_item_serializer: 'Spree::Api::V3::ReturnItemSerializer',
154
156
  stock_item_serializer: 'Spree::Api::V3::StockItemSerializer',
155
157
  stock_movement_serializer: 'Spree::Api::V3::StockMovementSerializer',
158
+ stock_reservation_serializer: 'Spree::Api::V3::StockReservationSerializer',
156
159
  stock_transfer_serializer: 'Spree::Api::V3::StockTransferSerializer',
157
160
 
158
161
  # v3 admin serializers (API v3 Admin)
@@ -166,16 +169,18 @@ module Spree
166
169
  admin_price_serializer: 'Spree::Api::V3::Admin::PriceSerializer',
167
170
  admin_price_history_serializer: 'Spree::Api::V3::Admin::PriceHistorySerializer',
168
171
  admin_custom_field_serializer: 'Spree::Api::V3::Admin::CustomFieldSerializer',
172
+ admin_custom_field_definition_serializer: 'Spree::Api::V3::Admin::CustomFieldDefinitionSerializer',
169
173
  admin_category_serializer: 'Spree::Api::V3::Admin::CategorySerializer',
170
174
  admin_line_item_serializer: 'Spree::Api::V3::Admin::LineItemSerializer',
171
175
  admin_option_type_serializer: 'Spree::Api::V3::Admin::OptionTypeSerializer',
172
176
  admin_option_value_serializer: 'Spree::Api::V3::Admin::OptionValueSerializer',
173
177
  admin_media_serializer: 'Spree::Api::V3::Admin::MediaSerializer',
174
- admin_asset_serializer: 'Spree::Api::V3::Admin::AssetSerializer',
175
178
  admin_stock_item_serializer: 'Spree::Api::V3::Admin::StockItemSerializer',
179
+ admin_stock_transfer_serializer: 'Spree::Api::V3::Admin::StockTransferSerializer',
176
180
  admin_shipment_serializer: 'Spree::Api::V3::Admin::FulfillmentSerializer',
177
181
  admin_fulfillment_serializer: 'Spree::Api::V3::Admin::FulfillmentSerializer',
178
182
  admin_gift_card_serializer: 'Spree::Api::V3::Admin::GiftCardSerializer',
183
+ admin_gift_card_batch_serializer: 'Spree::Api::V3::Admin::GiftCardBatchSerializer',
179
184
  admin_payment_serializer: 'Spree::Api::V3::Admin::PaymentSerializer',
180
185
  admin_refund_serializer: 'Spree::Api::V3::Admin::RefundSerializer',
181
186
  admin_adjustment_serializer: 'Spree::Api::V3::Admin::AdjustmentSerializer',
@@ -185,17 +190,36 @@ module Spree
185
190
  admin_reimbursement_serializer: 'Spree::Api::V3::Admin::ReimbursementSerializer',
186
191
  admin_admin_user_serializer: 'Spree::Api::V3::Admin::AdminUserSerializer',
187
192
  admin_address_serializer: 'Spree::Api::V3::Admin::AddressSerializer',
193
+ admin_channel_serializer: 'Spree::Api::V3::Admin::ChannelSerializer',
194
+ admin_product_publication_serializer: 'Spree::Api::V3::Admin::ProductPublicationSerializer',
188
195
  admin_market_serializer: 'Spree::Api::V3::Admin::MarketSerializer',
189
196
  admin_shipping_method_serializer: 'Spree::Api::V3::Admin::DeliveryMethodSerializer',
190
197
  admin_delivery_method_serializer: 'Spree::Api::V3::Admin::DeliveryMethodSerializer',
191
198
  admin_stock_location_serializer: 'Spree::Api::V3::Admin::StockLocationSerializer',
199
+ admin_stock_reservation_serializer: 'Spree::Api::V3::Admin::StockReservationSerializer',
192
200
  admin_shipping_rate_serializer: 'Spree::Api::V3::Admin::DeliveryRateSerializer',
193
201
  admin_delivery_rate_serializer: 'Spree::Api::V3::Admin::DeliveryRateSerializer',
194
202
  admin_payment_method_serializer: 'Spree::Api::V3::Admin::PaymentMethodSerializer',
195
203
  admin_credit_card_serializer: 'Spree::Api::V3::Admin::CreditCardSerializer',
196
204
  admin_store_credit_serializer: 'Spree::Api::V3::Admin::StoreCreditSerializer',
205
+ admin_store_credit_category_serializer: 'Spree::Api::V3::Admin::StoreCreditCategorySerializer',
206
+ admin_customer_group_serializer: 'Spree::Api::V3::Admin::CustomerGroupSerializer',
197
207
  admin_payment_source_serializer: 'Spree::Api::V3::Admin::PaymentSourceSerializer',
198
208
  admin_digital_link_serializer: 'Spree::Api::V3::Admin::DigitalLinkSerializer',
209
+ admin_store_serializer: 'Spree::Api::V3::Admin::StoreSerializer',
210
+ admin_api_key_serializer: 'Spree::Api::V3::Admin::ApiKeySerializer',
211
+ admin_allowed_origin_serializer: 'Spree::Api::V3::Admin::AllowedOriginSerializer',
212
+ admin_webhook_endpoint_serializer: 'Spree::Api::V3::Admin::WebhookEndpointSerializer',
213
+ admin_webhook_delivery_serializer: 'Spree::Api::V3::Admin::WebhookDeliverySerializer',
214
+ admin_invitation_serializer: 'Spree::Api::V3::Admin::InvitationSerializer',
215
+ admin_role_serializer: 'Spree::Api::V3::Admin::RoleSerializer',
216
+ admin_export_serializer: 'Spree::Api::V3::Admin::ExportSerializer',
217
+ admin_promotion_serializer: 'Spree::Api::V3::Admin::PromotionSerializer',
218
+ admin_promotion_action_serializer: 'Spree::Api::V3::Admin::PromotionActionSerializer',
219
+ admin_promotion_rule_serializer: 'Spree::Api::V3::Admin::PromotionRuleSerializer',
220
+ admin_coupon_code_serializer: 'Spree::Api::V3::Admin::CouponCodeSerializer',
221
+ admin_price_list_serializer: 'Spree::Api::V3::Admin::PriceListSerializer',
222
+ admin_price_rule_serializer: 'Spree::Api::V3::Admin::PriceRuleSerializer',
199
223
 
200
224
  # platform serializers
201
225
  platform_metafield_serializer: 'Spree::Api::V2::Platform::MetafieldSerializer',
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ module Api
5
+ module OpenAPI
6
+ # Reorders the `paths:` block of a generated OpenAPI YAML so paths are grouped
7
+ # by tag, in the same order as the top-level `tags:` array.
8
+ #
9
+ # rswag emits paths in the order specs are loaded (alphabetical by filename),
10
+ # which doesn't match the curated `tags:` array order in swagger_helper.rb.
11
+ # Mintlify groups sidebar sections by the *first appearance* of each tag in
12
+ # `paths:` — so after this sort runs, the sidebar matches the `tags:` array.
13
+ #
14
+ # The reorder is line-based to preserve the exact text formatting that
15
+ # rswag/Psych produced (indentation, multi-line string wrapping, etc.).
16
+ module PathSorter
17
+ module_function
18
+
19
+ # Sort the `paths:` block in `path` so each path's first-operation primary
20
+ # tag follows the order defined in the document's top-level `tags:` array.
21
+ # Returns true if the file was rewritten, false if already sorted.
22
+ def sort_file!(path)
23
+ original = File.read(path)
24
+ sorted = sort_text(original)
25
+ return false if sorted == original
26
+
27
+ File.write(path, sorted)
28
+ true
29
+ end
30
+
31
+ # Pure-string variant: sort a YAML document's `paths:` block by tag order.
32
+ def sort_text(yaml)
33
+ lines = yaml.lines
34
+ tag_rank = extract_tag_rank(lines)
35
+ return yaml if tag_rank.empty?
36
+
37
+ paths_start = lines.index { |l| l.start_with?('paths:') }
38
+ return yaml unless paths_start
39
+
40
+ paths_end_exclusive = (paths_start + 1...lines.size).find do |i|
41
+ line = lines[i]
42
+ line.match?(/\A[A-Za-z]/) || line.start_with?('x-')
43
+ end || lines.size
44
+
45
+ blocks = collect_path_blocks(lines, paths_start + 1, paths_end_exclusive)
46
+ return yaml if blocks.empty?
47
+
48
+ unknown_rank = tag_rank.size
49
+ sorted_blocks = blocks.each_with_index.sort_by do |block, original_index|
50
+ [tag_rank.fetch(block[:tag], unknown_rank), original_index]
51
+ end.map(&:first)
52
+
53
+ prefix = lines[0..paths_start].join
54
+ suffix = lines[paths_end_exclusive..].to_a.join
55
+ prefix + sorted_blocks.map { |b| b[:text] }.join + suffix
56
+ end
57
+
58
+ # Parse the top-level `tags:` block and return { tag_name => index } in
59
+ # declared order. Returns {} if not found.
60
+ def extract_tag_rank(lines)
61
+ start = lines.index { |l| l.start_with?('tags:') }
62
+ return {} unless start
63
+
64
+ rank = {}
65
+ i = start + 1
66
+ while i < lines.size
67
+ line = lines[i]
68
+ if line.start_with?('- name: ')
69
+ rank[line.sub('- name: ', '').strip] = rank.size
70
+ elsif line.match?(/\A[A-Za-z]/) || line.start_with?('x-')
71
+ break
72
+ end
73
+ i += 1
74
+ end
75
+ rank
76
+ end
77
+
78
+ # Collect each path block as { tag:, text: } from lines[range].
79
+ # A path block starts on a line beginning with two spaces + a quote.
80
+ def collect_path_blocks(lines, start_idx, end_idx_exclusive)
81
+ blocks = []
82
+ current_start = nil
83
+
84
+ (start_idx...end_idx_exclusive).each do |i|
85
+ if path_header?(lines[i])
86
+ blocks << build_block(lines, current_start, i) if current_start
87
+ current_start = i
88
+ end
89
+ end
90
+ blocks << build_block(lines, current_start, end_idx_exclusive) if current_start
91
+
92
+ blocks
93
+ end
94
+
95
+ def path_header?(line)
96
+ line.start_with?(' "/') || line.start_with?(' /')
97
+ end
98
+
99
+ def build_block(lines, from, to_exclusive)
100
+ slice = lines[from...to_exclusive]
101
+ {
102
+ tag: extract_primary_tag(slice),
103
+ text: slice.join
104
+ }
105
+ end
106
+
107
+ # Within a path block, find the first `tags:` line and return the first
108
+ # tag value following it (the path block's "primary" tag).
109
+ def extract_primary_tag(slice)
110
+ slice.each_with_index do |line, idx|
111
+ next unless line.match?(/\A {6}tags:\s*$/)
112
+
113
+ slice[(idx + 1)..].each do |next_line|
114
+ if next_line.start_with?(' - ')
115
+ value = next_line[8..].strip
116
+ return value unless value.empty?
117
+ end
118
+ break if next_line.match?(/\A {0,4}\S/)
119
+ end
120
+ end
121
+ nil
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end