@reactionary/algolia 0.9.0 → 0.9.1

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.
@@ -5,13 +5,18 @@ import {
5
5
  algoliasearch
6
6
  } from "algoliasearch";
7
7
  import { getProductIndexNameForLocale } from "../core/index-utils.js";
8
+ import { hash } from "node:crypto";
8
9
  class AlgoliaAnalyticsCapability extends AnalyticsCapability {
9
10
  client;
10
11
  config;
12
+ authenticatedUserToken = void 0;
11
13
  constructor(cache, requestContext, config) {
12
14
  super(cache, requestContext);
13
15
  this.config = config;
14
16
  this.client = algoliasearch(this.config.appId, this.config.apiKey).initInsights({});
17
+ if (requestContext.session.identityContext.identity.type === "Registered") {
18
+ this.authenticatedUserToken = hash("sha256", requestContext.session.identityContext.identity.id.userId);
19
+ }
15
20
  }
16
21
  async processProductAddToCart(event) {
17
22
  if (event.source && event.source.type === "search") {
@@ -21,7 +26,8 @@ class AlgoliaAnalyticsCapability extends AnalyticsCapability {
21
26
  eventSubtype: "addToCart",
22
27
  index: getProductIndexNameForLocale(this.config.indexName, this.context.languageContext.locale),
23
28
  objectIDs: [event.product.key],
24
- userToken: this.context.session.identityContext.personalizationKey,
29
+ userToken: event.personalizationProfile?.identifier.key || "anonymous",
30
+ authenticatedUserToken: this.authenticatedUserToken,
25
31
  queryID: event.source.identifier.key
26
32
  };
27
33
  await this.client.pushEvents({
@@ -36,7 +42,8 @@ class AlgoliaAnalyticsCapability extends AnalyticsCapability {
36
42
  eventType: "click",
37
43
  index: getProductIndexNameForLocale(this.config.indexName, this.context.languageContext.locale),
38
44
  objectIDs: [event.product.key],
39
- userToken: this.context.session.identityContext.personalizationKey,
45
+ userToken: event.personalizationProfile?.identifier.key || "anonymous",
46
+ authenticatedUserToken: this.authenticatedUserToken,
40
47
  positions: [event.position],
41
48
  queryID: event.source.identifier.key
42
49
  };
@@ -52,7 +59,8 @@ class AlgoliaAnalyticsCapability extends AnalyticsCapability {
52
59
  eventType: "view",
53
60
  index: getProductIndexNameForLocale(this.config.indexName, this.context.languageContext.locale),
54
61
  objectIDs: event.products.map((x) => x.key),
55
- userToken: this.context.session.identityContext.personalizationKey
62
+ userToken: event.personalizationProfile?.identifier.key || "anonymous",
63
+ authenticatedUserToken: this.authenticatedUserToken
56
64
  };
57
65
  await this.client.pushEvents({
58
66
  events: [algoliaEvent]
@@ -66,7 +74,8 @@ class AlgoliaAnalyticsCapability extends AnalyticsCapability {
66
74
  eventSubtype: "purchase",
67
75
  index: getProductIndexNameForLocale(this.config.indexName, this.context.languageContext.locale),
68
76
  objectIDs: event.order.items.map((x) => x.variant.sku),
69
- userToken: this.context.session.identityContext.personalizationKey
77
+ userToken: event.personalizationProfile?.identifier.key || "anonymous",
78
+ authenticatedUserToken: this.authenticatedUserToken
70
79
  };
71
80
  await this.client.pushEvents({
72
81
  events: [algoliaEvent]
@@ -19,11 +19,16 @@ class AlgoliaProductRecommendationsCapability extends ProductRecommendationsCapa
19
19
  getRecommendationThreshold(_algorithm) {
20
20
  return 10;
21
21
  }
22
- getQueryParametersForRecommendations(algorithm) {
22
+ getQueryParametersForRecommendations(algorithm, query) {
23
+ const ruleContexts = query.personalizationProfile ? [...query.personalizationProfile.segments.map((segment) => "segment:" + segment)] : [];
24
+ if (query.labels) {
25
+ ruleContexts.push(...query.labels);
26
+ }
23
27
  return {
24
- userToken: this.context.session.identityContext?.personalizationKey || "anonymous",
28
+ userToken: query.personalizationProfile?.identifier.key || "anonymous",
25
29
  analytics: true,
26
30
  analyticsTags: ["reactionary", algorithm],
31
+ ruleContexts,
27
32
  clickAnalytics: true
28
33
  };
29
34
  }
@@ -44,7 +49,7 @@ class AlgoliaProductRecommendationsCapability extends ProductRecommendationsCapa
44
49
  objectID: query.sourceProduct.key,
45
50
  maxRecommendations: query.numberOfRecommendations,
46
51
  threshold: this.getRecommendationThreshold("bought-together"),
47
- queryParameters: this.getQueryParametersForRecommendations("bought-together")
52
+ queryParameters: this.getQueryParametersForRecommendations("bought-together", query)
48
53
  }
49
54
  ]
50
55
  });
@@ -77,7 +82,7 @@ class AlgoliaProductRecommendationsCapability extends ProductRecommendationsCapa
77
82
  objectID: query.sourceProduct.key,
78
83
  maxRecommendations: query.numberOfRecommendations,
79
84
  threshold: this.getRecommendationThreshold("looking-similar"),
80
- queryParameters: this.getQueryParametersForRecommendations("looking-similar")
85
+ queryParameters: this.getQueryParametersForRecommendations("looking-similar", query)
81
86
  }
82
87
  ]
83
88
  });
@@ -110,7 +115,7 @@ class AlgoliaProductRecommendationsCapability extends ProductRecommendationsCapa
110
115
  objectID: query.sourceProduct.key,
111
116
  maxRecommendations: query.numberOfRecommendations,
112
117
  threshold: this.getRecommendationThreshold("related-products"),
113
- queryParameters: this.getQueryParametersForRecommendations("related-products")
118
+ queryParameters: this.getQueryParametersForRecommendations("related-products", query)
114
119
  }
115
120
  ]
