@reactionary/source 0.0.52 → 0.2.16

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 (293) hide show
  1. package/.env-template +19 -0
  2. package/.github/workflows/pull-request.yml +3 -1
  3. package/.github/workflows/release.yml +9 -0
  4. package/.vscode/extensions.json +0 -2
  5. package/LICENSE +21 -0
  6. package/README.md +175 -23
  7. package/core/package.json +6 -3
  8. package/core/src/cache/cache.interface.ts +1 -0
  9. package/core/src/cache/index.ts +4 -0
  10. package/core/src/cache/memory-cache.ts +30 -2
  11. package/core/src/cache/noop-cache.ts +15 -1
  12. package/core/src/cache/redis-cache.ts +20 -0
  13. package/core/src/client/client-builder.ts +71 -54
  14. package/core/src/client/client.ts +9 -47
  15. package/core/src/client/index.ts +2 -0
  16. package/core/src/decorators/index.ts +1 -0
  17. package/core/src/decorators/reactionary.decorator.ts +203 -34
  18. package/core/src/index.ts +6 -19
  19. package/core/src/initialization.ts +1 -18
  20. package/core/src/metrics/metrics.ts +67 -0
  21. package/core/src/providers/analytics.provider.ts +1 -6
  22. package/core/src/providers/base.provider.ts +5 -69
  23. package/core/src/providers/cart.provider.ts +15 -55
  24. package/core/src/providers/category.provider.ts +7 -11
  25. package/core/src/providers/checkout.provider.ts +17 -15
  26. package/core/src/providers/identity.provider.ts +6 -8
  27. package/core/src/providers/index.ts +2 -1
  28. package/core/src/providers/inventory.provider.ts +15 -5
  29. package/core/src/providers/order-search.provider.ts +29 -0
  30. package/core/src/providers/order.provider.ts +47 -15
  31. package/core/src/providers/price.provider.ts +30 -36
  32. package/core/src/providers/product-search.provider.ts +61 -0
  33. package/core/src/providers/product.provider.ts +71 -12
  34. package/core/src/providers/profile.provider.ts +74 -14
  35. package/core/src/providers/store.provider.ts +3 -5
  36. package/core/src/schemas/capabilities.schema.ts +10 -3
  37. package/core/src/schemas/errors/generic.error.ts +9 -0
  38. package/core/src/schemas/errors/index.ts +4 -0
  39. package/core/src/schemas/errors/invalid-input.error.ts +9 -0
  40. package/core/src/schemas/errors/invalid-output.error.ts +9 -0
  41. package/core/src/schemas/errors/not-found.error.ts +9 -0
  42. package/core/src/schemas/index.ts +7 -0
  43. package/core/src/schemas/models/analytics.model.ts +2 -1
  44. package/core/src/schemas/models/base.model.ts +6 -24
  45. package/core/src/schemas/models/cart.model.ts +5 -8
  46. package/core/src/schemas/models/category.model.ts +4 -9
  47. package/core/src/schemas/models/checkout.model.ts +6 -7
  48. package/core/src/schemas/models/cost.model.ts +4 -3
  49. package/core/src/schemas/models/currency.model.ts +2 -1
  50. package/core/src/schemas/models/identifiers.model.ts +106 -62
  51. package/core/src/schemas/models/identity.model.ts +10 -19
  52. package/core/src/schemas/models/index.ts +2 -1
  53. package/core/src/schemas/models/inventory.model.ts +8 -5
  54. package/core/src/schemas/models/order-search.model.ts +28 -0
  55. package/core/src/schemas/models/order.model.ts +20 -26
  56. package/core/src/schemas/models/payment.model.ts +14 -17
  57. package/core/src/schemas/models/price.model.ts +11 -11
  58. package/core/src/schemas/models/product-search.model.ts +42 -0
  59. package/core/src/schemas/models/product.model.ts +64 -22
  60. package/core/src/schemas/models/profile.model.ts +19 -22
  61. package/core/src/schemas/models/shipping-method.model.ts +24 -29
  62. package/core/src/schemas/models/store.model.ts +9 -5
  63. package/core/src/schemas/mutations/analytics.mutation.ts +8 -7
  64. package/core/src/schemas/mutations/base.mutation.ts +2 -1
  65. package/core/src/schemas/mutations/cart.mutation.ts +33 -33
  66. package/core/src/schemas/mutations/checkout.mutation.ts +23 -30
  67. package/core/src/schemas/mutations/identity.mutation.ts +4 -3
  68. package/core/src/schemas/mutations/profile.mutation.ts +38 -3
  69. package/core/src/schemas/queries/base.query.ts +2 -1
  70. package/core/src/schemas/queries/cart.query.ts +3 -3
  71. package/core/src/schemas/queries/category.query.ts +18 -18
  72. package/core/src/schemas/queries/checkout.query.ts +7 -9
  73. package/core/src/schemas/queries/identity.query.ts +2 -1
  74. package/core/src/schemas/queries/index.ts +2 -1
  75. package/core/src/schemas/queries/inventory.query.ts +5 -5
  76. package/core/src/schemas/queries/order-search.query.ts +10 -0
  77. package/core/src/schemas/queries/order.query.ts +3 -2
  78. package/core/src/schemas/queries/price.query.ts +10 -4
  79. package/core/src/schemas/queries/product-search.query.ts +16 -0
  80. package/core/src/schemas/queries/product.query.ts +13 -6
  81. package/core/src/schemas/queries/profile.query.ts +5 -2
  82. package/core/src/schemas/queries/store.query.ts +6 -5
  83. package/core/src/schemas/result.ts +107 -0
  84. package/core/src/schemas/session.schema.ts +4 -4
  85. package/core/src/test/reactionary.decorator.spec.ts +249 -0
  86. package/core/src/zod-utils.ts +19 -0
  87. package/core/tsconfig.json +1 -1
  88. package/core/tsconfig.spec.json +2 -26
  89. package/core/vitest.config.ts +14 -0
  90. package/documentation/1-purpose.md +114 -0
  91. package/documentation/2-getting-started.md +229 -0
  92. package/documentation/3-querying-and-changing-data.md +74 -0
  93. package/documentation/4-product-data.md +107 -0
  94. package/documentation/5-cart-and-checkout.md +211 -0
  95. package/documentation/6-product-search.md +143 -0
  96. package/documentation/7-marketing.md +3 -0
  97. package/eslint.config.mjs +1 -0
  98. package/examples/node/eslint.config.mjs +1 -4
  99. package/examples/node/package.json +10 -3
  100. package/examples/node/project.json +4 -1
  101. package/examples/node/src/basic/basic-node-provider-model-extension.spec.ts +22 -23
  102. package/examples/node/src/basic/basic-node-provider-query-extension.spec.ts +15 -11
  103. package/examples/node/src/basic/basic-node-setup.spec.ts +44 -28
  104. package/examples/node/src/basic/client-creation.spec.ts +53 -0
  105. package/examples/node/src/capabilities/cart.spec.ts +255 -0
  106. package/examples/node/src/capabilities/category.spec.ts +193 -0
  107. package/examples/node/src/capabilities/checkout.spec.ts +341 -0
  108. package/examples/node/src/capabilities/identity.spec.ts +93 -0
  109. package/examples/node/src/capabilities/inventory.spec.ts +66 -0
  110. package/examples/node/src/capabilities/order-search.spec.ts +265 -0
  111. package/examples/node/src/capabilities/order.spec.ts +91 -0
  112. package/examples/node/src/capabilities/price.spec.ts +51 -0
  113. package/examples/node/src/capabilities/product-search.spec.ts +293 -0
  114. package/examples/node/src/capabilities/product.spec.ts +122 -0
  115. package/examples/node/src/capabilities/profile.spec.ts +316 -0
  116. package/examples/node/src/capabilities/store.spec.ts +26 -0
  117. package/examples/node/src/utils.ts +147 -0
  118. package/examples/node/tsconfig.json +9 -12
  119. package/examples/node/tsconfig.lib.json +1 -2
  120. package/examples/node/tsconfig.spec.json +2 -14
  121. package/examples/node/vitest.config.ts +14 -0
  122. package/migrations.json +22 -5
  123. package/nx.json +8 -47
  124. package/package.json +24 -96
  125. package/providers/algolia/README.md +39 -2
  126. package/providers/algolia/package.json +2 -1
  127. package/providers/algolia/src/core/initialize.ts +7 -14
  128. package/providers/algolia/src/index.ts +2 -4
  129. package/providers/algolia/src/providers/index.ts +1 -0
  130. package/providers/algolia/src/providers/product-search.provider.ts +241 -0
  131. package/providers/algolia/src/schema/capabilities.schema.ts +2 -3
  132. package/providers/algolia/src/schema/index.ts +3 -0
  133. package/providers/algolia/src/schema/search.schema.ts +8 -8
  134. package/providers/algolia/tsconfig.json +1 -1
  135. package/providers/algolia/tsconfig.lib.json +1 -1
  136. package/providers/algolia/tsconfig.spec.json +2 -14
  137. package/providers/algolia/vitest.config.ts +14 -0
  138. package/providers/commercetools/README.md +30 -3
  139. package/providers/commercetools/package.json +2 -1
  140. package/providers/commercetools/src/core/client.ts +178 -99
  141. package/providers/commercetools/src/core/initialize.ts +130 -74
  142. package/providers/commercetools/src/core/token-cache.ts +45 -0
  143. package/providers/commercetools/src/index.ts +3 -2
  144. package/providers/commercetools/src/providers/cart.provider.ts +281 -341
  145. package/providers/commercetools/src/providers/category.provider.ts +223 -138
  146. package/providers/commercetools/src/providers/checkout.provider.ts +631 -449
  147. package/providers/commercetools/src/providers/identity.provider.ts +50 -29
  148. package/providers/commercetools/src/providers/index.ts +2 -2
  149. package/providers/commercetools/src/providers/inventory.provider.ts +76 -74
  150. package/providers/commercetools/src/providers/order-search.provider.ts +220 -0
  151. package/providers/commercetools/src/providers/order.provider.ts +96 -61
  152. package/providers/commercetools/src/providers/price.provider.ts +147 -117
  153. package/providers/commercetools/src/providers/product-search.provider.ts +528 -0
  154. package/providers/commercetools/src/providers/product.provider.ts +249 -74
  155. package/providers/commercetools/src/providers/profile.provider.ts +445 -28
  156. package/providers/commercetools/src/providers/store.provider.ts +54 -40
  157. package/providers/commercetools/src/schema/capabilities.schema.ts +3 -1
  158. package/providers/commercetools/src/schema/commercetools.schema.ts +17 -3
  159. package/providers/commercetools/src/schema/configuration.schema.ts +1 -0
  160. package/providers/commercetools/src/schema/session.schema.ts +7 -0
  161. package/providers/commercetools/src/test/caching.spec.ts +82 -0
  162. package/providers/commercetools/src/test/identity.spec.ts +109 -0
  163. package/providers/commercetools/src/test/test-utils.ts +21 -19
  164. package/providers/commercetools/tsconfig.json +1 -1
  165. package/providers/commercetools/tsconfig.lib.json +1 -1
  166. package/providers/commercetools/tsconfig.spec.json +2 -14
  167. package/providers/commercetools/vitest.config.ts +15 -0
  168. package/providers/fake/README.md +20 -4
  169. package/providers/fake/package.json +2 -1
  170. package/providers/fake/src/core/initialize.ts +47 -49
  171. package/providers/fake/src/providers/analytics.provider.ts +5 -7
  172. package/providers/fake/src/providers/cart.provider.ts +163 -92
  173. package/providers/fake/src/providers/category.provider.ts +78 -50
  174. package/providers/fake/src/providers/checkout.provider.ts +254 -0
  175. package/providers/fake/src/providers/identity.provider.ts +57 -65
  176. package/providers/fake/src/providers/index.ts +6 -2
  177. package/providers/fake/src/providers/inventory.provider.ts +40 -36
  178. package/providers/fake/src/providers/order-search.provider.ts +78 -0
  179. package/providers/fake/src/providers/order.provider.ts +106 -0
  180. package/providers/fake/src/providers/price.provider.ts +93 -41
  181. package/providers/fake/src/providers/product-search.provider.ts +206 -0
  182. package/providers/fake/src/providers/product.provider.ts +56 -41
  183. package/providers/fake/src/providers/profile.provider.ts +147 -0
  184. package/providers/fake/src/providers/store.provider.ts +30 -20
  185. package/providers/fake/src/schema/capabilities.schema.ts +5 -1
  186. package/providers/fake/src/test/cart.provider.spec.ts +59 -80
  187. package/providers/fake/src/test/category.provider.spec.ts +145 -87
  188. package/providers/fake/src/test/checkout.provider.spec.ts +222 -0
  189. package/providers/fake/src/test/order-search.provider.spec.ts +50 -0
  190. package/providers/fake/src/test/order.provider.spec.ts +44 -0
  191. package/providers/fake/src/test/price.provider.spec.ts +50 -45
  192. package/providers/fake/src/test/product.provider.spec.ts +15 -7
  193. package/providers/fake/src/test/profile.provider.spec.ts +167 -0
  194. package/providers/fake/tsconfig.json +1 -1
  195. package/providers/fake/tsconfig.lib.json +1 -1
  196. package/providers/fake/tsconfig.spec.json +2 -12
  197. package/providers/fake/vitest.config.ts +14 -0
  198. package/providers/medusa/README.md +30 -0
  199. package/providers/medusa/TESTING.md +98 -0
  200. package/providers/medusa/eslint.config.mjs +19 -0
  201. package/providers/medusa/package.json +22 -0
  202. package/providers/medusa/project.json +34 -0
  203. package/providers/medusa/src/core/client.ts +370 -0
  204. package/providers/medusa/src/core/initialize.ts +78 -0
  205. package/providers/medusa/src/index.ts +13 -0
  206. package/providers/medusa/src/providers/cart.provider.ts +575 -0
  207. package/providers/medusa/src/providers/category.provider.ts +247 -0
  208. package/providers/medusa/src/providers/checkout.provider.ts +636 -0
  209. package/providers/medusa/src/providers/identity.provider.ts +137 -0
  210. package/providers/medusa/src/providers/inventory.provider.ts +173 -0
  211. package/providers/medusa/src/providers/order-search.provider.ts +202 -0
  212. package/providers/medusa/src/providers/order.provider.ts +226 -0
  213. package/providers/medusa/src/providers/price.provider.ts +140 -0
  214. package/providers/medusa/src/providers/product-search.provider.ts +243 -0
  215. package/providers/medusa/src/providers/product.provider.ts +261 -0
  216. package/providers/medusa/src/providers/profile.provider.ts +392 -0
  217. package/providers/medusa/src/schema/capabilities.schema.ts +18 -0
  218. package/providers/medusa/src/schema/configuration.schema.ts +11 -0
  219. package/providers/medusa/src/schema/medusa.schema.ts +31 -0
  220. package/providers/medusa/src/test/cart.provider.spec.ts +240 -0
  221. package/providers/medusa/src/test/category.provider.spec.ts +231 -0
  222. package/providers/medusa/src/test/checkout.spec.ts +349 -0
  223. package/providers/medusa/src/test/identity.provider.spec.ts +122 -0
  224. package/providers/medusa/src/test/inventory.provider.spec.ts +88 -0
  225. package/providers/medusa/src/test/large-cart.provider.spec.ts +103 -0
  226. package/providers/medusa/src/test/price.provider.spec.ts +104 -0
  227. package/providers/medusa/src/test/product.provider.spec.ts +146 -0
  228. package/providers/medusa/src/test/search.provider.spec.ts +203 -0
  229. package/providers/medusa/src/test/test-utils.ts +13 -0
  230. package/providers/medusa/src/utils/medusa-helpers.ts +89 -0
  231. package/providers/medusa/tsconfig.json +21 -0
  232. package/providers/medusa/tsconfig.lib.json +9 -0
  233. package/providers/medusa/tsconfig.spec.json +4 -0
  234. package/providers/medusa/vitest.config.ts +15 -0
  235. package/providers/meilisearch/README.md +48 -0
  236. package/providers/meilisearch/eslint.config.mjs +22 -0
  237. package/providers/meilisearch/package.json +13 -0
  238. package/providers/meilisearch/project.json +34 -0
  239. package/providers/meilisearch/src/core/initialize.ts +21 -0
  240. package/providers/meilisearch/src/index.ts +6 -0
  241. package/providers/meilisearch/src/providers/index.ts +1 -0
  242. package/providers/meilisearch/src/providers/order-search.provider.ts +222 -0
  243. package/providers/meilisearch/src/providers/product-search.provider.ts +251 -0
  244. package/providers/meilisearch/src/schema/capabilities.schema.ts +10 -0
  245. package/providers/meilisearch/src/schema/configuration.schema.ts +11 -0
  246. package/providers/meilisearch/src/schema/index.ts +3 -0
  247. package/providers/meilisearch/src/schema/search.schema.ts +14 -0
  248. package/providers/meilisearch/tsconfig.json +24 -0
  249. package/providers/meilisearch/tsconfig.lib.json +10 -0
  250. package/providers/meilisearch/tsconfig.spec.json +4 -0
  251. package/providers/meilisearch/vitest.config.ts +14 -0
  252. package/providers/posthog/package.json +2 -1
  253. package/providers/posthog/tsconfig.json +1 -1
  254. package/tsconfig.base.json +5 -0
  255. package/vitest.config.ts +10 -0
  256. package/core/src/providers/search.provider.ts +0 -18
  257. package/core/src/schemas/models/search.model.ts +0 -36
  258. package/core/src/schemas/queries/search.query.ts +0 -9
  259. package/examples/next/.swcrc +0 -30
  260. package/examples/next/eslint.config.mjs +0 -21
  261. package/examples/next/index.d.ts +0 -6
  262. package/examples/next/next-env.d.ts +0 -5
  263. package/examples/next/next.config.js +0 -31
  264. package/examples/next/project.json +0 -9
  265. package/examples/next/public/.gitkeep +0 -0
  266. package/examples/next/public/favicon.ico +0 -0
  267. package/examples/next/src/app/global.css +0 -0
  268. package/examples/next/src/app/layout.tsx +0 -18
  269. package/examples/next/src/app/page.module.scss +0 -2
  270. package/examples/next/src/app/page.tsx +0 -47
  271. package/examples/next/src/instrumentation.ts +0 -9
  272. package/examples/next/tsconfig.json +0 -44
  273. package/examples/node/jest.config.ts +0 -10
  274. package/jest.config.ts +0 -6
  275. package/jest.preset.js +0 -3
  276. package/providers/algolia/jest.config.ts +0 -10
  277. package/providers/algolia/src/providers/product.provider.ts +0 -66
  278. package/providers/algolia/src/providers/search.provider.ts +0 -106
  279. package/providers/algolia/src/test/search.provider.spec.ts +0 -91
  280. package/providers/commercetools/jest.config.cjs +0 -10
  281. package/providers/commercetools/src/providers/search.provider.ts +0 -96
  282. package/providers/commercetools/src/test/cart.provider.spec.ts +0 -199
  283. package/providers/commercetools/src/test/category.provider.spec.ts +0 -168
  284. package/providers/commercetools/src/test/checkout.provider.spec.ts +0 -312
  285. package/providers/commercetools/src/test/identity.provider.spec.ts +0 -88
  286. package/providers/commercetools/src/test/inventory.provider.spec.ts +0 -41
  287. package/providers/commercetools/src/test/price.provider.spec.ts +0 -81
  288. package/providers/commercetools/src/test/product.provider.spec.ts +0 -80
  289. package/providers/commercetools/src/test/profile.provider.spec.ts +0 -49
  290. package/providers/commercetools/src/test/search.provider.spec.ts +0 -61
  291. package/providers/commercetools/src/test/store.provider.spec.ts +0 -37
  292. package/providers/fake/jest.config.cjs +0 -10
  293. package/providers/fake/src/providers/search.provider.ts +0 -132
