@reactionary/source 0.3.16 → 0.3.18

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 (37) hide show
  1. package/README.md +2 -2
  2. package/core/src/initialization.ts +2 -2
  3. package/core/src/providers/price.provider.ts +2 -1
  4. package/core/src/schemas/models/cart.model.ts +7 -2
  5. package/core/src/schemas/models/identifiers.model.ts +12 -8
  6. package/core/src/schemas/models/price.model.ts +12 -0
  7. package/examples/node/package.json +7 -7
  8. package/examples/node/src/capabilities/cart.spec.ts +97 -15
  9. package/examples/node/src/capabilities/category.spec.ts +27 -32
  10. package/examples/node/src/capabilities/checkout.spec.ts +5 -5
  11. package/examples/node/src/capabilities/identity.spec.ts +6 -2
  12. package/examples/node/src/capabilities/inventory.spec.ts +1 -1
  13. package/examples/node/src/capabilities/price.spec.ts +7 -7
  14. package/examples/node/src/utils.ts +4 -1
  15. package/package.json +3 -3
  16. package/providers/algolia/src/providers/product-search.provider.ts +19 -14
  17. package/providers/commercetools/src/core/client.ts +112 -9
  18. package/providers/commercetools/src/core/token-cache.ts +4 -5
  19. package/providers/commercetools/src/providers/cart.provider.ts +76 -11
  20. package/providers/commercetools/src/providers/inventory.provider.ts +5 -7
  21. package/providers/commercetools/src/providers/price.provider.ts +17 -30
  22. package/providers/commercetools/src/schema/configuration.schema.ts +4 -0
  23. package/providers/commercetools/src/schema/session.schema.ts +3 -1
  24. package/providers/fake/src/providers/cart.provider.ts +1 -0
  25. package/providers/fake/src/providers/price.provider.ts +54 -95
  26. package/providers/medusa/src/providers/cart.provider.ts +159 -70
  27. package/providers/medusa/src/providers/category.provider.ts +35 -23
  28. package/providers/medusa/src/providers/checkout.provider.ts +78 -41
  29. package/providers/medusa/src/providers/order-search.provider.ts +21 -10
  30. package/providers/medusa/src/providers/price.provider.ts +18 -9
  31. package/providers/medusa/src/providers/product-recommendations.provider.ts +10 -6
  32. package/providers/medusa/src/providers/product-search.provider.ts +19 -10
  33. package/providers/medusa/src/providers/product.provider.ts +20 -12
  34. package/providers/medusa/src/providers/profile.provider.ts +38 -13
  35. package/providers/meilisearch/src/providers/order-search.provider.ts +17 -12
  36. package/providers/meilisearch/src/providers/product-recommendations.provider.ts +10 -11
  37. package/providers/meilisearch/src/providers/product-search.provider.ts +23 -18
@@ -79,6 +79,14 @@ export class MedusaProfileProvider extends ProfileProvider {
79
79
  return success(model);
80
80
  }
81
81
 
