@thorprovider/adapters 4.2.1 → 5.0.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 (60) hide show
  1. package/PROVIDER_IMPLEMENTATION_ANALYSIS.md +659 -0
  2. package/dist/index.d.mts +225 -387
  3. package/dist/index.d.ts +225 -387
  4. package/dist/index.js +613 -3062
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +609 -3052
  7. package/dist/index.mjs.map +1 -1
  8. package/docs/RETRY_SOLUTION_SUMMARY.md +26 -11
  9. package/docs/authentication.md +115 -62
  10. package/docs/capabilities-system.md +4 -2
  11. package/docs/category-customization.md +37 -29
  12. package/docs/fetch-reliability-solution.md +127 -278
  13. package/docs/getting-started.md +43 -29
  14. package/docs/profile-management.md +68 -38
  15. package/docs/services-overview.md +4 -2
  16. package/package.json +1 -1
  17. package/quick-reference.md +33 -0
  18. package/src/backend/factory.ts +1 -11
  19. package/src/factory/index.ts +74 -52
  20. package/src/index.ts +5 -15
  21. package/src/providers/index.ts +1 -16
  22. package/src/providers/medusa/admin.test.ts +404 -0
  23. package/src/providers/medusa/admin.ts +442 -0
  24. package/src/providers/medusa/auth.test.ts +137 -0
  25. package/src/providers/medusa/auth.ts +96 -1
  26. package/src/providers/medusa/index.ts +21 -1
  27. package/src/resilience/README.md +70 -48
  28. package/src/types/capabilities.types.ts +0 -250
  29. package/src/core/errors.js +0 -161
  30. package/src/core/fetch-utils.js +0 -240
  31. package/src/core/logger.js +0 -63
  32. package/src/metadata/channel-scope-validation.js +0 -136
  33. package/src/metadata/channel-scope.js +0 -174
  34. package/src/metadata/index.js +0 -31
  35. package/src/providers/bigcommerce/bigcommerce.ts +0 -6
  36. package/src/providers/bigcommerce/index.ts +0 -315
  37. package/src/providers/bigcommerce/transforms.ts +0 -227
  38. package/src/providers/magento/index.ts +0 -387
  39. package/src/providers/magento/magento.ts +0 -5
  40. package/src/providers/magento/queries.ts +0 -267
  41. package/src/providers/magento/transforms.ts +0 -249
  42. package/src/providers/medusa/auth.js +0 -601
  43. package/src/providers/medusa/index.js +0 -2485
  44. package/src/providers/medusa/payment.js +0 -265
  45. package/src/providers/medusa/transforms.js +0 -505
  46. package/src/providers/shopify/auth.ts +0 -402
  47. package/src/providers/shopify/index.ts +0 -444
  48. package/src/providers/shopify/mutations.ts +0 -247
  49. package/src/providers/shopify/queries.ts +0 -324
  50. package/src/providers/shopify/shopify.ts +0 -7
  51. package/src/providers/shopify/transforms.ts +0 -275
  52. package/src/providers/spree/index.ts +0 -344
  53. package/src/providers/spree/spree.ts +0 -5
  54. package/src/providers/spree/transforms.ts +0 -254
  55. package/src/providers/woocommerce/index.ts +0 -310
  56. package/src/providers/woocommerce/transforms.ts +0 -254
  57. package/src/providers/woocommerce/woocommerce.ts +0 -5
  58. package/src/types/capabilities.types.js +0 -141
  59. package/src/types/provider.js +0 -9
  60. package/src/utils/payment-utils.js +0 -152
