@pulzar/core
Version:
Next-generation Node.js framework for ultra-fast web applications with zero-reflection DI, GraphQL, WebSockets, events, and edge runtime support
264 lines (257 loc) • 8.76 kB
JavaScript
import { logger } from "../utils/logger";
export class MercuriusAdapter {
app;
options;
resolvers = new Map();
schema = "";
initialized = false;
constructor(options = {}) {
this.options = {
schema: "",
subscriptions: true,
playground: process.env.NODE_ENV !== "production",
path: "/graphql",
jit: 1,
cache: 4096,
...options,
};
}
async initialize(app) {
if (this.initialized) {
throw new Error("MercuriusAdapter already initialized");
}
this.app = app;
try {
// Try to load Mercurius dynamically
const mercuriusModule = await this.dynamicImportMercurius();
if (mercuriusModule) {
const mercurius = mercuriusModule.default || mercuriusModule;
// Register Mercurius plugin with Fastify
await app.register(mercurius, {
schema: this.schema || this.getDefaultSchema(),
resolvers: this.buildResolvers(),
graphiql: this.options.playground,
path: this.options.path,
subscription: this.options.subscriptions,
jit: this.options.jit,
cache: this.options.cache,
context: async (request, reply) => {
return {
request,
reply,
user: request.user,
};
},
});
logger.info("Mercurius GraphQL adapter initialized", {
path: this.options.path,
subscriptions: this.options.subscriptions,
playground: this.options.playground,
schema: !!this.schema,
resolvers: this.resolvers.size,
});
}
else {
// Fallback to mock implementation
logger.warn("Mercurius package not installed, using mock implementation");
this.createMockMercurius(app);
}
this.initialized = true;
}
catch (error) {
logger.error("Failed to initialize Mercurius GraphQL server", { error });
throw error;
}
}
setSchema(schema) {
this.schema = schema;
logger.debug("GraphQL schema set", { length: schema.length });
}
addResolver(typeName, resolvers) {
this.resolvers.set(typeName, resolvers);
logger.debug("GraphQL resolver added", { typeName });
}
async executeQuery(query, variables, context) {
if (!this.initialized) {
throw new Error("MercuriusAdapter not initialized");
}
try {
if (this.app && this.app.graphql) {
// Use Mercurius to execute query
const result = await this.app.graphql(query, context, variables);
logger.debug("GraphQL query executed", {
query: query.substring(0, 100) + (query.length > 100 ? "..." : ""),
variables: variables ? Object.keys(variables) : undefined,
hasErrors: !!result.errors,
});
return result;
}
else {
// Mock implementation
logger.debug("GraphQL query executed (mock)", {
query: query.substring(0, 50) + "...",
variables,
});
return {
data: {
mock: "This is a mock GraphQL response",
query: query.substring(0, 100),
variables,
},
};
}
}
catch (error) {
logger.error("GraphQL query execution failed", {
query,
variables,
error,
});
return {
data: null,
errors: [
{
message: error instanceof Error ? error.message : "Unknown GraphQL error",
extensions: {
code: "EXECUTION_ERROR",
},
},
],
};
}
}
async dynamicImportMercurius() {
try {
return await new Function('return import("mercurius")')();
}
catch {
return null;
}
}
buildResolvers() {
const resolvers = {};
for (const [typeName, typeResolvers] of this.resolvers.entries()) {
resolvers[typeName] = typeResolvers;
}
// Add default resolvers if none provided
if (Object.keys(resolvers).length === 0) {
resolvers.Query = {
hello: () => "Hello from Pulzar GraphQL!",
version: () => "1.0.0",
};
}
return resolvers;
}
getDefaultSchema() {
if (this.schema) {
return this.schema;
}
return `
type Query {
hello: String
version: String
}
type Mutation {
placeholder: String
}
`;
}
createMockMercurius(app) {
// Create mock GraphQL endpoint
app.post(this.options.path, async (request, reply) => {
const { query, variables } = request.body || {};
const result = await this.executeQuery(query, variables, {
request,
reply,
});
return result;
});
if (this.options.playground) {
// Mock GraphiQL playground
app.get(this.options.path, async (request, reply) => {
reply.type("text/html");
return this.getPlaygroundHTML();
});
}
logger.info("Mock GraphQL endpoint created", { path: this.options.path });
}
getPlaygroundHTML() {
return `
<!DOCTYPE html>
<html>
<head>
<title>GraphQL Playground (Mock)</title>
<style>
body { font-family: Arial, sans-serif; padding: 20px; }
.container { max-width: 800px; margin: 0 auto; }
.warning { background: #fff3cd; padding: 15px; border-radius: 5px; margin-bottom: 20px; }
textarea { width: 100%; height: 200px; font-family: monospace; }
button { background: #007bff; color: white; padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer; }
.result { background: #f8f9fa; padding: 15px; border-radius: 5px; margin-top: 20px; white-space: pre-wrap; font-family: monospace; }
</style>
</head>
<body>
<div class="container">
<h1>GraphQL Playground (Mock)</h1>
<div class="warning">
<strong>Warning:</strong> This is a mock GraphQL playground. Install 'mercurius' package for full functionality.
</div>
<h3>Query:</h3>
<textarea id="query" placeholder="Enter your GraphQL query here...">
query {
hello
version
}
</textarea>
<br><br>
<button onclick="executeQuery()">Execute Query</button>
<h3>Result:</h3>
<div id="result" class="result">Click "Execute Query" to see results</div>
</div>
<script>
async function executeQuery() {
const query = document.getElementById('query').value;
const resultDiv = document.getElementById('result');
try {
const response = await fetch('${this.options.path}', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ query }),
});
const result = await response.json();
resultDiv.textContent = JSON.stringify(result, null, 2);
} catch (error) {
resultDiv.textContent = 'Error: ' + error.message;
}
}
</script>
</body>
</html>
`;
}
getStats() {
return {
initialized: this.initialized,
schema: !!this.schema,
resolvers: this.resolvers.size,
path: this.options.path,
};
}
async shutdown() {
this.resolvers.clear();
this.schema = "";
this.initialized = false;
logger.info("Mercurius GraphQL adapter shutdown");
}
}
export function Resolver(typeName) {
return function (target) {
const resolverName = typeName || target.name.replace(/Resolver$/, "");
Reflect.defineMetadata("graphql:resolver", { typeName: resolverName }, target);
return target;
};
}
export default MercuriusAdapter;
//# sourceMappingURL=mercurius-adapter.js.map