feat: introduce extra telemetry info for teams and backend operations
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
// TODO: fix cache
|
||||
import { ref } from "vue"
|
||||
import {
|
||||
createClient,
|
||||
@@ -9,10 +8,11 @@ import {
|
||||
makeOperation,
|
||||
createRequest,
|
||||
subscriptionExchange,
|
||||
errorExchange,
|
||||
CombinedError,
|
||||
Operation,
|
||||
} from "@urql/core"
|
||||
import { authExchange } from "@urql/exchange-auth"
|
||||
// import { offlineExchange } from "@urql/exchange-graphcache"
|
||||
// import { makeDefaultStorage } from "@urql/exchange-graphcache/default-storage"
|
||||
import { devtoolsExchange } from "@urql/devtools"
|
||||
import { SubscriptionClient } from "subscriptions-transport-ws"
|
||||
import * as E from "fp-ts/Either"
|
||||
@@ -20,11 +20,6 @@ import * as TE from "fp-ts/TaskEither"
|
||||
import { pipe, constVoid, flow } from "fp-ts/function"
|
||||
import { subscribe, pipe as wonkaPipe } from "wonka"
|
||||
import { filter, map, Subject } from "rxjs"
|
||||
// import { keyDefs } from "./caching/keys"
|
||||
// import { optimisticDefs } from "./caching/optimistic"
|
||||
// import { updatesDef } from "./caching/updates"
|
||||
// import { resolversDef } from "./caching/resolvers"
|
||||
// import schema from "./backend-schema.json"
|
||||
import {
|
||||
authIdToken$,
|
||||
getAuthIDToken,
|
||||
@@ -32,15 +27,25 @@ import {
|
||||
waitProbableLoginToConfirm,
|
||||
} from "~/helpers/fb/auth"
|
||||
|
||||
// TODO: Implement caching
|
||||
|
||||
const BACKEND_GQL_URL =
|
||||
import.meta.env.VITE_BACKEND_GQL_URL ?? "https://api.hoppscotch.io/graphql"
|
||||
const BACKEND_WS_URL =
|
||||
import.meta.env.VITE_BACKEND_WS_URL ?? "wss://api.hoppscotch.io/graphql"
|
||||
|
||||
// const storage = makeDefaultStorage({
|
||||
// idbName: "hoppcache-v1",
|
||||
// maxAge: 7,
|
||||
// })
|
||||
/**
|
||||
* A type that defines error events that are possible during backend operations on the GQLCLient
|
||||
*/
|
||||
export type GQLClientErrorEvent =
|
||||
| { type: "SUBSCRIPTION_CONN_CALLBACK_ERR_REPORT"; errors: Error[] }
|
||||
| { type: "CLIENT_REPORTED_ERROR"; error: CombinedError; op: Operation }
|
||||
|
||||
/**
|
||||
* A stream of the errors that occur during GQLClient operations.
|
||||
* Exposed to be subscribed to by systems like sentry for error reporting
|
||||
*/
|
||||
export const gqlClientError$ = new Subject<GQLClientErrorEvent>()
|
||||
|
||||
const subscriptionClient = new SubscriptionClient(BACKEND_WS_URL, {
|
||||
reconnect: true,
|
||||
@@ -49,6 +54,14 @@ const subscriptionClient = new SubscriptionClient(BACKEND_WS_URL, {
|
||||
authorization: `Bearer ${authIdToken$.value}`,
|
||||
}
|
||||
},
|
||||
connectionCallback(error) {
|
||||
if (error?.length > 0) {
|
||||
gqlClientError$.next({
|
||||
type: "SUBSCRIPTION_CONN_CALLBACK_ERR_REPORT",
|
||||
errors: error,
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
authIdToken$.subscribe(() => {
|
||||
@@ -61,14 +74,6 @@ const createHoppClient = () =>
|
||||
exchanges: [
|
||||
devtoolsExchange,
|
||||
dedupExchange,
|
||||
// offlineExchange({
|
||||
// schema: schema as any,
|
||||
// keys: keyDefs,
|
||||
// optimistic: optimisticDefs,
|
||||
// updates: updatesDef,
|
||||
// resolvers: resolversDef,
|
||||
// storage,
|
||||
// }),
|
||||
authExchange({
|
||||
addAuthToOperation({ authState, operation }) {
|
||||
if (!authState || !authState.authToken) {
|
||||
@@ -109,6 +114,15 @@ const createHoppClient = () =>
|
||||
forwardSubscription: (operation) =>
|
||||
subscriptionClient.request(operation),
|
||||
}),
|
||||
errorExchange({
|
||||
onError(error, op) {
|
||||
gqlClientError$.next({
|
||||
type: "CLIENT_REPORTED_ERROR",
|
||||
error,
|
||||
op,
|
||||
})
|
||||
},
|
||||
}),
|
||||
],
|
||||
})
|
||||
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
import { GraphCacheKeysConfig } from "../graphql"
|
||||
|
||||
export const keyDefs: GraphCacheKeysConfig = {
|
||||
User: (data) => data.uid!,
|
||||
TeamMember: (data) => data.membershipID!,
|
||||
Team: (data) => data.id!,
|
||||
Shortcode: (data) => data.id!,
|
||||
TeamInvitation: (data) => data.id!,
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
import { GraphCacheOptimisticUpdaters } from "../graphql"
|
||||
|
||||
export const optimisticDefs: GraphCacheOptimisticUpdaters = {}
|
||||
@@ -1,31 +0,0 @@
|
||||
import {
|
||||
GraphCacheResolvers,
|
||||
Shortcode,
|
||||
Team,
|
||||
TeamInvitation,
|
||||
WithTypename,
|
||||
} from "../graphql"
|
||||
|
||||
export const resolversDef: GraphCacheResolvers = {
|
||||
Query: {
|
||||
team: (_parent, { teamID }) =>
|
||||
<WithTypename<Team>>{
|
||||
__typename: "Team" as const,
|
||||
id: teamID,
|
||||
},
|
||||
user: (_parent, { uid }) => ({
|
||||
__typename: "User",
|
||||
uid,
|
||||
}),
|
||||
teamInvitation: (_parent, args) =>
|
||||
<WithTypename<TeamInvitation>>{
|
||||
__typename: "TeamInvitation",
|
||||
id: args.inviteID,
|
||||
},
|
||||
shortcode: (_parent, args) =>
|
||||
<WithTypename<Shortcode>>{
|
||||
__typename: "Shortcode",
|
||||
id: args.code,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
import { gql } from "@urql/core"
|
||||
import { GraphCacheUpdaters } from "../graphql"
|
||||
|
||||
export const updatesDef: GraphCacheUpdaters = {
|
||||
Subscription: {
|
||||
teamMemberAdded: (_r, { teamID }, cache) => {
|
||||
cache.invalidate(
|
||||
{
|
||||
__typename: "Team",
|
||||
id: teamID,
|
||||
},
|
||||
"teamMembers"
|
||||
)
|
||||
},
|
||||
teamMemberUpdated: (_r, { teamID }, cache) => {
|
||||
cache.invalidate(
|
||||
{
|
||||
__typename: "Team",
|
||||
id: teamID,
|
||||
},
|
||||
"teamMembers"
|
||||
)
|
||||
|
||||
cache.invalidate(
|
||||
{
|
||||
__typename: "Team",
|
||||
id: teamID,
|
||||
},
|
||||
"myRole"
|
||||
)
|
||||
},
|
||||
teamMemberRemoved: (_r, { teamID }, cache) => {
|
||||
cache.invalidate(
|
||||
{
|
||||
__typename: "Team",
|
||||
id: teamID,
|
||||
},
|
||||
"teamMembers"
|
||||
)
|
||||
},
|
||||
teamInvitationAdded: (_r, { teamID }, cache) => {
|
||||
cache.invalidate(
|
||||
{
|
||||
__typename: "Team",
|
||||
id: teamID,
|
||||
},
|
||||
"teamInvitations"
|
||||
)
|
||||
},
|
||||
teamInvitationRemoved: (_r, { teamID }, cache) => {
|
||||
cache.invalidate(
|
||||
{
|
||||
__typename: "Team",
|
||||
id: teamID,
|
||||
},
|
||||
"teamInvitations"
|
||||
)
|
||||
},
|
||||
},
|
||||
Mutation: {
|
||||
createTeamInvitation: (result, _args, cache) => {
|
||||
cache.invalidate(
|
||||
{
|
||||
__typename: "Team",
|
||||
id: result.createTeamInvitation.teamID!,
|
||||
},
|
||||
"teamInvitations"
|
||||
)
|
||||
},
|
||||
acceptTeamInvitation: (_result, _args, cache) => {
|
||||
cache.invalidate({ __typename: "Query" }, "myTeams")
|
||||
},
|
||||
revokeTeamInvitation: (_result, args, cache) => {
|
||||
const targetTeamID = cache.resolve(
|
||||
{
|
||||
__typename: "TeamInvitation",
|
||||
id: args.inviteID,
|
||||
},
|
||||
"teamID"
|
||||
)
|
||||
|
||||
if (typeof targetTeamID === "string") {
|
||||
const newInvites = (
|
||||
cache.resolve(
|
||||
{
|
||||
__typename: "Team",
|
||||
id: targetTeamID,
|
||||
},
|
||||
"teamInvitations"
|
||||
) as string[]
|
||||
).filter(
|
||||
(inviteKey) =>
|
||||
inviteKey !==
|
||||
cache.keyOfEntity({
|
||||
__typename: "TeamInvitation",
|
||||
id: args.inviteID,
|
||||
})
|
||||
)
|
||||
|
||||
cache.link(
|
||||
{ __typename: "Team", id: targetTeamID },
|
||||
"teamInvitations",
|
||||
newInvites
|
||||
)
|
||||
}
|
||||
},
|
||||
createShortcode: (result, _args, cache) => {
|
||||
cache.writeFragment(
|
||||
gql`
|
||||
fragment _ on Shortcode {
|
||||
id
|
||||
request
|
||||
}
|
||||
`,
|
||||
{
|
||||
id: result.createShortcode.id,
|
||||
request: result.createShortcode.request,
|
||||
}
|
||||
)
|
||||
},
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user