@reactionary/provider-commercetools 0.3.13 → 0.3.15
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/core/initialize.js +10 -1
- package/index.js +1 -0
- package/package.json +2 -2
- package/providers/index.js +1 -0
- package/providers/product-associations.provider.js +164 -0
- package/providers/product.provider.js +6 -1
- package/schema/capabilities.schema.js +1 -0
- package/src/index.d.ts +1 -0
- package/src/providers/index.d.ts +1 -0
- package/src/providers/product-associations.provider.d.ts +24 -0
- package/src/schema/capabilities.schema.d.ts +1 -0
package/core/initialize.js
CHANGED
|
@@ -17,7 +17,8 @@ import {
|
|
|
17
17
|
CommercetoolsOrderSearchProvider,
|
|
18
18
|
CommercetoolsProfileProvider,
|
|
19
19
|
CommercetoolsStoreProvider,
|
|
20
|
-
CommercetoolsProductReviewsProvider
|
|
20
|
+
CommercetoolsProductReviewsProvider,
|
|
21
|
+
CommercetoolsProductAssociationsProvider
|
|
21
22
|
} from "../providers/index.js";
|
|
22
23
|
import { CommercetoolsAPI } from "./client.js";
|
|
23
24
|
function withCommercetoolsCapabilities(configuration, capabilities) {
|
|
@@ -50,6 +51,14 @@ function withCommercetoolsCapabilities(configuration, capabilities) {
|
|
|
50
51
|
commercetoolsApi
|
|
51
52
|
);
|
|
52
53
|
}
|
|
54
|
+
if (caps.productAssociations) {
|
|
55
|
+
client.productAssociations = new CommercetoolsProductAssociationsProvider(
|
|
56
|
+
config,
|
|
57
|
+
cache,
|
|
58
|
+
context,
|
|
59
|
+
commercetoolsApi
|
|
60
|
+
);
|
|
61
|
+
}
|
|
53
62
|
if (caps.productReviews) {
|
|
54
63
|
client.productReviews = new CommercetoolsProductReviewsProvider(
|
|
55
64
|
config,
|
package/index.js
CHANGED
|
@@ -5,6 +5,7 @@ export * from "./providers/identity.provider.js";
|
|
|
5
5
|
export * from "./providers/inventory.provider.js";
|
|
6
6
|
export * from "./providers/order-search.provider.js";
|
|
7
7
|
export * from "./providers/price.provider.js";
|
|
8
|
+
export * from "./providers/product-associations.provider.js";
|
|
8
9
|
export * from "./providers/product.provider.js";
|
|
9
10
|
export * from "./providers/product-reviews.provider.js";
|
|
10
11
|
export * from "./providers/product-search.provider.js";
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reactionary/provider-commercetools",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.15",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"types": "src/index.d.ts",
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@reactionary/core": "0.3.
|
|
7
|
+
"@reactionary/core": "0.3.15",
|
|
8
8
|
"debug": "^4.4.3",
|
|
9
9
|
"zod": "4.1.9",
|
|
10
10
|
"@commercetools/ts-client": "^4.2.1",
|
package/providers/index.js
CHANGED
|
@@ -4,6 +4,7 @@ export * from "./identity.provider.js";
|
|
|
4
4
|
export * from "./inventory.provider.js";
|
|
5
5
|
export * from "./order-search.provider.js";
|
|
6
6
|
export * from "./price.provider.js";
|
|
7
|
+
export * from "./product-associations.provider.js";
|
|
7
8
|
export * from "./product.provider.js";
|
|
8
9
|
export * from "./product-reviews.provider.js";
|
|
9
10
|
export * from "./profile.provider.js";
|
|
@@ -0,0 +1,164 @@
|
|
|
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
|
+
ProductAssociationsProvider,
|
|
14
|
+
Reactionary,
|
|
15
|
+
ImageSchema,
|
|
16
|
+
ProductVariantOptionSchema,
|
|
17
|
+
ProductOptionIdentifierSchema,
|
|
18
|
+
ProductSearchResultItemVariantSchema,
|
|
19
|
+
ProductVariantIdentifierSchema,
|
|
20
|
+
success,
|
|
21
|
+
error
|
|
22
|
+
} from "@reactionary/core";
|
|
23
|
+
class CommercetoolsProductAssociationsProvider extends ProductAssociationsProvider {
|
|
24
|
+
constructor(config, cache, context, commercetools) {
|
|
25
|
+
super(cache, context);
|
|
26
|
+
this.config = config;
|
|
27
|
+
this.commercetools = commercetools;
|
|
28
|
+
}
|
|
29
|
+
async getClient() {
|
|
30
|
+
const client = await this.commercetools.getClient();
|
|
31
|
+
return client.withProjectKey({ projectKey: this.config.projectKey });
|
|
32
|
+
}
|
|
33
|
+
async fetchAssociatedProductsFor(productKey, maxNumberOfAssociations, attributeName) {
|
|
34
|
+
const client = await this.getClient();
|
|
35
|
+
const product = await client.productProjections().withKey({ key: productKey.key }).get().execute().catch((e) => {
|
|
36
|
+
if (e.statusCode === 404) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
throw e;
|
|
40
|
+
});
|
|
41
|
+
if (!product || !product.body) {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
const associatedProducts = [];
|
|
45
|
+
const associationsAttr = product.body.attributes.find((attr) => attr.name === attributeName);
|
|
46
|
+
if (!associationsAttr) {
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
const associatedProductSearchItems = [];
|
|
50
|
+
const allAssociatedProductPromises = associationsAttr.value.map(async (associatedProductId) => {
|
|
51
|
+
const associatedProduct = client.productProjections().withKey({ key: associatedProductId }).get().execute().catch(() => null);
|
|
52
|
+
return associatedProduct;
|
|
53
|
+
});
|
|
54
|
+
const associatedProductsResults = await Promise.all(allAssociatedProductPromises);
|
|
55
|
+
const validAssociatedProductsResults = associatedProductsResults.filter((result) => !!result).slice(0, maxNumberOfAssociations);
|
|
56
|
+
for (const associatedProductResult of validAssociatedProductsResults) {
|
|
57
|
+
const resultItem = this.parseSingle(associatedProductResult.body);
|
|
58
|
+
if (resultItem) {
|
|
59
|
+
associatedProductSearchItems.push(resultItem);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return associatedProductSearchItems;
|
|
63
|
+
}
|
|
64
|
+
parseSingle(body) {
|
|
65
|
+
const identifier = { key: body.id };
|
|
66
|
+
const name = body.name[this.context.languageContext.locale] || body.id;
|
|
67
|
+
const slug = body.slug?.[this.context.languageContext.locale] || body.id;
|
|
68
|
+
const variants = [body.masterVariant, ...body.variants].map(
|
|
69
|
+
(variant) => this.parseVariant(variant, body)
|
|
70
|
+
);
|
|
71
|
+
const product = {
|
|
72
|
+
identifier,
|
|
73
|
+
name,
|
|
74
|
+
slug,
|
|
75
|
+
variants
|
|
76
|
+
};
|
|
77
|
+
return product;
|
|
78
|
+
}
|
|
79
|
+
async getAccessories(query) {
|
|
80
|
+
const associatedProducts = await this.fetchAssociatedProductsFor(query.forProduct, query.numberOfAccessories || 4, "reactionaryaccessories");
|
|
81
|
+
const result = associatedProducts.map((product) => ({
|
|
82
|
+
associationIdentifier: {
|
|
83
|
+
key: `${query.forProduct.key}-accessory-${product.identifier.key}`
|
|
84
|
+
},
|
|
85
|
+
associationReturnType: "productSearchResultItem",
|
|
86
|
+
product
|
|
87
|
+
}));
|
|
88
|
+
return success(result);
|
|
89
|
+
}
|
|
90
|
+
async getSpareparts(query) {
|
|
91
|
+
const associatedProducts = await this.fetchAssociatedProductsFor(query.forProduct, query.numberOfSpareparts || 4, "reactionaryspareparts");
|
|
92
|
+
const result = associatedProducts.map((product) => ({
|
|
93
|
+
associationIdentifier: {
|
|
94
|
+
key: `${query.forProduct.key}-sparepart-${product.identifier.key}`
|
|
95
|
+
},
|
|
96
|
+
associationReturnType: "productSearchResultItem",
|
|
97
|
+
product
|
|
98
|
+
}));
|
|
99
|
+
return success(result);
|
|
100
|
+
}
|
|
101
|
+
async getReplacements(query) {
|
|
102
|
+
const associatedProducts = await this.fetchAssociatedProductsFor(query.forProduct, query.numberOfReplacements || 4, "reactionaryreplacements");
|
|
103
|
+
const result = associatedProducts.map((product) => ({
|
|
104
|
+
associationIdentifier: {
|
|
105
|
+
key: `${query.forProduct.key}-replacement-${product.identifier.key}`
|
|
106
|
+
},
|
|
107
|
+
associationReturnType: "productSearchResultItem",
|
|
108
|
+
product
|
|
109
|
+
}));
|
|
110
|
+
return success(result);
|
|
111
|
+
}
|
|
112
|
+
parseVariant(variant, product) {
|
|
113
|
+
const sourceImage = variant.images?.[0];
|
|
114
|
+
const img = ImageSchema.parse({
|
|
115
|
+
sourceUrl: sourceImage?.url || "",
|
|
116
|
+
height: sourceImage?.dimensions.h || void 0,
|
|
117
|
+
width: sourceImage?.dimensions.w || void 0,
|
|
118
|
+
altText: sourceImage?.label || product.name[this.context.languageContext.locale] || void 0
|
|
119
|
+
});
|
|
120
|
+
const mappedOptions = variant.attributes?.filter((x) => x.name === "Color").map(
|
|
121
|
+
(opt) => ProductVariantOptionSchema.parse({
|
|
122
|
+
identifier: ProductOptionIdentifierSchema.parse({
|
|
123
|
+
key: opt.name
|
|
124
|
+
}),
|
|
125
|
+
name: opt.value || ""
|
|
126
|
+
})
|
|
127
|
+
) || [];
|
|
128
|
+
const mappedOption = mappedOptions?.[0];
|
|
129
|
+
return ProductSearchResultItemVariantSchema.parse({
|
|
130
|
+
variant: ProductVariantIdentifierSchema.parse({
|
|
131
|
+
sku: variant.sku || ""
|
|
132
|
+
}),
|
|
133
|
+
image: img,
|
|
134
|
+
options: mappedOption
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
__decorateClass([
|
|
139
|
+
Reactionary({
|
|
140
|
+
cache: true,
|
|
141
|
+
cacheTimeToLiveInSeconds: 300,
|
|
142
|
+
currencyDependentCaching: false,
|
|
143
|
+
localeDependentCaching: false
|
|
144
|
+
})
|
|
145
|
+
], CommercetoolsProductAssociationsProvider.prototype, "getAccessories", 1);
|
|
146
|
+
__decorateClass([
|
|
147
|
+
Reactionary({
|
|
148
|
+
cache: true,
|
|
149
|
+
cacheTimeToLiveInSeconds: 300,
|
|
150
|
+
currencyDependentCaching: false,
|
|
151
|
+
localeDependentCaching: false
|
|
152
|
+
})
|
|
153
|
+
], CommercetoolsProductAssociationsProvider.prototype, "getSpareparts", 1);
|
|
154
|
+
__decorateClass([
|
|
155
|
+
Reactionary({
|
|
156
|
+
cache: true,
|
|
157
|
+
cacheTimeToLiveInSeconds: 300,
|
|
158
|
+
currencyDependentCaching: false,
|
|
159
|
+
localeDependentCaching: false
|
|
160
|
+
})
|
|
161
|
+
], CommercetoolsProductAssociationsProvider.prototype, "getReplacements", 1);
|
|
162
|
+
export {
|
|
163
|
+
CommercetoolsProductAssociationsProvider
|
|
164
|
+
};
|
|
@@ -80,7 +80,12 @@ class CommercetoolsProductProvider extends ProductProvider {
|
|
|
80
80
|
description = data.description[this.context.languageContext.locale];
|
|
81
81
|
}
|
|
82
82
|
const variantLevelAttributes = data.masterVariant.attributes?.map((x) => this.parseAttribute(x)) || [];
|
|
83
|
-
const
|
|
83
|
+
const specialAttributes = [
|
|
84
|
+
"reactionaryaccessories",
|
|
85
|
+
"reactionaryspareparts",
|
|
86
|
+
"reactionaryreplacements"
|
|
87
|
+
];
|
|
88
|
+
const productLevelAttributes = data.attributes.filter((x) => !specialAttributes.includes(x.name)).map((x) => this.parseAttribute(x)) || [];
|
|
84
89
|
const sharedAttributes = [
|
|
85
90
|
...productLevelAttributes,
|
|
86
91
|
...variantLevelAttributes
|
package/src/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export * from './providers/identity.provider.js';
|
|
|
5
5
|
export * from './providers/inventory.provider.js';
|
|
6
6
|
export * from './providers/order-search.provider.js';
|
|
7
7
|
export * from './providers/price.provider.js';
|
|
8
|
+
export * from './providers/product-associations.provider.js';
|
|
8
9
|
export * from './providers/product.provider.js';
|
|
9
10
|
export * from './providers/product-reviews.provider.js';
|
|
10
11
|
export * from './providers/product-search.provider.js';
|
package/src/providers/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export * from './identity.provider.js';
|
|
|
4
4
|
export * from './inventory.provider.js';
|
|
5
5
|
export * from './order-search.provider.js';
|
|
6
6
|
export * from './price.provider.js';
|
|
7
|
+
export * from './product-associations.provider.js';
|
|
7
8
|
export * from './product.provider.js';
|
|
8
9
|
export * from './product-reviews.provider.js';
|
|
9
10
|
export * from './profile.provider.js';
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ProductAssociationsProvider } from '@reactionary/core';
|
|
2
|
+
import type { ProductIdentifier, ProductAssociation, ProductSearchResultItem, ProductSearchResultItemVariant, ProductAssociationsGetAccessoriesQuery, ProductAssociationsGetSparepartsQuery, ProductAssociationsGetReplacementsQuery, Result, RequestContext, Cache } from '@reactionary/core';
|
|
3
|
+
import type { ProductProjection, ProductVariant as CTProductVariant } from '@commercetools/platform-sdk';
|
|
4
|
+
import type { CommercetoolsConfiguration } from '../schema/configuration.schema.js';
|
|
5
|
+
import type { CommercetoolsAPI } from '../core/client.js';
|
|
6
|
+
export declare class CommercetoolsProductAssociationsProvider extends ProductAssociationsProvider {
|
|
7
|
+
protected config: CommercetoolsConfiguration;
|
|
8
|
+
protected commercetools: CommercetoolsAPI;
|
|
9
|
+
constructor(config: CommercetoolsConfiguration, cache: Cache, context: RequestContext, commercetools: CommercetoolsAPI);
|
|
10
|
+
protected getClient(): Promise<import("@commercetools/platform-sdk").ByProjectKeyRequestBuilder>;
|
|
11
|
+
protected fetchAssociatedProductsFor(productKey: ProductIdentifier, maxNumberOfAssociations: number, attributeName: string): Promise<ProductSearchResultItem[]>;
|
|
12
|
+
protected parseSingle(body: ProductProjection): {
|
|
13
|
+
identifier: {
|
|
14
|
+
key: string;
|
|
15
|
+
};
|
|
16
|
+
name: string;
|
|
17
|
+
slug: string;
|
|
18
|
+
variants: ProductSearchResultItemVariant[];
|
|
19
|
+
};
|
|
20
|
+
getAccessories(query: ProductAssociationsGetAccessoriesQuery): Promise<Result<ProductAssociation[]>>;
|
|
21
|
+
getSpareparts(query: ProductAssociationsGetSparepartsQuery): Promise<Result<ProductAssociation[]>>;
|
|
22
|
+
getReplacements(query: ProductAssociationsGetReplacementsQuery): Promise<Result<ProductAssociation[]>>;
|
|
23
|
+
protected parseVariant(variant: CTProductVariant, product: ProductProjection): ProductSearchResultItemVariant;
|
|
24
|
+
}
|
|
@@ -11,6 +11,7 @@ export declare const CommercetoolsCapabilitiesSchema: z.ZodObject<{
|
|
|
11
11
|
profile: z.ZodOptional<z.ZodBoolean>;
|
|
12
12
|
store: z.ZodOptional<z.ZodBoolean>;
|
|
13
13
|
productSearch: z.ZodOptional<z.ZodBoolean>;
|
|
14
|
+
productAssociations: z.ZodOptional<z.ZodBoolean>;
|
|
14
15
|
productReviews: z.ZodOptional<z.ZodBoolean>;
|
|
15
16
|
orderSearch: z.ZodOptional<z.ZodBoolean>;
|
|
16
17
|
}, z.core.$loose>;
|