@graphcommerce/graphql 9.0.0-canary.114 → 9.0.0-canary.116

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
  # Change Log
2
2
 
3
+ ## 9.0.0-canary.116
4
+
5
+ ### Patch Changes
6
+
7
+ - [#2452](https://github.com/graphcommerce-org/graphcommerce/pull/2452) [`5dfd3b2`](https://github.com/graphcommerce-org/graphcommerce/commit/5dfd3b201255ef35263485d04153d37bb7e4fe67) - Renamed useInContextQuery to usePrivateQuery ([@paales](https://github.com/paales))
8
+
9
+ ## 9.0.0-canary.115
10
+
3
11
  ## 9.0.0-canary.114
4
12
 
5
13
  ## 9.0.0-canary.113
@@ -4,7 +4,7 @@
4
4
  import type { Page } from '@playwright/test'
5
5
  import { test as base } from '@playwright/test'
6
6
  import type { FetchResult, NormalizedCacheObject, TypedDocumentNode } from '../apollo'
7
- import { ApolloClient, InMemoryCache, getOperationName } from '../apollo'
7
+ import { ApolloClient, getOperationName, InMemoryCache } from '../apollo'
8
8
 
9
9
  type ApolloClientTest = {
10
10
  apolloClient: ApolloClient<NormalizedCacheObject>
@@ -27,7 +27,8 @@ export async function waitForGraphQlResponse<Q, V>(
27
27
  return (await response?.json()) as FetchResult<Q>
28
28
  }
29
29
 
30
- const test = base.extend<ApolloClientTest>({
30
+ /** @public */
31
+ export const test = base.extend<ApolloClientTest>({
31
32
  apolloClient: async ({}, use) => {
32
33
  const client = new ApolloClient({
33
34
  uri: 'http://localhost:3000/api/graphql',
@@ -37,5 +38,3 @@ const test = base.extend<ApolloClientTest>({
37
38
  await use(client)
38
39
  },
39
40
  })
40
-
41
- export { test }
@@ -7,7 +7,7 @@ import React, { createContext, useContext, useMemo } from 'react'
7
7
 
8
8
  type MaskProp = { skeleton?: SkeletonProps }
9
9
 
10
- interface InContextMaskTypeMap<
10
+ interface PrivateQueryMaskTypeMap<
11
11
  AdditionalProps = MaskProp,
12
12
  RootComponent extends React.ElementType = 'div',
13
13
  > {
@@ -15,19 +15,21 @@ interface InContextMaskTypeMap<
15
15
  defaultComponent: RootComponent
16
16
  }
17
17
 
18
- export type InContextMaskProps<
19
- RootComponent extends React.ElementType = InContextMaskTypeMap['defaultComponent'],
18
+ export type PrivateQueryMaskProps<
19
+ RootComponent extends React.ElementType = PrivateQueryMaskTypeMap['defaultComponent'],
20
20
  AdditionalProps = MaskProp,
21
- > = OverrideProps<InContextMaskTypeMap<AdditionalProps, RootComponent>, RootComponent> & {
21
+ > = OverrideProps<PrivateQueryMaskTypeMap<AdditionalProps, RootComponent>, RootComponent> & {
22
22
  component?: React.ElementType
23
23
  }
24
24
 
25
- type InContextMaskContextType = { mask: boolean }
25
+ type PrivateQueryMaskContextType = { mask: boolean }
26
26
 
27
- export const InContextMaskContext = createContext<InContextMaskContextType | undefined>(undefined)
27
+ export const PrivateQueryMaskContext = createContext<PrivateQueryMaskContextType | undefined>(
28
+ undefined,
29
+ )
28
30
 
29
- export function useInContextInputMask(): InContextMaskContextType {
30
- const context = useContext(InContextMaskContext)
31
+ export function usePrivateQueryMask(): PrivateQueryMaskContextType {
32
+ const context = useContext(PrivateQueryMaskContext)
31
33
 
32
34
  // eslint-disable-next-line react-hooks/rules-of-hooks
33
35
  const isSSR = process.env.NODE_ENV === 'development' ? useIsSSR() : false
@@ -35,7 +37,7 @@ export function useInContextInputMask(): InContextMaskContextType {
35
37
  if (!context) {
36
38
  if (isSSR)
37
39
  console.warn(
38
- "useInContextInputMask was used without a InContextMaskProvider, this means that customer specific pricing probably isn't working.",
40
+ "usePrivateQueryMask was used without a PrivateQueryMaskProvider, this means that customer specific pricing probably isn't working.",
39
41
  )
40
42
 
41
43
  return { mask: false }
@@ -43,31 +45,31 @@ export function useInContextInputMask(): InContextMaskContextType {
43
45
  return context
44
46
  }
45
47
 
46
- export function InContextMaskProvider(props: { mask: boolean; children: React.ReactNode }) {
48
+ export function PrivateQueryMaskProvider(props: { mask: boolean; children: React.ReactNode }) {
47
49
  const { mask = false, children } = props
48
50
  return (
49
- <InContextMaskContext.Provider value={useMemo(() => ({ mask }), [mask])}>
51
+ <PrivateQueryMaskContext.Provider value={useMemo(() => ({ mask }), [mask])}>
50
52
  {children}
51
- </InContextMaskContext.Provider>
53
+ </PrivateQueryMaskContext.Provider>
52
54
  )
53
55
  }
54
56
 
55
- export function useInContextInputMaskSx(props: { sx?: SxProps<Theme>; skeleton?: SkeletonProps }) {
57
+ export function usePrivateQueryMaskSx(props: { sx?: SxProps<Theme>; skeleton?: SkeletonProps }) {
56
58
  const { sx = [], skeleton } = props
57
- const { mask } = useInContextInputMask()
59
+ const { mask } = usePrivateQueryMask()
58
60
 
59
61
  return {
60
62
  mask,
61
63
  componentSx: [
62
64
  mask && {
63
- [cssFlag('in-context')]: { display: 'none' },
65
+ [cssFlag('private-query')]: { display: 'none' },
64
66
  },
65
67
  ...(Array.isArray(sx) ? sx : [sx]),
66
68
  ],
67
69
  maskSx: [
68
70
  {
69
71
  display: 'inline-block',
70
- [cssNotFlag('in-context')]: { display: 'none' },
72
+ [cssNotFlag('private-query')]: { display: 'none' },
71
73
  },
72
74
  ...(Array.isArray(sx) ? sx : [sx]),
73
75
  ...(Array.isArray(skeleton?.sx) ? skeleton.sx : [skeleton?.sx]),
@@ -75,12 +77,10 @@ export function useInContextInputMaskSx(props: { sx?: SxProps<Theme>; skeleton?:
75
77
  }
76
78
  }
77
79
 
78
- /**
79
- * A component that renders a skeleton mask when the user is signed in.
80
- */
81
- export function InContextMask(props: InContextMaskProps) {
80
+ /** A component that renders a skeleton mask when the user is signed in. */
81
+ export function PrivateQueryMask(props: PrivateQueryMaskProps) {
82
82
  const { skeleton, children, ...rest } = props
83
- const { mask, componentSx, maskSx } = useInContextInputMaskSx(props)
83
+ const { mask, componentSx, maskSx } = usePrivateQueryMaskSx(props)
84
84
 
85
85
  return (
86
86
  <>
package/config.ts CHANGED
@@ -2,6 +2,7 @@ import type { GraphCommerceStorefrontConfig } from '@graphcommerce/next-config'
2
2
  import type { ApolloLink, TypePolicies } from '@apollo/client'
3
3
  import type { SetRequired } from 'type-fest'
4
4
  import type { MigrateCache } from './components/GraphQLProvider/migrateCache'
5
+ import { RemovePrivateContextDirectivesLink } from './link/RemovePrivateContextDirectivesLink'
5
6
 
6
7
  export interface PreviewData {}
7
8
 
@@ -34,5 +35,11 @@ export type ApolloClientConfig = SetRequired<
34
35
 
35
36
  export function graphqlConfig(config: ApolloClientConfigInput): ApolloClientConfig {
36
37
  const { storefront, links = [], policies = [], migrations = [], ...rest } = config
37
- return { storefront, links, policies, migrations, ...rest }
38
+ return {
39
+ storefront,
40
+ links: [...links, new RemovePrivateContextDirectivesLink()],
41
+ policies,
42
+ migrations,
43
+ ...rest,
44
+ }
38
45
  }
@@ -1,51 +1,54 @@
1
- import type { InContextInput, InputMaybe } from '@graphcommerce/graphql-mesh'
1
+ import type { InputMaybe, PrivateContext } from '@graphcommerce/graphql-mesh'
2
2
  // eslint-disable-next-line import/no-extraneous-dependencies
3
3
  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 { QueryHookOptions, QueryResult, TypedDocumentNode } from '../apollo'
7
+ import type { MaybeMasked, QueryHookOptions, QueryResult, TypedDocumentNode } from '../apollo'
8
8
  import { useQuery } from '../apollo'
9
- import { InContextMaskContext } from '../components/InContextMask/InContextMask'
10
- import { useInContextInput } from './useInContextInput'
9
+ import { PrivateQueryMaskContext } from '../components/PrivateQueryMask/PrivateQueryMask'
10
+ import { usePrivateQueryContext } from './usePrivateQueryContext'
11
11
 
12
12
  /**
13
- * Creates a query that allows fetching data for logged in customers, but have
14
- * a fallback for guest users.
13
+ * Creates a query that allows fetching data for logged in customers (or other private contexts),
14
+ * but have a fallback for guest users.
15
15
  *
16
16
  * - Shows a global pageload indicator when loading customer specific information.
17
17
  *
18
18
  * When not to use this?
19
- * - When a query is always scoped. This method specifically targets queries that can resolve unscoped (guest) and both scoped (customer) data.
19
+ *
20
+ * - When a query is always scoped. This method specifically targets queries that can resolve unscoped
21
+ * (guest) and both scoped (customer) data.
20
22
  *
21
23
  * Usage:
22
- * - Define a `@inContext(context: $context)` directive in your query
23
- * - Use the useInContextQuery
24
+ *
25
+ * - Define a `@privateContext(context: $context)` directive in your query
26
+ * - Use the usePrivateQuery
24
27
  */
25
- export function useInContextQuery<
28
+ export function usePrivateQuery<
26
29
  Q,
27
- V extends { context?: InputMaybe<InContextInput>; [index: string]: unknown },
30
+ V extends { context?: InputMaybe<PrivateContext>; [index: string]: unknown },
28
31
  >(
29
32
  document: TypedDocumentNode<Q, V>,
30
33
  options: QueryHookOptions<Q, V>,
31
34
  unscopedResult: Q,
32
- ): Omit<QueryResult<Q, V>, 'data'> & { data: Q; mask: boolean } {
35
+ ): Omit<QueryResult<Q, V>, 'data'> & { data: Q | NonNullable<MaybeMasked<Q>>; mask: boolean } {
33
36
  const { skip = true } = options
34
- const context = useInContextInput()
37
+ const context = usePrivateQueryContext()
35
38
  const isSsr = useIsSSR()
36
39
 
37
- const inContext = useContext(InContextMaskContext)
40
+ const privateContext = useContext(PrivateQueryMaskContext)
38
41
 
39
42
  useEffect(() => {
40
43
  if (isSsr) return
41
- if (context && !getCssFlag('in-context')) setCssFlag('in-context', true)
42
- else if (!context && getCssFlag('in-context')) removeCssFlag('in-context')
44
+ if (context && !getCssFlag('private-query')) setCssFlag('private-query', true)
45
+ else if (!context && getCssFlag('private-query')) removeCssFlag('private-query')
43
46
  }, [context, isSsr])
44
47
 
45
48
  const clientQuery = useQuery<Q, V>(document, {
46
49
  ...options,
47
50
  variables: { ...options.variables, context } as V,
48
- skip: !!inContext || (skip && !context),
51
+ skip: !!privateContext || (skip && !context),
49
52
  })
50
53
 
51
54
  let { data } = clientQuery
@@ -57,9 +60,9 @@ export function useInContextQuery<
57
60
  mask = !skip ? !clientQuery.data && !clientQuery.previousData : !clientQuery.data
58
61
  }
59
62
 
60
- // If this method is called within an InContextMask, we skip this complete functionality so we show the parent mask.
61
- if (inContext) {
62
- mask = inContext.mask
63
+ // If this method is called within an PrivateQueryMask, we skip this complete functionality so we show the parent mask.
64
+ if (privateContext) {
65
+ mask = privateContext.mask
63
66
  }
64
67
 
65
68
  return { ...clientQuery, data: data ?? unscopedResult, mask }
@@ -1,10 +1,10 @@
1
- import type { InContextInput } from '@graphcommerce/graphql-mesh'
1
+ import type { PrivateContext } from '@graphcommerce/graphql-mesh'
2
2
  import type { ApolloClient } from '@apollo/client'
3
3
 
4
- export function getInContextInput(
4
+ export function getPrivateQueryContext(
5
5
  // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
6
6
  client: ApolloClient<any>,
7
- ): InContextInput | null {
7
+ ): PrivateContext | null {
8
8
  return null
9
9
  }
10
10
 
@@ -15,6 +15,6 @@ export function getInContextInput(
15
15
  *
16
16
  * @see @graphcommerce/magento-customer/plugins/magentoCustomerGetInContext.ts
17
17
  *
18
- * Note: ONLY return a value if the frontend should use the inContext directive.
18
+ * Note: ONLY return a value if the frontend should use the privateContext directive.
19
19
  */
20
- export const useInContextInput = (): InContextInput | null => null
20
+ export const usePrivateQueryContext = (): PrivateContext | null => null
package/index.ts CHANGED
@@ -5,6 +5,6 @@ export * from './generated/types'
5
5
  export * from './config'
6
6
  export * from './utils/getPreviewData'
7
7
  export * from './utils/cachePolicy'
8
- export * from './components/InContextMask/InContextMask'
9
- export * from './hooks/useInContextInput'
10
- export * from './hooks/useInContextQuery'
8
+ export * from './components/PrivateQueryMask/PrivateQueryMask'
9
+ export * from './hooks/usePrivateQueryContext'
10
+ export * from './hooks/usePrivateQuery'
@@ -0,0 +1,19 @@
1
+ import type { NextLink, Operation } from '../apollo'
2
+ import { ApolloLink, removeArgumentsFromDocument, removeDirectivesFromDocument } from '../apollo'
3
+
4
+ export class RemovePrivateContextDirectivesLink extends ApolloLink {
5
+ // eslint-disable-next-line class-methods-use-this
6
+ request(operation: Operation, forward?: NextLink) {
7
+ if (!forward) throw new Error('This is not a terminal link!')
8
+
9
+ let modifiedQuery = operation.query
10
+
11
+ modifiedQuery =
12
+ removeDirectivesFromDocument([{ name: 'privateContext' }], modifiedQuery) ?? modifiedQuery
13
+ modifiedQuery =
14
+ removeArgumentsFromDocument([{ name: 'context' }], modifiedQuery) ?? modifiedQuery
15
+
16
+ operation.query = modifiedQuery
17
+ return forward(operation)
18
+ }
19
+ }
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": "9.0.0-canary.114",
5
+ "version": "9.0.0-canary.116",
6
6
  "sideEffects": false,
7
7
  "main": "index.ts",
8
8
  "prettier": "@graphcommerce/prettier-config-pwa",
@@ -13,7 +13,7 @@
13
13
  }
14
14
  },
15
15
  "dependencies": {
16
- "@apollo/client": "~3.11.10",
16
+ "@apollo/client": "~3.12.3",
17
17
  "@graphql-codegen/add": "5.0.3",
18
18
  "@graphql-codegen/fragment-matcher": "5.0.2",
19
19
  "@graphql-codegen/introspection": "4.0.3",
@@ -24,14 +24,15 @@
24
24
  "@graphql-codegen/typescript-document-nodes": "4.0.12",
25
25
  "@graphql-codegen/typescript-operations": "4.4.0",
26
26
  "apollo3-cache-persist": "^0.15.0",
27
- "graphql": "^16.9.0"
27
+ "graphql": "^16.10.0"
28
28
  },
29
29
  "peerDependencies": {
30
- "@graphcommerce/eslint-config-pwa": "^9.0.0-canary.114",
31
- "@graphcommerce/graphql-codegen-near-operation-file": "9.0.0-canary.114",
32
- "@graphcommerce/graphql-codegen-relay-optimizer-plugin": "9.0.0-canary.114",
33
- "@graphcommerce/prettier-config-pwa": "^9.0.0-canary.114",
34
- "@graphcommerce/typescript-config-pwa": "^9.0.0-canary.114",
30
+ "@graphcommerce/eslint-config-pwa": "^9.0.0-canary.116",
31
+ "@graphcommerce/graphql-codegen-near-operation-file": "9.0.0-canary.116",
32
+ "@graphcommerce/graphql-codegen-relay-optimizer-plugin": "9.0.0-canary.116",
33
+ "@graphcommerce/prettier-config-pwa": "^9.0.0-canary.116",
34
+ "@graphcommerce/typescript-config-pwa": "^9.0.0-canary.116",
35
+ "@graphql-mesh/plugin-http-details-extensions": "*",
35
36
  "react": "^18.2.0",
36
37
  "react-dom": "^18.2.0"
37
38
  }
@@ -1,9 +1,9 @@
1
1
  """
2
2
  By providing these values the Apollo Client cache will automatically scope the cache to these specific values.
3
3
 
4
- If a InContext is provided
4
+ If a PrivateContext is provided
5
5
  """
6
- input InContextInput {
6
+ input PrivateContext {
7
7
  loggedIn: Boolean
8
8
 
9
9
  # storeCode: String
@@ -13,4 +13,4 @@ input InContextInput {
13
13
  """
14
14
  Certain values are only available in the context of a session and need to have the cache scoped to these values.
15
15
  """
16
- directive @inContext(context: InContextInput) on FIELD
16
+ directive @privateContext(context: PrivateContext) on FIELD