@reactionary/source 0.0.52 → 0.2.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (292) 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 +159 -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 +137 -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 +201 -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 +16 -0
  240. package/providers/meilisearch/src/index.ts +5 -0
  241. package/providers/meilisearch/src/providers/index.ts +1 -0
  242. package/providers/meilisearch/src/providers/product-search.provider.ts +251 -0
  243. package/providers/meilisearch/src/schema/capabilities.schema.ts +9 -0
  244. package/providers/meilisearch/src/schema/configuration.schema.ts +10 -0
  245. package/providers/meilisearch/src/schema/index.ts +3 -0
  246. package/providers/meilisearch/src/schema/search.schema.ts +14 -0
  247. package/providers/meilisearch/tsconfig.json +24 -0
  248. package/providers/meilisearch/tsconfig.lib.json +10 -0
  249. package/providers/meilisearch/tsconfig.spec.json +4 -0
  250. package/providers/meilisearch/vitest.config.ts +14 -0
  251. package/providers/posthog/package.json +2 -1
  252. package/providers/posthog/tsconfig.json +1 -1
  253. package/tsconfig.base.json +5 -0
  254. package/vitest.config.ts +10 -0
  255. package/core/src/providers/search.provider.ts +0 -18
  256. package/core/src/schemas/models/search.model.ts +0 -36
  257. package/core/src/schemas/queries/search.query.ts +0 -9
  258. package/examples/next/.swcrc +0 -30
  259. package/examples/next/eslint.config.mjs +0 -21
  260. package/examples/next/index.d.ts +0 -6
  261. package/examples/next/next-env.d.ts +0 -5
  262. package/examples/next/next.config.js +0 -31
  263. package/examples/next/project.json +0 -9
  264. package/examples/next/public/.gitkeep +0 -0
  265. package/examples/next/public/favicon.ico +0 -0
  266. package/examples/next/src/app/global.css +0 -0
  267. package/examples/next/src/app/layout.tsx +0 -18
  268. package/examples/next/src/app/page.module.scss +0 -2
  269. package/examples/next/src/app/page.tsx +0 -47
  270. package/examples/next/src/instrumentation.ts +0 -9
  271. package/examples/next/tsconfig.json +0 -44
  272. package/examples/node/jest.config.ts +0 -10
  273. package/jest.config.ts +0 -6
  274. package/jest.preset.js +0 -3
  275. package/providers/algolia/jest.config.ts +0 -10
  276. package/providers/algolia/src/providers/product.provider.ts +0 -66
  277. package/providers/algolia/src/providers/search.provider.ts +0 -106
  278. package/providers/algolia/src/test/search.provider.spec.ts +0 -91
  279. package/providers/commercetools/jest.config.cjs +0 -10
  280. package/providers/commercetools/src/providers/search.provider.ts +0 -96
  281. package/providers/commercetools/src/test/cart.provider.spec.ts +0 -199
  282. package/providers/commercetools/src/test/category.provider.spec.ts +0 -168
  283. package/providers/commercetools/src/test/checkout.provider.spec.ts +0 -312
  284. package/providers/commercetools/src/test/identity.provider.spec.ts +0 -88
  285. package/providers/commercetools/src/test/inventory.provider.spec.ts +0 -41
  286. package/providers/commercetools/src/test/price.provider.spec.ts +0 -81
  287. package/providers/commercetools/src/test/product.provider.spec.ts +0 -80
  288. package/providers/commercetools/src/test/profile.provider.spec.ts +0 -49
  289. package/providers/commercetools/src/test/search.provider.spec.ts +0 -61
  290. package/providers/commercetools/src/test/store.provider.spec.ts +0 -37
  291. package/providers/fake/jest.config.cjs +0 -10
  292. package/providers/fake/src/providers/search.provider.ts +0 -132
package/.env-template CHANGED
@@ -11,3 +11,22 @@ OTEL_SERVICE_NAME=reactionary
11
11
  OTEL_LOG_LEVEL=info
12
12
  OTEL_TRACES_EXPORTER=console
