@graphcommerce/magento-graphql 9.1.0-canary.49 → 9.1.0-canary.51
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 +16 -0
- package/mesh/scopedUidResolver.ts +33 -0
- package/package.json +5 -5
- package/plugins/magentoGraphqlConfig.ts +2 -14
- package/plugins/meshConfigAttrValue.ts +1 -0
- package/typePolicies.ts +16 -33
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 9.1.0-canary.51
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#2537](https://github.com/graphcommerce-org/graphcommerce/pull/2537) [`958dcb6`](https://github.com/graphcommerce-org/graphcommerce/commit/958dcb62d5abb3427a38e2a4583897f3e2043cc4) - Intoduce a new Product-`uid` to solve an issue where cache normalization was not working properly on the frontend when viewing products with a differen curreny, etc.
|
|
8
|
+
|
|
9
|
+
Products now have a more detailed `uid` which will include the scope the product is retrieved from. For example: `NDg5MDM=?store=nl_NL¤cyCode=EUR`. This results in a better cache normalization in Apollo Client and allows for switching between scopes (store/currency/price views/accounts) without creating a broken cache state.
|
|
10
|
+
|
|
11
|
+
We have implemented this with a new resolver that rewrites the `uid` passed from Magento to the Mesh Resolver, and additing additonal data to the `uid` based on the headers passed from the client. This also requires each package to implement the `getPrivateQueryContextMesh` method to retrieve the current PrivateQuery context from the GraphQL request headers. ([@paales](https://github.com/paales))
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- [#2537](https://github.com/graphcommerce-org/graphcommerce/pull/2537) [`3ebd5bb`](https://github.com/graphcommerce-org/graphcommerce/commit/3ebd5bbb9a63a9ee07c748173ed9f4a06ad9b04f) - Add flushMeasurePerf for product page ([@paales](https://github.com/paales))
|
|
16
|
+
|
|
17
|
+
## 9.1.0-canary.50
|
|
18
|
+
|
|
3
19
|
## 9.1.0-canary.49
|
|
4
20
|
|
|
5
21
|
## 9.1.0-canary.48
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/* eslint-disable arrow-body-style */
|
|
2
|
+
import { fragments, getPrivateQueryContextMesh } from '@graphcommerce/graphql'
|
|
3
|
+
import { type MeshContext, type Resolvers } from '@graphcommerce/graphql-mesh'
|
|
4
|
+
import { storefrontFromContext } from '@graphcommerce/magento-store'
|
|
5
|
+
import { storefrontConfigDefault } from '@graphcommerce/next-ui'
|
|
6
|
+
|
|
7
|
+
function scopedUid(root: { uid: string } | { id: string }, args: unknown, context: MeshContext) {
|
|
8
|
+
const store = storefrontFromContext(context) ?? storefrontConfigDefault()
|
|
9
|
+
const privateContext = getPrivateQueryContextMesh(context)
|
|
10
|
+
|
|
11
|
+
const params = new URLSearchParams()
|
|
12
|
+
params.set('store', store.magentoStoreCode)
|
|
13
|
+
|
|
14
|
+
if (privateContext) {
|
|
15
|
+
Object.entries(privateContext).forEach(([key, value]) => {
|
|
16
|
+
if (Array.isArray(value))
|
|
17
|
+
value.forEach((v) => {
|
|
18
|
+
if (v) params.append(key, v)
|
|
19
|
+
})
|
|
20
|
+
else if (typeof value === 'string') params.set(key, value)
|
|
21
|
+
else if (typeof value === 'boolean') params.set(key, value.toString())
|
|
22
|
+
})
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const id = 'uid' in root ? root.uid : root.id
|
|
26
|
+
return `${id}?${params.toString()}`
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const resolvers: Resolvers = {
|
|
30
|
+
...Object.fromEntries(
|
|
31
|
+
fragments.possibleTypes.ProductInterface.map((type) => [type, { uid: scopedUid }]),
|
|
32
|
+
),
|
|
33
|
+
}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@graphcommerce/magento-graphql",
|
|
3
3
|
"homepage": "https://www.graphcommerce.org/",
|
|
4
4
|
"repository": "github:graphcommerce-org/graphcommerce",
|
|
5
|
-
"version": "9.1.0-canary.
|
|
5
|
+
"version": "9.1.0-canary.51",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"main": "index.ts",
|
|
8
8
|
"prettier": "@graphcommerce/prettier-config-pwa",
|
|
@@ -13,10 +13,10 @@
|
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
15
|
"peerDependencies": {
|
|
16
|
-
"@graphcommerce/eslint-config-pwa": "^9.1.0-canary.
|
|
17
|
-
"@graphcommerce/graphql": "^9.1.0-canary.
|
|
18
|
-
"@graphcommerce/prettier-config-pwa": "^9.1.0-canary.
|
|
19
|
-
"@graphcommerce/typescript-config-pwa": "^9.1.0-canary.
|
|
16
|
+
"@graphcommerce/eslint-config-pwa": "^9.1.0-canary.51",
|
|
17
|
+
"@graphcommerce/graphql": "^9.1.0-canary.51",
|
|
18
|
+
"@graphcommerce/prettier-config-pwa": "^9.1.0-canary.51",
|
|
19
|
+
"@graphcommerce/typescript-config-pwa": "^9.1.0-canary.51",
|
|
20
20
|
"graphql": "^16.0.0",
|
|
21
21
|
"next": "*",
|
|
22
22
|
"react": "^18.2.0",
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
dataIdFromObject as baseDataIdFromObject,
|
|
3
|
-
graphqlConfig as graphqlConfigType,
|
|
4
|
-
} from '@graphcommerce/graphql'
|
|
1
|
+
import type { graphqlConfig as graphqlConfigType } from '@graphcommerce/graphql'
|
|
5
2
|
import type { FunctionPlugin, PluginConfig } from '@graphcommerce/next-config'
|
|
6
|
-
import {
|
|
3
|
+
import { magentoTypePolicies } from '../typePolicies'
|
|
7
4
|
|
|
8
5
|
export const config: PluginConfig = {
|
|
9
6
|
type: 'function',
|
|
@@ -14,12 +11,3 @@ export const graphqlConfig: FunctionPlugin<typeof graphqlConfigType> = (prev, co
|
|
|
14
11
|
const results = prev(conf)
|
|
15
12
|
return { ...results, policies: [magentoTypePolicies, ...results.policies] }
|
|
16
13
|
}
|
|
17
|
-
|
|
18
|
-
export const dataIdFromObject: FunctionPlugin<typeof baseDataIdFromObject> = (
|
|
19
|
-
prev,
|
|
20
|
-
object,
|
|
21
|
-
context,
|
|
22
|
-
) => {
|
|
23
|
-
const results = prev(object, context)
|
|
24
|
-
return results ?? magentoDataIdFromObject(object, context)
|
|
25
|
-
}
|
|
@@ -18,6 +18,7 @@ export const meshConfig: FunctionPlugin<typeof meshConfigBase> = (
|
|
|
18
18
|
...(baseConfig.additionalResolvers ?? []),
|
|
19
19
|
'@graphcommerce/magento-graphql/mesh/customAttributeV2Resolver.ts',
|
|
20
20
|
'@graphcommerce/magento-graphql/mesh/attributeValueResolver.ts',
|
|
21
|
+
'@graphcommerce/magento-graphql/mesh/scopedUidResolver.ts',
|
|
21
22
|
],
|
|
22
23
|
},
|
|
23
24
|
graphCommerceConfig,
|
package/typePolicies.ts
CHANGED
|
@@ -1,24 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
globalApolloClient,
|
|
4
|
-
type TypedTypePolicies,
|
|
5
|
-
} from '@graphcommerce/graphql'
|
|
6
|
-
import type { KeyFieldsFunction } from '@apollo/client/cache/inmemory/policies'
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* This method automatically creates a typePolicy for all types that have a `uid` field. Secondly,
|
|
10
|
-
* it allows scoping of this value based on the current private context.
|
|
11
|
-
*/
|
|
12
|
-
export const magentoDataIdFromObject: KeyFieldsFunction = (object) => {
|
|
13
|
-
const { uid, __typename } = object
|
|
14
|
-
const client = globalApolloClient.current
|
|
15
|
-
|
|
16
|
-
if (!uid || !__typename || typeof uid !== 'string' || !client?.cache) return ''
|
|
17
|
-
|
|
18
|
-
const ctx = getPrivateQueryContext(client)
|
|
19
|
-
const queryContext = ctx ? `@(${JSON.stringify(ctx)})` : ''
|
|
20
|
-
return `${__typename}:${uid}${queryContext}`
|
|
21
|
-
}
|
|
1
|
+
import type { TypedTypePolicies } from '@graphcommerce/graphql'
|
|
2
|
+
import fragments from '@graphcommerce/graphql/generated/fragments.json'
|
|
22
3
|
|
|
23
4
|
/**
|
|
24
5
|
* By default we don't need to do anything for types with an `id` or without anything to identify.
|
|
@@ -51,8 +32,8 @@ export const magentoTypePolicies: TypedTypePolicies = {
|
|
|
51
32
|
// BundleCartItem: { keyFields: ['uid'] },
|
|
52
33
|
// BundleCreditMemoItem: { keyFields: ['id'] },
|
|
53
34
|
// BundleInvoiceItem: { keyFields: ['id'] },
|
|
54
|
-
|
|
55
|
-
|
|
35
|
+
BundleItem: { keyFields: ['uid'] },
|
|
36
|
+
BundleItemOption: { keyFields: ['uid'] },
|
|
56
37
|
// BundleOrderItem: { keyFields: ['id'] },
|
|
57
38
|
// BundleProduct: { keyFields: ['uid'] },
|
|
58
39
|
// BundleShipmentItem: { keyFields: ['id'] },
|
|
@@ -63,6 +44,7 @@ export const magentoTypePolicies: TypedTypePolicies = {
|
|
|
63
44
|
// CartAddressRegion: { keyFields: false },
|
|
64
45
|
// CartDiscount: { keyFields: false },
|
|
65
46
|
// CartItemInterface: { keyFields: ['uid'] },
|
|
47
|
+
...Object.fromEntries(fragments.possibleTypes.CartItemInterface.map((type) => [type, ['uid']])),
|
|
66
48
|
// CartItemPrices: { keyFields: false },
|
|
67
49
|
CartItemQuantity: { keyFields: ['cart_item_id'] },
|
|
68
50
|
// CartItemSelectedOptionValuePrice: { keyFields: false },
|
|
@@ -70,6 +52,7 @@ export const magentoTypePolicies: TypedTypePolicies = {
|
|
|
70
52
|
// CartTaxItem: { keyFields: false },
|
|
71
53
|
// CartUserInputError: { keyFields: false },
|
|
72
54
|
// CategoryInterface: { keyFields: ['uid'] },
|
|
55
|
+
...Object.fromEntries(fragments.possibleTypes.CategoryInterface.map((type) => [type, ['uid']])),
|
|
73
56
|
// CategoryProducts: { keyFields: false },
|
|
74
57
|
// CategoryResult: { keyFields: false },
|
|
75
58
|
// CategoryTree: { keyFields: ['uid'] },
|
|
@@ -80,12 +63,13 @@ export const magentoTypePolicies: TypedTypePolicies = {
|
|
|
80
63
|
CmsPage: { keyFields: ['identifier'] },
|
|
81
64
|
// ColorSwatchData: { keyFields: false },
|
|
82
65
|
// ComparableAttribute: { keyFields: false },
|
|
83
|
-
|
|
84
|
-
|
|
66
|
+
ComparableItem: { keyFields: ['uid'] },
|
|
67
|
+
CompareList: { keyFields: ['uid'] },
|
|
85
68
|
// ComplexTextValue: { keyFields: false },
|
|
86
|
-
|
|
69
|
+
ConfigurableAttributeOption: { keyFields: ['uid'] },
|
|
87
70
|
// ConfigurableCartItem: { keyFields: ['uid'] },
|
|
88
71
|
// ConfigurableOptionAvailableForSelection: { keyFields: false },
|
|
72
|
+
// ConfigurableProduct: { keyFields: ['uid'] },
|
|
89
73
|
// ConfigurableProductOptions: { keyFields: ['uid'] },
|
|
90
74
|
// ConfigurableProductOptionsSelection: { keyFields: false },
|
|
91
75
|
// ConfigurableProductOptionsValues: { keyFields: ['uid'] },
|
|
@@ -102,9 +86,7 @@ export const magentoTypePolicies: TypedTypePolicies = {
|
|
|
102
86
|
// CustomAttributeMetadata: { keyFields: [] },
|
|
103
87
|
Customer: {
|
|
104
88
|
keyFields: [],
|
|
105
|
-
fields: {
|
|
106
|
-
custom_attributes: { merge: (_, incoming) => incoming },
|
|
107
|
-
},
|
|
89
|
+
fields: { custom_attributes: { merge: (_, incoming) => incoming } },
|
|
108
90
|
},
|
|
109
91
|
// CustomerAddress: { keyFields: ['id'] },
|
|
110
92
|
// CustomerAddressAttribute: { keyFields: false },
|
|
@@ -140,10 +122,10 @@ export const magentoTypePolicies: TypedTypePolicies = {
|
|
|
140
122
|
// DownloadableCartItem: { keyFields: ['uid'] },
|
|
141
123
|
// DownloadableCreditMemoItem: { keyFields: ['id'] },
|
|
142
124
|
// DownloadableInvoiceItem: { keyFields: ['id'] },
|
|
143
|
-
|
|
125
|
+
DownloadableItemsLinks: { keyFields: ['uid'] },
|
|
144
126
|
// DownloadableOrderItem: { keyFields: ['id'] },
|
|
145
127
|
// DownloadableProduct: { keyFields: ['uid'] },
|
|
146
|
-
|
|
128
|
+
DownloadableProductLinks: { keyFields: ['uid'] },
|
|
147
129
|
// DownloadableProductSamples: { keyFields: ['id'] },
|
|
148
130
|
// DownloadableWishlistItem: { keyFields: ['id'] },
|
|
149
131
|
// EntityUrl: { keyFields: ['id'] },
|
|
@@ -168,7 +150,7 @@ export const magentoTypePolicies: TypedTypePolicies = {
|
|
|
168
150
|
// LayerFilter: { keyFields: false },
|
|
169
151
|
// LayerFilterItem: { keyFields: false },
|
|
170
152
|
// LayerFilterItemInterface: { keyFields: false },
|
|
171
|
-
|
|
153
|
+
MediaGalleryEntry: { keyFields: ['uid'] },
|
|
172
154
|
// MediaGalleryInterface: { keyFields: false },
|
|
173
155
|
// Money: { keyFields: false },
|
|
174
156
|
Order: { keyFields: ['order_number'] },
|
|
@@ -196,7 +178,8 @@ export const magentoTypePolicies: TypedTypePolicies = {
|
|
|
196
178
|
// ProductAttribute: { keyFields: false },
|
|
197
179
|
// ProductDiscount: { keyFields: false },
|
|
198
180
|
// ProductImage: { keyFields: false },
|
|
199
|
-
// ProductInterface: { keyFields: ['uid'] },
|
|
181
|
+
// ProductInterface: { keyFields: ['uid'] },
|
|
182
|
+
...Object.fromEntries(fragments.possibleTypes.ProductInterface.map((type) => [type, ['uid']])),
|
|
200
183
|
// ProductLinks: { keyFields: false },
|
|
201
184
|
// ProductLinksInterface: { keyFields: false },
|
|
202
185
|
// ProductMediaGalleryEntriesContent: { keyFields: false },
|