@@ -1,227 +0,0 @@
1
- /**
2
- * @thorprovider/adapters — BigCommerce Provider
3
- * Transform functions: BigCommerce REST API → @thorprovider/types
4
- */
5
-
6
- import type {
7
- Product,
8
- ProductVariant,
9
- ProductOption,
10
- Cart,
11
- CartItem,
12
- Collection,
13
- Money,
14
- Image,
15
- Order,
16
- OrderItem,
17
- OrderStatus,
18
- PaymentStatus,
19
- FulfillmentStatus,
20
- Customer,
21
- Address,
22
- } from '@thorprovider/types';
23
-
24
- // ============================================
25
- // Money & Image Transforms
26
- // ============================================
27
-
28
- function transformMoney(amount: number | string | null | undefined, currencyCode: string = 'USD'): Money {
29
- const numAmount = typeof amount === 'string' ? parseFloat(amount) : (amount ?? 0);
30
- return {
31
- amount: numAmount.toFixed(2),
32
- currencyCode: currencyCode.toUpperCase(),
33
- };
34
- }
35
-
36
- function transformImage(url: string, alt: string = ''): Image {
37
- return { url, altText: alt, width: 800, height: 800 };
38
- }
39
-
40
- // ============================================
41
- // Product Transforms
42
- // ============================================
43
-
44
- export function transformProduct(raw: any, currencyCode: string = 'USD'): Product {
45
- const images: Image[] = (raw.images ?? []).map((img: any) =>
46
- transformImage(img.url_standard ?? img.url_thumbnail ?? '', img.description ?? ''),
47
- );
48
-
49
- const variants: ProductVariant[] = (raw.variants ?? []).map((v: any) => ({
50
- id: String(v.id),
51
- title: v.option_display_name ?? `Variant ${v.id}`,
52
- availableForSale: (v.purchasing_disabled !== true),
53
- price: transformMoney(v.price ?? raw.price, currencyCode),
54
- compareAtPrice: v.sale_price ? transformMoney(v.sale_price, currencyCode) : undefined,
55
- selectedOptions: (v.option_values ?? []).map((ov: any) => ({
56
- name: ov.option_display_name ?? '',
57
- value: ov.label ?? '',
58
- })),
59
- }));
60
-
61
- const options: ProductOption[] = (raw.options ?? []).map((opt: any) => ({
62
- id: String(opt.id),
63
- name: opt.display_name ?? '',
64
- values: (opt.option_values ?? []).map((val: any) => val.label ?? ''),
65
- }));
66
-
67
- const price = raw.price ?? raw.calculated_price?.as_entered ?? 0;
68
-
69
- return {
70
- id: String(raw.id),
71
- handle: raw.custom_url?.url?.replace(/^\//, '').replace(/\/$/, '') ?? String(raw.id),
72
- title: raw.name ?? '',
73
- description: raw.plain_text_description ?? raw.description ?? '',
74
- descriptionHtml: raw.description ?? '',
75
- availableForSale: raw.availability === 'available' || raw.is_visible !== false,
76
- featuredImage: images[0] ?? { url: '', altText: '', width: 800, height: 800 },
77
- images,
78
- options,
79
- variants,
80
- priceRange: {
81
- minVariantPrice: transformMoney(price, currencyCode),
82
- maxVariantPrice: transformMoney(price, currencyCode),
83
- },
84
- seo: {
85
- title: raw.page_title ?? raw.name ?? '',
86
- description: raw.meta_description ?? '',
87
- },
88
- tags: [],
89
- createdAt: raw.date_created ?? new Date().toISOString(),
90
- updatedAt: raw.date_modified ?? new Date().toISOString(),
91
- };
92
- }
93
-
94
- // ============================================
95
- // Collection Transforms (BigCommerce "Categories" or "Brands")
96
- // ============================================
97
-
98
- export function transformCollection(raw: any): Collection {
99
- return {
100
- id: String(raw.id ?? ''),
101
- handle: raw.custom_url?.url?.replace(/^\//, '').replace(/\/$/, '') ?? String(raw.id),
102
- title: raw.name ?? '',
103
- description: raw.description ?? '',
104
- seo: {
105
- title: raw.page_title ?? raw.name ?? '',
106
- description: raw.meta_description ?? '',
107
- },
108
- updatedAt: raw.date_modified ?? new Date().toISOString(),
109
- path: `/collections/${raw.custom_url?.url?.replace(/^\//, '').replace(/\/$/, '') ?? raw.id}`,
110
- };
111
- }
112
-
113
- // ============================================
114
- // Cart Transforms
115
- // ============================================
116
-
117
- export function transformCart(raw: any, currencyCode: string = 'USD'): Cart {
118
- const lineItems = Object.values(raw.line_items ?? {}).flat() as any[];
119
-
120
- const lines: CartItem[] = lineItems.map((item: any) => ({
121
- id: item.id,
122
- quantity: item.quantity ?? 1,
123
- cost: {
124
- totalAmount: transformMoney(item.extended_sale_price ?? item.sale_price ?? 0, currencyCode),
125
- },
126
- merchandise: {
127
- id: String(item.variant_id ?? item.product_id),
128
- title: item.name ?? '',
129
- selectedOptions: (item.options ?? []).map((opt: any) => ({
130
- name: opt.name ?? '',
131
- value: opt.value ?? '',
132
- })),
133
- product: {
134
- id: String(item.product_id),
135
- handle: String(item.product_id),
136
- title: item.name ?? '',
137
- featuredImage: item.image_url
138
- ? transformImage(item.image_url)
139
- : { url: '', altText: '', width: 800, height: 800 },
140
- },
141
- },
142
- }));
143
-
144
- return {
145
- id: raw.id,
146
- checkoutUrl: raw.redirect_urls?.checkout_url ?? '',
147
- totalQuantity: lines.reduce((sum, l) => sum + l.quantity, 0),
148
- cost: {
149
- subtotalAmount: transformMoney(raw.base_amount ?? 0, currencyCode),
150
- totalAmount: transformMoney(raw.cart_amount ?? 0, currencyCode),
151
- },
152
- lines,
153
- };
154
- }
155
-
156
- // ============================================
157
- // Customer Transforms
158
- // ============================================
159
-
160
- export function transformCustomer(raw: any): Customer {
161
- return {
162
- id: String(raw.id),
163
- email: raw.email ?? '',
164
- firstName: raw.first_name ?? '',
165
- lastName: raw.last_name ?? '',
166
- phone: raw.phone ?? '',
167
- hasAccount: true,
168
- };
169
- }
170
-
171
- export function transformAddress(raw: any): Address {
172
- return {
173
- id: String(raw.id ?? ''),
174
- firstName: raw.first_name ?? '',
175
- lastName: raw.last_name ?? '',
176
- address1: raw.address1 ?? '',
177
- address2: raw.address2 ?? '',
178
- city: raw.city ?? '',
179
- province: raw.state_or_province ?? '',
180
- countryCode: raw.country_code ?? '',
181
- postalCode: raw.postal_code ?? '',
182
- phone: raw.phone ?? '',
183
- company: raw.company ?? '',
184
- };
185
- }
186
-
187
- // ============================================
188
- // Order Transforms
189
- // ============================================
190
-
191
- export function transformOrder(raw: any, currencyCode: string = 'USD'): Order {
192
- const items: OrderItem[] = (raw.products ?? []).map((p: any) => ({
193
- id: String(p.id),
194
- title: p.name ?? '',
195
- variantTitle: p.sku ?? '',
196
- quantity: p.quantity ?? 1,
197
- price: transformMoney(p.base_price ?? 0, currencyCode),
198
- total: transformMoney(p.base_total ?? 0, currencyCode),
199
- productId: String(p.product_id),
200
- }));
201
-
202
- const statusMap: Record<string, OrderStatus> = {
203
- 'Incomplete': 'pending',
204
- 'Pending': 'pending',
205
- 'Shipped': 'completed',
206
- 'Partially Shipped': 'processing',
207
- 'Refunded': 'refunded',
208
- 'Cancelled': 'cancelled',
209
- 'Completed': 'completed',
210
- };
211
-
212
- return {
213
- id: String(raw.id),
214
- orderNumber: String(raw.id),
215
- email: raw.billing_address?.email ?? '',
216
- status: statusMap[raw.status] ?? 'pending',
217
- paymentStatus: raw.payment_status === 'paid' ? 'paid' : 'pending',
218
- fulfillmentStatus: raw.status === 'Shipped' ? 'fulfilled' : 'unfulfilled',
219
- items,
220
- total: transformMoney(raw.total_inc_tax ?? 0, currencyCode),
221
- subtotal: transformMoney(raw.subtotal_inc_tax ?? 0, currencyCode),
222
- tax: transformMoney(raw.total_tax ?? 0, currencyCode),
223
- shipping: transformMoney(raw.shipping_cost_inc_tax ?? 0, currencyCode),
224
- createdAt: raw.date_created ?? new Date().toISOString(),
225
- updatedAt: raw.date_modified ?? new Date().toISOString(),
226
- };
227
- }
@@ -1,387 +0,0 @@
1
- /**
2
- * @thorprovider/adapters — Magento (Adobe Commerce) Provider
3
- * Implements CommerceProvider for Magento 2 GraphQL + REST APIs
4
- *
5
- * Uses GraphQL Storefront for read operations (products, categories, cart).
6
- * REST API for customer/order operations requiring auth tokens.
7
- * PaaS-first approach (not Adobe IMS/SaaS).
8
- */
9
-
10
- import type {
11
- Product,
12
- GetProductsOptions,
13
- Cart,
14
- CartLineInput,
15
- CartLineUpdate,
16
- Collection,
17
- CollectionProductsOptions,
18
- GetCollectionsOptions,
19
- ProductCategory,
20
- GetCategoriesOptions,
21
- Order,
22
- GetOrdersOptions,
23
- Customer,
24
- Address,
25
- PaymentMethod,
26
- PaymentMethodsOptions,
27
- ShippingMethod,
28
- StockLocation,
29
- InventoryLevel,
30
- StockValidation,
31
- FulfillmentOption,
32
- StorefrontContext,
33
- BackendCapabilities,
34
- } from '@thorprovider/types';
35
- import type { CommerceProvider, ProviderConfig } from '../../types/provider';
36
- import { MAGENTO_CAPABILITIES } from '../../types/capabilities.types';
37
- import { createLogger } from '../../core/logger';
38
- import { ProviderAPIError } from '../../core/errors';
39
- import { transformProduct, transformCart, transformCollection, transformOrder, transformCustomer } from './transforms';
40
- import {
41
- GET_PRODUCTS,
42
- GET_PRODUCT_BY_URL_KEY,
43
- GET_CATEGORIES,
44
- GET_CATEGORY_BY_URL_KEY,
45
- GET_CATEGORY_PRODUCTS,
46
- GET_CART,
47
- CREATE_EMPTY_CART,
48
- ADD_TO_CART,
49
- REMOVE_FROM_CART,
50
- UPDATE_CART_ITEMS,
51
- APPLY_COUPON,
52
- REMOVE_COUPON,
53
- GET_CUSTOMER,
54
- GET_CUSTOMER_ORDERS,
55
- } from './queries';
56
-
57
- /**
58
- * Magento provider configuration
59
- */
60
- export interface MagentoProviderConfig extends ProviderConfig {
61
- /** Magento base URL (e.g., 'https://mymagento.com') */
62
- baseUrl: string;
63
- /** Store code for multi-tenant (default: 'default') */
64
- storeCode?: string;
65
- /** Customer bearer token (for authenticated operations) */
66
- customerToken?: string;
67
- /** Integration access token (for admin-level operations) */
68
- accessToken?: string;
69
- /** Default currency code (default: 'USD') */
70
- currencyCode?: string;
71
- }
72
-
73
- export class MagentoProvider implements CommerceProvider {
74
- readonly name = 'magento';
75
- readonly version = '1.0.0';
76
- readonly capabilities: BackendCapabilities = MAGENTO_CAPABILITIES;
77
-
78
- private logger: ReturnType<typeof createLogger>;
79
- private baseUrl: string;
80
- private storeCode: string;
81
- private currencyCode: string;
82
- private graphqlEndpoint: string;
83
- private customerToken?: string;
84
- private accessToken?: string;
85
-
86
- constructor(config: MagentoProviderConfig) {
87
- this.logger = createLogger('MagentoProvider', config.debug);
88
- this.baseUrl = config.baseUrl.replace(/\/$/, '');
89
- this.storeCode = config.storeCode ?? 'default';
90
- this.currencyCode = config.currencyCode ?? 'USD';
91
- this.graphqlEndpoint = `${this.baseUrl}/graphql`;
92
- this.customerToken = config.customerToken;
93
- this.accessToken = config.accessToken;
94
-
95
- this.logger.info('Initializing Magento Provider', {
96
- baseUrl: this.baseUrl,
97
- storeCode: this.storeCode,
98
- });
99
- }
100
-
101
- private async graphql<T = any>(query: string, variables?: Record<string, any>): Promise<T> {
102
- const headers: Record<string, string> = {
103
- 'Content-Type': 'application/json',
104
- 'Store': this.storeCode,
105
- };
106
-
107
- if (this.customerToken) {
108
- headers['Authorization'] = `Bearer ${this.customerToken}`;
109
- }
110
-
111
- const response = await fetch(this.graphqlEndpoint, {
112
- method: 'POST',
113
- headers,
114
- body: JSON.stringify({ query, variables }),
115
- });
116
-
117
- if (!response.ok) {
118
- throw new ProviderAPIError(
119
- `Magento GraphQL error: ${response.status}`,
120
- 'MAGENTO_API_ERROR',
121
- response.status,
122
- );
123
- }
124
-
125
- const json = await response.json() as { data?: T; errors?: Array<{ message: string }> };
126
-
127
- if (json.errors?.length) {
128
- const message = json.errors.map((e) => e.message).join('; ');
129
- throw new ProviderAPIError(`Magento GraphQL error: ${message}`, 'MAGENTO_GRAPHQL_ERROR');
130
- }
131
-
132
- return json.data as T;
133
- }
134
-
135
- // ============================================
136
- // Product Operations (GraphQL)
137
- // ============================================
138
-
139
- async getProduct(handle: string): Promise<Product | undefined> {
140
- try {
141
- const data = await this.graphql<{ products: { items: any[] } }>(GET_PRODUCT_BY_URL_KEY, { urlKey: handle });
142
- return data.products.items[0] ? transformProduct(data.products.items[0], this.currencyCode) : undefined;
143
- } catch {
144
- return undefined;
145
- }
146
- }
147
-
148
- async getProducts(options?: GetProductsOptions): Promise<Product[]> {
149
- const variables: Record<string, any> = {
150
- pageSize: options?.first ?? 20,
151
- currentPage: 1,
152
- };
153
-
154
- if (options?.query) variables.search = options.query;
155
- if (options?.sortKey) {
156
- const sortMap: Record<string, Record<string, string>> = {
157
- 'price-asc': { price: 'ASC' },
158
- 'price-desc': { price: 'DESC' },
159
- 'title-asc': { name: 'ASC' },
160
- 'title-desc': { name: 'DESC' },
161
- 'created-desc': { created_at: 'DESC' },
162
- 'relevance': { relevance: 'DESC' },
163
- };
164
- variables.sort = sortMap[options.sortKey] ?? { relevance: 'DESC' };
165
- }
166
-
167
- const data = await this.graphql<{ products: { items: any[] } }>(GET_PRODUCTS, variables);
168
- return (data.products?.items ?? []).map((p) => transformProduct(p, this.currencyCode));
169
- }
170
-
171
- async getProductRecommendations(_productId: string): Promise<Product[]> {
172
- return [];
173
- }
174
-
175
- // ============================================
176
- // Collection/Category Operations (GraphQL)
177
- // ============================================
178
-
179
- async getCollection(handle: string): Promise<Collection | undefined> {
180
- try {
181
- const data = await this.graphql<{ categories: { items: any[] } }>(GET_CATEGORY_BY_URL_KEY, { urlKey: handle });
182
- return data.categories.items[0] ? transformCollection(data.categories.items[0]) : undefined;
183
- } catch {
184
- return undefined;
185
- }
186
- }
187
-
188
- async getCollections(options?: GetCollectionsOptions): Promise<Collection[]> {
189
- const data = await this.graphql<{ categories: { items: any[] } }>(GET_CATEGORIES, {
190
- pageSize: options?.limit ?? 50,
191
- });
192
- return (data.categories?.items ?? []).map(transformCollection);
193
- }
194
-
195
- async getCollectionProducts(handle: string, options?: CollectionProductsOptions): Promise<Product[]> {
196
- const data = await this.graphql<{ products: { items: any[] } }>(GET_CATEGORY_PRODUCTS, {
197
- urlKey: handle,
198
- pageSize: options?.first ?? 20,
199
- });
200
- return (data.products?.items ?? []).map((p) => transformProduct(p, this.currencyCode));
201
- }
202
-
203
- async getCategory(handle: string): Promise<ProductCategory | undefined> {
204
- return this.getCollection(handle) as any;
205
- }
206
-
207
- async getCategories(options?: GetCategoriesOptions): Promise<ProductCategory[]> {
208
- return this.getCollections(options) as any;
209
- }
210
-
211
- async getCategoryProducts(handle: string, options?: CollectionProductsOptions): Promise<Product[]> {
212
- return this.getCollectionProducts(handle, options);
213
- }
214
-
215
- // ============================================
216
- // Cart Operations (GraphQL)
217
- // ============================================
218
-
219
- async createCart(): Promise<Cart> {
220
- const data = await this.graphql<{ createEmptyCart: string }>(CREATE_EMPTY_CART);
221
- const cartId = data.createEmptyCart;
222
- const cartData = await this.graphql<{ cart: any }>(GET_CART, { cartId });
223
- return transformCart(cartData.cart ?? { id: cartId, items: [], prices: {} }, this.currencyCode);
224
- }
225
-
226
- async getCart(cartId: string): Promise<Cart | undefined> {
227
- try {
228
- const data = await this.graphql<{ cart: any }>(GET_CART, { cartId });
229
- return data.cart ? transformCart(data.cart, this.currencyCode) : undefined;
230
- } catch {
231
- return undefined;
232
- }
233
- }
234
-
235
- async addToCart(cartId: string, lines: CartLineInput[]): Promise<Cart> {
236
- const cartItems = lines.map((l) => ({
237
- sku: l.merchandiseId,
238
- quantity: l.quantity,
239
- }));
240
-
241
- const data = await this.graphql<{ addProductsToCart: { cart: any; user_errors: any[] } }>(ADD_TO_CART, {
242
- cartId,
243
- cartItems,
244
- });
245
-
246
- if (data.addProductsToCart.user_errors?.length) {
247
- throw new ProviderAPIError(
248
- `Add to cart failed: ${data.addProductsToCart.user_errors.map((e: any) => e.message).join('; ')}`,
249
- 'MAGENTO_CART_ERROR',
250
- );
251
- }
252
-
253
- return transformCart(data.addProductsToCart.cart, this.currencyCode);
254
- }
255
-
256
- async removeFromCart(cartId: string, lineIds: string[]): Promise<Cart> {
257
- let cart: any;
258
- for (const itemUid of lineIds) {
259
- const data = await this.graphql<{ removeItemFromCart: { cart: any } }>(REMOVE_FROM_CART, {
260
- cartId,
261
- cartItemUid: itemUid,
262
- });
263
- cart = data.removeItemFromCart.cart;
264
- }
265
- return transformCart(cart ?? { id: cartId, items: [], prices: {} }, this.currencyCode);
266
- }
267
-
268
- async updateCart(cartId: string, lines: CartLineUpdate[]): Promise<Cart> {
269
- const cartItems = lines.map((l) => ({
270
- cart_item_uid: l.id,
271
- quantity: l.quantity,
272
- }));
273
-
274
- const data = await this.graphql<{ updateCartItems: { cart: any } }>(UPDATE_CART_ITEMS, {
275
- cartId,
276
- cartItems,
277
- });
278
-
279
- return transformCart(data.updateCartItems.cart, this.currencyCode);
280
- }
281
-
282
- // ============================================
283
- // Checkout Operations
284
- // ============================================
285
-
286
- async completeCheckout(_cartId: string): Promise<Order> {
287
- throw new ProviderAPIError(
288
- 'Magento checkout requires multi-step process (set addresses, shipping, payment, place order). Use the Magento checkout flow.',
289
- 'MAGENTO_CHECKOUT_MULTI_STEP',
290
- );
291
- }
292
-
293
- async getShippingMethods(_cartId: string): Promise<ShippingMethod[]> {
294
- return [];
295
- }
296
-
297
- async getRegionCountries(): Promise<import('@thorprovider/types').Country[]> {
298
- return [];
299
- }
300
-
301
- async addShippingMethod(_cartId: string, _methodId: string): Promise<Cart> {
302
- throw new ProviderAPIError(
303
- 'Magento shipping selection requires set-shipping-methods mutation.',
304
- 'MAGENTO_CHECKOUT_MULTI_STEP',
305
- );
306
- }
307
-
308
- async initiatePaymentSession(_cartId: string, _providerId: string): Promise<void> {
309
- // Magento handles payment via set-payment-method mutation
310
- }
311
-
312
- async applyDiscountCode(cartId: string, code: string): Promise<Cart> {
313
- const data = await this.graphql<{ applyCouponToCart: { cart: any } }>(APPLY_COUPON, {
314
- cartId,
315
- couponCode: code,
316
- });
317
- return transformCart(data.applyCouponToCart.cart, this.currencyCode);
318
- }
319
-
320
- async removeDiscountCode(cartId: string, _code: string): Promise<Cart> {
321
- const data = await this.graphql<{ removeCouponFromCart: { cart: any } }>(REMOVE_COUPON, {
322
- cartId,
323
- });
324
- return transformCart(data.removeCouponFromCart.cart, this.currencyCode);
325
- }
326
-
327
- // ============================================
328
- // Customer & Orders (GraphQL — requires customerToken)
329
- // ============================================
330
-
331
- async getOrders(_options: GetOrdersOptions): Promise<Order[]> {
332
- if (!this.customerToken) return [];
333
- try {
334
- const data = await this.graphql<{ customer: { orders: { items: any[] } } }>(GET_CUSTOMER_ORDERS, {
335
- pageSize: 20,
336
- currentPage: 1,
337
- });
338
- return (data.customer?.orders?.items ?? []).map((o) => transformOrder(o, this.currencyCode));
339
- } catch {
340
- return [];
341
- }
342
- }
343
-
344
- async getPaymentMethods(_options: PaymentMethodsOptions): Promise<PaymentMethod[]> {
345
- return [];
346
- }
347
-
348
- // ============================================
349
- // Inventory
350
- // ============================================
351
-
352
- async getStockLocations(): Promise<StockLocation[]> { return []; }
353
- async checkInventoryLevels(): Promise<InventoryLevel[]> { return []; }
354
- async validateCartStock(): Promise<StockValidation> { return { allAvailable: true, unavailableItems: [] }; }
355
- async getFulfillmentOptions(): Promise<FulfillmentOption[]> { return []; }
356
-
357
- // ============================================
358
- // Admin Operations
359
- // ============================================
360
-
361
- async cancelOrder(_orderId: string): Promise<Order> {
362
- throw new ProviderAPIError('Order cancellation requires Magento Admin API.', 'MAGENTO_ADMIN_REQUIRED');
363
- }
364
- async createFulfillment(_orderId: string): Promise<void> {
365
- throw new ProviderAPIError('Fulfillment requires Magento Admin API.', 'MAGENTO_ADMIN_REQUIRED');
366
- }
367
- async createRefund(_orderId: string): Promise<void> {
368
- throw new ProviderAPIError('Refunds require Magento Admin API.', 'MAGENTO_ADMIN_REQUIRED');
369
- }
370
- async getAdminOrders(): Promise<{ orders: Order[]; count: number }> { return { orders: [], count: 0 }; }
371
-
372
- // ============================================
373
- // Storefront / Multi-Tenant
374
- // ============================================
375
-
376
- async getStorefrontContext(): Promise<StorefrontContext> {
377
- return {
378
- id: this.storeCode,
379
- name: `Magento ${this.storeCode}`,
380
- platformType: 'magento',
381
- requiresProductScoping: true,
382
- currencyCode: this.currencyCode,
383
- };
384
- }
385
-
386
- isStorefrontRequired(): boolean { return true; }
387
- }
@@ -1,5 +0,0 @@
1
- /**
2
- * Magento (Adobe Commerce) Provider — barrel exports
3
- */
4
- export { MagentoProvider } from './index';
5
- export type { MagentoProviderConfig } from './index';