@reactionary/magento 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +11 -0
  2. package/capabilities/cart.capability.js +293 -0
  3. package/capabilities/category.capability.js +254 -0
  4. package/capabilities/identity.capability.js +107 -0
  5. package/capabilities/inventory.capability.js +84 -0
  6. package/capabilities/price.capability.js +72 -0
  7. package/capabilities/product-search.capability.js +113 -0
  8. package/capabilities/product.capability.js +146 -0
  9. package/core/client.js +321 -0
  10. package/core/initialize.js +176 -0
  11. package/core/initialize.types.js +13 -0
  12. package/factories/cart/cart.factory.js +135 -0
  13. package/factories/category/category.factory.js +48 -0
  14. package/factories/identity/identity.factory.js +12 -0
  15. package/factories/index.js +7 -0
  16. package/factories/inventory/inventory.factory.js +24 -0
  17. package/factories/price/price.factory.js +43 -0
  18. package/factories/product/product.factory.js +115 -0
  19. package/factories/product-search/product-search.factory.js +88 -0
  20. package/index.js +14 -0
  21. package/package.json +15 -0
  22. package/schema/capabilities.schema.js +31 -0
  23. package/schema/configuration.schema.js +13 -0
  24. package/schema/magento.schema.js +5 -0
  25. package/schema/magento.types.js +0 -0
  26. package/src/capabilities/cart.capability.d.ts +24 -0
  27. package/src/capabilities/category.capability.d.ts +22 -0
  28. package/src/capabilities/identity.capability.d.ts +13 -0
  29. package/src/capabilities/inventory.capability.d.ts +11 -0
  30. package/src/capabilities/price.capability.d.ts +12 -0
  31. package/src/capabilities/product-search.capability.d.ts +15 -0
  32. package/src/capabilities/product.capability.d.ts +14 -0
  33. package/src/core/client.d.ts +93 -0
  34. package/src/core/initialize.d.ts +5 -0
  35. package/src/core/initialize.types.d.ts +80 -0
  36. package/src/factories/cart/cart.factory.d.ts +20 -0
  37. package/src/factories/category/category.factory.d.ts +14 -0
  38. package/src/factories/identity/identity.factory.d.ts +7 -0
  39. package/src/factories/index.d.ts +7 -0
  40. package/src/factories/inventory/inventory.factory.d.ts +13 -0
  41. package/src/factories/price/price.factory.d.ts +15 -0
  42. package/src/factories/product/product.factory.d.ts +13 -0
  43. package/src/factories/product-search/product-search.factory.d.ts +12 -0
  44. package/src/index.d.ts +14 -0
  45. package/src/schema/capabilities.schema.d.ts +74 -0
  46. package/src/schema/configuration.schema.d.ts +11 -0
  47. package/src/schema/magento.schema.d.ts +5 -0
  48. package/src/schema/magento.types.d.ts +200 -0
