diff --git a/packages/leaders-program/apollo/create-client.js b/packages/leaders-program/apollo/create-client.js deleted file mode 100644 index 63f7ccef0..000000000 --- a/packages/leaders-program/apollo/create-client.js +++ /dev/null @@ -1,9 +0,0 @@ -import { ApolloClient } from 'apollo-client'; -import { createHttpLink } from 'apollo-link-http'; -import { InMemoryCache } from 'apollo-cache-inmemory'; -import fragmentMatcher from './fragment-matcher'; - -export default ({ uri, headers }) => new ApolloClient({ - link: createHttpLink({ uri, headers }), - cache: new InMemoryCache({ fragmentMatcher }), -}); diff --git a/packages/leaders-program/apollo/create-provider.js b/packages/leaders-program/apollo/create-provider.js deleted file mode 100644 index ac7249359..000000000 --- a/packages/leaders-program/apollo/create-provider.js +++ /dev/null @@ -1,22 +0,0 @@ -import VueApollo from 'vue-apollo'; -import createApolloClient from './create-client'; - -export default ({ - graphqlUri, - tenantKey, - siteId, - baseApiUri, -} = {}) => { - const apiUri = baseApiUri || window.location.origin; - if (!graphqlUri || !tenantKey || !apiUri) { - throw new Error('The graphqlUri, tenantKey, and baseApiUri options are required to create the BaseCMS Apollo Provider.'); - } - const headers = { - 'x-tenant-key': tenantKey, - 'x-base4-api-uri': apiUri, - }; - if (siteId) headers['x-site-id'] = siteId; - return new VueApollo({ - defaultClient: createApolloClient({ uri: graphqlUri, headers }), - }); -}; diff --git a/packages/leaders-program/apollo/fragment-matcher.js b/packages/leaders-program/apollo/fragment-matcher.js deleted file mode 100644 index 98bb02f18..000000000 --- a/packages/leaders-program/apollo/fragment-matcher.js +++ /dev/null @@ -1,4 +0,0 @@ -import { IntrospectionFragmentMatcher } from 'apollo-cache-inmemory'; -import introspectionQueryResultData from '@parameter1/base-cms-graphql-fragment-types'; - -export default new IntrospectionFragmentMatcher({ introspectionQueryResultData }); diff --git a/packages/leaders-program/package.json b/packages/leaders-program/package.json index a32aecb55..04269e989 100644 --- a/packages/leaders-program/package.json +++ b/packages/leaders-program/package.json @@ -14,12 +14,9 @@ }, "dependencies": { "core-js": "^3.18.2", - "graphql": "^14.7.0", - "graphql-tag": "^2.12.5", "object-path": "^0.11.8", "portal-vue": "^2.1.7", - "vue": "^2.6.14", - "vue-apollo": "^3.0.8" + "vue": "^2.6.14" }, "devDependencies": { "@parameter1/base-cms-graphql-fragment-types": "^2.45.0", @@ -27,10 +24,6 @@ "@vue/cli-plugin-eslint": "^4.5.13", "@vue/cli-service": "^4.5.13", "@vue/eslint-config-airbnb": "^4.0.1", - "apollo-cache-inmemory": "^1.6.6", - "apollo-client": "^2.6.10", - "apollo-link": "^1.2.14", - "apollo-link-http": "^1.5.17", "babel-eslint": "^10.1.0", "eslint": "^5.16.0", "eslint-plugin-vue": "^5.0.0", diff --git a/packages/leaders-program/public/index.html b/packages/leaders-program/public/index.html index e2ebac24b..6f20dbb84 100644 --- a/packages/leaders-program/public/index.html +++ b/packages/leaders-program/public/index.html @@ -10,7 +10,7 @@ diff --git a/packages/leaders-program/src/components/containers/section.vue b/packages/leaders-program/src/components/containers/section.vue index 8c9a85bba..f9e5de30c 100644 --- a/packages/leaders-program/src/components/containers/section.vue +++ b/packages/leaders-program/src/components/containers/section.vue @@ -58,6 +58,7 @@ import query from '../../graphql/queries/content-for-section'; import getEdgeNodes from '../../utils/get-edge-nodes'; export default { + inject: ['$graphql'], components: { PlusIcon, MinusIcon, @@ -197,7 +198,7 @@ export default { promotionLimit: this.promotionLimit, videoLimit: this.videoLimit, }; - const { data } = await this.$apollo.query({ query, variables }); + const { data } = await this.$graphql.query({ query, variables }); this.items = getEdgeNodes(data, 'websiteScheduledContent'); this.hasLoaded = true; } catch (e) { diff --git a/packages/leaders-program/src/components/leaders.vue b/packages/leaders-program/src/components/leaders.vue index 90ed1b811..f4a3c8bf3 100644 --- a/packages/leaders-program/src/components/leaders.vue +++ b/packages/leaders-program/src/components/leaders.vue @@ -50,6 +50,7 @@ import getEdgeNodes from '../utils/get-edge-nodes'; import getAsObject from '../utils/get-as-object'; export default { + inject: ['$graphql'], components: { Loading, LeadersHeader, @@ -253,7 +254,7 @@ export default { const { sectionIds } = this; if (sectionIds && sectionIds.length) { const variables = { sectionIds }; - const r = await this.$apollo.query({ query: fromIdsQuery, variables }); + const r = await this.$graphql.query({ query: fromIdsQuery, variables }); const sections = getEdgeNodes(r, 'data.websiteSections') .filter(s => s.hierarchy.some(({ alias }) => alias === this.sectionAlias)); if (sections.length) return sections; @@ -269,7 +270,7 @@ export default { async loadContentSections() { if (!this.contentId) return []; const variables = { contentId: this.contentId }; - const r1 = await this.$apollo.query({ query: contentQuery, variables }); + const r1 = await this.$graphql.query({ query: contentQuery, variables }); const taxonomyIds = getEdgeNodes(r1, 'data.content.taxonomy').map(t => t.id); const sectionIds = []; this.taxonomyIds = taxonomyIds; @@ -279,7 +280,7 @@ export default { } if (!taxonomyIds.length && !sectionIds.length) return []; const v2 = { taxonomyIds, relatedSectionIds: sectionIds }; - const r2 = await this.$apollo.query({ query: fromContentQuery, variables: v2 }); + const r2 = await this.$graphql.query({ query: fromContentQuery, variables: v2 }); const sections = getEdgeNodes(r2, 'data.websiteSections'); return sections .filter(s => s.hierarchy.some(({ alias }) => alias === this.sectionAlias)); @@ -287,7 +288,7 @@ export default { async loadAllSections() { const variables = { sectionAlias: this.sectionAlias }; - const { data } = await this.$apollo.query({ query: allQuery, variables }); + const { data } = await this.$graphql.query({ query: allQuery, variables }); this.loadType = 'all'; return getEdgeNodes(data, 'websiteSectionAlias.children'); }, diff --git a/packages/leaders-program/src/dev.js b/packages/leaders-program/src/dev.js index 457bb713c..df101efa7 100644 --- a/packages/leaders-program/src/dev.js +++ b/packages/leaders-program/src/dev.js @@ -1,12 +1,10 @@ /* eslint-disable no-new */ import Vue from 'vue'; -import VueApollo from 'vue-apollo'; import Leaders from './components/leaders.vue'; -import createProvider from '../apollo/create-provider'; +import createGraphQLClient from './graphql/create-client'; Vue.config.productionTip = false; -Vue.use(VueApollo); const components = { Leaders, @@ -15,21 +13,22 @@ const components = { const loadComponent = ({ el, name, - apollo = {}, + graphql = {}, props = {}, on, } = {}) => { - const { uri, tenant, siteId } = apollo; + const { uri, tenant, siteId } = graphql; if (!uri || !tenant || !siteId) throw new Error('The provided apollo config is invalid.'); if (!components[name]) throw new Error(`No BaseCMS Management Component found for '${name}'`); const Component = components[name]; new Vue({ el, - apolloProvider: createProvider({ - graphqlUri: uri, - tenantKey: tenant, - siteId, - }), + provide: { + $graphql: createGraphQLClient({ + uri, + headers: { 'x-tenant-key': tenant, 'x-site-id': siteId }, + }), + }, render: h => h(Component, { props, on }), }); }; diff --git a/packages/leaders-program/src/graphql/create-client.js b/packages/leaders-program/src/graphql/create-client.js new file mode 100644 index 000000000..dc35bca06 --- /dev/null +++ b/packages/leaders-program/src/graphql/create-client.js @@ -0,0 +1,48 @@ +import sha1 from './sha1'; + +const getOperationName = (string) => { + const matches = /query\s+([a-z0-9]+)[(]?.+{/gi.exec(string); + if (matches && matches[1]) return matches[1]; + return undefined; +}; + +export default ({ uri, headers: globalHeaders }) => { + const cache = new Map(); + return Object.create({ + query: async ({ query, variables, headers }) => { + const body = JSON.stringify({ + operationName: getOperationName(query), + variables, + query, + }); + const hash = await sha1(body); + if (hash && cache.has(hash)) return cache.get(hash); + + const res = await fetch(uri, { + method: 'POST', + headers: { + ...globalHeaders, + ...headers, + 'content-type': 'application/json', + }, + body, + }); + const json = await res.json(); + if (!res.ok || (json && json.errors)) { + if (!json || !json.errors) { + const err = new Error(`An unknown, fatal GraphQL error was encountered (${res.status})`); + err.statusCode = res.status; + throw err; + } + const [networkError] = json.errors; + const err = new Error(networkError.message); + const { extensions } = networkError; + if (extensions) err.code = extensions.code; + if (extensions && extensions.exception) err.statusCode = extensions.exception.statusCode; + throw err; + } + if (hash) cache.set(hash, json); + return json; + }, + }); +}; diff --git a/packages/leaders-program/src/graphql/parse.js b/packages/leaders-program/src/graphql/parse.js new file mode 100644 index 000000000..33a997c13 --- /dev/null +++ b/packages/leaders-program/src/graphql/parse.js @@ -0,0 +1 @@ +export default (strings, ...rest) => [...strings, ...rest].join('\n'); diff --git a/packages/leaders-program/src/graphql/queries/all-sections.js b/packages/leaders-program/src/graphql/queries/all-sections.js index 178e357a1..c58d82cad 100644 --- a/packages/leaders-program/src/graphql/queries/all-sections.js +++ b/packages/leaders-program/src/graphql/queries/all-sections.js @@ -1,4 +1,4 @@ -import gql from 'graphql-tag'; +import gql from '../parse'; export default gql` diff --git a/packages/leaders-program/src/graphql/queries/content-for-section.js b/packages/leaders-program/src/graphql/queries/content-for-section.js index c3ec0cff5..ba180c9fd 100644 --- a/packages/leaders-program/src/graphql/queries/content-for-section.js +++ b/packages/leaders-program/src/graphql/queries/content-for-section.js @@ -1,4 +1,4 @@ -import gql from 'graphql-tag'; +import gql from '../parse'; export default gql` diff --git a/packages/leaders-program/src/graphql/queries/content.js b/packages/leaders-program/src/graphql/queries/content.js index 0c0a3b19b..fdf4cfe6c 100644 --- a/packages/leaders-program/src/graphql/queries/content.js +++ b/packages/leaders-program/src/graphql/queries/content.js @@ -1,4 +1,4 @@ -import gql from 'graphql-tag'; +import gql from '../parse'; export default gql` diff --git a/packages/leaders-program/src/graphql/queries/sections-from-content.js b/packages/leaders-program/src/graphql/queries/sections-from-content.js index 1ed5a3121..f6798d120 100644 --- a/packages/leaders-program/src/graphql/queries/sections-from-content.js +++ b/packages/leaders-program/src/graphql/queries/sections-from-content.js @@ -1,4 +1,4 @@ -import gql from 'graphql-tag'; +import gql from '../parse'; export default gql` diff --git a/packages/leaders-program/src/graphql/queries/sections-from-ids.js b/packages/leaders-program/src/graphql/queries/sections-from-ids.js index bca40ca07..ed2ca5773 100644 --- a/packages/leaders-program/src/graphql/queries/sections-from-ids.js +++ b/packages/leaders-program/src/graphql/queries/sections-from-ids.js @@ -1,4 +1,4 @@ -import gql from 'graphql-tag'; +import gql from '../parse'; export default gql` diff --git a/packages/leaders-program/src/graphql/sha1.js b/packages/leaders-program/src/graphql/sha1.js new file mode 100644 index 000000000..f8bff715b --- /dev/null +++ b/packages/leaders-program/src/graphql/sha1.js @@ -0,0 +1,18 @@ +const { error } = console; + +export default async (string) => { + try { + const buffer = new TextEncoder('utf-8').encode(string); + const digest = await crypto.subtle.digest('SHA-1', buffer); + const hexCodes = []; + const view = new DataView(digest); + for (let i = 0; i < view.byteLength; i += 1) { + const byte = view.getUint8(i).toString(16).padStart(2, '0'); + hexCodes.push(byte); + } + return hexCodes.join(''); + } catch (e) { + error('Unable to create SHA1 - GraphQL cache will be disabled.', e); + return null; + } +}; diff --git a/packages/leaders-program/src/index.js b/packages/leaders-program/src/index.js index f6c194687..c0dc4b603 100644 --- a/packages/leaders-program/src/index.js +++ b/packages/leaders-program/src/index.js @@ -1,3 +1,5 @@ import Leaders from './components/leaders.vue'; +export { default as createGraphQLClient } from './graphql/create-client'; + export default Leaders; diff --git a/packages/marko-web-identity-x/browser/comments/post.vue b/packages/marko-web-identity-x/browser/comments/post.vue index 2c534cb4d..7b028b429 100644 --- a/packages/marko-web-identity-x/browser/comments/post.vue +++ b/packages/marko-web-identity-x/browser/comments/post.vue @@ -33,7 +33,7 @@