@reactionary/commercetools 0.6.3
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/README.md +11 -0
- package/capabilities/cart.capability.js +324 -0
- package/capabilities/category.capability.js +198 -0
- package/capabilities/checkout.capability.js +374 -0
- package/capabilities/identity.capability.js +95 -0
- package/capabilities/index.js +15 -0
- package/capabilities/inventory.capability.js +63 -0
- package/capabilities/order-search.capability.js +106 -0
- package/capabilities/order.capability.js +48 -0
- package/capabilities/price.capability.js +114 -0
- package/capabilities/product-associations.capability.js +120 -0
- package/capabilities/product-list.capability.js +393 -0
- package/capabilities/product-reviews.capability.js +193 -0
- package/capabilities/product-search.capability.js +297 -0
- package/capabilities/product.capability.js +103 -0
- package/capabilities/profile.capability.js +337 -0
- package/capabilities/store.capability.js +51 -0
- package/core/capability-descriptors.js +274 -0
- package/core/client.js +318 -0
- package/core/initialize.js +47 -0
- package/core/initialize.types.js +8 -0
- package/core/token-cache.js +36 -0
- package/factories/cart/cart.factory.js +110 -0
- package/factories/category/category.factory.js +40 -0
- package/factories/checkout/checkout-initializer-overrides.example.js +67 -0
- package/factories/checkout/checkout.factory.js +235 -0
- package/factories/identity/identity.factory.js +14 -0
- package/factories/inventory/inventory.factory.js +30 -0
- package/factories/order/order.factory.js +114 -0
- package/factories/order-search/order-search.factory.js +68 -0
- package/factories/price/price.factory.js +52 -0
- package/factories/product/product-capability-custom-method-only.example.js +38 -0
- package/factories/product/product-capability-schema-signature-extension.example.js +46 -0
- package/factories/product/product-factory-baseline.example.js +10 -0
- package/factories/product/product-factory-schema-and-parse-extension.example.js +25 -0
- package/factories/product/product-factory-schema-extension.example.js +18 -0
- package/factories/product/product-initializer-factory-extension.example.js +33 -0
- package/factories/product/product.factory.js +151 -0
- package/factories/product/utils.example.js +8 -0
- package/factories/product-associations/product-associations.factory.js +63 -0
- package/factories/product-list/product-list.factory.js +65 -0
- package/factories/product-reviews/product-reviews.factory.js +42 -0
- package/factories/product-search/product-search.factory.js +114 -0
- package/factories/profile/profile.factory.js +62 -0
- package/factories/store/store.factory.js +29 -0
- package/index.js +28 -0
- package/package.json +17 -0
- package/schema/capabilities.schema.js +46 -0
- package/schema/commercetools.schema.js +30 -0
- package/schema/configuration.schema.js +19 -0
- package/schema/session.schema.js +9 -0
- package/src/capabilities/cart.capability.d.ts +34 -0
- package/src/capabilities/category.capability.d.ts +47 -0
- package/src/capabilities/checkout.capability.d.ts +39 -0
- package/src/capabilities/identity.capability.d.ts +14 -0
- package/src/capabilities/index.d.ts +15 -0
- package/src/capabilities/inventory.capability.d.ts +13 -0
- package/src/capabilities/order-search.capability.d.ts +13 -0
- package/src/capabilities/order.capability.d.ts +13 -0
- package/src/capabilities/price.capability.d.ts +18 -0
- package/src/capabilities/product-associations.capability.d.ts +17 -0
- package/src/capabilities/product-list.capability.d.ts +29 -0
- package/src/capabilities/product-reviews.capability.d.ts +18 -0
- package/src/capabilities/product-search.capability.d.ts +82 -0
- package/src/capabilities/product.capability.d.ts +17 -0
- package/src/capabilities/profile.capability.d.ts +30 -0
- package/src/capabilities/store.capability.d.ts +13 -0
- package/src/core/capability-descriptors.d.ts +16 -0
- package/src/core/client.d.ts +55 -0
- package/src/core/initialize.d.ts +5 -0
- package/src/core/initialize.types.d.ts +118 -0
- package/src/core/token-cache.d.ts +9 -0
- package/src/factories/cart/cart.factory.d.ts +14 -0
- package/src/factories/category/category.factory.d.ts +11 -0
- package/src/factories/checkout/checkout-initializer-overrides.example.d.ts +1 -0
- package/src/factories/checkout/checkout.factory.d.ts +18 -0
- package/src/factories/identity/identity.factory.d.ts +8 -0
- package/src/factories/inventory/inventory.factory.d.ts +9 -0
- package/src/factories/order/order.factory.d.ts +9 -0
- package/src/factories/order-search/order-search.factory.d.ts +11 -0
- package/src/factories/price/price.factory.d.ts +11 -0
- package/src/factories/product/product-capability-custom-method-only.example.d.ts +1 -0
- package/src/factories/product/product-capability-schema-signature-extension.example.d.ts +1 -0
- package/src/factories/product/product-factory-baseline.example.d.ts +1 -0
- package/src/factories/product/product-factory-schema-and-parse-extension.example.d.ts +1 -0
- package/src/factories/product/product-factory-schema-extension.example.d.ts +1 -0
- package/src/factories/product/product-initializer-factory-extension.example.d.ts +1 -0
- package/src/factories/product/product.factory.d.ts +18 -0
- package/src/factories/product/utils.example.d.ts +4 -0
- package/src/factories/product-associations/product-associations.factory.d.ts +15 -0
- package/src/factories/product-list/product-list.factory.d.ts +17 -0
- package/src/factories/product-reviews/product-reviews.factory.d.ts +14 -0
- package/src/factories/product-search/product-search.factory.d.ts +13 -0
- package/src/factories/profile/profile.factory.d.ts +11 -0
- package/src/factories/store/store.factory.d.ts +9 -0
- package/src/index.d.ts +28 -0
- package/src/schema/capabilities.schema.d.ts +104 -0
- package/src/schema/commercetools.schema.d.ts +30 -0
- package/src/schema/configuration.schema.d.ts +30 -0
- package/src/schema/session.schema.d.ts +7 -0
- package/src/test/client-builder-merge-extensions.example.d.ts +1 -0
- package/src/test/test-utils.d.ts +27 -0
- package/test/client-builder-merge-extensions.example.js +94 -0
- package/test/test-utils.js +27 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ImageSchema,
|
|
3
|
+
ProductAttributeIdentifierSchema,
|
|
4
|
+
ProductAttributeSchema,
|
|
5
|
+
ProductAttributeValueIdentifierSchema,
|
|
6
|
+
ProductAttributeValueSchema
|
|
7
|
+
} from "@reactionary/core";
|
|
8
|
+
class CommercetoolsProductFactory {
|
|
9
|
+
productSchema;
|
|
10
|
+
// PAIN: not being able to assign a default for productSchema (productSchema: TProductSchema = ProductSchema)
|
|
11
|
+
// because it will invalidate TS' conservative instantiation-point generics
|
|
12
|
+
// PAIN: consider whether we can pass in request context here
|
|
13
|
+
constructor(productSchema) {
|
|
14
|
+
this.productSchema = productSchema;
|
|
15
|
+
}
|
|
16
|
+
parseProduct(context, data) {
|
|
17
|
+
const identifier = { key: data.key || data.id };
|
|
18
|
+
const name = data.name[context.languageContext.locale];
|
|
19
|
+
const slug = data.slug[context.languageContext.locale];
|
|
20
|
+
let description = "";
|
|
21
|
+
if (data.description) {
|
|
22
|
+
description = data.description[context.languageContext.locale];
|
|
23
|
+
}
|
|
24
|
+
const variantLevelAttributes = data.masterVariant.attributes?.map(
|
|
25
|
+
(x) => this.parseAttribute(context, x)
|
|
26
|
+
) || [];
|
|
27
|
+
const specialAttributes = [
|
|
28
|
+
"reactionaryaccessories",
|
|
29
|
+
"reactionaryspareparts",
|
|
30
|
+
"reactionaryreplacements"
|
|
31
|
+
];
|
|
32
|
+
const productLevelAttributes = data.attributes.filter((x) => !specialAttributes.includes(x.name)).map((x) => this.parseAttribute(context, x)) || [];
|
|
33
|
+
const sharedAttributes = [
|
|
34
|
+
...productLevelAttributes,
|
|
35
|
+
...variantLevelAttributes
|
|
36
|
+
];
|
|
37
|
+
const mainVariant = this.parseVariant(context, data.masterVariant, data);
|
|
38
|
+
const otherVariants = [];
|
|
39
|
+
for (const variant of data.variants || []) {
|
|
40
|
+
if (variant.id !== data.masterVariant.id) {
|
|
41
|
+
otherVariants.push(this.parseVariant(context, variant, data));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const result = {
|
|
45
|
+
identifier,
|
|
46
|
+
name,
|
|
47
|
+
slug,
|
|
48
|
+
description,
|
|
49
|
+
sharedAttributes,
|
|
50
|
+
mainVariant,
|
|
51
|
+
brand: "",
|
|
52
|
+
longDescription: "",
|
|
53
|
+
manufacturer: "",
|
|
54
|
+
options: [],
|
|
55
|
+
parentCategories: [],
|
|
56
|
+
published: true,
|
|
57
|
+
variants: otherVariants
|
|
58
|
+
};
|
|
59
|
+
return this.productSchema.parse(result);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Return true, if the attribute is a defining attribute (ie an option)
|
|
63
|
+
* @param attr a variant attribute
|
|
64
|
+
* @returns true if the attribute is an option
|
|
65
|
+
*/
|
|
66
|
+
isVariantAttributeAnOption(attr) {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
parseVariant(context, variant, product) {
|
|
70
|
+
const identifier = {
|
|
71
|
+
sku: variant.sku
|
|
72
|
+
};
|
|
73
|
+
const images = [
|
|
74
|
+
...(variant.images || []).map(
|
|
75
|
+
(img) => ImageSchema.parse({
|
|
76
|
+
sourceUrl: img.url,
|
|
77
|
+
altText: img.label || "",
|
|
78
|
+
width: img.dimensions?.w,
|
|
79
|
+
height: img.dimensions?.h
|
|
80
|
+
})
|
|
81
|
+
)
|
|
82
|
+
];
|
|
83
|
+
const options = (variant.attributes ?? []).filter((attr) => this.isVariantAttributeAnOption(attr)).map((attr) => {
|
|
84
|
+
const attrVal = this.parseAttributeValue(context, attr);
|
|
85
|
+
const optionIdentifier = {
|
|
86
|
+
key: attr.name
|
|
87
|
+
};
|
|
88
|
+
const option = {
|
|
89
|
+
identifier: optionIdentifier,
|
|
90
|
+
name: attr.name,
|
|
91
|
+
value: {
|
|
92
|
+
identifier: {
|
|
93
|
+
key: attrVal.value,
|
|
94
|
+
option: optionIdentifier
|
|
95
|
+
},
|
|
96
|
+
label: attrVal.label
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
return option;
|
|
100
|
+
}) || [];
|
|
101
|
+
const result = {
|
|
102
|
+
identifier,
|
|
103
|
+
images,
|
|
104
|
+
barcode: "",
|
|
105
|
+
ean: "",
|
|
106
|
+
gtin: "",
|
|
107
|
+
name: product.name[context.languageContext.locale],
|
|
108
|
+
options,
|
|
109
|
+
upc: ""
|
|
110
|
+
};
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
parseAttribute(context, attr) {
|
|
114
|
+
const result = ProductAttributeSchema.parse({
|
|
115
|
+
identifier: ProductAttributeIdentifierSchema.parse({
|
|
116
|
+
key: attr.name
|
|
117
|
+
}),
|
|
118
|
+
group: "",
|
|
119
|
+
name: attr.name,
|
|
120
|
+
values: [this.parseAttributeValue(context, attr)]
|
|
121
|
+
});
|
|
122
|
+
return result;
|
|
123
|
+
}
|
|
124
|
+
parseAttributeValue(context, attr) {
|
|
125
|
+
let attrValue = "";
|
|
126
|
+
if (attr.value && Array.isArray(attr.value)) {
|
|
127
|
+
attrValue = attr.value[0];
|
|
128
|
+
}
|
|
129
|
+
if (attr.value && typeof attr.value === "object") {
|
|
130
|
+
if (context.languageContext.locale in attr.value) {
|
|
131
|
+
attrValue = attr.value[context.languageContext.locale];
|
|
132
|
+
} else {
|
|
133
|
+
attrValue = "-";
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (typeof attr.value === "string") {
|
|
137
|
+
attrValue = attr.value;
|
|
138
|
+
}
|
|
139
|
+
const attrVal = ProductAttributeValueSchema.parse({
|
|
140
|
+
identifier: ProductAttributeValueIdentifierSchema.parse({
|
|
141
|
+
key: attrValue
|
|
142
|
+
}),
|
|
143
|
+
value: String(attrValue),
|
|
144
|
+
label: String(attrValue)
|
|
145
|
+
});
|
|
146
|
+
return attrVal;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
export {
|
|
150
|
+
CommercetoolsProductFactory
|
|
151
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ImageSchema,
|
|
3
|
+
ProductOptionIdentifierSchema,
|
|
4
|
+
ProductSearchResultItemVariantSchema,
|
|
5
|
+
ProductVariantIdentifierSchema,
|
|
6
|
+
ProductVariantOptionSchema
|
|
7
|
+
} from "@reactionary/core";
|
|
8
|
+
class CommercetoolsProductAssociationsFactory {
|
|
9
|
+
productAssociationSchema;
|
|
10
|
+
constructor(productAssociationSchema) {
|
|
11
|
+
this.productAssociationSchema = productAssociationSchema;
|
|
12
|
+
}
|
|
13
|
+
parseAssociation(context, data) {
|
|
14
|
+
const product = this.parseSearchResultItem(context, data.product);
|
|
15
|
+
const result = {
|
|
16
|
+
associationIdentifier: {
|
|
17
|
+
key: `${data.sourceProductKey}-${data.relation}-${product.identifier.key}`
|
|
18
|
+
},
|
|
19
|
+
associationReturnType: "productSearchResultItem",
|
|
20
|
+
product
|
|
21
|
+
};
|
|
22
|
+
return this.productAssociationSchema.parse(result);
|
|
23
|
+
}
|
|
24
|
+
parseSearchResultItem(context, data) {
|
|
25
|
+
const variants = [data.masterVariant, ...data.variants].map(
|
|
26
|
+
(variant) => this.parseVariant(context, variant, data)
|
|
27
|
+
);
|
|
28
|
+
return {
|
|
29
|
+
identifier: { key: data.id },
|
|
30
|
+
name: data.name[context.languageContext.locale] || data.id,
|
|
31
|
+
slug: data.slug?.[context.languageContext.locale] || data.id,
|
|
32
|
+
variants
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
parseVariant(context, variant, product) {
|
|
36
|
+
const sourceImage = variant.images?.[0];
|
|
37
|
+
const image = ImageSchema.parse({
|
|
38
|
+
sourceUrl: sourceImage?.url || "",
|
|
39
|
+
height: sourceImage?.dimensions.h || void 0,
|
|
40
|
+
width: sourceImage?.dimensions.w || void 0,
|
|
41
|
+
altText: sourceImage?.label || product.name[context.languageContext.locale] || void 0
|
|
42
|
+
});
|
|
43
|
+
const mappedOptions = variant.attributes?.filter((attribute) => attribute.name === "Color").map(
|
|
44
|
+
(option) => ProductVariantOptionSchema.parse({
|
|
45
|
+
identifier: ProductOptionIdentifierSchema.parse({
|
|
46
|
+
key: option.name
|
|
47
|
+
}),
|
|
48
|
+
name: option.value || ""
|
|
49
|
+
})
|
|
50
|
+
) || [];
|
|
51
|
+
const mappedOption = mappedOptions?.[0];
|
|
52
|
+
return ProductSearchResultItemVariantSchema.parse({
|
|
53
|
+
variant: ProductVariantIdentifierSchema.parse({
|
|
54
|
+
sku: variant.sku || ""
|
|
55
|
+
}),
|
|
56
|
+
image,
|
|
57
|
+
options: mappedOption
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
export {
|
|
62
|
+
CommercetoolsProductAssociationsFactory
|
|
63
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import {
|
|
2
|
+
} from "@reactionary/core";
|
|
3
|
+
class CommercetoolsProductListFactory {
|
|
4
|
+
productListSchema;
|
|
5
|
+
productListItemSchema;
|
|
6
|
+
productListPaginatedSchema;
|
|
7
|
+
productListItemPaginatedSchema;
|
|
8
|
+
constructor(productListSchema, productListItemSchema, productListPaginatedSchema, productListItemPaginatedSchema) {
|
|
9
|
+
this.productListSchema = productListSchema;
|
|
10
|
+
this.productListItemSchema = productListItemSchema;
|
|
11
|
+
this.productListPaginatedSchema = productListPaginatedSchema;
|
|
12
|
+
this.productListItemPaginatedSchema = productListItemPaginatedSchema;
|
|
13
|
+
}
|
|
14
|
+
parseProductList(_context, data) {
|
|
15
|
+
return this.productListSchema.parse(data);
|
|
16
|
+
}
|
|
17
|
+
parseProductListItem(_context, data) {
|
|
18
|
+
return this.productListItemSchema.parse(data);
|
|
19
|
+
}
|
|
20
|
+
parseProductListPaginatedResult(_context, data) {
|
|
21
|
+
return this.productListPaginatedSchema.parse(data);
|
|
22
|
+
}
|
|
23
|
+
parseProductListItemPaginatedResult(_context, data) {
|
|
24
|
+
return this.productListItemPaginatedSchema.parse(data);
|
|
25
|
+
}
|
|
26
|
+
parseListFromCommercetools(list) {
|
|
27
|
+
const listType = list.custom?.fields["listType"] || "favorite";
|
|
28
|
+
const image = list.custom?.fields["imageUrl"];
|
|
29
|
+
const published = list.custom?.fields["published"] && true;
|
|
30
|
+
const publishDateValue = list.custom?.fields["publishedDate"];
|
|
31
|
+
const publishDate = publishDateValue ? new Date(publishDateValue).toISOString() : void 0;
|
|
32
|
+
return this.productListSchema.parse({
|
|
33
|
+
identifier: {
|
|
34
|
+
listType,
|
|
35
|
+
key: list.id
|
|
36
|
+
},
|
|
37
|
+
type: listType,
|
|
38
|
+
name: list.name["en"] || "Unnamed List",
|
|
39
|
+
description: list.description?.["en"] || "",
|
|
40
|
+
published,
|
|
41
|
+
publishDate,
|
|
42
|
+
image: {
|
|
43
|
+
sourceUrl: image || "",
|
|
44
|
+
altText: list.name["en"] || "List Image"
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
parseListItemFromCommercetools(listIdentifier, lineItem) {
|
|
49
|
+
return this.productListItemSchema.parse({
|
|
50
|
+
identifier: {
|
|
51
|
+
list: listIdentifier,
|
|
52
|
+
key: lineItem.id
|
|
53
|
+
},
|
|
54
|
+
variant: {
|
|
55
|
+
sku: lineItem.variant?.sku || ""
|
|
56
|
+
},
|
|
57
|
+
quantity: lineItem.quantity,
|
|
58
|
+
notes: lineItem.custom?.fields["notes"] || "",
|
|
59
|
+
order: lineItem.custom?.fields["order"] || 1
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
export {
|
|
64
|
+
CommercetoolsProductListFactory
|
|
65
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import {
|
|
2
|
+
} from "@reactionary/core";
|
|
3
|
+
class CommercetoolsProductReviewsFactory {
|
|
4
|
+
ratingSummarySchema;
|
|
5
|
+
reviewSchema;
|
|
6
|
+
reviewPaginatedSchema;
|
|
7
|
+
constructor(ratingSummarySchema, reviewSchema, reviewPaginatedSchema) {
|
|
8
|
+
this.ratingSummarySchema = ratingSummarySchema;
|
|
9
|
+
this.reviewSchema = reviewSchema;
|
|
10
|
+
this.reviewPaginatedSchema = reviewPaginatedSchema;
|
|
11
|
+
}
|
|
12
|
+
parseRatingSummary(_context, data) {
|
|
13
|
+
return this.ratingSummarySchema.parse(data);
|
|
14
|
+
}
|
|
15
|
+
parseReview(_context, data) {
|
|
16
|
+
return this.reviewSchema.parse(data);
|
|
17
|
+
}
|
|
18
|
+
parseReviewPaginatedResult(_context, data) {
|
|
19
|
+
return this.reviewPaginatedSchema.parse(data);
|
|
20
|
+
}
|
|
21
|
+
parseReviewFromCommercetools(_context, review, productKey) {
|
|
22
|
+
return this.reviewSchema.parse({
|
|
23
|
+
identifier: {
|
|
24
|
+
key: review.key || ""
|
|
25
|
+
},
|
|
26
|
+
product: {
|
|
27
|
+
key: productKey
|
|
28
|
+
},
|
|
29
|
+
authorName: review.authorName ?? "Anonymous",
|
|
30
|
+
authorId: review.customer?.id,
|
|
31
|
+
rating: review.rating ?? 0,
|
|
32
|
+
title: review.title ?? "",
|
|
33
|
+
content: review.text ?? "",
|
|
34
|
+
createdAt: review.createdAt,
|
|
35
|
+
updatedAt: review.lastModifiedAt,
|
|
36
|
+
verified: !!review.customer
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export {
|
|
41
|
+
CommercetoolsProductReviewsFactory
|
|
42
|
+
};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FacetIdentifierSchema,
|
|
3
|
+
FacetValueIdentifierSchema,
|
|
4
|
+
ImageSchema,
|
|
5
|
+
ProductOptionIdentifierSchema,
|
|
6
|
+
ProductSearchResultFacetSchema,
|
|
7
|
+
ProductSearchResultFacetValueSchema,
|
|
8
|
+
ProductSearchResultItemVariantSchema,
|
|
9
|
+
ProductVariantIdentifierSchema,
|
|
10
|
+
ProductVariantOptionSchema
|
|
11
|
+
} from "@reactionary/core";
|
|
12
|
+
class CommercetoolsProductSearchFactory {
|
|
13
|
+
productSearchResultSchema;
|
|
14
|
+
constructor(productSearchResultSchema) {
|
|
15
|
+
this.productSearchResultSchema = productSearchResultSchema;
|
|
16
|
+
}
|
|
17
|
+
parseSearchResult(context, data, query) {
|
|
18
|
+
const identifier = {
|
|
19
|
+
...query.search
|
|
20
|
+
};
|
|
21
|
+
const items = data.results.map(
|
|
22
|
+
(product) => this.parseSingle(context, product.productProjection)
|
|
23
|
+
);
|
|
24
|
+
const facets = [];
|
|
25
|
+
for (const facet of data.facets) {
|
|
26
|
+
const facetIdentifier = FacetIdentifierSchema.parse({
|
|
27
|
+
key: facet.name
|
|
28
|
+
});
|
|
29
|
+
const candidateFacet = this.parseFacet(facetIdentifier, facet);
|
|
30
|
+
if (candidateFacet.values.length > 0) {
|
|
31
|
+
facets.push(candidateFacet);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const result = {
|
|
35
|
+
identifier,
|
|
36
|
+
pageNumber: (Math.ceil(data.offset / data.limit) || 0) + 1,
|
|
37
|
+
pageSize: data.limit,
|
|
38
|
+
totalCount: data.total || 0,
|
|
39
|
+
totalPages: Math.ceil((data.total || 0) / data.limit || 0) + 1,
|
|
40
|
+
items,
|
|
41
|
+
facets
|
|
42
|
+
};
|
|
43
|
+
return this.productSearchResultSchema.parse(result);
|
|
44
|
+
}
|
|
45
|
+
parseSingle(context, data) {
|
|
46
|
+
const identifier = { key: data.id };
|
|
47
|
+
const name = data.name[context.languageContext.locale] || data.id;
|
|
48
|
+
const slug = data.slug?.[context.languageContext.locale] || data.id;
|
|
49
|
+
const variants = [data.masterVariant, ...data.variants].map(
|
|
50
|
+
(variant) => this.parseVariant(context, variant, data)
|
|
51
|
+
);
|
|
52
|
+
const result = {
|
|
53
|
+
identifier,
|
|
54
|
+
name,
|
|
55
|
+
slug,
|
|
56
|
+
variants
|
|
57
|
+
};
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
parseFacet(facetIdentifier, facet) {
|
|
61
|
+
const result = ProductSearchResultFacetSchema.parse({
|
|
62
|
+
identifier: facetIdentifier,
|
|
63
|
+
name: facet.name,
|
|
64
|
+
values: []
|
|
65
|
+
});
|
|
66
|
+
const distinctFacet = facet;
|
|
67
|
+
for (const bucket of distinctFacet.buckets || []) {
|
|
68
|
+
const facetValueIdentifier = FacetValueIdentifierSchema.parse({
|
|
69
|
+
facet: facetIdentifier,
|
|
70
|
+
key: bucket.key
|
|
71
|
+
});
|
|
72
|
+
result.values.push(
|
|
73
|
+
this.parseFacetValue(facetValueIdentifier, bucket.key, bucket.count)
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
parseFacetValue(facetValueIdentifier, label, count) {
|
|
79
|
+
return ProductSearchResultFacetValueSchema.parse({
|
|
80
|
+
identifier: facetValueIdentifier,
|
|
81
|
+
name: label,
|
|
82
|
+
count,
|
|
83
|
+
active: false
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
parseVariant(context, variant, product) {
|
|
87
|
+
const sourceImage = variant.images?.[0];
|
|
88
|
+
const image = ImageSchema.parse({
|
|
89
|
+
sourceUrl: sourceImage?.url || "",
|
|
90
|
+
height: sourceImage?.dimensions.h || void 0,
|
|
91
|
+
width: sourceImage?.dimensions.w || void 0,
|
|
92
|
+
altText: sourceImage?.label || product.name[context.languageContext.locale] || void 0
|
|
93
|
+
});
|
|
94
|
+
const mappedOptions = variant.attributes?.filter((attribute) => attribute.name === "Color").map(
|
|
95
|
+
(option) => ProductVariantOptionSchema.parse({
|
|
96
|
+
identifier: ProductOptionIdentifierSchema.parse({
|
|
97
|
+
key: option.name
|
|
98
|
+
}),
|
|
99
|
+
name: option.value || ""
|
|
100
|
+
})
|
|
101
|
+
) || [];
|
|
102
|
+
const mappedOption = mappedOptions?.[0];
|
|
103
|
+
return ProductSearchResultItemVariantSchema.parse({
|
|
104
|
+
variant: ProductVariantIdentifierSchema.parse({
|
|
105
|
+
sku: variant.sku || ""
|
|
106
|
+
}),
|
|
107
|
+
image,
|
|
108
|
+
options: mappedOption
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
export {
|
|
113
|
+
CommercetoolsProductSearchFactory
|
|
114
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import {
|
|
2
|
+
} from "@reactionary/core";
|
|
3
|
+
class CommercetoolsProfileFactory {
|
|
4
|
+
profileSchema;
|
|
5
|
+
constructor(profileSchema) {
|
|
6
|
+
this.profileSchema = profileSchema;
|
|
7
|
+
}
|
|
8
|
+
parseProfile(_context, data) {
|
|
9
|
+
const email = data.email;
|
|
10
|
+
const emailVerified = data.isEmailVerified;
|
|
11
|
+
let defaultBilling = data.addresses.find((address) => address.id === data.defaultBillingAddressId);
|
|
12
|
+
const phone = defaultBilling?.phone ?? "";
|
|
13
|
+
if (this.isIncompleteAddress(defaultBilling)) {
|
|
14
|
+
defaultBilling = void 0;
|
|
15
|
+
}
|
|
16
|
+
const defaultShipping = data.addresses.find(
|
|
17
|
+
(address) => address.id === data.defaultShippingAddressId
|
|
18
|
+
);
|
|
19
|
+
const alternateShippingAddresses = data.addresses.filter((address) => address.id !== data.defaultBillingAddressId).filter((address) => address.id !== data.defaultShippingAddressId).map((address) => this.parseAddress(address));
|
|
20
|
+
const billingAddress = defaultBilling ? this.parseAddress(defaultBilling) : void 0;
|
|
21
|
+
const shippingAddress = defaultShipping ? this.parseAddress(defaultShipping) : void 0;
|
|
22
|
+
const result = {
|
|
23
|
+
identifier: {
|
|
24
|
+
userId: data.id
|
|
25
|
+
},
|
|
26
|
+
email,
|
|
27
|
+
emailVerified,
|
|
28
|
+
alternateShippingAddresses,
|
|
29
|
+
billingAddress,
|
|
30
|
+
shippingAddress,
|
|
31
|
+
createdAt: data.createdAt,
|
|
32
|
+
phone,
|
|
33
|
+
phoneVerified: false,
|
|
34
|
+
updatedAt: data.lastModifiedAt
|
|
35
|
+
};
|
|
36
|
+
return this.profileSchema.parse(result);
|
|
37
|
+
}
|
|
38
|
+
parseAddress(address) {
|
|
39
|
+
return {
|
|
40
|
+
identifier: {
|
|
41
|
+
nickName: address.key || ""
|
|
42
|
+
},
|
|
43
|
+
firstName: address.firstName || "",
|
|
44
|
+
lastName: address.lastName || "",
|
|
45
|
+
streetAddress: address.streetName || "",
|
|
46
|
+
streetNumber: address.streetNumber || "",
|
|
47
|
+
city: address.city || "",
|
|
48
|
+
region: address.region || "",
|
|
49
|
+
postalCode: address.postalCode || "",
|
|
50
|
+
countryCode: address.country
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
isIncompleteAddress(address) {
|
|
54
|
+
if (!address) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
return !address.firstName && !address.lastName && !address.streetName && !address.streetNumber && !address.city;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export {
|
|
61
|
+
CommercetoolsProfileFactory
|
|
62
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import {
|
|
2
|
+
} from "@reactionary/core";
|
|
3
|
+
class CommercetoolsStoreFactory {
|
|
4
|
+
storeSchema;
|
|
5
|
+
constructor(storeSchema) {
|
|
6
|
+
this.storeSchema = storeSchema;
|
|
7
|
+
}
|
|
8
|
+
parseStore(_context, data) {
|
|
9
|
+
let name = "";
|
|
10
|
+
if (data.name && data.name["la"]) {
|
|
11
|
+
name = data.name["la"];
|
|
12
|
+
}
|
|
13
|
+
const identifier = {
|
|
14
|
+
key: data.key || ""
|
|
15
|
+
};
|
|
16
|
+
const fulfillmentCenter = {
|
|
17
|
+
key: data.key || ""
|
|
18
|
+
};
|
|
19
|
+
const result = {
|
|
20
|
+
identifier,
|
|
21
|
+
fulfillmentCenter,
|
|
22
|
+
name
|
|
23
|
+
};
|
|
24
|
+
return this.storeSchema.parse(result);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export {
|
|
28
|
+
CommercetoolsStoreFactory
|
|
29
|
+
};
|
package/index.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export * from "./core/client.js";
|
|
2
|
+
export * from "./core/initialize.js";
|
|
3
|
+
export * from "./capabilities/cart.capability.js";
|
|
4
|
+
export * from "./capabilities/identity.capability.js";
|
|
5
|
+
export * from "./capabilities/inventory.capability.js";
|
|
6
|
+
export * from "./capabilities/order-search.capability.js";
|
|
7
|
+
export * from "./capabilities/price.capability.js";
|
|
8
|
+
export * from "./capabilities/product-associations.capability.js";
|
|
9
|
+
export * from "./capabilities/product.capability.js";
|
|
10
|
+
export * from "./capabilities/product-reviews.capability.js";
|
|
11
|
+
export * from "./capabilities/product-search.capability.js";
|
|
12
|
+
export * from "./factories/product/product.factory.js";
|
|
13
|
+
export * from "./factories/checkout/checkout.factory.js";
|
|
14
|
+
export * from "./factories/product-search/product-search.factory.js";
|
|
15
|
+
export * from "./factories/inventory/inventory.factory.js";
|
|
16
|
+
export * from "./factories/price/price.factory.js";
|
|
17
|
+
export * from "./factories/store/store.factory.js";
|
|
18
|
+
export * from "./factories/order/order.factory.js";
|
|
19
|
+
export * from "./factories/category/category.factory.js";
|
|
20
|
+
export * from "./factories/cart/cart.factory.js";
|
|
21
|
+
export * from "./factories/profile/profile.factory.js";
|
|
22
|
+
export * from "./factories/order-search/order-search.factory.js";
|
|
23
|
+
export * from "./factories/product-associations/product-associations.factory.js";
|
|
24
|
+
export * from "./factories/product-reviews/product-reviews.factory.js";
|
|
25
|
+
export * from "./factories/product-list/product-list.factory.js";
|
|
26
|
+
export * from "./factories/identity/identity.factory.js";
|
|
27
|
+
export * from "./schema/capabilities.schema.js";
|
|
28
|
+
export * from "./schema/configuration.schema.js";
|
package/package.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@reactionary/commercetools",
|
|
3
|
+
"version": "0.6.3",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./index.js",
|
|
6
|
+
"types": "./src/index.d.ts",
|
|
7
|
+
"dependencies": {
|
|
8
|
+
"vitest": "^4.0.9",
|
|
9
|
+
"@nx/vite": "22.4.5",
|
|
10
|
+
"@reactionary/core": "0.6.3",
|
|
11
|
+
"zod": "4.1.9",
|
|
12
|
+
"@commercetools/ts-client": "^4.9.1",
|
|
13
|
+
"@commercetools/platform-sdk": "^8.25.0",
|
|
14
|
+
"debug": "^4.4.3"
|
|
15
|
+
},
|
|
16
|
+
"sideEffects": false
|
|
17
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { CapabilitiesSchema } from "@reactionary/core";
|
|
2
|
+
import * as z from "zod";
|
|
3
|
+
const EnabledCapabilitySchema = z.looseObject({
|
|
4
|
+
enabled: z.boolean()
|
|
5
|
+
});
|
|
6
|
+
const OverridableCapabilitySchema = z.looseObject({
|
|
7
|
+
enabled: z.boolean(),
|
|
8
|
+
factory: z.unknown().optional(),
|
|
9
|
+
capability: z.unknown().optional()
|
|
10
|
+
});
|
|
11
|
+
const CommercetoolsCapabilitiesSchema = CapabilitiesSchema.pick({
|
|
12
|
+
product: true,
|
|
13
|
+
productSearch: true,
|
|
14
|
+
productAssociations: true,
|
|
15
|
+
productReviews: true,
|
|
16
|
+
productList: true,
|
|
17
|
+
identity: true,
|
|
18
|
+
cart: true,
|
|
19
|
+
checkout: true,
|
|
20
|
+
order: true,
|
|
21
|
+
orderSearch: true,
|
|
22
|
+
inventory: true,
|
|
23
|
+
price: true,
|
|
24
|
+
category: true,
|
|
25
|
+
store: true,
|
|
26
|
+
profile: true
|
|
27
|
+
}).extend({
|
|
28
|
+
productSearch: EnabledCapabilitySchema.optional(),
|
|
29
|
+
productAssociations: EnabledCapabilitySchema.optional(),
|
|
30
|
+
productReviews: EnabledCapabilitySchema.optional(),
|
|
31
|
+
productList: EnabledCapabilitySchema.optional(),
|
|
32
|
+
identity: EnabledCapabilitySchema.optional(),
|
|
33
|
+
cart: EnabledCapabilitySchema.optional(),
|
|
34
|
+
order: EnabledCapabilitySchema.optional(),
|
|
35
|
+
orderSearch: EnabledCapabilitySchema.optional(),
|
|
36
|
+
inventory: EnabledCapabilitySchema.optional(),
|
|
37
|
+
price: EnabledCapabilitySchema.optional(),
|
|
38
|
+
category: EnabledCapabilitySchema.optional(),
|
|
39
|
+
store: EnabledCapabilitySchema.optional(),
|
|
40
|
+
profile: EnabledCapabilitySchema.optional(),
|
|
41
|
+
product: OverridableCapabilitySchema.optional(),
|
|
42
|
+
checkout: OverridableCapabilitySchema.optional()
|
|
43
|
+
}).partial();
|
|
44
|
+
export {
|
|
45
|
+
CommercetoolsCapabilitiesSchema
|
|
46
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { BaseModelSchema, CartIdentifierSchema, CategoryIdentifierSchema, CheckoutIdentifierSchema, OrderIdentifierSchema } from "@reactionary/core";
|
|
2
|
+
import * as z from "zod";
|
|
3
|
+
const CommercetoolsCartIdentifierSchema = CartIdentifierSchema.extend({
|
|
4
|
+
version: z.number().default(0)
|
|
5
|
+
});
|
|
6
|
+
const CommercetoolsOrderIdentifierSchema = OrderIdentifierSchema.extend({
|
|
7
|
+
version: z.number().default(0)
|
|
8
|
+
});
|
|
9
|
+
const CommercetoolsCheckoutIdentifierSchema = CheckoutIdentifierSchema.extend({
|
|
10
|
+
version: z.number().default(0)
|
|
11
|
+
});
|
|
12
|
+
const CommercetoolsResolveCategoryQueryByKeySchema = z.object({
|
|
13
|
+
key: z.string().meta({ description: "The key of the category to resolve." })
|
|
14
|
+
});
|
|
15
|
+
const CommercetoolsResolveCategoryQueryByIdSchema = z.object({
|
|
16
|
+
id: z.string().meta({ description: "The ID of the category to resolve." })
|
|
17
|
+
});
|
|
18
|
+
const CommercetoolsCategoryLookupSchema = BaseModelSchema.extend({
|
|
19
|
+
id: z.string(),
|
|
20
|
+
key: z.string().optional(),
|
|
21
|
+
name: z.record(z.string(), z.string())
|
|
22
|
+
});
|
|
23
|
+
export {
|
|
24
|
+
CommercetoolsCartIdentifierSchema,
|
|
25
|
+
CommercetoolsCategoryLookupSchema,
|
|
26
|
+
CommercetoolsCheckoutIdentifierSchema,
|
|
27
|
+
CommercetoolsOrderIdentifierSchema,
|
|
28
|
+
CommercetoolsResolveCategoryQueryByIdSchema,
|
|
29
|
+
CommercetoolsResolveCategoryQueryByKeySchema
|
|
30
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
import { PaymentMethodSchema } from "@reactionary/core";
|
|
3
|
+
const CommercetoolsConfigurationSchema = z.looseObject({
|
|
4
|
+
projectKey: z.string(),
|
|
5
|
+
authUrl: z.string(),
|
|
6
|
+
apiUrl: z.string(),
|
|
7
|
+
clientId: z.string(),
|
|
8
|
+
clientSecret: z.string(),
|
|
9
|
+
scopes: z.array(z.string()).default(() => []),
|
|
10
|
+
adminClientId: z.string().optional(),
|
|
11
|
+
adminClientSecret: z.string().optional(),
|
|
12
|
+
paymentMethods: PaymentMethodSchema.array().optional().default(() => []),
|
|
13
|
+
facetFieldsForSearch: z.array(z.string()).default(() => []),
|
|
14
|
+
listPriceChannelKey: z.string().optional(),
|
|
15
|
+
customerPriceChannelKey: z.string().optional()
|
|
16
|
+
});
|
|
17
|
+
export {
|
|
18
|
+
CommercetoolsConfigurationSchema
|
|
19
|
+
};
|