@@ -0,0 +1,84 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __decorateClass = (decorators, target, key, kind) => {
4
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
5
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
6
+ if (decorator = decorators[i])
7
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
8
+ if (kind && result)
9
+ __defProp(target, key, result);
10
+ return result;
11
+ };
12
+ import {
13
+ InventoryCapability,
14
+ InventorySchema,
15
+ InventoryQueryBySKUSchema,
16
+ Reactionary,
17
+ success
18
+ } from "@reactionary/core";
19
+ import createDebug from "debug";
20
+ const debug = createDebug("reactionary:magento:inventory");
21
+ class MagentoInventoryCapability extends InventoryCapability {
22
+ constructor(config, cache, context, magentoApi, factory) {
23
+ super(cache, context);
24
+ this.magentoApi = magentoApi;
25
+ this.config = config;
26
+ this.factory = factory;
27
+ }
28
+ config;
29
+ factory;
30
+ async getBySKU(payload) {
31
+ const sku = payload.variant.sku;
32
+ const fulfillmentCenterKey = payload.fulfilmentCenter?.key;
33
+ const client = await this.magentoApi.getClient();
34
+ try {
35
+ if (fulfillmentCenterKey) {
36
+ const params = new URLSearchParams();
37
+ params.set("searchCriteria[filterGroups][0][filters][0][field]", "sku");
38
+ params.set("searchCriteria[filterGroups][0][filters][0][value]", sku);
39
+ params.set("searchCriteria[filterGroups][0][filters][0][condition_type]", "eq");
40
+ params.set("searchCriteria[filterGroups][1][filters][0][field]", "source_code");
41
+ params.set("searchCriteria[filterGroups][1][filters][0][value]", fulfillmentCenterKey);
42
+ params.set("searchCriteria[filterGroups][1][filters][0][condition_type]", "eq");
43
+ const msiResponse = await client.store.inventory.getSourceItems(params);
44
+ if (msiResponse?.items?.length > 0) {
45
+ const item = msiResponse.items[0];
46
+ return success(
47
+ this.factory.parseInventory(this.context, {
48
+ sku,
49
+ fulfillmentCenterKey,
50
+ quantity: item.quantity,
51
+ status: item.status === 1 ? "inStock" : "outOfStock"
52
+ })
53
+ );
54
+ }
55
+ }
56
+ const statusResponse = await client.store.inventory.getStockStatus(sku);
57
+ return success(
58
+ this.factory.parseInventory(this.context, {
59
+ sku,
60
+ fulfillmentCenterKey: fulfillmentCenterKey || "default",
61
+ quantity: statusResponse.qty || 0,
62
+ status: statusResponse.stock_status === 1 ? "inStock" : "outOfStock"
63
+ })
64
+ );
65
+ } catch (e) {
66
+ debug("Error fetching inventory", e);
67
+ return success(
68
+ this.createEmptyInventory({
69
+ variant: { sku },
70
+ fulfillmentCenter: { key: fulfillmentCenterKey || "default" }
71
+ })
72
+ );
73
+ }
74
+ }
75
+ }
76
+ __decorateClass([
77
+ Reactionary({
78
+ inputSchema: InventoryQueryBySKUSchema,
79
+ outputSchema: InventorySchema
80
+ })
81
+ ], MagentoInventoryCapability.prototype, "getBySKU", 1);
82
+ export {
83
+ MagentoInventoryCapability
84
+ };
@@ -0,0 +1,72 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __decorateClass = (decorators, target, key, kind) => {
4
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
5
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
6
+ if (decorator = decorators[i])
7
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
8
+ if (kind && result)
9
+ __defProp(target, key, result);
10
+ return result;
11
+ };
12
+ import {
13
+ PriceCapability,
14
+ PriceSchema,
15
+ CustomerPriceQuerySchema,
16
+ ListPriceQuerySchema,
17
+ Reactionary,
18
+ success
19
+ } from "@reactionary/core";
20
+ import createDebug from "debug";
21
+ const debug = createDebug("reactionary:magento:price");
22
+ class MagentoPriceCapability extends PriceCapability {
23
+ constructor(config, cache, context, magentoApi, factory) {
24
+ super(cache, context);
25
+ this.magentoApi = magentoApi;
26
+ this.config = config;
27
+ this.factory = factory;
28
+ }
29
+ config;
30
+ factory;
31
+ async getListPrice(payload) {
32
+ const sku = payload.variant.sku;
33
+ try {
34
+ const client = await this.magentoApi.getClient();
35
+ const product = await client.store.product.getBySKU(sku);
36
+ return success(
37
+ this.factory.parsePrice(this.context, { product, sku, mode: "list" })
38
+ );
39
+ } catch (e) {
40
+ debug(`Error fetching list price for ${sku}`, e);
41
+ return success(this.createEmptyPriceResult(sku));
42
+ }
43
+ }
44
+ async getCustomerPrice(payload) {
45
+ const sku = payload.variant.sku;
46
+ try {
47
+ const client = await this.magentoApi.getClient();
48
+ const product = await client.store.product.getBySKU(sku);
49
+ return success(
50
+ this.factory.parsePrice(this.context, { product, sku, mode: "customer" })
51
+ );
52
+ } catch (e) {
53
+ debug(`Error fetching customer price for ${sku}`, e);
54
+ return success(this.createEmptyPriceResult(sku));
55
+ }
56
+ }
57
+ }
58
+ __decorateClass([
59
+ Reactionary({
60
+ inputSchema: ListPriceQuerySchema,
61
+ outputSchema: PriceSchema
62
+ })
63
+ ], MagentoPriceCapability.prototype, "getListPrice", 1);
64
+ __decorateClass([
65
+ Reactionary({
66
+ inputSchema: CustomerPriceQuerySchema,
67
+ outputSchema: PriceSchema
68
+ })
69
+ ], MagentoPriceCapability.prototype, "getCustomerPrice", 1);
70
+ export {
71
+ MagentoPriceCapability
72
+ };
@@ -0,0 +1,113 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __decorateClass = (decorators, target, key, kind) => {
4
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
5
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
6
+ if (decorator = decorators[i])
7
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
8
+ if (kind && result)
9
+ __defProp(target, key, result);
10
+ return result;
11
+ };
12
+ import {
13
+ FacetIdentifierSchema,
14
+ FacetValueIdentifierSchema,
15
+ ProductSearchCapability,
16
+ ProductSearchQueryByTermSchema,
17
+ ProductSearchResultSchema,
18
+ Reactionary,
19
+ success
20
+ } from "@reactionary/core";
21
+ import createDebug from "debug";
22
+ const debug = createDebug("reactionary:magento:search");
23
+ class MagentoProductSearchCapability extends ProductSearchCapability {
24
+ constructor(config, cache, context, magentoApi, factory) {
25
+ super(cache, context);
26
+ this.magentoApi = magentoApi;
27
+ this.config = config;
28
+ this.factory = factory;
29
+ }
30
+ config;
31
+ factory;
32
+ async queryByTerm(payload) {
33
+ const finalSearch = (payload.search.term || "").trim().replace("*", "");
34
+ const pageSize = payload.search.paginationOptions.pageSize;
35
+ const currentPage = payload.search.paginationOptions.pageNumber;
36
+ const params = new URLSearchParams();
37
+ let filterGroupIndex = 0;
38
+ if (finalSearch) {
39
+ params.set(
40
+ `searchCriteria[filterGroups][${filterGroupIndex}][filters][0][field]`,
41
+ "name"
42
+ );
43
+ params.set(
44
+ `searchCriteria[filterGroups][${filterGroupIndex}][filters][0][value]`,
45
+ `%${finalSearch}%`
46
+ );
47
+ params.set(
48
+ `searchCriteria[filterGroups][${filterGroupIndex}][filters][0][condition_type]`,
49
+ "like"
50
+ );
51
+ filterGroupIndex++;
52
+ }
53
+ if (payload.search.categoryFilter?.key) {
54
+ debug(`Applying category filter: ${payload.search.categoryFilter.key}`);
55
+ params.set(
56
+ `searchCriteria[filterGroups][${filterGroupIndex}][filters][0][field]`,
57
+ "category_id"
58
+ );
59
+ params.set(
60
+ `searchCriteria[filterGroups][${filterGroupIndex}][filters][0][value]`,
61
+ payload.search.categoryFilter.key
62
+ );
63
+ params.set(
64
+ `searchCriteria[filterGroups][${filterGroupIndex}][filters][0][condition_type]`,
65
+ "eq"
66
+ );
67
+ filterGroupIndex++;
68
+ }
69
+ params.set("searchCriteria[pageSize]", String(pageSize));
70
+ params.set("searchCriteria[currentPage]", String(currentPage));
71
+ const client = await this.magentoApi.getClient();
72
+ const response = await client.store.product.search(params);
73
+ const result = this.factory.parseSearchResult(this.context, response, payload);
74
+ if (debug.enabled) {
75
+ debug(
76
+ `Search for term "${payload.search.term}" returned ${response.items?.length ?? 0} products (page ${currentPage} of ${result.totalPages})`
77
+ );
78
+ }
79
+ return success(result);
80
+ }
81
+ async createCategoryNavigationFilter(payload) {
82
+ const facetIdentifier = FacetIdentifierSchema.parse({
83
+ key: "categories"
84
+ });
85
+ const facetValueIdentifier = FacetValueIdentifierSchema.parse({
86
+ facet: facetIdentifier,
87
+ key: payload.categoryPath[payload.categoryPath.length - 1].identifier.key
88
+ });
89
+ return success(facetValueIdentifier);
90
+ }
91
+ parseFacetValue(_facetValueIdentifier, _label, _count) {
92
+ throw new Error("Method not implemented.");
93
+ }
94
+ parseFacet(_facetIdentifier, _facetValue) {
95
+ throw new Error("Method not implemented.");
96
+ }
97
+ parseVariant() {
98
+ throw new Error("Method not implemented.");
99
+ }
100
+ }
101
+ __decorateClass([
102
+ Reactionary({
103
+ inputSchema: ProductSearchQueryByTermSchema,
104
+ outputSchema: ProductSearchResultSchema,
105
+ cache: true,
106
+ cacheTimeToLiveInSeconds: 300,
107
+ currencyDependentCaching: false,
108
+ localeDependentCaching: true
109
+ })
110
+ ], MagentoProductSearchCapability.prototype, "queryByTerm", 1);
111
+ export {
112
+ MagentoProductSearchCapability
113
+ };
@@ -0,0 +1,146 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __decorateClass = (decorators, target, key, kind) => {
4
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
5
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
6
+ if (decorator = decorators[i])
7
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
8
+ if (kind && result)
9
+ __defProp(target, key, result);
10
+ return result;
11
+ };
12
+ import {
13
+ ProductCapability,
14
+ ProductQueryByIdSchema,
15
+ ProductQueryBySKUSchema,
16
+ ProductQueryBySlugSchema,
17
+ ProductSchema,
18
+ Reactionary,
19
+ success,
20
+ error
21
+ } from "@reactionary/core";
22
+ import createDebug from "debug";
23
+ const debug = createDebug("reactionary:magento:product");
24
+ function normalizeBaseUrl(baseUrl) {
25
+ return baseUrl.replace(/\/+$/, "");
26
+ }
27
+ function buildProductsSearchUrl(baseUrl, storeCode, field, value, condition = "eq", pageSize = 1, currentPage = 1) {
28
+ const b = normalizeBaseUrl(baseUrl);
29
+ const params = new URLSearchParams();
30
+ params.set("searchCriteria[filterGroups][0][filters][0][field]", field);
31
+ params.set("searchCriteria[filterGroups][0][filters][0][value]", String(value));
32
+ params.set("searchCriteria[filterGroups][0][filters][0][condition_type]", condition);
33
+ params.set("searchCriteria[pageSize]", String(pageSize));
34
+ params.set("searchCriteria[currentPage]", String(currentPage));
35
+ return `${b}/${storeCode}/rest/V1/products?${params.toString()}`;
36
+ }
37
+ async function adminSearchProducts(config, field, value) {
38
+ const token = config.adminApiKey;
39
+ if (!token) {
40
+ throw new Error(
41
+ `Magento admin search requires admin token. Missing config.adminApiKey for field=${field}.`
42
+ );
43
+ }
44
+ const url = buildProductsSearchUrl(config.baseUrl, config.storeCode, field, value, "eq", 1, 1);
45
+ const res = await fetch(url, {
46
+ method: "GET",
47
+ headers: {
48
+ Accept: "application/json",
49
+ Authorization: `Bearer ${token}`
50
+ }
51
+ });
52
+ if (!res.ok) {
53
+ const text = await res.text().catch(() => "");
54
+ throw new Error(
55
+ `Magento admin search failed: GET ${url} -> ${res.status} ${res.statusText}
56
+ ${text}`
57
+ );
58
+ }
59
+ return await res.json();
60
+ }
61
+ class MagentoProductCapability extends ProductCapability {
62
+ constructor(config, cache, context, magentoApi, factory) {
63
+ super(cache, context);
64
+ this.magentoApi = magentoApi;
65
+ this.config = config;
66
+ this.factory = factory;
67
+ }
68
+ config;
69
+ factory;
70
+ async getById(payload) {
71
+ const key = payload.identifier.key;
72
+ if (debug.enabled) {
73
+ debug(`Fetching product by ID/key: ${key}`);
74
+ }
75
+ try {
76
+ if (/^\d+$/.test(key)) {
77
+ const result = await adminSearchProducts(this.config, "entity_id", Number(key));
78
+ const product2 = result.items?.[0];
79
+ if (!product2) {
80
+ return success(this.createEmptyProduct(key));
81
+ }
82
+ return success(this.factory.parseProduct(this.context, product2));
83
+ }
84
+ const product = await this.magentoApi.getProductBySKU(key);
85
+ return success(this.factory.parseProduct(this.context, product));
86
+ } catch (e) {
87
+ if (debug.enabled) {
88
+ debug(`Product with key ${key} not found. Error %O`, e);
89
+ }
90
+ return success(this.createEmptyProduct(key));
91
+ }
92
+ }
93
+ async getBySlug(payload) {
94
+ if (debug.enabled) {
95
+ debug(`Fetching product by slug(url_key): ${payload.slug}`);
96
+ }
97
+ try {
98
+ const result = await adminSearchProducts(this.config, "url_key", payload.slug);
99
+ const product = result.items?.[0];
100
+ if (!product) {
101
+ return error({
102
+ type: "NotFound",
103
+ identifier: payload
104
+ });
105
+ }
106
+ return success(this.factory.parseProduct(this.context, product));
107
+ } catch (e) {
108
+ if (debug.enabled) {
109
+ debug(`Slug lookup failed for ${payload.slug}. Error %O`, e);
110
+ }
111
+ return error({
112
+ type: "NotFound",
113
+ identifier: payload
114
+ });
115
+ }
116
+ }
117
+ async getBySKU(payload) {
118
+ const sku = payload.variant.sku;
119
+ if (debug.enabled) {
120
+ debug(`Fetching product by SKU: ${sku}`);
121
+ }
122
+ const product = await this.magentoApi.getProductBySKU(sku);
123
+ return success(this.factory.parseProduct(this.context, product));
124
+ }
125
+ }
126
+ __decorateClass([
127
+ Reactionary({
128
+ inputSchema: ProductQueryByIdSchema,
129
+ outputSchema: ProductSchema
130
+ })
131
+ ], MagentoProductCapability.prototype, "getById", 1);
132
+ __decorateClass([
133
+ Reactionary({
134
+ inputSchema: ProductQueryBySlugSchema,
135
+ outputSchema: ProductSchema.nullable()
136
+ })
137
+ ], MagentoProductCapability.prototype, "getBySlug", 1);
138
+ __decorateClass([
139
+ Reactionary({
140
+ inputSchema: ProductQueryBySKUSchema,
141
+ outputSchema: ProductSchema
142
+ })
143
+ ], MagentoProductCapability.prototype, "getBySKU", 1);
144
+ export {
145
+ MagentoProductCapability
146
+ };