@graphcommerce/graphql 10.0.0-canary.68 → 10.0.0
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 +116 -0
- package/__playwright__/apolloClient.fixture.ts +5 -4
- package/apollo.ts +24 -3
- package/components/GraphQLProvider/GraphQLProvider.tsx +10 -6
- package/components/GraphQLProvider/createCacheReviver.ts +4 -4
- package/components/GraphQLProvider/errorLink.ts +9 -8
- package/components/GraphQLProvider/measurePerformanceLink.ts +76 -71
- package/components/GraphQLProvider/migrateCache.ts +4 -7
- package/components/GraphQLProvider/persistenceMapper.ts +1 -1
- package/components/GraphQLProvider/typePolicies.ts +0 -1
- package/hooks/usePrivateQuery.ts +5 -5
- package/hooks/usePrivateQueryContext.ts +1 -1
- package/link/RemovePrivateContextDirectivesLink.ts +32 -3
- package/package.json +15 -12
- package/rxjs.ts +1 -0
- package/utils/cachePolicy.ts +2 -5
- package/utils/getPreviewData.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,121 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 10.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- [#2546](https://github.com/graphcommerce-org/graphcommerce/pull/2546) [`ed9332a`](https://github.com/graphcommerce-org/graphcommerce/commit/ed9332a7f78966d932041d9a7725641edc92b28d) - ## GraphCommerce 10 - Turbopack Support
|
|
8
|
+
|
|
9
|
+
This major release brings full Turbopack compatibility, dramatically improving development speed.
|
|
10
|
+
|
|
11
|
+
### 🚀 Turbopack-Compatible Interceptor System
|
|
12
|
+
|
|
13
|
+
The entire plugin/interceptor system has been rewritten to work with Turbopack:
|
|
14
|
+
|
|
15
|
+
- **No more Webpack plugins** - Removed `InterceptorPlugin` webpack plugin entirely
|
|
16
|
+
- **File-based interception** - Original files are moved to `.original.tsx` and replaced with interceptor content
|
|
17
|
+
- **Direct imports** - Interceptors import from `.original` files instead of embedding source
|
|
18
|
+
- **New CLI commands**:
|
|
19
|
+
- `graphcommerce codegen-interceptors` - Generate interceptor files
|
|
20
|
+
- `graphcommerce cleanup-interceptors` - Reset interceptor system, restore original files
|
|
21
|
+
- **Stable file hashing** - Deterministic interceptor generation for better caching
|
|
22
|
+
|
|
23
|
+
### ⚙️ Treeshakable Configuration System
|
|
24
|
+
|
|
25
|
+
Replaced Webpack `DefinePlugin`-based `import.meta.graphCommerce` with a new generated configuration system:
|
|
26
|
+
|
|
27
|
+
- **New `codegen-config-values` command** - Generates TypeScript files with precise typing
|
|
28
|
+
- **Schema-driven** - Dynamically introspects Zod schemas to determine all available properties
|
|
29
|
+
- **Fully treeshakable** - Unused config values are eliminated from the bundle
|
|
30
|
+
- **Type-safe** - Uses `Get<GraphCommerceConfig, 'path'>` for nested property access
|
|
31
|
+
- **Separate files for nested objects** - Optimal treeshaking for complex configurations
|
|
32
|
+
|
|
33
|
+
### 🔧 withGraphCommerce Changes
|
|
34
|
+
|
|
35
|
+
- **Removed** `InterceptorPlugin` - No longer needed with file-based interception
|
|
36
|
+
- **Removed** `DefinePlugin` for `import.meta.graphCommerce` - Replaced with generated config
|
|
37
|
+
- **Removed** `@mui/*` alias rewrites - No longer required
|
|
38
|
+
- **Added** Turbopack loader rules for `.yaml`, `.yml`, and `.po` files
|
|
39
|
+
- **Added** `serverExternalPackages` for all `@whatwg-node/*` packages
|
|
40
|
+
- **Added** `optimizePackageImports` for better bundle optimization
|
|
41
|
+
- **Added** `images.qualities: [52, 75]` for Next.js image optimization
|
|
42
|
+
|
|
43
|
+
### 📦 Lingui Configuration
|
|
44
|
+
|
|
45
|
+
- **Renamed** `lingui.config.js` → `lingui.config.ts` with TypeScript support
|
|
46
|
+
- **Updated** `@graphcommerce/lingui-next/config` to TypeScript with proper exports
|
|
47
|
+
- **Simplified** formatter options
|
|
48
|
+
|
|
49
|
+
### ⚛️ React 19 & Next.js 16 Compatibility
|
|
50
|
+
|
|
51
|
+
- Updated `RefObject<T>` types for React 19 (now includes `null` by default)
|
|
52
|
+
- Replaced deprecated `React.VFC` with `React.FC`
|
|
53
|
+
- Fixed `useRef` calls to require explicit initial values
|
|
54
|
+
- Updated `MutableRefObject` usage in `framer-scroller`
|
|
55
|
+
|
|
56
|
+
### 📋 ESLint 9 Flat Config
|
|
57
|
+
|
|
58
|
+
- Migrated from legacy `.eslintrc` to new flat config format (`eslint.config.mjs`)
|
|
59
|
+
- Updated `@typescript-eslint/*` packages to v8
|
|
60
|
+
- Fixed AST selector for `SxProps` rule (`typeParameters` → `typeArguments`)
|
|
61
|
+
|
|
62
|
+
### 🔄 Apollo Client
|
|
63
|
+
|
|
64
|
+
- Fixed deprecated `name` option → `clientAwareness: { name: 'ssr' }`
|
|
65
|
+
- Updated error handling types to accept `ApolloError | null | undefined`
|
|
66
|
+
|
|
67
|
+
### ⚠️ Breaking Changes
|
|
68
|
+
|
|
69
|
+
- **Node.js 24.x not supported** - Restricted to `>=20 <24.0.0` due to [nodejs/undici#4290](https://github.com/nodejs/undici/issues/4290)
|
|
70
|
+
- **Interceptor files changed** - Original components now at `.original.tsx`
|
|
71
|
+
- **Config access changed** - Use generated config values instead of `import.meta.graphCommerce`
|
|
72
|
+
- **ESLint config format** - Must use flat config (`eslint.config.mjs`)
|
|
73
|
+
- **Lingui config** - Rename `lingui.config.js` to `lingui.config.ts`
|
|
74
|
+
|
|
75
|
+
### 🗑️ Removed
|
|
76
|
+
|
|
77
|
+
- `InterceptorPlugin` webpack plugin
|
|
78
|
+
- `configToImportMeta` utility
|
|
79
|
+
- Webpack `DefinePlugin` usage for config
|
|
80
|
+
- `@mui/*` modern alias rewrites
|
|
81
|
+
- Debug plugins (`CircularDependencyPlugin`, `DuplicatesPlugin`) ([@paales](https://github.com/paales))
|
|
82
|
+
|
|
83
|
+
- [#2565](https://github.com/graphcommerce-org/graphcommerce/pull/2565) [`c96dfcd`](https://github.com/graphcommerce-org/graphcommerce/commit/c96dfcdca981baca387c270ad9e2b9515cdd00cc) - Updated to Apollo Client 4 ([@paales](https://github.com/paales))
|
|
84
|
+
|
|
85
|
+
### Minor Changes
|
|
86
|
+
|
|
87
|
+
- [#2537](https://github.com/graphcommerce-org/graphcommerce/pull/2537) [`958dcb6`](https://github.com/graphcommerce-org/graphcommerce/commit/958dcb62d5abb3427a38e2a4583897f3e2043cc4) - Introduce 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.
|
|
88
|
+
|
|
89
|
+
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.
|
|
90
|
+
|
|
91
|
+
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))
|
|
92
|
+
|
|
93
|
+
### Patch Changes
|
|
94
|
+
|
|
95
|
+
- [#2528](https://github.com/graphcommerce-org/graphcommerce/pull/2528) [`c52604f`](https://github.com/graphcommerce-org/graphcommerce/commit/c52604f89e1776fc1f0913f016b8b24fa194c6b7) - Solve issue where the persistenceMapper didn't use the same typePolicies and other configuration from the cache, causing potential issues. ([@paales](https://github.com/paales))
|
|
96
|
+
|
|
97
|
+
- [#2496](https://github.com/graphcommerce-org/graphcommerce/pull/2496) [`a261149`](https://github.com/graphcommerce-org/graphcommerce/commit/a261149b6b32ad6a35606da2d530b8e41bfa10a0) - ReCaptcha now using the `recaptchaV3Config` query and add a fallback for Magento 2.4.6 and earlier to still use the configuration. Magento 2.4.7 doesn't need that configuration anymore. ([@paales](https://github.com/paales))
|
|
98
|
+
|
|
99
|
+
- [#2525](https://github.com/graphcommerce-org/graphcommerce/pull/2525) [`e1e132d`](https://github.com/graphcommerce-org/graphcommerce/commit/e1e132d076fbc6b3a081a245e51cb2bc91b0c707) - usePrivateQuery now disables masking when an error occurs. ([@paales](https://github.com/paales))
|
|
100
|
+
|
|
101
|
+
- [#2528](https://github.com/graphcommerce-org/graphcommerce/pull/2528) [`529d7a8`](https://github.com/graphcommerce-org/graphcommerce/commit/529d7a88a4e010cb3e50c1358e2ac43e80e0bf38) - Solve issue where the ApolloClient cache wasn't scoped properly causing the wrong currency to be shown when switching currency. ([@paales](https://github.com/paales))
|
|
102
|
+
|
|
103
|
+
- [`62b71d5`](https://github.com/graphcommerce-org/graphcommerce/commit/62b71d5ed1d482fdb5b76dc19ac4d55fc41fb191) - Solve issue: TypeError: InMemoryLRUCache is not a constructor ([@paales](https://github.com/paales))
|
|
104
|
+
|
|
105
|
+
- [#2477](https://github.com/graphcommerce-org/graphcommerce/pull/2477) [`8015eab`](https://github.com/graphcommerce-org/graphcommerce/commit/8015eabc130dacf1f2703980cd5f0ad2c550aa4d) - Upgraded to @apollo/client 3.12.3 without impacting typescript compilation performance. ([@paales](https://github.com/paales))
|
|
106
|
+
|
|
107
|
+
## 10.0.0-canary.72
|
|
108
|
+
|
|
109
|
+
## 10.0.0-canary.71
|
|
110
|
+
|
|
111
|
+
## 10.0.0-canary.70
|
|
112
|
+
|
|
113
|
+
### Major Changes
|
|
114
|
+
|
|
115
|
+
- [#2565](https://github.com/graphcommerce-org/graphcommerce/pull/2565) [`c96dfcd`](https://github.com/graphcommerce-org/graphcommerce/commit/c96dfcdca981baca387c270ad9e2b9515cdd00cc) - Updated to Apollo Client 4 ([@paales](https://github.com/paales))
|
|
116
|
+
|
|
117
|
+
## 10.0.0-canary.69
|
|
118
|
+
|
|
3
119
|
## 10.0.0-canary.68
|
|
4
120
|
|
|
5
121
|
## 10.0.0-canary.67
|
|
@@ -3,28 +3,29 @@
|
|
|
3
3
|
/* eslint-disable no-empty-pattern */
|
|
4
4
|
import type { Page } from '@playwright/test'
|
|
5
5
|
import { test as base } from '@playwright/test'
|
|
6
|
-
import type {
|
|
6
|
+
import type { ApolloLink, TypedDocumentNode } from '../apollo'
|
|
7
7
|
import { ApolloClient, getOperationName, InMemoryCache } from '../apollo'
|
|
8
8
|
|
|
9
9
|
type ApolloClientTest = {
|
|
10
|
-
apolloClient: ApolloClient
|
|
10
|
+
apolloClient: ApolloClient
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export async function waitForGraphQlResponse<Q, V>(
|
|
14
14
|
page: Page,
|
|
15
15
|
docOrName: string | TypedDocumentNode<Q, V>,
|
|
16
|
-
): Promise<
|
|
16
|
+
): Promise<ApolloLink.Result<Q>> {
|
|
17
17
|
const name = typeof docOrName === 'string' ? docOrName : getOperationName(docOrName)
|
|
18
18
|
|
|
19
19
|
const response = await page.waitForResponse((r) => {
|
|
20
20
|
try {
|
|
21
21
|
return r.request().postDataJSON()?.operationName === name
|
|
22
22
|
} catch (e) {
|
|
23
|
+
console.error(e)
|
|
23
24
|
return false
|
|
24
25
|
}
|
|
25
26
|
})
|
|
26
27
|
|
|
27
|
-
return (await response?.json()) as
|
|
28
|
+
return (await response?.json()) as ApolloLink.Result<Q>
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
/** @public */
|
package/apollo.ts
CHANGED
|
@@ -1,13 +1,34 @@
|
|
|
1
|
-
export { cloneDeep, mergeDeep } from '@apollo/client/utilities'
|
|
1
|
+
export { cloneDeep, mergeDeep, getOperationName } from '@apollo/client/utilities/internal'
|
|
2
2
|
|
|
3
|
+
// Core Apollo Client exports
|
|
3
4
|
export * from '@apollo/client'
|
|
5
|
+
|
|
6
|
+
// React hooks - exported explicitly
|
|
7
|
+
export {
|
|
8
|
+
ApolloProvider,
|
|
9
|
+
useApolloClient,
|
|
10
|
+
useQuery,
|
|
11
|
+
useLazyQuery,
|
|
12
|
+
useMutation,
|
|
13
|
+
useSubscription,
|
|
14
|
+
useFragment,
|
|
15
|
+
useSuspenseQuery,
|
|
16
|
+
useBackgroundQuery,
|
|
17
|
+
useReadQuery,
|
|
18
|
+
useLoadableQuery,
|
|
19
|
+
useSuspenseFragment,
|
|
20
|
+
useQueryRefHandlers,
|
|
21
|
+
useReactiveVar,
|
|
22
|
+
skipToken,
|
|
23
|
+
getApolloContext,
|
|
24
|
+
createQueryPreloader,
|
|
25
|
+
} from '@apollo/client/react'
|
|
26
|
+
|
|
4
27
|
export * from '@apollo/client/link/schema'
|
|
5
28
|
export * from '@apollo/client/link/context'
|
|
6
29
|
export * from '@apollo/client/link/error'
|
|
7
30
|
export * from '@apollo/client/utilities'
|
|
8
31
|
|
|
9
|
-
export { getOperationName } from '@apollo/client/utilities'
|
|
10
|
-
|
|
11
32
|
declare module '@apollo/client' {
|
|
12
33
|
interface DataMasking {
|
|
13
34
|
enabled: true
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
2
2
|
import { useStorefrontConfig } from '@graphcommerce/next-ui/hooks/useStorefrontConfig'
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
3
|
+
import { ApolloClient, ApolloLink, HttpLink, InMemoryCache } from '@apollo/client'
|
|
4
|
+
import type { NormalizedCacheObject } from '@apollo/client'
|
|
5
|
+
import { LocalState } from '@apollo/client/local-state'
|
|
6
|
+
import { ApolloProvider } from '@apollo/client/react'
|
|
5
7
|
import type { AppProps } from 'next/app'
|
|
6
8
|
import { useCallback, useEffect, useRef, useState } from 'react'
|
|
7
9
|
import type { ApolloClientConfig, ApolloClientConfigInput, PreviewConfig } from '../../config'
|
|
@@ -12,7 +14,7 @@ import { errorLink } from './errorLink'
|
|
|
12
14
|
import { measurePerformanceLink } from './measurePerformanceLink'
|
|
13
15
|
import { mergeTypePolicies } from './typePolicies'
|
|
14
16
|
|
|
15
|
-
export const globalApolloClient: { current: ApolloClient
|
|
17
|
+
export const globalApolloClient: { current: ApolloClient | null } = {
|
|
16
18
|
current: null,
|
|
17
19
|
}
|
|
18
20
|
|
|
@@ -27,7 +29,7 @@ export type GraphQLProviderProps = AppProps &
|
|
|
27
29
|
*/
|
|
28
30
|
export function GraphQLProvider(props: GraphQLProviderProps) {
|
|
29
31
|
const { children, links, migrations, policies, pageProps, router } = props
|
|
30
|
-
const state = (pageProps as { apolloState?:
|
|
32
|
+
const state = (pageProps as { apolloState?: unknown }).apolloState
|
|
31
33
|
|
|
32
34
|
const stateRef = useRef(state)
|
|
33
35
|
|
|
@@ -60,7 +62,7 @@ export function GraphQLProvider(props: GraphQLProviderProps) {
|
|
|
60
62
|
])
|
|
61
63
|
|
|
62
64
|
const cache = createCache()
|
|
63
|
-
if (stateRef.current) cache.restore(stateRef.current)
|
|
65
|
+
if (stateRef.current) cache.restore(stateRef.current as unknown as NormalizedCacheObject)
|
|
64
66
|
|
|
65
67
|
const ssrMode = typeof window === 'undefined'
|
|
66
68
|
return new ApolloClient({
|
|
@@ -68,11 +70,13 @@ export function GraphQLProvider(props: GraphQLProviderProps) {
|
|
|
68
70
|
cache,
|
|
69
71
|
clientAwareness: { name: 'web' },
|
|
70
72
|
ssrMode,
|
|
73
|
+
|
|
71
74
|
defaultOptions: {
|
|
72
75
|
preview: {
|
|
73
76
|
preview: router.isPreview,
|
|
74
77
|
} as PreviewConfig,
|
|
75
|
-
} as DefaultOptions,
|
|
78
|
+
} as ApolloClient.DefaultOptions,
|
|
79
|
+
localState: new LocalState({}),
|
|
76
80
|
})
|
|
77
81
|
})
|
|
78
82
|
|
|
@@ -9,14 +9,14 @@ import { getTypePoliciesVersion } from './typePolicies'
|
|
|
9
9
|
const APOLLO_CACHE_PERSIST = 'apollo-cache-persist'
|
|
10
10
|
const APOLLO_CACHE_VERSION = 'apollo-cache-version'
|
|
11
11
|
|
|
12
|
-
let persistor: CachePersistor<
|
|
12
|
+
let persistor: CachePersistor<unknown> | null = null
|
|
13
13
|
|
|
14
14
|
/** Revives the cache from the localStorage if it is available. */
|
|
15
15
|
export async function createCacheReviver(
|
|
16
|
-
client: ApolloClient
|
|
17
|
-
createCache: () => ApolloCache
|
|
16
|
+
client: ApolloClient,
|
|
17
|
+
createCache: () => ApolloCache,
|
|
18
18
|
config: ApolloClientConfig,
|
|
19
|
-
incomingState:
|
|
19
|
+
incomingState: unknown = {},
|
|
20
20
|
) {
|
|
21
21
|
let state = incomingState
|
|
22
22
|
const typePoliciesVersion = getTypePoliciesVersion(config.policies)
|
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CombinedGraphQLErrors } from '@apollo/client/errors'
|
|
2
|
+
import { ErrorLink } from '@apollo/client/link/error'
|
|
2
3
|
|
|
3
|
-
export const errorLink =
|
|
4
|
-
if (
|
|
4
|
+
export const errorLink = new ErrorLink(({ error, operation }) => {
|
|
5
|
+
if (CombinedGraphQLErrors.is(error)) {
|
|
5
6
|
console.error(
|
|
6
|
-
`[GraphQL errors]: ${
|
|
7
|
+
`[GraphQL errors]: ${error.errors
|
|
7
8
|
.map(({ message, path }) => `${message} ${path?.join(',')}`)
|
|
8
9
|
.join(', ')}`,
|
|
9
10
|
)
|
|
11
|
+
} else if (error) {
|
|
12
|
+
console.error(`[Graphql error]: ${error}`)
|
|
13
|
+
}
|
|
10
14
|
|
|
11
|
-
|
|
12
|
-
console.error(`[Graphql error]: ${networkError}`)
|
|
13
|
-
|
|
14
|
-
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
15
16
|
;(async () => {
|
|
16
17
|
const graphql = await import('graphql')
|
|
17
18
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
2
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
3
|
+
import { map } from '@graphcommerce/graphql/rxjs'
|
|
3
4
|
import { canonicalBaseUrl } from '@graphcommerce/next-config/config'
|
|
4
5
|
import { ApolloLink } from '@apollo/client'
|
|
5
6
|
import { print } from '@apollo/client/utilities'
|
|
6
7
|
import type { MeshFetchHTTPInformation } from '@graphql-mesh/plugin-http-details-extensions'
|
|
7
8
|
import { responsePathAsArray, stripIgnoredCharacters } from 'graphql'
|
|
8
|
-
import { cliHyperlink } from '../../lib/hyperlinker'
|
|
9
9
|
|
|
10
10
|
const running = new Map<
|
|
11
11
|
string,
|
|
@@ -147,88 +147,93 @@ export const measurePerformanceLink = new ApolloLink((operation, forward) => {
|
|
|
147
147
|
operation.setContext({ measurePerformanceLinkStart: new Date() })
|
|
148
148
|
const vars =
|
|
149
149
|
Object.keys(operation.variables).length > 0 ? `(${JSON.stringify(operation.variables)})` : ''
|
|
150
|
-
const operationString = `${operation.operationName}${vars}`
|
|
150
|
+
const operationString = `${operation.operationName ?? 'anonymous'}${vars}`
|
|
151
151
|
|
|
152
152
|
running.set(operationString, {
|
|
153
153
|
start: new Date(),
|
|
154
|
-
operationName: [
|
|
154
|
+
operationName: [
|
|
155
|
+
operation.operationName ?? 'anonymous',
|
|
156
|
+
operation.operationName ?? 'anonymous',
|
|
157
|
+
],
|
|
155
158
|
})
|
|
156
159
|
markTimeout()
|
|
157
160
|
|
|
158
|
-
return forward(operation).
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
if (httpDetails) {
|
|
192
|
-
running.forEach((_, key) => {
|
|
193
|
-
if (key.startsWith(operationString)) running.delete(key)
|
|
161
|
+
return forward(operation).pipe(
|
|
162
|
+
map((data) => {
|
|
163
|
+
const httpDetails: MeshFetchHTTPInformation[] | undefined = data.extensions?.httpDetails
|
|
164
|
+
|
|
165
|
+
const additional = ['', ''] as [string, string]
|
|
166
|
+
|
|
167
|
+
// Called after server responds
|
|
168
|
+
const query = [
|
|
169
|
+
`# Variables: ${JSON.stringify(operation.variables)}`,
|
|
170
|
+
`# Headers: ${JSON.stringify(operation.getContext().headers)}`,
|
|
171
|
+
stripIgnoredCharacters(print(operation.query)),
|
|
172
|
+
].join('\n')
|
|
173
|
+
|
|
174
|
+
const meshUrl = new URL(
|
|
175
|
+
process.env.NODE_ENV === 'production'
|
|
176
|
+
? `${canonicalBaseUrl}/api/graphql`
|
|
177
|
+
: 'http://localhost:3000/api/graphql',
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
meshUrl.searchParams.set('query', query)
|
|
181
|
+
|
|
182
|
+
running.delete(operationString)
|
|
183
|
+
running.set(operationString, {
|
|
184
|
+
start: operation.getContext().measurePerformanceLinkStart as Date,
|
|
185
|
+
end: new Date(),
|
|
186
|
+
operationName: [
|
|
187
|
+
operation.operationName ?? 'anonymous',
|
|
188
|
+
operation.operationName ?? 'anonymous',
|
|
189
|
+
// cliHyperlink(operation.operationName, meshUrl.toString()),
|
|
190
|
+
],
|
|
191
|
+
additional,
|
|
192
|
+
idx: 0,
|
|
194
193
|
})
|
|
195
194
|
|
|
196
|
-
httpDetails
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
195
|
+
if (httpDetails) {
|
|
196
|
+
running.forEach((_, key) => {
|
|
197
|
+
if (key.startsWith(operationString)) running.delete(key)
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
httpDetails.forEach((d) => {
|
|
201
|
+
const requestUrl = new URL(d.request.url)
|
|
202
|
+
requestUrl.searchParams.delete('extensions')
|
|
203
|
+
|
|
204
|
+
const sourceName =
|
|
205
|
+
!d.sourceName && URL.canParse(d.request.url)
|
|
206
|
+
? new URL(d.request.url).hostname
|
|
207
|
+
: d.sourceName
|
|
208
|
+
|
|
209
|
+
const key = `${operationString}.${responsePathAsArray(d.path).join('.')}`
|
|
210
|
+
const name = `${operation.operationName ?? 'anonymous'}.${responsePathAsArray(d.path).join('.')} (${sourceName})`
|
|
211
|
+
|
|
212
|
+
let start = new Date(d.request.timestamp)
|
|
213
|
+
let end = new Date(d.response.timestamp)
|
|
214
|
+
let operationName: [string, string] = [name, name]
|
|
215
|
+
let idx = 0
|
|
216
|
+
|
|
217
|
+
if (running.has(key)) {
|
|
218
|
+
// Get the earliest start time and latest end time.
|
|
219
|
+
const existing = running.get(key)
|
|
220
|
+
if (existing) {
|
|
221
|
+
idx = (existing.idx ?? 0) + 1
|
|
222
|
+
start = existing.start < start ? existing.start : start
|
|
223
|
+
end = existing?.end ? (existing.end > end ? existing.end : end) : end
|
|
224
|
+
operationName = [`${name} ⨉ ${idx}`, `${name} ⨉ ${idx}`]
|
|
225
|
+
}
|
|
221
226
|
}
|
|
222
|
-
}
|
|
223
227
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
228
|
+
running.set(key, { start, end, operationName, idx })
|
|
229
|
+
})
|
|
230
|
+
}
|
|
227
231
|
|
|
228
|
-
|
|
232
|
+
markTimeout()
|
|
229
233
|
|
|
230
|
-
|
|
231
|
-
|
|
234
|
+
return data
|
|
235
|
+
}),
|
|
236
|
+
)
|
|
232
237
|
}
|
|
233
238
|
return forward(operation)
|
|
234
239
|
})
|
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
import type { ApolloCache
|
|
1
|
+
import type { ApolloCache } from '../../apollo'
|
|
2
2
|
|
|
3
|
-
export type MigrateCache = (
|
|
4
|
-
oldCache: ApolloCache<NormalizedCacheObject>,
|
|
5
|
-
newCache: ApolloCache<NormalizedCacheObject>,
|
|
6
|
-
) => void
|
|
3
|
+
export type MigrateCache = (oldCache: ApolloCache, newCache: ApolloCache) => void
|
|
7
4
|
|
|
8
5
|
export const migrateCacheHandler = (
|
|
9
|
-
oldCache: ApolloCache
|
|
10
|
-
newCache: ApolloCache
|
|
6
|
+
oldCache: ApolloCache,
|
|
7
|
+
newCache: ApolloCache,
|
|
11
8
|
migrations: MigrateCache[],
|
|
12
9
|
) => {
|
|
13
10
|
migrations.forEach((migration) => migration(oldCache, newCache))
|
|
@@ -22,7 +22,7 @@ function pruneCache(cacheObject: object, patterns: string[]) {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
export const createPersistenceMapper =
|
|
25
|
-
(createCache: () => ApolloCache
|
|
25
|
+
(createCache: () => ApolloCache) =>
|
|
26
26
|
(data: string): Promise<string> => {
|
|
27
27
|
const parsedCache = JSON.parse(data) as NormalizedCacheObject
|
|
28
28
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { StrictTypedTypePolicies } from '@graphcommerce/graphql'
|
|
2
|
-
import type { KeyFieldsFunction } from '@apollo/client/cache/inmemory/policies'
|
|
3
2
|
import { mergeDeep } from '../../apollo'
|
|
4
3
|
|
|
5
4
|
export const mergeTypePolicies = (policies: StrictTypedTypePolicies[]): StrictTypedTypePolicies =>
|
package/hooks/usePrivateQuery.ts
CHANGED
|
@@ -4,8 +4,8 @@ import { useIsSSR } from '@graphcommerce/next-ui/hooks/useIsSsr'
|
|
|
4
4
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
5
5
|
import { getCssFlag, removeCssFlag, setCssFlag } from '@graphcommerce/next-ui/utils/cssFlags'
|
|
6
6
|
import { useContext, useEffect } from 'react'
|
|
7
|
-
import type { MaybeMasked,
|
|
8
|
-
import { useQuery } from '../apollo'
|
|
7
|
+
import type { MaybeMasked, TypedDocumentNode, useQuery } from '../apollo'
|
|
8
|
+
import { useQuery as useQueryHook } from '../apollo'
|
|
9
9
|
import { PrivateQueryMaskContext } from '../components/PrivateQueryMask/PrivateQueryMask'
|
|
10
10
|
import { usePrivateQueryContext } from './usePrivateQueryContext'
|
|
11
11
|
|
|
@@ -30,9 +30,9 @@ export function usePrivateQuery<
|
|
|
30
30
|
V extends { context?: InputMaybe<PrivateContext>; [index: string]: unknown },
|
|
31
31
|
>(
|
|
32
32
|
document: TypedDocumentNode<Q, V>,
|
|
33
|
-
options:
|
|
33
|
+
options: useQuery.Options<Q, V>,
|
|
34
34
|
unscopedResult: Q,
|
|
35
|
-
): Omit<
|
|
35
|
+
): Omit<useQuery.Result<Q, V>, 'data'> & { data: Q | NonNullable<MaybeMasked<Q>>; mask: boolean } {
|
|
36
36
|
const { skip = true } = options
|
|
37
37
|
const context = usePrivateQueryContext()
|
|
38
38
|
const isSsr = useIsSSR()
|
|
@@ -45,7 +45,7 @@ export function usePrivateQuery<
|
|
|
45
45
|
else if (!context && getCssFlag('private-query')) removeCssFlag('private-query')
|
|
46
46
|
}, [context, isSsr])
|
|
47
47
|
|
|
48
|
-
const clientQuery =
|
|
48
|
+
const clientQuery = useQueryHook<Q, V>(document, {
|
|
49
49
|
...options,
|
|
50
50
|
variables: { ...options.variables, context } as V,
|
|
51
51
|
skip: !!privateContext || (skip && !context),
|
|
@@ -10,7 +10,7 @@ export function getPrivateQueryContextMesh(
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
/** Get the private context from the apollo client. */
|
|
13
|
-
export function getPrivateQueryContext(_client: ApolloClient
|
|
13
|
+
export function getPrivateQueryContext(_client: ApolloClient): PrivateContext | null {
|
|
14
14
|
return null
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -1,9 +1,38 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import {
|
|
1
|
+
import type { ApolloLink as ApolloLinkType } from '@apollo/client'
|
|
2
|
+
import { removeDirectivesFromDocument } from '@apollo/client/utilities/internal'
|
|
3
|
+
import type { DocumentNode } from 'graphql'
|
|
4
|
+
import { visit } from 'graphql'
|
|
5
|
+
import { ApolloLink } from '../apollo'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Remove arguments from a GraphQL document. This is a replacement for the removed
|
|
9
|
+
* removeArgumentsFromDocument from Apollo Client.
|
|
10
|
+
*/
|
|
11
|
+
function removeArgumentsFromDocument(
|
|
12
|
+
args: Array<{ name: string }>,
|
|
13
|
+
doc: DocumentNode,
|
|
14
|
+
): DocumentNode | null {
|
|
15
|
+
const argNames = new Set(args.map((a) => a.name))
|
|
16
|
+
|
|
17
|
+
return visit(doc, {
|
|
18
|
+
Argument(node) {
|
|
19
|
+
if (argNames.has(node.name.value)) {
|
|
20
|
+
return null
|
|
21
|
+
}
|
|
22
|
+
return undefined
|
|
23
|
+
},
|
|
24
|
+
VariableDefinition(node) {
|
|
25
|
+
if (argNames.has(node.variable.name.value)) {
|
|
26
|
+
return null
|
|
27
|
+
}
|
|
28
|
+
return undefined
|
|
29
|
+
},
|
|
30
|
+
})
|
|
31
|
+
}
|
|
3
32
|
|
|
4
33
|
export class RemovePrivateContextDirectivesLink extends ApolloLink {
|
|
5
34
|
// eslint-disable-next-line class-methods-use-this
|
|
6
|
-
request(operation: Operation, forward?:
|
|
35
|
+
request(operation: ApolloLinkType.Operation, forward?: ApolloLinkType.ForwardFunction) {
|
|
7
36
|
if (!forward) throw new Error('This is not a terminal link!')
|
|
8
37
|
|
|
9
38
|
let modifiedQuery = operation.query
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@graphcommerce/graphql",
|
|
3
3
|
"homepage": "https://www.graphcommerce.org/",
|
|
4
4
|
"repository": "github:graphcommerce-org/graphcommerce",
|
|
5
|
-
"version": "10.0.0
|
|
5
|
+
"version": "10.0.0",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"main": "index.ts",
|
|
8
8
|
"prettier": "@graphcommerce/prettier-config-pwa",
|
|
@@ -13,25 +13,27 @@
|
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@apollo/client": "^
|
|
16
|
+
"@apollo/client": "^4.0.11",
|
|
17
17
|
"@graphql-codegen/add": "6.0.0",
|
|
18
18
|
"@graphql-codegen/fragment-matcher": "6.0.0",
|
|
19
19
|
"@graphql-codegen/introspection": "5.0.0",
|
|
20
20
|
"@graphql-codegen/schema-ast": "5.0.0",
|
|
21
|
-
"@graphql-codegen/typed-document-node": "6.1.
|
|
22
|
-
"@graphql-codegen/typescript": "5.0.
|
|
21
|
+
"@graphql-codegen/typed-document-node": "6.1.5",
|
|
22
|
+
"@graphql-codegen/typescript": "5.0.7",
|
|
23
23
|
"@graphql-codegen/typescript-apollo-client-helpers": "3.0.1",
|
|
24
|
-
"@graphql-codegen/typescript-document-nodes": "5.0.
|
|
25
|
-
"@graphql-codegen/typescript-operations": "5.0.
|
|
24
|
+
"@graphql-codegen/typescript-document-nodes": "5.0.7",
|
|
25
|
+
"@graphql-codegen/typescript-operations": "5.0.7",
|
|
26
26
|
"apollo3-cache-persist": "^0.15.0",
|
|
27
|
-
"graphql": "^16.12.0"
|
|
27
|
+
"graphql": "^16.12.0",
|
|
28
|
+
"rxjs": "^7.8.2"
|
|
28
29
|
},
|
|
29
30
|
"peerDependencies": {
|
|
30
|
-
"@graphcommerce/eslint-config-pwa": "^10.0.0
|
|
31
|
-
"@graphcommerce/graphql-codegen-near-operation-file": "10.0.0
|
|
32
|
-
"@graphcommerce/graphql-codegen-relay-optimizer-plugin": "10.0.0
|
|
33
|
-
"@graphcommerce/
|
|
34
|
-
"@graphcommerce/
|
|
31
|
+
"@graphcommerce/eslint-config-pwa": "^10.0.0",
|
|
32
|
+
"@graphcommerce/graphql-codegen-near-operation-file": "10.0.0",
|
|
33
|
+
"@graphcommerce/graphql-codegen-relay-optimizer-plugin": "10.0.0",
|
|
34
|
+
"@graphcommerce/next-config": "^10.0.0",
|
|
35
|
+
"@graphcommerce/prettier-config-pwa": "^10.0.0",
|
|
36
|
+
"@graphcommerce/typescript-config-pwa": "^10.0.0",
|
|
35
37
|
"@graphql-mesh/plugin-http-details-extensions": "*",
|
|
36
38
|
"react": "^19.2.0",
|
|
37
39
|
"react-dom": "^19.2.0"
|
|
@@ -40,6 +42,7 @@
|
|
|
40
42
|
".": "./index.ts",
|
|
41
43
|
"./apollo": "./apollo.ts",
|
|
42
44
|
"./config": "./config.ts",
|
|
45
|
+
"./rxjs": "./rxjs.ts",
|
|
43
46
|
"./generated/fragments.json": "./generated/fragments.json"
|
|
44
47
|
}
|
|
45
48
|
}
|
package/rxjs.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from 'rxjs'
|
package/utils/cachePolicy.ts
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
import type { ApolloClient, FetchPolicy } from '@apollo/client'
|
|
2
2
|
import { getPreviewData } from './getPreviewData'
|
|
3
3
|
|
|
4
|
-
export function cachePolicy(
|
|
5
|
-
client: ApolloClient<object>,
|
|
6
|
-
requestedCachePolicy: FetchPolicy,
|
|
7
|
-
): FetchPolicy {
|
|
4
|
+
export function cachePolicy(client: ApolloClient, requestedCachePolicy: FetchPolicy): FetchPolicy {
|
|
8
5
|
return process.env.NODE_ENV !== 'development' && !getPreviewData(client)?.preview
|
|
9
6
|
? requestedCachePolicy
|
|
10
7
|
: 'network-only'
|
|
11
8
|
}
|
|
12
9
|
|
|
13
|
-
export function cacheFirst(client: ApolloClient
|
|
10
|
+
export function cacheFirst(client: ApolloClient) {
|
|
14
11
|
return cachePolicy(client, 'cache-first')
|
|
15
12
|
}
|
package/utils/getPreviewData.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ApolloClient } from '@apollo/client'
|
|
2
2
|
import type { PreviewConfig } from '../config'
|
|
3
3
|
|
|
4
|
-
export function getPreviewData(client: ApolloClient
|
|
4
|
+
export function getPreviewData(client: ApolloClient): PreviewConfig | undefined {
|
|
5
5
|
if ('preview' in client.defaultOptions) return client.defaultOptions.preview as PreviewConfig
|
|
6
6
|
return undefined
|
|
7
7
|
}
|