13
13
  OTEL_METRICS_EXPORTER=console
14
+
15
+
16
+
17
+ MEILISEARCH_API_URL=
18
+ MEILISEARCH_API_KEY=
19
+ MEILISEARCH_INDEX=icecat_products
20
+ MEILISEARCH_USE_AI_EMBEDDING=huggingface
21
+
22
+
23
+ ALGOLIA_API_KEY=
24
+ ALGOLIA_APP_ID=
25
+ ALGOLIA_INDEX=icecat_products
26
+
27
+
28
+
29
+ MEDUSA_PUBLISHABLE_KEY=
30
+ MEDUSA_ADMIN_KEY=
31
+ MEDUSA_API_URL=
32
+ MEDUSA_DEFAULT_CURRENCY=EUR
@@ -25,7 +25,7 @@ jobs:
25
25
 
26
26
  - uses: pnpm/action-setup@v4
27
27
 
28
- - run: pnpm dlx nx-cloud start-ci-run --distribute-on="3 linux-medium-js" --stop-agents-after="build"
28
+ - run: pnpm dlx nx-cloud start-ci-run --distribute-on="3 linux-medium-js" --stop-agents-after="test"
29
29
 
30
30
  - uses: actions/setup-node@v4
31
31
  with:
@@ -37,3 +37,5 @@ jobs:
37
37
  - uses: nrwl/nx-set-shas@v4
38
38
 
39
39
  - run: pnpm exec nx affected -t lint build
40
+
41
+ - run: pnpm exec nx test core
@@ -2,9 +2,18 @@ name: release
2
2
 
3
3
  on:
4
4
  push:
5
+ paths-ignore:
6
+ - 'docs/**'
7
+ - '.gitignore'
8
+ - 'README.md'
9
+ - 'documentation/**'
10
+ - '**/*.md'
11
+
5
12
  branches:
6
13
  main
7
14
 
15
+
16
+
8
17
  permissions:
9
18
  actions: read
10
19
  contents: write
@@ -1,9 +1,7 @@
1
1
  {
2
2
  "recommendations": [
3
- "nrwl.angular-console",
4
3
  "esbenp.prettier-vscode",
5
4
  "dbaeumer.vscode-eslint",
6
- "firsttris.vscode-jest-runner",
7
5
  "ms-playwright.playwright"
8
6
  ]
9
7
  }
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Solteq
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -43,38 +43,190 @@ The following is a short list of commonly used terms and phrases, to keep guessi
43
43
  ## TODO:
44
44
 
45
45
 
46
+ ### Roadmap to V0.1
47
+ Usecase: As a shopper i search for products, add to cart and check out.
48
+ Vendors: Commercetools, Algolia, Medusa
49
+
50
+ UX Pages and components supported:
51
+ - PDP
52
+ - Product info
53
+ - Attribute table
54
+ - Variant selection
55
+ - Inventory display
56
+ - Price display (simple pricing)
57
+ - PLP - Keyword Search + Facet
58
+ - Minicart
59
+ - Cart Page
60
+ - Checkout - Address
61
+ - Checkout - Shipping
62
+ - Checkout - Payment
63
+ - Checkout - Confirmation
64
+ - Account - Sign up (email, password)
65
+ - Account - Log in (email, password)
66
+
67
+ #### Tasks:
68
+ - [X] Cart - Remove checkout related functions - AKJ
69
+ - [X] Checkout - Receive full cart in input - MR
70
+ - [X] Inventory - Model to use ProductVariantIdentifier instead of SKU - AKJ
71
+ - [X] Price - Add Usage/Pricelist modifier for Queries to allow for List/Offer price. - MR
72
+ - [X] Commercetools - Guest sesion race condition - MR
73
+ - [X] Commercetools - Seperate temporary admin client from `Me` based client. - MR
74
+ - [X] Medusa - Identity capability - AKJ
75
+ - [X] Medusa - Price capability - AKJ
76
+ - [X] Medusa - Category capability - AKJ
77
+ - [X] Medusa - Inventory capability - AKJ
78
+ - [X] Medusa - Checkout capability - AKJ
79
+ - [X] Search Index Model Add information about number of variants on the main model (or directly if it can be added to cart or not) - AKJ
80
+ - [X] CLI for importing icecat to all vendors - AKJ
81
+ - [X] Unified Data Set for Products - AKJ
82
+ - [X] Unified Data Set for Inventory - AKJ
83
+ - [X] Unified Data Set for Prices - AKJ
84
+ - [X] Unified test set for all vendors - AKJ
85
+ - [X] Reactionary Decorator on all public Query and Mutation methods - MR
86
+ - [X] Input validation via Zod.parse for all public Query and Mutation methods - MR
87
+ - [X] Output validation via Zod.parse for all public Query and Mutation methods - MR
88
+ - [X] Change Zod schema from looseObjects to .passthrough - MR
89
+ - [X] Minor fixes from Angular Frontend - MR
46
90
 
