const { createClient } = require('graphql-ws'); const WebSocket = require('ws'); const { PubSub } = require('graphql-subscriptions'); const { parse } = require('graphql'); const fs = require('fs'); import path from 'path'; const pubsub = new PubSub(); const schemaPath = path.resolve(process.cwd(), './schemas/directus.graphql'); const schema = fs.readFileSync(schemaPath, '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 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`], }, }; }; // Find the Subscription type definition const subscriptionType = findTypeDefinition('Subscription'); // Extract the subscription type names, excluding the ones starting with 'directus_' const subscriptionTypeNames = subscriptionType.fields .map(field => field.name.value.replace('_mutated', '')) .filter(name => !name.startsWith('directus_')); // Generate subscriptions for each type const subscriptions = subscriptionTypeNames.reduce((acc, typeName) => { return { ...acc, ...handleSubscription(typeName) }; }, {}); module.exports = { Subscription: subscriptions, };