link.ts 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. // Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
  2. import {
  3. ApolloLink,
  4. createHttpLink,
  5. from,
  6. Operation,
  7. } from '@apollo/client/core'
  8. import csrfLink from '@common/server/apollo/link/csrf'
  9. import errorLink from '@common/server/apollo/link/error'
  10. import debugLink from '@common/server/apollo/link/debug'
  11. import setAuthorizationLink from '@common/server/apollo/link/setAuthorization'
  12. import ActionCableLink from 'graphql-ruby-client/subscriptions/ActionCableLink'
  13. import consumer from '@common/server/action_cable/consumer'
  14. import { getMainDefinition } from '@apollo/client/utilities'
  15. import { BatchHttpLink } from '@apollo/client/link/batch-http'
  16. import { FragmentDefinitionNode, OperationDefinitionNode } from 'graphql'
  17. import connectedStateLink from '@common/server/apollo/link/connectedState'
  18. // Should subsequent HTTP calls be batched together?
  19. const enableBatchLink = false
  20. // Should queries and mutations be sent over ActionCable?
  21. const enableQueriesOverWebsocket = false
  22. const connectionSettings = {
  23. uri: '/graphql',
  24. credentials: 'same-origin', // Must have for CSRF validation via Rails.
  25. }
  26. const noBatchLink = createHttpLink(connectionSettings)
  27. const batchLink = new BatchHttpLink({
  28. ...connectionSettings,
  29. batchMax: 5,
  30. batchInterval: 20,
  31. })
  32. const operationIsLoginLogout = (
  33. definition: OperationDefinitionNode | FragmentDefinitionNode,
  34. ) => {
  35. return !!(
  36. definition.kind === 'OperationDefinition' &&
  37. definition.operation === 'mutation' &&
  38. definition.name?.value &&
  39. ['login', 'logout'].includes(definition.name?.value)
  40. )
  41. }
  42. const requiresBatchLink = (op: Operation) => {
  43. if (!enableBatchLink) return false
  44. const definition = getMainDefinition(op.query)
  45. return !operationIsLoginLogout(definition)
  46. }
  47. const httpLink = ApolloLink.split(requiresBatchLink, batchLink, noBatchLink)
  48. const requiresHttpLink = (op: Operation) => {
  49. const definition = getMainDefinition(op.query)
  50. if (!enableQueriesOverWebsocket) {
  51. // Only subscriptions over websocket.
  52. return !(
  53. definition.kind === 'OperationDefinition' &&
  54. definition.operation === 'subscription'
  55. )
  56. }
  57. // Everything over websocket except login/logout as that changes cookies.
  58. return operationIsLoginLogout(definition)
  59. }
  60. const actionCableLink = new ActionCableLink({ cable: consumer })
  61. const splitLink = ApolloLink.split(requiresHttpLink, httpLink, actionCableLink)
  62. const link = from([
  63. csrfLink,
  64. errorLink,
  65. setAuthorizationLink,
  66. debugLink,
  67. connectedStateLink,
  68. splitLink,
  69. ])
  70. export default link