47
- ### Core
48
- - [ ] Figure a way to get a correlation id from the caller
49
- - [ ] Maybe rework session so its not languageContext but requestContext, and this could have the correlation id in it?
50
91
 
51
92
 
52
- ### Search
53
- - [ ] Add support for filters, not just facets
93
+ ### Roadmap to V0.2
94
+ Usecase: as a shopper i use the site navigation to find products, add to cart and checkout
95
+ Vendors: Commercetools, Algolia, Medusa
54
96
 
55
- ### Marketing
56
- - [ ] Add marketing provider (input: (name, url, user, segments, productid, categoryid) => output { Array<Product | Category | Image | Text>}
97
+ - Menu navigation
98
+ - CLP - Category Navigation
99
+ - Revise and review Schema usage patterns to reduce number of irrelevant default values.
100
+ - Move to Errors as Values on base api, no null, no undefineds, no exceptions out of Reactionary
57
101
 
102
+ ### Roadmap to V0.3
103
+ Usecase: As a registered user, i access my-account
104
+ Vendors: Commercetools, Algolia, Medusa
58
105
 
59
- ### Inventory
60
- - [ ] Invent and document some notational standard for cannel-key to purpose.
61
- - [ ] Be traced and cached
106
+ - Profile - Address book
107
+ - Orderhistory - List and Details
108
+ - Consents - marketing, newsletters etc
109
+ - Store location vs pickup points
62
110
 
63
- ### Profile
64
- - [ ] Be able to register new account
65
- - [ ] Create profile provider
111
+ ### Roadmap to V0.4
112
+ Usecase: As a seller i want to seed my recommendation and analytics with customer actions (Analytics)
113
+ Vendors: Algolia, Google Analytics
66
114
 
115
+ - PLP
116
+ - Attribution Tracking
117
+ - Facet Tracking
118
+ - PDP
119
+ - Attribution Tracking
120
+ - Checkout
121
+ - Conversion Tracking
67
122
 
68
- ### Organization
69
- - [ ] Create organization provider
70
- - [ ] Create business user provider
71
- - [ ] Create role provider
72
123
 
73
- ### Cart
74
- - [ ] Add B2B/organization identifier
124
+ ### Roadmap to V0.5
125
+ Usecase: As a merchandiser i want to upsell
126
+ Vendors: Algolia, Commercetools
75
127
 
76
- ### Price
77
- - [ ] Add list price
128
+ - PDP
129
+ - Recommendations (Products, Categories)
130
+ - Associations (Spareparts, Accessories)
131
+ - Ratings and Reviews
132
+ - Checkout
133
+ - Recommendations (Products)
78
134
 
79
- ### Order
80
- - [ ] Add Order
135
+
136
+ ### Roadmap to V0.6
137
+ Usecase: As a shopper i want to create shoppinglist/wishlist
138
+ Vendors: Commercetools, Medusa
139
+
140
+ - Account - Shopping List, Listing and Details
141
+ - PDP
142
+ - Add to Shopping List
143
+ - PLP
144
+ - Add to Shopping List
145
+
146
+
147
+ ### Roadmap to V0.7
148
+ Usecase: As a B2B user i want to shop using my own prices
149
+ Vendors: Commercetools
150
+
151
+ - PDP / PLP
152
+ - External Pricing
153
+ - Organizational/Entitlement Context
154
+ - Multi currency/Multi lingual
155
+
156
+
157
+ ### Roadmap to V0.8
158
+ Usecase: As a B2B user i want to see my organization data
159
+ Vendors: Commercetools
160
+
161
+ - Account - My Organization(s)
162
+ - Account - Self management of users and roles
163
+
164
+
165
+ ### Roadmap to V0.9
166
+ Usecase: As a B2B user i want have multiple carts and requisition lists
167
+ Vendors: Commercetools
168
+
169
+ - Account - My Open Carts
170
+
171
+ ### Roadmap to V1.0
172
+ Usecase: As a B2B user i want to see other peoples carts and orders
173
+ Vendors: Commercetools
174
+
175
+ - Account - Organizational Order History
176
+
177
+
178
+
179
+
180
+
181
+
182
+
183
+
184
+
185
+ ### Roadmap V0.x
186
+ - Additional vendors
187
+ - AthosCommerce (Klevu)
188
+ - ShopifyPlus
189
+ - HCL Commerce
190
+ - Adobe Commerce
191
+ - Lipscore
192
+ - PDP
193
+ - Price display (tiered pricing, variant differential pricing)
194
+
195
+
196
+
197
+
198
+
199
+
200
+ ## Adding a new provider
201
+ So, you want to add to the fun, and add a new provider.
202
+ A new provider can be as partial or as complete as you need it to be, but each capability it undertakes, must be fully supported.
203
+
204
+ ## Step 0
205
+ Make sure you have a clean test environment. Ie not some half-baked instance with broken test data. Ideally, you are able to spin up and preconfigure instances via scripts.
206
+
207
+ ## Step 1
208
+ Populate your environment with the shared test-data set. Reactionarys providers all share a set of product information based on ICECAT.
209
+
210
+ If you are internal to Solteq, you can work off of https://github.com/Solteq/composable-commerce-base-workspace. If you are external, go to ICECAT.biz, and register an account.
211
+ Then use their API to download the free dataset and all the various product-data files. Parse those, and import them in your system as appropriate.
212
+
213
+ Consider, that you may not need to import all of it, if your capability doesn't need it. Ie if you are only implementing the CART capability, you don't really need the product images, or long descriptions.
214
+
215
+ ## Step 2
216
+ Add your provider library here.
217
+
218
+ ```
219
+ npx nx g lib providers/<vendor> --buildable --publishable TODO: Martin, fill in
220
+ ```
221
+
222
+ Within each `src` folder, adhere to the naming convention of the existing providers:
223
+ - `core` (capabilities and initalization)
224
+ - `providers` (each capability in its own file, named for itself )
225
+ - `schema` any vendor specific schema overrides
226
+ - `test` any internal/specific test to that provider.
227
+
228
+ ## Step 3
229
+ Create the initialization and capabilities schema, and start adding logic.
230
+
231
+ ## Step 4
232
+ As your new vendor lib contains the same test data that all other vendors do, you can run the `global-tests` suite. This will show if your capability implementation adheres to the expected behavior within reactionary.
package/core/package.json CHANGED
@@ -6,8 +6,11 @@
6
6
  "dependencies": {
7
7
  "zod": "4.1.9",
8
8
  "@upstash/redis": "^1.34.9",
9
- "node-object-hash": "^3.1.1",
10
- "@opentelemetry/api": "^1.9.0"
9
+ "node-object-hash": "^3.1.1"
11
10
  },
12
- "type": "module"
11
+ "peerDependencies": {
12
+ "@opentelemetry/api": "^1.0.0"
13
+ },
14
+ "type": "module",
15
+ "sideEffects": false
13
16
  }
