build: switch from yarn to npm to manage js dependencies and move js contents to root
yarn v1 is being deprecated and starts to have some issues Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
212
src/apollo/utils.ts
Normal file
212
src/apollo/utils.ts
Normal file
@@ -0,0 +1,212 @@
|
||||
import { AUTH_ACCESS_TOKEN, AUTH_REFRESH_TOKEN } from "@/constants";
|
||||
import { REFRESH_TOKEN } from "@/graphql/auth";
|
||||
import { IFollower } from "@/types/actor/follower.model";
|
||||
import { IParticipant } from "@/types/participant.model";
|
||||
import { Paginate } from "@/types/paginate";
|
||||
import { saveTokenData } from "@/utils/auth";
|
||||
import { FieldPolicy, Reference, TypePolicies } from "@apollo/client/core";
|
||||
import introspectionQueryResultData from "../../fragmentTypes.json";
|
||||
import { IMember } from "@/types/actor/member.model";
|
||||
import { IComment } from "@/types/comment.model";
|
||||
import { IEvent } from "@/types/event.model";
|
||||
import { IActivity } from "@/types/activity.model";
|
||||
import uniqBy from "lodash/uniqBy";
|
||||
import { provideApolloClient, useMutation } from "@vue/apollo-composable";
|
||||
import { apolloClient } from "@/vue-apollo";
|
||||
import { IToken } from "@/types/login.model";
|
||||
|
||||
type possibleTypes = { name: string };
|
||||
type schemaType = {
|
||||
kind: string;
|
||||
name: string;
|
||||
possibleTypes: possibleTypes[];
|
||||
};
|
||||
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
const types = introspectionQueryResultData.__schema.types as schemaType[];
|
||||
export const possibleTypes = types.reduce(
|
||||
(acc, type) => {
|
||||
if (type.kind === "INTERFACE") {
|
||||
acc[type.name] = type.possibleTypes.map(({ name }) => name);
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, string[]>
|
||||
);
|
||||
|
||||
const replaceMergePolicy = <TExisting = any, TIncoming = any>(
|
||||
_existing: TExisting,
|
||||
incoming: TIncoming
|
||||
): TIncoming => incoming;
|
||||
|
||||
export const typePolicies: TypePolicies = {
|
||||
Discussion: {
|
||||
fields: {
|
||||
comments: paginatedLimitPagination<IComment>(),
|
||||
},
|
||||
},
|
||||
Conversation: {
|
||||
fields: {
|
||||
comments: paginatedLimitPagination<IComment>(),
|
||||
},
|
||||
},
|
||||
Group: {
|
||||
fields: {
|
||||
organizedEvents: paginatedLimitPagination([
|
||||
"afterDatetime",
|
||||
"beforeDatetime",
|
||||
]),
|
||||
activity: paginatedLimitPagination<IActivity>(["type", "author"]),
|
||||
},
|
||||
},
|
||||
Person: {
|
||||
fields: {
|
||||
organizedEvents: paginatedLimitPagination<IEvent>(),
|
||||
participations: paginatedLimitPagination<IParticipant>(["eventId"]),
|
||||
memberships: paginatedLimitPagination<IMember>(["group"]),
|
||||
},
|
||||
},
|
||||
Event: {
|
||||
fields: {
|
||||
participants: paginatedLimitPagination<IParticipant>(["roles"]),
|
||||
comments: pageLimitPagination<IComment>(),
|
||||
relatedEvents: pageLimitPagination<IEvent>(),
|
||||
options: { merge: replaceMergePolicy },
|
||||
participantStats: { merge: replaceMergePolicy },
|
||||
},
|
||||
},
|
||||
Instance: {
|
||||
keyFields: ["domain"],
|
||||
},
|
||||
Config: {
|
||||
merge: true,
|
||||
},
|
||||
Address: {
|
||||
keyFields: ["id", "originId"],
|
||||
},
|
||||
RootQueryType: {
|
||||
fields: {
|
||||
relayFollowers: paginatedLimitPagination<IFollower>(),
|
||||
relayFollowings: paginatedLimitPagination<IFollower>([
|
||||
"orderBy",
|
||||
"direction",
|
||||
]),
|
||||
events: paginatedLimitPagination(),
|
||||
groups: paginatedLimitPagination([
|
||||
"preferredUsername",
|
||||
"name",
|
||||
"domain",
|
||||
"local",
|
||||
"suspended",
|
||||
]),
|
||||
persons: paginatedLimitPagination([
|
||||
"preferredUsername",
|
||||
"name",
|
||||
"domain",
|
||||
"local",
|
||||
"suspended",
|
||||
]),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export async function refreshAccessToken(): Promise<boolean> {
|
||||
// Remove invalid access token, so the next request is not authenticated
|
||||
localStorage.removeItem(AUTH_ACCESS_TOKEN);
|
||||
|
||||
const refreshToken = localStorage.getItem(AUTH_REFRESH_TOKEN);
|
||||
|
||||
if (!refreshToken) {
|
||||
console.debug("Refresh token not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
console.debug("Refreshing access token.");
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const { mutate, onDone, onError } = provideApolloClient(apolloClient)(() =>
|
||||
useMutation<{ refreshToken: IToken }>(REFRESH_TOKEN)
|
||||
);
|
||||
|
||||
mutate({
|
||||
refreshToken,
|
||||
});
|
||||
|
||||
onDone(({ data }) => {
|
||||
if (data?.refreshToken) {
|
||||
saveTokenData(data?.refreshToken);
|
||||
resolve(true);
|
||||
}
|
||||
reject(false);
|
||||
});
|
||||
|
||||
onError((err) => {
|
||||
console.debug("Failed to refresh token", err);
|
||||
reject(false);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
type KeyArgs = FieldPolicy<any>["keyArgs"];
|
||||
|
||||
export function pageLimitPagination<T = Reference>(
|
||||
keyArgs: KeyArgs = false
|
||||
): FieldPolicy<T[]> {
|
||||
return {
|
||||
keyArgs,
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
merge(existing, incoming, { args }) {
|
||||
if (!incoming) return existing;
|
||||
if (!existing) return incoming; // existing will be empty the first time
|
||||
|
||||
return doMerge(existing as Array<T>, incoming as Array<T>, args);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function paginatedLimitPagination<T = Paginate<any>>(
|
||||
keyArgs: KeyArgs = false
|
||||
): FieldPolicy<Paginate<T>> {
|
||||
return {
|
||||
keyArgs,
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
merge(existing, incoming, { args }) {
|
||||
if (!incoming) return existing;
|
||||
if (!existing) return incoming; // existing will be empty the first time
|
||||
|
||||
return {
|
||||
total: incoming.total,
|
||||
elements: doMerge(existing.elements, incoming.elements, args),
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function doMerge<T = any>(
|
||||
existing: Array<T>,
|
||||
incoming: Array<T>,
|
||||
args: Record<string, any> | null
|
||||
): Array<T> {
|
||||
const merged = existing && Array.isArray(existing) ? existing.slice(0) : [];
|
||||
const previous = incoming && Array.isArray(incoming) ? incoming.slice(0) : [];
|
||||
let res;
|
||||
if (args) {
|
||||
// Assume an page of 1 if args.page omitted.
|
||||
const { page = 1, limit = 10 } = args;
|
||||
for (let i = 0; i < previous.length; ++i) {
|
||||
merged[(page - 1) * limit + i] = previous[i];
|
||||
}
|
||||
res = merged;
|
||||
} else {
|
||||
// It's unusual (probably a mistake) for a paginated field not
|
||||
// to receive any arguments, so you might prefer to throw an
|
||||
// exception here, instead of recovering by appending incoming
|
||||
// onto the existing array.
|
||||
res = [...merged, ...previous];
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
res = uniqBy(res, (elem: any) => elem.__ref);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
Reference in New Issue
Block a user