@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
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "provider-meilisearch",
3
+ "$schema": "../../node_modules/nx/schemas/project-schema.json",
4
+ "sourceRoot": "providers/meilisearch/src",
5
+ "projectType": "library",
6
+ "release": {
7
+ "version": {
8
+ "currentVersionResolver": "git-tag",
9
+ "fallbackCurrentVersionResolver": "disk",
10
+ "preserveLocalDependencyProtocols": false,
11
+ "manifestRootsToUpdate": ["dist/{projectRoot}"]
12
+ }
13
+ },
14
+ "tags": [],
15
+ "targets": {
16
+ "build": {
17
+ "executor": "@nx/esbuild:esbuild",
18
+ "outputs": ["{options.outputPath}"],
19
+ "options": {
20
+ "outputPath": "dist/providers/meilisearch",
21
+ "main": "providers/meilisearch/src/index.ts",
22
+ "tsConfig": "providers/meilisearch/tsconfig.lib.json",
23
+ "assets": ["providers/meilisearch/*.md"],
24
+ "format": ["esm"],
25
+ "bundle": false
26
+ }
27
+ },
28
+ "nx-release-publish": {
29
+ "options": {
30
+ "packageRoot": "dist/{projectRoot}"
31
+ }
32
+ }
33
+ }
34
+ }
@@ -0,0 +1,16 @@
1
+ import type { Cache, ClientFromCapabilities, RequestContext } from "@reactionary/core";
2
+ import { MeilisearchSearchProvider } from "../providers/product-search.provider.js";
3
+ import type { MeilisearchCapabilities } from "../schema/capabilities.schema.js";
4
+ import type { MeilisearchConfiguration } from "../schema/configuration.schema.js";
5
+
6
+ export function withMeilisearchCapabilities<T extends MeilisearchCapabilities>(configuration: MeilisearchConfiguration, capabilities: T) {
7
+ return (cache: Cache, context: RequestContext): ClientFromCapabilities<T> => {
8
+ const client: any = {};
9
+
10
+ if (capabilities.productSearch) {
11
+ client.productSearch = new MeilisearchSearchProvider(configuration, cache, context);
12
+ }
13
+
14
+ return client;
15
+ };
16
+ }
@@ -0,0 +1,5 @@
1
+ export * from './core/initialize.js';
2
+ export * from './providers/product-search.provider.js';
3
+
4
+ export * from './schema/configuration.schema.js';
5
+ export * from './schema/capabilities.schema.js';
@@ -0,0 +1 @@
1
+ export * from './product-search.provider.js';
@@ -0,0 +1,251 @@
1
+ import {
2
+ type Cache,
3
+ type FacetIdentifier,
4
+ FacetIdentifierSchema,
5
+ type FacetValueIdentifier,
6
+ FacetValueIdentifierSchema,
7
+ ImageSchema,
8
+ ProductSearchProvider,
9
+ type ProductSearchQueryByTerm,
10
+ ProductSearchQueryByTermSchema,
11
+ type ProductSearchQueryCreateNavigationFilter,
12
+ type ProductSearchResult,
13
+ type ProductSearchResultFacet,
14
+ ProductSearchResultFacetSchema,
15
+ type ProductSearchResultFacetValue,
16
+ ProductSearchResultFacetValueSchema,
17
+ type ProductSearchResultItem,
18
+ type ProductSearchResultItemVariant,
19
+ ProductSearchResultItemVariantSchema,
20
+ ProductSearchResultSchema,
21
+ Reactionary,
22
+ type RequestContext,
23
+ type Result,
24
+ success
25
+ } from '@reactionary/core';
26
+ import { MeiliSearch, type SearchParams, type SearchResponse } from 'meilisearch';
27
+ import type { MeilisearchConfiguration } from '../schema/configuration.schema.js';
28
+ import type { MeilisearchProductSearchResult } from '../schema/search.schema.js';
29
+
30
+ interface MeilisearchNativeVariant {
31
+ sku: string;
32
+ image: string;
33
+ }
34
+
35
+ interface MeilisearchNativeRecord {
36
+ objectID: string;
37
+ slug?: string;
38
+ name?: string;
39
+ variants: Array<MeilisearchNativeVariant>;
40
+ }
41
+
42
+
43
+ export class MeilisearchSearchProvider extends ProductSearchProvider {
44
+ protected config: MeilisearchConfiguration;
45
+
46
+ constructor(config: MeilisearchConfiguration, cache: Cache, context: RequestContext) {
47
+ super(cache, context);
48
+ this.config = config;
49
+ }
50
+
51
+ @Reactionary({
52
+ inputSchema: ProductSearchQueryByTermSchema,
53
+ outputSchema: ProductSearchResultSchema,
54
+ cache: true,
55
+ cacheTimeToLiveInSeconds: 300,
56
+ currencyDependentCaching: false,
57
+ localeDependentCaching: true
58
+ })
59
+ public override async queryByTerm(
60
+ payload: ProductSearchQueryByTerm
61
+ ): Promise<Result<ProductSearchResult>> {
62
+ const client = new MeiliSearch({
63
+ host: this.config.apiUrl,
64
+ apiKey: this.config.apiKey,
65
+ });
66
+
67
+ const index = client.index(this.config.indexName);
68
+
69
+ const facetsThatAreNotCategory = payload.search.facets.filter(x => x.facet.key !== 'categories');
70
+ const categoryFacet = payload.search.facets.find(x => x.facet.key === 'categories') || payload.search.categoryFilter;
71
+
72
+ const finalFilters: string[] = [...payload.search.filters || []];
73
+
74
+ const finalFacetFilters: string[] = [
75
+ ...facetsThatAreNotCategory.map(
76
+ (x) => `${x.facet.key}="${x.key}"`
77
+ ),
78
+ ];
79
+
80
+ if (categoryFacet) {
81
+ finalFilters.push(`categories = "${categoryFacet.key}"`);
82
+ }
83
+
84
+ // Combine all filters
85
+ let filterString: string | undefined;
86
+ if (finalFilters.length > 0 || finalFacetFilters.length > 0) {
87
+ const allFilters = [...finalFilters, ...finalFacetFilters];
88
+ filterString = allFilters.join(' AND ');
89
+ }
90
+
91
+ const searchOptions: SearchParams = {
92
+ offset: (payload.search.paginationOptions.pageNumber - 1) * payload.search.paginationOptions.pageSize,
93
+ limit: payload.search.paginationOptions.pageSize,
94
+ facets: ['*'],
95
+ filter: filterString,
96
+ };
97
+
98
+ if (this.config.useAIEmbedding) {
99
+ searchOptions.hybrid = {
100
+ embedder: this.config.useAIEmbedding
101
+ };
102
+ }
103
+
104
+ const remote = await index.search<MeilisearchNativeRecord>(payload.search.term, searchOptions);
105
+
106
+ const result = this.parsePaginatedResult(remote, payload) as MeilisearchProductSearchResult;
107
+
108
+ // mark selected facets as active
109
+ for (const selectedFacet of payload.search.facets) {
110
+ const facet = result.facets.find((f) => f.identifier.key === selectedFacet.facet.key);
111
+ if (facet) {
112
+ const value = facet.values.find((v) => v.identifier.key === selectedFacet.key);
113
+ if (value) {
114
+ value.active = true;
115
+ }
116
+ }
117
+ }
118
+
119
+ return success(result);
120
+ }
121
+
122
+ public override async createCategoryNavigationFilter(payload: ProductSearchQueryCreateNavigationFilter): Promise<Result<FacetValueIdentifier>> {
123
+
124
+ const facetIdentifier = FacetIdentifierSchema.parse({
125
+ key: 'categories'
126
+ });
127
+ const facetValueIdentifier = FacetValueIdentifierSchema.parse({
128
+ facet: facetIdentifier,
129
+ key: payload.categoryPath.map(c => c.name).join(' > ')
130
+ });
131
+ return success(facetValueIdentifier);
132
+ }
133
+
134
+
135
+ protected parseSingle(body: MeilisearchNativeRecord) {
136
+ const product = {
137
+ identifier: { key: body.objectID },
138
+ name: body.name || body.objectID,
139
+ slug: body.slug || body.objectID,
140
+ variants: [...(body.variants || [])].map(variant => this.parseVariant(variant, body)),
141
+ } satisfies ProductSearchResultItem;
142
+
143
+ return product;
144
+ }
145
+
146
+ protected override parseVariant(variant: MeilisearchNativeVariant, product: MeilisearchNativeRecord): ProductSearchResultItemVariant {
147
+ const result = ProductSearchResultItemVariantSchema.parse({
148
+ variant: {
149
+ sku: variant.sku
150
+ },
151
+ image: ImageSchema.parse({
152
+ sourceUrl: variant.image,
153
+ altText: product.name || '',
154
+ })
155
+ } satisfies Partial<ProductSearchResultItemVariant>);
156
+
157
+ return result;
158
+ }
159
+
160
+ protected parsePaginatedResult(body: SearchResponse<MeilisearchNativeRecord>, query: ProductSearchQueryByTerm) {
161
+ const items = body.hits.map((hit) => this.parseSingle(hit));
162
+ let facets: ProductSearchResultFacet[] = [];
163
+
164
+ if (body.facetDistribution) {
165
+ for (const id in body.facetDistribution) {
166
+ const f = body.facetDistribution[id];
167
+ const facetId = FacetIdentifierSchema.parse({
168
+ key: id
169
+ });
170
+ const facet = this.parseFacet(facetId, f);
171
+ if (facet.values.length > 0) {
172
+ facets.push(facet);
173
+ }
174
+ }
175
+ }
176
+
177
+ // Handle category hierarchy similar to Algolia
178
+ const selectedCategoryFacet = query.search.facets.find(x => x.facet.key === 'categories') || query.search.categoryFilter;
179
+ let subCategoryFacet;
180
+ if (selectedCategoryFacet) {
181
+ const valueDepth = selectedCategoryFacet.key.split(' > ').length;
182
+ subCategoryFacet = facets.find(f => f.identifier.key === `hierarchy.lvl${valueDepth}`);
183
+ } else {
184
+ subCategoryFacet = facets.find(f => f.identifier.key === 'hierarchy.lvl0');
185
+ }
186
+
187
+ if (subCategoryFacet) {
188
+ // remap to 'categories' facet
189
+ subCategoryFacet.identifier = FacetIdentifierSchema.parse({
190
+ key: 'categories'
191
+ });
192
+ subCategoryFacet.name = 'Categories';
193
+ for (const v of subCategoryFacet.values) {
194
+ const pathParts = v.identifier.key.split(' > ');
195
+ v.identifier.facet = subCategoryFacet.identifier;
196
+ v.name = pathParts[pathParts.length - 1];
197
+ }
198
+ }
199
+
200
+ // remove other hierarchy facets
201
+ facets = facets.filter(f => !f.identifier.key.startsWith('hierarchy.lvl'));
202
+
203
+ const totalPages = Math.ceil((body.estimatedTotalHits || 0) / query.search.paginationOptions.pageSize);
204
+
205
+ const result = {
206
+ identifier: {
207
+ term: query.search.term,
208
+ facets: query.search.facets,
209
+ filters: query.search.filters,
210
+ paginationOptions: query.search.paginationOptions,
211
+ },
212
+ pageNumber: query.search.paginationOptions.pageNumber,
213
+ pageSize: query.search.paginationOptions.pageSize,
214
+ totalCount: body.estimatedTotalHits || 0,
215
+ totalPages: totalPages,
216
+ items: items,
217
+ facets,
218
+ } satisfies ProductSearchResult;
219
+
220
+ return result;
221
+ }
222
+
223
+ protected parseFacet(facetIdentifier: FacetIdentifier, facetValues: Record<string, number>): ProductSearchResultFacet {
224
+ const result: ProductSearchResultFacet = ProductSearchResultFacetSchema.parse({
225
+ identifier: facetIdentifier,
226
+ name: facetIdentifier.key.replace(/_/g, ' '),
227
+ values: []
228
+ });
229
+
230
+ for (const vid in facetValues) {
231
+ const fv = facetValues[vid];
232
+
233
+ const facetValueIdentifier = FacetValueIdentifierSchema.parse({
234
+ facet: facetIdentifier,
235
+ key: vid
236
+ } satisfies Partial<FacetValueIdentifier>);
237
+
238
+ result.values.push(this.parseFacetValue(facetValueIdentifier, vid, fv));
239
+ }
240
+ return result;
241
+ }
242
+
243
+ protected parseFacetValue(facetValueIdentifier: FacetValueIdentifier, label: string, count: number): ProductSearchResultFacetValue {
244
+ return ProductSearchResultFacetValueSchema.parse({
245
+ identifier: facetValueIdentifier,
246
+ name: label,
247
+ count: count,
248
+ active: false,
249
+ } satisfies Partial<ProductSearchResultFacetValue>);
250
+ }
251
+ }
@@ -0,0 +1,9 @@
1
+ import { CapabilitiesSchema } from "@reactionary/core";
2
+ import type { z } from 'zod';
3
+
4
+ export const MeilisearchCapabilitiesSchema = CapabilitiesSchema.pick({
5
+ productSearch: true,
6
+ analytics: true
7
+ }).partial();
8
+
9
+ export type MeilisearchCapabilities = z.infer<typeof MeilisearchCapabilitiesSchema>;
@@ -0,0 +1,10 @@
1
+ import { z } from 'zod';
2
+
3
+ export const MeilisearchConfigurationSchema = z.looseObject({
4
+ apiUrl: z.string(),
5
+ apiKey: z.string(),
6
+ indexName: z.string(),
7
+ useAIEmbedding: z.string().optional()
8
+ });
9
+
10
+ export type MeilisearchConfiguration = z.infer<typeof MeilisearchConfigurationSchema>;
@@ -0,0 +1,3 @@
1
+ export * from './configuration.schema.js';
2
+ export * from './capabilities.schema.js';
3
+ export * from './search.schema.js';
@@ -0,0 +1,14 @@
1
+ import { ProductSearchIdentifierSchema, ProductSearchResultSchema } from '@reactionary/core';
2
+ import { z } from 'zod';
3
+
4
+ export const MeilisearchProductSearchIdentifierSchema = ProductSearchIdentifierSchema.extend({
5
+ key: z.string(),
6
+ index: z.string(),
7
+ });
8
+
9
+ export const MeilisearchProductSearchResultSchema = ProductSearchResultSchema.extend({
10
+ identifier: MeilisearchProductSearchIdentifierSchema.default(() => MeilisearchProductSearchIdentifierSchema.parse({}))
11
+ });
12
+
13
+ export type MeilisearchProductSearchResult = z.infer<typeof MeilisearchProductSearchResultSchema>;
14
+ export type MeilisearchProductSearchIdentifier = z.infer<typeof MeilisearchProductSearchIdentifierSchema>;
@@ -0,0 +1,24 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "module": "NodeNext",
5
+ "moduleResolution": "nodenext",
6
+ "forceConsistentCasingInFileNames": true,
7
+ "strict": true,
8
+ "importHelpers": true,
9
+ "noImplicitOverride": true,
10
+ "noImplicitReturns": true,
11
+ "noFallthroughCasesInSwitch": true,
12
+ "noPropertyAccessFromIndexSignature": true
13
+ },
14
+ "files": [],
15
+ "include": [],
16
+ "references": [
17
+ {
18
+ "path": "./tsconfig.lib.json"
19
+ },
20
+ {
21
+ "path": "./tsconfig.spec.json"
22
+ }
23
+ ]
24
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "../../dist/out-tsc",
5
+ "declaration": true,
6
+ "types": ["node"]
7
+ },
8
+ "include": ["src/**/*.ts"],
9
+ "exclude": ["src/**/*.spec.ts", "vitest.config.ts"]
10
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "extends": "./tsconfig.lib.json",
3
+ "exclude": []
4
+ }
@@ -0,0 +1,14 @@
1
+ import { defineConfig, defineProject } from 'vitest/config';
2
+ import tsconfigPaths from 'vite-tsconfig-paths';
3
+ import { resolve } from 'path';
4
+ import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
5
+
6
+ export default defineProject({
7
+ plugins: [nxViteTsPaths()],
8
+ test: {
9
+ root: resolve(__dirname),
10
+ globals: true,
11
+ environment: 'node',
12
+ include: ['src/**/*.spec.ts'],
13
+ },
14
+ });
@@ -7,5 +7,6 @@
7
7
  "@reactionary/core": "0.0.1",
