@freshsqueezed/mammothgql
Advanced tools
Comparing version 1.0.14 to 1.0.15
@@ -0,1 +1,8 @@ | ||
## [1.0.15](https://github.com/freshsqueezed/mammothgql/compare/v1.0.14...v1.0.15) (2025-01-07) | ||
### Bug Fixes | ||
* **mammoth:** Extend context properly, Partial options ([8bcd6d4](https://github.com/freshsqueezed/mammothgql/commit/8bcd6d47b07731aee73c27af80eda9cc2382693c)) | ||
## [1.0.14](https://github.com/freshsqueezed/mammothgql/compare/v1.0.13...v1.0.14) (2025-01-07) | ||
@@ -2,0 +9,0 @@ |
import { Request, Response } from 'express'; | ||
import type { GraphQLSchema, ValidationRule } from 'graphql'; | ||
interface MammothOptions<TContext extends MammothContext> { | ||
interface MammothBaseContext { | ||
req: Request; | ||
res: Response; | ||
} | ||
interface MammothOptions<ServerContext extends MammothBaseContext> { | ||
schema: GraphQLSchema; | ||
context: ({ req, res }: { | ||
req: Request; | ||
res: Response; | ||
}) => TContext; | ||
context?: (args: MammothBaseContext) => Partial<ServerContext>; | ||
pretty?: boolean; | ||
@@ -13,9 +14,5 @@ graphiql?: boolean; | ||
} | ||
export interface MammothContext { | ||
req: Request; | ||
res: Response; | ||
} | ||
export declare function mammothGraphql<TContext extends MammothContext>(options: MammothOptions<TContext>): (req: Request, res: Response) => Promise<void>; | ||
export declare function mammothGraphql<ServerContext extends MammothBaseContext>(options: MammothOptions<ServerContext>): (req: Request, res: Response) => Promise<void>; | ||
export declare function graphiqlHtml(req: Request, res: Response, cookies: string): void; | ||
export {}; | ||
//# sourceMappingURL=mammoth.d.ts.map |
@@ -7,3 +7,3 @@ "use strict"; | ||
function mammothGraphql(options) { | ||
const { schema, pretty = false, graphiql: showGraphiQL = false, validationRules = [], } = options; | ||
const { schema, pretty = false, graphiql: showGraphiQL = false, validationRules = [], context = () => ({}), } = options; | ||
return async (req, res) => { | ||
@@ -69,31 +69,32 @@ if (req.method !== 'GET' && req.method !== 'POST') { | ||
try { | ||
const result = (await (0, graphql_1.execute)({ | ||
const contextValue = { | ||
req, | ||
res, | ||
...context({ req, res }), | ||
}; | ||
const result = await (0, graphql_1.execute)({ | ||
schema, | ||
document: documentAST, | ||
contextValue: options.context({ req, res }), | ||
contextValue, | ||
variableValues: variables, | ||
operationName, | ||
})); | ||
if (result.errors && result.errors.length > 0) { | ||
// If there are errors, handle them properly | ||
res.status(500).json(createErrorMessages(result.errors.map((e) => e.message), result.errors)); | ||
}); | ||
if (result.errors) { | ||
res.status(400).json(createErrorMessages(result.errors.map((err) => err.message), result.errors)); | ||
return; | ||
} | ||
const payload = pretty ? JSON.stringify(result, null, 2) : result; | ||
res.status(200).json(payload); | ||
res.status(200).json(pretty ? JSON.stringify(result, null, 2) : result); | ||
} | ||
catch (error) { | ||
const executionError = error instanceof Error ? error : new Error('Unknown execution error'); | ||
const graphQLError = new graphql_1.GraphQLError(executionError.message, { | ||
originalError: executionError, | ||
}); | ||
res | ||
.status(500) | ||
.json(createErrorMessages(['GraphQL execution error.'], [graphQLError])); | ||
catch (err) { | ||
const executionError = err instanceof Error ? err : new Error('Unknown execution error'); | ||
res.status(500).json(createErrorMessages([executionError.message])); | ||
} | ||
}; | ||
} | ||
const createErrorMessages = (messages, graphqlErrors) => ({ | ||
errors: graphqlErrors ?? messages.map((message) => ({ message })), | ||
}); | ||
function createErrorMessages(messages, errors) { | ||
return { | ||
data: null, | ||
errors: errors || messages.map((msg) => ({ message: msg })), | ||
}; | ||
} | ||
function graphiqlHtml(req, res, cookies) { | ||
@@ -103,5 +104,5 @@ const protocol = req.protocol; | ||
const path = req.path; | ||
const fullUrl = `${protocol}://${host}${path}graphql`; | ||
const fullUrl = `${protocol}://${host}${path}`; | ||
const wsProtocol = protocol === 'https' ? 'wss' : 'ws'; | ||
const wsUrl = `${wsProtocol}://${host}${path}graphql`; | ||
const wsUrl = `${wsProtocol}://${host}${path}`; | ||
res.send(`<!-- | ||
@@ -129,2 +130,12 @@ * Copyright (c) 2021 GraphQL Contributors | ||
} | ||
.spinner { | ||
display: flex; | ||
align-items: center; | ||
justify-content: center; | ||
height: 100vh; | ||
width: 100vw; | ||
font-size: 24px; | ||
color: #333; | ||
} | ||
</style> | ||
@@ -157,3 +168,3 @@ <script | ||
<div id="graphiql"> | ||
<div class="spinner"></div> <!-- Spinner element --> | ||
<div class="spinner">Loading GraphiQL...</div> | ||
</div> | ||
@@ -163,2 +174,3 @@ | ||
const root = ReactDOM.createRoot(document.getElementById('graphiql')); | ||
const fetcher = GraphiQL.createFetcher({ | ||
@@ -172,6 +184,6 @@ url: "${fullUrl}", | ||
...options, | ||
credentials: 'include', // Ensure cookies are included for same-origin requests | ||
credentials: 'include', // Include cookies for same-origin requests | ||
headers: { | ||
...options.headers, | ||
'Cookie': '${cookies}', // Send cookies to the server with the request | ||
'Cookie': \`${cookies}\`, // Inject cookies into the headers | ||
}, | ||
@@ -182,2 +194,3 @@ }; | ||
}); | ||
const explorerPlugin = GraphiQLPluginExplorer.explorerPlugin(); | ||
@@ -192,2 +205,4 @@ | ||
); | ||
// Hide the spinner once GraphiQL is rendered | ||
document.querySelector('.spinner').style.display = 'none'; | ||
@@ -194,0 +209,0 @@ </script> |
@@ -6,3 +6,3 @@ { | ||
"types": "lib/index.d.ts", | ||
"version": "1.0.14", | ||
"version": "1.0.15", | ||
"author": "Matt Gordon <matt@lemonade.tech>", | ||
@@ -9,0 +9,0 @@ "license": "MIT", |
@@ -20,5 +20,11 @@ import { Request, Response } from 'express'; | ||
interface MammothOptions<TContext extends MammothContext> { | ||
interface MammothBaseContext { | ||
req: Request; | ||
res: Response; | ||
} | ||
// MammothOptions is now generic, expecting a ServerContext that extends MammothBaseContext | ||
interface MammothOptions<ServerContext extends MammothBaseContext> { | ||
schema: GraphQLSchema; | ||
context: ({ req, res }: { req: Request; res: Response }) => TContext; | ||
context?: (args: MammothBaseContext) => Partial<ServerContext>; | ||
pretty?: boolean; | ||
@@ -29,9 +35,4 @@ graphiql?: boolean; | ||
export interface MammothContext { | ||
req: Request; | ||
res: Response; | ||
} | ||
export function mammothGraphql<TContext extends MammothContext>( | ||
options: MammothOptions<TContext>, | ||
export function mammothGraphql<ServerContext extends MammothBaseContext>( | ||
options: MammothOptions<ServerContext>, | ||
) { | ||
@@ -43,2 +44,3 @@ const { | ||
validationRules = [], | ||
context = () => ({}), | ||
} = options; | ||
@@ -57,3 +59,2 @@ | ||
const { query, variables, operationName } = req.body; | ||
const cookies = req.headers.cookie || ''; | ||
@@ -126,15 +127,20 @@ | ||
try { | ||
const result = (await execute({ | ||
const contextValue: ServerContext = { | ||
req, | ||
res, | ||
...context({ req, res }), | ||
} as ServerContext; | ||
const result = await execute({ | ||
schema, | ||
document: documentAST, | ||
contextValue: options.context({ req, res }), | ||
contextValue, | ||
variableValues: variables, | ||
operationName, | ||
})) as FormattedExecutionResult; | ||
}); | ||
if (result.errors && result.errors.length > 0) { | ||
// If there are errors, handle them properly | ||
res.status(500).json( | ||
if (result.errors) { | ||
res.status(400).json( | ||
createErrorMessages( | ||
result.errors.map((e) => e.message), | ||
result.errors.map((err) => err.message), | ||
result.errors, | ||
@@ -146,16 +152,7 @@ ), | ||
const payload = pretty ? JSON.stringify(result, null, 2) : result; | ||
res.status(200).json(payload); | ||
} catch (error: unknown) { | ||
res.status(200).json(pretty ? JSON.stringify(result, null, 2) : result); | ||
} catch (err: unknown) { | ||
const executionError = | ||
error instanceof Error ? error : new Error('Unknown execution error'); | ||
const graphQLError = new GraphQLError(executionError.message, { | ||
originalError: executionError, | ||
}); | ||
res | ||
.status(500) | ||
.json( | ||
createErrorMessages(['GraphQL execution error.'], [graphQLError]), | ||
); | ||
err instanceof Error ? err : new Error('Unknown execution error'); | ||
res.status(500).json(createErrorMessages([executionError.message])); | ||
} | ||
@@ -165,8 +162,11 @@ }; | ||
const createErrorMessages = ( | ||
function createErrorMessages( | ||
messages: string[], | ||
graphqlErrors?: readonly GraphQLError[] | readonly GraphQLFormattedError[], | ||
) => ({ | ||
errors: graphqlErrors ?? messages.map((message) => ({ message })), | ||
}); | ||
errors?: ReadonlyArray<GraphQLFormattedError>, | ||
): FormattedExecutionResult { | ||
return { | ||
data: null, | ||
errors: errors || messages.map((msg) => ({ message: msg })), | ||
}; | ||
} | ||
@@ -177,5 +177,5 @@ export function graphiqlHtml(req: Request, res: Response, cookies: string) { | ||
const path = req.path; | ||
const fullUrl = `${protocol}://${host}${path}graphql`; | ||
const fullUrl = `${protocol}://${host}${path}`; | ||
const wsProtocol = protocol === 'https' ? 'wss' : 'ws'; | ||
const wsUrl = `${wsProtocol}://${host}${path}graphql`; | ||
const wsUrl = `${wsProtocol}://${host}${path}`; | ||
@@ -204,2 +204,12 @@ res.send(`<!-- | ||
} | ||
.spinner { | ||
display: flex; | ||
align-items: center; | ||
justify-content: center; | ||
height: 100vh; | ||
width: 100vw; | ||
font-size: 24px; | ||
color: #333; | ||
} | ||
</style> | ||
@@ -232,3 +242,3 @@ <script | ||
<div id="graphiql"> | ||
<div class="spinner"></div> <!-- Spinner element --> | ||
<div class="spinner">Loading GraphiQL...</div> | ||
</div> | ||
@@ -238,2 +248,3 @@ | ||
const root = ReactDOM.createRoot(document.getElementById('graphiql')); | ||
const fetcher = GraphiQL.createFetcher({ | ||
@@ -247,6 +258,6 @@ url: "${fullUrl}", | ||
...options, | ||
credentials: 'include', // Ensure cookies are included for same-origin requests | ||
credentials: 'include', // Include cookies for same-origin requests | ||
headers: { | ||
...options.headers, | ||
'Cookie': '${cookies}', // Send cookies to the server with the request | ||
'Cookie': \`${cookies}\`, // Inject cookies into the headers | ||
}, | ||
@@ -257,2 +268,3 @@ }; | ||
}); | ||
const explorerPlugin = GraphiQLPluginExplorer.explorerPlugin(); | ||
@@ -267,2 +279,4 @@ | ||
); | ||
// Hide the spinner once GraphiQL is rendered | ||
document.querySelector('.spinner').style.display = 'none'; | ||
@@ -269,0 +283,0 @@ </script> |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
40569
711