From dd0653bb57c00087815675074718fc50142b2310 Mon Sep 17 00:00:00 2001
From: Frank <frank.pfeift@protonmail.com>
Date: Tue, 9 Jan 2024 12:51:03 +0100
Subject: [PATCH] fix: definitions error

---
 api/src/generated/nexus.ts                    | 192 ++++++++----------
 api/src/generated/schema.graphql              | 104 +++++-----
 api/src/modules/DocumentDrive/definitions.ts  |  74 ++++++-
 .../DocumentDrive/mutations/deleteListener.ts |   0
 .../modules/DocumentDrive/mutations/index.ts  |  21 +-
 .../DocumentDrive/mutations/pushUpdates.ts    |  19 ++
 .../mutations/registerListener.ts             |   0
 .../DocumentDrive/mutations/updateListener.ts |   0
 .../modules/DocumentDrive/queries/index.ts    |   1 +
 .../DocumentDrive/queries/pullUpdates.ts      |  50 +++++
 10 files changed, 288 insertions(+), 173 deletions(-)
 create mode 100644 api/src/modules/DocumentDrive/mutations/deleteListener.ts
 create mode 100644 api/src/modules/DocumentDrive/mutations/pushUpdates.ts
 create mode 100644 api/src/modules/DocumentDrive/mutations/registerListener.ts
 create mode 100644 api/src/modules/DocumentDrive/mutations/updateListener.ts
 create mode 100644 api/src/modules/DocumentDrive/queries/pullUpdates.ts

