@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
package/core/client.js ADDED
@@ -0,0 +1,321 @@
1
+ import createDebug from "debug";
2
+ const debug = createDebug("reactionary:magento");
3
+ const SESSION_KEY = "MAGENTO_PROVIDER";
4
+ class RequestContextTokenStore {
5
+ constructor(context, keyPrefix = "__x") {
6
+ this.context = context;
7
+ this.keyPrefix = keyPrefix;
8
+ }
9
+ ensureNamespace() {
10
+ if (this.context.session[SESSION_KEY] === void 0) {
11
+ this.context.session[SESSION_KEY] = {};
12
+ }
13
+ }
14
+ async getItem(key) {
15
+ this.ensureNamespace();
16
+ const session = this.context.session[SESSION_KEY];
17
+ return session[`${this.keyPrefix}_${key}`] ?? null;
18
+ }
19
+ async setItem(key, value) {
20
+ this.ensureNamespace();
21
+ const session = this.context.session[SESSION_KEY];
22
+ session[`${this.keyPrefix}_${key}`] = value;
23
+ }
24
+ async removeItem(key) {
25
+ this.ensureNamespace();
26
+ const session = this.context.session[SESSION_KEY];
27
+ delete session[`${this.keyPrefix}_${key}`];
28
+ }
29
+ }
30
+ class MagentoRest {
31
+ constructor(baseUrl, storeCode, getAuthHeader) {
32
+ this.baseUrl = baseUrl;
33
+ this.storeCode = storeCode;
34
+ this.getAuthHeader = getAuthHeader;
35
+ this.apiUrl = `${this.baseUrl}/rest/${this.storeCode}`;
36
+ }
37
+ apiUrl;
38
+ normalizeUrl(path) {
39
+ const base = this.apiUrl.replace(/\/+$/, "");
40
+ const p = path.startsWith("/") ? path : `/${path}`;
41
+ return `${base}${p}`;
42
+ }
43
+ async request(method, path, body) {
44
+ const url = this.normalizeUrl(path);
45
+ const headers = {
46
+ "Content-Type": "application/json",
47
+ ...await this.getAuthHeader()
48
+ };
49
+ const res = await fetch(url, {
50
+ method,
51
+ headers,
52
+ body: body === void 0 ? void 0 : JSON.stringify(body)
53
+ });
54
+ if (!res.ok) {
55
+ const text = await res.text().catch(() => "");
56
+ throw new Error(
57
+ `Magento request failed: ${method} ${path} \u2192 ${res.status}
58
+ ${text}`
59
+ );
60
+ }
61
+ const contentType = res.headers.get("content-type") ?? "";
62
+ if (contentType.includes("application/json")) {
63
+ return await res.json();
64
+ }
65
+ return await res.text();
66
+ }
67
+ }
68
+ class Magento {
69
+ constructor(rest, tokenStore) {
70
+ this.rest = rest;
71
+ this.tokenStore = tokenStore;
72
+ }
73
+ auth = {
74
+ login: async (email, password) => {
75
+ const token = await this.rest.request(
76
+ "POST",
77
+ "/V1/integration/customer/token",
78
+ { username: email, password }
79
+ );
80
+ const normalized = typeof token === "string" ? token.replace(/^"|"$/g, "") : String(token);
81
+ await this.tokenStore.setItem("customerToken", normalized);
82
+ return normalized;
83
+ },
84
+ logout: async () => {
85
+ await this.tokenStore.removeItem("customerToken");
86
+ }
87
+ };
88
+ store = {
89
+ customer: {
90
+ register: async (customer, password) => {
91
+ return this.rest.request("POST", "/V1/customers", { customer, password });
92
+ },
93
+ me: async () => {
94
+ return this.rest.request("GET", "/V1/customers/me");
95
+ }
96
+ },
97
+ product: {
98
+ getBySKU: async (sku) => {
99
+ return this.rest.request(
100
+ "GET",
101
+ `/V1/products/${encodeURIComponent(sku)}`
102
+ );
103
+ },
104
+ search: async (params) => {
105
+ return this.rest.request(
106
+ "GET",
107
+ `/V1/products?${params.toString()}`
108
+ );
109
+ }
110
+ },
111
+ category: {
112
+ getById: async (categoryId) => {
113
+ return this.rest.request("GET", `/V1/categories/${encodeURIComponent(categoryId)}`);
114
+ },
115
+ getByExternalId: async (externalId) => {
116
+ const searchParams = new URLSearchParams({
117
+ "searchCriteria[filterGroups][0][filters][0][field]": "external_id",
118
+ "searchCriteria[filterGroups][0][filters][0][value]": externalId,
119
+ "searchCriteria[filterGroups][0][filters][0][condition_type]": "eq"
120
+ });
121
+ const response = await this.rest.request("GET", `/V1/categories?${searchParams.toString()}`);
122
+ return response.items?.[0] || null;
123
+ },
124
+ list: async (params) => {
125
+ return this.rest.request("GET", `/V1/categories/list?${params.toString()}`);
126
+ }
127
+ },
128
+ inventory: {
129
+ getStockStatus: async (sku) => {
130
+ return this.rest.request("GET", `/V1/stockStatuses/${encodeURIComponent(sku)}`);
131
+ },
132
+ getSourceItems: async (params) => {
133
+ return this.rest.request("GET", `/V1/inventory/source-items?${params.toString()}`);
134
+ }
135
+ },
136
+ cart: {
137
+ create: async (customerToken) => {
138
+ if (customerToken) {
139
+ const res2 = await this.rest.request("POST", "/V1/carts/mine");
140
+ return typeof res2 === "string" ? res2.replace(/^"|"$/g, "") : String(res2);
141
+ }
142
+ const res = await this.rest.request("POST", "/V1/guest-carts");
143
+ return res.replace(/^"|"$/g, "");
144
+ },
145
+ get: async (cartId, customerToken) => {
146
+ if (customerToken) {
147
+ return this.rest.request("GET", "/V1/carts/mine");
148
+ }
149
+ return this.rest.request("GET", `/V1/guest-carts/${cartId}`);
150
+ },
151
+ getTotals: async (cartId, customerToken) => {
152
+ if (customerToken) {
153
+ return this.rest.request("GET", "/V1/carts/mine/totals");
154
+ }
155
+ return this.rest.request("GET", `/V1/guest-carts/${cartId}/totals`);
156
+ },
157
+ addItem: async (cartId, item, customerToken) => {
158
+ const id = cartId && !isNaN(Number(cartId)) ? Number(cartId) : cartId;
159
+ if (customerToken) {
160
+ return this.rest.request("POST", "/V1/carts/mine/items", {
161
+ cartItem: { ...item, quote_id: id }
162
+ });
163
+ }
164
+ return this.rest.request("POST", `/V1/guest-carts/${cartId}/items`, {
165
+ cartItem: { ...item, quote_id: id, quoteId: id }
166
+ });
167
+ },
168
+ updateItem: async (cartId, itemId, item, customerToken) => {
169
+ const id = cartId && !isNaN(Number(cartId)) ? Number(cartId) : cartId;
170
+ if (customerToken) {
171
+ return this.rest.request("PUT", `/V1/carts/mine/items/${itemId}`, {
172
+ cartItem: { ...item, item_id: itemId, quote_id: id }
173
+ });
174
+ }
175
+ return this.rest.request("PUT", `/V1/guest-carts/${cartId}/items/${itemId}`, {
176
+ cartItem: { ...item, item_id: itemId, quote_id: id, quoteId: id }
177
+ });
178
+ },
179
+ removeItem: async (cartId, itemId, customerToken) => {
180
+ if (customerToken) {
181
+ return this.rest.request("DELETE", `/V1/carts/mine/items/${itemId}`);
182
+ }
183
+ return this.rest.request("DELETE", `/V1/guest-carts/${cartId}/items/${itemId}`);
184
+ },
185
+ applyCoupon: async (cartId, couponCode, customerToken) => {
186
+ if (customerToken) {
187
+ return this.rest.request("PUT", `/V1/carts/mine/coupons/${encodeURIComponent(couponCode)}`);
188
+ }
189
+ return this.rest.request("PUT", `/V1/guest-carts/${cartId}/coupons/${encodeURIComponent(couponCode)}`);
190
+ },
191
+ removeCoupon: async (cartId, customerToken) => {
192
+ if (customerToken) {
193
+ return this.rest.request("DELETE", "/V1/carts/mine/coupons");
194
+ }
195
+ return this.rest.request("DELETE", `/V1/guest-carts/${cartId}/coupons`);
196
+ }
197
+ }
198
+ };
199
+ }
200
+ class MagentoAdminClient {
201
+ rest;
202
+ client;
203
+ constructor(config, context) {
204
+ this.rest = new MagentoRest(config.baseUrl, config.storeCode, async () => {
205
+ const headers = {};
206
+ const token = config.adminApiKey ?? "";
207
+ if (token)
208
+ headers["Authorization"] = `Bearer ${token}`;
209
+ return headers;
210
+ });
211
+ this.client = new Magento(this.rest, new RequestContextTokenStore(context));
212
+ if (debug.enabled)
213
+ debug("MagentoAdminClient created");
214
+ }
215
+ async getClient() {
216
+ return this.client;
217
+ }
218
+ }
219
+ class MagentoClient {
220
+ constructor(config, context) {
221
+ this.config = config;
222
+ this.tokenStore = new RequestContextTokenStore(context);
223
+ this.client = void 0;
224
+ this.rest = new MagentoRest(this.config.baseUrl, this.config.storeCode, async () => {
225
+ const headers = {};
226
+ const customerToken = await this.tokenStore.getItem("customerToken");
227
+ if (customerToken) {
228
+ headers["Authorization"] = `Bearer ${customerToken}`;
229
+ return headers;
230
+ }
231
+ const adminToken = this.config.adminApiKey;
232
+ if (adminToken) {
233
+ headers["Authorization"] = `Bearer ${adminToken}`;
234
+ }
235
+ return headers;
236
+ });
237
+ if (debug.enabled)
238
+ debug("MagentoClient created");
239
+ }
240
+ tokenStore;
241
+ rest;
242
+ client;
243
+ async getClient() {
244
+ if (!this.client) {
245
+ this.client = Promise.resolve(
246
+ new Magento(this.rest, this.tokenStore)
247
+ );
248
+ }
249
+ return this.client;
250
+ }
251
+ async login(email, password) {
252
+ const client = await this.getClient();
253
+ return client.auth.login(email, password);
254
+ }
255
+ async logout() {
256
+ const client = await this.getClient();
257
+ return client.auth.logout();
258
+ }
259
+ async getMe() {
260
+ const client = await this.getClient();
261
+ return client.store.customer.me();
262
+ }
263
+ async register(customer, password) {
264
+ const client = await this.getClient();
265
+ return client.store.customer.register(customer, password);
266
+ }
267
+ async getProductBySKU(sku) {
268
+ const client = await this.getClient();
269
+ return client.store.product.getBySKU(sku);
270
+ }
271
+ async resolveProductForSKU(sku) {
272
+ return this.getProductBySKU(sku);
273
+ }
274
+ async createCart() {
275
+ const client = await this.getClient();
276
+ const customerToken = await this.tokenStore.getItem("customerToken");
277
+ return client.store.cart.create(customerToken);
278
+ }
279
+ async getCart(cartId) {
280
+ const client = await this.getClient();
281
+ const customerToken = await this.tokenStore.getItem("customerToken");
282
+ return client.store.cart.get(cartId, customerToken);
283
+ }
284
+ async getCartTotals(cartId) {
285
+ const client = await this.getClient();
286
+ const customerToken = await this.tokenStore.getItem("customerToken");
287
+ return client.store.cart.getTotals(cartId, customerToken);
288
+ }
289
+ async addItemToCart(cartId, item) {
290
+ const client = await this.getClient();
291
+ const customerToken = await this.tokenStore.getItem("customerToken");
292
+ return client.store.cart.addItem(cartId, item, customerToken);
293
+ }
294
+ async updateCartItem(cartId, itemId, item) {
295
+ const client = await this.getClient();
296
+ const customerToken = await this.tokenStore.getItem("customerToken");
297
+ return client.store.cart.updateItem(cartId, itemId, item, customerToken);
298
+ }
299
+ async removeCartItem(cartId, itemId) {
300
+ const client = await this.getClient();
301
+ const customerToken = await this.tokenStore.getItem("customerToken");
302
+ return client.store.cart.removeItem(cartId, itemId, customerToken);
303
+ }
304
+ async applyCoupon(cartId, couponCode) {
305
+ const client = await this.getClient();
306
+ const customerToken = await this.tokenStore.getItem("customerToken");
307
+ return client.store.cart.applyCoupon(cartId, couponCode, customerToken);
308
+ }
309
+ async removeCoupon(cartId) {
310
+ const client = await this.getClient();
311
+ const customerToken = await this.tokenStore.getItem("customerToken");
312
+ return client.store.cart.removeCoupon(cartId, customerToken);
313
+ }
314
+ }
315
+ export {
316
+ Magento,
317
+ MagentoAdminClient,
318
+ MagentoClient,
319
+ RequestContextTokenStore,
320
+ SESSION_KEY
321
+ };
@@ -0,0 +1,176 @@
1
+ import {
2
+ CartIdentifierSchema,
3
+ CartPaginatedSearchResultSchema,
4
+ CartSchema,
5
+ CategoryPaginatedResultSchema,
6
+ CategorySchema,
7
+ InventorySchema,
8
+ PriceSchema,
9
+ ProductSchema,
10
+ ProductSearchResultSchema
11
+ } from "@reactionary/core";
12
+ import { MagentoCartCapability } from "../capabilities/cart.capability.js";
13
+ import { MagentoCategoryCapability } from "../capabilities/category.capability.js";
14
+ import { MagentoIdentityCapability } from "../capabilities/identity.capability.js";
15
+ import { MagentoInventoryCapability } from "../capabilities/inventory.capability.js";
16
+ import { MagentoPriceCapability } from "../capabilities/price.capability.js";
17
+ import { MagentoProductSearchCapability } from "../capabilities/product-search.capability.js";
18
+ import { MagentoProductCapability } from "../capabilities/product.capability.js";
19
+ import {
20
+ MagentoCapabilitiesSchema
21
+ } from "../schema/capabilities.schema.js";
22
+ import {
23
+ MagentoConfigurationSchema
24
+ } from "../schema/configuration.schema.js";
25
+ import { MagentoClient } from "./client.js";
26
+ import {
27
+ MagentoCartFactory,
28
+ MagentoCategoryFactory,
29
+ MagentoInventoryFactory,
30
+ MagentoPriceFactory,
31
+ MagentoProductFactory,
32
+ MagentoProductSearchFactory
33
+ } from "../factories/index.js";
34
+ import {
35
+ resolveCapabilityWithFactory,
36
+ resolveDirectCapability
37
+ } from "./initialize.types.js";
38
+ function withMagentoCapabilities(configuration, capabilities) {
39
+ return (cache, context) => {
40
+ const client = {};
41
+ const config = MagentoConfigurationSchema.parse(configuration);
42
+ const caps = MagentoCapabilitiesSchema.parse(capabilities);
43
+ const magentoApi = new MagentoClient(config, context);
44
+ const buildCapabilityArgs = (factory) => ({
45
+ cache,
46
+ context,
47
+ config,
48
+ magentoApi,
49
+ factory
50
+ });
51
+ if (caps.product?.enabled) {
52
+ client.product = resolveCapabilityWithFactory(
53
+ capabilities.product,
54
+ {
55
+ factory: new MagentoProductFactory(ProductSchema, config),
56
+ capability: (args) => new MagentoProductCapability(
57
+ args.config,
58
+ args.cache,
59
+ args.context,
60
+ args.magentoApi,
61
+ args.factory
62
+ )
63
+ },
64
+ buildCapabilityArgs
65
+ );
66
+ }
67
+ if (caps.productSearch?.enabled) {
68
+ client.productSearch = resolveCapabilityWithFactory(
69
+ capabilities.productSearch,
70
+ {
71
+ factory: new MagentoProductSearchFactory(ProductSearchResultSchema, config),
72
+ capability: (args) => new MagentoProductSearchCapability(
73
+ args.config,
74
+ args.cache,
75
+ args.context,
76
+ args.magentoApi,
77
+ args.factory
78
+ )
79
+ },
80
+ buildCapabilityArgs
81
+ );
82
+ }
83
+ if (caps.category?.enabled) {
84
+ client.category = resolveCapabilityWithFactory(
85
+ capabilities.category,
86
+ {
87
+ factory: new MagentoCategoryFactory(
88
+ CategorySchema,
89
+ CategoryPaginatedResultSchema
90
+ ),
91
+ capability: (args) => new MagentoCategoryCapability(
92
+ args.config,
93
+ args.cache,
94
+ args.context,
95
+ args.magentoApi,
96
+ args.factory
97
+ )
98
+ },
99
+ buildCapabilityArgs
100
+ );
101
+ }
102
+ if (caps.cart?.enabled) {
103
+ client.cart = resolveCapabilityWithFactory(
104
+ capabilities.cart,
105
+ {
106
+ factory: new MagentoCartFactory(
107
+ CartSchema,
108
+ CartIdentifierSchema,
109
+ CartPaginatedSearchResultSchema
110
+ ),
111
+ capability: (args) => new MagentoCartCapability(
112
+ args.config,
113
+ args.cache,
114
+ args.context,
115
+ args.magentoApi,
116
+ args.factory
117
+ )
118
+ },
119
+ buildCapabilityArgs
120
+ );
121
+ }
122
+ if (caps.price?.enabled) {
123
+ client.price = resolveCapabilityWithFactory(
124
+ capabilities.price,
125
+ {
126
+ factory: new MagentoPriceFactory(PriceSchema),
127
+ capability: (args) => new MagentoPriceCapability(
128
+ args.config,
129
+ args.cache,
130
+ args.context,
131
+ args.magentoApi,
132
+ args.factory
133
+ )
134
+ },
135
+ buildCapabilityArgs
136
+ );
137
+ }
138
+ if (caps.inventory?.enabled) {
139
+ client.inventory = resolveCapabilityWithFactory(
140
+ capabilities.inventory,
141
+ {
142
+ factory: new MagentoInventoryFactory(InventorySchema),
143
+ capability: (args) => new MagentoInventoryCapability(
144
+ args.config,
145
+ args.cache,
146
+ args.context,
147
+ args.magentoApi,
148
+ args.factory
149
+ )
150
+ },
151
+ buildCapabilityArgs
152
+ );
153
+ }
154
+ if (caps.identity?.enabled) {
155
+ client.identity = resolveDirectCapability(
156
+ capabilities.identity,
157
+ (args) => new MagentoIdentityCapability(
158
+ args.config,
159
+ args.cache,
160
+ args.context,
161
+ args.magentoApi
162
+ ),
163
+ {
164
+ cache,
165
+ context,
166
+ config,
167
+ magentoApi
168
+ }
169
+ );
170
+ }
171
+ return client;
172
+ };
173
+ }
174
+ export {
175
+ withMagentoCapabilities
176
+ };
@@ -0,0 +1,13 @@
1
+ function resolveCapabilityWithFactory(capability, defaults, buildCapabilityArgs) {
2
+ const factory = capability?.factory ?? defaults.factory;
3
+ const capabilityFactory = capability?.capability ?? defaults.capability;
4
+ return capabilityFactory(buildCapabilityArgs(factory));
5
+ }
6
+ function resolveDirectCapability(capability, defaultCapability, args) {
7
+ const capabilityFactory = capability?.capability ?? defaultCapability;
8
+ return capabilityFactory(args);
9
+ }
10
+ export {
11
+ resolveCapabilityWithFactory,
12
+ resolveDirectCapability
13
+ };
@@ -0,0 +1,135 @@
1
+ import {
2
+ ProductVariantIdentifierSchema
3
+ } from "@reactionary/core";
4
+ import { MagentoCartIdentifierSchema } from "../../schema/magento.schema.js";
5
+ class MagentoCartFactory {
6
+ cartSchema;
7
+ cartIdentifierSchema;
8
+ cartPaginatedSearchResultSchema;
9
+ constructor(cartSchema, cartIdentifierSchema, cartPaginatedSearchResultSchema) {
10
+ this.cartSchema = cartSchema;
11
+ this.cartIdentifierSchema = cartIdentifierSchema;
12
+ this.cartPaginatedSearchResultSchema = cartPaginatedSearchResultSchema;
13
+ }
14
+ parseCart(_context, data) {
15
+ const requestedId = data._requestedId;
16
+ const currency = data.quote_currency_code || "USD";
17
+ const cost = this.parseCostBreakdown(data, currency);
18
+ const items = (data.items || []).map((item) => this.parseCartItem(item, currency));
19
+ let identifierKey = data.masked_id;
20
+ if (!identifierKey && requestedId && isNaN(Number(requestedId))) {
21
+ identifierKey = requestedId;
22
+ }
23
+ if (!identifierKey) {
24
+ identifierKey = String(data.id || "");
25
+ }
26
+ const result = {
27
+ identifier: {
28
+ key: String(identifierKey || "")
29
+ },
30
+ user: {
31
+ userId: String(data.customer?.id || "")
32
+ },
33
+ items,
34
+ price: cost,
35
+ appliedPromotions: [],
36
+ name: data.name || "",
37
+ description: data.description || ""
38
+ };
39
+ return this.cartSchema.parse(result);
40
+ }
41
+ parseCartIdentifier(_context, data) {
42
+ const result = MagentoCartIdentifierSchema.parse({
43
+ key: String(data.id || data.masked_id || "")
44
+ });
45
+ return this.cartIdentifierSchema.parse(result);
46
+ }
47
+ parseCartPaginatedSearchResult(_context, data, query) {
48
+ const result = {
49
+ identifier: query.search,
50
+ items: data.items.map((item) => this.parseCartSearchResultItem(_context, item)),
51
+ totalCount: data.totalCount,
52
+ pageNumber: query.search.paginationOptions.pageNumber,
53
+ pageSize: query.search.paginationOptions.pageSize,
54
+ totalPages: Math.ceil(data.totalCount / query.search.paginationOptions.pageSize)
55
+ };
56
+ return this.cartPaginatedSearchResultSchema.parse(result);
57
+ }
58
+ parseCartSearchResultItem(context, data) {
59
+ const cart = this.parseCart(context, data);
60
+ return {
61
+ identifier: cart.identifier,
62
+ user: cart.user,
63
+ numItems: cart.items.length,
64
+ name: cart.name,
65
+ lastModifiedDate: data.updated_at ?? ""
66
+ };
67
+ }
68
+ parseCostBreakdown(cart, currency) {
69
+ return {
70
+ totalProductPrice: {
71
+ value: cart.subtotal ?? cart.base_subtotal ?? 0,
72
+ currency
73
+ },
74
+ grandTotal: {
75
+ value: cart.grand_total ?? cart.base_grand_total ?? 0,
76
+ currency
77
+ },
78
+ totalTax: {
79
+ value: cart.tax_amount ?? cart.base_tax_amount ?? 0,
80
+ currency
81
+ },
82
+ totalShipping: {
83
+ value: cart.shipping_amount ?? cart.base_shipping_amount ?? 0,
84
+ currency
85
+ },
86
+ totalDiscount: {
87
+ value: Math.abs(cart.discount_amount ?? cart.base_discount_amount ?? 0),
88
+ currency
89
+ },
90
+ totalSurcharge: {
91
+ value: 0,
92
+ currency
93
+ }
94
+ };
95
+ }
96
+ parseItemPrice(item, currency) {
97
+ const qty = item.qty ?? 0;
98
+ return {
99
+ unitPrice: {
100
+ value: item.price ?? 0,
101
+ currency
102
+ },
103
+ unitDiscount: {
104
+ value: item.discount_amount ? Math.abs(item.discount_amount / (qty || 1)) : 0,
105
+ currency
106
+ },
107
+ totalPrice: {
108
+ value: item.row_total !== void 0 ? item.row_total : (item.price || 0) * (qty || 0),
109
+ currency
110
+ },
111
+ totalDiscount: {
112
+ value: Math.abs(item.discount_amount || 0),
113
+ currency
114
+ }
115
+ };
116
+ }
117
+ parseCartItem(item, currency) {
118
+ return {
119
+ identifier: {
120
+ key: String(item.item_id)
121
+ },
122
+ product: {
123
+ key: item.sku
124
+ },
125
+ variant: ProductVariantIdentifierSchema.parse({
126
+ sku: item.sku
127
+ }),
128
+ quantity: item.qty,
129
+ price: this.parseItemPrice(item, currency)
130
+ };
131
+ }
132
+ }
133
+ export {
134
+ MagentoCartFactory
135
+ };
@@ -0,0 +1,48 @@
1
+ import {
2
+ CategoryIdentifierSchema
3
+ } from "@reactionary/core";
4
+ class MagentoCategoryFactory {
5
+ categorySchema;
6
+ categoryPaginatedResultSchema;
7
+ constructor(categorySchema, categoryPaginatedResultSchema) {
8
+ this.categorySchema = categorySchema;
9
+ this.categoryPaginatedResultSchema = categoryPaginatedResultSchema;
10
+ }
11
+ parseCategory(_context, data) {
12
+ const identifier = CategoryIdentifierSchema.parse({
13
+ key: String(data.custom_attributes?.find((a) => a.attribute_code === "external_id")?.value || data.id)
14
+ });
15
+ const name = data.name || "";
16
+ const urlKeyAttr = data.custom_attributes?.find((a) => a.attribute_code === "url_key");
17
+ const slug = urlKeyAttr ? String(urlKeyAttr.value) : "";
18
+ const textAttr = data.custom_attributes?.find((a) => a.attribute_code === "description");
19
+ const text = textAttr ? String(textAttr.value) : name;
20
+ const parentCategoryStr = String(data.parent_id || "");
21
+ const parentCategory = parentCategoryStr && parentCategoryStr !== "0" ? { key: parentCategoryStr } : void 0;
22
+ const result = {
23
+ identifier,
24
+ name,
25
+ slug,
26
+ text,
27
+ parentCategory,
28
+ images: []
29
+ };
30
+ return this.categorySchema.parse(result);
31
+ }
32
+ parseCategoryPaginatedResult(context, data) {
33
+ const items = (data.items || []).map((c) => this.parseCategory(context, c));
34
+ const totalCount = data.total_count ?? 0;
35
+ const totalPages = Math.max(1, Math.ceil(totalCount / data.pageSize));
36
+ const result = {
37
+ pageNumber: data.currentPage,
38
+ pageSize: data.pageSize,
39
+ totalCount,
40
+ totalPages,
41
+ items
42
+ };
43
+ return this.categoryPaginatedResultSchema.parse(result);
44
+ }
45
+ }
46
+ export {
47
+ MagentoCategoryFactory
48
+ };
@@ -0,0 +1,12 @@
1
+ class MagentoIdentityFactory {
2
+ identitySchema;
3
+ constructor(identitySchema) {
4
+ this.identitySchema = identitySchema;
5
+ }
6
+ parseIdentity(_context, data) {
7
+ return this.identitySchema.parse(data);
8
+ }
9
+ }
10
+ export {
11
+ MagentoIdentityFactory
12
+ };