@@ -9,84 +9,93 @@ import type {
9
9
  CartIdentifier,
10
10
  CartMutationApplyCoupon,
11
11
  CartMutationChangeCurrency,
12
- CartMutationCheckout,
13
12
  CartMutationDeleteCart,
14
13
  CartMutationRemoveCoupon,
15
- CartMutationSetBillingAddress,
16
- CartMutationSetShippingInfo,
17
- OrderIdentifier} from '@reactionary/core';
14
+ Result,
15
+ NotFoundError
16
+ } from '@reactionary/core';
18
17
  import {
19
- CartProvider
18
+ CartIdentifierSchema,
19
+ CartMutationApplyCouponSchema,
20
+ CartMutationChangeCurrencySchema,
21
+ CartMutationDeleteCartSchema,
22
+ CartMutationItemAddSchema,
23
+ CartMutationItemQuantityChangeSchema,
24
+ CartMutationItemRemoveSchema,
25
+ CartMutationRemoveCouponSchema,
26
+ CartProvider,
27
+ CartQueryByIdSchema,
28
+ CartSchema,
29
+ Reactionary,
30
+ error,
31
+ success,
32
+ unwrapValue,
20
33
  } from '@reactionary/core';
21
- import type z from 'zod';
22
34
  import type { FakeConfiguration } from '../schema/configuration.schema.js';