8
8
  "zod": "4.1.9"
9
9
  },
10
- "type": "module"
10
+ "type": "module",
11
+ "sideEffects": false
11
12
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "extends": "../../tsconfig.base.json",
3
3
  "compilerOptions": {
4
- "module": "nodenext",
4
+ "module": "NodeNext",
5
5
  "moduleResolution": "nodenext",
6
6
  "forceConsistentCasingInFileNames": true,
7
7
  "strict": true,
@@ -17,7 +17,12 @@
17
17
  "paths": {
18
18
  "@reactionary/core": ["core/src/index.ts"],
19
19
  "@reactionary/examples-node": ["examples/node/src/index.ts"],
20
+ "@reactionary/provider-medusa": ["providers/medusa/src/index.ts"],
21
+ "@reactionary/otel": ["otel/src/index.ts"],
20
22
  "@reactionary/provider-algolia": ["providers/algolia/src/index.ts"],
23
+ "@reactionary/provider-meilisearch": [
24
+ "providers/meilisearch/src/index.ts"
25
+ ],
21
26
  "@reactionary/provider-commercetools": [
22
27
  "providers/commercetools/src/index.ts"
23
28
  ],
@@ -0,0 +1,10 @@
1
+ import { resolve } from 'path'
2
+ import { defineConfig } from 'vitest/config'
3
+
4
+ export default defineConfig({
5
+ test: {
6
+ projects: ['providers/*', 'examples/*', 'core'],
7
+ reporters: ['default', 'verbose', 'github-actions'],
8
+
9
+ },
10
+ })
@@ -1,18 +0,0 @@
1
- import type { SearchResult } from '../schemas/models/search.model.js';
2
- import type { SearchQueryByTerm } from '../schemas/queries/search.query.js';
3
- import type { RequestContext } from '../schemas/session.schema.js';
4
- import { BaseProvider } from './base.provider.js';
5
-
6
- export abstract class SearchProvider<
7
- T extends SearchResult = SearchResult
8
- > extends BaseProvider<T> {
9
- public abstract queryByTerm(payload: SearchQueryByTerm, reqCtx: RequestContext): Promise<SearchResult>;
10
-
11
-
12
- protected override getResourceName(): string {
13
- return 'product-search';
14
- }
15
-
16
- }
17
-
18
-
@@ -1,36 +0,0 @@
1
- import { z } from 'zod';
2
- import { ProductIdentifierSchema, FacetValueIdentifierSchema, FacetIdentifierSchema, SearchIdentifierSchema } from './identifiers.model.js';
3
- import { BaseModelSchema } from './base.model.js';
4
-
5
- export const SearchResultProductSchema = z.looseObject({
6
- identifier: ProductIdentifierSchema.default(ProductIdentifierSchema.parse({})),
7
- name: z.string().default(''),
8
- image: z.string().url().default('https://placehold.co/400'),
9
- slug: z.string().default('')
10
- });
11
-
12
- export const SearchResultFacetValueSchema = z.looseObject({
13
- identifier: FacetValueIdentifierSchema.default(() => FacetValueIdentifierSchema.parse({})),
14
- name: z.string().default(''),
15
- count: z.number().default(0),
16
- active: z.boolean().default(false)
17
- });
18
-
19
- export const SearchResultFacetSchema = z.looseObject({
20
- identifier: FacetIdentifierSchema.default(() => FacetIdentifierSchema.parse({})),
21
- name: z.string().default(''),
22
- values: z.array(SearchResultFacetValueSchema).default(() => [])
23
- });
24
-
25
- export const SearchResultSchema = BaseModelSchema.extend({
26
- identifier: SearchIdentifierSchema.default(() => SearchIdentifierSchema.parse({})),
27
- products: z.array(SearchResultProductSchema).default(() => []),
28
- pages: z.number().default(0),
29
- facets: z.array(SearchResultFacetSchema).default(() => [])
30
- });
31
-
32
-
33
- export type SearchResultProduct = z.infer<typeof SearchResultProductSchema>;
34
- export type SearchResult = z.infer<typeof SearchResultSchema>;
35
- export type SearchResultFacet = z.infer<typeof SearchResultFacetSchema>;
36
- export type SearchResultFacetValue = z.infer<typeof SearchResultFacetValueSchema>;
@@ -1,9 +0,0 @@
1
- import type { z } from 'zod';
2
- import { BaseQuerySchema } from './base.query.js';
3
- import { SearchIdentifierSchema } from '../models/identifiers.model.js';
4
-
5
- export const SearchQueryByTermSchema = BaseQuerySchema.extend({
6
- search: SearchIdentifierSchema.required()
7
- });
8
-
9
- export type SearchQueryByTerm = z.infer<typeof SearchQueryByTermSchema>;
@@ -1,30 +0,0 @@
1
- {
2
- "jsc": {
3
- "target": "es2017",
4
- "parser": {
5
- "syntax": "typescript",
6
- "decorators": true,
7
- "dynamicImport": true
8
- },
9
- "transform": {
10
- "decoratorMetadata": true,
11
- "legacyDecorator": true
12
- },
13
- "keepClassNames": true,
14
- "externalHelpers": true,
15
- "loose": true
16
- },
17
- "module": {
18
- "type": "commonjs"
19
- },
20
- "sourceMaps": true,
21
- "exclude": [
22
- "jest.config.ts",
23
- ".*\\.spec.tsx?$",
24
- ".*\\.test.tsx?$",
25
- "./src/jest-setup.ts$",
26
- "./**/jest-setup.ts$",
27
- ".*.js$",
28
- ".*.d.ts$"
29
- ]
30
- }
@@ -1,21 +0,0 @@
1
- import { FlatCompat } from '@eslint/eslintrc';
2
- import { dirname } from 'path';
3
- import { fileURLToPath } from 'url';
4
- import js from '@eslint/js';
5
- import { fixupConfigRules } from '@eslint/compat';
6
- import nx from '@nx/eslint-plugin';
7
- import baseConfig from '../../eslint.config.mjs';
8
- const compat = new FlatCompat({
9
- baseDirectory: dirname(fileURLToPath(import.meta.url)),
10
- recommendedConfig: js.configs.recommended,
11
- });
12
-
13
- export default [
14
- ...fixupConfigRules(compat.extends('next')),
15
- ...fixupConfigRules(compat.extends('next/core-web-vitals')),
16
- ...baseConfig,
17
- ...nx.configs['flat/react-typescript'],
18
- {
19
- ignores: ['.next/**/*'],
20
- },
21
- ];
@@ -1,6 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
- declare module '*.svg' {
3
- const content: any;
4
- export const ReactComponent: any;
5
- export default content;
6
- }
@@ -1,5 +0,0 @@
1
- /// <reference types="next" />
2
- /// <reference types="next/image-types/global" />
3
-
4
- // NOTE: This file should not be edited
5
- // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
@@ -1,31 +0,0 @@
1
- // @ts-check
2
-
3
- const { composePlugins, withNx } = require('@nx/next');
4
-
5
- /**
6
- * @type {import('@nx/next/plugins/with-nx').WithNxOptions}
7
- **/
8
- const nextConfig = {
9
- // Nx-specific options
10
- nx: {},
11
-
12
- webpack: (config) => {
13
- // Ensure Next resolves .ts and .tsx files when .js imports are used
14
- config.resolve.extensions.push('.ts', '.tsx');
15
-
16
- // Tell Webpack: whenever you see a `.js` import, also look for a `.ts` file.
17
- config.resolve.extensionAlias = {
18
- '.js': ['.ts', '.js'],
19
- '.mjs': ['.mts', '.mjs'],
20
- };
21
-
22
- return config;
23
- },
24
- };
25
-
26
- const plugins = [
27
- // Add more Next.js plugins if needed.
28
- withNx,
29
- ];
30
-
31
- module.exports = composePlugins(...plugins)(nextConfig);
@@ -1,9 +0,0 @@
1
- {
2
- "name": "next",
3
- "$schema": "../../node_modules/nx/schemas/project-schema.json",
4
- "sourceRoot": "examples/next",
5
- "projectType": "application",
6
- "tags": [],
7
- "// targets": "to see all targets run: nx show project next --web",
8
- "targets": {}
9
- }
File without changes
Binary file
File without changes
@@ -1,18 +0,0 @@
1
- import './global.css';
2
-
3
- export const metadata = {
4
- title: 'Welcome to next',
5
- description: 'Generated by create-nx-workspace',
6
- };
7
-
8
- export default function RootLayout({
9
- children,
10
- }: {
11
- children: React.ReactNode;
12
- }) {
13
- return (
14
- <html lang="en">
15
- <body>{children}</body>
16
- </html>
17
- );
18
- }
@@ -1,2 +0,0 @@
1
- .page {
2
- }