-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(partners): setup graphql server
- Loading branch information
Showing
12 changed files
with
280 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
import { cookies } from "next/headers"; | ||
import { createYoga } from "graphql-yoga"; | ||
import { getSession, lucia } from "@/lib/auth"; | ||
import persistedOperations from "@/persisted-operations.json"; | ||
import { partners_schema, initContextCache } from "@umamin/gql"; | ||
import { useResponseCache } from "@graphql-yoga/plugin-response-cache"; | ||
import { useCSRFPrevention } from "@graphql-yoga/plugin-csrf-prevention"; | ||
import { usePersistedOperations } from "@graphql-yoga/plugin-persisted-operations"; | ||
import { useDisableIntrospection } from "@graphql-yoga/plugin-disable-introspection"; | ||
|
||
const { handleRequest } = createYoga({ | ||
schema: partners_schema, | ||
context: async () => { | ||
const { session } = await getSession(); | ||
|
||
return { | ||
...initContextCache(), | ||
userId: session?.userId, | ||
}; | ||
}, | ||
graphqlEndpoint: "/api/graphql", | ||
graphiql: process.env.NODE_ENV === "development", | ||
fetchAPI: { Response }, | ||
cors: { | ||
origin: | ||
process.env.NODE_ENV === "production" | ||
? "https://www.umamin.link" | ||
: "http://localhost:3000", | ||
credentials: true, | ||
methods: ["POST", "GET", "OPTIONS"], | ||
allowedHeaders: ["Content-Type", "Authorization"], | ||
}, | ||
plugins: [ | ||
useCSRFPrevention({ | ||
requestHeaders: ["x-graphql-yoga-csrf"], | ||
}), | ||
useResponseCache({ | ||
session: () => cookies().get(lucia.sessionCookieName)?.value, | ||
invalidateViaMutation: false, | ||
scopePerSchemaCoordinate: { | ||
"Query.user": "PRIVATE", | ||
"Query.note": "PRIVATE", | ||
"Query.messages": "PRIVATE", | ||
"Query.messagesFromCursor": "PRIVATE", | ||
}, | ||
ttl: 30_000, | ||
ttlPerSchemaCoordinate: { | ||
"Query.notes": 120_000, | ||
"Query.notesFromCursor": 120_000, | ||
"Query.userByUsername": 120_000, | ||
}, | ||
}), | ||
useDisableIntrospection({ | ||
isDisabled: () => process.env.NODE_ENV === "production", | ||
}), | ||
usePersistedOperations({ | ||
allowArbitraryOperations: process.env.NODE_ENV === "development", | ||
customErrors: { | ||
notFound: { | ||
message: "Operation is not found", | ||
extensions: { | ||
http: { | ||
status: 404, | ||
}, | ||
}, | ||
}, | ||
keyNotFound: { | ||
message: "Key is not found", | ||
extensions: { | ||
http: { | ||
status: 404, | ||
}, | ||
}, | ||
}, | ||
persistedQueryOnly: { | ||
message: "Operation is not allowed", | ||
extensions: { | ||
http: { | ||
status: 403, | ||
}, | ||
}, | ||
}, | ||
}, | ||
skipDocumentValidation: true, | ||
async getPersistedOperation(key: string) { | ||
// @ts-ignore | ||
return persistedOperations[key]; | ||
}, | ||
}), | ||
], | ||
}); | ||
|
||
export { | ||
handleRequest as GET, | ||
handleRequest as POST, | ||
handleRequest as OPTIONS, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
/* eslint-disable */ | ||
/* prettier-ignore */ | ||
|
||
export type introspection_types = { | ||
'Boolean': unknown; | ||
'CreateMessageInput': { kind: 'INPUT_OBJECT'; name: 'CreateMessageInput'; isOneOf: false; inputFields: [{ name: 'content'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; }; defaultValue: null }, { name: 'question'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; }; defaultValue: null }, { name: 'receiverId'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; }; defaultValue: null }, { name: 'senderId'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; }; defaultValue: null }]; }; | ||
'CursorInput': { kind: 'INPUT_OBJECT'; name: 'CursorInput'; isOneOf: false; inputFields: [{ name: 'createdAt'; type: { kind: 'SCALAR'; name: 'Int'; ofType: null; }; defaultValue: null }, { name: 'id'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; }; defaultValue: null }]; }; | ||
'ID': unknown; | ||
'Int': unknown; | ||
'Message': { kind: 'OBJECT'; name: 'Message'; fields: { 'content': { name: 'content'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'createdAt': { name: 'createdAt'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'Int'; ofType: null; }; } }; 'id': { name: 'id'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'ID'; ofType: null; }; } }; 'question': { name: 'question'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'receiverId': { name: 'receiverId'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'reply': { name: 'reply'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; } }; 'updatedAt': { name: 'updatedAt'; type: { kind: 'SCALAR'; name: 'Int'; ofType: null; } }; }; }; | ||
'MessageCursor': { kind: 'OBJECT'; name: 'MessageCursor'; fields: { 'createdAt': { name: 'createdAt'; type: { kind: 'SCALAR'; name: 'Int'; ofType: null; } }; 'id': { name: 'id'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; } }; }; }; | ||
'MessagesFromCursorInput': { kind: 'INPUT_OBJECT'; name: 'MessagesFromCursorInput'; isOneOf: false; inputFields: [{ name: 'cursor'; type: { kind: 'INPUT_OBJECT'; name: 'CursorInput'; ofType: null; }; defaultValue: null }, { name: 'limit'; type: { kind: 'SCALAR'; name: 'Int'; ofType: null; }; defaultValue: null }, { name: 'type'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; }; defaultValue: null }]; }; | ||
'MessagesWithCursor': { kind: 'OBJECT'; name: 'MessagesWithCursor'; fields: { 'cursor': { name: 'cursor'; type: { kind: 'OBJECT'; name: 'MessageCursor'; ofType: null; } }; 'data': { name: 'data'; type: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'Message'; ofType: null; }; }; } }; 'hasMore': { name: 'hasMore'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'Boolean'; ofType: null; }; } }; }; }; | ||
'Mutation': { kind: 'OBJECT'; name: 'Mutation'; fields: { 'createMessage': { name: 'createMessage'; type: { kind: 'OBJECT'; name: 'Message'; ofType: null; } }; 'deleteMessage': { name: 'deleteMessage'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; } }; }; }; | ||
'Query': { kind: 'OBJECT'; name: 'Query'; fields: { 'messages': { name: 'messages'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'Message'; ofType: null; }; }; }; } }; 'messagesFromCursor': { name: 'messagesFromCursor'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'MessagesWithCursor'; ofType: null; }; } }; }; }; | ||
'String': unknown; | ||
}; | ||
|
||
/** An IntrospectionQuery representation of your schema. | ||
* | ||
* @remarks | ||
* This is an introspection of your schema saved as a file by GraphQLSP. | ||
* It will automatically be used by `gql.tada` to infer the types of your GraphQL documents. | ||
* If you need to reuse this data or update your `scalars`, update `tadaOutputLocation` to | ||
* instead save to a .ts instead of a .d.ts file. | ||
*/ | ||
export type introspection = { | ||
name: never; | ||
query: 'Query'; | ||
mutation: 'Mutation'; | ||
subscription: never; | ||
types: introspection_types; | ||
}; | ||
|
||
import * as gqlTada from 'gql.tada'; | ||
|
||
declare module 'gql.tada' { | ||
interface setupSchema { | ||
introspection: introspection | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { Client, cacheExchange, fetchExchange } from "@urql/core"; | ||
import { persistedExchange } from "@urql/exchange-persisted"; | ||
|
||
const client = new Client({ | ||
url: process.env.NEXT_PUBLIC_GQL_URL!, | ||
exchanges: [ | ||
cacheExchange, | ||
persistedExchange({ | ||
enforcePersistedQueries: true, | ||
enableForMutation: true, | ||
generateHash: (_, document: any) => document.documentId, | ||
}), | ||
fetchExchange, | ||
], | ||
}); | ||
|
||
export default client; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { lucia } from "../auth"; | ||
import { registerUrql } from "@urql/next/rsc"; | ||
import { persistedExchange } from "@urql/exchange-persisted"; | ||
import { cacheExchange, createClient, fetchExchange } from "@urql/core"; | ||
|
||
const getClient = (sessionId?: string) => { | ||
const makeClient = () => { | ||
return createClient({ | ||
url: process.env.NEXT_PUBLIC_GQL_URL!, | ||
exchanges: [ | ||
cacheExchange, | ||
persistedExchange({ | ||
enforcePersistedQueries: true, | ||
enableForMutation: true, | ||
generateHash: (_, document: any) => document.documentId, | ||
}), | ||
fetchExchange, | ||
], | ||
fetchOptions: () => ({ | ||
headers: { | ||
cookie: `${lucia.sessionCookieName}=${sessionId}`, | ||
}, | ||
}), | ||
}); | ||
}; | ||
|
||
const { getClient: _getClient } = registerUrql(makeClient); | ||
|
||
return _getClient(); | ||
}; | ||
|
||
export default getClient; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"f07a17f7e44b839d7a1449115b9810d55447696a558d7416f16dc0b9c978217f": "query ReceivedMessages($type: String!) {\n messages(type: $type, limit: 20) {\n __typename\n id\n createdAt\n ...MessageFragment\n }\n}\n\nfragment MessageFragment on Message {\n id\n question\n content\n reply\n createdAt\n updatedAt\n}", | ||
"10ae521c718fee919520bf95d2cdc74ee1bd0d862d468ca4948ad705bb1e2909": "query ReceivedMessagesFromCursor($input: MessagesFromCursorInput!) {\n messagesFromCursor(input: $input) {\n __typename\n data {\n __typename\n id\n createdAt\n ...MessageFragment\n }\n hasMore\n cursor {\n __typename\n id\n createdAt\n }\n }\n}\n\nfragment MessageFragment on Message {\n id\n question\n content\n reply\n createdAt\n updatedAt\n}" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
input CreateMessageInput { | ||
content: String! | ||
question: String! | ||
receiverId: String! | ||
senderId: String | ||
} | ||
|
||
input CursorInput { | ||
createdAt: Int | ||
id: String | ||
} | ||
|
||
type Message { | ||
content: String! | ||
createdAt: Int! | ||
id: ID! | ||
question: String! | ||
receiverId: String! | ||
reply: String | ||
updatedAt: Int | ||
} | ||
|
||
type MessageCursor { | ||
createdAt: Int | ||
id: String | ||
} | ||
|
||
input MessagesFromCursorInput { | ||
cursor: CursorInput | ||
limit: Int | ||
type: String! | ||
} | ||
|
||
type MessagesWithCursor { | ||
cursor: MessageCursor | ||
data: [Message!] | ||
hasMore: Boolean! | ||
} | ||
|
||
type Mutation { | ||
createMessage(input: CreateMessageInput!): Message | ||
deleteMessage(id: String!): String | ||
} | ||
|
||
type Query { | ||
messages(limit: Int, type: String!): [Message!]! | ||
messagesFromCursor(input: MessagesFromCursorInput!): MessagesWithCursor! | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,28 @@ | ||
{ | ||
"extends": "@umamin/tsconfig/nextjs.json", | ||
"compilerOptions": { | ||
"lib": ["dom", "dom.iterable", "esnext"], | ||
"allowJs": true, | ||
"skipLibCheck": true, | ||
"strict": true, | ||
"noEmit": true, | ||
"esModuleInterop": true, | ||
"module": "esnext", | ||
"moduleResolution": "bundler", | ||
"resolveJsonModule": true, | ||
"isolatedModules": true, | ||
"jsx": "preserve", | ||
"incremental": true, | ||
"plugins": [ | ||
{ | ||
"name": "next" | ||
}, | ||
{ | ||
"name": "@0no-co/graphqlsp", | ||
"schema": "./src/schema.graphql", | ||
"tadaOutputLocation": "./src/graphql-env.d.ts", | ||
"tadaPersistedLocation": "./src/persisted-operations.json", | ||
"trackFieldUsage": false | ||
} | ||
], | ||
"paths": { | ||
"@/*": ["./src/*"] | ||
} | ||
}, | ||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], | ||
"include": [ | ||
"next-env.d.ts", | ||
"next.config.mjs", | ||
"**/*.ts", | ||
"**/*.tsx", | ||
".next/types/**/*.ts" | ||
], | ||
"exclude": ["node_modules"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.