@reactionary/source 0.3.18 → 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 +28 -14
  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,54 +1,61 @@
1
1
  import {
2
+ ProductRatingSummarySchema,
3
+ ProductReviewPaginatedResultSchema,
4
+ ProductReviewSchema,
2
5
  ProductReviewsProvider,
3
6
  Reactionary,
4
- success,
5
7
  error,
6
- ProductReviewSchema,
7
- ProductRatingSummarySchema,
8
- ProductReviewPaginatedResultSchema,
9
- } from '@reactionary/core';
10
- import type {
11
- ProductReview,
12
- ProductRatingSummary,
13
- ProductReviewPaginatedResult,
14
- ProductReviewsListQuery,
15
- ProductReviewsGetRatingSummaryQuery,
16
- ProductReviewMutationSubmit,
17
- Result,
18
- RequestContext,
19
- Cache,
20
- NotFoundError,
21
- InvalidInputError,
22
- ProductIdentifier,
8
+ success,
9
+ type Cache,
10
+ type InvalidInputError,
11
+ type ProductIdentifier,
12
+ type ProductRatingSummary,
13
+ type ProductReviewsFactory,
14
+ type ProductReviewsFactoryRatingOutput,
15
+ type ProductReviewsFactoryReviewOutput,
16
+ type ProductReviewsFactoryReviewPaginatedOutput,
17
+ type ProductReviewsFactoryWithOutput,
18
+ type ProductReviewsGetRatingSummaryQuery,
19
+ type ProductReviewsListQuery,
20
+ type ProductReview,
21
+ type ProductReviewMutationSubmit,
22
+ type RequestContext,
23
+ type Result,
23
24
  } from '@reactionary/core';
24
25
  import type { FakeConfiguration } from '../schema/configuration.schema.js';
25
26
  import { base, en, Faker } from '@faker-js/faker';
26
27
  import { calcSeed } from '../utilities/seed.js';