23
35
  import { Faker, en, base } from '@faker-js/faker';
24
36
 
25
- export class FakeCartProvider<
26
- T extends Cart = Cart
27
- > extends CartProvider<T> {
37
+ export class FakeCartProvider extends CartProvider {
28
38
  protected config: FakeConfiguration;
29
- private carts: Map<string, T> = new Map();
39
+ private carts: Map<string, Cart> = new Map();
30
40
  private generator: Faker;
31
41
 
32
-
33
- constructor(config: FakeConfiguration, schema: z.ZodType<T>, cache: Cache) {
34
- super(schema, cache);
42
+ constructor(
43
+ config: FakeConfiguration,
44
+ cache: Cache,
45
+ context: RequestContext
46
+ ) {
47
+ super(cache, context);
35
48
  this.generator = new Faker({
36
49
  locale: [en, base],
37
- seed: config.seeds.product
50
+ seed: config.seeds.product,
38
51
  });
39
52
  this.config = config;
40
53
  }
41
54
 
55
+ @Reactionary({
56
+ inputSchema: CartQueryByIdSchema,
57
+ outputSchema: CartSchema,
58
+ })
42
59
  public override async getById(
43
- payload: CartQueryById,
44
- _reqCtx: RequestContext
45
- ): Promise<T> {
60
+ payload: CartQueryById
61
+ ): Promise<Result<Cart, NotFoundError>> {
46
62
  const cartId = payload.cart.key;
47
63
 
48
64
  if (payload.cart.key === '') {
49
- const result = this.newModel();
50
- result.meta = {
51
- cache: { hit: false, key: 'empty' },
52
- placeholder: true
53
- };
54
- return this.assert(result);
65
+ return error<NotFoundError>({
66
+ type: 'NotFound',
67
+ identifier: cartId,
68
+ });
55
69
  }
56
70
 
57
71
  if (!this.carts.has(cartId)) {
58
- const model = this.newModel();
59
- Object.assign(model, {
60
- identifier: { key: cartId },
61
- items: [],
62
- meta: {
63
- cache: {
64
- hit: false,
65
- key: cartId,
66
- },
67
- placeholder: false,
68
- },
69
- });
70
- this.carts.set(cartId, this.assert(model));
72
+ const cart = this.createEmptyCart();
73
+ cart.identifier.key = cartId;
74
+
75
+ this.carts.set(cartId, cart);
71
76
  }
72
77
 
73
78
  const cart = this.carts.get(cartId);
74
79
  if (!cart) {
75
80
  throw new Error(`Cart with id ${cartId} not found`);
76
81
  }
77
- return cart;
82
+ return success(cart);
78
83
  }
79
84
 
80
- public override async add(
81
- payload: CartMutationItemAdd,
82
- reqCtx: RequestContext
83
- ): Promise<T> {
84
-
85
- const cartId = payload.cart.key || `cart-${this.generator.string.uuid()}`;
86
- const cart = await this.getById({ cart: { key: cartId } }, reqCtx);
85
+ @Reactionary({
86
+ inputSchema: CartMutationItemAddSchema,
87
+ outputSchema: CartSchema,
88
+ })
89
+ public override async add(payload: CartMutationItemAdd): Promise<Result<Cart>> {
90
+ const cartId = payload?.cart?.key || `cart-${this.generator.string.uuid()}`;
91
+ const cart = unwrapValue(await this.getById({ cart: { key: cartId } }));
87
92
 
93
+ if (cart.identifier.key === '') {
94
+ cart.identifier.key = cartId;
95
+ this.carts.set(cartId, cart);
96
+ }
88
97
  const existingItemIndex = cart.items.findIndex(
89
- item => item.sku.key === payload.sku.key
98
+ (item) => item.variant.sku === payload.variant.sku
90
99
  );
91
100
 
92
101
  if (existingItemIndex >= 0) {
@@ -96,118 +105,180 @@ export class FakeCartProvider<
96
105
 
97
106
  cart.items.push({
98
107
  identifier: { key: `item-${Date.now()}` },
99
- sku: payload.sku,
108
+ variant: payload.variant,
100
109
  quantity: payload.quantity,
101
110
  price: {
102
111
  unitPrice: {
103
112
  value: price,
104
- currency: reqCtx.languageContext.currencyCode,
113
+ currency: this.context.languageContext.currencyCode,
105
114
  },
106
115
  totalPrice: {
107
116
  value: 0, // Will be calculated below
108
- currency: reqCtx.languageContext.currencyCode,
117
+ currency: this.context.languageContext.currencyCode,
109
118
  },
110
119
  totalDiscount: {
111
120
  value: 0,
112
- currency: reqCtx.languageContext.currencyCode,
121
+ currency: this.context.languageContext.currencyCode,
113
122
  },
114
123
  unitDiscount: {
115
124
  value: 0,
116
- currency: reqCtx.languageContext.currencyCode,
125
+ currency: this.context.languageContext.currencyCode,
117
126
  },
118
127
  },
119
128
  product: {
120
- key: `product-for-${payload.sku.key}`,
129
+ key: `product-for-${payload.variant.sku}`,
121
130
  },
122
-
123
-
124
131
  });
125
132
  }
126
133
 
127
134
  this.recalculateCart(cart);
128
135
 
129
- return this.assert(cart);
136
+ return success(cart);
130
137
  }
131
138
 
132
- public override async remove(
133
- payload: CartMutationItemRemove,
134
- reqCtx: RequestContext
135
- ): Promise<T> {
139
+ @Reactionary({
140
+ inputSchema: CartMutationItemRemoveSchema,
141
+ outputSchema: CartSchema,
142
+ })
143
+ public override async remove(payload: CartMutationItemRemove): Promise<Result<Cart>> {
136
144
  const cartId = payload.cart.key || `cart-${this.generator.string.uuid()}`;
137
- const cart = await this.getById({ cart: { key: cartId } }, reqCtx);
145
+ const cart = unwrapValue(await this.getById({ cart: { key: cartId } }));
138
146
 
139
147
  cart.items = cart.items.filter(
140
- item => item.identifier.key !== payload.item.key
148
+ (item) => item.identifier.key !== payload.item.key
141
149
  );
142
150
  this.recalculateCart(cart);
143
- return this.assert(cart);
151
+
152
+ return success(cart);
144
153
  }
145
154
 
155
+ @Reactionary({
156
+ inputSchema: CartMutationItemQuantityChangeSchema,
157
+ outputSchema: CartSchema,
158
+ })
146
159
  public override async changeQuantity(
147
- payload: CartMutationItemQuantityChange,
148
- reqCtx: RequestContext
149
- ): Promise<T> {
160
+ payload: CartMutationItemQuantityChange
161
+ ): Promise<Result<Cart>> {
150
162
  const cartId = payload.cart.key || `cart-${this.generator.string.uuid()}`;
151
- const cart = await this.getById({ cart: { key: cartId } }, reqCtx);
163
+ const cart = unwrapValue(await this.getById({ cart: { key: cartId } }));
152
164
 
153
165
  const item = cart.items.find(
154
- item => item.identifier.key === payload.item.key
166
+ (item) => item.identifier.key === payload.item.key
155
167
  );
156
168
  if (payload.quantity < 1) {
157
- return cart;
169
+ return success(cart);
158
170
  }
159
171
  if (item) {
160
172
  item.quantity = payload.quantity;
161
173
  }
162
174
  this.recalculateCart(cart);
163
- return this.assert(cart);
175
+ return success(cart);
164
176
  }
165
177
 
166
-
167
- public override getActiveCartId(reqCtx: RequestContext): Promise<CartIdentifier> {
178
+ @Reactionary({
179
+ outputSchema: CartIdentifierSchema,
180
+ })
181
+ public override getActiveCartId(): Promise<Result<CartIdentifier, NotFoundError>> {
168
182
  throw new Error('Method not implemented.');
169
183
  }
170
- public override deleteCart(payload: CartMutationDeleteCart, reqCtx: RequestContext): Promise<T> {
171
- throw new Error('Method not implemented.');
172
- }
173
- public override setShippingInfo(payload: CartMutationSetShippingInfo, reqCtx: RequestContext): Promise<T> {
174
- throw new Error('Method not implemented.');
175
- }
176
- public override setBillingAddress(payload: CartMutationSetBillingAddress, reqCtx: RequestContext): Promise<T> {
177
- throw new Error('Method not implemented.');
178
- }
179
- public override applyCouponCode(payload: CartMutationApplyCoupon, reqCtx: RequestContext): Promise<T> {
184
+
185
+ @Reactionary({
186
+ inputSchema: CartMutationDeleteCartSchema,
187
+ outputSchema: CartSchema,
188
+ })
189
+ public override deleteCart(payload: CartMutationDeleteCart): Promise<Result<void>> {
180
190
  throw new Error('Method not implemented.');
181
191
  }
182
- public override removeCouponCode(payload: CartMutationRemoveCoupon, reqCtx: RequestContext): Promise<T> {
192
+
193
+ @Reactionary({
194
+ inputSchema: CartMutationApplyCouponSchema,
195
+ outputSchema: CartSchema,
196
+ })
197
+ public override applyCouponCode(
198
+ payload: CartMutationApplyCoupon
199
+ ): Promise<Result<Cart>> {
183
200
  throw new Error('Method not implemented.');
184
201
  }
185
- public override checkout(payload: CartMutationCheckout, reqCtx: RequestContext): Promise<OrderIdentifier> {
202
+
203
+ @Reactionary({
204
+ inputSchema: CartMutationRemoveCouponSchema,
205
+ outputSchema: CartSchema,
206
+ })
207
+ public override removeCouponCode(
208
+ payload: CartMutationRemoveCoupon
209
+ ): Promise<Result<Cart>> {
186
210
  throw new Error('Method not implemented.');
187
211
  }
188
- public override changeCurrency(payload: CartMutationChangeCurrency, reqCtx: RequestContext): Promise<T> {
212
+
213
+ @Reactionary({
214
+ inputSchema: CartMutationChangeCurrencySchema,
215
+ outputSchema: CartSchema,
216
+ })
217
+ public override changeCurrency(
218
+ payload: CartMutationChangeCurrency
219
+ ): Promise<Result<Cart>> {
189
220
  throw new Error('Method not implemented.');
190
221
  }
191
222
 
192
-
193
-
194
-
195
- protected recalculateCart(cart: T) {
196
- cart.items.forEach(item => {
223
+ protected recalculateCart(cart: Cart) {
224
+ cart.items.forEach((item) => {
197
225
  item.price.totalPrice.value = item.price.unitPrice.value * item.quantity;
198
226
  });
199
227
 
200
228
  cart.price.totalProductPrice = {
201
- value: cart.items.reduce((sum, item) => sum + item.price.totalPrice.value, 0),
229
+ value: cart.items.reduce(
230
+ (sum, item) => sum + item.price.totalPrice.value,
231
+ 0
232
+ ),
202
233
  currency: cart.items[0]?.price.unitPrice.currency || 'USD',
203
- }
234
+ };
204
235
 
205
236
  cart.price.grandTotal = {
206
- value: cart.items.reduce((sum, item) => sum + item.price.totalPrice.value, 0),
237
+ value: cart.items.reduce(
238
+ (sum, item) => sum + item.price.totalPrice.value,
239
+ 0
240
+ ),
207
241
  currency: cart.items[0]?.price.unitPrice.currency || 'USD',
208
242
  };
209
243
  }
210
244
 
245
+ protected createEmptyCart(): Cart {
246
+ const cart = {
247
+ identifier: { key: '' },
248
+ description: '',
249
+ items: [],
250
+ name: '',
251
+ price: {
252
+ grandTotal: {
253
+ value: 0,
254
+ currency: 'XXX',
255
+ },
256
+ totalDiscount: {
257
+ value: 0,
258
+ currency: 'XXX',
259
+ },
260
+ totalProductPrice: {
261
+ value: 0,
262
+ currency: 'XXX',
263
+ },
264
+ totalShipping: {
265
+ value: 0,
266
+ currency: 'XXX',
267
+ },
268
+ totalSurcharge: {
269
+ value: 0,
270
+ currency: 'XXX',
271
+ },
272
+ totalTax: {
273
+ value: 0,
274
+ currency: 'XXX',
275
+ },
276
+ },
277
+ userId: {
278
+ userId: '',
279
+ },
280
+ } satisfies Cart;
211
281
 
212
-
282
+ return cart;
283
+ }
213
284
  }
@@ -1,23 +1,21 @@
1
- import type { Category, CategoryQueryById, CategoryQueryBySlug, CategoryQueryForBreadcrumb, CategoryQueryForChildCategories, CategoryQueryForTopCategories, RequestContext} from "@reactionary/core";
2
- import { CategoryProvider, Reactionary } from "@reactionary/core";
1
+ import type { Result, NotFoundError, Category, CategoryPaginatedResult, CategoryQueryById, CategoryQueryBySlug, CategoryQueryForBreadcrumb, CategoryQueryForChildCategories, CategoryQueryForTopCategories, RequestContext} from "@reactionary/core";
2
+ import { success, error, CategoryPaginatedResultSchema, CategoryProvider, CategoryQueryByIdSchema, CategoryQueryBySlugSchema, CategoryQueryForBreadcrumbSchema, CategoryQueryForChildCategoriesSchema, CategoryQueryForTopCategoriesSchema, CategorySchema, Reactionary } from "@reactionary/core";
3
3
  import type { FakeConfiguration } from "../schema/configuration.schema.js";
4
4
  import type { Cache as ReactionaryCache } from "@reactionary/core";
5
- import type z from "zod";
5
+ import z from "zod";
6
6
  import { Faker, en, base } from '@faker-js/faker';
7
- export class FakeCategoryProvider<
8
- T extends Category = Category
9
- > extends CategoryProvider<T> {
7
+
8
+ export class FakeCategoryProvider extends CategoryProvider {
10
9
 
11
10
  protected config: FakeConfiguration;
12
11
 
13
- protected topCategories = new Array<T>();
14
- protected childCategories = new Map<string, Array<T>>();
15
- protected allCategories = new Map<string, T>();
12
+ protected topCategories = new Array<Category>();
13
+ protected childCategories = new Map<string, Array<Category>>();
14
+ protected allCategories = new Map<string, Category>();
16
15
 
17
16
  protected categoryGenerator: Faker;
18
17
 
19
- protected generateFakeCategory(parent: Category | undefined, index: number): T {
20
-
18
+ protected generateFakeCategory(parent: Category | undefined, index: number): Category {
21
19
  let name: string;
22
20
  if (!parent) {
23
21
  name = this.categoryGenerator.commerce.department();
@@ -25,21 +23,31 @@ export class FakeCategoryProvider<
25
23
  name = `${parent.name}-${index}`;
26
24
  }
27
25
 
28
- const category: T = this.newModel();
29
- category.identifier = { key: name.toLowerCase().replace(/\s+/g, '-') };
30
- category.name = name;
31
- category.text = this.categoryGenerator.lorem.sentences(3);
32
- category.slug = category.identifier.key + '-slug';
26
+ const identifier = { key: name.toLowerCase().replace(/\s+/g, '-') };
27
+ const text = this.categoryGenerator.lorem.sentences(3);
28
+ const slug = identifier.key + '-slug';
29
+
30
+ let parentCategory;
33
31
  if (parent) {
34
- category.parentCategory = parent.identifier;
32
+ parentCategory = parent.identifier;
35
33
  }
36
- this.allCategories.set(category.identifier.key, category);
34
+
35
+ const category = {
36
+ identifier,
37
+ images: [],
38
+ name,
39
+ slug,
40
+ text,
41
+ parentCategory
42
+ } satisfies Category;
43
+
44
+ this.allCategories.set(identifier.key, category);
37
45
  return category;
38
46
  }
39
47
 
40
48
 
41
- constructor(config: FakeConfiguration, schema: z.ZodType<T>, cache: ReactionaryCache) {
42
- super(schema, cache);
49
+ constructor(config: FakeConfiguration, cache: ReactionaryCache, context: RequestContext) {
50
+ super(cache, context);
43
51
  this.config = config;
44
52
  this.categoryGenerator = new Faker({
45
53
  seed: this.config.seeds.category,
@@ -48,21 +56,21 @@ export class FakeCategoryProvider<
48
56
 
49
57
  // Generate some top-level categories
50
58
  for (let i = 0; i < 6; i++) {
51
- const category: T = this.generateFakeCategory(undefined, i);
59
+ const category = this.generateFakeCategory(undefined, i);
52
60
  this.topCategories.push(category);
53
61
  }
54
62
 
55
63
  // Generate two levels of child categories
56
64
  this.topCategories.forEach((parentCategory) => {
57
- const children = new Array<T>();
65
+ const children = new Array<Category>();
58
66
  for (let j = 0; j < 5; j++) {
59
- const childCategory: T = this.generateFakeCategory(parentCategory, j);
67
+ const childCategory = this.generateFakeCategory(parentCategory, j);
60
68
  children.push(childCategory);
61
69
 
62
70
 
63
- const subCategoryChildren = new Array<T>();
71
+ const subCategoryChildren = new Array<Category>();
64
72
  for(let k = 0; k < 5; k++) {
65
- const subChildCategory: T = this.generateFakeCategory(childCategory, k);
73
+ const subChildCategory = this.generateFakeCategory(childCategory, k);
66
74
  subCategoryChildren.push(subChildCategory);
67
75
  }
68
76
  this.childCategories.set(childCategory.identifier.key, subCategoryChildren);
@@ -71,48 +79,64 @@ export class FakeCategoryProvider<
71
79
  });
72
80
  }
73
81
 
74
- @Reactionary({})
75
- public override async getById(payload: CategoryQueryById, reqCtx: RequestContext): Promise<T> {
82
+ @Reactionary({
83
+ inputSchema: CategoryQueryByIdSchema,
84
+ outputSchema: CategorySchema
85
+ })
86
+ public override async getById(payload: CategoryQueryById): Promise<Result<Category, NotFoundError>> {
76
87
  const category = this.allCategories.get(payload.id.key);
77
88
 
78
89
  if(!category) {
79
- const dummyCategory = this.newModel();
80
- dummyCategory.meta.placeholder = true;
81
- dummyCategory.identifier = { key: payload.id.key };
82
- return dummyCategory;
90
+ return error<NotFoundError>({
91
+ type: 'NotFound',
92
+ identifier: payload
93
+ });
83
94
  }
84
- return category;
95
+
96
+ return success(category);
85
97
  }
86
98
 
87
- @Reactionary({})
88
- public override getBySlug(payload: CategoryQueryBySlug, reqCtx: RequestContext): Promise<T | null> {
99
+ @Reactionary({
100
+ inputSchema: CategoryQueryBySlugSchema,
101
+ outputSchema: CategorySchema
102
+ })
103
+ public override async getBySlug(payload: CategoryQueryBySlug): Promise<Result<Category, NotFoundError>> {
89
104
  for(const p of this.allCategories.values()) {
90
105
  if(p.slug === payload.slug) {
91
- return Promise.resolve(p as T);
106
+ return success(p);
92
107
  }
93
108
  }
94
- return Promise.resolve(null);
109
+ return error<NotFoundError>({
110
+ type: 'NotFound',
111
+ identifier: payload
112
+ });
95
113
  }
96
114
 
97
- @Reactionary({})
98
- public override getBreadcrumbPathToCategory(payload: CategoryQueryForBreadcrumb, reqCtx: RequestContext): Promise<T[]> {
99
- const path = new Array<T>();
115
+ @Reactionary({
116
+ inputSchema: CategoryQueryForBreadcrumbSchema,
117
+ outputSchema: z.array(CategorySchema)
118
+ })
119
+ public override async getBreadcrumbPathToCategory(payload: CategoryQueryForBreadcrumb): Promise<Result<Category[]>> {
120
+ const path = new Array<Category>();
100
121
  let category = this.allCategories.get(payload.id.key);
101
- path.push(category as T);
122
+ path.push(category!);
102
123
  while(category?.parentCategory) {
103
124
  category = this.allCategories.get(category.parentCategory.key);
104
125
  if(category) {
105
- path.unshift(category as T);
126
+ path.unshift(category);
106
127
  }
107
128
  }
108
- return Promise.resolve(path);
129
+ return success(path);
109
130
  }
110
131
 
111
- public override async findChildCategories(payload: CategoryQueryForChildCategories, reqCtx: RequestContext): Promise<ReturnType<typeof this.parsePaginatedResult>> {
132
+ @Reactionary({
133
+ inputSchema: CategoryQueryForChildCategoriesSchema,
134
+ outputSchema: CategoryPaginatedResultSchema
135
+ })
136
+ public override async findChildCategories(payload: CategoryQueryForChildCategories): Promise<Result<CategoryPaginatedResult>> {
112
137
  const children = this.childCategories.get(payload.parentId.key);
113
138
  const page = children?.slice((payload.paginationOptions.pageNumber - 1) * payload.paginationOptions.pageSize, payload.paginationOptions.pageNumber * payload.paginationOptions.pageSize);
114
139
 
115
-
116
140
  const res = {
117
141
  meta: {
118
142
  placeholder: false,
@@ -121,20 +145,24 @@ export class FakeCategoryProvider<
121
145
  key: 'child-categories-' + payload.parentId.key + '-' + payload.paginationOptions.pageNumber + '-' + payload.paginationOptions.pageSize,
122
146
  },
123
147
  },
124
- items: page ? page as T[] : [],
148
+ items: page ? page : [],
125
149
  totalCount: children ? children.length : 0,
126
150
  pageNumber: payload.paginationOptions.pageNumber,
127
151
  pageSize: payload.paginationOptions.pageSize,
128
152
  totalPages: children ? Math.ceil(children.length / payload.paginationOptions.pageSize) : 1,
129
153
  };
130
154
 
131
- return Promise.resolve(res);
155
+ return success(res);
132
156
  }
133
- public override findTopCategories(payload: CategoryQueryForTopCategories, reqCtx: RequestContext): Promise<ReturnType<typeof this.parsePaginatedResult>> {
157
+
158
+ @Reactionary({
159
+ inputSchema: CategoryQueryForTopCategoriesSchema,
160
+ outputSchema: CategoryPaginatedResultSchema
161
+ })
162
+ public override async findTopCategories(payload: CategoryQueryForTopCategories): Promise<Result<CategoryPaginatedResult>> {
134
163
  const children = this.topCategories;
135
164
  const page = children?.slice((payload.paginationOptions.pageNumber - 1) * payload.paginationOptions.pageSize, payload.paginationOptions.pageNumber * payload.paginationOptions.pageSize);
136
165
 
137
-
138
166
  const res = {
139
167
  meta: {
140
168
  placeholder: false,
@@ -143,14 +171,14 @@ export class FakeCategoryProvider<
143
171
  key: 'top' + '-' + payload.paginationOptions.pageNumber + '-' + payload.paginationOptions.pageSize,
144
172
  },
145
173
  },
146
- items: page ? page as T[] : [],
174
+ items: page ? page : [],
147
175
  totalCount: children ? children.length : 0,
148
176
  pageNumber: payload.paginationOptions.pageNumber,
149
177
  pageSize: payload.paginationOptions.pageSize,
150
178
  totalPages: children ? Math.ceil(children.length / payload.paginationOptions.pageSize) : 1,
151
179
  };
152
180
 
153
- return Promise.resolve(res);
181
+ return success(res);
154
182
  }
155
183
 
156
184
  }