@thorprovider/adapters 4.3.0 → 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.
package/dist/index.mjs CHANGED
@@ -106,209 +106,6 @@ var STELORDER_CAPABILITIES = {
106
106
  // Loyalty
107
107
  loyaltyProgram: false
108
108
  };
109
- var SHOPIFY_CAPABILITIES = {
110
- // Profile Management
111
- updateProfile: true,
112
- updateEmail: true,
113
- changePasswordDirect: true,
114
- changePasswordViaEmail: true,
115
- deleteAccount: false,
116
- // Requires admin API
117
- // Avatar
118
- uploadAvatar: false,
119
- avatarViaMetadata: true,
120
- // Custom Attributes
121
- customAttributes: true,
122
- // Orders
123
- fetchOrders: true,
124
- cancelOrder: true,
125
- // Addresses
126
- manageAddresses: true,
127
- defaultAddress: true,
128
- // Cart/Checkout
129
- applyDiscounts: true,
130
- shippingCalculation: true,
131
- guestCheckout: true,
132
- savedPaymentMethods: true,
133
- listPaymentProviders: true,
134
- regionSpecificPayments: false,
135
- // Global payment methods
136
- // Wishlist
137
- wishlist: false,
138
- // Requires app
139
- // Search
140
- advancedSearch: true,
141
- facetedFilters: true,
142
- // Reviews
143
- productReviews: false,
144
- // Requires app
145
- // Loyalty
146
- loyaltyProgram: false
147
- // Requires app
148
- };
149
- var BIGCOMMERCE_CAPABILITIES = {
150
- // Profile Management
151
- updateProfile: true,
152
- updateEmail: true,
153
- changePasswordDirect: true,
154
- changePasswordViaEmail: true,
155
- deleteAccount: false,
156
- // Avatar
157
- uploadAvatar: false,
158
- avatarViaMetadata: false,
159
- // Custom Attributes
160
- customAttributes: true,
161
- // Orders
162
- fetchOrders: true,
163
- cancelOrder: false,
164
- // Admin API only
165
- // Addresses
166
- manageAddresses: true,
167
- defaultAddress: false,
168
- // Cart/Checkout
169
- applyDiscounts: true,
170
- shippingCalculation: true,
171
- guestCheckout: true,
172
- savedPaymentMethods: true,
173
- listPaymentProviders: true,
174
- regionSpecificPayments: false,
175
- // Wishlist
176
- wishlist: true,
177
- // Native support
178
- // Search
179
- advancedSearch: true,
180
- facetedFilters: true,
181
- // Reviews
182
- productReviews: true,
183
- // Native support
184
- // Loyalty
185
- loyaltyProgram: false
186
- };
187
- var WOOCOMMERCE_CAPABILITIES = {
188
- // Profile Management
189
- updateProfile: true,
190
- updateEmail: true,
191
- changePasswordDirect: false,
192
- // WordPress handles auth
193
- changePasswordViaEmail: true,
194
- deleteAccount: false,
195
- // Avatar
196
- uploadAvatar: false,
197
- avatarViaMetadata: false,
198
- // Gravatar-based
199
- // Custom Attributes
200
- customAttributes: true,
201
- // Via meta_data
202
- // Orders
203
- fetchOrders: true,
204
- cancelOrder: true,
205
- // Addresses
206
- manageAddresses: true,
207
- defaultAddress: false,
208
- // Billing/shipping only
209
- // Cart/Checkout
210
- applyDiscounts: true,
211
- // Coupon codes
212
- shippingCalculation: true,
213
- guestCheckout: true,
214
- savedPaymentMethods: false,
215
- listPaymentProviders: true,
216
- regionSpecificPayments: false,
217
- // Wishlist
218
- wishlist: false,
219
- // Requires plugin
220
- // Search
221
- advancedSearch: false,
222
- // Basic WP search
223
- facetedFilters: false,
224
- // Requires plugin
225
- // Reviews
226
- productReviews: true,
227
- // Native WP reviews
228
- // Loyalty
229
- loyaltyProgram: false
230
- };
231
- var SPREE_CAPABILITIES = {
232
- // Profile Management
233
- updateProfile: true,
234
- updateEmail: true,
235
- changePasswordDirect: true,
236
- changePasswordViaEmail: true,
237
- deleteAccount: false,
238
- // Avatar
239
- uploadAvatar: false,
240
- avatarViaMetadata: false,
241
- // Custom Attributes
242
- customAttributes: false,
243
- // Orders
244
- fetchOrders: true,
245
- cancelOrder: true,
246
- // Addresses
247
- manageAddresses: true,
248
- defaultAddress: true,
249
- // Cart/Checkout
250
- applyDiscounts: true,
251
- shippingCalculation: true,
252
- guestCheckout: true,
253
- savedPaymentMethods: false,
254
- listPaymentProviders: true,
255
- regionSpecificPayments: false,
256
- // Wishlist
257
- wishlist: true,
258
- // Native support
259
- // Search
260
- advancedSearch: false,
261
- facetedFilters: true,
262
- // Taxon-based filtering
263
- // Reviews
264
- productReviews: false,
265
- // Requires extension
266
- // Loyalty
267
- loyaltyProgram: false
268
- };
269
- var MAGENTO_CAPABILITIES = {
270
- // Profile Management
271
- updateProfile: true,
272
- updateEmail: true,
273
- changePasswordDirect: true,
274
- changePasswordViaEmail: true,
275
- deleteAccount: false,
276
- // Admin only
277
- // Avatar
278
- uploadAvatar: false,
279
- avatarViaMetadata: false,
280
- // Custom Attributes
281
- customAttributes: true,
282
- // EAV model
283
- // Orders
284
- fetchOrders: true,
285
- cancelOrder: true,
286
- // Addresses
287
- manageAddresses: true,
288
- defaultAddress: true,
289
- // Cart/Checkout
290
- applyDiscounts: true,
291
- shippingCalculation: true,
292
- guestCheckout: true,
293
- savedPaymentMethods: true,
294
- listPaymentProviders: true,
295
- regionSpecificPayments: true,
296
- // Store-view scoped
297
- // Wishlist
298
- wishlist: true,
299
- // Native support
300
- // Search
301
- advancedSearch: true,
302
- // Elasticsearch/OpenSearch
303
- facetedFilters: true,
304
- // Layered navigation
305
- // Reviews
306
- productReviews: true,
307
- // Native support
308
- // Loyalty
309
- loyaltyProgram: false
310
- // Requires extension
311
- };
312
109
  function isBackendCapabilities(obj) {
313
110
  if (typeof obj !== "object" || obj === null) return false;
314
111
  const capabilities = obj;
@@ -1528,13 +1325,7 @@ function createBackendMetadataAdapter(config) {
1528
1325
  });
1529
1326
  return new MedusaMetadataAdapter(medusa);
1530
1327
  }
1531
- if (provider === "shopify") {
1532
- throw new Error("Shopify metadata adapter not yet implemented");
1533
- }
1534
- if (provider === "woocommerce") {
1535
- throw new Error("WooCommerce metadata adapter not yet implemented");
1536
- }
1537
- throw new Error(`Unsupported provider: ${provider}`);
1328
+ throw new Error(`Unsupported provider for metadata adapter: ${provider}. Only 'medusa' is currently supported.`);
1538
1329
  }
1539
1330
 
1540
1331
  // src/metadata/channel-scope.ts
@@ -5787,2669 +5578,62 @@ var MedusaProvider = class {
5787
5578
  }
5788
5579
  };
5789
5580
 