27
-
28
- export class FakeProductReviewsProvider extends ProductReviewsProvider {
28
+ import type { FakeProductReviewsFactory } from '../factories/product-reviews/product-reviews.factory.js';
29
+
30
+ export class FakeProductReviewsProvider<
31
+ TFactory extends ProductReviewsFactory = FakeProductReviewsFactory,
32
+ > extends ProductReviewsProvider<
33
+ ProductReviewsFactoryRatingOutput<TFactory>,
34
+ ProductReviewsFactoryReviewPaginatedOutput<TFactory>,
35
+ ProductReviewsFactoryReviewOutput<TFactory>
36
+ > {
29
37
  protected config: FakeConfiguration;
38
+ protected factory: ProductReviewsFactoryWithOutput<TFactory>;
30
39
  private faker: Faker;
31
40
 
32
41
  constructor(
33
42
  config: FakeConfiguration,
34
43
  cache: Cache,
35
- context: RequestContext
44
+ context: RequestContext,
45
+ factory: ProductReviewsFactoryWithOutput<TFactory>,
36
46
  ) {
37
47
  super(cache, context);
38
48
  this.config = config;
39
- this.faker = new Faker({ locale: [en] });
49
+ this.factory = factory;
50
+ this.faker = new Faker({ locale: [en, base] });
40
51
  }
41
52
 
42
53
  protected createReviewsForProduct(productIdentifier: ProductIdentifier): ProductReview[] {
43
54
  const seed = calcSeed(productIdentifier.key);
44
- this.faker.seed(seed); // Seed faker with product key for consistent results
45
-
46
- const hasAnyReviews = this.faker.datatype.boolean({ probability: 0.5 }); // 50% chance that the product has reviews
47
- if (!hasAnyReviews) {
48
- return [];
49
- }
55
+ this.faker.seed(seed);
50
56
 
51
- if (productIdentifier.key === 'unknown-product-id') {
57
+ const hasAnyReviews = this.faker.datatype.boolean({ probability: 0.5 });
58
+ if (!hasAnyReviews || productIdentifier.key === 'unknown-product-id') {
52
59
  return [];
53
60
  }
54
61
 
@@ -56,9 +63,9 @@ export class FakeProductReviewsProvider extends ProductReviewsProvider {
56
63
  const totalReviews = this.faker.number.int({ min: 1, max: 20 });
57
64
 
58
65
  for (let i = 0; i < totalReviews; i++) {
59
- const hasReply = this.faker.datatype.boolean({ probability: 0.3 }); // 30% chance that the review has a reply
66
+ const hasReply = this.faker.datatype.boolean({ probability: 0.3 });
60
67
 
61
- const review = {
68
+ reviews.push({
62
69
  identifier: {
63
70
  key: `fake-review-${productIdentifier.key}-${i}`,
64
71
  },
@@ -69,48 +76,38 @@ export class FakeProductReviewsProvider extends ProductReviewsProvider {
69
76
  title: this.faker.lorem.sentence(),
70
77
  content: this.faker.lorem.paragraphs({ min: 1, max: 5 }),
71
78
  createdAt: this.faker.date.past({ years: 1 }).toISOString(),
72
- updatedAt: this.faker.datatype.boolean() ? this.faker.date.recent({ days: 30 }).toISOString() : undefined,
79
+ updatedAt: this.faker.datatype.boolean()
80
+ ? this.faker.date.recent({ days: 30 }).toISOString()
81
+ : undefined,
73
82
  verified: this.faker.datatype.boolean(),
74
83
  reply: hasReply ? this.faker.lorem.sentences(2) : undefined,
75
84
  repliedAt: hasReply ? this.faker.date.recent({ days: 7 }).toISOString() : undefined,
76
-
77
- } satisfies ProductReview;
78
-
79
- reviews.push(review);
85
+ });
80
86
  }
81
87
 
82
- return reviews.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()); // Sort reviews by created date descending
88
+ return reviews.sort(
89
+ (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(),
90
+ );
83
91
  }
84
92
 
85
-
86
93
  @Reactionary({
87
94
  outputSchema: ProductRatingSummarySchema,
88
95
  cache: true,
89
96
  cacheTimeToLiveInSeconds: 300,
90
97
  currencyDependentCaching: false,
91
- localeDependentCaching: false
98
+ localeDependentCaching: false,
92
99
  })
93
100
  public override async getRatingSummary(
94
- query: ProductReviewsGetRatingSummaryQuery
95
- ): Promise<Result<ProductRatingSummary>> {
96
-
101
+ query: ProductReviewsGetRatingSummaryQuery,
102
+ ): Promise<Result<ProductReviewsFactoryRatingOutput<TFactory>>> {
97
103
  const reviews = this.createReviewsForProduct(query.product);
98
104
  if (reviews.length === 0) {
99
- // If there are no reviews, return a summary with averageRating 0 and totalRatings 0
100
105
  const emptySummary = this.createEmptyProductRatingSummary({ product: query.product });
101
- return success(emptySummary);
106
+ return success(this.factory.parseRatingSummary(this.context, emptySummary));
102
107
  }
103
108
 
104
109
  const totalRatings = reviews.length;
105
- const averageRating = reviews.reduce((sum, review) => sum + review.rating, 0) / (totalRatings || 1);
106
-
107
- const ratingDistribution = {
108
- '1': reviews.filter(x => x.rating === 1).length,
109
- '2': reviews.filter(x => x.rating === 2).length,
110
- '3': reviews.filter(x => x.rating === 3).length,
111
- '4': reviews.filter(x => x.rating === 4).length,
112
- '5': reviews.filter(x => x.rating === 5).length,
113
- };
110
+ const averageRating = reviews.reduce((sum, review) => sum + review.rating, 0) / totalRatings;
114
111
 
115
112
  const summary: ProductRatingSummary = {
116
113
  identifier: {
@@ -118,10 +115,16 @@ export class FakeProductReviewsProvider extends ProductReviewsProvider {
118
115
  },
119
116
  averageRating,
120
117
  totalRatings,
121
- ratingDistribution,
118
+ ratingDistribution: {
119
+ '1': reviews.filter((x) => x.rating === 1).length,
120
+ '2': reviews.filter((x) => x.rating === 2).length,
121
+ '3': reviews.filter((x) => x.rating === 3).length,
122
+ '4': reviews.filter((x) => x.rating === 4).length,
123
+ '5': reviews.filter((x) => x.rating === 5).length,
124
+ },
122
125
  };
123
126
 
124
- return success(summary);
127
+ return success(this.factory.parseRatingSummary(this.context, summary));
125
128
  }
126
129
 
127
130
  @Reactionary({
@@ -129,19 +132,18 @@ export class FakeProductReviewsProvider extends ProductReviewsProvider {
129
132
  cache: true,
130
133
  cacheTimeToLiveInSeconds: 60,
131
134
  currencyDependentCaching: false,
132
- localeDependentCaching: true
135
+ localeDependentCaching: true,
133
136
  })
134
137
  public override async findReviews(
135
- query: ProductReviewsListQuery
136
- ): Promise<Result<ProductReviewPaginatedResult>> {
138
+ query: ProductReviewsListQuery,
139
+ ): Promise<Result<ProductReviewsFactoryReviewPaginatedOutput<TFactory>>> {
137
140
  const pageSize = query.paginationOptions?.pageSize ?? 20;
138
141
  const pageNumber = query.paginationOptions?.pageNumber ?? 1;
139
142
 
140
143
  const reviews = this.createReviewsForProduct(query.product);
141
-
142
144
  const returnedReviews = reviews.slice((pageNumber - 1) * pageSize, pageNumber * pageSize);
143
145
 
144
- const paginatedResult: ProductReviewPaginatedResult = {
146
+ const result = {
145
147
  items: returnedReviews,
146
148
  totalCount: reviews.length,
147
149
  pageSize,
@@ -149,7 +151,7 @@ export class FakeProductReviewsProvider extends ProductReviewsProvider {
149
151
  totalPages: Math.ceil(reviews.length / Math.max(pageSize, 1)),
150
152
  };
151
153
 
152
- return success(paginatedResult);
154
+ return success(this.factory.parseReviewPaginatedResult(this.context, result));
153
155
  }
154
156
 
155
157
  @Reactionary({
@@ -157,18 +159,18 @@ export class FakeProductReviewsProvider extends ProductReviewsProvider {
157
159
  cache: false,
158
160
  cacheTimeToLiveInSeconds: 0,
159
161
  currencyDependentCaching: false,
160
- localeDependentCaching: false
162
+ localeDependentCaching: false,
161
163
  })
162
164
  public override async submitReview(
163
- mutation: ProductReviewMutationSubmit
164
- ): Promise<Result<ProductReview>> {
165
- // For fake provider, we always succeed and return a fake review
166
-
165
+ mutation: ProductReviewMutationSubmit,
166
+ ): Promise<Result<ProductReviewsFactoryReviewOutput<TFactory>>> {
167
167
  if (this.context.session.identityContext.identity.type !== 'Registered') {
168
- return error<InvalidInputError>({ type: 'InvalidInput', error: 'Only registered users can submit reviews.' });
168
+ return error<InvalidInputError>({
169
+ type: 'InvalidInput',
170
+ error: 'Only registered users can submit reviews.',
171
+ });
169
172
  }
170
173
 
171
-
172
174
  const review: ProductReview = {
173
175
  identifier: {
174
176
  key: this.faker.string.uuid(),
@@ -182,6 +184,6 @@ export class FakeProductReviewsProvider extends ProductReviewsProvider {
182
184
  verified: this.faker.datatype.boolean(),
183
185
  };
184
186
 
185
- return success(review);
187
+ return success(this.factory.parseReview(this.context, review));
186
188
  }
187
189
  }
@@ -6,40 +6,42 @@ import {
6
6
  ProductSearchResultSchema,
7
7
  Reactionary,
8
8
  success,
9
- error,
10
- } from '@reactionary/core';
11
- import type {
12
- ProductSearchResult,
13
- ProductSearchResultFacet,
14
- ProductSearchResultItem,
15
- Cache as ReactionaryCache,
16
- Image,
17
- FacetIdentifier,
18
- FacetValueIdentifier,
19
- ProductSearchResultFacetValue,
20
- ProductSearchResultItemVariant,
21
- ProductSearchQueryCreateNavigationFilter,
22
- Result,
23
- } from '@reactionary/core';
24
- import type {
25
- RequestContext,
26
- ProductSearchQueryByTerm,
9
+ type Cache,
10
+ type FacetIdentifier,
11
+ type FacetValueIdentifier,
12
+ type ProductSearchFactory,
13
+ type ProductSearchFactoryOutput,
14
+ type ProductSearchFactoryWithOutput,
15
+ type ProductSearchQueryByTerm,
16
+ type ProductSearchQueryCreateNavigationFilter,
17
+ type ProductSearchResult,
18
+ type ProductSearchResultFacet,
19
+ type ProductSearchResultItem,
20
+ type ProductSearchResultItemVariant,
21
+ type RequestContext,
22
+ type Result,
27
23
  } from '@reactionary/core';
28
24
  import type { FakeConfiguration } from '../schema/configuration.schema.js';
29
25
  import { Faker, en, base } from '@faker-js/faker';
30
26
  import { jitter } from '../utilities/jitter.js';
27
+ import type { FakeProductSearchFactory } from '../factories/product-search/product-search.factory.js';
31
28
 
32
- export class FakeSearchProvider extends ProductSearchProvider {
29
+ export class FakeSearchProvider<
30
+ TFactory extends ProductSearchFactory = FakeProductSearchFactory,
31
+ > extends ProductSearchProvider<ProductSearchFactoryOutput<TFactory>> {
33
32
  protected config: FakeConfiguration;
33
+ protected factory: ProductSearchFactoryWithOutput<TFactory>;
34
34
 
35
35
  constructor(
36
36
  config: FakeConfiguration,
37
- cache: ReactionaryCache,
38
- context: RequestContext
37
+ cache: Cache,
38
+ context: RequestContext,
39
+ factory: ProductSearchFactoryWithOutput<TFactory>,
39
40
  ) {
40
41
  super(cache, context);
41
42
 
42
43
  this.config = config;
44
+ this.factory = factory;
43
45
  }
44
46
 
45
47
  @Reactionary({
@@ -47,25 +49,17 @@ export class FakeSearchProvider extends ProductSearchProvider {
47
49
  outputSchema: ProductSearchResultSchema,
48
50
  })
49
51
  public override async queryByTerm(
50
- payload: ProductSearchQueryByTerm
51
- ): Promise<Result<ProductSearchResult>> {
52
+ payload: ProductSearchQueryByTerm,
53
+ ): Promise<Result<ProductSearchFactoryOutput<TFactory>>> {
52
54
  await jitter(this.config.jitter.mean, this.config.jitter.deviation);
53
55
 
54
56
  const query = payload.search;
55
57
 
56
58
  const querySpecificity =
57
- 20 -
58
- query.term.length -
59
- query.paginationOptions.pageNumber -
60
- query.facets.length;
59
+ 20 - query.term.length - query.paginationOptions.pageNumber - query.facets.length;
61
60
  const totalProducts = 10 * querySpecificity;
62
- const totalPages = Math.ceil(
63
- totalProducts / query.paginationOptions.pageSize
64
- );
65
- const productsOnPage = Math.min(
66
- totalProducts,
67
- query.paginationOptions.pageSize
68
- );
61
+ const totalPages = Math.ceil(totalProducts / query.paginationOptions.pageSize);
62
+ const productsOnPage = Math.min(totalProducts, query.paginationOptions.pageSize);
69
63
 
70
64
  const productGenerator = new Faker({
71
65
  seed: querySpecificity,
@@ -77,8 +71,8 @@ export class FakeSearchProvider extends ProductSearchProvider {
77
71
  locale: [en, base],
78
72
  });
79
73
 
80
- const products = new Array<ProductSearchResultItem>();
81
- const facets = new Array<ProductSearchResultFacet>();
74
+ const products: ProductSearchResultItem[] = [];
75
+ const facets: ProductSearchResultFacet[] = [];
82
76
 
83
77
  for (let i = 0; i < productsOnPage; i++) {
84
78
  const srcUrl = productGenerator.image.urlPicsumPhotos({
@@ -93,12 +87,12 @@ export class FakeSearchProvider extends ProductSearchProvider {
93
87
  altText: 'Fake product image',
94
88
  height: 300,
95
89
  width: 300,
96
- } satisfies Partial<Image>);
90
+ });
97
91
 
98
92
  products.push(
99
93
  ProductSearchResultItemSchema.parse({
100
94
  identifier: {
101
- key: 'product_' + productGenerator.commerce.isbn(),
95
+ key: `product_${productGenerator.commerce.isbn()}`,
102
96
  },
103
97
  name: productGenerator.commerce.productName(),
104
98
  slug: productGenerator.lorem.slug(),
@@ -111,18 +105,16 @@ export class FakeSearchProvider extends ProductSearchProvider {
111
105
  options: undefined,
112
106
  } satisfies Partial<ProductSearchResultItemVariant>,
113
107
  ],
114
- } satisfies Partial<ProductSearchResultItem>)
108
+ }),
115
109
  );
116
110
  }
117
111
 
118
- const facetBase = ['color', 'size'];
119
-
120
- for (const base of facetBase) {
112
+ for (const baseFacet of ['color', 'size']) {
121
113
  const facet: ProductSearchResultFacet = {
122
114
  identifier: {
123
- key: base,
115
+ key: baseFacet,
124
116
  },
125
- name: base,
117
+ name: baseFacet,
126
118
  values: [],
127
119
  };
128
120
 
@@ -130,7 +122,7 @@ export class FakeSearchProvider extends ProductSearchProvider {
130
122
  const valueKey = i.toString();
131
123
  const isActive =
132
124
  query.facets.find(
133
- (x) => x.facet.key === facet.identifier.key && x.key === valueKey
125
+ (x) => x.facet.key === facet.identifier.key && x.key === valueKey,
134
126
  ) !== undefined;
135
127
 
136
128
  facet.values.push({
@@ -149,7 +141,7 @@ export class FakeSearchProvider extends ProductSearchProvider {
149
141
  facets.push(facet);
150
142
  }
151
143
 
152
- const result = ProductSearchResultSchema.parse({
144
+ const result = {
153
145
  identifier: {
154
146
  term: query.term,
155
147
  paginationOptions: {
@@ -159,19 +151,19 @@ export class FakeSearchProvider extends ProductSearchProvider {
159
151
  facets: query.facets,
160
152
  filters: [],
161
153
  },
162
- facets: facets,
154
+ facets,
163
155
  items: products,
164
156
  pageNumber: query.paginationOptions.pageNumber,
165
157
  pageSize: query.paginationOptions.pageSize,
166
158
  totalCount: totalProducts,
167
- totalPages: totalPages,
168
- } satisfies ProductSearchResult);
159
+ totalPages,
160
+ } satisfies ProductSearchResult;
169
161
 
170
- return success(result);
162
+ return success(this.factory.parseSearchResult(this.context, result, payload));
171
163
  }
172
164
 
173
165
  public override async createCategoryNavigationFilter(
174
- payload: ProductSearchQueryCreateNavigationFilter
166
+ payload: ProductSearchQueryCreateNavigationFilter,
175
167
  ): Promise<Result<FacetValueIdentifier>> {
176
168
  const facetIdentifier = {
177
169
  key: 'category',
@@ -184,23 +176,4 @@ export class FakeSearchProvider extends ProductSearchProvider {
184
176
  return success(facetValueIdentifier);
185
177
  }
186
178
 
187
- protected override parseFacetValue(
188
- facetValueIdentifier: FacetValueIdentifier,
189
- label: string,
190
- count: number
191
- ): ProductSearchResultFacetValue {
192
- throw new Error('Method not implemented.');
193
- }
194
- protected override parseFacet(
195
- facetIdentifier: FacetIdentifier,
196
- facetValue: unknown
197
- ): ProductSearchResultFacet {
198
- throw new Error('Method not implemented.');
199
- }
200
- protected override parseVariant(
201
- variant: unknown,
202
- product: unknown
203
- ): ProductSearchResultItemVariant {
204
- throw new Error('Method not implemented.');
205
- }
206
179
  }
@@ -1,36 +1,41 @@
1
1
  import {
2
+ type Cache,
3
+ type NotFoundError,
4
+ type ProductFactory,
5
+ type ProductFactoryOutput,
6
+ type ProductFactoryWithOutput,
2
7
  type ProductQueryById,
8
+ ProductQueryByIdSchema,
9
+ type ProductQueryBySKU,
10
+ ProductQueryBySKUSchema,
3
11
  type ProductQueryBySlug,
4
- type RequestContext,
5
- type Cache as ReactinaryCache,
12
+ ProductQueryBySlugSchema,
6
13
  ProductProvider,
7
- Reactionary,
8
- type ProductQueryBySKU,
9
- type Product,
10
- ProductQueryByIdSchema,
11
14
  ProductSchema,
12
- ProductQueryBySlugSchema,
13
- ProductQueryBySKUSchema,
15
+ type RequestContext,
14
16
  type Result,
15
- error,
17
+ Reactionary,
16
18
  success,
17
- type NotFoundError,
18
19
  } from '@reactionary/core';
19
- import type * as z from 'zod';
20
20
  import type { FakeConfiguration } from '../schema/configuration.schema.js';
21
21
  import { base, en, Faker } from '@faker-js/faker';
22
+ import type { FakeProductFactory } from '../factories/product/product.factory.js';
22
23
 
23
- export class FakeProductProvider extends ProductProvider {
24
+ export class FakeProductProvider<
25
+ TFactory extends ProductFactory = FakeProductFactory,
26
+ > extends ProductProvider<ProductFactoryOutput<TFactory>> {
24
27
  protected config: FakeConfiguration;
28
+ protected factory: ProductFactoryWithOutput<TFactory>;
25
29
 
26
30
  constructor(
27
31
  config: FakeConfiguration,
28
- cache: ReactinaryCache,
29
- context: RequestContext
32
+ cache: Cache,
33
+ context: RequestContext,
34
+ factory: ProductFactoryWithOutput<TFactory>,
30
35
  ) {
31
36
  super(cache, context);
32
-
33
37
  this.config = config;
38
+ this.factory = factory;
34
39
  }
35
40
 
36
41
  @Reactionary({
@@ -42,9 +47,9 @@ export class FakeProductProvider extends ProductProvider {
42
47
  localeDependentCaching: true,
43
48
  })
44
49
  public override async getById(
45
- payload: ProductQueryById
46
- ): Promise<Result<Product>> {
47
- return success(this.parseSingle(payload.identifier.key));
50
+ payload: ProductQueryById,
51
+ ): Promise<Result<ProductFactoryOutput<TFactory>>> {
52
+ return success(this.composeSingle(payload.identifier.key));
48
53
  }
49
54
 
50
55
  @Reactionary({
@@ -52,9 +57,9 @@ export class FakeProductProvider extends ProductProvider {
52
57
  outputSchema: ProductSchema,
53
58
  })
54
59
  public override async getBySlug(
55
- payload: ProductQueryBySlug
56
- ): Promise<Result<Product, NotFoundError>> {
57
- return success(this.parseSingle(payload.slug));
60
+ payload: ProductQueryBySlug,
61
+ ): Promise<Result<ProductFactoryOutput<TFactory>, NotFoundError>> {
62
+ return success(this.composeSingle(payload.slug));
58
63
  }
59
64
 
60
65
  @Reactionary({
@@ -62,26 +67,23 @@ export class FakeProductProvider extends ProductProvider {
62
67
  outputSchema: ProductSchema,
63
68
  })
64
69
  public override async getBySKU(
65
- payload: ProductQueryBySKU
66
- ): Promise<Result<Product>> {
67
- return success(this.parseSingle(payload.variant.sku));
70
+ payload: ProductQueryBySKU,
71
+ ): Promise<Result<ProductFactoryOutput<TFactory>>> {
72
+ return success(this.composeSingle(payload.variant.sku));
68
73
  }
69
74
 
70
- protected parseSingle(body: string): Product {
75
+ protected composeSingle(body: string): ProductFactoryOutput<TFactory> {
71
76
  const generator = new Faker({
72
77
  seed: 42,
73
78
  locale: [en, base],
74
79
  });
75
80
 
76
- const key = body;
77
-
78
- // Merge the generated data into the model
79
81
  const result = {
80
82
  identifier: {
81
- key: key,
83
+ key: body,
82
84
  },
83
85
  name: generator.commerce.productName(),
84
- slug: key,
86
+ slug: body,
85
87
  brand: '',
86
88
  longDescription: '',
87
89
  mainVariant: {
@@ -103,8 +105,8 @@ export class FakeProductProvider extends ProductProvider {
103
105
  published: true,
104
106
  sharedAttributes: [],
105
107
  variants: [],
106
- } satisfies Product;
108
+ };
107
109
 
108
- return result;
110
+ return this.factory.parseProduct(this.context, result);
109
111
  }
110
112
  }