@graphcommerce/algolia-recommend 9.0.0-canary.85 → 9.0.0-canary.87

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @graphcommerce/algolia-recommend
2
2
 
3
+ ## 9.0.0-canary.87
4
+
5
+ ## 9.0.0-canary.86
6
+
7
+ ### Patch Changes
8
+
9
+ - [#2379](https://github.com/graphcommerce-org/graphcommerce/pull/2379) [`ce30678`](https://github.com/graphcommerce-org/graphcommerce/commit/ce30678ad353ac4c7c38d79e96a2bb3de55f6fcb) - Automatically fall back to existing upsells/related products if they are defined and Algolia returns an error ([@paales](https://github.com/paales))
10
+
3
11
  ## 9.0.0-canary.85
4
12
 
5
13
  ## 9.0.0-canary.84
@@ -5,9 +5,13 @@ import type {
5
5
  AlgoliarecommendationsHit,
6
6
  } from '@graphcommerce/graphql-mesh'
7
7
  import { nonNullable } from '@graphcommerce/next-ui'
8
- import type { GraphQLResolveInfo } from 'graphql'
8
+ import type { GraphQLError, GraphQLResolveInfo } from 'graphql'
9
9
  import type { Simplify } from 'type-fest'
10
10
 
11
+ function isGraphQLError(err: unknown): err is GraphQLError {
12
+ return !!(err as GraphQLError)?.message
13
+ }
14
+
11
15
  const inputToModel = {
12
16
  Trending_items_Input: 'trending_items' as const,
13
17
  Trending_facet_values_Input: 'trending_facets' as const,
@@ -15,29 +19,11 @@ const inputToModel = {
15
19
  Looking_similar_Input: 'looking_similar' as const,
16
20
  Related_products_Input: 'related_products' as const,
17
21
  }
22
+
18
23
  function isAlgoliaResponse<T extends object>(root: T): root is T & { uid: string } {
19
24
  return 'uid' in root
20
25
  }
21
- function argsFromKeysInput(keys, args, context) {
22
- const body = keys
23
- .map(
24
- (key) =>
25
- ({
26
- [key.keyInput]: {
27
- model: inputToModel[key.keyInput as string],
28
- indexName: getIndexName(context),
29
-
30
- ...args,
31
- objectID: key.objectId,
32
- },
33
- }) as unknown as AlgoliarecommendationsRequest_Input,
34
- )
35
- .filter(nonNullable)
36
-
37
- const returnObject = { input: { requests: body } }
38
26
 
39
- return returnObject
40
- }
41
27
  export async function getRecommendations<
42
28
  K extends keyof AlgoliarecommendationsRequest_Input,
43
29
  Input extends AlgoliarecommendationsRequest_Input[K],
@@ -53,29 +39,57 @@ export async function getRecommendations<
53
39
  if (!isAlgoliaResponse(root)) {
54
40
  return []
55
41
  }
56
- return (
57
- (await context.algoliaRecommend.Query.algolia_getRecommendations({
58
- key: { keyInput, objectId: atob(root.uid) },
59
- argsFromKeys: (keys) => argsFromKeysInput(keys, args, context),
60
- valuesFromResults: (res, keys) =>
61
- keys
62
- .map((_key, index) => res?.results[index])
63
- .map((r) => r?.hits.map((hit) => hit && mapper(hit)).filter(nonNullable)) ?? null,
64
- selectionSet: /* GraphQL */ `
65
- {
66
- results {
67
- nbHits
68
- hits {
69
- ... on AlgoliarecommendHit {
70
- objectID
71
- additionalProperties
42
+ try {
43
+ return (
44
+ (await context.algoliaRecommend.Query.algolia_getRecommendations({
45
+ key: { keyInput, objectId: atob(root.uid) },
46
+ argsFromKeys: (keys) => ({
47
+ input: {
48
+ requests: keys
49
+ .map(
50
+ (key) =>
51
+ ({
52
+ [key.keyInput]: {
53
+ model: inputToModel[key.keyInput as string],
54
+ indexName: getIndexName(context),
55
+
56
+ ...args,
57
+ objectID: key.objectId,
58
+ },
59
+ }) as unknown as AlgoliarecommendationsRequest_Input,
60
+ )
61
+ .filter(nonNullable),
62
+ },
63
+ }),
64
+ valuesFromResults: (res, keys) =>
65
+ keys
66
+ .map((_key, index) => res?.results[index])
67
+ .map((r) => r?.hits.map((hit) => hit && mapper(hit)).filter(nonNullable)) ?? null,
68
+ selectionSet: /* GraphQL */ `
69
+ {
70
+ results {
71
+ nbHits
72
+ hits {
73
+ ... on AlgoliarecommendHit {
74
+ objectID
75
+ additionalProperties
76
+ }
72
77
  }
73
78
  }
74
79
  }
75
- }
76
- `,
77
- context,
78
- info,
79
- })) ?? null
80
- )
80
+ `,
81
+ context,
82
+ info,
83
+ })) ?? null
84
+ )
85
+ } catch (e) {
86
+ if (isGraphQLError(e)) {
87
+ console.log(
88
+ 'There was an error retrieving Algolia Recommendations, make sure the recommendation models are created',
89
+ e,
90
+ )
91
+ }
92
+
93
+ return null
94
+ }
81
95
  }
package/mesh/resolvers.ts CHANGED
@@ -87,11 +87,12 @@ type ProductResolver = ResolverFn<
87
87
  >
88
88
 