5790
- // src/providers/shopify/transforms.ts
5791
- function transformMoney2(shopifyMoney) {
5792
- return {
5793
- amount: shopifyMoney?.amount ?? "0.00",
5794
- currencyCode: shopifyMoney?.currencyCode?.toUpperCase() ?? "USD"
5795
- };
5796
- }
5797
- function transformImage2(shopifyImage) {
5798
- return {
5799
- url: shopifyImage?.url ?? "",
5800
- altText: shopifyImage?.altText ?? "",
5801
- width: shopifyImage?.width ?? 800,
5802
- height: shopifyImage?.height ?? 800
5803
- };
5581
+ // src/providers/stelorder/transforms.ts
5582
+ function normalizeStelCollection(payload) {
5583
+ if (!payload) {
5584
+ return [];
5585
+ }
5586
+ return Array.isArray(payload) ? payload : [payload];
5804
5587
  }
5805
- function transformVariant(raw) {
5806
- return {
5807
- id: raw.id,
5808
- title: raw.title ?? "",
5809
- availableForSale: raw.availableForSale ?? true,
5810
- price: transformMoney2(raw.price),
5811
- compareAtPrice: raw.compareAtPrice ? transformMoney2(raw.compareAtPrice) : void 0,
5812
- selectedOptions: (raw.selectedOptions ?? []).map((opt) => ({
5813
- name: opt.name,
5814
- value: opt.value
5815
- })),
5816
- image: raw.image ? transformImage2(raw.image) : void 0
5817
- };
5588
+ function normalizeStelEntity(payload) {
5589
+ if (!payload) {
5590
+ return void 0;
5591
+ }
5592
+ return Array.isArray(payload) ? payload[0] : payload;
5818
5593
  }
5819
- function transformOption(raw) {
5594
+ function transformStelMoney(amount, currencyCode = "USD") {
5595
+ const normalizedAmount = typeof amount === "string" ? Number.parseFloat(amount) : amount ?? 0;
5820
5596
  return {
5821
- id: raw.id,
5822
- name: raw.name,
5823
- values: raw.values ?? []
5597
+ amount: Number.isFinite(normalizedAmount) ? normalizedAmount.toFixed(2) : "0.00",
5598
+ currencyCode: currencyCode.toUpperCase()
5824
5599
  };
5825
5600
  }
5826
- function transformProduct2(raw) {
5827
- const images = (raw.images?.edges ?? []).map((edge) => transformImage2(edge.node));
5828
- const variants = (raw.variants?.edges ?? []).map((edge) => transformVariant(edge.node));
5601
+ function transformStelImage(url, altText = "") {
5602
+ const normalizedUrl = url?.trim();
5603
+ if (!normalizedUrl) {
5604
+ return void 0;
5605
+ }
5829
5606
  return {
5830
- id: raw.id,
5831
- handle: raw.handle,
5832
- title: raw.title,
5833
- description: raw.description ?? "",
5834
- descriptionHtml: raw.descriptionHtml ?? "",
5835
- availableForSale: raw.availableForSale ?? true,
5836
- featuredImage: raw.featuredImage ? transformImage2(raw.featuredImage) : images[0] ?? { url: "", altText: "", width: 800, height: 800 },
5837
- images,
5838
- options: (raw.options ?? []).map(transformOption),
5839
- variants,
5840
- priceRange: {
5841
- minVariantPrice: transformMoney2(raw.priceRange?.minVariantPrice),
5842
- maxVariantPrice: transformMoney2(raw.priceRange?.maxVariantPrice)
5843
- },
5844
- seo: {
5845
- title: raw.seo?.title ?? raw.title ?? "",
5846
- description: raw.seo?.description ?? raw.description ?? ""
5847
- },
5848
- tags: raw.tags ?? [],
5849
- createdAt: raw.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
5850
- updatedAt: raw.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
5851
- vendor: raw.vendor,
5852
- productType: raw.productType
5607
+ url: normalizedUrl,
5608
+ altText,
5609
+ width: 800,
5610
+ height: 800
5853
5611
  };
5854
5612
  }
5855
- function transformCollection2(raw) {
5856
- return {
5857
- id: raw.id ?? "",
5858
- handle: raw.handle,
5859
- title: raw.title,
5860
- description: raw.description ?? "",
5861
- seo: {
5862
- title: raw.seo?.title ?? raw.title ?? "",
5863
- description: raw.seo?.description ?? raw.description ?? ""
5864
- },
5865
- updatedAt: raw.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
5866
- path: `/collections/${raw.handle}`
5867
- };
5613
+ function normalizeStelDate(value) {
5614
+ if (!value) {
5615
+ return (/* @__PURE__ */ new Date()).toISOString();
5616
+ }
5617
+ const parsed = new Date(value);
5618
+ return Number.isNaN(parsed.getTime()) ? (/* @__PURE__ */ new Date()).toISOString() : parsed.toISOString();
5868
5619
  }
5869
- function transformCartItem2(raw) {
5870
- const merchandise = raw.merchandise ?? {};
5871
- const product = merchandise.product ?? {};
5872
- return {
5873
- id: raw.id,
5874
- quantity: raw.quantity ?? 1,
5875
- cost: {
5876
- totalAmount: transformMoney2(raw.cost?.totalAmount)
5877
- },
5878
- merchandise: {
5879
- id: merchandise.id ?? "",
5880
- title: merchandise.title ?? "",
5881
- selectedOptions: (merchandise.selectedOptions ?? []).map((opt) => ({
5882
- name: opt.name,
5883
- value: opt.value
5884
- })),
5885
- product: {
5886
- id: product.id ?? "",
5887
- handle: product.handle ?? "",
5888
- title: product.title ?? "",
5889
- featuredImage: product.featuredImage ? transformImage2(product.featuredImage) : { url: "", altText: "", width: 800, height: 800 }
5890
- }
5891
- }
5892
- };
5620
+ function toStelStringId(value) {
5621
+ if (value === null || value === void 0) {
5622
+ return "";
5623
+ }
5624
+ return String(value);
5893
5625
  }
5894
- function transformCart2(raw) {
5895
- const lines = (raw.lines?.edges ?? []).map((edge) => transformCartItem2(edge.node));
5896
- return {
5897
- id: raw.id,
5898
- checkoutUrl: raw.checkoutUrl ?? "",
5899
- totalQuantity: raw.totalQuantity ?? 0,
5900
- cost: {
5901
- subtotalAmount: transformMoney2(raw.cost?.subtotalAmount),
5902
- totalAmount: transformMoney2(raw.cost?.totalAmount),
5903
- totalTaxAmount: raw.cost?.totalTaxAmount ? transformMoney2(raw.cost.totalTaxAmount) : void 0
5904
- },
5905
- lines
5906
- };
5626
+ function slugify(value) {
5627
+ return value.normalize("NFKD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
5907
5628
  }
5908
-
5909
- // src/providers/shopify/queries.ts
5910
- var PRODUCT_FRAGMENT = `
5911
- fragment ProductFields on Product {
5912
- id
5913
- title
5914
- handle
5915
- description
5916
- descriptionHtml
5917
- vendor
5918
- productType
5919
- tags
5920
- availableForSale
5921
- createdAt
5922
- updatedAt
5923
- seo {
5924
- title
5925
- description
5926
- }
5927
- featuredImage {
5928
- url
5929
- altText
5930
- width
5931
- height
5932
- }
5933
- images(first: 10) {
5934
- edges {
5935
- node {
5936
- url
5937
- altText
5938
- width
5939
- height
5940
- }
5941
- }
5942
- }
5943
- priceRange {
5944
- minVariantPrice {
5945
- amount
5946
- currencyCode
5947
- }
5948
- maxVariantPrice {
5949
- amount
5950
- currencyCode
5951
- }
5952
- }
5953
- options {
5954
- id
5955
- name
5956
- values
5957
- }
5958
- variants(first: 100) {
5959
- edges {
5960
- node {
5961
- id
5962
- title
5963
- availableForSale
5964
- price {
5965
- amount
5966
- currencyCode
5967
- }
5968
- compareAtPrice {
5969
- amount
5970
- currencyCode
5971
- }
5972
- selectedOptions {
5973
- name
5974
- value
5975
- }
5976
- image {
5977
- url
5978
- altText
5979
- width
5980
- height
5981
- }
5982
- }
5983
- }
5629
+ function buildStelHandle(...candidates) {
5630
+ for (const candidate of candidates) {
5631
+ if (candidate === null || candidate === void 0) {
5632
+ continue;
5984
5633
  }
5985
- }
5986
- `;
5987
- var GET_PRODUCT_BY_HANDLE = `
5988
- query GetProductByHandle($handle: String!) {
5989
- product(handle: $handle) {
5990
- ...ProductFields
5991
- }
5992
- }
5993
- ${PRODUCT_FRAGMENT}
5994
- `;
5995
- var GET_PRODUCTS = `
5996
- query GetProducts($first: Int!, $query: String, $sortKey: ProductSortKeys, $reverse: Boolean, $after: String) {
5997
- products(first: $first, query: $query, sortKey: $sortKey, reverse: $reverse, after: $after) {
5998
- edges {
5999
- node {
6000
- ...ProductFields
6001
- }
6002
- cursor
6003
- }
6004
- pageInfo {
6005
- hasNextPage
6006
- hasPreviousPage
6007
- }
6008
- }
6009
- }
6010
- ${PRODUCT_FRAGMENT}
6011
- `;
6012
- var GET_PRODUCT_RECOMMENDATIONS = `
6013
- query GetProductRecommendations($productId: ID!) {
6014
- productRecommendations(productId: $productId) {
6015
- ...ProductFields
6016
- }
6017
- }
6018
- ${PRODUCT_FRAGMENT}
6019
- `;
6020
- var COLLECTION_FRAGMENT = `
6021
- fragment CollectionFields on Collection {
6022
- id
6023
- title
6024
- handle
6025
- description
6026
- image {
6027
- url
6028
- altText
6029
- width
6030
- height
6031
- }
6032
- seo {
6033
- title
6034
- description
6035
- }
6036
- updatedAt
6037
- }
6038
- `;
6039
- var GET_COLLECTION_BY_HANDLE = `
6040
- query GetCollectionByHandle($handle: String!) {
6041
- collection(handle: $handle) {
6042
- ...CollectionFields
6043
- }
6044
- }
6045
- ${COLLECTION_FRAGMENT}
6046
- `;
6047
- var GET_COLLECTIONS = `
6048
- query GetCollections($first: Int!) {
6049
- collections(first: $first) {
6050
- edges {
6051
- node {
6052
- ...CollectionFields
6053
- }
6054
- }
6055
- }
6056
- }
6057
- ${COLLECTION_FRAGMENT}
6058
- `;
6059
- var GET_COLLECTION_PRODUCTS = `
6060
- query GetCollectionProducts($handle: String!, $first: Int!, $sortKey: ProductCollectionSortKeys, $reverse: Boolean, $after: String) {
6061
- collection(handle: $handle) {
6062
- products(first: $first, sortKey: $sortKey, reverse: $reverse, after: $after) {
6063
- edges {
6064
- node {
6065
- ...ProductFields
6066
- }
6067
- cursor
6068
- }
6069
- pageInfo {
6070
- hasNextPage
6071
- }
6072
- }
6073
- }
6074
- }
6075
- ${PRODUCT_FRAGMENT}
6076
- `;
6077
- var CART_FRAGMENT = `
6078
- fragment CartFields on Cart {
6079
- id
6080
- checkoutUrl
6081
- totalQuantity
6082
- cost {
6083
- subtotalAmount {
6084
- amount
6085
- currencyCode
6086
- }
6087
- totalAmount {
6088
- amount
6089
- currencyCode
6090
- }
6091
- totalTaxAmount {
6092
- amount
6093
- currencyCode
6094
- }
6095
- }
6096
- lines(first: 100) {
6097
- edges {
6098
- node {
6099
- id
6100
- quantity
6101
- cost {
6102
- totalAmount {
6103
- amount
6104
- currencyCode
6105
- }
6106
- }
6107
- merchandise {
6108
- ... on ProductVariant {
6109
- id
6110
- title
6111
- selectedOptions {
6112
- name
6113
- value
6114
- }
6115
- product {
6116
- id
6117
- handle
6118
- title
6119
- featuredImage {
6120
- url
6121
- altText
6122
- width
6123
- height
6124
- }
6125
- }
6126
- }
6127
- }
6128
- }
6129
- }
6130
- }
6131
- }
6132
- `;
6133
- var GET_CART = `
6134
- query GetCart($cartId: ID!) {
6135
- cart(id: $cartId) {
6136
- ...CartFields
6137
- }
6138
- }
6139
- ${CART_FRAGMENT}
6140
- `;
6141
-
6142
- // src/providers/shopify/mutations.ts
6143
- var CART_CREATE = `
6144
- mutation CartCreate($input: CartInput!) {
6145
- cartCreate(input: $input) {
6146
- cart {
6147
- ...CartFields
6148
- }
6149
- userErrors {
6150
- field
6151
- message
6152
- code
6153
- }
6154
- }
6155
- }
6156
- ${CART_FRAGMENT}
6157
- `;
6158
- var CART_LINES_ADD = `
6159
- mutation CartLinesAdd($cartId: ID!, $lines: [CartLineInput!]!) {
6160
- cartLinesAdd(cartId: $cartId, lines: $lines) {
6161
- cart {
6162
- ...CartFields
6163
- }
6164
- userErrors {
6165
- field
6166
- message
6167
- code
6168
- }
6169
- }
6170
- }
6171
- ${CART_FRAGMENT}
6172
- `;
6173
- var CART_LINES_UPDATE = `
6174
- mutation CartLinesUpdate($cartId: ID!, $lines: [CartLineUpdateInput!]!) {
6175
- cartLinesUpdate(cartId: $cartId, lines: $lines) {
6176
- cart {
6177
- ...CartFields
6178
- }
6179
- userErrors {
6180
- field
6181
- message
6182
- code
6183
- }
6184
- }
6185
- }
6186
- ${CART_FRAGMENT}
6187
- `;
6188
- var CART_LINES_REMOVE = `
6189
- mutation CartLinesRemove($cartId: ID!, $lineIds: [ID!]!) {
6190
- cartLinesRemove(cartId: $cartId, lineIds: $lineIds) {
6191
- cart {
6192
- ...CartFields
6193
- }
6194
- userErrors {
6195
- field
6196
- message
6197
- code
6198
- }
6199
- }
6200
- }
6201
- ${CART_FRAGMENT}
6202
- `;
6203
- var CART_DISCOUNT_CODES_UPDATE = `
6204
- mutation CartDiscountCodesUpdate($cartId: ID!, $discountCodes: [String!]!) {
6205
- cartDiscountCodesUpdate(cartId: $cartId, discountCodes: $discountCodes) {
6206
- cart {
6207
- ...CartFields
6208
- }
6209
- userErrors {
6210
- field
6211
- message
6212
- code
6213
- }
6214
- }
6215
- }
6216
- ${CART_FRAGMENT}
6217
- `;
6218
-
6219
- // src/providers/shopify/index.ts
6220
- var ShopifyProvider = class {
6221
- name = "shopify";
6222
- version = "1.0.0";
6223
- capabilities = SHOPIFY_CAPABILITIES;
6224
- logger;
6225
- storeDomain;
6226
- apiVersion;
6227
- endpoint;
6228
- headers;
6229
- constructor(config) {
6230
- this.logger = createLogger("ShopifyProvider", config.debug);
6231
- this.storeDomain = config.storeDomain.replace(/^https?:\/\//, "").replace(/\/$/, "");
6232
- this.apiVersion = config.apiVersion ?? "2026-04";
6233
- this.endpoint = `https://${this.storeDomain}/api/${this.apiVersion}/graphql.json`;
6234
- this.headers = {
6235
- "Content-Type": "application/json",
6236
- ...config.privateAccessToken ? { "Shopify-Storefront-Private-Token": config.privateAccessToken } : { "X-Shopify-Storefront-Access-Token": config.publicAccessToken }
6237
- };
6238
- this.logger.info("Initializing Shopify Provider", {
6239
- storeDomain: this.storeDomain,
6240
- apiVersion: this.apiVersion,
6241
- authType: config.privateAccessToken ? "private" : "public"
6242
- });
6243
- }
6244
- // ============================================
6245
- // GraphQL Client
6246
- // ============================================
6247
- async query(gql, variables) {
6248
- const response = await fetch(this.endpoint, {
6249
- method: "POST",
6250
- headers: this.headers,
6251
- body: JSON.stringify({ query: gql, variables })
6252
- });
6253
- if (!response.ok) {
6254
- throw new ProviderAPIError(
6255
- `Shopify API error: ${response.status} ${response.statusText}`,
6256
- "SHOPIFY_API_ERROR",
6257
- response.status
6258
- );
6259
- }
6260
- const json = await response.json();
6261
- if (json.errors?.length) {
6262
- const message = json.errors.map((e) => e.message).join("; ");
6263
- throw new ProviderAPIError(`Shopify GraphQL error: ${message}`, "SHOPIFY_GRAPHQL_ERROR");
6264
- }
6265
- return json.data;
6266
- }
6267
- // ============================================
6268
- // Product Operations
6269
- // ============================================
6270
- async getProduct(handle) {
6271
- const data = await this.query(GET_PRODUCT_BY_HANDLE, { handle });
6272
- return data.product ? transformProduct2(data.product) : void 0;
6273
- }
6274
- async getProducts(options) {
6275
- const first = options?.first ?? 20;
6276
- const sortKeyMap = {
6277
- "title-asc": "TITLE",
6278
- "title-desc": "TITLE",
6279
- "price-asc": "PRICE",
6280
- "price-desc": "PRICE",
6281
- "best-selling": "BEST_SELLING",
6282
- "created-desc": "CREATED_AT",
6283
- "relevance": "RELEVANCE"
6284
- };
6285
- const sortKey = options?.sortKey ? sortKeyMap[options.sortKey] ?? "RELEVANCE" : "RELEVANCE";
6286
- const reverse = options?.sortKey?.endsWith("-desc") ?? false;
6287
- const data = await this.query(GET_PRODUCTS, {
6288
- first,
6289
- query: options?.query,
6290
- sortKey,
6291
- reverse
6292
- });
6293
- return data.products.edges.map((edge) => transformProduct2(edge.node));
6294
- }
6295
- async getProductRecommendations(productId) {
6296
- const data = await this.query(GET_PRODUCT_RECOMMENDATIONS, {
6297
- productId
6298
- });
6299
- return (data.productRecommendations ?? []).map(transformProduct2);
6300
- }
6301
- // ============================================
6302
- // Collection Operations
6303
- // ============================================
6304
- async getCollection(handle) {
6305
- const data = await this.query(GET_COLLECTION_BY_HANDLE, { handle });
6306
- return data.collection ? transformCollection2(data.collection) : void 0;
6307
- }
6308
- async getCollections(options) {
6309
- const data = await this.query(GET_COLLECTIONS, {
6310
- first: options?.limit ?? 50
6311
- });
6312
- return data.collections.edges.map((edge) => transformCollection2(edge.node));
6313
- }
6314
- async getCollectionProducts(handle, options) {
6315
- const data = await this.query(
6316
- GET_COLLECTION_PRODUCTS,
6317
- {
6318
- handle,
6319
- first: options?.first ?? 20,
6320
- sortKey: options?.sortKey === "price-asc" || options?.sortKey === "price-desc" ? "PRICE" : "BEST_SELLING",
6321
- reverse: options?.sortKey?.endsWith("-desc") ?? false
6322
- }
6323
- );
6324
- return (data.collection?.products?.edges ?? []).map((edge) => transformProduct2(edge.node));
6325
- }
6326
- // ============================================
6327
- // Category Operations (Shopify does not have native categories)
6328
- // ============================================
6329
- async getCategory() {
6330
- this.logger.warn("Shopify does not support native categories. Use collections instead.");
6331
- return void 0;
6332
- }
6333
- async getCategories() {
6334
- return [];
6335
- }
6336
- async getCategoryProducts() {
6337
- return [];
6338
- }
6339
- // ============================================
6340
- // Cart Operations
6341
- // ============================================
6342
- async createCart() {
6343
- const data = await this.query(CART_CREATE, {
6344
- input: {}
6345
- });
6346
- if (data.cartCreate.userErrors?.length) {
6347
- throw new ProviderAPIError(
6348
- `Cart creation failed: ${data.cartCreate.userErrors.map((e) => e.message).join("; ")}`,
6349
- "SHOPIFY_CART_ERROR"
6350
- );
6351
- }
6352
- return transformCart2(data.cartCreate.cart);
6353
- }
6354
- async getCart(cartId) {
6355
- const data = await this.query(GET_CART, { cartId });
6356
- return data.cart ? transformCart2(data.cart) : void 0;
6357
- }
6358
- async addToCart(cartId, lines) {
6359
- const data = await this.query(CART_LINES_ADD, {
6360
- cartId,
6361
- lines: lines.map((l) => ({ merchandiseId: l.merchandiseId, quantity: l.quantity }))
6362
- });
6363
- if (data.cartLinesAdd.userErrors?.length) {
6364
- throw new ProviderAPIError(
6365
- `Add to cart failed: ${data.cartLinesAdd.userErrors.map((e) => e.message).join("; ")}`,
6366
- "SHOPIFY_CART_ERROR"
6367
- );
6368
- }
6369
- return transformCart2(data.cartLinesAdd.cart);
6370
- }
6371
- async removeFromCart(cartId, lineIds) {
6372
- const data = await this.query(CART_LINES_REMOVE, {
6373
- cartId,
6374
- lineIds
6375
- });
6376
- if (data.cartLinesRemove.userErrors?.length) {
6377
- throw new ProviderAPIError(
6378
- `Remove from cart failed: ${data.cartLinesRemove.userErrors.map((e) => e.message).join("; ")}`,
6379
- "SHOPIFY_CART_ERROR"
6380
- );
6381
- }
6382
- return transformCart2(data.cartLinesRemove.cart);
6383
- }
6384
- async updateCart(cartId, lines) {
6385
- const data = await this.query(CART_LINES_UPDATE, {
6386
- cartId,
6387
- lines: lines.map((l) => ({ id: l.id, quantity: l.quantity }))
6388
- });
6389
- if (data.cartLinesUpdate.userErrors?.length) {
6390
- throw new ProviderAPIError(
6391
- `Update cart failed: ${data.cartLinesUpdate.userErrors.map((e) => e.message).join("; ")}`,
6392
- "SHOPIFY_CART_ERROR"
6393
- );
6394
- }
6395
- return transformCart2(data.cartLinesUpdate.cart);
6396
- }
6397
- // ============================================
6398
- // Checkout Operations
6399
- // ============================================
6400
- async completeCheckout(_cartId) {
6401
- throw new ProviderAPIError(
6402
- "Shopify uses hosted checkout. Redirect the buyer to cart.checkoutUrl instead of calling completeCheckout().",
6403
- "SHOPIFY_HOSTED_CHECKOUT"
6404
- );
6405
- }
6406
- async getShippingMethods(_cartId) {
6407
- return [];
6408
- }
6409
- async getRegionCountries() {
6410
- return [];
6411
- }
6412
- async addShippingMethod(_cartId, _methodId) {
6413
- throw new ProviderAPIError(
6414
- "Shopify handles shipping selection in hosted checkout.",
6415
- "SHOPIFY_HOSTED_CHECKOUT"
6416
- );
6417
- }
6418
- async initiatePaymentSession(_cartId, _providerId) {
6419
- throw new ProviderAPIError(
6420
- "Shopify handles payment in hosted checkout.",
6421
- "SHOPIFY_HOSTED_CHECKOUT"
6422
- );
6423
- }
6424
- async applyDiscountCode(cartId, code) {
6425
- const currentCart = await this.getCart(cartId);
6426
- const existingCodes = [];
6427
- existingCodes.push(code);
6428
- const data = await this.query(
6429
- CART_DISCOUNT_CODES_UPDATE,
6430
- { cartId, discountCodes: existingCodes }
6431
- );
6432
- if (data.cartDiscountCodesUpdate.userErrors?.length) {
6433
- throw new ProviderAPIError(
6434
- `Discount code failed: ${data.cartDiscountCodesUpdate.userErrors.map((e) => e.message).join("; ")}`,
6435
- "SHOPIFY_DISCOUNT_ERROR"
6436
- );
6437
- }
6438
- return transformCart2(data.cartDiscountCodesUpdate.cart);
6439
- }
6440
- async removeDiscountCode(cartId, _code) {
6441
- const data = await this.query(
6442
- CART_DISCOUNT_CODES_UPDATE,
6443
- { cartId, discountCodes: [] }
6444
- );
6445
- return transformCart2(data.cartDiscountCodesUpdate.cart);
6446
- }
6447
- // ============================================
6448
- // Customer Operations
6449
- // ============================================
6450
- async getOrders(options) {
6451
- this.logger.warn("Shopify orders require Customer Account API (planned upgrade path).");
6452
- return [];
6453
- }
6454
- // ============================================
6455
- // Payment Operations
6456
- // ============================================
6457
- async getPaymentMethods(_options) {
6458
- return [];
6459
- }
6460
- // ============================================
6461
- // Inventory Operations (not available via Storefront API)
6462
- // ============================================
6463
- async getStockLocations() {
6464
- return [];
6465
- }
6466
- async checkInventoryLevels() {
6467
- return [];
6468
- }
6469
- async validateCartStock() {
6470
- return { allAvailable: true, unavailableItems: [] };
6471
- }
6472
- async getFulfillmentOptions() {
6473
- return [];
6474
- }
6475
- // ============================================
6476
- // Admin Operations (not available via Storefront API)
6477
- // ============================================
6478
- async cancelOrder(_orderId) {
6479
- throw new ProviderAPIError(
6480
- "Order cancellation requires Shopify Admin API (not available in Storefront API).",
6481
- "SHOPIFY_ADMIN_REQUIRED"
6482
- );
6483
- }
6484
- async createFulfillment(_orderId) {
6485
- throw new ProviderAPIError(
6486
- "Fulfillment requires Shopify Admin API.",
6487
- "SHOPIFY_ADMIN_REQUIRED"
6488
- );
6489
- }
6490
- async createRefund(_orderId) {
6491
- throw new ProviderAPIError(
6492
- "Refunds require Shopify Admin API.",
6493
- "SHOPIFY_ADMIN_REQUIRED"
6494
- );
6495
- }
6496
- async getAdminOrders() {
6497
- return { orders: [], count: 0 };
6498
- }
6499
- // ============================================
6500
- // Storefront / Multi-Tenant
6501
- // ============================================
6502
- async getStorefrontContext() {
6503
- return {
6504
- id: this.storeDomain,
6505
- name: this.storeDomain,
6506
- platformType: "shopify",
6507
- requiresProductScoping: false,
6508
- currencyCode: "USD"
6509
- };
6510
- }
6511
- isStorefrontRequired() {
6512
- return false;
6513
- }
6514
- };
6515
-
6516
- // src/providers/bigcommerce/transforms.ts
6517
- function transformMoney3(amount, currencyCode = "USD") {
6518
- const numAmount = typeof amount === "string" ? parseFloat(amount) : amount ?? 0;
6519
- return {
6520
- amount: numAmount.toFixed(2),
6521
- currencyCode: currencyCode.toUpperCase()
6522
- };
6523
- }
6524
- function transformImage3(url, alt = "") {
6525
- return { url, altText: alt, width: 800, height: 800 };
6526
- }
6527
- function transformProduct3(raw, currencyCode = "USD") {
6528
- const images = (raw.images ?? []).map(
6529
- (img) => transformImage3(img.url_standard ?? img.url_thumbnail ?? "", img.description ?? "")
6530
- );
6531
- const variants = (raw.variants ?? []).map((v) => ({
6532
- id: String(v.id),
6533
- title: v.option_display_name ?? `Variant ${v.id}`,
6534
- availableForSale: v.purchasing_disabled !== true,
6535
- price: transformMoney3(v.price ?? raw.price, currencyCode),
6536
- compareAtPrice: v.sale_price ? transformMoney3(v.sale_price, currencyCode) : void 0,
6537
- selectedOptions: (v.option_values ?? []).map((ov) => ({
6538
- name: ov.option_display_name ?? "",
6539
- value: ov.label ?? ""
6540
- }))
6541
- }));
6542
- const options = (raw.options ?? []).map((opt) => ({
6543
- id: String(opt.id),
6544
- name: opt.display_name ?? "",
6545
- values: (opt.option_values ?? []).map((val) => val.label ?? "")
6546
- }));
6547
- const price = raw.price ?? raw.calculated_price?.as_entered ?? 0;
6548
- return {
6549
- id: String(raw.id),
6550
- handle: raw.custom_url?.url?.replace(/^\//, "").replace(/\/$/, "") ?? String(raw.id),
6551
- title: raw.name ?? "",
6552
- description: raw.plain_text_description ?? raw.description ?? "",
6553
- descriptionHtml: raw.description ?? "",
6554
- availableForSale: raw.availability === "available" || raw.is_visible !== false,
6555
- featuredImage: images[0] ?? { url: "", altText: "", width: 800, height: 800 },
6556
- images,
6557
- options,
6558
- variants,
6559
- priceRange: {
6560
- minVariantPrice: transformMoney3(price, currencyCode),
6561
- maxVariantPrice: transformMoney3(price, currencyCode)
6562
- },
6563
- seo: {
6564
- title: raw.page_title ?? raw.name ?? "",
6565
- description: raw.meta_description ?? ""
6566
- },
6567
- tags: [],
6568
- createdAt: raw.date_created ?? (/* @__PURE__ */ new Date()).toISOString(),
6569
- updatedAt: raw.date_modified ?? (/* @__PURE__ */ new Date()).toISOString()
6570
- };
6571
- }
6572
- function transformCollection3(raw) {
6573
- return {
6574
- id: String(raw.id ?? ""),
6575
- handle: raw.custom_url?.url?.replace(/^\//, "").replace(/\/$/, "") ?? String(raw.id),
6576
- title: raw.name ?? "",
6577
- description: raw.description ?? "",
6578
- seo: {
6579
- title: raw.page_title ?? raw.name ?? "",
6580
- description: raw.meta_description ?? ""
6581
- },
6582
- updatedAt: raw.date_modified ?? (/* @__PURE__ */ new Date()).toISOString(),
6583
- path: `/collections/${raw.custom_url?.url?.replace(/^\//, "").replace(/\/$/, "") ?? raw.id}`
6584
- };
6585
- }
6586
- function transformCart3(raw, currencyCode = "USD") {
6587
- const lineItems = Object.values(raw.line_items ?? {}).flat();
6588
- const lines = lineItems.map((item) => ({
6589
- id: item.id,
6590
- quantity: item.quantity ?? 1,
6591
- cost: {
6592
- totalAmount: transformMoney3(item.extended_sale_price ?? item.sale_price ?? 0, currencyCode)
6593
- },
6594
- merchandise: {
6595
- id: String(item.variant_id ?? item.product_id),
6596
- title: item.name ?? "",
6597
- selectedOptions: (item.options ?? []).map((opt) => ({
6598
- name: opt.name ?? "",
6599
- value: opt.value ?? ""
6600
- })),
6601
- product: {
6602
- id: String(item.product_id),
6603
- handle: String(item.product_id),
6604
- title: item.name ?? "",
6605
- featuredImage: item.image_url ? transformImage3(item.image_url) : { url: "", altText: "", width: 800, height: 800 }
6606
- }
6607
- }
6608
- }));
6609
- return {
6610
- id: raw.id,
6611
- checkoutUrl: raw.redirect_urls?.checkout_url ?? "",
6612
- totalQuantity: lines.reduce((sum, l) => sum + l.quantity, 0),
6613
- cost: {
6614
- subtotalAmount: transformMoney3(raw.base_amount ?? 0, currencyCode),
6615
- totalAmount: transformMoney3(raw.cart_amount ?? 0, currencyCode)
6616
- },
6617
- lines
6618
- };
6619
- }
6620
-
6621
- // src/providers/bigcommerce/index.ts
6622
- var BigCommerceProvider = class {
6623
- name = "bigcommerce";
6624
- version = "1.0.0";
6625
- capabilities = BIGCOMMERCE_CAPABILITIES;
6626
- logger;
6627
- storefrontApiUrl;
6628
- storeHash;
6629
- channelId;
6630
- currencyCode;
6631
- headers;
6632
- constructor(config) {
6633
- this.logger = createLogger("BigCommerceProvider", config.debug);
6634
- this.storefrontApiUrl = config.storefrontApiUrl.replace(/\/$/, "");
6635
- this.storeHash = config.storeHash;
6636
- this.channelId = config.channelId;
6637
- this.currencyCode = config.currencyCode ?? "USD";
6638
- this.headers = {
6639
- "Content-Type": "application/json",
6640
- "Authorization": `Bearer ${config.storefrontApiToken}`
6641
- };
6642
- this.logger.info("Initializing BigCommerce Provider", { storeHash: this.storeHash, channelId: this.channelId });
6643
- }
6644
- async fetchApi(path, init) {
6645
- const url = `${this.storefrontApiUrl}${path}`;
6646
- const response = await fetch(url, {
6647
- ...init,
6648
- headers: { ...this.headers, ...init?.headers }
6649
- });
6650
- if (!response.ok) {
6651
- throw new ProviderAPIError(
6652
- `BigCommerce API error: ${response.status} ${response.statusText}`,
6653
- "BIGCOMMERCE_API_ERROR",
6654
- response.status
6655
- );
6656
- }
6657
- return response.json();
6658
- }
6659
- // ============================================
6660
- // Product Operations
6661
- // ============================================
6662
- async getProduct(handle) {
6663
- try {
6664
- const data = await this.fetchApi(`/api/storefront/products?include=variants,options,images&keyword=${encodeURIComponent(handle)}`);
6665
- const product = data.data?.[0];
6666
- return product ? transformProduct3(product, this.currencyCode) : void 0;
6667
- } catch {
6668
- return void 0;
6669
- }
6670
- }
6671
- async getProducts(options) {
6672
- const limit = options?.first ?? 20;
6673
- let path = `/api/storefront/products?include=variants,options,images&limit=${limit}`;
6674
- if (options?.query) path += `&keyword=${encodeURIComponent(options.query)}`;
6675
- const data = await this.fetchApi(path);
6676
- return (data.data ?? []).map((p) => transformProduct3(p, this.currencyCode));
6677
- }
6678
- async getProductRecommendations(_productId) {
6679
- return [];
6680
- }
6681
- // ============================================
6682
- // Collection Operations (BigCommerce Categories)
6683
- // ============================================
6684
- async getCollection(handle) {
6685
- try {
6686
- const data = await this.fetchApi(`/api/storefront/categories?url=/${handle}/`);
6687
- const cat = data.data?.[0];
6688
- return cat ? transformCollection3(cat) : void 0;
6689
- } catch {
6690
- return void 0;
6691
- }
6692
- }
6693
- async getCollections(options) {
6694
- const limit = options?.limit ?? 50;
6695
- const data = await this.fetchApi(`/api/storefront/categories?limit=${limit}`);
6696
- return (data.data ?? []).map(transformCollection3);
6697
- }
6698
- async getCollectionProducts(handle, options) {
6699
- const limit = options?.first ?? 20;
6700
- const data = await this.fetchApi(
6701
- `/api/storefront/products?include=variants,options,images&categories:in=${handle}&limit=${limit}`
6702
- );
6703
- return (data.data ?? []).map((p) => transformProduct3(p, this.currencyCode));
6704
- }
6705
- // ============================================
6706
- // Category Operations
6707
- // ============================================
6708
- async getCategory(idOrHandle) {
6709
- return this.getCollection(idOrHandle);
6710
- }
6711
- async getCategories(options) {
6712
- return this.getCollections(options);
6713
- }
6714
- async getCategoryProducts(handle, options) {
6715
- return this.getCollectionProducts(handle, options);
6716
- }
6717
- // ============================================
6718
- // Cart Operations
6719
- // ============================================
6720
- async createCart() {
6721
- const data = await this.fetchApi("/api/storefront/carts", {
6722
- method: "POST",
6723
- body: JSON.stringify({ line_items: [] })
6724
- });
6725
- return transformCart3(data.data ?? data, this.currencyCode);
6726
- }
6727
- async getCart(cartId) {
6728
- try {
6729
- const data = await this.fetchApi(`/api/storefront/carts/${cartId}?include=line_items.physical_items.options`);
6730
- return transformCart3(data.data ?? data, this.currencyCode);
6731
- } catch {
6732
- return void 0;
6733
- }
6734
- }
6735
- async addToCart(cartId, lines) {
6736
- const lineItems = lines.map((l) => ({
6737
- product_id: parseInt(l.merchandiseId, 10),
6738
- quantity: l.quantity
6739
- }));
6740
- const data = await this.fetchApi(`/api/storefront/carts/${cartId}/items`, {
6741
- method: "POST",
6742
- body: JSON.stringify({ line_items: lineItems })
6743
- });
6744
- return transformCart3(data.data ?? data, this.currencyCode);
6745
- }
6746
- async removeFromCart(cartId, lineIds) {
6747
- for (const lineId of lineIds) {
6748
- await this.fetchApi(`/api/storefront/carts/${cartId}/items/${lineId}`, { method: "DELETE" });
6749
- }
6750
- const cart = await this.getCart(cartId);
6751
- if (!cart) throw new ProviderAPIError("Cart not found after removal", "BIGCOMMERCE_CART_ERROR");
6752
- return cart;
6753
- }
6754
- async updateCart(cartId, lines) {
6755
- for (const line of lines) {
6756
- await this.fetchApi(`/api/storefront/carts/${cartId}/items/${line.id}`, {
6757
- method: "PUT",
6758
- body: JSON.stringify({ line_item: { quantity: line.quantity } })
6759
- });
6760
- }
6761
- const cart = await this.getCart(cartId);
6762
- if (!cart) throw new ProviderAPIError("Cart not found after update", "BIGCOMMERCE_CART_ERROR");
6763
- return cart;
6764
- }
6765
- // ============================================
6766
- // Checkout Operations (Hosted)
6767
- // ============================================
6768
- async completeCheckout(_cartId) {
6769
- throw new ProviderAPIError(
6770
- "BigCommerce uses Embedded Checkout. Redirect the buyer to cart.checkoutUrl.",
6771
- "BIGCOMMERCE_HOSTED_CHECKOUT"
6772
- );
6773
- }
6774
- async getShippingMethods(_cartId) {
6775
- return [];
6776
- }
6777
- async getRegionCountries() {
6778
- return [];
6779
- }
6780
- async addShippingMethod(_cartId, _methodId) {
6781
- throw new ProviderAPIError("BigCommerce handles shipping in Embedded Checkout.", "BIGCOMMERCE_HOSTED_CHECKOUT");
6782
- }
6783
- async initiatePaymentSession(_cartId, _providerId) {
6784
- throw new ProviderAPIError("BigCommerce handles payment in Embedded Checkout.", "BIGCOMMERCE_HOSTED_CHECKOUT");
6785
- }
6786
- async applyDiscountCode(cartId, code) {
6787
- const data = await this.fetchApi(`/api/storefront/carts/${cartId}/coupons`, {
6788
- method: "POST",
6789
- body: JSON.stringify({ coupon_code: code })
6790
- });
6791
- return transformCart3(data.data ?? data, this.currencyCode);
6792
- }
6793
- async removeDiscountCode(cartId, code) {
6794
- await this.fetchApi(`/api/storefront/carts/${cartId}/coupons/${encodeURIComponent(code)}`, { method: "DELETE" });
6795
- const cart = await this.getCart(cartId);
6796
- if (!cart) throw new ProviderAPIError("Cart not found after coupon removal", "BIGCOMMERCE_CART_ERROR");
6797
- return cart;
6798
- }
6799
- // ============================================
6800
- // Customer, Order, Payment, Inventory, Admin
6801
- // ============================================
6802
- async getOrders(_options) {
6803
- return [];
6804
- }
6805
- async getPaymentMethods(_options) {
6806
- return [];
6807
- }
6808
- async getStockLocations() {
6809
- return [];
6810
- }
6811
- async checkInventoryLevels() {
6812
- return [];
6813
- }
6814
- async validateCartStock() {
6815
- return { allAvailable: true, unavailableItems: [] };
6816
- }
6817
- async getFulfillmentOptions() {
6818
- return [];
6819
- }
6820
- async cancelOrder(_orderId) {
6821
- throw new ProviderAPIError("Order cancellation requires BigCommerce Management API.", "BIGCOMMERCE_ADMIN_REQUIRED");
6822
- }
6823
- async createFulfillment(_orderId) {
6824
- throw new ProviderAPIError("Fulfillment requires BigCommerce Management API.", "BIGCOMMERCE_ADMIN_REQUIRED");
6825
- }
6826
- async createRefund(_orderId) {
6827
- throw new ProviderAPIError("Refunds require BigCommerce Management API.", "BIGCOMMERCE_ADMIN_REQUIRED");
6828
- }
6829
- async getAdminOrders() {
6830
- return { orders: [], count: 0 };
6831
- }
6832
- async getStorefrontContext() {
6833
- return {
6834
- id: this.channelId,
6835
- name: `BigCommerce Store ${this.storeHash}`,
6836
- platformType: "bigcommerce",
6837
- requiresProductScoping: false,
6838
- currencyCode: this.currencyCode
6839
- };
6840
- }
6841
- isStorefrontRequired() {
6842
- return false;
6843
- }
6844
- };
6845
-
6846
- // src/providers/woocommerce/transforms.ts
6847
- function transformMoney4(amount, currencyCode = "USD") {
6848
- const numAmount = typeof amount === "string" ? parseFloat(amount) : amount ?? 0;
6849
- return {
6850
- amount: isNaN(numAmount) ? "0.00" : numAmount.toFixed(2),
6851
- currencyCode: currencyCode.toUpperCase()
6852
- };
6853
- }
6854
- function transformImage4(url, alt = "") {
6855
- return { url, altText: alt, width: 800, height: 800 };
6856
- }
6857
- function transformProduct4(raw, currencyCode = "USD") {
6858
- const images = (raw.images ?? []).map(
6859
- (img) => transformImage4(img.src ?? "", img.alt ?? img.name ?? "")
6860
- );
6861
- const variants = (raw.variations ?? []).map((v) => ({
6862
- id: String(v.id),
6863
- title: v.name ?? "",
6864
- availableForSale: v.in_stock !== false,
6865
- price: transformMoney4(v.prices?.price ?? v.price, currencyCode),
6866
- compareAtPrice: v.prices?.regular_price ? transformMoney4(v.prices.regular_price, currencyCode) : void 0,
6867
- selectedOptions: (v.attributes ?? []).map((attr) => ({
6868
- name: attr.name ?? "",
6869
- value: attr.value ?? ""
6870
- }))
6871
- }));
6872
- const options = (raw.attributes ?? []).filter((attr) => attr.variation === true || attr.has_options === true).map((attr) => ({
6873
- id: String(attr.id),
6874
- name: attr.name ?? "",
6875
- values: (attr.terms ?? attr.options ?? []).map(
6876
- (t) => typeof t === "string" ? t : t.name ?? t.value ?? ""
6877
- )
6878
- }));
6879
- const priceMinor = raw.prices?.price ?? "0";
6880
- const priceDecimalPlaces = raw.prices?.currency_minor_unit ?? 2;
6881
- const priceMajor = parseInt(priceMinor, 10) / Math.pow(10, priceDecimalPlaces);
6882
- return {
6883
- id: String(raw.id),
6884
- handle: raw.slug ?? String(raw.id),
6885
- title: raw.name ?? "",
6886
- description: raw.short_description ?? raw.description ?? "",
6887
- descriptionHtml: raw.description ?? "",
6888
- availableForSale: raw.is_purchasable !== false && raw.is_in_stock !== false,
6889
- featuredImage: images[0] ?? { url: "", altText: "", width: 800, height: 800 },
6890
- images,
6891
- options,
6892
- variants,
6893
- priceRange: {
6894
- minVariantPrice: transformMoney4(priceMajor, currencyCode),
6895
- maxVariantPrice: transformMoney4(priceMajor, currencyCode)
6896
- },
6897
- seo: {
6898
- title: raw.name ?? "",
6899
- description: raw.short_description?.replace(/<[^>]*>/g, "") ?? ""
6900
- },
6901
- tags: [],
6902
- createdAt: raw.date_created ?? (/* @__PURE__ */ new Date()).toISOString(),
6903
- updatedAt: raw.date_modified ?? (/* @__PURE__ */ new Date()).toISOString()
6904
- };
6905
- }
6906
- function transformCollection4(raw) {
6907
- return {
6908
- id: String(raw.id ?? ""),
6909
- handle: raw.slug ?? String(raw.id),
6910
- title: raw.name ?? "",
6911
- description: raw.description ?? "",
6912
- seo: {
6913
- title: raw.name ?? "",
6914
- description: raw.description?.replace(/<[^>]*>/g, "") ?? ""
6915
- },
6916
- updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
6917
- path: `/collections/${raw.slug ?? raw.id}`
6918
- };
6919
- }
6920
- function transformCart4(raw, currencyCode = "USD") {
6921
- const lines = (raw.items ?? []).map((item) => {
6922
- const minorUnit2 = item.prices?.currency_minor_unit ?? 2;
6923
- const divisor2 = Math.pow(10, minorUnit2);
6924
- const lineTotal = parseInt(item.totals?.line_total ?? "0", 10) / divisor2;
6925
- return {
6926
- id: item.key ?? String(item.id),
6927
- quantity: item.quantity ?? 1,
6928
- cost: {
6929
- totalAmount: transformMoney4(lineTotal, currencyCode)
6930
- },
6931
- merchandise: {
6932
- id: String(item.id),
6933
- title: item.name ?? "",
6934
- selectedOptions: (item.variation ?? []).map((v) => ({
6935
- name: v.attribute ?? "",
6936
- value: v.value ?? ""
6937
- })),
6938
- product: {
6939
- id: String(item.id),
6940
- handle: item.slug ?? String(item.id),
6941
- title: item.name ?? "",
6942
- featuredImage: item.images?.[0] ? transformImage4(item.images[0].src, item.images[0].alt ?? "") : { url: "", altText: "", width: 800, height: 800 }
6943
- }
6944
- }
6945
- };
6946
- });
6947
- const minorUnit = raw.totals?.currency_minor_unit ?? 2;
6948
- const divisor = Math.pow(10, minorUnit);
6949
- const subtotal = parseInt(raw.totals?.total_items ?? "0", 10) / divisor;
6950
- const total = parseInt(raw.totals?.total_price ?? "0", 10) / divisor;
6951
- return {
6952
- id: raw.cart_key ?? void 0,
6953
- checkoutUrl: "",
6954
- // WooCommerce handles checkout via its own /checkout page
6955
- totalQuantity: raw.items_count ?? lines.reduce((sum, l) => sum + l.quantity, 0),
6956
- cost: {
6957
- subtotalAmount: transformMoney4(subtotal, currencyCode),
6958
- totalAmount: transformMoney4(total, currencyCode)
6959
- },
6960
- lines
6961
- };
6962
- }
6963
- function transformWooAddress(raw) {
6964
- return {
6965
- id: void 0,
6966
- firstName: raw.first_name ?? "",
6967
- lastName: raw.last_name ?? "",
6968
- address1: raw.address_1 ?? "",
6969
- address2: raw.address_2 ?? "",
6970
- city: raw.city ?? "",
6971
- province: raw.state ?? "",
6972
- countryCode: raw.country ?? "",
6973
- postalCode: raw.postcode ?? "",
6974
- phone: raw.phone ?? "",
6975
- company: raw.company ?? ""
6976
- };
6977
- }
6978
- function transformOrder4(raw, currencyCode = "USD") {
6979
- const items = (raw.line_items ?? []).map((item) => ({
6980
- id: String(item.id),
6981
- title: item.name ?? "",
6982
- quantity: item.quantity ?? 1,
6983
- price: transformMoney4(item.price ?? 0, currencyCode),
6984
- total: transformMoney4(item.total ?? 0, currencyCode),
6985
- productId: String(item.product_id),
6986
- variantId: item.variation_id ? String(item.variation_id) : void 0
6987
- }));
6988
- const statusMap = {
6989
- pending: "pending",
6990
- processing: "processing",
6991
- "on-hold": "pending",
6992
- completed: "completed",
6993
- cancelled: "cancelled",
6994
- refunded: "refunded",
6995
- failed: "cancelled"
6996
- };
6997
- const paymentMap = {
6998
- pending: "pending",
6999
- processing: "authorized",
7000
- completed: "paid",
7001
- refunded: "refunded"
7002
- };
7003
- return {
7004
- id: String(raw.id),
7005
- orderNumber: String(raw.number ?? raw.id),
7006
- email: raw.billing?.email ?? "",
7007
- status: statusMap[raw.status] ?? "pending",
7008
- paymentStatus: paymentMap[raw.status] ?? "pending",
7009
- fulfillmentStatus: raw.status === "completed" ? "fulfilled" : "unfulfilled",
7010
- items,
7011
- total: transformMoney4(raw.total ?? 0, currencyCode),
7012
- subtotal: transformMoney4(raw.subtotal ?? 0, currencyCode),
7013
- tax: transformMoney4(raw.total_tax ?? 0, currencyCode),
7014
- shipping: transformMoney4(raw.shipping_total ?? 0, currencyCode),
7015
- shippingAddress: raw.shipping ? transformWooAddress(raw.shipping) : void 0,
7016
- billingAddress: raw.billing ? transformWooAddress(raw.billing) : void 0,
7017
- createdAt: raw.date_created ?? (/* @__PURE__ */ new Date()).toISOString(),
7018
- updatedAt: raw.date_modified ?? (/* @__PURE__ */ new Date()).toISOString()
7019
- };
7020
- }
7021
-
7022
- // src/providers/woocommerce/index.ts
7023
- var WooCommerceProvider = class {
7024
- name = "woocommerce";
7025
- version = "1.0.0";
7026
- capabilities = WOOCOMMERCE_CAPABILITIES;
7027
- logger;
7028
- baseUrl;
7029
- storeApiBase;
7030
- restApiBase;
7031
- currencyCode;
7032
- authHeader;
7033
- constructor(config) {
7034
- this.logger = createLogger("WooCommerceProvider", config.debug);
7035
- this.baseUrl = config.url.replace(/\/$/, "");
7036
- this.storeApiBase = `${this.baseUrl}/wp-json/wc/store/v1`;
7037
- this.restApiBase = `${this.baseUrl}/wp-json/wc/v3`;
7038
- this.currencyCode = config.currencyCode ?? "USD";
7039
- if (config.consumerKey && config.consumerSecret) {
7040
- this.authHeader = "Basic " + btoa(`${config.consumerKey}:${config.consumerSecret}`);
7041
- }
7042
- this.logger.info("Initializing WooCommerce Provider", { baseUrl: this.baseUrl });
7043
- }
7044
- async storeApiFetch(path, init) {
7045
- const response = await fetch(`${this.storeApiBase}${path}`, {
7046
- ...init,
7047
- headers: { "Content-Type": "application/json", ...init?.headers }
7048
- });
7049
- if (!response.ok) {
7050
- throw new ProviderAPIError(`WooCommerce Store API error: ${response.status}`, "WOOCOMMERCE_API_ERROR", response.status);
7051
- }
7052
- return response.json();
7053
- }
7054
- async restApiFetch(path, init) {
7055
- if (!this.authHeader) {
7056
- throw new ProviderAPIError("WooCommerce REST API requires consumer key/secret.", "WOOCOMMERCE_AUTH_REQUIRED");
7057
- }
7058
- const response = await fetch(`${this.restApiBase}${path}`, {
7059
- ...init,
7060
- headers: { "Content-Type": "application/json", "Authorization": this.authHeader, ...init?.headers }
7061
- });
7062
- if (!response.ok) {
7063
- throw new ProviderAPIError(`WooCommerce REST API error: ${response.status}`, "WOOCOMMERCE_API_ERROR", response.status);
7064
- }
7065
- return response.json();
7066
- }
7067
- // ============================================
7068
- // Product Operations (Store API)
7069
- // ============================================
7070
- async getProduct(handle) {
7071
- try {
7072
- const products = await this.storeApiFetch(`/products?slug=${encodeURIComponent(handle)}`);
7073
- return products[0] ? transformProduct4(products[0], this.currencyCode) : void 0;
7074
- } catch {
7075
- return void 0;
7076
- }
7077
- }
7078
- async getProducts(options) {
7079
- let path = `/products?per_page=${options?.first ?? 20}`;
7080
- if (options?.query) path += `&search=${encodeURIComponent(options.query)}`;
7081
- if (options?.sortKey) {
7082
- const [orderby, order] = options.sortKey.includes("-desc") ? [options.sortKey.replace("-desc", ""), "desc"] : [options.sortKey.replace("-asc", ""), "asc"];
7083
- path += `&orderby=${orderby}&order=${order}`;
7084
- }
7085
- const products = await this.storeApiFetch(path);
7086
- return products.map((p) => transformProduct4(p, this.currencyCode));
7087
- }
7088
- async getProductRecommendations(_productId) {
7089
- return [];
7090
- }
7091
- // ============================================
7092
- // Collection/Category Operations (Store API)
7093
- // ============================================
7094
- async getCollection(handle) {
7095
- try {
7096
- const cats = await this.storeApiFetch(`/products/categories?slug=${encodeURIComponent(handle)}`);
7097
- return cats[0] ? transformCollection4(cats[0]) : void 0;
7098
- } catch {
7099
- return void 0;
7100
- }
7101
- }
7102
- async getCollections(options) {
7103
- const cats = await this.storeApiFetch(`/products/categories?per_page=${options?.limit ?? 50}`);
7104
- return cats.map(transformCollection4);
7105
- }
7106
- async getCollectionProducts(handle, options) {
7107
- const products = await this.storeApiFetch(
7108
- `/products?category=${encodeURIComponent(handle)}&per_page=${options?.first ?? 20}`
7109
- );
7110
- return products.map((p) => transformProduct4(p, this.currencyCode));
7111
- }
7112
- async getCategory(idOrHandle) {
7113
- return this.getCollection(idOrHandle);
7114
- }
7115
- async getCategories(options) {
7116
- return this.getCollections(options);
7117
- }
7118
- async getCategoryProducts(handle, options) {
7119
- return this.getCollectionProducts(handle, options);
7120
- }
7121
- // ============================================
7122
- // Cart Operations (Store API)
7123
- // ============================================
7124
- async createCart() {
7125
- const cart = await this.storeApiFetch("/cart");
7126
- return transformCart4(cart, this.currencyCode);
7127
- }
7128
- async getCart(_cartId) {
7129
- try {
7130
- const cart = await this.storeApiFetch("/cart");
7131
- return transformCart4(cart, this.currencyCode);
7132
- } catch {
7133
- return void 0;
7134
- }
7135
- }
7136
- async addToCart(_cartId, lines) {
7137
- for (const line of lines) {
7138
- await this.storeApiFetch("/cart/add-item", {
7139
- method: "POST",
7140
- body: JSON.stringify({ id: parseInt(line.merchandiseId, 10), quantity: line.quantity })
7141
- });
7142
- }
7143
- const cart = await this.storeApiFetch("/cart");
7144
- return transformCart4(cart, this.currencyCode);
7145
- }
7146
- async removeFromCart(_cartId, lineIds) {
7147
- for (const key of lineIds) {
7148
- await this.storeApiFetch("/cart/remove-item", {
7149
- method: "POST",
7150
- body: JSON.stringify({ key })
7151
- });
7152
- }
7153
- const cart = await this.storeApiFetch("/cart");
7154
- return transformCart4(cart, this.currencyCode);
7155
- }
7156
- async updateCart(_cartId, lines) {
7157
- for (const line of lines) {
7158
- await this.storeApiFetch("/cart/update-item", {
7159
- method: "POST",
7160
- body: JSON.stringify({ key: line.id, quantity: line.quantity })
7161
- });
7162
- }
7163
- const cart = await this.storeApiFetch("/cart");
7164
- return transformCart4(cart, this.currencyCode);
7165
- }
7166
- // ============================================
7167
- // Checkout Operations (Store API)
7168
- // ============================================
7169
- async completeCheckout(_cartId) {
7170
- const result = await this.storeApiFetch("/checkout", { method: "POST", body: JSON.stringify({}) });
7171
- return transformOrder4(result, this.currencyCode);
7172
- }
7173
- async getShippingMethods(_cartId) {
7174
- return [];
7175
- }
7176
- async getRegionCountries() {
7177
- return [];
7178
- }
7179
- async addShippingMethod(_cartId, methodId) {
7180
- await this.storeApiFetch("/cart/select-shipping-rate", {
7181
- method: "POST",
7182
- body: JSON.stringify({ rate_id: methodId })
7183
- });
7184
- const cart = await this.storeApiFetch("/cart");
7185
- return transformCart4(cart, this.currencyCode);
7186
- }
7187
- async initiatePaymentSession(_cartId, _providerId) {
7188
- }
7189
- async applyDiscountCode(_cartId, code) {
7190
- await this.storeApiFetch("/cart/apply-coupon", {
7191
- method: "POST",
7192
- body: JSON.stringify({ code })
7193
- });
7194
- const cart = await this.storeApiFetch("/cart");
7195
- return transformCart4(cart, this.currencyCode);
7196
- }
7197
- async removeDiscountCode(_cartId, code) {
7198
- await this.storeApiFetch("/cart/remove-coupon", {
7199
- method: "POST",
7200
- body: JSON.stringify({ code })
7201
- });
7202
- const cart = await this.storeApiFetch("/cart");
7203
- return transformCart4(cart, this.currencyCode);
7204
- }
7205
- // ============================================
7206
- // Customer, Order, Payment, Inventory, Admin
7207
- // ============================================
7208
- async getOrders(_options) {
7209
- return [];
7210
- }
7211
- async getPaymentMethods(_options) {
7212
- return [];
7213
- }
7214
- async getStockLocations() {
7215
- return [];
7216
- }
7217
- async checkInventoryLevels() {
7218
- return [];
7219
- }
7220
- async validateCartStock() {
7221
- return { allAvailable: true, unavailableItems: [] };
7222
- }
7223
- async getFulfillmentOptions() {
7224
- return [];
7225
- }
7226
- async cancelOrder(_orderId) {
7227
- throw new ProviderAPIError("Order cancellation requires WooCommerce REST API v3.", "WOOCOMMERCE_AUTH_REQUIRED");
7228
- }
7229
- async createFulfillment(_orderId) {
7230
- throw new ProviderAPIError("Fulfillment requires WooCommerce REST API v3.", "WOOCOMMERCE_AUTH_REQUIRED");
7231
- }
7232
- async createRefund(_orderId) {
7233
- throw new ProviderAPIError("Refunds require WooCommerce REST API v3.", "WOOCOMMERCE_AUTH_REQUIRED");
7234
- }
7235
- async getAdminOrders() {
7236
- return { orders: [], count: 0 };
7237
- }
7238
- async getStorefrontContext() {
7239
- return {
7240
- id: this.baseUrl,
7241
- name: `WooCommerce ${this.baseUrl}`,
7242
- platformType: "woocommerce",
7243
- requiresProductScoping: false,
7244
- currencyCode: this.currencyCode
7245
- };
7246
- }
7247
- isStorefrontRequired() {
7248
- return false;
7249
- }
7250
- };
7251
-
7252
- // src/providers/spree/transforms.ts
7253
- function toMoney(amount, currencyCode) {
7254
- const num = typeof amount === "string" ? parseFloat(amount) || 0 : amount;
7255
- return { amount: num.toFixed(2), currencyCode };
7256
- }
7257
- function transformProduct5(data, included = [], currencyCode = "USD") {
7258
- const attrs = data.attributes ?? data;
7259
- const id = String(data.id ?? "");
7260
- const images = [];
7261
- const imageRels = data.relationships?.images?.data ?? [];
7262
- for (const imgRef of imageRels) {
7263
- const imgIncluded = included.find((i) => i.type === "image" && String(i.id) === String(imgRef.id));
7264
- if (imgIncluded) {
7265
- images.push({
7266
- url: imgIncluded.attributes?.original_url ?? imgIncluded.attributes?.styles?.[0]?.url ?? "",
7267
- altText: imgIncluded.attributes?.alt ?? attrs.name ?? "",
7268
- width: void 0,
7269
- height: void 0
7270
- });
7271
- }
7272
- }
7273
- if (images.length === 0 && Array.isArray(attrs.images)) {
7274
- for (const img of attrs.images) {
7275
- images.push({
7276
- url: img.original_url ?? img.url ?? "",
7277
- altText: img.alt ?? attrs.name ?? "",
7278
- width: void 0,
7279
- height: void 0
7280
- });
7281
- }
7282
- }
7283
- const variants = [];
7284
- const variantRels = data.relationships?.variants?.data ?? [];
7285
- for (const varRef of variantRels) {
7286
- const varIncluded = included.find((i) => i.type === "variant" && String(i.id) === String(varRef.id));
7287
- if (varIncluded) {
7288
- const vAttrs = varIncluded.attributes ?? {};
7289
- variants.push({
7290
- id: String(varIncluded.id),
7291
- title: vAttrs.name ?? vAttrs.sku ?? `Variant ${varIncluded.id}`,
7292
- availableForSale: vAttrs.in_stock !== false && vAttrs.purchasable !== false,
7293
- price: toMoney(vAttrs.price ?? vAttrs.display_price ?? "0", currencyCode),
7294
- compareAtPrice: vAttrs.compare_at_price ? toMoney(vAttrs.compare_at_price, currencyCode) : void 0,
7295
- selectedOptions: (vAttrs.option_values ?? []).map((ov) => ({
7296
- name: ov.option_type_name ?? "Option",
7297
- value: ov.name ?? ov.presentation ?? ""
7298
- }))
7299
- });
7300
- }
7301
- }
7302
- if (variants.length === 0) {
7303
- variants.push({
7304
- id: attrs.default_variant_id ? String(attrs.default_variant_id) : id,
7305
- title: "Default",
7306
- availableForSale: attrs.in_stock !== false && attrs.purchasable !== false,
7307
- price: toMoney(attrs.price ?? attrs.display_price ?? "0", currencyCode),
7308
- compareAtPrice: attrs.compare_at_price ? toMoney(attrs.compare_at_price, currencyCode) : void 0,
7309
- selectedOptions: []
7310
- });
7311
- }
7312
- const options = (attrs.option_types ?? []).map((ot) => ({
7313
- id: String(ot.id ?? ot.name ?? ""),
7314
- name: ot.presentation ?? ot.name ?? "",
7315
- values: (ot.option_values ?? []).map((ov) => ov.presentation ?? ov.name ?? "")
7316
- }));
7317
- return {
7318
- id,
7319
- handle: attrs.slug ?? id,
7320
- title: attrs.name ?? "",
7321
- description: attrs.description ?? "",
7322
- descriptionHtml: attrs.description ?? "",
7323
- availableForSale: attrs.in_stock !== false && attrs.purchasable !== false,
7324
- priceRange: {
7325
- minVariantPrice: variants.reduce(
7326
- (min, v) => v.price.amount < min.amount ? v.price : min,
7327
- variants[0]?.price ?? toMoney("0", currencyCode)
7328
- ),
7329
- maxVariantPrice: variants.reduce(
7330
- (max, v) => v.price.amount > max.amount ? v.price : max,
7331
- variants[0]?.price ?? toMoney("0", currencyCode)
7332
- )
7333
- },
7334
- variants,
7335
- options,
7336
- images,
7337
- featuredImage: images[0] ?? { url: "", altText: attrs.name ?? "" },
7338
- tags: [],
7339
- seo: {
7340
- title: attrs.meta_title ?? attrs.name ?? "",
7341
- description: attrs.meta_description ?? ""
7342
- },
7343
- updatedAt: attrs.updated_at ?? (/* @__PURE__ */ new Date()).toISOString(),
7344
- createdAt: attrs.created_at ?? (/* @__PURE__ */ new Date()).toISOString()
7345
- };
7346
- }
7347
- function transformCollection5(data) {
7348
- const attrs = data.attributes ?? data;
7349
- return {
7350
- id: String(data.id ?? ""),
7351
- handle: attrs.permalink ?? attrs.slug ?? String(data.id ?? ""),
7352
- title: attrs.name ?? "",
7353
- description: attrs.description ?? "",
7354
- seo: {
7355
- title: attrs.meta_title ?? attrs.name ?? "",
7356
- description: attrs.meta_description ?? ""
7357
- },
7358
- updatedAt: attrs.updated_at ?? (/* @__PURE__ */ new Date()).toISOString(),
7359
- path: `/collections/${attrs.permalink ?? attrs.slug ?? data.id}`
7360
- };
7361
- }
7362
- function transformCart5(data, currencyCode = "USD") {
7363
- const attrs = data.attributes ?? data;
7364
- const items = (attrs.line_items ?? data.included?.filter((i) => i.type === "line_item") ?? []).map(
7365
- (item) => {
7366
- const itemAttrs = item.attributes ?? item;
7367
- return {
7368
- id: String(item.id ?? itemAttrs.id ?? ""),
7369
- quantity: itemAttrs.quantity ?? 1,
7370
- cost: {
7371
- totalAmount: toMoney(itemAttrs.total ?? itemAttrs.display_total ?? "0", currencyCode)
7372
- },
7373
- merchandise: {
7374
- id: String(itemAttrs.variant_id ?? item.id ?? ""),
7375
- title: itemAttrs.name ?? "",
7376
- selectedOptions: [],
7377
- product: {
7378
- id: String(itemAttrs.product_id ?? ""),
7379
- handle: itemAttrs.slug ?? "",
7380
- title: itemAttrs.name ?? "",
7381
- featuredImage: { url: itemAttrs.image_url ?? "", altText: itemAttrs.name ?? "" }
7382
- }
7383
- }
7384
- };
7385
- }
7386
- );
7387
- return {
7388
- id: String(data.id ?? attrs.token ?? ""),
7389
- checkoutUrl: "",
7390
- totalQuantity: items.reduce((sum, i) => sum + i.quantity, 0),
7391
- cost: {
7392
- subtotalAmount: toMoney(attrs.item_total ?? attrs.display_item_total ?? "0", currencyCode),
7393
- totalAmount: toMoney(attrs.total ?? attrs.display_total ?? "0", currencyCode),
7394
- totalTaxAmount: toMoney(attrs.tax_total ?? attrs.display_tax_total ?? "0", currencyCode)
7395
- },
7396
- lines: items
7397
- };
7398
- }
7399
- function transformAddress2(addr) {
7400
- return {
7401
- id: String(addr.id ?? ""),
7402
- firstName: addr.first_name ?? addr.firstname ?? "",
7403
- lastName: addr.last_name ?? addr.lastname ?? "",
7404
- company: addr.company ?? "",
7405
- address1: addr.address1 ?? "",
7406
- address2: addr.address2 ?? "",
7407
- city: addr.city ?? "",
7408
- province: addr.state_name ?? addr.state ?? "",
7409
- postalCode: addr.zipcode ?? addr.zip ?? "",
7410
- countryCode: addr.country_iso ?? addr.country_code ?? "",
7411
- phone: addr.phone ?? ""
7412
- };
7413
- }
7414
- function transformOrder5(data, currencyCode = "USD") {
7415
- const attrs = data.attributes ?? data;
7416
- const items = (attrs.line_items ?? []).map((item) => ({
7417
- id: String(item.id ?? ""),
7418
- title: item.name ?? "",
7419
- quantity: item.quantity ?? 1,
7420
- price: toMoney(item.price ?? "0", currencyCode),
7421
- total: toMoney(item.total ?? "0", currencyCode),
7422
- productId: String(item.product_id ?? ""),
7423
- variantId: String(item.variant_id ?? "")
7424
- }));
7425
- return {
7426
- id: String(data.id ?? attrs.number ?? ""),
7427
- orderNumber: attrs.number ?? String(data.id ?? ""),
7428
- email: attrs.email ?? "",
7429
- status: attrs.state === "complete" ? "completed" : attrs.state === "canceled" ? "cancelled" : "pending",
7430
- paymentStatus: attrs.payment_state === "paid" ? "paid" : attrs.payment_state === "balance_due" ? "pending" : "pending",
7431
- fulfillmentStatus: attrs.shipment_state === "shipped" ? "fulfilled" : attrs.shipment_state === "partial" ? "partially_fulfilled" : "unfulfilled",
7432
- items,
7433
- total: toMoney(attrs.total ?? "0", currencyCode),
7434
- subtotal: toMoney(attrs.item_total ?? "0", currencyCode),
7435
- tax: toMoney(attrs.tax_total ?? "0", currencyCode),
7436
- shipping: toMoney(attrs.ship_total ?? "0", currencyCode),
7437
- shippingAddress: attrs.ship_address ? transformAddress2(attrs.ship_address) : void 0,
7438
- billingAddress: attrs.bill_address ? transformAddress2(attrs.bill_address) : void 0,
7439
- createdAt: attrs.created_at ?? (/* @__PURE__ */ new Date()).toISOString(),
7440
- updatedAt: attrs.updated_at ?? (/* @__PURE__ */ new Date()).toISOString()
7441
- };
7442
- }
7443
-
7444
- // src/providers/spree/index.ts
7445
- var SpreeProvider = class {
7446
- name = "spree";
7447
- version = "1.0.0";
7448
- capabilities = SPREE_CAPABILITIES;
7449
- logger;
7450
- baseUrl;
7451
- apiBase;
7452
- currencyCode;
7453
- bearerToken;
7454
- orderToken;
7455
- // guest cart token
7456
- constructor(config) {
7457
- this.logger = createLogger("SpreeProvider", config.debug);
7458
- this.baseUrl = config.baseUrl.replace(/\/$/, "");
7459
- this.apiBase = `${this.baseUrl}/api/v2/storefront`;
7460
- this.currencyCode = config.currencyCode ?? "USD";
7461
- this.bearerToken = config.bearerToken;
7462
- this.logger.info("Initializing Spree Provider", { baseUrl: this.baseUrl });
7463
- }
7464
- async apiFetch(path, init) {
7465
- const headers = {
7466
- "Content-Type": "application/vnd.api+json",
7467
- "Accept": "application/vnd.api+json",
7468
- ...init?.headers ?? {}
7469
- };
7470
- if (this.bearerToken) {
7471
- headers["Authorization"] = `Bearer ${this.bearerToken}`;
7472
- }
7473
- if (this.orderToken) {
7474
- headers["X-Spree-Order-Token"] = this.orderToken;
7475
- }
7476
- const response = await fetch(`${this.apiBase}${path}`, {
7477
- ...init,
7478
- headers
7479
- });
7480
- if (!response.ok) {
7481
- throw new ProviderAPIError(
7482
- `Spree API error: ${response.status}`,
7483
- "SPREE_API_ERROR",
7484
- response.status
7485
- );
7486
- }
7487
- return response.json();
7488
- }
7489
- // ============================================
7490
- // Product Operations
7491
- // ============================================
7492
- async getProduct(handle) {
7493
- try {
7494
- const { data, included } = await this.apiFetch(
7495
- `/products/${encodeURIComponent(handle)}?include=images,variants,option_types`
7496
- );
7497
- return transformProduct5(data, included ?? [], this.currencyCode);
7498
- } catch {
7499
- return void 0;
7500
- }
7501
- }
7502
- async getProducts(options) {
7503
- let path = `/products?include=images,variants&per_page=${options?.first ?? 20}`;
7504
- if (options?.query) path += `&filter[name]=${encodeURIComponent(options.query)}`;
7505
- if (options?.sortKey) {
7506
- const sortMap = {
7507
- "price-asc": "price",
7508
- "price-desc": "-price",
7509
- "title-asc": "name",
7510
- "title-desc": "-name",
7511
- "created-desc": "-created_at"
7512
- };
7513
- if (sortMap[options.sortKey]) path += `&sort=${sortMap[options.sortKey]}`;
7514
- }
7515
- const { data, included } = await this.apiFetch(path);
7516
- return (Array.isArray(data) ? data : []).map((p) => transformProduct5(p, included ?? [], this.currencyCode));
7517
- }
7518
- async getProductRecommendations(_productId) {
7519
- return [];
7520
- }
7521
- // ============================================
7522
- // Collection/Taxon Operations
7523
- // ============================================
7524
- async getCollection(handle) {
7525
- try {
7526
- const { data } = await this.apiFetch(`/taxons/${encodeURIComponent(handle)}`);
7527
- return transformCollection5(data);
7528
- } catch {
7529
- return void 0;
7530
- }
7531
- }
7532
- async getCollections(options) {
7533
- const { data } = await this.apiFetch(`/taxons?per_page=${options?.limit ?? 50}`);
7534
- return (Array.isArray(data) ? data : []).map(transformCollection5);
7535
- }
7536
- async getCollectionProducts(handle, options) {
7537
- const { data, included } = await this.apiFetch(
7538
- `/products?include=images,variants&filter[taxons]=${encodeURIComponent(handle)}&per_page=${options?.first ?? 20}`
7539
- );
7540
- return (Array.isArray(data) ? data : []).map((p) => transformProduct5(p, included ?? [], this.currencyCode));
7541
- }
7542
- async getCategory(handle) {
7543
- return this.getCollection(handle);
7544
- }
7545
- async getCategories(options) {
7546
- return this.getCollections(options);
7547
- }
7548
- async getCategoryProducts(handle, options) {
7549
- return this.getCollectionProducts(handle, options);
7550
- }
7551
- // ============================================
7552
- // Cart Operations
7553
- // ============================================
7554
- async createCart() {
7555
- const { data } = await this.apiFetch("/cart", {
7556
- method: "POST",
7557
- body: JSON.stringify({})
7558
- });
7559
- if (data.attributes?.token) {
7560
- this.orderToken = data.attributes.token;
7561
- }
7562
- return transformCart5(data, this.currencyCode);
7563
- }
7564
- async getCart(_cartId) {
7565
- try {
7566
- const { data } = await this.apiFetch("/cart?include=line_items");
7567
- return transformCart5(data, this.currencyCode);
7568
- } catch {
7569
- return void 0;
7570
- }
7571
- }
7572
- async addToCart(_cartId, lines) {
7573
- for (const line of lines) {
7574
- await this.apiFetch("/cart/add_item", {
7575
- method: "POST",
7576
- body: JSON.stringify({ variant_id: line.merchandiseId, quantity: line.quantity })
7577
- });
7578
- }
7579
- const { data } = await this.apiFetch("/cart?include=line_items");
7580
- return transformCart5(data, this.currencyCode);
7581
- }
7582
- async removeFromCart(_cartId, lineIds) {
7583
- for (const id of lineIds) {
7584
- await this.apiFetch(`/cart/remove_line_item/${id}`, { method: "DELETE" });
7585
- }
7586
- const { data } = await this.apiFetch("/cart?include=line_items");
7587
- return transformCart5(data, this.currencyCode);
7588
- }
7589
- async updateCart(_cartId, lines) {
7590
- for (const line of lines) {
7591
- await this.apiFetch(`/cart/set_quantity`, {
7592
- method: "PATCH",
7593
- body: JSON.stringify({ line_item_id: line.id, quantity: line.quantity })
7594
- });
7595
- }
7596
- const { data } = await this.apiFetch("/cart?include=line_items");
7597
- return transformCart5(data, this.currencyCode);
7598
- }
7599
- // ============================================
7600
- // Checkout Operations
7601
- // ============================================
7602
- async completeCheckout(_cartId) {
7603
- const { data } = await this.apiFetch("/checkout/complete", { method: "PATCH" });
7604
- return transformOrder5(data, this.currencyCode);
7605
- }
7606
- async getShippingMethods(_cartId) {
7607
- try {
7608
- const { data } = await this.apiFetch("/checkout/shipping_rates");
7609
- return (Array.isArray(data) ? data : []).map((rate) => ({
7610
- id: String(rate.id),
7611
- name: rate.attributes?.name ?? rate.name ?? "",
7612
- price: { amount: String(parseFloat(rate.attributes?.final_price ?? rate.attributes?.cost ?? "0").toFixed(2)), currencyCode: this.currencyCode }
7613
- }));
7614
- } catch {
7615
- return [];
7616
- }
7617
- }
7618
- async getRegionCountries() {
7619
- return [];
7620
- }
7621
- async addShippingMethod(_cartId, methodId) {
7622
- await this.apiFetch("/checkout", {
7623
- method: "PATCH",
7624
- body: JSON.stringify({ order: { shipments_attributes: [{ selected_shipping_rate_id: methodId }] } })
7625
- });
7626
- const { data } = await this.apiFetch("/cart?include=line_items");
7627
- return transformCart5(data, this.currencyCode);
7628
- }
7629
- async initiatePaymentSession(_cartId, _providerId) {
7630
- }
7631
- async applyDiscountCode(_cartId, code) {
7632
- await this.apiFetch("/cart/apply_coupon_code", {
7633
- method: "PATCH",
7634
- body: JSON.stringify({ coupon_code: code })
7635
- });
7636
- const { data } = await this.apiFetch("/cart?include=line_items");
7637
- return transformCart5(data, this.currencyCode);
7638
- }
7639
- async removeDiscountCode(_cartId, code) {
7640
- await this.apiFetch(`/cart/remove_coupon_code/${encodeURIComponent(code)}`, { method: "DELETE" });
7641
- const { data } = await this.apiFetch("/cart?include=line_items");
7642
- return transformCart5(data, this.currencyCode);
7643
- }
7644
- // ============================================
7645
- // Customer, Order, Payment, Inventory, Admin
7646
- // ============================================
7647
- async getOrders(_options) {
7648
- try {
7649
- const { data } = await this.apiFetch("/account/orders");
7650
- return (Array.isArray(data) ? data : []).map((o) => transformOrder5(o, this.currencyCode));
7651
- } catch {
7652
- return [];
7653
- }
7654
- }
7655
- async getPaymentMethods(_options) {
7656
- try {
7657
- const { data } = await this.apiFetch("/checkout/payment_methods");
7658
- return (Array.isArray(data) ? data : []).map((pm) => ({
7659
- id: String(pm.id),
7660
- name: pm.attributes?.name ?? "",
7661
- type: "other",
7662
- isEnabled: true,
7663
- requiresSetup: false
7664
- }));
7665
- } catch {
7666
- return [];
7667
- }
7668
- }
7669
- async getStockLocations() {
7670
- return [];
7671
- }
7672
- async checkInventoryLevels() {
7673
- return [];
7674
- }
7675
- async validateCartStock() {
7676
- return { allAvailable: true, unavailableItems: [] };
7677
- }
7678
- async getFulfillmentOptions() {
7679
- return [];
7680
- }
7681
- async cancelOrder(_orderId) {
7682
- throw new ProviderAPIError("Order cancellation requires Spree Admin API.", "SPREE_ADMIN_REQUIRED");
7683
- }
7684
- async createFulfillment(_orderId) {
7685
- throw new ProviderAPIError("Fulfillment requires Spree Admin API.", "SPREE_ADMIN_REQUIRED");
7686
- }
7687
- async createRefund(_orderId) {
7688
- throw new ProviderAPIError("Refunds require Spree Admin API.", "SPREE_ADMIN_REQUIRED");
7689
- }
7690
- async getAdminOrders() {
7691
- return { orders: [], count: 0 };
7692
- }
7693
- async getStorefrontContext() {
7694
- return {
7695
- id: this.baseUrl,
7696
- name: `Spree ${this.baseUrl}`,
7697
- platformType: "spree",
7698
- requiresProductScoping: true,
7699
- currencyCode: this.currencyCode
7700
- };
7701
- }
7702
- isStorefrontRequired() {
7703
- return true;
7704
- }
7705
- };
7706
-
7707
- // src/providers/magento/transforms.ts
7708
- function toMoney2(value, currencyCode) {
7709
- return { amount: (value ?? 0).toFixed(2), currencyCode };
7710
- }
7711
- function extractPrice(priceRange, currencyCode) {
7712
- const minPrice = priceRange?.minimum_price?.regular_price?.value ?? priceRange?.minimum_price?.final_price?.value ?? 0;
7713
- const maxPrice = priceRange?.maximum_price?.regular_price?.value ?? priceRange?.maximum_price?.final_price?.value ?? minPrice;
7714
- const currency = priceRange?.minimum_price?.regular_price?.currency ?? currencyCode;
7715
- return {
7716
- min: toMoney2(minPrice, currency),
7717
- max: toMoney2(maxPrice, currency)
7718
- };
7719
- }
7720
- function transformProduct6(data, currencyCode = "USD") {
7721
- const id = String(data.id ?? data.uid ?? "");
7722
- const { min, max } = extractPrice(data.price_range, currencyCode);
7723
- const images = (data.media_gallery ?? data.media_gallery_entries ?? []).map((img) => ({
7724
- url: img.url ?? (img.file ? `${img.file}` : ""),
7725
- altText: img.label ?? data.name ?? "",
7726
- width: void 0,
7727
- height: void 0
7728
- }));
7729
- if (images.length === 0 && data.small_image?.url) {
7730
- images.push({ url: data.small_image.url, altText: data.small_image.label ?? data.name ?? "" });
7731
- }
7732
- if (images.length === 0 && data.image?.url) {
7733
- images.push({ url: data.image.url, altText: data.image.label ?? data.name ?? "" });
7734
- }
7735
- const variants = [];
7736
- if (data.variants && Array.isArray(data.variants)) {
7737
- for (const v of data.variants) {
7738
- const product = v.product ?? {};
7739
- const vPrice = product.price_range?.minimum_price?.final_price ?? {};
7740
- variants.push({
7741
- id: String(product.id ?? product.uid ?? product.sku ?? ""),
7742
- title: product.name ?? product.sku ?? "",
7743
- availableForSale: product.stock_status === "IN_STOCK",
7744
- price: toMoney2(vPrice.value ?? min.amount, vPrice.currency ?? currencyCode),
7745
- compareAtPrice: void 0,
7746
- selectedOptions: (v.attributes ?? []).map((attr) => ({
7747
- name: attr.label ?? "",
7748
- value: attr.value_index != null ? String(attr.value_index) : ""
7749
- }))
7750
- });
7751
- }
7752
- }
7753
- if (variants.length === 0) {
7754
- variants.push({
7755
- id: data.sku ?? id,
7756
- title: data.name ?? "",
7757
- availableForSale: data.stock_status === "IN_STOCK",
7758
- price: min,
7759
- compareAtPrice: void 0,
7760
- selectedOptions: []
7761
- });
7762
- }
7763
- const options = (data.configurable_options ?? []).map((opt) => ({
7764
- id: String(opt.attribute_id ?? opt.attribute_code ?? ""),
7765
- name: opt.label ?? opt.attribute_code ?? "",
7766
- values: (opt.values ?? []).map((v) => v.label ?? v.store_label ?? String(v.value_index ?? ""))
7767
- }));
7768
- return {
7769
- id,
7770
- handle: data.url_key ?? data.sku ?? id,
7771
- title: data.name ?? "",
7772
- description: data.short_description?.html ?? data.description?.html ?? "",
7773
- descriptionHtml: data.description?.html ?? "",
7774
- availableForSale: data.stock_status === "IN_STOCK",
7775
- priceRange: { minVariantPrice: min, maxVariantPrice: max },
7776
- variants,
7777
- options,
7778
- images,
7779
- featuredImage: images[0] ?? { url: "", altText: data.name ?? "" },
7780
- tags: [],
7781
- seo: {
7782
- title: data.meta_title ?? data.name ?? "",
7783
- description: data.meta_description ?? ""
7784
- },
7785
- updatedAt: data.updated_at ?? (/* @__PURE__ */ new Date()).toISOString(),
7786
- createdAt: data.created_at ?? (/* @__PURE__ */ new Date()).toISOString()
7787
- };
7788
- }
7789
- function transformCollection6(data) {
7790
- return {
7791
- id: String(data.id ?? data.uid ?? ""),
7792
- handle: data.url_key ?? data.url_path ?? String(data.id ?? data.uid ?? ""),
7793
- title: data.name ?? "",
7794
- description: data.description ?? "",
7795
- seo: {
7796
- title: data.meta_title ?? data.name ?? "",
7797
- description: data.meta_description ?? ""
7798
- },
7799
- updatedAt: data.updated_at ?? (/* @__PURE__ */ new Date()).toISOString(),
7800
- path: `/collections/${data.url_key ?? data.url_path ?? data.id}`
7801
- };
7802
- }
7803
- function transformCart6(data, currencyCode = "USD") {
7804
- const items = (data.items ?? []).map((item) => {
7805
- const product = item.product ?? {};
7806
- const priceVal = item.prices?.price?.value ?? product.price_range?.minimum_price?.final_price?.value ?? 0;
7807
- const totalVal2 = item.prices?.row_total?.value ?? priceVal * (item.quantity ?? 1);
7808
- return {
7809
- id: String(item.id ?? item.uid ?? ""),
7810
- quantity: item.quantity ?? 1,
7811
- cost: {
7812
- totalAmount: toMoney2(totalVal2, item.prices?.price?.currency ?? currencyCode)
7813
- },
7814
- merchandise: {
7815
- id: String(product.sku ?? item.id ?? ""),
7816
- title: product.name ?? item.product?.name ?? "",
7817
- selectedOptions: (item.configurable_options ?? []).map((opt) => ({
7818
- name: opt.option_label ?? "",
7819
- value: opt.value_label ?? ""
7820
- })),
7821
- product: {
7822
- id: String(product.id ?? product.uid ?? ""),
7823
- handle: product.url_key ?? "",
7824
- title: product.name ?? "",
7825
- featuredImage: {
7826
- url: product.small_image?.url ?? product.thumbnail?.url ?? "",
7827
- altText: product.name ?? ""
7828
- }
7829
- }
7830
- }
7831
- };
7832
- });
7833
- const totalVal = data.prices?.grand_total?.value ?? 0;
7834
- const subtotalVal = data.prices?.subtotal_excluding_tax?.value ?? data.prices?.subtotal_including_tax?.value ?? totalVal;
7835
- const taxVal = (data.prices?.applied_taxes ?? []).reduce((sum, t) => sum + (t.amount?.value ?? 0), 0);
7836
- return {
7837
- id: String(data.id ?? ""),
7838
- checkoutUrl: "",
7839
- totalQuantity: items.reduce((sum, i) => sum + i.quantity, 0),
7840
- cost: {
7841
- subtotalAmount: toMoney2(subtotalVal, data.prices?.grand_total?.currency ?? currencyCode),
7842
- totalAmount: toMoney2(totalVal, data.prices?.grand_total?.currency ?? currencyCode),
7843
- totalTaxAmount: toMoney2(taxVal, currencyCode)
7844
- },
7845
- lines: items
7846
- };
7847
- }
7848
- function transformAddress3(addr) {
7849
- return {
7850
- id: String(addr.id ?? ""),
7851
- firstName: addr.firstname ?? "",
7852
- lastName: addr.lastname ?? "",
7853
- company: addr.company ?? "",
7854
- address1: Array.isArray(addr.street) ? addr.street[0] ?? "" : addr.street ?? "",
7855
- address2: Array.isArray(addr.street) ? addr.street[1] ?? "" : "",
7856
- city: addr.city ?? "",
7857
- province: addr.region?.region ?? "",
7858
- postalCode: addr.postcode ?? "",
7859
- countryCode: addr.country_code ?? addr.country_id ?? "",
7860
- phone: addr.telephone ?? ""
7861
- };
7862
- }
7863
- function transformOrder6(data, currencyCode = "USD") {
7864
- const items = (data.items ?? []).map((item) => ({
7865
- id: String(item.id ?? ""),
7866
- title: item.product_name ?? "",
7867
- quantity: item.quantity_ordered ?? item.quantity ?? 1,
7868
- price: toMoney2(item.product_sale_price?.value ?? item.price ?? 0, currencyCode),
7869
- total: toMoney2((item.product_sale_price?.value ?? item.price ?? 0) * (item.quantity_ordered ?? item.quantity ?? 1), currencyCode),
7870
- sku: item.product_sku ?? item.sku,
7871
- productId: String(item.product_id ?? "")
7872
- }));
7873
- return {
7874
- id: String(data.id ?? data.order_number ?? ""),
7875
- orderNumber: data.order_number ?? data.number ?? String(data.id ?? ""),
7876
- email: data.email ?? "",
7877
- status: data.status === "complete" ? "completed" : data.status === "canceled" ? "cancelled" : data.status === "closed" ? "refunded" : "pending",
7878
- paymentStatus: data.payment_status === "paid" ? "paid" : "pending",
7879
- fulfillmentStatus: data.shipment_status === "shipped" ? "fulfilled" : "unfulfilled",
7880
- items,
7881
- total: toMoney2(data.total?.grand_total?.value ?? data.grand_total ?? 0, currencyCode),
7882
- subtotal: toMoney2(data.total?.subtotal?.value ?? data.subtotal ?? 0, currencyCode),
7883
- tax: toMoney2(data.total?.total_tax?.value ?? data.tax_amount ?? 0, currencyCode),
7884
- shipping: toMoney2(data.total?.total_shipping?.value ?? data.shipping_amount ?? 0, currencyCode),
7885
- shippingAddress: data.shipping_address ? transformAddress3(data.shipping_address) : void 0,
7886
- billingAddress: data.billing_address ? transformAddress3(data.billing_address) : void 0,
7887
- createdAt: data.order_date ?? data.created_at ?? (/* @__PURE__ */ new Date()).toISOString(),
7888
- updatedAt: data.updated_at ?? data.order_date ?? (/* @__PURE__ */ new Date()).toISOString()
7889
- };
7890
- }
7891
-
7892
- // src/providers/magento/queries.ts
7893
- var PRODUCT_FIELDS = `
7894
- id
7895
- uid
7896
- sku
7897
- name
7898
- url_key
7899
- stock_status
7900
- short_description { html }
7901
- description { html }
7902
- meta_title
7903
- meta_description
7904
- created_at
7905
- updated_at
7906
- price_range {
7907
- minimum_price {
7908
- regular_price { value currency }
7909
- final_price { value currency }
7910
- }
7911
- maximum_price {
7912
- regular_price { value currency }
7913
- final_price { value currency }
7914
- }
7915
- }
7916
- small_image { url label }
7917
- image { url label }
7918
- media_gallery {
7919
- url
7920
- label
7921
- }
7922
- ... on ConfigurableProduct {
7923
- configurable_options {
7924
- attribute_code
7925
- attribute_id
7926
- label
7927
- values {
7928
- label
7929
- value_index
7930
- }
7931
- }
7932
- variants {
7933
- product {
7934
- id uid sku name
7935
- stock_status
7936
- price_range {
7937
- minimum_price {
7938
- final_price { value currency }
7939
- }
7940
- }
7941
- small_image { url label }
7942
- }
7943
- attributes {
7944
- label
7945
- value_index
7946
- }
7947
- }
7948
- }
7949
- `;
7950
- var GET_PRODUCTS2 = `
7951
- query GetProducts($search: String, $pageSize: Int, $currentPage: Int, $sort: ProductAttributeSortInput) {
7952
- products(search: $search, pageSize: $pageSize, currentPage: $currentPage, sort: $sort) {
7953
- items { ${PRODUCT_FIELDS} }
7954
- total_count
7955
- }
7956
- }
7957
- `;
7958
- var GET_PRODUCT_BY_URL_KEY = `
7959
- query GetProductByUrlKey($urlKey: String!) {
7960
- products(filter: { url_key: { eq: $urlKey } }, pageSize: 1) {
7961
- items { ${PRODUCT_FIELDS} }
7962
- }
7963
- }
7964
- `;
7965
- var GET_CATEGORIES = `
7966
- query GetCategories($pageSize: Int) {
7967
- categories(pageSize: $pageSize) {
7968
- items {
7969
- id uid name url_key url_path description meta_title meta_description
7970
- }
7971
- }
7972
- }
7973
- `;
7974
- var GET_CATEGORY_BY_URL_KEY = `
7975
- query GetCategoryByUrlKey($urlKey: String!) {
7976
- categories(filters: { url_key: { eq: $urlKey } }, pageSize: 1) {
7977
- items {
7978
- id uid name url_key url_path description meta_title meta_description
7979
- }
7980
- }
7981
- }
7982
- `;
7983
- var GET_CATEGORY_PRODUCTS = `
7984
- query GetCategoryProducts($urlKey: String!, $pageSize: Int) {
7985
- products(filter: { category_url_key: { eq: $urlKey } }, pageSize: $pageSize) {
7986
- items { ${PRODUCT_FIELDS} }
7987
- total_count
7988
- }
7989
- }
7990
- `;
7991
- var GET_CART2 = `
7992
- query GetCart($cartId: String!) {
7993
- cart(cart_id: $cartId) {
7994
- id
7995
- items {
7996
- id uid quantity
7997
- product {
7998
- id uid sku name url_key
7999
- small_image { url }
8000
- thumbnail { url }
8001
- price_range {
8002
- minimum_price {
8003
- final_price { value currency }
8004
- }
8005
- }
8006
- }
8007
- prices {
8008
- price { value currency }
8009
- row_total { value currency }
8010
- }
8011
- ... on ConfigurableCartItem {
8012
- configurable_options {
8013
- option_label
8014
- value_label
8015
- }
8016
- }
8017
- }
8018
- prices {
8019
- grand_total { value currency }
8020
- subtotal_excluding_tax { value currency }
8021
- subtotal_including_tax { value currency }
8022
- applied_taxes {
8023
- amount { value currency }
8024
- label
8025
- }
8026
- }
8027
- }
8028
- }
8029
- `;
8030
- var CREATE_EMPTY_CART = `
8031
- mutation CreateEmptyCart {
8032
- createEmptyCart
8033
- }
8034
- `;
8035
- var ADD_TO_CART = `
8036
- mutation AddToCart($cartId: String!, $cartItems: [CartItemInput!]!) {
8037
- addProductsToCart(cartId: $cartId, cartItems: $cartItems) {
8038
- cart {
8039
- id
8040
- items { id uid quantity product { sku name } prices { price { value currency } row_total { value currency } } }
8041
- prices { grand_total { value currency } subtotal_excluding_tax { value currency } }
8042
- }
8043
- user_errors { code message }
8044
- }
8045
- }
8046
- `;
8047
- var REMOVE_FROM_CART = `
8048
- mutation RemoveFromCart($cartId: String!, $cartItemUid: ID!) {
8049
- removeItemFromCart(input: { cart_id: $cartId, cart_item_uid: $cartItemUid }) {
8050
- cart {
8051
- id
8052
- items { id uid quantity product { sku name } prices { price { value currency } row_total { value currency } } }
8053
- prices { grand_total { value currency } subtotal_excluding_tax { value currency } }
8054
- }
8055
- }
8056
- }
8057
- `;
8058
- var UPDATE_CART_ITEMS = `
8059
- mutation UpdateCartItems($cartId: String!, $cartItems: [CartItemUpdateInput!]!) {
8060
- updateCartItems(input: { cart_id: $cartId, cart_items: $cartItems }) {
8061
- cart {
8062
- id
8063
- items { id uid quantity product { sku name } prices { price { value currency } row_total { value currency } } }
8064
- prices { grand_total { value currency } subtotal_excluding_tax { value currency } }
8065
- }
8066
- }
8067
- }
8068
- `;
8069
- var APPLY_COUPON = `
8070
- mutation ApplyCoupon($cartId: String!, $couponCode: String!) {
8071
- applyCouponToCart(input: { cart_id: $cartId, coupon_code: $couponCode }) {
8072
- cart {
8073
- id
8074
- prices { grand_total { value currency } subtotal_excluding_tax { value currency } }
8075
- }
8076
- }
8077
- }
8078
- `;
8079
- var REMOVE_COUPON = `
8080
- mutation RemoveCoupon($cartId: String!) {
8081
- removeCouponFromCart(input: { cart_id: $cartId }) {
8082
- cart {
8083
- id
8084
- prices { grand_total { value currency } subtotal_excluding_tax { value currency } }
8085
- }
8086
- }
8087
- }
8088
- `;
8089
- var GET_CUSTOMER_ORDERS = `
8090
- query GetCustomerOrders($pageSize: Int, $currentPage: Int) {
8091
- customer {
8092
- orders(pageSize: $pageSize, currentPage: $currentPage) {
8093
- items {
8094
- id order_number order_date status
8095
- total {
8096
- grand_total { value currency }
8097
- subtotal { value currency }
8098
- total_tax { value currency }
8099
- total_shipping { value currency }
8100
- }
8101
- items {
8102
- id product_name product_sku
8103
- quantity_ordered
8104
- product_sale_price { value currency }
8105
- }
8106
- shipping_address {
8107
- firstname lastname street city
8108
- region postcode country_code telephone
8109
- }
8110
- billing_address {
8111
- firstname lastname street city
8112
- region postcode country_code telephone
8113
- }
8114
- }
8115
- total_count
8116
- }
8117
- }
8118
- }
8119
- `;
8120
-
8121
- // src/providers/magento/index.ts
8122
- var MagentoProvider = class {
8123
- name = "magento";
8124
- version = "1.0.0";
8125
- capabilities = MAGENTO_CAPABILITIES;
8126
- logger;
8127
- baseUrl;
8128
- storeCode;
8129
- currencyCode;
8130
- graphqlEndpoint;
8131
- customerToken;
8132
- accessToken;
8133
- constructor(config) {
8134
- this.logger = createLogger("MagentoProvider", config.debug);
8135
- this.baseUrl = config.baseUrl.replace(/\/$/, "");
8136
- this.storeCode = config.storeCode ?? "default";
8137
- this.currencyCode = config.currencyCode ?? "USD";
8138
- this.graphqlEndpoint = `${this.baseUrl}/graphql`;
8139
- this.customerToken = config.customerToken;
8140
- this.accessToken = config.accessToken;
8141
- this.logger.info("Initializing Magento Provider", {
8142
- baseUrl: this.baseUrl,
8143
- storeCode: this.storeCode
8144
- });
8145
- }
8146
- async graphql(query, variables) {
8147
- const headers = {
8148
- "Content-Type": "application/json",
8149
- "Store": this.storeCode
8150
- };
8151
- if (this.customerToken) {
8152
- headers["Authorization"] = `Bearer ${this.customerToken}`;
8153
- }
8154
- const response = await fetch(this.graphqlEndpoint, {
8155
- method: "POST",
8156
- headers,
8157
- body: JSON.stringify({ query, variables })
8158
- });
8159
- if (!response.ok) {
8160
- throw new ProviderAPIError(
8161
- `Magento GraphQL error: ${response.status}`,
8162
- "MAGENTO_API_ERROR",
8163
- response.status
8164
- );
8165
- }
8166
- const json = await response.json();
8167
- if (json.errors?.length) {
8168
- const message = json.errors.map((e) => e.message).join("; ");
8169
- throw new ProviderAPIError(`Magento GraphQL error: ${message}`, "MAGENTO_GRAPHQL_ERROR");
8170
- }
8171
- return json.data;
8172
- }
8173
- // ============================================
8174
- // Product Operations (GraphQL)
8175
- // ============================================
8176
- async getProduct(handle) {
8177
- try {
8178
- const data = await this.graphql(GET_PRODUCT_BY_URL_KEY, { urlKey: handle });
8179
- return data.products.items[0] ? transformProduct6(data.products.items[0], this.currencyCode) : void 0;
8180
- } catch {
8181
- return void 0;
8182
- }
8183
- }
8184
- async getProducts(options) {
8185
- const variables = {
8186
- pageSize: options?.first ?? 20,
8187
- currentPage: 1
8188
- };
8189
- if (options?.query) variables.search = options.query;
8190
- if (options?.sortKey) {
8191
- const sortMap = {
8192
- "price-asc": { price: "ASC" },
8193
- "price-desc": { price: "DESC" },
8194
- "title-asc": { name: "ASC" },
8195
- "title-desc": { name: "DESC" },
8196
- "created-desc": { created_at: "DESC" },
8197
- "relevance": { relevance: "DESC" }
8198
- };
8199
- variables.sort = sortMap[options.sortKey] ?? { relevance: "DESC" };
8200
- }
8201
- const data = await this.graphql(GET_PRODUCTS2, variables);
8202
- return (data.products?.items ?? []).map((p) => transformProduct6(p, this.currencyCode));
8203
- }
8204
- async getProductRecommendations(_productId) {
8205
- return [];
8206
- }
8207
- // ============================================
8208
- // Collection/Category Operations (GraphQL)
8209
- // ============================================
8210
- async getCollection(handle) {
8211
- try {
8212
- const data = await this.graphql(GET_CATEGORY_BY_URL_KEY, { urlKey: handle });
8213
- return data.categories.items[0] ? transformCollection6(data.categories.items[0]) : void 0;
8214
- } catch {
8215
- return void 0;
8216
- }
8217
- }
8218
- async getCollections(options) {
8219
- const data = await this.graphql(GET_CATEGORIES, {
8220
- pageSize: options?.limit ?? 50
8221
- });
8222
- return (data.categories?.items ?? []).map(transformCollection6);
8223
- }
8224
- async getCollectionProducts(handle, options) {
8225
- const data = await this.graphql(GET_CATEGORY_PRODUCTS, {
8226
- urlKey: handle,
8227
- pageSize: options?.first ?? 20
8228
- });
8229
- return (data.products?.items ?? []).map((p) => transformProduct6(p, this.currencyCode));
8230
- }
8231
- async getCategory(handle) {
8232
- return this.getCollection(handle);
8233
- }
8234
- async getCategories(options) {
8235
- return this.getCollections(options);
8236
- }
8237
- async getCategoryProducts(handle, options) {
8238
- return this.getCollectionProducts(handle, options);
8239
- }
8240
- // ============================================
8241
- // Cart Operations (GraphQL)
8242
- // ============================================
8243
- async createCart() {
8244
- const data = await this.graphql(CREATE_EMPTY_CART);
8245
- const cartId = data.createEmptyCart;
8246
- const cartData = await this.graphql(GET_CART2, { cartId });
8247
- return transformCart6(cartData.cart ?? { id: cartId, items: [], prices: {} }, this.currencyCode);
8248
- }
8249
- async getCart(cartId) {
8250
- try {
8251
- const data = await this.graphql(GET_CART2, { cartId });
8252
- return data.cart ? transformCart6(data.cart, this.currencyCode) : void 0;
8253
- } catch {
8254
- return void 0;
8255
- }
8256
- }
8257
- async addToCart(cartId, lines) {
8258
- const cartItems = lines.map((l) => ({
8259
- sku: l.merchandiseId,
8260
- quantity: l.quantity
8261
- }));
8262
- const data = await this.graphql(ADD_TO_CART, {
8263
- cartId,
8264
- cartItems
8265
- });
8266
- if (data.addProductsToCart.user_errors?.length) {
8267
- throw new ProviderAPIError(
8268
- `Add to cart failed: ${data.addProductsToCart.user_errors.map((e) => e.message).join("; ")}`,
8269
- "MAGENTO_CART_ERROR"
8270
- );
8271
- }
8272
- return transformCart6(data.addProductsToCart.cart, this.currencyCode);
8273
- }
8274
- async removeFromCart(cartId, lineIds) {
8275
- let cart;
8276
- for (const itemUid of lineIds) {
8277
- const data = await this.graphql(REMOVE_FROM_CART, {
8278
- cartId,
8279
- cartItemUid: itemUid
8280
- });
8281
- cart = data.removeItemFromCart.cart;
8282
- }
8283
- return transformCart6(cart ?? { id: cartId, items: [], prices: {} }, this.currencyCode);
8284
- }
8285
- async updateCart(cartId, lines) {
8286
- const cartItems = lines.map((l) => ({
8287
- cart_item_uid: l.id,
8288
- quantity: l.quantity
8289
- }));
8290
- const data = await this.graphql(UPDATE_CART_ITEMS, {
8291
- cartId,
8292
- cartItems
8293
- });
8294
- return transformCart6(data.updateCartItems.cart, this.currencyCode);
8295
- }
8296
- // ============================================
8297
- // Checkout Operations
8298
- // ============================================
8299
- async completeCheckout(_cartId) {
8300
- throw new ProviderAPIError(
8301
- "Magento checkout requires multi-step process (set addresses, shipping, payment, place order). Use the Magento checkout flow.",
8302
- "MAGENTO_CHECKOUT_MULTI_STEP"
8303
- );
8304
- }
8305
- async getShippingMethods(_cartId) {
8306
- return [];
8307
- }
8308
- async getRegionCountries() {
8309
- return [];
8310
- }
8311
- async addShippingMethod(_cartId, _methodId) {
8312
- throw new ProviderAPIError(
8313
- "Magento shipping selection requires set-shipping-methods mutation.",
8314
- "MAGENTO_CHECKOUT_MULTI_STEP"
8315
- );
8316
- }
8317
- async initiatePaymentSession(_cartId, _providerId) {
8318
- }
8319
- async applyDiscountCode(cartId, code) {
8320
- const data = await this.graphql(APPLY_COUPON, {
8321
- cartId,
8322
- couponCode: code
8323
- });
8324
- return transformCart6(data.applyCouponToCart.cart, this.currencyCode);
8325
- }
8326
- async removeDiscountCode(cartId, _code) {
8327
- const data = await this.graphql(REMOVE_COUPON, {
8328
- cartId
8329
- });
8330
- return transformCart6(data.removeCouponFromCart.cart, this.currencyCode);
8331
- }
8332
- // ============================================
8333
- // Customer & Orders (GraphQL — requires customerToken)
8334
- // ============================================
8335
- async getOrders(_options) {
8336
- if (!this.customerToken) return [];
8337
- try {
8338
- const data = await this.graphql(GET_CUSTOMER_ORDERS, {
8339
- pageSize: 20,
8340
- currentPage: 1
8341
- });
8342
- return (data.customer?.orders?.items ?? []).map((o) => transformOrder6(o, this.currencyCode));
8343
- } catch {
8344
- return [];
8345
- }
8346
- }
8347
- async getPaymentMethods(_options) {
8348
- return [];
8349
- }
8350
- // ============================================
8351
- // Inventory
8352
- // ============================================
8353
- async getStockLocations() {
8354
- return [];
8355
- }
8356
- async checkInventoryLevels() {
8357
- return [];
8358
- }
8359
- async validateCartStock() {
8360
- return { allAvailable: true, unavailableItems: [] };
8361
- }
8362
- async getFulfillmentOptions() {
8363
- return [];
8364
- }
8365
- // ============================================
8366
- // Admin Operations
8367
- // ============================================
8368
- async cancelOrder(_orderId) {
8369
- throw new ProviderAPIError("Order cancellation requires Magento Admin API.", "MAGENTO_ADMIN_REQUIRED");
8370
- }
8371
- async createFulfillment(_orderId) {
8372
- throw new ProviderAPIError("Fulfillment requires Magento Admin API.", "MAGENTO_ADMIN_REQUIRED");
8373
- }
8374
- async createRefund(_orderId) {
8375
- throw new ProviderAPIError("Refunds require Magento Admin API.", "MAGENTO_ADMIN_REQUIRED");
8376
- }
8377
- async getAdminOrders() {
8378
- return { orders: [], count: 0 };
8379
- }
8380
- // ============================================
8381
- // Storefront / Multi-Tenant
8382
- // ============================================
8383
- async getStorefrontContext() {
8384
- return {
8385
- id: this.storeCode,
8386
- name: `Magento ${this.storeCode}`,
8387
- platformType: "magento",
8388
- requiresProductScoping: true,
8389
- currencyCode: this.currencyCode
8390
- };
8391
- }
8392
- isStorefrontRequired() {
8393
- return true;
8394
- }
8395
- };
8396
-
8397
- // src/providers/stelorder/transforms.ts
8398
- function normalizeStelCollection(payload) {
8399
- if (!payload) {
8400
- return [];
8401
- }
8402
- return Array.isArray(payload) ? payload : [payload];
8403
- }
8404
- function normalizeStelEntity(payload) {
8405
- if (!payload) {
8406
- return void 0;
8407
- }
8408
- return Array.isArray(payload) ? payload[0] : payload;
8409
- }
8410
- function transformStelMoney(amount, currencyCode = "USD") {
8411
- const normalizedAmount = typeof amount === "string" ? Number.parseFloat(amount) : amount ?? 0;
8412
- return {
8413
- amount: Number.isFinite(normalizedAmount) ? normalizedAmount.toFixed(2) : "0.00",
8414
- currencyCode: currencyCode.toUpperCase()
8415
- };
8416
- }
8417
- function transformStelImage(url, altText = "") {
8418
- const normalizedUrl = url?.trim();
8419
- if (!normalizedUrl) {
8420
- return void 0;
8421
- }
8422
- return {
8423
- url: normalizedUrl,
8424
- altText,
8425
- width: 800,
8426
- height: 800
8427
- };
8428
- }
8429
- function normalizeStelDate(value) {
8430
- if (!value) {
8431
- return (/* @__PURE__ */ new Date()).toISOString();
8432
- }
8433
- const parsed = new Date(value);
8434
- return Number.isNaN(parsed.getTime()) ? (/* @__PURE__ */ new Date()).toISOString() : parsed.toISOString();
8435
- }
8436
- function toStelStringId(value) {
8437
- if (value === null || value === void 0) {
8438
- return "";
8439
- }
8440
- return String(value);
8441
- }
8442
- function slugify(value) {
8443
- return value.normalize("NFKD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
8444
- }
8445
- function buildStelHandle(...candidates) {
8446
- for (const candidate of candidates) {
8447
- if (candidate === null || candidate === void 0) {
8448
- continue;
8449
- }
8450
- const normalized = slugify(String(candidate).trim());
8451
- if (normalized) {
8452
- return normalized;
5634
+ const normalized = slugify(String(candidate).trim());
5635
+ if (normalized) {
5636
+ return normalized;
8453
5637
  }
8454
5638
  }
8455
5639
  return "stel-item";
@@ -10425,6 +7609,16 @@ var MockProvider = class {
10425
7609
  };
10426
7610
 
10427
7611
  // src/factory/index.ts
7612
+ var registry = /* @__PURE__ */ new Map();
7613
+ function registerProvider(type, factory) {
7614
+ registry.set(type, factory);
7615
+ }
7616
+ function getRegisteredProviders() {
7617
+ return Array.from(registry.keys());
7618
+ }
7619
+ registerProvider("mock", (config) => new MockProvider(config));
7620
+ registerProvider("medusa", (config) => new MedusaProvider(config));
7621
+ registerProvider("stelorder", (config) => new StelOrderProvider(config));
10428
7622
  function createProvider(options) {
10429
7623
  if (!options || !options.provider) {
10430
7624
  throw new ConfigurationError("Provider type is required");
@@ -10432,27 +7626,14 @@ function createProvider(options) {
10432
7626
  if (!options.config) {
10433
7627
  throw new ConfigurationError("Provider configuration is required");
10434
7628
  }
10435
- const config = options.config;
10436
- switch (options.provider) {
10437
- case "mock":
10438
- return new MockProvider(config);
10439
- case "medusa":
10440
- return new MedusaProvider(config);
10441
- case "stelorder":
10442
- return new StelOrderProvider(config);
10443
- case "shopify":
10444
- return new ShopifyProvider(config);
10445
- case "bigcommerce":
10446
- return new BigCommerceProvider(config);
10447
- case "woocommerce":
10448
- return new WooCommerceProvider(config);
10449
- case "spree":
10450
- return new SpreeProvider(config);
10451
- case "magento":
10452
- return new MagentoProvider(config);
10453
- default:
10454
- throw new ProviderNotFoundError(String(options.provider));
7629
+ const factory = registry.get(options.provider);
7630
+ if (!factory) {
7631
+ const available = getRegisteredProviders().join(", ");
7632
+ throw new ProviderNotFoundError(
7633
+ `Provider "${options.provider}" is not registered. Available: ${available}. Did you forget to import the provider package?`
7634
+ );
10455
7635
  }
7636
+ return factory(options.config);
10456
7637
  }
10457
7638
  function isProviderType(provider, type) {
10458
7639
  return provider.name === type;
@@ -10460,8 +7641,6 @@ function isProviderType(provider, type) {
10460
7641
  export {
10461
7642
  AdminAuthService,
10462
7643
  AdminSessionService,
10463
- BIGCOMMERCE_CAPABILITIES,
10464
- BigCommerceProvider,
10465
7644
  CHANNEL_ASSIGNED_AT_KEY,
10466
7645
  CHANNEL_ASSIGNED_BY_KEY,
10467
7646
  CHANNEL_SCOPE_KEY,
@@ -10470,10 +7649,8 @@ export {
10470
7649
  CircuitBreakerOpenError,
10471
7650
  CommerceError,
10472
7651
  ConfigurationError,
10473
- MAGENTO_CAPABILITIES,
10474
7652
  MEDUSA_CAPABILITIES,
10475
7653
  MOCK_CAPABILITIES,
10476
- MagentoProvider,
10477
7654
  MedusaMetadataAdapter,
10478
7655
  MedusaProvider,
10479
7656
  MetricsService,
@@ -10481,15 +7658,9 @@ export {
10481
7658
  ProviderAPIError,
10482
7659
  ProviderNotFoundError,
10483
7660
  ResourceNotFoundError,
10484
- SHOPIFY_CAPABILITIES,
10485
- SPREE_CAPABILITIES,
10486
7661
  STELORDER_CAPABILITIES,
10487
- ShopifyProvider,
10488
- SpreeProvider,
10489
7662
  StelOrderProvider,
10490
7663
  StorefrontConfigError2 as StorefrontConfigError,
10491
- WOOCOMMERCE_CAPABILITIES,
10492
- WooCommerceProvider,
10493
7664
  assertEntityBelongsToChannel,
10494
7665
  backendCircuitBreaker,
10495
7666
  buildChannelScopeMetadata,
@@ -10497,12 +7668,15 @@ export {
10497
7668
  createBackendMetadataAdapter,
10498
7669
  createLogger,
10499
7670
  createProvider,
7671
+ extractErrorMessage,
7672
+ fetchWithRetry,
10500
7673
  filterByChannel,
10501
7674
  filterGlobalOnly,
10502
7675
  geocodeAddress,
10503
7676
  getBackendProviderId,
10504
7677
  getCapabilityDescription,
10505
7678
  getChannelScope,
7679
+ getRegisteredProviders,
10506
7680
  isBackendCapabilities,
10507
7681
  isGlobalEntity,
10508
7682
  isProviderType,
@@ -10512,6 +7686,7 @@ export {
10512
7686
  numberToMoney,
10513
7687
  partitionByChannel,
10514
7688
  planFulfillment,
7689
+ registerProvider,
10515
7690
  transformFulfillmentOption,
10516
7691
  transformInventoryLevel,
10517
7692
  transformStockLocation,