@@ -1,5 +1,6 @@
1
1
  import type { z } from 'zod';
2
2
  import type { BaseModel } from '../schemas/models/index.js';
3
+ import type { NotFoundError, Result } from '../schemas/index.js';
3
4
 
4
5
  export interface CacheEntryOptions {
5
6
  ttlSeconds: number;
@@ -0,0 +1,4 @@
1
+ export * from './cache.interface.js';
2
+ export * from './memory-cache.js';
3
+ export * from './noop-cache.js';
4
+ export * from './redis-cache.js';
@@ -1,31 +1,43 @@
1
+ import { getReactionaryCacheMeter } from '../metrics/metrics.js';
2
+ import { error, NotFoundErrorSchema, success, type NotFoundError } from '../schemas/index.js';
1
3
  import type { BaseModel } from '../schemas/models/index.js';
4
+ import type { Result } from '../schemas/result.js';
2
5
  import type { Cache, CacheEntryOptions } from './cache.interface.js';
3
6
  import type z from 'zod';
4
7
 
8
+
5
9
  /**
6
10
  * Memory version of the cache. Primarily useful for local development.
7
11
  * This is NOT suited for production use.
8
12
  */
9
13
  export class MemoryCache implements Cache {
10
14
  protected entries = new Array<{ key: string; value: unknown, options: CacheEntryOptions }>();
15
+ protected meter = getReactionaryCacheMeter();
16
+
11
17
 
12
18
  public async get<T extends BaseModel>(key: string, schema: z.ZodType<T>): Promise<T | null> {
13
19
  const c = this.entries.find((x) => x.key === key);
14
20
 
15
21
  if (!c) {
22
+ this.meter.misses.add(1, {
23
+ 'labels.cache_type': 'memory',
24
+ });
25
+
16
26
  return null;
17
27
  }
18
28
 
19
29
  const parsed = schema.parse(c.value);
20
30
 
21
- parsed.meta.cache.hit = true;
31
+ this.meter.hits.add(1, {
32
+ 'labels.cache_type': 'memory',
33
+ });
22
34
 
23
35
  return parsed;
24
36
  }
25
37
 
26
38
  public async put(
27
39
  key: string,
28
- value: unknown,
40
+ value: Result<unknown>,
29
41
  options: CacheEntryOptions
30
42
  ): Promise<void> {
31
43
  this.entries.push({
@@ -34,6 +46,10 @@ export class MemoryCache implements Cache {
34
46
  options
35
47
  });
36
48
 
49
+ this.meter.items.record(this.entries.length, {
50
+ 'labels.cache_type': 'memory',
51
+ });
52
+
37
53
  return;
38
54
  }
39
55
 
@@ -48,9 +64,21 @@ export class MemoryCache implements Cache {
48
64
 
49
65
  index++;
50
66
  }
67
+
68
+ this.meter.items.record(this.entries.length, {
69
+ 'labels.cache_type': 'memory',
70
+ });
71
+
72
+
51
73
  }
52
74
 
53
75
  public async clear(): Promise<void> {
54
76
  this.entries = [];
77
+
78
+ this.meter.items.record(this.entries.length, {
79
+ 'labels.cache_type': 'memory',
80
+ });
81
+
82
+
55
83
  }
56
84
  }
@@ -1,3 +1,4 @@
1
+ import { getReactionaryCacheMeter } from '../metrics/metrics.js';
1
2
  import type { Cache, CacheEntryOptions } from './cache.interface.js';
2
3
  import type z from 'zod';
3
4
 
@@ -6,19 +7,32 @@ import type z from 'zod';
6
7
  * Useful for testing or when caching should be disabled.
7
8
  */
8
9
  export class NoOpCache implements Cache {
10
+ protected meter = getReactionaryCacheMeter();
9
11
  public async get<T>(_key: string, _schema: z.ZodType<T>): Promise<T | null> {
12
+ this.meter.misses.add(1, {
13
+ 'labels.cache_type': 'noop',
14
+ });
10
15
  return null;
11
16
  }
12
17
 
13
18
  public async put(_key: string, _value: unknown, options: CacheEntryOptions): Promise<void> {
19
+ this.meter.items.record(0, {
20
+ 'labels.cache_type': 'noop',
21
+ });
14
22
  return;
15
23
  }
16
24
 
17
25
  public async invalidate(dependencyIds: Array<string>): Promise<void> {
26
+ this.meter.items.record(0, {
27
+ 'labels.cache_type': 'noop',
28
+ });
18
29
  return;
19
30
  }
20
31
 
21
32
  public async clear(): Promise<void> {
33
+ this.meter.items.record(0, {
34
+ 'labels.cache_type': 'noop',
35
+ });
22
36
  return;
23
37
  }
24
- }
38
+ }
@@ -1,9 +1,12 @@
1
1
  import { Redis } from '@upstash/redis';
