@reactionary/source 0.6.1 → 0.6.2

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 (191) hide show
  1. package/README.md +14 -11
  2. package/core/src/client/client-builder.ts +54 -6
  3. package/core/src/factories/cart.factory.ts +40 -0
  4. package/core/src/factories/category.factory.ts +40 -0
  5. package/core/src/factories/checkout.factory.ts +59 -0
  6. package/core/src/factories/identity.factory.ts +26 -0
  7. package/core/src/factories/index.ts +15 -0
  8. package/core/src/factories/inventory.factory.ts +26 -0
  9. package/core/src/factories/order-search.factory.ts +33 -0
  10. package/core/src/factories/order.factory.ts +21 -0
  11. package/core/src/factories/price.factory.ts +29 -0
  12. package/core/src/factories/product-associations.factory.ts +30 -0
  13. package/core/src/factories/product-list.factory.ts +82 -0
  14. package/core/src/factories/product-reviews.factory.ts +58 -0
  15. package/core/src/factories/product-search.factory.ts +31 -0
  16. package/core/src/factories/product.factory.ts +21 -0
  17. package/core/src/factories/profile.factory.ts +23 -0
  18. package/core/src/factories/store.factory.ts +21 -0
  19. package/core/src/index.ts +3 -1
  20. package/core/src/providers/cart.provider.ts +12 -10
  21. package/core/src/providers/category.provider.ts +9 -7
  22. package/core/src/providers/checkout.provider.ts +14 -10
  23. package/core/src/providers/identity.provider.ts +7 -7
  24. package/core/src/providers/inventory.provider.ts +4 -4
  25. package/core/src/providers/order-search.provider.ts +4 -2
  26. package/core/src/providers/order.provider.ts +4 -4
  27. package/core/src/providers/price.provider.ts +5 -5
  28. package/core/src/providers/product-associations.provider.ts +6 -4
  29. package/core/src/providers/product-list.provider.ts +13 -8
  30. package/core/src/providers/product-reviews.provider.ts +8 -4
  31. package/core/src/providers/product-search.provider.ts +15 -28
  32. package/core/src/providers/product.provider.ts +6 -6
  33. package/core/src/providers/profile.provider.ts +8 -8
  34. package/core/src/providers/store.provider.ts +2 -2
  35. package/core/src/test/client-builder.spec.ts +81 -0
  36. package/examples/node/package.json +7 -7
  37. package/examples/node/src/basic/basic-node-provider-model-extension.spec.ts +10 -4
  38. package/examples/node/src/basic/basic-node-provider-query-extension.spec.ts +8 -2
  39. package/examples/node/src/basic/basic-node-setup.spec.ts +5 -1
  40. package/examples/node/src/basic/client-creation.spec.ts +3 -3
  41. package/examples/node/src/utils.ts +41 -41
  42. package/examples/node/tsconfig.lib.json +2 -1
  43. package/package.json +1 -1
  44. package/providers/algolia/src/core/initialize.ts +76 -21
  45. package/providers/algolia/src/core/initialize.types.ts +107 -0
  46. package/providers/algolia/src/factories/index.ts +1 -0
  47. package/providers/algolia/src/factories/product-search/product-search.factory.ts +182 -0
  48. package/providers/algolia/src/index.ts +2 -2
  49. package/providers/algolia/src/providers/analytics.provider.ts +4 -4
  50. package/providers/algolia/src/providers/product-search.provider.ts +67 -184
  51. package/providers/algolia/src/schema/capabilities.schema.ts +81 -7
  52. package/providers/algolia/src/test/analytics.spec.ts +9 -1
  53. package/providers/algolia/src/test/client-builder-product-search-extension.example.ts +85 -0
  54. package/providers/commercetools/src/core/capability-descriptors.ts +324 -0
  55. package/providers/commercetools/src/core/initialize.ts +35 -151
  56. package/providers/commercetools/src/core/initialize.types.ts +174 -0
  57. package/providers/commercetools/src/factories/cart/cart.factory.ts +142 -0
  58. package/providers/commercetools/src/factories/category/category.factory.ts +77 -0
  59. package/providers/commercetools/src/factories/checkout/checkout-initializer-overrides.example.ts +94 -0
  60. package/providers/commercetools/src/factories/checkout/checkout.factory.ts +338 -0
  61. package/providers/commercetools/src/factories/identity/identity.factory.ts +26 -0
  62. package/providers/commercetools/src/factories/inventory/inventory.factory.ts +49 -0
  63. package/providers/commercetools/src/factories/order/order.factory.ts +149 -0
  64. package/providers/commercetools/src/factories/order-search/order-search.factory.ts +108 -0
  65. package/providers/commercetools/src/factories/price/price.factory.ts +76 -0
  66. package/providers/commercetools/src/factories/product/product-factory-baseline.example.ts +14 -0
  67. package/providers/commercetools/src/factories/product/product-factory-schema-and-parse-extension.example.ts +35 -0
  68. package/providers/commercetools/src/factories/product/product-factory-schema-extension.example.ts +23 -0
  69. package/providers/commercetools/src/factories/product/product-initializer-factory-extension.example.ts +41 -0
  70. package/providers/commercetools/src/factories/product/product-provider-custom-method-only.example.ts +47 -0
  71. package/providers/commercetools/src/factories/product/product-provider-schema-signature-extension.example.ts +61 -0
  72. package/providers/commercetools/src/factories/product/product.factory.ts +220 -0
  73. package/providers/commercetools/src/factories/product/utils.example.ts +9 -0
  74. package/providers/commercetools/src/factories/product-associations/product-associations.factory.ts +103 -0
  75. package/providers/commercetools/src/factories/product-list/product-list.factory.ts +122 -0
  76. package/providers/commercetools/src/factories/product-reviews/product-reviews.factory.ts +81 -0
  77. package/providers/commercetools/src/factories/product-search/product-search.factory.ts +182 -0
  78. package/providers/commercetools/src/factories/profile/profile.factory.ts +94 -0
  79. package/providers/commercetools/src/factories/store/store.factory.ts +49 -0
  80. package/providers/commercetools/src/index.ts +15 -0
  81. package/providers/commercetools/src/providers/cart.provider.ts +67 -193
  82. package/providers/commercetools/src/providers/category.provider.ts +24 -64
  83. package/providers/commercetools/src/providers/checkout.provider.ts +50 -322
  84. package/providers/commercetools/src/providers/identity.provider.ts +35 -15
  85. package/providers/commercetools/src/providers/inventory.provider.ts +13 -31
  86. package/providers/commercetools/src/providers/order-search.provider.ts +16 -110
  87. package/providers/commercetools/src/providers/order.provider.ts +13 -144
  88. package/providers/commercetools/src/providers/price.provider.ts +37 -51
  89. package/providers/commercetools/src/providers/product-associations.provider.ts +39 -104
  90. package/providers/commercetools/src/providers/product-list.provider.ts +38 -23
  91. package/providers/commercetools/src/providers/product-reviews.provider.ts +34 -14
  92. package/providers/commercetools/src/providers/product-search.provider.ts +17 -170
  93. package/providers/commercetools/src/providers/product.provider.ts +20 -199
  94. package/providers/commercetools/src/providers/profile.provider.ts +27 -73
  95. package/providers/commercetools/src/providers/store.provider.ts +13 -31
  96. package/providers/commercetools/src/schema/capabilities.schema.ts +258 -20
  97. package/providers/commercetools/src/test/caching.spec.ts +18 -2
  98. package/providers/commercetools/src/test/client-builder-merge-extensions.example.ts +125 -0
  99. package/providers/fake/src/core/initialize.ts +213 -44
  100. package/providers/fake/src/core/initialize.types.ts +164 -0
  101. package/providers/fake/src/factories/cart/cart.factory.ts +34 -0
  102. package/providers/fake/src/factories/category/category.factory.ts +40 -0
  103. package/providers/fake/src/factories/checkout/checkout.factory.ts +53 -0
  104. package/providers/fake/src/factories/identity/identity.factory.ts +25 -0
  105. package/providers/fake/src/factories/index.ts +14 -0
  106. package/providers/fake/src/factories/inventory/inventory.factory.ts +25 -0
  107. package/providers/fake/src/factories/order/order.factory.ts +22 -0
  108. package/providers/fake/src/factories/order-search/order-search.factory.ts +27 -0
  109. package/providers/fake/src/factories/price/price.factory.ts +26 -0
  110. package/providers/fake/src/factories/product/product.factory.ts +22 -0
  111. package/providers/fake/src/factories/product-associations/product-associations.factory.ts +25 -0
  112. package/providers/fake/src/factories/product-reviews/product-reviews.factory.ts +53 -0
  113. package/providers/fake/src/factories/product-search/product-search.factory.ts +27 -0
  114. package/providers/fake/src/factories/profile/profile.factory.ts +22 -0
  115. package/providers/fake/src/factories/store/store.factory.ts +22 -0
  116. package/providers/fake/src/index.ts +2 -0
  117. package/providers/fake/src/providers/cart.provider.ts +23 -14
  118. package/providers/fake/src/providers/category.provider.ts +120 -105
  119. package/providers/fake/src/providers/checkout.provider.ts +39 -20
  120. package/providers/fake/src/providers/identity.provider.ts +40 -34
  121. package/providers/fake/src/providers/inventory.provider.ts +26 -24
  122. package/providers/fake/src/providers/order-search.provider.ts +38 -30
  123. package/providers/fake/src/providers/order.provider.ts +21 -37
  124. package/providers/fake/src/providers/price.provider.ts +42 -34
  125. package/providers/fake/src/providers/product-associations.provider.ts +23 -10
  126. package/providers/fake/src/providers/product-reviews.provider.ts +71 -69
  127. package/providers/fake/src/providers/product-search.provider.ts +43 -70
  128. package/providers/fake/src/providers/product.provider.ts +34 -32
  129. package/providers/fake/src/providers/profile.provider.ts +62 -55
  130. package/providers/fake/src/providers/store.provider.ts +38 -22
  131. package/providers/fake/src/schema/capabilities.schema.ts +175 -18
  132. package/providers/fake/src/test/cart.provider.spec.ts +20 -3
  133. package/providers/fake/src/test/category.provider.spec.ts +4 -1
  134. package/providers/fake/src/test/checkout.provider.spec.ts +12 -2
  135. package/providers/fake/src/test/client-builder-product-extension.example.ts +75 -0
  136. package/providers/fake/src/test/order-search.provider.spec.ts +4 -7
  137. package/providers/fake/src/test/order.provider.spec.ts +4 -6
  138. package/providers/fake/src/test/price.provider.spec.ts +3 -1
  139. package/providers/fake/src/test/product.provider.spec.ts +8 -2
  140. package/providers/fake/src/test/profile.provider.spec.ts +4 -2
  141. package/providers/google-analytics/src/core/initialize.ts +37 -12
  142. package/providers/google-analytics/src/core/initialize.types.ts +47 -0
  143. package/providers/google-analytics/src/index.ts +1 -0
  144. package/providers/google-analytics/src/schema/capabilities.schema.ts +31 -5
  145. package/providers/medusa/src/core/initialize.ts +324 -81
  146. package/providers/medusa/src/core/initialize.types.ts +184 -0
  147. package/providers/medusa/src/factories/cart/cart.factory.ts +34 -0
  148. package/providers/medusa/src/factories/category/category.factory.ts +37 -0
  149. package/providers/medusa/src/factories/checkout/checkout.factory.ts +50 -0
  150. package/providers/medusa/src/factories/identity/identity.factory.ts +22 -0
  151. package/providers/medusa/src/factories/index.ts +12 -0
  152. package/providers/medusa/src/factories/inventory/inventory.factory.ts +25 -0
  153. package/providers/medusa/src/factories/order/order.factory.ts +22 -0
  154. package/providers/medusa/src/factories/order-search/order-search.factory.ts +27 -0
  155. package/providers/medusa/src/factories/price/price.factory.ts +26 -0
  156. package/providers/medusa/src/factories/product/product.factory.ts +22 -0
  157. package/providers/medusa/src/factories/product-associations/product-associations.factory.ts +25 -0
  158. package/providers/medusa/src/factories/product-search/product-search.factory.ts +27 -0
  159. package/providers/medusa/src/factories/profile/profile.factory.ts +22 -0
  160. package/providers/medusa/src/index.ts +2 -0
  161. package/providers/medusa/src/providers/cart.provider.ts +33 -20
  162. package/providers/medusa/src/providers/category.provider.ts +30 -12
  163. package/providers/medusa/src/providers/checkout.provider.ts +42 -17
  164. package/providers/medusa/src/providers/identity.provider.ts +1 -1
  165. package/providers/medusa/src/providers/inventory.provider.ts +21 -7
  166. package/providers/medusa/src/providers/order-search.provider.ts +16 -5
  167. package/providers/medusa/src/providers/order.provider.ts +17 -5
  168. package/providers/medusa/src/providers/price.provider.ts +26 -7
  169. package/providers/medusa/src/providers/product-associations.provider.ts +19 -8
  170. package/providers/medusa/src/providers/product-search.provider.ts +19 -31
  171. package/providers/medusa/src/providers/product.provider.ts +47 -11
  172. package/providers/medusa/src/providers/profile.provider.ts +35 -11
  173. package/providers/medusa/src/schema/capabilities.schema.ts +229 -18
  174. package/providers/medusa/src/test/cart.provider.spec.ts +18 -2
  175. package/providers/medusa/src/test/category.provider.spec.ts +4 -1
  176. package/providers/medusa/src/test/checkout.spec.ts +9 -9
  177. package/providers/medusa/src/test/inventory.provider.spec.ts +3 -1
  178. package/providers/medusa/src/test/large-cart.provider.spec.ts +8 -2
  179. package/providers/medusa/src/test/price.provider.spec.ts +8 -1
  180. package/providers/medusa/src/test/product.provider.spec.ts +3 -1
  181. package/providers/medusa/src/test/search.provider.spec.ts +16 -3
  182. package/providers/meilisearch/src/core/initialize.ts +88 -21
  183. package/providers/meilisearch/src/core/initialize.types.ts +119 -0
  184. package/providers/meilisearch/src/factories/index.ts +2 -0
  185. package/providers/meilisearch/src/factories/order-search/order-search.factory.ts +27 -0
  186. package/providers/meilisearch/src/factories/product-search/product-search.factory.ts +27 -0
  187. package/providers/meilisearch/src/index.ts +2 -0
  188. package/providers/meilisearch/src/providers/index.ts +1 -0
  189. package/providers/meilisearch/src/providers/order-search.provider.ts +21 -6
  190. package/providers/meilisearch/src/providers/product-search.provider.ts +24 -8
  191. package/providers/meilisearch/src/schema/capabilities.schema.ts +95 -8
