uzen
Version:
General-purpose GraphQL subscription server library
91 lines (90 loc) • 3.97 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.startServer = startServer;
const uWebSockets_js_1 = require("uWebSockets.js");
const uWebSockets_1 = require("graphql-ws/use/uWebSockets");
const index_1 = require("./graphql/index");
const graphql_1 = require("graphql");
const rusty_jwt_1 = require("rusty-jwt");
const JwtValidator_1 = require("./services/JwtValidator");
const redis_pubsub_1 = require("./graphql/redis-pubsub");
function startServer(config) {
const accessTokenService = new rusty_jwt_1.RustJWT(config.jwt.access);
const refreshTokenService = new rusty_jwt_1.RustJWT(config.jwt.refresh);
const { pubsub } = (0, redis_pubsub_1.createRedisPubSub)(config.redis);
const yoga = (0, index_1.createGraphQLServer)({
...config.graphql,
pubsub,
});
function getAllowedList(cors) {
return Array.isArray(cors) ? cors : cors?.origin;
}
const wsHandler = (0, uWebSockets_1.makeBehavior)({
execute: args => args.rootValue.execute(args),
subscribe: args => args.rootValue.subscribe(args),
onSubscribe: async (ctx, _, payload) => {
const origin = ctx.extra.persistedRequest.headers?.origin;
const allowedList = getAllowedList(config.graphql.cors);
if (allowedList !== '*' && !allowedList?.includes(origin)) {
return [new graphql_1.GraphQLError('ws:Unauthorized: Origin not allowed')];
}
const auth = (0, JwtValidator_1.JwtValidator)({
headers: ctx.extra.persistedRequest.headers,
aTs: accessTokenService,
rTs: refreshTokenService,
debug: config.jwt.debug,
});
if (!auth) {
return [new graphql_1.GraphQLError('ws:Unauthorized: Invalid or missing token claims')];
}
const { schema, execute, subscribe, contextFactory, parse, validate } = yoga.getEnveloped({
req: ctx,
authorization: auth,
});
const args = {
schema,
operationName: payload.operationName,
document: parse(payload.query),
variableValues: payload.variables,
contextValue: {
...(await contextFactory()),
authorization: auth,
},
rootValue: {
execute,
subscribe
}
};
const errors = validate(args.schema, args.document);
if (errors.length)
return errors.map((err) => new graphql_1.GraphQLError(err.message));
return args;
},
});
return {
start() {
const PORT = config.port || 3003;
const HOST = config.host || 'localhost';
(0, uWebSockets_js_1.App)()
.any('/*', (res, req) => {
const origin = req.getHeader('origin');
const allowedList = getAllowedList(config.graphql.cors);
const allowedOrigin = allowedList === "*" ? allowedList?.includes(origin) ? origin : "" : "*";
res.writeHeader("Access-Control-Allow-Origin", allowedOrigin);
res.writeHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
res.writeHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
res.writeHeader("Access-Control-Allow-Credentials", "true");
if (req.getMethod() === 'options') {
res.writeStatus('204 No Content').end();
}
else {
yoga(res, req);
}
})
.ws(yoga.graphqlEndpoint, wsHandler)
.listen(HOST, PORT, () => {
console.log(`Server is running on http://${HOST}:${PORT}`);
});
},
};
}