2
2
  import type { Cache, CacheEntryOptions } from './cache.interface.js';
3
3
  import type z from 'zod';
4
+ import { getReactionaryCacheMeter } from '../metrics/metrics.js';
4
5
 
5
6
  export class RedisCache implements Cache {
6
7
  protected redis: Redis;
8
+ protected meter = getReactionaryCacheMeter();
9
+
7
10
 
8
11
  constructor() {
9
12
  this.redis = Redis.fromEnv();
@@ -18,6 +21,11 @@ export class RedisCache implements Cache {
18
21
  const parsed = schema.safeParse(unvalidated);
19
22
 
20
23
  if (parsed.success) {
24
+ this.meter.hits.add(1, {
25
+ 'labels.cache_type': 'redis',
26
+ });
27
+
28
+
21
29
  return parsed.data;
22
30
  }
23
31
 
@@ -42,6 +50,10 @@ export class RedisCache implements Cache {
42
50
  multi.sadd(`dep:${depId}`, key);
43
51
  }
44
52
 
53
+ this.meter.items.record(await this.redis.dbsize(), {
54
+ 'labels.cache_type': 'redis',
55
+ });
56
+
45
57
  await multi.exec();
46
58
  }
47
59
 
@@ -56,9 +68,17 @@ export class RedisCache implements Cache {
56
68
 
57
69
  await this.redis.del(depKey);
58
70
  }
71
+
72
+ this.meter.items.record(await this.redis.dbsize(), {
73
+ 'labels.cache_type': 'redis',
74
+ });
75
+
59
76
  }
60
77
 
61
78
  public async clear(): Promise<void> {
79
+ this.meter.items.record(await this.redis.dbsize(), {
80
+ 'labels.cache_type': 'redis',
81
+ });
62
82
  // Not sure about supporting this on Redis.
63
83
  }
64
84
  }