@@ -1,47 +1,45 @@
1
1
  import {
2
+ type ProductAssociationsFactory,
3
+ type ProductAssociationsFactoryOutput,
4
+ type ProductAssociationsFactoryWithOutput,
2
5
  ProductAssociationsProvider,
3
6
  Reactionary,
4
- ImageSchema,
5
- ProductVariantOptionSchema,
6
- ProductOptionIdentifierSchema,
7
- ProductSearchResultItemVariantSchema,
8
- ProductVariantIdentifierSchema,
9
7
  success,
10
8
  error,
11
9
  } from '@reactionary/core';
12
10
  import type {
13
- ProductVariantIdentifier,
14
11
  ProductIdentifier,
15
- ProductAssociation,
16
- ProductSearchResultItem,
17
- ProductSearchResultItemVariant,
18
12
  ProductAssociationsGetAccessoriesQuery,
19
13
  ProductAssociationsGetSparepartsQuery,
20
14
  ProductAssociationsGetReplacementsQuery,
21
15
  Result,
22
16
  RequestContext,
23
17
  Cache,
24
- ProductOptionIdentifier,
25
- ProductVariantOption,
26
18
  NotFoundError,
27
19
  } from '@reactionary/core';
28
- import type { ProductProjection, ProductVariant as CTProductVariant } from '@commercetools/platform-sdk';
20
+ import type { ProductProjection } from '@commercetools/platform-sdk';
29
21
  import type { CommercetoolsConfiguration } from '../schema/configuration.schema.js';
