@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
@@ -6,57 +6,78 @@ import {
6
6
  type Cache,
7
7
  IdentityProvider,
8
8
  type IdentityMutationRegister,
9
+ Reactionary,
10
+ IdentityQuerySelfSchema,
11
+ IdentitySchema,
12
+ IdentityMutationRegisterSchema,
13
+ IdentityMutationLoginSchema,
14
+ type Result,
15
+ success,
9
16
  } from '@reactionary/core';
10
17
  import type { CommercetoolsConfiguration } from '../schema/configuration.schema.js';
11
18
  import type z from 'zod';
12
- import { CommercetoolsClient } from '../core/client.js';
19
+ import type { CommercetoolsAPI } from '../core/client.js';
13
20
 
14
- export class CommercetoolsIdentityProvider<
15
- T extends Identity = Identity
16
- > extends IdentityProvider<T> {
21
+ export class CommercetoolsIdentityProvider extends IdentityProvider {
17
22
  protected config: CommercetoolsConfiguration;
23
+ protected commercetools: CommercetoolsAPI;
18
24
 
19
25
  constructor(
20
26
  config: CommercetoolsConfiguration,
21
- schema: z.ZodType<T>,
22
- cache: Cache
27
+ cache: Cache,
28
+ context: RequestContext,
29
+ commercetools: CommercetoolsAPI
23
30
  ) {
24
- super(schema, cache);
31
+ super(cache, context);
25
32
 
26
33
  this.config = config;
34
+ this.commercetools = commercetools;
27
35
  }
28
36
 
29
- public override async getSelf(
30
- payload: IdentityQuerySelf,
31
- reqCtx: RequestContext
32
- ): Promise<T> {
33
- return this.assert(reqCtx.identity as T);
37
+ @Reactionary({
38
+ inputSchema: IdentityQuerySelfSchema,
39
+ outputSchema: IdentitySchema,
40
+ })
41
+ public override async getSelf(payload: IdentityQuerySelf): Promise<Result<Identity>> {
42
+ const identity = await this.commercetools.introspect();
43
+
44
+ return success(identity);
34
45
  }
35
46
 
36
- public override async login(
37
- payload: IdentityMutationLogin,
38
- reqCtx: RequestContext
39
- ): Promise<T> {
40
- const identity = await new CommercetoolsClient(this.config).login(payload.username, payload.password, reqCtx);
47
+ @Reactionary({
48
+ inputSchema: IdentityMutationLoginSchema,
49
+ outputSchema: IdentitySchema,
50
+ })
51
+ public override async login(payload: IdentityMutationLogin): Promise<Result<Identity>> {
52
+ const identity = await this.commercetools.login(
53
+ payload.username,
54
+ payload.password
55
+ );
41
56
 
42
- return identity as T;
57
+ return success(identity);
43
58
  }
44
59
 
45
- public override async logout(
46
- payload: Record<string, never>,
47
- reqCtx: RequestContext
48
- ): Promise<T> {
49
- const identity = await new CommercetoolsClient(this.config).logout(reqCtx);
60
+ @Reactionary({
61
+ outputSchema: IdentitySchema,
62
+ })
63
+ public override async logout(payload: Record<string, never>): Promise<Result<Identity>> {
64
+ const identity = await this.commercetools.logout();
50
65
 
51
- return identity as T;
66
+ return success(identity);
52
67
  }
53
68
 
69
+ @Reactionary({
70
+ inputSchema: IdentityMutationRegisterSchema,
71
+ outputSchema: IdentitySchema,
72
+ })
54
73
  public override async register(
55
- payload: IdentityMutationRegister,
56
- reqCtx: RequestContext
57
- ): Promise<T> {
58
- const identity = await new CommercetoolsClient(this.config).register(payload.username, payload.password, reqCtx);
74
+ payload: IdentityMutationRegister
75
+ ): Promise<Result<Identity>> {
76
+ const identity = await this.commercetools.register(
77
+ payload.username,
78
+ payload.password
79
+ );
59
80
 
60
- return identity as T;
81
+ return success(identity);
61
82
  }
62
83
  }
@@ -2,11 +2,11 @@ export * from './cart.provider.js';
2
2
  export * from './category.provider.js';
3
3
  export * from './identity.provider.js';
4
4
  export * from './inventory.provider.js';
5
+ export * from './order-search.provider.js';
5
6
  export * from './price.provider.js';
6
7
  export * from './product.provider.js';
7
8
  export * from './profile.provider.js';
8
- export * from './search.provider.js';
9
+ export * from './product-search.provider.js';
9
10
  export * from './store.provider.js';
10
-
11
11
  export * from './order.provider.js';
12
12
  export * from './checkout.provider.js';
@@ -3,102 +3,104 @@ import type {
3
3
  RequestContext,
4
4
  Cache,
5
5
  InventoryQueryBySKU,
6
+ InventoryIdentifier,
7
+ InventoryStatus,
8
+ Result,
9
+ NotFoundError,
6
10
  } from '@reactionary/core';
7
- import { InventoryProvider } from '@reactionary/core';
8
- import type z from 'zod';
11
+ import { InventoryProvider, InventoryQueryBySKUSchema, InventorySchema, Reactionary, success, error } from '@reactionary/core';
9
12
  import type { CommercetoolsConfiguration } from '../schema/configuration.schema.js';
10
- import { CommercetoolsClient } from '../core/client.js';
11
- import type {
12
- InventoryEntry,
13
- } from '@commercetools/platform-sdk';
14
- export class CommercetoolsInventoryProvider<
15
- T extends Inventory = Inventory
16
- > extends InventoryProvider<T> {
13
+ import type { InventoryEntry } from '@commercetools/platform-sdk';
14
+ import type { CommercetoolsAPI } from '../core/client.js';
15
+
16
+ export class CommercetoolsInventoryProvider extends InventoryProvider {
17
17
  protected config: CommercetoolsConfiguration;
18
+ protected commercetools: CommercetoolsAPI;
18
19
 
19
20
  constructor(
20
21
  config: CommercetoolsConfiguration,
21
- schema: z.ZodType<T>,
22
- cache: Cache
22
+ cache: Cache,
23
+ context: RequestContext,
24
+ commercetools: CommercetoolsAPI
23
25
  ) {
24
- super(schema, cache);
26
+ super(cache, context);
25
27
 
26
28
  this.config = config;
29
+ this.commercetools = commercetools;
27
30
  }
28
31
 
29
- protected async getClient(reqCtx: RequestContext) {
30
- const client = await new CommercetoolsClient(this.config).getClient(reqCtx);
31
- return client
32
- .withProjectKey({ projectKey: this.config.projectKey })
33
- .inventory();
32
+ protected async getClient() {
33
+ const client = await this.commercetools.getClient();
34
+ return client.withProjectKey({ projectKey: this.config.projectKey });
34
35
  }
35
36
 
36
- public override async getBySKU(
37
- payload: InventoryQueryBySKU,
38
- reqCtx: RequestContext
39
- ): Promise<T> {
40
- const client = await new CommercetoolsClient(this.config).getClient(reqCtx);
41
-
42
- // TODO: We can't query by supplyChannel.key, so we have to resolve it first.
43
- // This is probably a good candidate for internal data caching at some point.
44
- const channel = await client
45
- .withProjectKey({ projectKey: this.config.projectKey })
46
- .channels()
47
- .withKey({ key: payload.fulfilmentCenter.key })
48
- .get()
49
- .execute();
50
-
51
- const channelId = channel.body.id;
52
-
53
- const remote = await client
54
- .withProjectKey({ projectKey: this.config.projectKey })
55
- .inventory()
56
- .get({
57
- queryArgs: {
58
- where: 'sku=:sku AND supplyChannel(id=:channel)',
59
- 'var.sku': payload.sku.key,
60
- 'var.channel': channelId,
61
- expand: 'supplyChannel'
62
- },
63
- })
64
- .execute();
65
-
66
- const result = remote.body.results[0];
67
-
68
- const model = this.parseSingle(result, reqCtx);
69
-
70
- return model;
37
+ @Reactionary({
38
+ inputSchema: InventoryQueryBySKUSchema,
39
+ outputSchema: InventorySchema,
40
+ })
41
+ public override async getBySKU(payload: InventoryQueryBySKU): Promise<Result<Inventory, NotFoundError>> {
42
+ const client = await this.getClient();
43
+
44
+ try {
45
+
46
+ // TODO: We can't query by supplyChannel.key, so we have to resolve it first.
47
+ // This is probably a good candidate for internal data caching at some point.
48
+ const channel = await client
49
+ .channels()
50
+ .withKey({ key: payload.fulfilmentCenter.key })
51
+ .get()
52
+ .execute();
53
+
54
+ const channelId = channel.body.id;
55
+
56
+ const remote = await client
57
+ .inventory()
58
+ .get({
59
+ queryArgs: {
60
+ where: 'sku=:sku AND supplyChannel(id=:channel)',
61
+ 'var.sku': payload.variant.sku,
62
+ 'var.channel': channelId,
63
+ expand: 'supplyChannel',
64
+ },
65
+ })
66
+ .execute();
67
+
68
+ const result = remote.body.results[0];
69
+
70
+ const model = this.parseSingle(result);
71
+
72
+
73
+ return success(model);
74
+ } catch (err) {
75
+ console.error('Error fetching inventory by SKU and Fulfillment Center:', error, payload);
76
+ return error<NotFoundError>({
77
+ type: 'NotFound',
78
+ identifier: payload
79
+ });
80
+ }
71
81
  }
72
82
 
73
- protected override parseSingle(
74
- body: InventoryEntry,
75
- reqCtx: RequestContext
76
- ): T {
77
- const model = this.newModel();
78
-
79
- model.identifier = {
80
- sku: { key: body.sku || '' },
83
+ protected parseSingle(body: InventoryEntry): Inventory {
84
+ const identifier = {
85
+ variant: { sku: body.sku || '' },
81
86
  fulfillmentCenter: {
82
87
  key: body.supplyChannel?.obj?.key || '',
83
88
  },
84
- };
89
+ } satisfies InventoryIdentifier;
85
90
 
86
- model.quantity = body.availableQuantity || 0;
91
+ const quantity = body.availableQuantity || 0;
92
+ let status: InventoryStatus = 'outOfStock';
87
93
 
88
- if (model.quantity > 0) {
89
- model.status = 'inStock';
90
- } else {
91
- model.status = 'outOfStock';
94
+ if (quantity > 0) {
95
+ status = 'inStock';
92
96
  }
93
97
 
94
- model.meta = {
95
- cache: {
96
- hit: false,
97
- key: this.generateCacheKeySingle(model.identifier, reqCtx),
98
- },
99
- placeholder: false,
100
- };
98
+ const result = {
99
+ identifier,
100
+ quantity,
101
+ status,
102
+ } satisfies Inventory;
101
103
 
102
- return this.assert(model);
104
+ return result;
103
105
  }
104
106
  }
@@ -0,0 +1,220 @@
1
+ import type {
2
+ RequestContext,
3
+ Cache,
4
+ OrderSearchQueryByTerm,
5
+ OrderSearchResult,
6
+ Result,
7
+ OrderSearchIdentifier,
8
+ MonetaryAmount,
9
+ Currency,
10
+ IdentityIdentifier,
11
+ Address,
12
+ OrderStatus,
13
+ } from '@reactionary/core';
14
+ import {
15
+ OrderSearchProvider,
16
+ OrderSearchQueryByTermSchema,
17
+ OrderSearchResultSchema,
18
+ type OrderSearchResultItem,
19
+ Reactionary,
20
+ success,
21
+ } from '@reactionary/core';
22
+ import type { CommercetoolsConfiguration } from '../schema/configuration.schema.js';
23
+ import type { CommercetoolsAPI } from '../core/client.js';
24
+ import createDebug from 'debug';
25
+ import type { Order as CTOrder, OrderPagedSearchResponse , Address as CTAddress, OrderPagedQueryResponse} from '@commercetools/platform-sdk';
26
+
27
+ const debug = createDebug('reactionary:commercetools:order-search');
28
+
29
+ export class CommercetoolsOrderSearchProvider extends OrderSearchProvider {
30
+ protected config: CommercetoolsConfiguration;
31
+ protected commercetools: CommercetoolsAPI;
32
+
33
+ constructor(
34
+ config: CommercetoolsConfiguration,
35
+ cache: Cache,
36
+ context: RequestContext,
37
+ commercetools: CommercetoolsAPI
38
+ ) {
39
+ super(cache, context);
40
+
41
+ this.config = config;
42
+ this.commercetools = commercetools;
43
+ }
44
+
45
+ protected async getClient() {
46
+ const client = await this.commercetools.getClient();
47
+ return client
48
+ .withProjectKey({ projectKey: this.config.projectKey })
49
+ .me()
50
+ .orders();
51
+ }
52
+
53
+ @Reactionary({
54
+ inputSchema: OrderSearchQueryByTermSchema,
55
+ outputSchema: OrderSearchResultSchema,
56
+ })
57
+ public async queryByTerm(payload: OrderSearchQueryByTerm): Promise<Result<OrderSearchResult>> {
58
+ debug('queryByTerm', payload);
59
+
60
+ const client = await this.getClient();
61
+ const where: string[] = [];
62
+ if (payload.search) {
63
+ if (payload.search.term) {
64
+ debug('Search by term is not implemented yet in CommercetoolsOrderSearchProvider');
65
+ }
66
+
67
+ if (payload.search.partNumber) {
68
+ for (const partNumber of payload.search.partNumber) {
69
+ where.push(`lineItems(variant(sku="${partNumber}"))`);
70
+ }
71
+ }
72
+
73
+ if (payload.search.user && payload.search.user.userId) {
74
+ where.push(`customerId="${payload.search.user.userId}"`);
75
+ }
76
+
77
+ if (payload.search.orderStatus) {
78
+ const orderStatusWhere = payload.search.orderStatus.map(x => {
79
+ if (x === 'AwaitingPayment') {
80
+ return `Open`
81
+ }
82
+ if (x === 'ReleasedToFulfillment') {
83
+ return `Confirmed`
84
+ }
85
+ if (x === 'Shipped') {
86
+ return `Completed`
87
+ }
88
+ if (x === 'Cancelled') {
89
+ return `Cancelled`
90
+ }
91
+ return `orderState="${x}"`
92
+ }).join(' OR ');
93
+ where.push(orderStatusWhere);
94
+ }
95
+
96
+ if (payload.search.startDate) {
97
+ where.push(`createdAt >= "${payload.search.startDate}"`);
98
+ }
99
+
100
+ if (payload.search.endDate) {
101
+ where.push(`createdAt <= "${payload.search.endDate}"`);
102
+ }
103
+ }
104
+
105
+ const response = await client.get({
106
+ queryArgs: {
107
+ where: where,
108
+ withTotal: true,
109
+ limit: payload.search.paginationOptions.pageSize,
110
+ offset:
111
+ (payload.search.paginationOptions.pageNumber - 1) *
112
+ payload.search.paginationOptions.pageSize,
113
+ }
114
+ }).execute();
115
+
116
+ const responseBody = response.body;
117
+ const result = this.parsePaginatedResult(
118
+ responseBody,
119
+ payload
120
+ ) as OrderSearchResult;
121
+
122
+ if (debug.enabled) {
123
+ debug(
124
+ `Search for term "${payload.search.term}" returned ${responseBody.results.length} orders (page ${payload.search.paginationOptions.pageNumber} of ${result.totalPages})`
125
+ );
126
+ }
127
+
128
+ return success(result);
129
+ }
130
+
131
+ protected parseAddress(remote: CTAddress) {
132
+ return {
133
+ countryCode: remote.country || '',
134
+ firstName: remote.firstName || '',
135
+ lastName: remote.lastName || '',
136
+ streetAddress: remote.streetName || '',
137
+ streetNumber: remote.streetNumber || '',
138
+ postalCode: remote.postalCode || '',
139
+ city: remote.city || '',
140
+ identifier: {
141
+ nickName: '',
142
+ },
143
+ region: '',
144
+ } satisfies Address;
145
+ }
146
+
147
+
148
+ protected parseSingle(body: CTOrder) {
149
+ const identifier = { key: body.id };
150
+ const userId: IdentityIdentifier = {
151
+ userId: body.customerId || body.anonymousId || '',
152
+ };
153
+ const customerName = `${body.billingAddress?.firstName} ${body.billingAddress?.lastName}`;
154
+ const shippingAddress = this.parseAddress(body.shippingAddress!);
155
+ const orderDate = body.createdAt;
156
+ let orderStatus: OrderStatus = 'AwaitingPayment';
157
+ if (body.paymentState === 'Pending' && body.orderState === 'Open') {
158
+ orderStatus = 'AwaitingPayment';
159
+ } else if (
160
+ body.paymentState === 'Paid' &&
161
+ body.orderState === 'Confirmed'
162
+ ) {
163
+ orderStatus = 'ReleasedToFulfillment';
164
+ }
165
+ if (body.shipmentState === 'Ready' && body.orderState === 'Confirmed') {
166
+ orderStatus = 'ReleasedToFulfillment';
167
+ }
168
+ if (
169
+ (body.shipmentState === 'Shipped' ||
170
+ body.shipmentState === 'Delivered') &&
171
+ body.orderState === 'Completed'
172
+ ) {
173
+ orderStatus = 'Shipped';
174
+ }
175
+ const inventoryStatus = body.shipmentState as OrderSearchResultItem['inventoryStatus'];
176
+ const totalAmount: MonetaryAmount = {
177
+ currency: body.totalPrice ? body.totalPrice.currencyCode as Currency : this.context.languageContext.currencyCode,
178
+ value: body.totalPrice ? body.totalPrice.centAmount / 100 : 0
179
+ };
180
+
181
+ const order = {
182
+ identifier,
183
+ userId,
184
+ customerName,
185
+ shippingAddress,
186
+ orderDate,
187
+ orderStatus,
188
+ inventoryStatus,
189
+ totalAmount
190
+ } satisfies OrderSearchResultItem;
191
+
192
+ return order;
193
+ }
194
+
195
+ protected parsePaginatedResult(
196
+ body: OrderPagedQueryResponse,
197
+ query: OrderSearchQueryByTerm
198
+ ) {
199
+ const identifier = {
200
+ ...query.search,
201
+ } satisfies OrderSearchIdentifier;
202
+
203
+ const orders: OrderSearchResultItem[] = body.results.map((o) => {
204
+ return this.parseSingle(o);
205
+ })
206
+
207
+ const result = {
208
+ identifier,
209
+ pageNumber: (Math.ceil(body.offset / body.limit) || 0) + 1,
210
+ pageSize: body.limit,
211
+ totalCount: body.total || 0,
212
+ totalPages: Math.ceil((body.total || 0) / body.limit || 0) + 1,
213
+ items: orders,
214
+ } satisfies OrderSearchResult;
215
+
216
+ return result;
217
+ }
218
+
219
+
220
+ }