116
121
  });
@@ -144,7 +149,7 @@ class AlgoliaProductRecommendationsCapability extends ProductRecommendationsCapa
144
149
  facetValue: query.sourceCategory.key,
145
150
  maxRecommendations: query.numberOfRecommendations,
146
151
  threshold: this.getRecommendationThreshold("trending-items"),
147
- queryParameters: this.getQueryParametersForRecommendations("trending-items")
152
+ queryParameters: this.getQueryParametersForRecommendations("trending-items", query)
148
153
  }
149
154
  ]
150
155
  });
@@ -40,6 +40,10 @@ class AlgoliaProductSearchCapability extends ProductSearchCapability {
40
40
  if (categoryFacet) {
41
41
  finalFilters.push(`categories:"${categoryFacet.key}"`);
42
42
  }
43
+ const rulesContext = [];
44
+ if (payload.personalizationProfile) {
45
+ rulesContext.push(...payload.personalizationProfile.segments.map((s) => `segment:${s}`));
46
+ }
43
47
  return {
44
48
  indexName: getProductIndexNameForLocale(this.config.indexName, this.context.languageContext.locale),
45
49
  query: payload.search.term,
@@ -49,7 +53,9 @@ class AlgoliaProductSearchCapability extends ProductSearchCapability {
49
53
  analytics: true,
50
54
  clickAnalytics: true,
51
55
  facetFilters: finalFacetFilters,
52
- filters: finalFilters.join(" AND ")
56
+ filters: finalFilters.join(" AND "),
57
+ ruleContexts: rulesContext,
58
+ userToken: payload.personalizationProfile?.identifier.key || "anonymous"
53
59
  };
54
60
  }
55
61
  async queryByTerm(payload) {
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@reactionary/algolia",
3
- "version": "0.9.0",
3
+ "version": "0.9.1",
4
4
  "type": "module",
5
5
  "main": "./index.js",
6
6
  "types": "./src/index.d.ts",
7
7
  "dependencies": {
8
- "@reactionary/core": "0.9.0",
8
+ "@reactionary/core": "0.9.1",
9
9
  "zod": "4.1.9",
10
10
  "algoliasearch": "^5.48.0",
11
11
  "vitest": "^4.0.9",
@@ -4,6 +4,7 @@ import type { AlgoliaConfiguration } from '../schema/configuration.schema.js';
4
4
  export declare class AlgoliaAnalyticsCapability extends AnalyticsCapability {
5
5
  protected client: InsightsClient;
6
6
  protected config: AlgoliaConfiguration;
7
+ protected authenticatedUserToken: string | undefined;
7
8
  constructor(cache: Cache, requestContext: RequestContext, config: AlgoliaConfiguration);
8
9
  protected processProductAddToCart(event: AnalyticsMutationProductAddToCartEvent): Promise<void>;
9
10
  protected processProductSummaryClick(event: AnalyticsMutationProductSummaryClickEvent): Promise<void>;
@@ -1,4 +1,4 @@
1
- import { type Cache, ProductRecommendationsCapability, type ProductRecommendation, type ProductRecommendationAlgorithmFrequentlyBoughtTogetherQuery, type ProductRecommendationAlgorithmSimilarProductsQuery, type ProductRecommendationAlgorithmRelatedProductsQuery, type ProductRecommendationAlgorithmTrendingInCategoryQuery, type RequestContext, type ProductRecommendationsQuery, type ProductSearchResultItemVariant } from '@reactionary/core';
1
+ import { type Cache, ProductRecommendationsCapability, type ProductRecommendation, type ProductRecommendationAlgorithmFrequentlyBoughtTogetherQuery, type ProductRecommendationAlgorithmSimilarProductsQuery, type ProductRecommendationAlgorithmRelatedProductsQuery, type ProductRecommendationAlgorithmTrendingInCategoryQuery, type RequestContext, type ProductRecommendationsQuery, type ProductSearchResultItemVariant, type ProductRecommendationBaseQuery } from '@reactionary/core';
2
2
  import { type RecommendationsResults, type RecommendSearchParams, type LiteClient } from 'algoliasearch/lite';
3
3
  import type { AlgoliaConfiguration } from '../schema/configuration.schema.js';
4
4
  import type { AlgoliaProductRecommendationIdentifier } from '../schema/product-recommendation.schema.js';
@@ -17,7 +17,7 @@ export declare class AlgoliaProductRecommendationsCapability extends ProductReco
17
17
  protected client: LiteClient;
18
18
  constructor(config: AlgoliaConfiguration, cache: Cache, context: RequestContext);
19
19
  protected getRecommendationThreshold(_algorithm: string): number;
20
- protected getQueryParametersForRecommendations(algorithm: string): RecommendSearchParams;
20
+ protected getQueryParametersForRecommendations(algorithm: string, query: ProductRecommendationBaseQuery): RecommendSearchParams;
21
21
  /**
22
22
  * Get frequently bought together recommendations using Algolia Recommend
23
23
  */
@@ -11,10 +11,12 @@ export declare class AlgoliaProductSearchCapability<TFactory extends ProductSear
11
11
  page: number;
12
12
  hitsPerPage: number;
13
13
  facets: string[];
14
- analytics: boolean;
15
- clickAnalytics: boolean;
14
+ analytics: true;
15
+ clickAnalytics: true;
16
16
  facetFilters: string[];
17
17
  filters: string;
18
+ ruleContexts: string[];
19
+ userToken: string;
18
20
  };
19
21
  queryByTerm(payload: ProductSearchQueryByTerm): Promise<Result<ProductSearchFactoryOutput<TFactory>>>;
20
22
  createCategoryNavigationFilter(payload: ProductSearchQueryCreateNavigationFilter): Promise<Result<FacetValueIdentifier>>;