30
22
  import type { CommercetoolsAPI } from '../core/client.js';
23
+ import type { CommercetoolsProductAssociationsFactory } from '../factories/product-associations/product-associations.factory.js';
31
24
 
32
- export class CommercetoolsProductAssociationsProvider extends ProductAssociationsProvider {
25
+ export class CommercetoolsProductAssociationsProvider<
26
+ TFactory extends ProductAssociationsFactory = CommercetoolsProductAssociationsFactory,
27
+ > extends ProductAssociationsProvider<ProductAssociationsFactoryOutput<TFactory>> {
33
28
  protected config: CommercetoolsConfiguration;
34
29
  protected commercetools: CommercetoolsAPI;
30
+ protected factory: ProductAssociationsFactoryWithOutput<TFactory>;
35
31
 
36
32
  constructor(
37
33
  config: CommercetoolsConfiguration,
38
34
  cache: Cache,
39
35
  context: RequestContext,
40
- commercetools: CommercetoolsAPI
36
+ commercetools: CommercetoolsAPI,
37
+ factory: ProductAssociationsFactoryWithOutput<TFactory>,
41
38
  ) {
42
39
  super(cache, context);
43
40
  this.config = config;
44
41
  this.commercetools = commercetools;
42
+ this.factory = factory;
45
43
  }
46
44
 
47
45
  protected async getClient() {
@@ -49,7 +47,7 @@ export class CommercetoolsProductAssociationsProvider extends ProductAssociation
49
47
  return client.withProjectKey({ projectKey: this.config.projectKey });
50
48
  }
51
49
 
52
- protected async fetchAssociatedProductsFor(productKey: ProductIdentifier, maxNumberOfAssociations: number, attributeName: string): Promise<ProductSearchResultItem[]> {
50
+ protected async fetchAssociatedProductsFor(productKey: ProductIdentifier, maxNumberOfAssociations: number, attributeName: string): Promise<ProductProjection[]> {
53
51
  const client = await this.getClient();
54
52
 
55
53
  const product = await client
@@ -74,7 +72,7 @@ export class CommercetoolsProductAssociationsProvider extends ProductAssociation
74
72
  if (!associationsAttr) {
75
73
  return [];
76
74
  }
77
- const associatedProductSearchItems: ProductSearchResultItem[] = [];
75
+ const associatedProductSearchItems: ProductProjection[] = [];
78
76
 
79
77
  // look up each associated product,
80
78
  const allAssociatedProductPromises = (associationsAttr.value as string[]).map(async (associatedProductId) => {
@@ -90,34 +88,12 @@ export class CommercetoolsProductAssociationsProvider extends ProductAssociation
90
88
  const associatedProductsResults = await Promise.all(allAssociatedProductPromises);
91
89
  const validAssociatedProductsResults = associatedProductsResults.filter(result => !!result).slice(0, maxNumberOfAssociations);
92
90
  for (const associatedProductResult of validAssociatedProductsResults) {
93
- const resultItem = this.parseSingle(associatedProductResult.body);
94
- if (resultItem) {
95
- associatedProductSearchItems.push(resultItem);
96
- }
91
+ associatedProductSearchItems.push(associatedProductResult.body);
97
92
  }
98
93
  return associatedProductSearchItems;
99
94
  }
100
95
 
101
96
 
102
- protected parseSingle(body: ProductProjection) {
103
- const identifier = { key: body.id };
104
- const name = body.name[this.context.languageContext.locale] || body.id;
105
- const slug = body.slug?.[this.context.languageContext.locale] || body.id;
106
- const variants = [body.masterVariant, ...body.variants].map((variant) =>
107
- this.parseVariant(variant, body)
108
- );
109
-
110
- const product = {
111
- identifier,
112
- name,
113
- slug,
114
- variants,
115
- } satisfies ProductSearchResultItem;
116
-
117
- return product;
118
- }
119
-
120
-
121
97
  @Reactionary({
122
98
  cache: true,
123
99
  cacheTimeToLiveInSeconds: 300,
@@ -126,17 +102,17 @@ export class CommercetoolsProductAssociationsProvider extends ProductAssociation
126
102
  })
127
103
  public override async getAccessories(
128
104
  query: ProductAssociationsGetAccessoriesQuery
129
- ): Promise<Result<ProductAssociation[]>> {
105
+ ): Promise<Result<ProductAssociationsFactoryOutput<TFactory>[]>> {
130
106
 
131
107
  const associatedProducts = await this.fetchAssociatedProductsFor(query.forProduct, query.numberOfAccessories || 4, 'reactionaryaccessories');
132
108
 
133
- const result: ProductAssociation[] = associatedProducts.map(product => ({
134
- associationIdentifier: {
135
- key: `${query.forProduct.key}-accessory-${product.identifier.key}`
136
- },
137
- associationReturnType: 'productSearchResultItem',
138
- product,
139
- } satisfies ProductAssociation));
109
+ const result = associatedProducts.map((product) =>
110
+ this.factory.parseAssociation(this.context, {
111
+ sourceProductKey: query.forProduct.key,
112
+ relation: 'accessory',
113
+ product,
114
+ }),
115
+ );
140
116
 
141
117
  return success(result);
142
118
  }
@@ -149,16 +125,16 @@ export class CommercetoolsProductAssociationsProvider extends ProductAssociation
149
125
  })
150
126
  public override async getSpareparts(
151
127
  query: ProductAssociationsGetSparepartsQuery
152
- ): Promise<Result<ProductAssociation[]>> {
128
+ ): Promise<Result<ProductAssociationsFactoryOutput<TFactory>[]>> {
153
129
  const associatedProducts = await this.fetchAssociatedProductsFor(query.forProduct, query.numberOfSpareparts || 4, 'reactionaryspareparts');
154
130
 
155
- const result: ProductAssociation[] = associatedProducts.map(product => ({
156
- associationIdentifier: {
157
- key: `${query.forProduct.key}-sparepart-${product.identifier.key}`
158
- },
159
- associationReturnType: 'productSearchResultItem',
160
- product,
161
- } satisfies ProductAssociation));
131
+ const result = associatedProducts.map((product) =>
132
+ this.factory.parseAssociation(this.context, {
133
+ sourceProductKey: query.forProduct.key,
134
+ relation: 'sparepart',
135
+ product,
136
+ }),
137
+ );
162
138
 
163
139
  return success(result);
164
140
  }
@@ -171,59 +147,18 @@ export class CommercetoolsProductAssociationsProvider extends ProductAssociation
171
147
  })
172
148
  public override async getReplacements(
173
149
  query: ProductAssociationsGetReplacementsQuery
174
- ): Promise<Result<ProductAssociation[]>> {
150
+ ): Promise<Result<ProductAssociationsFactoryOutput<TFactory>[]>> {
175
151
  const associatedProducts = await this.fetchAssociatedProductsFor(query.forProduct, query.numberOfReplacements || 4, 'reactionaryreplacements');
176
152
 
177
- const result: ProductAssociation[] = associatedProducts.map(product => ({
178
- associationIdentifier: {
179
- key: `${query.forProduct.key}-replacement-${product.identifier.key}`
180
- },
181
- associationReturnType: 'productSearchResultItem',
182
- product,
183
- } satisfies ProductAssociation));
153
+ const result = associatedProducts.map((product) =>
154
+ this.factory.parseAssociation(this.context, {
155
+ sourceProductKey: query.forProduct.key,
156
+ relation: 'replacement',
157
+ product,
158
+ }),
159
+ );
184
160
 
185
161
  return success(result);
186
162
  }
187
163
 
188
-
189
-
190
-
191
- protected parseVariant(
192
- variant: CTProductVariant,
193
- product: ProductProjection
194
- ): ProductSearchResultItemVariant {
195
- const sourceImage = variant.images?.[0];
196
-
197
- const img = ImageSchema.parse({
198
- sourceUrl: sourceImage?.url || '',
199
- height: sourceImage?.dimensions.h || undefined,
200
- width: sourceImage?.dimensions.w || undefined,
201
- altText:
202
- sourceImage?.label ||
203
- product.name[this.context.languageContext.locale] ||
204
- undefined,
205
- });
206
-
207
- const mappedOptions =
208
- variant.attributes
209
- ?.filter((x) => x.name === 'Color')
210
- .map((opt) =>
211
- ProductVariantOptionSchema.parse({
212
- identifier: ProductOptionIdentifierSchema.parse({
213
- key: opt.name,
214
- } satisfies Partial<ProductOptionIdentifier>),
215
- name: opt.value || '',
216
- } satisfies Partial<ProductVariantOption>)
217
- ) || [];
218
-
219
- const mappedOption = mappedOptions?.[0];
220
-
221
- return ProductSearchResultItemVariantSchema.parse({
222
- variant: ProductVariantIdentifierSchema.parse({
223
- sku: variant.sku || '',
224
- } satisfies ProductVariantIdentifier),
225
- image: img,
226
- options: mappedOption,
227
- } satisfies Partial<ProductSearchResultItemVariant>);
228
- }
229
164
  }