89
89
  if (isEnabled(import.meta.graphCommerce.algolia.relatedProducts)) {
90
+ const fieldName = enumToLocation(import.meta.graphCommerce.algolia.relatedProducts)
90
91
  const resolve: ProductResolver = async (root, args, context, info) => {
91
92
  const { objectID, threshold, fallbackParameters, maxRecommendations, queryParameters } =
92
93
  await getRecommendationsArgs(root, args, context)
93
94
 
94
- return getRecommendations(
95
+ const recommendations = await getRecommendations(
95
96
  root,
96
97
  'Related_products_Input',
97
98
  { objectID, threshold, fallbackParameters, maxRecommendations, queryParameters },
@@ -99,11 +100,12 @@ if (isEnabled(import.meta.graphCommerce.algolia.relatedProducts)) {
99
100
  info,
100
101
  await createProductMapper(context),
101
102
  )
103
+ return recommendations ?? root[fieldName] ?? null
102
104
  }
103
105
 
104
106
  productInterfaceTypes.forEach((productType) => {
105
107
  if (!resolvers[productType]) resolvers[productType] = {}
106
- resolvers[productType][enumToLocation(import.meta.graphCommerce.algolia.relatedProducts)] = {
108
+ resolvers[productType][fieldName] = {
107
109
  selectionSet: `{ uid }`,
108
110
  resolve,
109
111
  }
@@ -111,10 +113,11 @@ if (isEnabled(import.meta.graphCommerce.algolia.relatedProducts)) {
111
113
  }
112
114
 
113
115
  if (isEnabled(import.meta.graphCommerce.algolia.lookingSimilar)) {
116
+ const fieldName = enumToLocation(import.meta.graphCommerce.algolia.lookingSimilar)
114
117
  const resolve: ProductResolver = async (root, args, context, info) => {
115
118
  const { objectID, threshold, fallbackParameters, maxRecommendations, queryParameters } =
116
119
  await getRecommendationsArgs(root, args, context)
117
- return getRecommendations(
120
+ const recommendations = await getRecommendations(
118
121
  root,
119
122
  'Looking_similar_Input',
120
123
  { objectID, threshold, fallbackParameters, maxRecommendations, queryParameters },
@@ -122,11 +125,12 @@ if (isEnabled(import.meta.graphCommerce.algolia.lookingSimilar)) {
122
125
  info,
123
126
  await createProductMapper(context),
124
127
  )
128
+ return recommendations ?? root[fieldName] ?? null
125
129
  }
126
130
 
127
131
  productInterfaceTypes.forEach((productType) => {
128
132
  if (!resolvers[productType]) resolvers[productType] = {}
129
- resolvers[productType][enumToLocation(import.meta.graphCommerce.algolia.lookingSimilar)] = {
133
+ resolvers[productType][fieldName] = {
130
134
  selectionSet: `{ uid }`,
131
135
  resolve,
132
136
  }
@@ -134,11 +138,12 @@ if (isEnabled(import.meta.graphCommerce.algolia.lookingSimilar)) {
134
138
  }
135
139
 
136
140
  if (isEnabled(import.meta.graphCommerce.algolia.frequentlyBoughtTogether)) {
137
- const resolver: ProductResolver = async (root, args, context, info) => {
141
+ const fieldName = enumToLocation(import.meta.graphCommerce.algolia.frequentlyBoughtTogether)
142
+
143
+ const resolve: ProductResolver = async (root, args, context, info) => {
138
144
  const { objectID, threshold, maxRecommendations, queryParameters } =
139
145
  await getRecommendationsArgs(root, args, context)
140
-
141
- return getRecommendations(
146
+ const recommendations = await getRecommendations(
142
147
  root,
143
148
  'Frequently_bought_together_Input',
144
149
  { objectID, threshold, maxRecommendations, queryParameters },
@@ -146,13 +151,12 @@ if (isEnabled(import.meta.graphCommerce.algolia.frequentlyBoughtTogether)) {
146
151
  info,
147
152
  await createProductMapper(context),
148
153
  )
154
+ return recommendations ?? root[fieldName] ?? null
149
155
  }
150
156
 
151
157
  productInterfaceTypes.forEach((productType) => {
152
158
  if (!resolvers[productType]) resolvers[productType] = {}
153
- resolvers[productType][
154
- enumToLocation(import.meta.graphCommerce.algolia.frequentlyBoughtTogether)
155
- ] = resolver
159
+ resolvers[productType][fieldName] = { selectionSet: `{ uid }`, resolve }
156
160
  })
157
161
  }
158
162
 
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@graphcommerce/algolia-recommend",
3
3
  "homepage": "https://www.graphcommerce.org/",
4
4
  "repository": "github:graphcommerce-org/graphcommerce",
5
- "version": "9.0.0-canary.85",
5
+ "version": "9.0.0-canary.87",
6
6
  "sideEffects": false,
7
7
  "prettier": "@graphcommerce/prettier-config-pwa",
8
8
  "eslintConfig": {
@@ -15,11 +15,11 @@
15
15
  "generate": "tsx scripts/generate-recommend-spec.mts"
16
16
  },
17
17
  "peerDependencies": {
18
- "@graphcommerce/algolia-products": "^9.0.0-canary.85",
19
- "@graphcommerce/graphql": "^9.0.0-canary.85",
20
- "@graphcommerce/graphql-mesh": "^9.0.0-canary.85",
21
- "@graphcommerce/next-config": "^9.0.0-canary.85",
22
- "@graphcommerce/next-ui": "^9.0.0-canary.85",
18
+ "@graphcommerce/algolia-products": "^9.0.0-canary.87",
19
+ "@graphcommerce/graphql": "^9.0.0-canary.87",
20
+ "@graphcommerce/graphql-mesh": "^9.0.0-canary.87",
21
+ "@graphcommerce/next-config": "^9.0.0-canary.87",
22
+ "@graphcommerce/next-ui": "^9.0.0-canary.87",
23
23
  "react": "^18.2.0"
24
24
  },
25
25
  "devDependencies": {