@reactionary/provider-commercetools 0.0.59 → 0.0.61
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 +30 -3
- package/core/client.js +1 -1
- package/core/initialize.js +6 -5
- package/index.js +1 -1
- package/package.json +2 -2
- package/providers/cart.provider.js +2 -2
- package/providers/checkout.provider.js +1 -1
- package/providers/index.js +1 -1
- package/providers/inventory.provider.js +2 -2
- package/providers/order.provider.js +1 -1
- package/providers/price.provider.js +5 -5
- package/providers/product-search.provider.js +123 -0
- package/providers/product.provider.js +62 -18
- package/schema/capabilities.schema.js +1 -1
- package/src/core/initialize.d.ts +3 -3
- package/src/index.d.ts +1 -1
- package/src/providers/index.d.ts +1 -1
- package/src/providers/product-search.provider.d.ts +31 -0
- package/src/providers/product.provider.d.ts +6 -2
- package/src/schema/capabilities.schema.d.ts +1 -1
- package/providers/search.provider.js +0 -48
- package/src/providers/search.provider.d.ts +0 -11
package/README.md
CHANGED
|
@@ -1,6 +1,33 @@
|
|
|
1
|
-
# provider
|
|
1
|
+
# Commmercetools provider for Reactionary
|
|
2
|
+
|
|
3
|
+
## Supports
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
| Feature | Support | Notes |
|
|
7
|
+
| ----------- | ----------- | --------- |
|
|
8
|
+
| product | Full | |
|
|
9
|
+
| productSearch | Full | |
|
|
10
|
+
| identity | Full | |
|
|
11
|
+
| cart | Full | |
|
|
12
|
+
| checkout | Full | |
|
|
13
|
+
| order | Full | |
|
|
14
|
+
| inventory | Full | |
|
|
15
|
+
| price | Full | |
|
|
16
|
+
| category | Full | |
|
|
17
|
+
| store | Full | |
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
## Notes
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
2
30
|
|
|
3
|
-
This library was generated with [Nx](https://nx.dev).
|
|
4
31
|
|
|
5
32
|
## Building
|
|
6
33
|
|
|
@@ -11,7 +38,7 @@ Run `nx build provider-commercetools` to build the library.
|
|
|
11
38
|
Run `nx test provider-commercetools` to execute the unit tests via [Jest](https://jestjs.io).
|
|
12
39
|
|
|
13
40
|
|
|
14
|
-
|
|
41
|
+
## Assumptions for backend config
|
|
15
42
|
|
|
16
43
|
- You will have 2 different channels for prices, one called `Offer Price` and one called `List Price`
|
|
17
44
|
- ProductVariants will all have unique SKU values.
|
package/core/client.js
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
} from "@reactionary/core";
|
|
11
11
|
import * as crypto from "crypto";
|
|
12
12
|
import createDebug from "debug";
|
|
13
|
-
const debug = createDebug("commercetools
|
|
13
|
+
const debug = createDebug("reactionary:commercetools");
|
|
14
14
|
class RequestContextTokenCache {
|
|
15
15
|
constructor(context) {
|
|
16
16
|
this.context = context;
|
package/core/initialize.js
CHANGED
|
@@ -4,11 +4,12 @@ import {
|
|
|
4
4
|
InventorySchema,
|
|
5
5
|
PriceSchema,
|
|
6
6
|
ProductSchema,
|
|
7
|
-
|
|
7
|
+
ProductSearchResultSchema,
|
|
8
8
|
CategorySchema,
|
|
9
|
-
CheckoutSchema
|
|
9
|
+
CheckoutSchema,
|
|
10
|
+
ProductSearchResultItemSchema
|
|
10
11
|
} from "@reactionary/core";
|
|
11
|
-
import { CommercetoolsSearchProvider } from "../providers/search.provider.js";
|
|
12
|
+
import { CommercetoolsSearchProvider } from "../providers/product-search.provider.js";
|
|
12
13
|
import { CommercetoolsProductProvider } from "../providers/product.provider.js";
|
|
13
14
|
import { CommercetoolsIdentityProvider } from "../providers/identity.provider.js";
|
|
14
15
|
import { CommercetoolsCartProvider } from "../providers/cart.provider.js";
|
|
@@ -22,8 +23,8 @@ function withCommercetoolsCapabilities(configuration, capabilities) {
|
|
|
22
23
|
if (capabilities.product) {
|
|
23
24
|
client.product = new CommercetoolsProductProvider(configuration, ProductSchema, cache);
|
|
24
25
|
}
|
|
25
|
-
if (capabilities.
|
|
26
|
-
client.
|
|
26
|
+
if (capabilities.productSearch) {
|
|
27
|
+
client.productSearch = new CommercetoolsSearchProvider(configuration, ProductSearchResultItemSchema, cache);
|
|
27
28
|
}
|
|
28
29
|
if (capabilities.identity) {
|
|
29
30
|
client.identity = new CommercetoolsIdentityProvider(configuration, IdentitySchema, cache);
|
package/index.js
CHANGED
|
@@ -5,6 +5,6 @@ export * from "./providers/identity.provider.js";
|
|
|
5
5
|
export * from "./providers/inventory.provider.js";
|
|
6
6
|
export * from "./providers/price.provider.js";
|
|
7
7
|
export * from "./providers/product.provider.js";
|
|
8
|
-
export * from "./providers/search.provider.js";
|
|
8
|
+
export * from "./providers/product-search.provider.js";
|
|
9
9
|
export * from "./schema/capabilities.schema.js";
|
|
10
10
|
export * from "./schema/configuration.schema.js";
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reactionary/provider-commercetools",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.61",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"types": "src/index.d.ts",
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@reactionary/core": "0.0.
|
|
7
|
+
"@reactionary/core": "0.0.61",
|
|
8
8
|
"debug": "^4.4.3",
|
|
9
9
|
"zod": "4.1.9",
|
|
10
10
|
"@commercetools/ts-client": "^4.2.1",
|
|
@@ -34,7 +34,7 @@ class CommercetoolsCartProvider extends CartProvider {
|
|
|
34
34
|
{
|
|
35
35
|
action: "addLineItem",
|
|
36
36
|
quantity: payload.quantity,
|
|
37
|
-
sku: payload.sku
|
|
37
|
+
sku: payload.variant.sku
|
|
38
38
|
},
|
|
39
39
|
{
|
|
40
40
|
action: "recalculate"
|
|
@@ -346,7 +346,7 @@ class CommercetoolsCartProvider extends CartProvider {
|
|
|
346
346
|
const item = CartItemSchema.parse({});
|
|
347
347
|
item.identifier.key = remoteItem.id;
|
|
348
348
|
item.product.key = remoteItem.productId;
|
|
349
|
-
item.sku
|
|
349
|
+
item.variant.sku = remoteItem.variant.sku || "";
|
|
350
350
|
item.quantity = remoteItem.quantity;
|
|
351
351
|
const unitPrice = remoteItem.price.value.centAmount;
|
|
352
352
|
const totalPrice = remoteItem.totalPrice.centAmount || 0;
|
|
@@ -378,7 +378,7 @@ class CommercetoolsCheckoutProvider extends CheckoutProvider {
|
|
|
378
378
|
for (const remoteItem of remote.lineItems) {
|
|
379
379
|
const item = CheckoutItemSchema.parse({});
|
|
380
380
|
item.identifier.key = remoteItem.id;
|
|
381
|
-
item.sku
|
|
381
|
+
item.variant.sku = remoteItem.variant.sku || "";
|
|
382
382
|
item.quantity = remoteItem.quantity;
|
|
383
383
|
const unitPrice = remoteItem.price.value.centAmount;
|
|
384
384
|
const totalPrice = remoteItem.totalPrice.centAmount || 0;
|
package/providers/index.js
CHANGED
|
@@ -5,7 +5,7 @@ export * from "./inventory.provider.js";
|
|
|
5
5
|
export * from "./price.provider.js";
|
|
6
6
|
export * from "./product.provider.js";
|
|
7
7
|
export * from "./profile.provider.js";
|
|
8
|
-
export * from "./search.provider.js";
|
|
8
|
+
export * from "./product-search.provider.js";
|
|
9
9
|
export * from "./store.provider.js";
|
|
10
10
|
export * from "./order.provider.js";
|
|
11
11
|
export * from "./checkout.provider.js";
|
|
@@ -16,7 +16,7 @@ class CommercetoolsInventoryProvider extends InventoryProvider {
|
|
|
16
16
|
const remote = await client.withProjectKey({ projectKey: this.config.projectKey }).inventory().get({
|
|
17
17
|
queryArgs: {
|
|
18
18
|
where: "sku=:sku AND supplyChannel(id=:channel)",
|
|
19
|
-
"var.sku": payload.sku
|
|
19
|
+
"var.sku": payload.variant.sku,
|
|
20
20
|
"var.channel": channelId,
|
|
21
21
|
expand: "supplyChannel"
|
|
22
22
|
}
|
|
@@ -28,7 +28,7 @@ class CommercetoolsInventoryProvider extends InventoryProvider {
|
|
|
28
28
|
parseSingle(body, reqCtx) {
|
|
29
29
|
const model = this.newModel();
|
|
30
30
|
model.identifier = {
|
|
31
|
-
|
|
31
|
+
variant: { sku: body.sku || "" },
|
|
32
32
|
fulfillmentCenter: {
|
|
33
33
|
key: body.supplyChannel?.obj?.key || ""
|
|
34
34
|
}
|
|
@@ -77,7 +77,7 @@ class CommercetoolsOrderProvider extends OrderProvider {
|
|
|
77
77
|
for (const remoteItem of remote.lineItems) {
|
|
78
78
|
const item = OrderItemSchema.parse({});
|
|
79
79
|
item.identifier.key = remoteItem.id;
|
|
80
|
-
item.sku
|
|
80
|
+
item.variant.sku = remoteItem.variant.sku || "";
|
|
81
81
|
item.quantity = remoteItem.quantity;
|
|
82
82
|
const unitPrice = remoteItem.price.value.centAmount;
|
|
83
83
|
const totalPrice = remoteItem.totalPrice.centAmount || 0;
|
|
@@ -23,16 +23,16 @@ class CommercetoolsPriceProvider extends PriceProvider {
|
|
|
23
23
|
priceCurrency: reqCtx.languageContext.currencyCode,
|
|
24
24
|
// storeProjection: reqCtx.storeIdentifier?.key || undefined,
|
|
25
25
|
where: "variants(sku in (:skus)) OR (masterVariant(sku in (:skus))) ",
|
|
26
|
-
"var.skus": payload.map((p) => p.sku
|
|
26
|
+
"var.skus": payload.map((p) => p.variant.sku),
|
|
27
27
|
limit: payload.length
|
|
28
28
|
}
|
|
29
29
|
}).execute();
|
|
30
30
|
const result = [];
|
|
31
31
|
const allReturnedVariants = [...response.body.results.map((x) => x.variants).flat(), ...response.body.results.map((x) => x.masterVariant).flat()];
|
|
32
32
|
for (const p of payload) {
|
|
33
|
-
const foundSku = allReturnedVariants.find((v) => v.sku === p.sku
|
|
33
|
+
const foundSku = allReturnedVariants.find((v) => v.sku === p.variant.sku);
|
|
34
34
|
if (!foundSku) {
|
|
35
|
-
result.push(this.createEmptyPriceResult(p.sku
|
|
35
|
+
result.push(this.createEmptyPriceResult(p.variant.sku, reqCtx.languageContext.currencyCode));
|
|
36
36
|
} else {
|
|
37
37
|
result.push(this.parseSingle(foundSku, reqCtx));
|
|
38
38
|
}
|
|
@@ -66,8 +66,8 @@ class CommercetoolsPriceProvider extends PriceProvider {
|
|
|
66
66
|
base.tieredPrices = p;
|
|
67
67
|
}
|
|
68
68
|
base.identifier = {
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
variant: {
|
|
70
|
+
sku: body.sku
|
|
71
71
|
}
|
|
72
72
|
};
|
|
73
73
|
base.meta = {
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { createPaginatedResponseSchema, FacetIdentifierSchema, FacetValueIdentifierSchema, ImageSchema, ProductOptionIdentifierSchema, ProductSearchProvider, ProductSearchResultFacetSchema, ProductSearchResultFacetValueSchema, ProductSearchResultItemVariantSchema, ProductVariantIdentifierSchema, ProductVariantOptionSchema } from "@reactionary/core";
|
|
2
|
+
import { CommercetoolsClient } from "../core/client.js";
|
|
3
|
+
import createDebug from "debug";
|
|
4
|
+
const debug = createDebug("reactionary:commercetools:search");
|
|
5
|
+
class CommercetoolsSearchProvider extends ProductSearchProvider {
|
|
6
|
+
constructor(config, schema, cache) {
|
|
7
|
+
super(schema, cache);
|
|
8
|
+
this.config = config;
|
|
9
|
+
}
|
|
10
|
+
async getClient(reqCtx) {
|
|
11
|
+
const client = await new CommercetoolsClient(this.config).getClient(reqCtx);
|
|
12
|
+
return client.withProjectKey({ projectKey: this.config.projectKey }).productProjections();
|
|
13
|
+
}
|
|
14
|
+
async queryByTerm(payload, reqCtx) {
|
|
15
|
+
const client = await this.getClient(reqCtx);
|
|
16
|
+
const response = await client.search().get({
|
|
17
|
+
queryArgs: {
|
|
18
|
+
limit: payload.search.paginationOptions.pageSize,
|
|
19
|
+
offset: (payload.search.paginationOptions.pageNumber - 1) * payload.search.paginationOptions.pageSize,
|
|
20
|
+
[`text.${reqCtx.languageContext.locale}`]: payload.search.term
|
|
21
|
+
}
|
|
22
|
+
}).execute();
|
|
23
|
+
const responseBody = response.body;
|
|
24
|
+
const result = this.parsePaginatedResult(responseBody, reqCtx);
|
|
25
|
+
if (debug.enabled) {
|
|
26
|
+
debug(`Search for term "${payload.search.term}" returned ${responseBody.results.length} products (page ${payload.search.paginationOptions.pageNumber} of ${result.totalPages})`);
|
|
27
|
+
}
|
|
28
|
+
result.identifier = {
|
|
29
|
+
...payload.search
|
|
30
|
+
};
|
|
31
|
+
result.meta = {
|
|
32
|
+
cache: { hit: false, key: "" },
|
|
33
|
+
placeholder: false
|
|
34
|
+
};
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
parseSingle(body, reqCtx) {
|
|
38
|
+
const product = this.newModel();
|
|
39
|
+
product.identifier = { key: body.id };
|
|
40
|
+
product.name = body.name[reqCtx.languageContext.locale] || body.id;
|
|
41
|
+
product.slug = body.slug?.[reqCtx.languageContext.locale] || body.id;
|
|
42
|
+
product.variants = [body.masterVariant, ...body.variants].map((variant) => this.parseVariant(variant, body, reqCtx));
|
|
43
|
+
return product;
|
|
44
|
+
}
|
|
45
|
+
parsePaginatedResult(body, reqCtx) {
|
|
46
|
+
const products = body.results.map((p) => this.parseSingle(p, reqCtx));
|
|
47
|
+
const facets = [];
|
|
48
|
+
for (const id in body.facets) {
|
|
49
|
+
const f = body.facets[id];
|
|
50
|
+
const facetId = FacetIdentifierSchema.parse({
|
|
51
|
+
key: id
|
|
52
|
+
});
|
|
53
|
+
const facet = this.parseFacet(facetId, f, reqCtx);
|
|
54
|
+
facets.push(facet);
|
|
55
|
+
}
|
|
56
|
+
const result = createPaginatedResponseSchema(this.schema).parse({
|
|
57
|
+
meta: {
|
|
58
|
+
cache: { hit: false, key: "unknown" },
|
|
59
|
+
placeholder: false
|
|
60
|
+
},
|
|
61
|
+
pageNumber: (Math.ceil(body.offset / body.limit) || 0) + 1,
|
|
62
|
+
pageSize: body.limit,
|
|
63
|
+
totalCount: body.total,
|
|
64
|
+
totalPages: Math.ceil((body.total || 0) / body.limit || 0) + 1,
|
|
65
|
+
items: products
|
|
66
|
+
});
|
|
67
|
+
result.facets = facets;
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
parseFacet(facetIdentifier, facetValue, reqCtx) {
|
|
71
|
+
const result = ProductSearchResultFacetSchema.parse({
|
|
72
|
+
identifier: facetIdentifier,
|
|
73
|
+
name: facetIdentifier.key,
|
|
74
|
+
values: []
|
|
75
|
+
});
|
|
76
|
+
if (facetValue.type === "terms") {
|
|
77
|
+
for (const ft of facetValue.terms) {
|
|
78
|
+
const facetValueIdentifier = FacetValueIdentifierSchema.parse({
|
|
79
|
+
facet: facetIdentifier,
|
|
80
|
+
key: ft.term
|
|
81
|
+
});
|
|
82
|
+
result.values.push(this.parseFacetValue(facetValueIdentifier, ft.term, ft.count, reqCtx));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
87
|
+
parseFacetValue(facetValueIdentifier, label, count, reqCtx) {
|
|
88
|
+
return ProductSearchResultFacetValueSchema.parse({
|
|
89
|
+
identifier: facetValueIdentifier,
|
|
90
|
+
name: label,
|
|
91
|
+
count,
|
|
92
|
+
active: false
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
parseVariant(variant, product, reqCtx) {
|
|
96
|
+
const sourceImage = variant.images?.[0];
|
|
97
|
+
const img = ImageSchema.parse({
|
|
98
|
+
sourceUrl: sourceImage?.url || "",
|
|
99
|
+
height: sourceImage?.dimensions.h || void 0,
|
|
100
|
+
width: sourceImage?.dimensions.w || void 0,
|
|
101
|
+
altText: sourceImage?.label || product.name[reqCtx.languageContext.locale] || void 0
|
|
102
|
+
});
|
|
103
|
+
const mappedOptions = variant.attributes?.filter((x) => x.name === "Color").map(
|
|
104
|
+
(opt) => ProductVariantOptionSchema.parse(
|
|
105
|
+
{
|
|
106
|
+
identifier: ProductOptionIdentifierSchema.parse({
|
|
107
|
+
key: opt.name
|
|
108
|
+
}),
|
|
109
|
+
name: opt.value || ""
|
|
110
|
+
}
|
|
111
|
+
)
|
|
112
|
+
) || [];
|
|
113
|
+
const mappedOption = mappedOptions?.[0];
|
|
114
|
+
return ProductSearchResultItemVariantSchema.parse({
|
|
115
|
+
variant: ProductVariantIdentifierSchema.parse({ sku: variant.sku || "" }),
|
|
116
|
+
image: img,
|
|
117
|
+
option: mappedOption
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
export {
|
|
122
|
+
CommercetoolsSearchProvider
|
|
123
|
+
};
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
2
|
+
ImageSchema,
|
|
3
|
+
ProductAttributeIdentifierSchema,
|
|
4
|
+
ProductAttributeSchema,
|
|
5
|
+
ProductAttributeValueIdentifierSchema,
|
|
6
|
+
ProductAttributeValueSchema,
|
|
7
|
+
ProductProvider,
|
|
8
|
+
ProductVariantIdentifierSchema,
|
|
9
|
+
ProductVariantSchema
|
|
3
10
|
} from "@reactionary/core";
|
|
4
11
|
import { CommercetoolsClient } from "../core/client.js";
|
|
5
12
|
class CommercetoolsProductProvider extends ProductProvider {
|
|
@@ -40,13 +47,12 @@ class CommercetoolsProductProvider extends ProductProvider {
|
|
|
40
47
|
staged: false,
|
|
41
48
|
limit: 1,
|
|
42
49
|
where: "variants(sku in (:skus)) OR (masterVariant(sku in (:skus))) ",
|
|
43
|
-
"var.skus": [payload].map((p) => p.sku
|
|
50
|
+
"var.skus": [payload].map((p) => p.variant.sku)
|
|
44
51
|
}
|
|
45
52
|
}).execute();
|
|
46
53
|
return this.parseSingle(remote.body.results[0], reqCtx);
|
|
47
54
|
}
|
|
48
|
-
parseSingle(
|
|
49
|
-
const data = dataIn;
|
|
55
|
+
parseSingle(data, reqCtx) {
|
|
50
56
|
const base = this.newModel();
|
|
51
57
|
base.identifier = { key: data.id };
|
|
52
58
|
base.name = data.name[reqCtx.languageContext.locale];
|
|
@@ -54,26 +60,64 @@ class CommercetoolsProductProvider extends ProductProvider {
|
|
|
54
60
|
if (data.description) {
|
|
55
61
|
base.description = data.description[reqCtx.languageContext.locale];
|
|
56
62
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
base.images = [];
|
|
61
|
-
base.attributes = [];
|
|
62
|
-
base.skus = [];
|
|
63
|
-
const variants = [data.masterVariant, ...data.variants];
|
|
64
|
-
for (const variant of variants) {
|
|
65
|
-
if (variant.sku) {
|
|
66
|
-
base.skus.push({
|
|
67
|
-
identifier: { key: variant.sku }
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
}
|
|
63
|
+
base.sharedAttributes = data.masterVariant.attributes?.map((x) => this.parseAttribute(x, reqCtx)) || [];
|
|
64
|
+
base.mainVariant = this.parseVariant(data.masterVariant, data, reqCtx);
|
|
71
65
|
base.meta = {
|
|
72
66
|
cache: { hit: false, key: this.generateCacheKeySingle(base.identifier, reqCtx) },
|
|
73
67
|
placeholder: false
|
|
74
68
|
};
|
|
75
69
|
return this.assert(base);
|
|
76
70
|
}
|
|
71
|
+
parseVariant(variant, product, reqCtx) {
|
|
72
|
+
const result = ProductVariantSchema.parse({
|
|
73
|
+
identifier: ProductVariantIdentifierSchema.parse({
|
|
74
|
+
sku: variant.sku
|
|
75
|
+
}),
|
|
76
|
+
images: [
|
|
77
|
+
...(variant.images || []).map((img) => ImageSchema.parse({
|
|
78
|
+
sourceUrl: img.url,
|
|
79
|
+
altText: img.label || "",
|
|
80
|
+
width: img.dimensions?.w,
|
|
81
|
+
height: img.dimensions?.h
|
|
82
|
+
}))
|
|
83
|
+
]
|
|
84
|
+
});
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
87
|
+
parseAttribute(attr, reqCtx) {
|
|
88
|
+
const result = ProductAttributeSchema.parse({
|
|
89
|
+
identifier: ProductAttributeIdentifierSchema.parse({
|
|
90
|
+
key: attr.name
|
|
91
|
+
}),
|
|
92
|
+
group: "",
|
|
93
|
+
name: attr.name,
|
|
94
|
+
values: [
|
|
95
|
+
this.parseAttributeValue(attr, reqCtx)
|
|
96
|
+
]
|
|
97
|
+
});
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
parseAttributeValue(attr, reqCtx) {
|
|
101
|
+
let attrValue = "";
|
|
102
|
+
if (attr.value && Array.isArray(attr.value)) {
|
|
103
|
+
attrValue = attr.value[0];
|
|
104
|
+
}
|
|
105
|
+
if (attrValue && typeof attrValue === "object") {
|
|
106
|
+
if (reqCtx.languageContext.locale in attrValue) {
|
|
107
|
+
attrValue = attrValue[reqCtx.languageContext.locale];
|
|
108
|
+
} else {
|
|
109
|
+
attrValue = "-";
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const attrVal = ProductAttributeValueSchema.parse({
|
|
113
|
+
identifier: ProductAttributeValueIdentifierSchema.parse({
|
|
114
|
+
key: attrValue
|
|
115
|
+
}),
|
|
116
|
+
value: String(attrValue),
|
|
117
|
+
label: String(attrValue)
|
|
118
|
+
});
|
|
119
|
+
return attrVal;
|
|
120
|
+
}
|
|
77
121
|
}
|
|
78
122
|
export {
|
|
79
123
|
CommercetoolsProductProvider
|
package/src/core/initialize.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import type { Cache, ProductProvider,
|
|
1
|
+
import type { Cache, ProductProvider, ProductSearchProvider, IdentityProvider, CartProvider, InventoryProvider, PriceProvider, CategoryProvider, StoreProvider, CheckoutProvider, OrderProvider } from "@reactionary/core";
|
|
2
2
|
import type { CommercetoolsCapabilities } from "../schema/capabilities.schema.js";
|
|
3
3
|
import type { CommercetoolsConfiguration } from "../schema/configuration.schema.js";
|
|
4
4
|
type CommercetoolsClient<T extends CommercetoolsCapabilities> = (T['cart'] extends true ? {
|
|
5
5
|
cart: CartProvider;
|
|
6
6
|
} : object) & (T['product'] extends true ? {
|
|
7
7
|
product: ProductProvider;
|
|
8
|
-
} : object) & (T['
|
|
9
|
-
|
|
8
|
+
} : object) & (T['productSearch'] extends true ? {
|
|
9
|
+
productSearch: ProductSearchProvider;
|
|
10
10
|
} : object) & (T['identity'] extends true ? {
|
|
11
11
|
identity: IdentityProvider;
|
|
12
12
|
} : object) & (T['category'] extends true ? {
|
package/src/index.d.ts
CHANGED
|
@@ -5,6 +5,6 @@ export * from './providers/identity.provider.js';
|
|
|
5
5
|
export * from './providers/inventory.provider.js';
|
|
6
6
|
export * from './providers/price.provider.js';
|
|
7
7
|
export * from './providers/product.provider.js';
|
|
8
|
-
export * from './providers/search.provider.js';
|
|
8
|
+
export * from './providers/product-search.provider.js';
|
|
9
9
|
export * from './schema/capabilities.schema.js';
|
|
10
10
|
export * from './schema/configuration.schema.js';
|
package/src/providers/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export * from './inventory.provider.js';
|
|
|
5
5
|
export * from './price.provider.js';
|
|
6
6
|
export * from './product.provider.js';
|
|
7
7
|
export * from './profile.provider.js';
|
|
8
|
-
export * from './search.provider.js';
|
|
8
|
+
export * from './product-search.provider.js';
|
|
9
9
|
export * from './store.provider.js';
|
|
10
10
|
export * from './order.provider.js';
|
|
11
11
|
export * from './checkout.provider.js';
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { ProductSearchProvider } from '@reactionary/core';
|
|
2
|
+
import type { Cache, ProductSearchQueryByTerm, RequestContext, ProductSearchResultItem, ProductSearchResult, ProductSearchResultItemVariant, FacetIdentifier, ProductSearchResultFacet, FacetValueIdentifier, ProductSearchResultFacetValue } from '@reactionary/core';
|
|
3
|
+
import type z from 'zod';
|
|
4
|
+
import type { CommercetoolsConfiguration } from '../schema/configuration.schema.js';
|
|
5
|
+
import type { ProductVariant as CTProductVariant, FacetResult, ProductProjection, ProductProjectionPagedSearchResponse } from '@commercetools/platform-sdk';
|
|
6
|
+
export declare class CommercetoolsSearchProvider<T extends ProductSearchResultItem = ProductSearchResultItem> extends ProductSearchProvider<T> {
|
|
7
|
+
protected config: CommercetoolsConfiguration;
|
|
8
|
+
constructor(config: CommercetoolsConfiguration, schema: z.ZodType<T>, cache: Cache);
|
|
9
|
+
protected getClient(reqCtx: RequestContext): Promise<import("@commercetools/platform-sdk").ByProjectKeyProductProjectionsRequestBuilder>;
|
|
10
|
+
queryByTerm(payload: ProductSearchQueryByTerm, reqCtx: RequestContext): Promise<ProductSearchResult>;
|
|
11
|
+
protected parseSingle(body: ProductProjection, reqCtx: RequestContext): T;
|
|
12
|
+
protected parsePaginatedResult(body: ProductProjectionPagedSearchResponse, reqCtx: RequestContext): {
|
|
13
|
+
meta: {
|
|
14
|
+
[x: string]: unknown;
|
|
15
|
+
cache: {
|
|
16
|
+
[x: string]: unknown;
|
|
17
|
+
hit: boolean;
|
|
18
|
+
key: string;
|
|
19
|
+
};
|
|
20
|
+
placeholder: boolean;
|
|
21
|
+
};
|
|
22
|
+
pageNumber: number;
|
|
23
|
+
pageSize: number;
|
|
24
|
+
totalCount: number;
|
|
25
|
+
totalPages: number;
|
|
26
|
+
items: T[];
|
|
27
|
+
};
|
|
28
|
+
protected parseFacet(facetIdentifier: FacetIdentifier, facetValue: FacetResult, reqCtx: RequestContext): ProductSearchResultFacet;
|
|
29
|
+
protected parseFacetValue(facetValueIdentifier: FacetValueIdentifier, label: string, count: number, reqCtx: RequestContext): ProductSearchResultFacetValue;
|
|
30
|
+
protected parseVariant(variant: CTProductVariant, product: ProductProjection, reqCtx: RequestContext): ProductSearchResultItemVariant;
|
|
31
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { ProductProvider } from '@reactionary/core';
|
|
2
2
|
import type { z } from 'zod';
|
|
3
3
|
import type { CommercetoolsConfiguration } from '../schema/configuration.schema.js';
|
|
4
|
-
import type {
|
|
4
|
+
import type { ProductProjection, ProductVariant as CTProductVariant, Attribute as CTAttribute } from '@commercetools/platform-sdk';
|
|
5
|
+
import type { Product, ProductVariant, ProductQueryById, ProductQueryBySKU, ProductQueryBySlug, RequestContext, ProductAttribute, ProductAttributeValue } from '@reactionary/core';
|
|
5
6
|
import type { Cache } from '@reactionary/core';
|
|
6
7
|
export declare class CommercetoolsProductProvider<T extends Product = Product> extends ProductProvider<T> {
|
|
7
8
|
protected config: CommercetoolsConfiguration;
|
|
@@ -10,5 +11,8 @@ export declare class CommercetoolsProductProvider<T extends Product = Product> e
|
|
|
10
11
|
getById(payload: ProductQueryById, reqCtx: RequestContext): Promise<T>;
|
|
11
12
|
getBySlug(payload: ProductQueryBySlug, reqCtx: RequestContext): Promise<T | null>;
|
|
12
13
|
getBySKU(payload: ProductQueryBySKU, reqCtx: RequestContext): Promise<T>;
|
|
13
|
-
protected parseSingle(
|
|
14
|
+
protected parseSingle(data: ProductProjection, reqCtx: RequestContext): T;
|
|
15
|
+
protected parseVariant(variant: CTProductVariant, product: ProductProjection, reqCtx: RequestContext): ProductVariant;
|
|
16
|
+
protected parseAttribute(attr: CTAttribute, reqCtx: RequestContext): ProductAttribute;
|
|
17
|
+
protected parseAttributeValue(attr: CTAttribute, reqCtx: RequestContext): ProductAttributeValue;
|
|
14
18
|
}
|
|
@@ -3,12 +3,12 @@ export declare const CommercetoolsCapabilitiesSchema: z.ZodObject<{
|
|
|
3
3
|
price: z.ZodOptional<z.ZodBoolean>;
|
|
4
4
|
product: z.ZodOptional<z.ZodBoolean>;
|
|
5
5
|
identity: z.ZodOptional<z.ZodBoolean>;
|
|
6
|
-
search: z.ZodOptional<z.ZodBoolean>;
|
|
7
6
|
cart: z.ZodOptional<z.ZodBoolean>;
|
|
8
7
|
inventory: z.ZodOptional<z.ZodBoolean>;
|
|
9
8
|
category: z.ZodOptional<z.ZodBoolean>;
|
|
10
9
|
checkout: z.ZodOptional<z.ZodBoolean>;
|
|
11
10
|
order: z.ZodOptional<z.ZodBoolean>;
|
|
12
11
|
store: z.ZodOptional<z.ZodBoolean>;
|
|
12
|
+
productSearch: z.ZodOptional<z.ZodBoolean>;
|
|
13
13
|
}, z.core.$loose>;
|
|
14
14
|
export type CommercetoolsCapabilities = z.infer<typeof CommercetoolsCapabilitiesSchema>;
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { SearchProvider } from "@reactionary/core";
|
|
2
|
-
import { CommercetoolsClient } from "../core/client.js";
|
|
3
|
-
class CommercetoolsSearchProvider extends SearchProvider {
|
|
4
|
-
constructor(config, schema, cache) {
|
|
5
|
-
super(schema, cache);
|
|
6
|
-
this.config = config;
|
|
7
|
-
}
|
|
8
|
-
async getClient(reqCtx) {
|
|
9
|
-
const client = await new CommercetoolsClient(this.config).getClient(reqCtx);
|
|
10
|
-
return client.withProjectKey({ projectKey: this.config.projectKey }).productProjections();
|
|
11
|
-
}
|
|
12
|
-
async queryByTerm(payload, reqCtx) {
|
|
13
|
-
const client = await this.getClient(reqCtx);
|
|
14
|
-
const remote = await client.search().get({
|
|
15
|
-
queryArgs: {
|
|
16
|
-
limit: payload.search.pageSize,
|
|
17
|
-
offset: (payload.search.page - 1) * payload.search.pageSize,
|
|
18
|
-
[`text.${reqCtx.languageContext.locale}`]: payload.search.term
|
|
19
|
-
}
|
|
20
|
-
}).execute();
|
|
21
|
-
return this.parseSearchResult(remote, payload, reqCtx);
|
|
22
|
-
}
|
|
23
|
-
parseSearchResult(remote, payload, reqCtx) {
|
|
24
|
-
const result = this.newModel();
|
|
25
|
-
const remoteData = remote;
|
|
26
|
-
result.identifier = payload.search;
|
|
27
|
-
for (const p of remoteData.body.results) {
|
|
28
|
-
const product = {
|
|
29
|
-
identifier: { key: p.id },
|
|
30
|
-
name: p.name[reqCtx.languageContext.locale] || p.id,
|
|
31
|
-
slug: p.slug?.[reqCtx.languageContext.locale] || p.id,
|
|
32
|
-
image: p.masterVariant.images?.[0]?.url || "https://placehold.co/400"
|
|
33
|
-
};
|
|
34
|
-
result.products.push(product);
|
|
35
|
-
}
|
|
36
|
-
result.pages = Math.ceil(
|
|
37
|
-
(remoteData.body.total || 0) / payload.search.pageSize
|
|
38
|
-
);
|
|
39
|
-
result.meta = {
|
|
40
|
-
cache: { hit: false, key: payload.search.term },
|
|
41
|
-
placeholder: false
|
|
42
|
-
};
|
|
43
|
-
return this.assert(result);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
export {
|
|
47
|
-
CommercetoolsSearchProvider
|
|
48
|
-
};
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { SearchProvider } from '@reactionary/core';
|
|
2
|
-
import type { SearchResult, Cache, SearchQueryByTerm, RequestContext } from '@reactionary/core';
|
|
3
|
-
import type z from 'zod';
|
|
4
|
-
import type { CommercetoolsConfiguration } from '../schema/configuration.schema.js';
|
|
5
|
-
export declare class CommercetoolsSearchProvider<T extends SearchResult = SearchResult> extends SearchProvider<T> {
|
|
6
|
-
protected config: CommercetoolsConfiguration;
|
|
7
|
-
constructor(config: CommercetoolsConfiguration, schema: z.ZodType<T>, cache: Cache);
|
|
8
|
-
protected getClient(reqCtx: RequestContext): Promise<import("@commercetools/platform-sdk").ByProjectKeyProductProjectionsRequestBuilder>;
|
|
9
|
-
queryByTerm(payload: SearchQueryByTerm, reqCtx: RequestContext): Promise<T>;
|
|
10
|
-
protected parseSearchResult(remote: unknown, payload: SearchQueryByTerm, reqCtx: RequestContext): T;
|
|
11
|
-
}
|