@@ -1,63 +1,80 @@
1
- import type { Cache } from "../cache/cache.interface.js";
2
- import { NoOpCache } from "../cache/noop-cache.js";
3
- import type { Client } from "./client.js";
4
- import type { AnalyticsProvider } from "../providers/analytics.provider.js";
1
+ import type { Cache } from '../cache/cache.interface.js';
2
+ import { NoOpCache } from '../cache/noop-cache.js';
3
+ import type { Client } from './client.js';
4
+ import type { AnalyticsProvider } from '../providers/analytics.provider.js';
5
+ import {
6
+ RequestContextSchema,
7
+ type RequestContext,
8
+ } from '../schemas/session.schema.js';
5
9
 
6
- type CapabilityFactory<T> = (cache: Cache) => T;
10
+ type CapabilityFactory<T> = (cache: Cache, context: RequestContext) => T;
7
11
 
8
12
  type MergeCapabilities<Acc, New> = Omit<Acc, keyof New> & New;
9
13
 
10
- export class ClientBuilder<TClient = object> {
11
- private factories: Array<CapabilityFactory<Partial<Client>>> = [];
12
- private cache: Cache | undefined;
13
-
14
- withCapability<TNew extends Partial<Client>>(
15
- factory: CapabilityFactory<TNew>
16
- ): ClientBuilder<MergeCapabilities<TClient, TNew>> {
17
- const newBuilder = new ClientBuilder<MergeCapabilities<TClient, TNew>>();
18
- newBuilder.factories = [...this.factories, factory];
19
- newBuilder.cache = this.cache;
20
- return newBuilder;
14
+ export class ClientBuilder<TClient = Client> {
15
+ private factories: Array<CapabilityFactory<Partial<Client>>> = [];
16
+ private cache: Cache | undefined;
17
+ private context: RequestContext;
18
+
19
+ constructor(context: RequestContext) {
20
+ this.context = context;
21
+ }
22
+
23
+ withCapability<TNew extends Partial<Client>>(
24
+ factory: CapabilityFactory<TNew>
25
+ ): ClientBuilder<MergeCapabilities<TClient, TNew>> {
26
+ const newBuilder = new ClientBuilder<MergeCapabilities<TClient, TNew>>(this.context);
27
+ newBuilder.factories = [...this.factories, factory];
28
+ newBuilder.cache = this.cache;
29
+ newBuilder.context = this.context;
30
+ return newBuilder;
31
+ }
32
+
33
+ withCache(cache: Cache): ClientBuilder<TClient> {
34
+ const newBuilder = new ClientBuilder<TClient>(this.context);
35
+ newBuilder.factories = [...this.factories];
36
+ newBuilder.cache = cache;
37
+ newBuilder.context = this.context;
38
+ return newBuilder;
39
+ }
40
+
41
+ build(): TClient & { cache: Cache } {
42
+ let client = {} as TClient;
43
+
44
+ // Default to no-op cache if none is provided
45
+ const sharedCache = this.cache || new NoOpCache();
46
+ const validatedContext = RequestContextSchema.safeParse(this.context);
47
+
48
+ // Avoid returning the parsed result for context, to preserve object equality at the top level
49
+ if (!validatedContext.success) {
50
+ throw new Error('Invalid context: ' + validatedContext.error);
21
51
  }
22
52
 
23
- withCache(cache: Cache): ClientBuilder<TClient> {
24
- const newBuilder = new ClientBuilder<TClient>();
25
- newBuilder.factories = [...this.factories];
26
- newBuilder.cache = cache;
27
- return newBuilder;
53
+ const mergedAnalytics: AnalyticsProvider[] = [];
54
+
55
+ for (const factory of this.factories) {
56
+ const provider = factory(sharedCache, this.context);
57
+ client = {
58
+ ...client,
59
+ ...provider,
60
+ };
61
+
62
+ if (provider.analytics) {
63
+ mergedAnalytics.push(...provider.analytics);
64
+ }
28
65
  }
29
66
 
30
- build(): TClient & { cache: Cache } {
31
- let client = {} as TClient;
32
-
33
- // Use provided cache or default to NoOpCache
34
- const sharedCache = this.cache || new NoOpCache();
35
-
36
- const mergedAnalytics: AnalyticsProvider[] = [];
37
-
38
- for (const factory of this.factories) {
39
- const provider = factory(sharedCache);
40
- client = {
41
- ...client,
42
- ...provider
43
- };
44
-
45
- if (provider.analytics) {
46
- mergedAnalytics.push(...provider.analytics);
47
- }
48
- }
49
-
50
- // Add merged analytics if any were collected
51
- if (mergedAnalytics.length > 0) {
52
- (client as Record<string, unknown>)['analytics'] = mergedAnalytics;
53
- }
54
-
55
- // Add cache to complete the client
56
- const completeClient = {
57
- ...client,
58
- cache: sharedCache
59
- } as TClient & { cache: Cache };
60
-
61
- return completeClient;
67
+ // Add merged analytics if any were collected
68
+ if (mergedAnalytics.length > 0) {
69
+ (client as Record<string, unknown>)['analytics'] = mergedAnalytics;
62
70
  }
63
- }
71
+
72
+ // Add cache to complete the client
73
+ const completeClient = {
74
+ ...client,
75
+ cache: sharedCache,
76
+ } as TClient & { cache: Cache };
77
+
78
+ return completeClient;
79
+ }
80
+ }