82
+ protected updatePayload(payload: ProfileMutationUpdate) {
83
+ const updateData: any = {};
84
+ if (payload.phone !== undefined) {
85
+ updateData.phone = payload.phone;
86
+ }
87
+ return updateData;
88
+ }
89
+
82
90
  @Reactionary({
83
91
  inputSchema: ProfileMutationUpdateSchema,
84
92
  outputSchema: ProfileSchema,
@@ -98,14 +106,16 @@ export class MedusaProfileProvider extends ProfileProvider {
98
106
 
99
107
  const customer = customerResponse.customer;
100
108
 
101
- const updatedResponse = await client.store.customer.update({
102
- phone: payload.phone ?? customer.phone,
103
- }, { fields: this.includedFields.join(',') });
109
+ const updatedResponse = await client.store.customer.update(this.updatePayload(payload), { fields: this.includedFields.join(',') });
104
110
 
105
111
  const model = this.parseSingle(updatedResponse.customer);
106
112
  return success(model);
107
113
  }
108
114
 
115
+ protected addShippingAddressPayload(payload: ProfileMutationAddShippingAddress) {
116
+ return this.createMedusaAddress(payload.address);
117
+ }
118
+
109
119
  @Reactionary({
110
120
  inputSchema: ProfileMutationAddShippingAddressSchema,
111
121
  outputSchema: ProfileSchema,
@@ -115,7 +125,6 @@ export class MedusaProfileProvider extends ProfileProvider {
115
125
 
116
126
  const client = await this.medusaApi.getClient();
117
127
 
118
- const medusaAddress = this.createMedusaAddress(payload.address);
119
128
 
120
129
  // check if any address with the same nickName exists
121
130
  const customer = await client.store.customer.retrieve({ fields: this.includedFields.join(',') });
@@ -133,7 +142,7 @@ export class MedusaProfileProvider extends ProfileProvider {
133
142
  });
134
143
  }
135
144
 
136
- const response = await client.store.customer.createAddress(medusaAddress, { fields: this.includedFields.join(',') });
145
+ const response = await client.store.customer.createAddress(this.addShippingAddressPayload(payload), { fields: this.includedFields.join(',') });
137
146
  if (!response.customer) {
138
147
  return error<InvalidInputError>({
139
148
  type: 'InvalidInput',
@@ -145,6 +154,10 @@ export class MedusaProfileProvider extends ProfileProvider {
145
154
  return success(model);
146
155
  }
147
156
 
157
+ protected updateShippingAddressPayload(payload: ProfileMutationUpdateShippingAddress) {
158
+ return this.createMedusaAddress(payload.address);
159
+ }
160
+
148
161
  @Reactionary({
149
162
  inputSchema: ProfileMutationUpdateShippingAddressSchema,
150
163
  outputSchema: ProfileSchema,
@@ -162,8 +175,6 @@ export class MedusaProfileProvider extends ProfileProvider {
162
175
  });
163
176
  }
164
177
 
165
- const medusaAddress = this.createMedusaAddress(payload.address);
166
-
167
178
  const existingAddress = customer.customer.addresses.find(addr => addr.address_name === payload.address.identifier.nickName);
168
179
  if (!existingAddress) {
169
180
  return error<NotFoundError>({
@@ -172,7 +183,7 @@ export class MedusaProfileProvider extends ProfileProvider {
172
183
  });
173
184
  }
174
185
 
175
- const response = await client.store.customer.updateAddress(existingAddress.id, medusaAddress , { fields: this.includedFields.join(',') });
186
+ const response = await client.store.customer.updateAddress(existingAddress.id, this.updateShippingAddressPayload(payload), { fields: this.includedFields.join(',') });
176
187
  if (!response.customer) {
177
188
  return error<InvalidInputError>({
178
189
  type: 'InvalidInput',
@@ -226,6 +237,12 @@ export class MedusaProfileProvider extends ProfileProvider {
226
237
  }
227
238
 
228
239
 
240
+ protected makeShippingAddressDefaultPayload(payload: ProfileMutationMakeShippingAddressDefault) {
241
+ return {
242
+ is_default_shipping: true
243
+ }
244
+ }
245
+
229
246
  @Reactionary({
230
247
  inputSchema: ProfileMutationMakeShippingAddressDefaultSchema,
231
248
  outputSchema: ProfileSchema,
@@ -251,15 +268,23 @@ export class MedusaProfileProvider extends ProfileProvider {
251
268
  });
252
269
  }
253
270
 
254
- const response = await client.store.customer.updateAddress(existingAddress.id, {
255
- is_default_shipping: true
256
- }, { fields: this.includedFields.join(',') }
271
+ const response = await client.store.customer.updateAddress(
272
+ existingAddress.id,
273
+ this.makeShippingAddressDefaultPayload(payload),
274
+ { fields: this.includedFields.join(',') }
257
275
  );
258
276
 
259
277
  const model = this.parseSingle(response.customer!);
260
278
  return success(model);
261
279
  }
262
280
 
281
+
282
+ protected setBillingAddressPayload(payload: ProfileMutationSetBillingAddress) {
283
+ const newAddr = this.createMedusaAddress(payload.address);
284
+ newAddr.is_default_billing = true;
285
+ return newAddr;
286
+ }
287
+
263
288
  @Reactionary({
264
289
  inputSchema: ProfileMutationSetBillingAddressSchema,
265
290
  outputSchema: ProfileSchema,
@@ -289,9 +314,9 @@ export class MedusaProfileProvider extends ProfileProvider {
289
314
  }
290
315
 
291
316
 
292
- const newAddr = this.createMedusaAddress(payload.address);
293
- newAddr.is_default_billing = true;
294
317
 
318
+
319
+ const newAddr = this.setBillingAddressPayload(payload);
295
320
  // two scenarios: Either we already have a billing addres, in which case we update it, or we dont and we need to create it.
296
321
  const existingBillingAddress = customer.addresses.find(addr => addr.is_default_billing);
297
322
  if (existingBillingAddress) {
@@ -52,17 +52,7 @@ export class MeilisearchOrderSearchProvider extends OrderSearchProvider {
52
52
  this.config = config;
53
53
  }
54
54
 
55
- @Reactionary({
56
- inputSchema: OrderSearchQueryByTermSchema,
57
- outputSchema: OrderSearchResultSchema,
58
- })
59
- public async queryByTerm(payload: OrderSearchQueryByTerm): Promise<Result<OrderSearchResult>> {
60
- const client = new MeiliSearch({
61
- host: this.config.apiUrl,
62
- apiKey: this.config.apiKey,
63
- });
64
-
65
- const index = client.index(this.config.orderIndexName);
55
+ protected queryByTermPayload(payload: OrderSearchQueryByTerm): SearchParams {
66
56
 
67
57
  const filters: string[] = [];
68
58
 
@@ -103,10 +93,25 @@ export class MeilisearchOrderSearchProvider extends OrderSearchProvider {
103
93
  filter: filters.length > 0 ? filters.join(' AND ') : undefined,
104
94
  sort: ['orderDateTimestamp:desc'],
105
95
  };
96
+ return searchOptions
97
+ }
98
+
99
+ @Reactionary({
100
+ inputSchema: OrderSearchQueryByTermSchema,
101
+ outputSchema: OrderSearchResultSchema,
102
+ })
103
+ public async queryByTerm(payload: OrderSearchQueryByTerm): Promise<Result<OrderSearchResult>> {
104
+ const client = new MeiliSearch({
105
+ host: this.config.apiUrl,
106
+ apiKey: this.config.apiKey,
107
+ });
108
+
109
+ const index = client.index(this.config.orderIndexName);
110
+
106
111
 
107
112
  const remote = await index.search<MeilisearchNativeOrderRecord>(
108
113
  payload.search.term || '',
109
- searchOptions
114
+ this.queryByTermPayload(payload)
110
115
  );
111
116
 
112
117
  const result = this.parsePaginatedResult(remote, payload) as OrderSearchResult;
@@ -9,7 +9,7 @@ import {
9
9
  type ProductSearchResultItemVariant,
10
10
  ProductSearchResultItemVariantSchema,
11
11
  } from '@reactionary/core';
12
- import { MeiliSearch, type Hits, type RecordAny, type SearchParams, type SearchResponse } from 'meilisearch';
12
+ import { MeiliSearch, type Hits, type RecordAny, type SearchParams, type SearchResponse, type SearchSimilarDocumentsParams } from 'meilisearch';
13
13
  import type { MeilisearchConfiguration } from '../schema/configuration.schema.js';
14
14
  import type { MeilisearchNativeRecord, MeilisearchNativeVariant } from '../schema/index.js';
15
15
 
@@ -32,6 +32,14 @@ export class MeilisearchProductRecommendationsProvider extends ProductRecommenda
32
32
  this.config = config;
33
33
  }
34
34
 
35
+ protected getSimilarProductsRecommendationsPayload(query: ProductRecommendationAlgorithmSimilarProductsQuery): SearchSimilarDocumentsParams {
36
+ return {
37
+ id: query.sourceProduct.key,
38
+ limit: query.numberOfRecommendations,
39
+ embedder: this.config.useAIEmbedding,
40
+ }
41
+ }
42
+
35
43
  /**
36
44
  * Get similar product recommendations
37
45
  * Uses semantic search to find visually or data-wise similar products
@@ -52,16 +60,7 @@ export class MeilisearchProductRecommendationsProvider extends ProductRecommenda
52
60
  }
53
61
 
54
62
  try {
55
- const searchOptions: SearchParams = {
56
- limit: query.numberOfRecommendations,
57
- };
58
-
59
- const response = await index.searchSimilarDocuments<MeilisearchNativeRecord>({
60
- id: query.sourceProduct.key,
61
- limit: query.numberOfRecommendations,
62
- embedder: this.config.useAIEmbedding,
63
- });
64
-
63
+ const response = await index.searchSimilarDocuments<MeilisearchNativeRecord>(this.getSimilarProductsRecommendationsPayload(query));
65
64
 
66
65
  return this.parseRecommendations(response, 'similar');
67
66
  } catch (error) {
@@ -36,23 +36,7 @@ export class MeilisearchSearchProvider extends ProductSearchProvider {
36
36
  this.config = config;
37
37
  }
38
38
 
39
- @Reactionary({
40
- inputSchema: ProductSearchQueryByTermSchema,
41
- outputSchema: ProductSearchResultSchema,
42
- cache: true,
43
- cacheTimeToLiveInSeconds: 300,
44
- currencyDependentCaching: false,
45
- localeDependentCaching: true
46
- })
47
- public override async queryByTerm(
48
- payload: ProductSearchQueryByTerm
49
- ): Promise<Result<ProductSearchResult>> {
50
- const client = new MeiliSearch({
51
- host: this.config.apiUrl,
52
- apiKey: this.config.apiKey,
53
- });
54
-
55
- const index = client.index(this.config.indexName);
39
+ protected queryByTermPayload(payload: ProductSearchQueryByTerm) {
56
40
 
57
41
  const facetsThatAreNotCategory = payload.search.facets.filter(x => x.facet.key !== 'categories');
58
42
  const categoryFacet = payload.search.facets.find(x => x.facet.key === 'categories') || payload.search.categoryFilter;
@@ -88,8 +72,29 @@ export class MeilisearchSearchProvider extends ProductSearchProvider {
88
72
  embedder: this.config.useAIEmbedding
89
73
  };
90
74
  }
75
+ return searchOptions;
76
+ }
77
+
78
+ @Reactionary({
79
+ inputSchema: ProductSearchQueryByTermSchema,
80
+ outputSchema: ProductSearchResultSchema,
81
+ cache: true,
82
+ cacheTimeToLiveInSeconds: 300,
83
+ currencyDependentCaching: false,
84
+ localeDependentCaching: true
85
+ })
86
+ public override async queryByTerm(
87
+ payload: ProductSearchQueryByTerm
88
+ ): Promise<Result<ProductSearchResult>> {
89
+ const client = new MeiliSearch({
90
+ host: this.config.apiUrl,
91
+ apiKey: this.config.apiKey,
92
+ });
93
+
94
+ const index = client.index(this.config.indexName);
95
+
91
96
 
92
- const remote = await index.search<MeilisearchNativeRecord>(payload.search.term, searchOptions);
97
+ const remote = await index.search<MeilisearchNativeRecord>(payload.search.term, this.queryByTermPayload(payload) as SearchParams);
93
98
 
94
99
  const result = this.parsePaginatedResult(remote, payload) as MeilisearchProductSearchResult;
95
100