diff --git a/api/src/generated/nexus.ts b/api/src/generated/nexus.ts
index 2e258dee..a1869c67 100644
--- a/api/src/generated/nexus.ts
+++ b/api/src/generated/nexus.ts
@@ -40,26 +40,6 @@ declare global {
 }
 
 export interface NexusGenInputs {
-  AddFileInput: { // input type
-    documentType: string; // String!
-    id: string; // ID!
-    name: string; // String!
-    parentFolder?: string | null; // ID
-  }
-  AddFolderInput: { // input type
-    id: string; // ID!
-    name: string; // String!
-    parentFolder?: string | null; // ID
-  }
-  CopyNodeInput: { // input type
-    srcId: string; // ID!
-    targetId: string; // ID!
-    targetName?: string | null; // String
-    targetParentFolder?: string | null; // ID
-  }
-  DeleteNodeInput: { // input type
-    id: string; // ID!
-  }
   DocumentDriveLocalStateInput: { // input type
     availableOffline: boolean; // Boolean!
     sharingType?: string | null; // String
@@ -70,38 +50,37 @@ export interface NexusGenInputs {
     name: string; // String!
     remoteUrl?: string | null; // String
   }
-  MoveNodeInput: { // input type
-    srcFolder: string; // ID!
-    targetParentFolder?: string | null; // ID
+  InputListenerRevision: { // input type
+    branch: string; // String!
+    documentId: string; // String!
+    driveId: string; // String!
+    revision: number; // Int!
+    scope: string; // String!
+    status: NexusGenEnums['UpdateStatus']; // UpdateStatus!
   }
-  SessionInput: { // input type
-    allowedOrigins: string; // String!
-    expiryDurationSeconds?: number | null; // Int
+  InputOperationUpdate: { // input type
+    inputJson: string; // String!
     name: string; // String!
+    revision: number; // Int!
+    skip: number; // Int!
+    stateHash: string; // String!
   }
-  SetAvailableOfflineInput: { // input type
-    availableOffline: boolean; // Boolean!
+  InputStrandUpdate: { // input type
+    branch: string; // String!
+    documentId: string; // String!
+    driveId: string; // String!
+    operations: NexusGenInputs['InputOperationUpdate'][]; // [InputOperationUpdate!]!
+    scope: string; // String!
   }
-  SetDriveNameInput: { // input type
+  SessionInput: { // input type
+    allowedOrigins: string; // String!
+    expiryDurationSeconds?: number | null; // Int
     name: string; // String!
   }
-  SetSharingTypeInput: { // input type
-    type: string; // String!
-  }
-  UpdateFileInput: { // input type
-    documentType?: string | null; // String
-    id: string; // ID!
-    name?: string | null; // String
-    parentFolder?: string | null; // ID
-  }
-  UpdateNodeInput: { // input type
-    id: string; // ID!
-    name?: string | null; // String
-    parentFolder?: string | null; // ID
-  }
 }
 
 export interface NexusGenEnums {
+  UpdateStatus: "CONFLICT" | "ERROR" | "MISSING" | "SUCCESS"
 }
 
 export interface NexusGenScalars {
@@ -134,6 +113,13 @@ export interface NexusGenObjects {
     message: string; // String!
   }
   Mutation: {};
+  OperationUpdate: { // root type
+    inputJson: string; // String!
+    name: string; // String!
+    revision: number; // Int!
+    skip: number; // Int!
+    stateHash: string; // String!
+  }
   Query: {};
   Session: { // root type
     allowedOrigins?: string | null; // String
@@ -150,6 +136,13 @@ export interface NexusGenObjects {
     session: NexusGenRootTypes['Session']; // Session!
     token: string; // String!
   }
+  StrandUpdate: { // root type
+    branch: string; // String!
+    documentId: string; // String!
+    driveId: string; // String!
+    operations: NexusGenRootTypes['OperationUpdate'][]; // [OperationUpdate!]!
+    scope: string; // String!
+  }
   User: { // root type
     address: string; // String!
     createdAt: NexusGenScalars['Date']; // Date!
@@ -164,7 +157,7 @@ export interface NexusGenUnions {
 
 export type NexusGenRootTypes = NexusGenObjects
 
-export type NexusGenAllTypes = NexusGenRootTypes & NexusGenScalars
+export type NexusGenAllTypes = NexusGenRootTypes & NexusGenScalars & NexusGenEnums
 
 export interface NexusGenFieldTypes {
   Challenge: { // field return type
@@ -188,29 +181,30 @@ export interface NexusGenFieldTypes {
   }
   Mutation: { // field return type
     addDrive: boolean | null; // Boolean
-    addFile: boolean | null; // Boolean
-    addFolder: boolean | null; // Boolean
-    copyNode: boolean | null; // Boolean
     createChallenge: NexusGenRootTypes['Challenge'] | null; // Challenge
     createSession: NexusGenRootTypes['SessionOutput'] | null; // SessionOutput
     deleteDrive: boolean | null; // Boolean
-    deleteNode: boolean | null; // Boolean
-    moveNode: boolean | null; // Boolean
+    pushUpdates: boolean | null; // Boolean
     revokeSession: NexusGenRootTypes['Session'] | null; // Session
-    setAvailableOffline: boolean | null; // Boolean
-    setDriveName: boolean | null; // Boolean
-    setSharingType: boolean | null; // Boolean
     solveChallenge: NexusGenRootTypes['SessionOutput'] | null; // SessionOutput
-    updateFile: boolean | null; // Boolean
-    updateNode: boolean | null; // Boolean
+  }
+  OperationUpdate: { // field return type
+    inputJson: string; // String!
+    name: string; // String!
+    revision: number; // Int!
+    skip: number; // Int!
+    stateHash: string; // String!
   }
   Query: { // field return type
+    acknowledge: boolean | null; // Boolean
     coreUnit: NexusGenRootTypes['CoreUnit'] | null; // CoreUnit
     coreUnits: Array<NexusGenRootTypes['CoreUnit'] | null> | null; // [CoreUnit]
     countUsers: NexusGenRootTypes['Counter'] | null; // Counter
     drives: Array<string | null> | null; // [String]
     me: NexusGenRootTypes['User'] | null; // User
     sessions: Array<NexusGenRootTypes['Session'] | null> | null; // [Session]
+    strands: Array<NexusGenRootTypes['StrandUpdate'] | null> | null; // [StrandUpdate]
+    strandsSince: Array<NexusGenRootTypes['StrandUpdate'] | null> | null; // [StrandUpdate]
   }
   Session: { // field return type
     allowedOrigins: string | null; // String
@@ -227,6 +221,13 @@ export interface NexusGenFieldTypes {
     session: NexusGenRootTypes['Session']; // Session!
     token: string; // String!
   }
+  StrandUpdate: { // field return type
+    branch: string; // String!
+    documentId: string; // String!
+    driveId: string; // String!
+    operations: NexusGenRootTypes['OperationUpdate'][]; // [OperationUpdate!]!
+    scope: string; // String!
+  }
   User: { // field return type
     address: string; // String!
     createdAt: NexusGenScalars['Date']; // Date!
@@ -255,29 +256,30 @@ export interface NexusGenFieldTypeNames {
   }
   Mutation: { // field return type name
     addDrive: 'Boolean'
-    addFile: 'Boolean'
-    addFolder: 'Boolean'
-    copyNode: 'Boolean'
     createChallenge: 'Challenge'
     createSession: 'SessionOutput'
     deleteDrive: 'Boolean'
-    deleteNode: 'Boolean'
-    moveNode: 'Boolean'
+    pushUpdates: 'Boolean'
     revokeSession: 'Session'
-    setAvailableOffline: 'Boolean'
-    setDriveName: 'Boolean'
-    setSharingType: 'Boolean'
     solveChallenge: 'SessionOutput'
-    updateFile: 'Boolean'
-    updateNode: 'Boolean'
+  }
+  OperationUpdate: { // field return type name
+    inputJson: 'String'
+    name: 'String'
+    revision: 'Int'
+    skip: 'Int'
+    stateHash: 'String'
   }
   Query: { // field return type name
+    acknowledge: 'Boolean'
     coreUnit: 'CoreUnit'
     coreUnits: 'CoreUnit'
     countUsers: 'Counter'
     drives: 'String'
     me: 'User'
     sessions: 'Session'
+    strands: 'StrandUpdate'
+    strandsSince: 'StrandUpdate'
   }
   Session: { // field return type name
     allowedOrigins: 'String'
@@ -294,6 +296,13 @@ export interface NexusGenFieldTypeNames {
     session: 'Session'
     token: 'String'
   }
+  StrandUpdate: { // field return type name
+    branch: 'String'
+    documentId: 'String'
+    driveId: 'String'
+    operations: 'OperationUpdate'
+    scope: 'String'
+  }
   User: { // field return type name
     address: 'String'
     createdAt: 'Date'
@@ -306,18 +315,6 @@ export interface NexusGenArgTypes {
       global: NexusGenInputs['DocumentDriveStateInput']; // DocumentDriveStateInput!
       local: NexusGenInputs['DocumentDriveLocalStateInput']; // DocumentDriveLocalStateInput!
     }
-    addFile: { // args
-      drive: string; // String!
-      operation: NexusGenInputs['AddFileInput']; // AddFileInput!
-    }
-    addFolder: { // args
-      drive: string; // String!
-      operation: NexusGenInputs['AddFolderInput']; // AddFolderInput!
-    }
-    copyNode: { // args
-      drive: string; // String!
-      operation: NexusGenInputs['CopyNodeInput']; // CopyNodeInput!
-    }
     createChallenge: { // args
       address: string; // String!
     }
@@ -327,49 +324,36 @@ export interface NexusGenArgTypes {
     deleteDrive: { // args
       id: string; // String!
     }
-    deleteNode: { // args
-      drive: string; // String!
-      operation: NexusGenInputs['DeleteNodeInput']; // DeleteNodeInput!
-    }
-    moveNode: { // args
-      drive: string; // String!
-      operation: NexusGenInputs['MoveNodeInput']; // MoveNodeInput!
+    pushUpdates: { // args
+      strands?: NexusGenInputs['InputStrandUpdate'][] | null; // [InputStrandUpdate!]
     }
     revokeSession: { // args
       sessionId: string; // String!
     }
-    setAvailableOffline: { // args
-      drive: string; // String!
-      operation: NexusGenInputs['SetAvailableOfflineInput']; // SetAvailableOfflineInput!
-    }
-    setDriveName: { // args
-      drive: string; // String!
-      operation: NexusGenInputs['SetDriveNameInput']; // SetDriveNameInput!
-    }
-    setSharingType: { // args
-      drive: string; // String!
-      operation: NexusGenInputs['SetSharingTypeInput']; // SetSharingTypeInput!
-    }
     solveChallenge: { // args
       nonce: string; // String!
       signature: string; // String!
     }
-    updateFile: { // args
-      drive: string; // String!
-      operation: NexusGenInputs['UpdateFileInput']; // UpdateFileInput!
-    }
-    updateNode: { // args
-      drive: string; // String!
-      operation: NexusGenInputs['UpdateNodeInput']; // UpdateNodeInput!
-    }
   }
   Query: {
+    acknowledge: { // args
+      listenerId?: string | null; // ID
+      revisions?: Array<NexusGenInputs['InputListenerRevision'] | null> | null; // [InputListenerRevision]
+    }
     coreUnit: { // args
       id?: string | null; // String
     }
     countUsers: { // args
       message: string; // String!
     }
+    strands: { // args
+      listenerId?: string | null; // ID
+      revisions?: Array<NexusGenInputs['InputListenerRevision'] | null> | null; // [InputListenerRevision]
+    }
+    strandsSince: { // args
+      listenerId?: string | null; // ID
+      since?: NexusGenScalars['Date'] | null; // Date
+    }
   }
 }
 
@@ -383,7 +367,7 @@ export type NexusGenObjectNames = keyof NexusGenObjects;
 
 export type NexusGenInputNames = keyof NexusGenInputs;
 
-export type NexusGenEnumNames = never;
+export type NexusGenEnumNames = keyof NexusGenEnums;
 
 export type NexusGenInterfaceNames = never;
 
diff --git a/api/src/generated/schema.graphql b/api/src/generated/schema.graphql
index cbc00531..def3e48e 100644
--- a/api/src/generated/schema.graphql
+++ b/api/src/generated/schema.graphql
@@ -2,32 +2,12 @@
 ### Do not make changes to this file directly
 
 
-input AddFileInput {
-  documentType: String!
-  id: ID!
-  name: String!
-  parentFolder: ID
-}
-
-input AddFolderInput {
-  id: ID!
-  name: String!
-  parentFolder: ID
-}
-
 type Challenge {
   hex: String!
   message: String!
   nonce: String!
 }
 
-input CopyNodeInput {
-  srcId: ID!
-  targetId: ID!
-  targetName: String
-  targetParentFolder: ID
-}
-
 type CoreUnit {
   code: String
   descriptionParagraph: String
@@ -47,10 +27,6 @@ type Counter {
 """Date custom scalar type"""
 scalar Date
 
-input DeleteNodeInput {
-  id: ID!
-}
-
 input DocumentDriveLocalStateInput {
   availableOffline: Boolean!
   sharingType: String
@@ -63,37 +39,59 @@ input DocumentDriveStateInput {
   remoteUrl: String
 }
 
-input MoveNodeInput {
-  srcFolder: ID!
-  targetParentFolder: ID
+input InputListenerRevision {
+  branch: String!
+  documentId: String!
+  driveId: String!
+  revision: Int!
+  scope: String!
+  status: UpdateStatus!
+}
+
+input InputOperationUpdate {
+  inputJson: String!
+  name: String!
+  revision: Int!
+  skip: Int!
+  stateHash: String!
+}
+
+input InputStrandUpdate {
+  branch: String!
+  documentId: String!
+  driveId: String!
+  operations: [InputOperationUpdate!]!
+  scope: String!
 }
 
 type Mutation {
   addDrive(global: DocumentDriveStateInput!, local: DocumentDriveLocalStateInput!): Boolean
-  addFile(drive: String!, operation: AddFileInput!): Boolean
-  addFolder(drive: String!, operation: AddFolderInput!): Boolean
-  copyNode(drive: String!, operation: CopyNodeInput!): Boolean
   createChallenge(address: String!): Challenge
   createSession(session: SessionInput!): SessionOutput
   deleteDrive(id: String!): Boolean
-  deleteNode(drive: String!, operation: DeleteNodeInput!): Boolean
-  moveNode(drive: String!, operation: MoveNodeInput!): Boolean
+  pushUpdates(strands: [InputStrandUpdate!]): Boolean
   revokeSession(sessionId: String!): Session
-  setAvailableOffline(drive: String!, operation: SetAvailableOfflineInput!): Boolean
-  setDriveName(drive: String!, operation: SetDriveNameInput!): Boolean
-  setSharingType(drive: String!, operation: SetSharingTypeInput!): Boolean
   solveChallenge(nonce: String!, signature: String!): SessionOutput
-  updateFile(drive: String!, operation: UpdateFileInput!): Boolean
-  updateNode(drive: String!, operation: UpdateNodeInput!): Boolean
+}
+
+type OperationUpdate {
+  inputJson: String!
+  name: String!
+  revision: Int!
+  skip: Int!
+  stateHash: String!
 }
 
 type Query {
+  acknowledge(listenerId: ID, revisions: [InputListenerRevision]): Boolean
   coreUnit(id: String): CoreUnit
   coreUnits: [CoreUnit]
   countUsers(message: String!): Counter
   drives: [String]
   me: User
   sessions: [Session]
+  strands(listenerId: ID, revisions: [InputListenerRevision]): [StrandUpdate]
+  strandsSince(listenerId: ID, since: Date): [StrandUpdate]
 }
 
 type Session {
@@ -119,29 +117,19 @@ type SessionOutput {
   token: String!
 }
 
-input SetAvailableOfflineInput {
-  availableOffline: Boolean!
-}
-
-input SetDriveNameInput {
-  name: String!
-}
-
-input SetSharingTypeInput {
-  type: String!
-}
-
-input UpdateFileInput {
-  documentType: String
-  id: ID!
-  name: String
-  parentFolder: ID
+type StrandUpdate {
+  branch: String!
+  documentId: String!
+  driveId: String!
+  operations: [OperationUpdate!]!
+  scope: String!
 }
 
-input UpdateNodeInput {
-  id: ID!
-  name: String
-  parentFolder: ID
+enum UpdateStatus {
+  CONFLICT
+  ERROR
+  MISSING
+  SUCCESS
 }
 
 type User {
diff --git a/api/src/modules/DocumentDrive/definitions.ts b/api/src/modules/DocumentDrive/definitions.ts
index a05e8b61..8765c35f 100644
--- a/api/src/modules/DocumentDrive/definitions.ts
+++ b/api/src/modules/DocumentDrive/definitions.ts
@@ -1,4 +1,15 @@
-import { inputObjectType, interfaceType, objectType, unionType } from 'nexus';
+import {
+  arg,
+  enumType,
+  idArg,
+  inputObjectType,
+  interfaceType,
+  list,
+  nonNull,
+  objectType,
+  stringArg,
+  unionType,
+} from 'nexus';
 
 export const DocumentDriveLocalState = objectType({
   name: 'DocumentDriveLocalState',
@@ -153,3 +164,64 @@ export const DocumentDriveState = objectType({
     t.string('remoteUrl');
   },
 });
+
+// v2
+export const ListenerRevision = inputObjectType({
+  name: 'InputListenerRevision',
+  definition(t) {
+    t.nonNull.string('driveId');
+    t.nonNull.string('documentId');
+    t.nonNull.string('scope');
+    t.nonNull.string('branch');
+    t.nonNull.field('status', { type: UpdateStatus });
+    t.nonNull.int('revision');
+  },
+});
+export const OperationUpdate = objectType({
+  name: 'OperationUpdate',
+  definition(t) {
+    t.nonNull.int('revision');
+    t.nonNull.int('skip');
+    t.nonNull.string('name');
+    t.nonNull.string('inputJson');
+    t.nonNull.string('stateHash');
+  },
+});
+
+export const InputOperationUpdate = inputObjectType({
+  name: 'InputOperationUpdate',
+  definition(t) {
+    t.nonNull.int('revision');
+    t.nonNull.int('skip');
+    t.nonNull.string('name');
+    t.nonNull.string('inputJson');
+    t.nonNull.string('stateHash');
+  },
+});
+
+export const StrandUpdate = objectType({
+  name: 'StrandUpdate',
+  definition(t) {
+    t.nonNull.string('driveId');
+    t.nonNull.string('documentId');
+    t.nonNull.string('scope');
+    t.nonNull.string('branch');
+    t.nonNull.list.nonNull.field('operations', { type: OperationUpdate });
+  },
+});
+
+export const InputStrandUpdate = inputObjectType({
+  name: 'InputStrandUpdate',
+  definition(t) {
+    t.nonNull.string('driveId');
+    t.nonNull.string('documentId');
+    t.nonNull.string('scope');
+    t.nonNull.string('branch');
+    t.nonNull.list.nonNull.field('operations', { type: InputOperationUpdate });
+  },
+});
+
+export const UpdateStatus = enumType({
+  name: 'UpdateStatus',
+  members: ['SUCCESS', 'MISSING', 'CONFLICT', 'ERROR'],
+});
diff --git a/api/src/modules/DocumentDrive/mutations/deleteListener.ts b/api/src/modules/DocumentDrive/mutations/deleteListener.ts
new file mode 100644
index 00000000..e69de29b
diff --git a/api/src/modules/DocumentDrive/mutations/index.ts b/api/src/modules/DocumentDrive/mutations/index.ts
index d5c2fa42..ec278d52 100644
--- a/api/src/modules/DocumentDrive/mutations/index.ts
+++ b/api/src/modules/DocumentDrive/mutations/index.ts
@@ -1,12 +1,13 @@
-export * from './addFile';
-export * from './addFolder';
+// export * from './addFile';
+// export * from './addFolder';
 export * from './addDrive';
-export * from './copyNode';
+// export * from './copyNode';
 export * from './deleteDrive';
-export * from './deleteNode';
-export * from './moveNode';
-export * from './setAvailableOffline';
-export * from './setDriveName';
-export * from './setSharingType';
-export * from './updateFile';
-export * from './updateNode';
+// export * from './deleteNode';
+// export * from './moveNode';
+// export * from './setAvailableOffline';
+// export * from './setDriveName';
+// export * from './setSharingType';
+// export * from './updateFile';
+// export * from './updateNode';
+export * from './pushUpdates';
diff --git a/api/src/modules/DocumentDrive/mutations/pushUpdates.ts b/api/src/modules/DocumentDrive/mutations/pushUpdates.ts
new file mode 100644
index 00000000..4401fc51
--- /dev/null
+++ b/api/src/modules/DocumentDrive/mutations/pushUpdates.ts
@@ -0,0 +1,19 @@
+import { list, mutationField, nonNull } from 'nexus';
+import { InputStrandUpdate } from '../definitions';
+
+export const pushUpdates = mutationField('pushUpdates', {
+  type: 'Boolean',
+  args: {
+    strands: list(nonNull(InputStrandUpdate)),
+  },
+  resolve: async (_parent, args, ctx) => {
+    try {
+      //@todo: get connect drive server from ctx and apply updates
+    } catch (e) {
+      console.log(e);
+      return false;
+    }
+
+    return true;
+  },
+});
diff --git a/api/src/modules/DocumentDrive/mutations/registerListener.ts b/api/src/modules/DocumentDrive/mutations/registerListener.ts
new file mode 100644
index 00000000..e69de29b
diff --git a/api/src/modules/DocumentDrive/mutations/updateListener.ts b/api/src/modules/DocumentDrive/mutations/updateListener.ts
new file mode 100644
index 00000000..e69de29b
diff --git a/api/src/modules/DocumentDrive/queries/index.ts b/api/src/modules/DocumentDrive/queries/index.ts
index eff1340d..2d98fbef 100644
--- a/api/src/modules/DocumentDrive/queries/index.ts
+++ b/api/src/modules/DocumentDrive/queries/index.ts
@@ -1,2 +1,3 @@
 // export * from './drive';
 export * from './drives';
+export * from './pullUpdates';
diff --git a/api/src/modules/DocumentDrive/queries/pullUpdates.ts b/api/src/modules/DocumentDrive/queries/pullUpdates.ts
new file mode 100644
index 00000000..ba94764f
--- /dev/null
+++ b/api/src/modules/DocumentDrive/queries/pullUpdates.ts
@@ -0,0 +1,50 @@
+import { idArg, list, nonNull, queryField, stringArg } from 'nexus';
+import { ListenerRevision, StrandUpdate } from '../definitions';
+
+export const strands = queryField('strands', {
+  type: list(StrandUpdate),
+  args: {
+    listenerId: idArg(),
+    revisions: list(ListenerRevision),
+  },
+  resolve: async (_parent, args, ctx) => {
+    try {
+      // @todo: fetch strands from connect drive server
+      return [];
+    } catch (e) {
+      return [];
+    }
+  },
+});
+
+export const strandsSince = queryField('strandsSince', {
+  type: list(StrandUpdate),
+  args: {
+    listenerId: idArg(),
+    since: 'Date',
+  },
+  resolve: async (_parent, args, ctx) => {
+    try {
+      // @todo: fetch strands from connect drive server
+      return [];
+    } catch (e) {
+      return [];
+    }
+  },
+});
+
+export const acknowledge = queryField('acknowledge', {
+  type: 'Boolean',
+  args: {
+    listenerId: idArg(),
+    revisions: list(ListenerRevision),
+  },
+  resolve: async (_parent, args, ctx) => {
+    try {
+      // do something
+      return true;
+    } catch (e) {
+      return false;
+    }
+  },
+});