const { createClient } = require('graphql-ws'); const WebSocket = require('ws'); const { PubSub } = require('graphql-subscriptions'); const { parse } = require('graphql'); const fs = require('fs'); const pubsub = new PubSub(); const PROJECTS_MUTATED = 'PROJECTS_MUTATED'; // Read the schema file const schema = fs.readFileSync('./schemas/directus.graphql', 'utf8'); // Parse the schema const document = parse(schema); // Function to find a type definition by name const findTypeDefinition = (typeName) => { return document.definitions.find( def => def.kind === 'ObjectTypeDefinition' && def.name.value === typeName ); }; // Extract the fields excluding the ones ending with '_func', of object type, and specific fields const extractFields = (type, depth = 0) => { return type.fields .filter(field => !field.name.value.endsWith('_func') && !['avatar', 'role'].includes(field.name.value)) .map(field => { if (field.type.kind === 'NamedType' && depth < 1) { // If the field is of object type and we are not too deep, recursively extract its fields const nestedType = findTypeDefinition(field.type.name.value); if (nestedType) { return `${field.name.value} {\n${extractFields(nestedType, depth + 1)}\n}`; } } return field.name.value; }) .join('\n'); }; const projectsType = findTypeDefinition('projects'); const projectsFields = extractFields(projectsType); const client = createClient({ url: 'wss://directus.andert.me/graphql', keepAlive: 30000, webSocketImpl: WebSocket, connectionParams: async () => { return { access_token: process.env.DIRECTUS_API }; }, }); const generateSubscriptionQuery = (typeName) => { const typeDefinition = findTypeDefinition(typeName); const fields = extractFields(typeDefinition); return ` subscription { ${typeName}_mutated { key event data { ${fields} } } } `; }; const handleSubscription = (typeName) => { const MUTATED = `${typeName.toUpperCase()}_MUTATED`; const type = findTypeDefinition(typeName); const fields = extractFields(type); const query = generateSubscriptionQuery(typeName); client.subscribe( { query: query, }, { next: data => { if (data && data.data && data.data[`${typeName}_mutated`]) { pubsub.publish(MUTATED, { [`${typeName}_mutated`]: data.data[`${typeName}_mutated`] }); } }, error: error => console.error('error:', error), } ); return { [`${typeName}_mutated`]: { subscribe: () => pubsub.asyncIterator([MUTATED]), resolve: payload => payload[`${typeName}_mutated`], }, }; }; module.exports = { Subscription: { ...handleSubscription('projects'), ...handleSubscription('todos'), }, };