@@ -1,6 +1,12 @@
1
1
  import type { MyShoppingListAddLineItemAction, MyShoppingListDraft, MyShoppingListUpdate, MyShoppingListUpdateAction, ShoppingList, ShoppingListLineItem } from '@commercetools/platform-sdk';
2
2
  import type {
3
3
  Cache,
4
+ ProductListFactory,
5
+ ProductListFactoryItemOutput,
6
+ ProductListFactoryItemPaginatedOutput,
7
+ ProductListFactoryListOutput,
8
+ ProductListFactoryListPaginatedOutput,
9
+ ProductListFactoryWithOutput,
4
10
  NotFoundError,
5
11
  ProductList,
6
12
  ProductListIdentifier,
@@ -8,12 +14,10 @@ import type {
8
14
  ProductListItemMutationCreate,
9
15
  ProductListItemMutationDelete,
10
16
  ProductListItemMutationUpdate,
11
- ProductListItemPaginatedResult,
12
17
  ProductListItemsQuery,
13
18
  ProductListMutationCreate,
14
19
  ProductListMutationDelete,
15
20
  ProductListMutationUpdate,
16
- ProductListPaginatedResult,
17
21
  ProductListQuery,
18
22
  ProductListQueryById,
19
23
  ProductListType,
@@ -42,20 +46,31 @@ import {
42
46
  } from '@reactionary/core';
43
47
  import type { CommercetoolsAPI } from '../core/client.js';
44
48
  import type { CommercetoolsConfiguration } from '../schema/configuration.schema.js';
45
-
46
- export class CommercetoolsProductListProvider extends ProductListProvider {
49
+ import type { CommercetoolsProductListFactory } from '../factories/product-list/product-list.factory.js';
50
+
51
+ export class CommercetoolsProductListProvider<
52
+ TFactory extends ProductListFactory = CommercetoolsProductListFactory,
53
+ > extends ProductListProvider<
54
+ ProductListFactoryListOutput<TFactory>,
55
+ ProductListFactoryItemOutput<TFactory>,
56
+ ProductListFactoryListPaginatedOutput<TFactory>,
57
+ ProductListFactoryItemPaginatedOutput<TFactory>
58
+ > {
47
59
  protected config: CommercetoolsConfiguration;
48
60
  protected commercetools: CommercetoolsAPI;
61
+ protected factory: ProductListFactoryWithOutput<TFactory>;
49
62
 
50
63
  constructor(
51
64
  config: CommercetoolsConfiguration,
52
65
  cache: Cache,
53
66
  context: RequestContext,
54
- commercetools: CommercetoolsAPI
67
+ commercetools: CommercetoolsAPI,
68
+ factory: ProductListFactoryWithOutput<TFactory>,
55
69
  ) {
56
70
  super(cache, context);
57
71
  this.config = config;
58
72
  this.commercetools = commercetools;
73
+ this.factory = factory;
59
74
  }
60
75
 
61
76
  protected async getClient() {
@@ -71,7 +86,7 @@ export class CommercetoolsProductListProvider extends ProductListProvider {
71
86
  inputSchema: ProductListQueryByIdSchema,
72
87
  outputSchema: ProductListSchema
73
88
  })
74
- public override async getById(payload: ProductListQueryById): Promise<Result<ProductList>> {
89
+ public override async getById(payload: ProductListQueryById): Promise<Result<ProductListFactoryListOutput<TFactory>>> {
75
90
  try {
76
91
  const client = await this.getClient();
77
92
  const response = await client.shoppingLists()
@@ -79,7 +94,7 @@ export class CommercetoolsProductListProvider extends ProductListProvider {
79
94
  .get()
80
95
  .execute();
81
96
 
82
- return success(this.parseSingle(response.body));
97
+ return success(this.factory.parseProductList(this.context, this.parseSingle(response.body)));
83
98
  } catch(err: any) {
84
99
  if (err.statusCode === 404) {
85
100
  return error<NotFoundError>({
@@ -101,17 +116,17 @@ export class CommercetoolsProductListProvider extends ProductListProvider {
101
116
  inputSchema: ProductListQuerySchema,
102
117
  outputSchema: ProductListPaginatedResultsSchema
103
118
  })
104
- public override async queryLists(payload: ProductListQuery): Promise<Result<ProductListPaginatedResult>> {
119
+ public override async queryLists(payload: ProductListQuery): Promise<Result<ProductListFactoryListPaginatedOutput<TFactory>>> {
105
120
 
106
121
  if (this.context.session.identityContext?.identity?.type !== 'Registered') {
107
- return success({
122
+ return success(this.factory.parseProductListPaginatedResult(this.context, {
108
123
  items: [],
109
124
  pageNumber: 1,
110
125
  pageSize: payload.search.paginationOptions.pageSize,
111
126
  totalCount: 0,
112
127
  totalPages: 0,
113
128
  identifier: payload.search,
114
- });
129
+ }));
115
130
  }
116
131
 
117
132
  const client = await this.getClient();
@@ -125,14 +140,14 @@ export class CommercetoolsProductListProvider extends ProductListProvider {
125
140
  }
126
141
  }).execute();
127
142
 
128
- return success({
143
+ return success(this.factory.parseProductListPaginatedResult(this.context, {
129
144
  items: response.body.results.map(list => this.parseSingle(list)),
130
145
  pageNumber: payload.search.paginationOptions.pageNumber,
131
146
  pageSize: payload.search.paginationOptions.pageSize,
132
147
  totalCount: response.body.total || 0,
133
148
  totalPages: Math.ceil((response.body.total || 0) / payload.search.paginationOptions.pageSize),
134
149
  identifier: payload.search,
135
- });
150
+ }));
136
151
 
137
152
  }
138
153
 
@@ -141,7 +156,7 @@ export class CommercetoolsProductListProvider extends ProductListProvider {
141
156
  inputSchema: ProductListMutationCreateSchema,
142
157
  outputSchema: ProductListSchema
143
158
  })
144
- public override async addList(mutation: ProductListMutationCreate): Promise<Result<ProductList>> {
159
+ public override async addList(mutation: ProductListMutationCreate): Promise<Result<ProductListFactoryListOutput<TFactory>>> {
145
160
  const client = await this.getClient();
146
161
  const localeString = this.getLocaleString();
147
162
 
@@ -174,7 +189,7 @@ export class CommercetoolsProductListProvider extends ProductListProvider {
174
189
  body: draft
175
190
  }).execute();
176
191
 
177
- return success(this.parseSingle(response.body));
192
+ return success(this.factory.parseProductList(this.context, this.parseSingle(response.body)));
178
193
  }
179
194
 
180
195
  @Reactionary({
@@ -182,7 +197,7 @@ export class CommercetoolsProductListProvider extends ProductListProvider {
182
197
  inputSchema: ProductListMutationUpdateSchema,
183
198
  outputSchema: ProductListSchema
184
199
  })
185
- public override async updateList(mutation: ProductListMutationUpdate): Promise<Result<ProductList>> {
200
+ public override async updateList(mutation: ProductListMutationUpdate): Promise<Result<ProductListFactoryListOutput<TFactory>>> {
186
201
  const client = await this.getClient();
187
202
  const actions: MyShoppingListUpdateAction[] = [];
188
203
  const localeString = this.getLocaleString()
@@ -234,7 +249,7 @@ export class CommercetoolsProductListProvider extends ProductListProvider {
234
249
  .post({ body: update })
235
250
  .execute();
236
251
 
237
- return success(this.parseSingle(response.body));
252
+ return success(this.factory.parseProductList(this.context, this.parseSingle(response.body)));
238
253
  }
239
254
 
240
255
  @Reactionary({
@@ -270,7 +285,7 @@ export class CommercetoolsProductListProvider extends ProductListProvider {
270
285
  inputSchema: ProductListItemQuerySchema,
271
286
  outputSchema: ProductListItemPaginatedResultsSchema
272
287
  })
273
- public override async queryListItems(query: ProductListItemsQuery): Promise<Result<ProductListItemPaginatedResult>> {
288
+ public override async queryListItems(query: ProductListItemsQuery): Promise<Result<ProductListFactoryItemPaginatedOutput<TFactory>>> {
274
289
  const client = await this.getClient();
275
290
 
276
291
  const response = await client.shoppingLists()
@@ -282,14 +297,14 @@ export class CommercetoolsProductListProvider extends ProductListProvider {
282
297
 
283
298
  const items = response.body.lineItems.map(lineItem => this.parseProductListItem(query.search.list, lineItem ));
284
299
 
285
- return success({
300
+ return success(this.factory.parseProductListItemPaginatedResult(this.context, {
286
301
  items: items.slice((query.search.paginationOptions.pageNumber - 1) * query.search.paginationOptions.pageSize, query.search.paginationOptions.pageNumber * query.search.paginationOptions.pageSize),
287
302
  identifier: query.search,
288
303
  pageNumber: query.search.paginationOptions.pageNumber,
289
304
  pageSize: query.search.paginationOptions.pageSize,
290
305
  totalCount: items.length,
291
306
  totalPages: Math.ceil(items.length / query.search.paginationOptions.pageSize),
292
- });
307
+ }));
293
308
  }
294
309
 
295
310
  @Reactionary({
@@ -297,7 +312,7 @@ export class CommercetoolsProductListProvider extends ProductListProvider {
297
312
  inputSchema: ProductListItemMutationCreateSchema,
298
313
  outputSchema: ProductListItemSchema
299
314
  })
300
- public override async addItem(mutation: ProductListItemMutationCreate): Promise<Result<ProductListItem>> {
315
+ public override async addItem(mutation: ProductListItemMutationCreate): Promise<Result<ProductListFactoryItemOutput<TFactory>>> {
301
316
  const client = await this.getClient();
302
317
 
303
318
  const lineItemDraft: MyShoppingListAddLineItemAction = {
@@ -331,7 +346,7 @@ export class CommercetoolsProductListProvider extends ProductListProvider {
331
346
  throw new Error('The added line item is not the last item in the list, cannot reliably determine the identifier of the added item');
332
347
  }
333
348
 
334
- return success(this.parseProductListItem(mutation.list, lastItem ));
349
+ return success(this.factory.parseProductListItem(this.context, this.parseProductListItem(mutation.list, lastItem)));
335
350
  }
336
351
 
337
352
  @Reactionary({
@@ -363,7 +378,7 @@ export class CommercetoolsProductListProvider extends ProductListProvider {
363
378
  inputSchema: ProductListItemMutationUpdateSchema,
364
379
  outputSchema: ProductListItemSchema
365
380
  })
366
- public override async updateItem(mutation: ProductListItemMutationUpdate): Promise<Result<ProductListItem>> {
381
+ public override async updateItem(mutation: ProductListItemMutationUpdate): Promise<Result<ProductListFactoryItemOutput<TFactory>>> {
367
382
  const client = await this.getClient();
368
383
 
369
384
  const actions: MyShoppingListUpdateAction[] = [];
@@ -408,7 +423,7 @@ export class CommercetoolsProductListProvider extends ProductListProvider {
408
423
  throw new Error('Failed to find the updated line item in response');
409
424
  }
410
425
 
411
- return success(this.parseProductListItem(mutation.listItem.list, updatedLineItem));
426
+ return success(this.factory.parseProductListItem(this.context, this.parseProductListItem(mutation.listItem.list, updatedLineItem)));
412
427
  }
413
428
 
414
429
  /**
@@ -1,4 +1,9 @@
1
1
  import {
2
+ type ProductReviewsFactory,
3
+ type ProductReviewsFactoryRatingOutput,
4
+ type ProductReviewsFactoryReviewOutput,
5
+ type ProductReviewsFactoryReviewPaginatedOutput,
6
+ type ProductReviewsFactoryWithOutput,
2
7
  ProductReviewsProvider,
3
8
  Reactionary,
4
9
  success,
@@ -8,9 +13,8 @@ import {
8
13
  ProductReviewPaginatedResultSchema,
9
14
  } from '@reactionary/core';
10
15
  import type {
11
- ProductReview,
12
16
  ProductRatingSummary,
13
- ProductReviewPaginatedResult,
17
+ ProductReview,
14
18
  ProductReviewsListQuery,
15
19
  ProductReviewsGetRatingSummaryQuery,
16
20
  ProductReviewMutationSubmit,
@@ -23,20 +27,30 @@ import type {
23
27
  import type { CommercetoolsConfiguration } from '../schema/configuration.schema.js';
24
28
  import type { CommercetoolsAPI } from '../core/client.js';
25
29
  import type { Review as CTReview } from '@commercetools/platform-sdk';
30
+ import type { CommercetoolsProductReviewsFactory } from '../factories/product-reviews/product-reviews.factory.js';
26
31
 
27
- export class CommercetoolsProductReviewsProvider extends ProductReviewsProvider {
32
+ export class CommercetoolsProductReviewsProvider<
33
+ TFactory extends ProductReviewsFactory = CommercetoolsProductReviewsFactory,
34
+ > extends ProductReviewsProvider<
35
+ ProductReviewsFactoryRatingOutput<TFactory>,
36
+ ProductReviewsFactoryReviewPaginatedOutput<TFactory>,
37
+ ProductReviewsFactoryReviewOutput<TFactory>
38
+ > {
28
39
  protected config: CommercetoolsConfiguration;
29
40
  protected commercetools: CommercetoolsAPI;
41
+ protected factory: ProductReviewsFactoryWithOutput<TFactory>;
30
42
 
31
43
  constructor(
32
44
  config: CommercetoolsConfiguration,
33
45
  cache: Cache,
34
46
  context: RequestContext,
35
- commercetools: CommercetoolsAPI
47
+ commercetools: CommercetoolsAPI,
48
+ factory: ProductReviewsFactoryWithOutput<TFactory>,
36
49
  ) {
37
50
  super(cache, context);
38
51
  this.config = config;
39
52
  this.commercetools = commercetools;
53
+ this.factory = factory;
40
54
  }
41
55
 
42
56
  protected async getClient() {
@@ -58,7 +72,7 @@ export class CommercetoolsProductReviewsProvider extends ProductReviewsProvider
58
72
  })
59
73
  public override async getRatingSummary(
60
74
  query: ProductReviewsGetRatingSummaryQuery
61
- ): Promise<Result<ProductRatingSummary>> {
75
+ ): Promise<Result<ProductReviewsFactoryRatingOutput<TFactory>>> {
62
76
  const client = await this.getClient();
63
77
 
64
78
  // Get all reviews for the product to calculate summary
@@ -80,6 +94,7 @@ export class CommercetoolsProductReviewsProvider extends ProductReviewsProvider
80
94
  },
81
95
  averageRating: 0,
82
96
  totalRatings: 0,
97
+ ratingDistribution: undefined,
83
98
  }
84
99
 
85
100
  if (response.body.reviewRatingStatistics) {
@@ -93,9 +108,14 @@ export class CommercetoolsProductReviewsProvider extends ProductReviewsProvider
93
108
  '5': response.body.reviewRatingStatistics.ratingsDistribution['5'] ?? 0,
94
109
  };
95
110
  }
96
- return success(summary);
111
+ return success(this.factory.parseRatingSummary(this.context, summary));
97
112
  } else {
98
- return success(this.createEmptyProductRatingSummary({ product: query.product }));
113
+ return success(
114
+ this.factory.parseRatingSummary(
115
+ this.context,
116
+ this.createEmptyProductRatingSummary({ product: query.product }),
117
+ ),
118
+ );
99
119
  }
100
120
  }
101
121
 
@@ -108,7 +128,7 @@ export class CommercetoolsProductReviewsProvider extends ProductReviewsProvider
108
128
  })
109
129
  public override async findReviews(
110
130
  query: ProductReviewsListQuery
111
- ): Promise<Result<ProductReviewPaginatedResult>> {
131
+ ): Promise<Result<ProductReviewsFactoryReviewPaginatedOutput<TFactory>>> {
112
132
  const client = await this.getClient();
113
133
 
114
134
  const pageNumber = query.paginationOptions?.pageNumber ?? 1;
@@ -124,13 +144,13 @@ export class CommercetoolsProductReviewsProvider extends ProductReviewsProvider
124
144
  });
125
145
 
126
146
  if (!product || !product.body) {
127
- return success({
147
+ return success(this.factory.parseReviewPaginatedResult(this.context, {
128
148
  items: [],
129
149
  totalCount: 0,
130
150
  pageSize,
131
151
  pageNumber,
132
152
  totalPages: 0,
133
- })
153
+ }));
134
154
  }
135
155
 
136
156
  // Build where clause
@@ -175,7 +195,7 @@ export class CommercetoolsProductReviewsProvider extends ProductReviewsProvider
175
195
  const reviews = response.body.results.map((review) =>
176
196
  this.parseSingle(review, query.product.key)
177
197
  );
178
- const returnedResult: ProductReviewPaginatedResult = {
198
+ const returnedResult = {
179
199
  items: reviews,
180
200
  totalCount: response.body.total || reviews.length,
181
201
  pageSize,
@@ -183,7 +203,7 @@ export class CommercetoolsProductReviewsProvider extends ProductReviewsProvider
183
203
  totalPages: Math.ceil((response.body.total || reviews.length) / Math.max(pageSize, 1)),
184
204
  };
185
205
 
186
- return success(returnedResult);
206
+ return success(this.factory.parseReviewPaginatedResult(this.context, returnedResult));
187
207
  }
188
208
 
189
209
  @Reactionary({
@@ -195,7 +215,7 @@ export class CommercetoolsProductReviewsProvider extends ProductReviewsProvider
195
215
  })
196
216
  public override async submitReview(
197
217
  mutation: ProductReviewMutationSubmit
198
- ): Promise<Result<ProductReview>> {
218
+ ): Promise<Result<ProductReviewsFactoryReviewOutput<TFactory>>> {
199
219
 
200
220
 
201
221
  if (!(this.context.session.identityContext.identity.type === 'Registered')) {
@@ -227,7 +247,7 @@ export class CommercetoolsProductReviewsProvider extends ProductReviewsProvider
227
247
 
228
248
  const review = this.parseSingle(response.body, mutation.product.key);
229
249
 
230
- return success(review);
250
+ return success(this.factory.parseReview(this.context, review));
231
251
  }
232
252
 
233
253
  protected parseSingle(review: CTReview, productKey: string): ProductReview {