Remove apollo link state
This commit is contained in:
@@ -17,7 +17,6 @@
|
||||
"apollo-client": "2.5.1",
|
||||
"apollo-link": "^1.2.11",
|
||||
"apollo-link-http": "^1.5.14",
|
||||
"apollo-link-state": "^0.4.2",
|
||||
"buefy": "^0.7.3",
|
||||
"easygettext": "^2.7.0",
|
||||
"graphql": "^14.2.1",
|
||||
@@ -53,6 +52,7 @@
|
||||
"@vue/cli-service": "^3.6.0",
|
||||
"@vue/eslint-config-typescript": "^4.0.0",
|
||||
"@vue/test-utils": "^1.0.0-beta.29",
|
||||
"apollo-link-error": "^1.1.11",
|
||||
"chai": "^4.2.0",
|
||||
"dotenv-webpack": "^1.7.0",
|
||||
"eslint": "^6.0.1",
|
||||
|
||||
@@ -9,15 +9,15 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import NavBar from '@/components/NavBar.vue';
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
import { AUTH_TOKEN, AUTH_USER_ACTOR, AUTH_USER_EMAIL, AUTH_USER_ID } from '@/constants';
|
||||
import { CURRENT_USER_CLIENT, UPDATE_CURRENT_USER_CLIENT } from '@/graphql/user';
|
||||
import { ICurrentUser } from '@/types/current-user.model';
|
||||
import Footer from '@/components/Footer.vue';
|
||||
import Logo from '@/components/Logo.vue';
|
||||
import NavBar from '@/components/NavBar.vue';
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
import { AUTH_ACCESS_TOKEN, AUTH_USER_ACTOR, AUTH_USER_EMAIL, AUTH_USER_ID } from '@/constants';
|
||||
import { CURRENT_USER_CLIENT, UPDATE_CURRENT_USER_CLIENT } from '@/graphql/user';
|
||||
import { ICurrentUser } from '@/types/current-user.model';
|
||||
import Footer from '@/components/Footer.vue';
|
||||
import Logo from '@/components/Logo.vue';
|
||||
|
||||
@Component({
|
||||
@Component({
|
||||
apollo: {
|
||||
currentUser: {
|
||||
query: CURRENT_USER_CLIENT,
|
||||
@@ -45,9 +45,9 @@ export default class App extends Vue {
|
||||
private initializeCurrentUser() {
|
||||
const userId = localStorage.getItem(AUTH_USER_ID);
|
||||
const userEmail = localStorage.getItem(AUTH_USER_EMAIL);
|
||||
const token = localStorage.getItem(AUTH_TOKEN);
|
||||
const accessToken = localStorage.getItem(AUTH_ACCESS_TOKEN);
|
||||
|
||||
if (userId && userEmail && token) {
|
||||
if (userId && userEmail && accessToken) {
|
||||
return this.$apollo.mutate({
|
||||
mutation: UPDATE_CURRENT_USER_CLIENT,
|
||||
variables: {
|
||||
|
||||
@@ -1,27 +1,32 @@
|
||||
export const currentUser = {
|
||||
defaults: {
|
||||
currentUser: {
|
||||
__typename: 'CurrentUser',
|
||||
id: null,
|
||||
email: null,
|
||||
isLoggedIn: false,
|
||||
},
|
||||
},
|
||||
import { ApolloCache } from 'apollo-cache';
|
||||
import { NormalizedCacheObject } from 'apollo-cache-inmemory';
|
||||
|
||||
resolvers: {
|
||||
Mutation: {
|
||||
updateCurrentUser: (_, { id, email, isLoggedIn }, { cache }) => {
|
||||
const data = {
|
||||
export function buildCurrentUserResolver(cache: ApolloCache<NormalizedCacheObject>) {
|
||||
cache.writeData({
|
||||
data: {
|
||||
currentUser: {
|
||||
__typename: 'CurrentUser',
|
||||
id: null,
|
||||
email: null,
|
||||
isLoggedIn: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
updateCurrentUser: (_, { id, email, isLoggedIn }, { cache }) => {
|
||||
const data = {
|
||||
Mutation: {
|
||||
currentUser: {
|
||||
id,
|
||||
email,
|
||||
isLoggedIn,
|
||||
__typename: 'CurrentUser',
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
cache.writeData({ data });
|
||||
},
|
||||
cache.writeData({ data });
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -60,19 +60,18 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue, Watch } from 'vue-property-decorator';
|
||||
import { CURRENT_USER_CLIENT, UPDATE_CURRENT_USER_CLIENT } from '@/graphql/user';
|
||||
import { onLogout } from '@/vue-apollo';
|
||||
import { deleteUserData } from '@/utils/auth';
|
||||
import { LOGGED_PERSON } from '@/graphql/actor';
|
||||
import { IPerson } from '@/types/actor';
|
||||
import { CONFIG } from '@/graphql/config';
|
||||
import { IConfig } from '@/types/config.model';
|
||||
import { ICurrentUser } from '@/types/current-user.model';
|
||||
import Logo from '@/components/Logo.vue';
|
||||
import SearchField from '@/components/SearchField.vue';
|
||||
import { Component, Vue, Watch } from 'vue-property-decorator';
|
||||
import { CURRENT_USER_CLIENT } from '@/graphql/user';
|
||||
import { logout } from '@/utils/auth';
|
||||
import { LOGGED_PERSON } from '@/graphql/actor';
|
||||
import { IPerson } from '@/types/actor';
|
||||
import { CONFIG } from '@/graphql/config';
|
||||
import { IConfig } from '@/types/config.model';
|
||||
import { ICurrentUser } from '@/types/current-user.model';
|
||||
import Logo from '@/components/Logo.vue';
|
||||
import SearchField from '@/components/SearchField.vue';
|
||||
|
||||
@Component({
|
||||
@Component({
|
||||
apollo: {
|
||||
currentUser: {
|
||||
query: CURRENT_USER_CLIENT,
|
||||
@@ -111,18 +110,7 @@ export default class NavBar extends Vue {
|
||||
}
|
||||
|
||||
async logout() {
|
||||
await this.$apollo.mutate({
|
||||
mutation: UPDATE_CURRENT_USER_CLIENT,
|
||||
variables: {
|
||||
id: null,
|
||||
email: null,
|
||||
isLoggedIn: false,
|
||||
},
|
||||
});
|
||||
|
||||
deleteUserData();
|
||||
|
||||
onLogout(this.$apollo);
|
||||
await logout(this.$apollo.provider.defaultClient);
|
||||
|
||||
return this.$router.push({ path: '/' });
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export const AUTH_TOKEN = 'auth-token';
|
||||
export const AUTH_ACCESS_TOKEN = 'auth-access-token';
|
||||
export const AUTH_REFRESH_TOKEN = 'auth-refresh-token';
|
||||
export const AUTH_USER_ID = 'auth-user-id';
|
||||
export const AUTH_USER_EMAIL = 'auth-user-email';
|
||||
export const AUTH_USER_ACTOR = 'auth-user-actor';
|
||||
|
||||
@@ -3,7 +3,8 @@ import gql from 'graphql-tag';
|
||||
export const LOGIN = gql`
|
||||
mutation Login($email: String!, $password: String!) {
|
||||
login(email: $email, password: $password) {
|
||||
token,
|
||||
accessToken,
|
||||
refreshToken,
|
||||
user {
|
||||
id,
|
||||
}
|
||||
@@ -33,3 +34,12 @@ mutation ResendConfirmationEmail($email: String!) {
|
||||
resendConfirmationEmail(email: $email)
|
||||
}
|
||||
`;
|
||||
|
||||
export const REFRESH_TOKEN = gql`
|
||||
mutation RefreshToken($refreshToken: String!) {
|
||||
refreshToken(refreshToken: $refreshToken) {
|
||||
accessToken,
|
||||
refreshToken,
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -12,7 +12,8 @@ mutation CreateUser($email: String!, $password: String!) {
|
||||
export const VALIDATE_USER = gql`
|
||||
mutation ValidateUser($token: String!) {
|
||||
validateUser(token: $token) {
|
||||
token,
|
||||
accessToken,
|
||||
refreshToken,
|
||||
user {
|
||||
id,
|
||||
email,
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { NavigationGuard } from 'vue-router';
|
||||
import { UserRouteName } from '@/router/user';
|
||||
import { LoginErrorCode } from '@/types/login-error-code.model';
|
||||
import { AUTH_TOKEN } from '@/constants';
|
||||
import { AUTH_ACCESS_TOKEN } from '@/constants';
|
||||
|
||||
export const authGuardIfNeeded: NavigationGuard = async function (to, from, next) {
|
||||
if (to.meta.requiredAuth !== true) return next();
|
||||
|
||||
// We can't use "currentUser" from apollo here because we may not have loaded the user from the local storage yet
|
||||
if (!localStorage.getItem(AUTH_TOKEN)) {
|
||||
if (!localStorage.getItem(AUTH_ACCESS_TOKEN)) {
|
||||
return next({
|
||||
name: UserRouteName.LOGIN,
|
||||
query: {
|
||||
|
||||
7
js/src/types/apollo.ts
Normal file
7
js/src/types/apollo.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { ServerError, ServerParseError } from 'apollo-link-http-common';
|
||||
|
||||
function isServerError(err: Error | ServerError | ServerParseError | undefined): err is ServerError {
|
||||
return !!err && (err as ServerError).statusCode !== undefined;
|
||||
}
|
||||
|
||||
export { isServerError };
|
||||
@@ -1,7 +1,10 @@
|
||||
import { ICurrentUser } from '@/types/current-user.model';
|
||||
|
||||
export interface ILogin {
|
||||
user: ICurrentUser;
|
||||
|
||||
token: string;
|
||||
export interface IToken {
|
||||
accessToken: string;
|
||||
refreshToken: string;
|
||||
}
|
||||
|
||||
export interface ILogin extends IToken {
|
||||
user: ICurrentUser;
|
||||
}
|
||||
|
||||
@@ -1,14 +1,38 @@
|
||||
import { AUTH_TOKEN, AUTH_USER_EMAIL, AUTH_USER_ID } from '@/constants';
|
||||
import { ILogin } from '@/types/login.model';
|
||||
import { AUTH_ACCESS_TOKEN, AUTH_REFRESH_TOKEN, AUTH_USER_EMAIL, AUTH_USER_ID } from '@/constants';
|
||||
import { ILogin, IToken } from '@/types/login.model';
|
||||
import { UPDATE_CURRENT_USER_CLIENT } from '@/graphql/user';
|
||||
import { onLogout } from '@/vue-apollo';
|
||||
import ApolloClient from 'apollo-client';
|
||||
|
||||
export function saveUserData(obj: ILogin) {
|
||||
localStorage.setItem(AUTH_USER_ID, `${obj.user.id}`);
|
||||
localStorage.setItem(AUTH_USER_EMAIL, obj.user.email);
|
||||
localStorage.setItem(AUTH_TOKEN, obj.token);
|
||||
|
||||
saveTokenData(obj);
|
||||
}
|
||||
|
||||
export function saveTokenData(obj: IToken) {
|
||||
localStorage.setItem(AUTH_ACCESS_TOKEN, obj.accessToken);
|
||||
localStorage.setItem(AUTH_REFRESH_TOKEN, obj.refreshToken);
|
||||
}
|
||||
|
||||
export function deleteUserData() {
|
||||
for (const key of [AUTH_USER_ID, AUTH_USER_EMAIL, AUTH_TOKEN]) {
|
||||
for (const key of [AUTH_USER_ID, AUTH_USER_EMAIL, AUTH_ACCESS_TOKEN, AUTH_REFRESH_TOKEN]) {
|
||||
localStorage.removeItem(key);
|
||||
}
|
||||
}
|
||||
|
||||
export function logout(apollo: ApolloClient<any>) {
|
||||
apollo.mutate({
|
||||
mutation: UPDATE_CURRENT_USER_CLIENT,
|
||||
variables: {
|
||||
id: null,
|
||||
email: null,
|
||||
isLoggedIn: false,
|
||||
},
|
||||
});
|
||||
|
||||
deleteUserData();
|
||||
|
||||
onLogout();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<div class="container" v-if="config">
|
||||
<section class="hero is-link" v-if="!currentUser.id || !loggedPerson">
|
||||
<div class="hero-body">
|
||||
<div class="container">
|
||||
|
||||
@@ -17,13 +17,14 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { VALIDATE_USER } from '@/graphql/user';
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
import { AUTH_TOKEN, AUTH_USER_ID } from '@/constants';
|
||||
import { RouteName } from '@/router';
|
||||
import { UserRouteName } from '@/router/user';
|
||||
import { VALIDATE_USER } from '@/graphql/user';
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
import { AUTH_USER_ID } from '@/constants';
|
||||
import { RouteName } from '@/router';
|
||||
import { UserRouteName } from '@/router/user';
|
||||
import { saveTokenData } from '@/utils/auth';
|
||||
|
||||
@Component
|
||||
@Component
|
||||
export default class Validate extends Vue {
|
||||
@Prop({ type: String, required: true }) token!: string;
|
||||
|
||||
@@ -62,7 +63,8 @@ export default class Validate extends Vue {
|
||||
|
||||
saveUserData({ validateUser: login }) {
|
||||
localStorage.setItem(AUTH_USER_ID, login.user.id);
|
||||
localStorage.setItem(AUTH_TOKEN, login.token);
|
||||
|
||||
saveTokenData(login)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
import Vue from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import { ApolloLink } from 'apollo-link';
|
||||
import { ApolloLink, Observable } from 'apollo-link';
|
||||
import { InMemoryCache, IntrospectionFragmentMatcher } from 'apollo-cache-inmemory';
|
||||
import { onError } from 'apollo-link-error';
|
||||
import { createLink } from 'apollo-absinthe-upload-link';
|
||||
import { AUTH_TOKEN } from './constants';
|
||||
import { GRAPHQL_API_ENDPOINT, GRAPHQL_API_FULL_PATH } from './api/_entrypoint';
|
||||
import { withClientState } from 'apollo-link-state';
|
||||
import { currentUser } from '@/apollo/user';
|
||||
import merge from 'lodash/merge';
|
||||
import { ApolloClient } from 'apollo-client';
|
||||
import { DollarApollo } from 'vue-apollo/types/vue-apollo';
|
||||
import { buildCurrentUserResolver } from '@/apollo/user';
|
||||
import { isServerError } from '@/types/apollo';
|
||||
import { inspect } from 'util';
|
||||
import { REFRESH_TOKEN } from '@/graphql/auth';
|
||||
import { AUTH_ACCESS_TOKEN, AUTH_REFRESH_TOKEN } from '@/constants';
|
||||
import { logout, saveTokenData } from '@/utils/auth';
|
||||
|
||||
// Install the vue plugin
|
||||
Vue.use(VueApollo);
|
||||
@@ -44,14 +47,11 @@ const fragmentMatcher = new IntrospectionFragmentMatcher({
|
||||
},
|
||||
});
|
||||
|
||||
const cache = new InMemoryCache({ fragmentMatcher });
|
||||
|
||||
const authMiddleware = new ApolloLink((operation, forward) => {
|
||||
// add the authorization to the headers
|
||||
const token = localStorage.getItem(AUTH_TOKEN);
|
||||
operation.setContext({
|
||||
headers: {
|
||||
authorization: token ? `Bearer ${token}` : null,
|
||||
authorization: generateTokenHeader(),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -64,21 +64,54 @@ const uploadLink = createLink({
|
||||
uri: httpEndpoint,
|
||||
});
|
||||
|
||||
const stateLink = withClientState({
|
||||
...merge(currentUser),
|
||||
cache,
|
||||
let refreshingTokenPromise: Promise<boolean> | undefined;
|
||||
let alreadyRefreshedToken = false;
|
||||
const errorLink = onError(({ graphQLErrors, networkError, forward, operation }) => {
|
||||
if (isServerError(networkError) && networkError.statusCode === 401 && !alreadyRefreshedToken) {
|
||||
if (!refreshingTokenPromise) refreshingTokenPromise = refreshAccessToken();
|
||||
|
||||
return promiseToObservable(refreshingTokenPromise).flatMap(() => {
|
||||
refreshingTokenPromise = undefined;
|
||||
alreadyRefreshedToken = true;
|
||||
|
||||
const context = operation.getContext();
|
||||
const oldHeaders = context.headers;
|
||||
|
||||
operation.setContext({
|
||||
headers: {
|
||||
...oldHeaders,
|
||||
authorization: generateTokenHeader(),
|
||||
},
|
||||
});
|
||||
|
||||
return forward(operation);
|
||||
});
|
||||
}
|
||||
|
||||
if (graphQLErrors) {
|
||||
graphQLErrors.forEach(({ message, locations, path }) =>
|
||||
console.log(`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`),
|
||||
);
|
||||
}
|
||||
|
||||
if (networkError) console.log(`[Network error]: ${networkError}`);
|
||||
});
|
||||
|
||||
const link = stateLink.concat(authMiddleware).concat(uploadLink);
|
||||
const link = authMiddleware
|
||||
.concat(errorLink)
|
||||
.concat(uploadLink);
|
||||
|
||||
const cache = new InMemoryCache({ fragmentMatcher });
|
||||
|
||||
const apolloClient = new ApolloClient({
|
||||
cache,
|
||||
link,
|
||||
connectToDevTools: true,
|
||||
resolvers: {
|
||||
currentUser: buildCurrentUserResolver(cache),
|
||||
},
|
||||
});
|
||||
|
||||
apolloClient.onResetStore(stateLink.writeDefaults as any);
|
||||
|
||||
export const apolloProvider = new VueApollo({
|
||||
defaultClient: apolloClient,
|
||||
errorHandler(error) {
|
||||
@@ -93,13 +126,65 @@ export function onLogin(apolloClient) {
|
||||
}
|
||||
|
||||
// Manually call this when user log out
|
||||
export async function onLogout(apolloClient: DollarApollo<any>) {
|
||||
export async function onLogout() {
|
||||
// if (apolloClient.wsClient) restartWebsockets(apolloClient.wsClient);
|
||||
|
||||
try {
|
||||
await apolloClient.provider.defaultClient.resetStore();
|
||||
await apolloClient.resetStore();
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('%cError on cache reset (logout)', 'color: orange;', e.message);
|
||||
}
|
||||
}
|
||||
|
||||
async function refreshAccessToken() {
|
||||
// Remove invalid access token, so the next request is not authenticated
|
||||
localStorage.removeItem(AUTH_ACCESS_TOKEN);
|
||||
|
||||
const refreshToken = localStorage.getItem(AUTH_REFRESH_TOKEN);
|
||||
|
||||
console.log('Refreshing access token.');
|
||||
|
||||
try {
|
||||
const res = await apolloClient.mutate({
|
||||
mutation: REFRESH_TOKEN,
|
||||
variables: {
|
||||
refreshToken,
|
||||
},
|
||||
});
|
||||
|
||||
saveTokenData(res.data.refreshToken);
|
||||
|
||||
return true;
|
||||
} catch (err) {
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function generateTokenHeader() {
|
||||
const token = localStorage.getItem(AUTH_ACCESS_TOKEN);
|
||||
|
||||
return token ? `Bearer ${token}` : null;
|
||||
}
|
||||
|
||||
// Thanks: https://github.com/apollographql/apollo-link/issues/747#issuecomment-502676676
|
||||
const promiseToObservable = <T> (promise: Promise<T>) => {
|
||||
return new Observable<T>((subscriber) => {
|
||||
promise.then(
|
||||
(value) => {
|
||||
if (subscriber.closed) {
|
||||
return;
|
||||
}
|
||||
subscriber.next(value);
|
||||
subscriber.complete();
|
||||
},
|
||||
(err) => {
|
||||
console.error('Cannot refresh token.', err);
|
||||
|
||||
subscriber.error(err);
|
||||
logout(apolloClient);
|
||||
},
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
35
js/yarn.lock
35
js/yarn.lock
@@ -1845,6 +1845,15 @@ apollo-link-dedup@^1.0.0:
|
||||
apollo-link "^1.2.12"
|
||||
tslib "^1.9.3"
|
||||
|
||||
apollo-link-error@^1.1.11:
|
||||
version "1.1.11"
|
||||
resolved "https://registry.yarnpkg.com/apollo-link-error/-/apollo-link-error-1.1.11.tgz#7cd363179616fb90da7866cee85cb00ee45d2f3b"
|
||||
integrity sha512-442DNqn3CNRikDaenMMkoDmCRmkoUx/XyUMlRTZBEFdTw3FYPQLsmDO3hzzC4doY5/BHcn9/jdYh9EeLx4HPsA==
|
||||
dependencies:
|
||||
apollo-link "^1.2.12"
|
||||
apollo-link-http-common "^0.2.14"
|
||||
tslib "^1.9.3"
|
||||
|
||||
apollo-link-http-common@^0.2.14, apollo-link-http-common@^0.2.4:
|
||||
version "0.2.14"
|
||||
resolved "https://registry.yarnpkg.com/apollo-link-http-common/-/apollo-link-http-common-0.2.14.tgz#d3a195c12e00f4e311c417f121181dcc31f7d0c8"
|
||||
@@ -1863,14 +1872,6 @@ apollo-link-http@^1.3.2, apollo-link-http@^1.5.14:
|
||||
apollo-link-http-common "^0.2.14"
|
||||
tslib "^1.9.3"
|
||||
|
||||
apollo-link-state@^0.4.2:
|
||||
version "0.4.2"
|
||||
resolved "https://registry.yarnpkg.com/apollo-link-state/-/apollo-link-state-0.4.2.tgz#ac00e9be9b0ca89eae0be6ba31fe904b80bbe2e8"
|
||||
integrity sha512-xMPcAfuiPVYXaLwC6oJFIZrKgV3GmdO31Ag2eufRoXpvT0AfJZjdaPB4450Nu9TslHRePN9A3quxNueILlQxlw==
|
||||
dependencies:
|
||||
apollo-utilities "^1.0.8"
|
||||
graphql-anywhere "^4.1.0-alpha.0"
|
||||
|
||||
apollo-link@^1.0.0, apollo-link@^1.0.7, apollo-link@^1.2.11, apollo-link@^1.2.12:
|
||||
version "1.2.12"
|
||||
resolved "https://registry.yarnpkg.com/apollo-link/-/apollo-link-1.2.12.tgz#014b514fba95f1945c38ad4c216f31bcfee68429"
|
||||
@@ -1890,7 +1891,7 @@ apollo-utilities@1.2.1:
|
||||
ts-invariant "^0.2.1"
|
||||
tslib "^1.9.3"
|
||||
|
||||
apollo-utilities@1.3.2, apollo-utilities@^1.0.8, apollo-utilities@^1.2.1, apollo-utilities@^1.3.0, apollo-utilities@^1.3.2:
|
||||
apollo-utilities@1.3.2, apollo-utilities@^1.2.1, apollo-utilities@^1.3.0, apollo-utilities@^1.3.2:
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/apollo-utilities/-/apollo-utilities-1.3.2.tgz#8cbdcf8b012f664cd6cb5767f6130f5aed9115c9"
|
||||
integrity sha512-JWNHj8XChz7S4OZghV6yc9FNnzEXj285QYp/nLNh943iObycI5GTDO3NGR9Dth12LRrSFMeDOConPfPln+WGfg==
|
||||
@@ -4931,15 +4932,6 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6
|
||||
resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
|
||||
integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=
|
||||
|
||||
graphql-anywhere@^4.1.0-alpha.0:
|
||||
version "4.2.4"
|
||||
resolved "https://registry.yarnpkg.com/graphql-anywhere/-/graphql-anywhere-4.2.4.tgz#7f1c08c9348c730c6bb5e818c81f0b72c13696a8"
|
||||
integrity sha512-rN6Op5vle0Ucqo8uOVPuFzRz1L/MB+ZVa+XezhFcQ6iP13vy95HOXRysrRtWcu2kQQTLyukSGmfU08D8LXWSIw==
|
||||
dependencies:
|
||||
apollo-utilities "^1.3.2"
|
||||
ts-invariant "^0.3.2"
|
||||
tslib "^1.9.3"
|
||||
|
||||
graphql-tag@^2.10.1:
|
||||
version "2.10.1"
|
||||
resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.10.1.tgz#10aa41f1cd8fae5373eaf11f1f67260a3cad5e02"
|
||||
@@ -10196,13 +10188,6 @@ ts-invariant@^0.2.1:
|
||||
dependencies:
|
||||
tslib "^1.9.3"
|
||||
|
||||
ts-invariant@^0.3.2:
|
||||
version "0.3.3"
|
||||
resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.3.3.tgz#b5742b1885ecf9e29c31a750307480f045ec0b16"
|
||||
integrity sha512-UReOKsrJFGC9tUblgSRWo+BsVNbEd77Cl6WiV/XpMlkifXwNIJbknViCucHvVZkXSC/mcWeRnIGdY7uprcwvdQ==
|
||||
dependencies:
|
||||
tslib "^1.9.3"
|
||||
|
||||
ts-invariant@^0.4.0:
|
||||
version "0.4.4"
|
||||
resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.4.4.tgz#97a523518688f93aafad01b0e80eb803eb2abd86"
|
||||
|
||||
Reference in New Issue
Block a user