2023-08-23 05:25:32 +00:00
|
|
|
const { createClient } = require('graphql-ws');
|
|
|
|
const WebSocket = require('ws');
|
2023-08-23 06:53:31 +00:00
|
|
|
const { PubSub } = require('graphql-subscriptions');
|
2023-08-23 09:52:27 +00:00
|
|
|
const { parse } = require('graphql');
|
2023-08-23 09:27:51 +00:00
|
|
|
const fs = require('fs');
|
2023-08-23 06:53:31 +00:00
|
|
|
|
|
|
|
const pubsub = new PubSub();
|
2023-08-23 05:25:32 +00:00
|
|
|
|
2023-08-23 09:27:51 +00:00
|
|
|
// Read the schema file
|
|
|
|
const schema = fs.readFileSync('./schemas/directus.graphql', 'utf8');
|
|
|
|
|
|
|
|
// Parse the schema
|
|
|
|
const document = parse(schema);
|
2023-08-23 10:44:05 +00:00
|
|
|
|
2023-08-23 09:52:27 +00:00
|
|
|
// Function to find a type definition by name
|
|
|
|
const findTypeDefinition = (typeName) => {
|
|
|
|
return document.definitions.find(
|
|
|
|
def => def.kind === 'ObjectTypeDefinition' && def.name.value === typeName
|
|
|
|
);
|
|
|
|
};
|
2023-08-23 09:27:51 +00:00
|
|
|
|
|
|
|
// Extract the fields excluding the ones ending with '_func', of object type, and specific fields
|
2023-08-23 09:52:27 +00:00
|
|
|
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');
|
2023-08-23 09:27:51 +00:00
|
|
|
};
|
|
|
|
|
2023-08-23 05:25:32 +00:00
|
|
|
const client = createClient({
|
|
|
|
url: 'wss://directus.andert.me/graphql',
|
|
|
|
keepAlive: 30000,
|
|
|
|
webSocketImpl: WebSocket,
|
|
|
|
connectionParams: async () => {
|
2023-08-23 07:30:08 +00:00
|
|
|
return { access_token: process.env.DIRECTUS_API };
|
2023-08-23 05:25:32 +00:00
|
|
|
},
|
|
|
|
});
|
|
|
|
|
2023-08-23 10:23:50 +00:00
|
|
|
const generateSubscriptionQuery = (typeName) => {
|
|
|
|
const typeDefinition = findTypeDefinition(typeName);
|
|
|
|
const fields = extractFields(typeDefinition);
|
|
|
|
|
|
|
|
return `
|
|
|
|
subscription {
|
|
|
|
${typeName}_mutated {
|
|
|
|
key
|
|
|
|
event
|
|
|
|
data {
|
|
|
|
${fields}
|
|
|
|
}
|
2023-08-23 09:27:51 +00:00
|
|
|
}
|
|
|
|
}
|
2023-08-23 10:23:50 +00:00
|
|
|
`;
|
|
|
|
};
|
2023-08-23 09:27:51 +00:00
|
|
|
|
2023-08-23 10:37:30 +00:00
|
|
|
const handleSubscription = (typeName) => {
|
|
|
|
const MUTATED = `${typeName.toUpperCase()}_MUTATED`;
|
2023-08-23 09:27:51 +00:00
|
|
|
|
2023-08-23 10:37:30 +00:00
|
|
|
const type = findTypeDefinition(typeName);
|
|
|
|
const fields = extractFields(type);
|
|
|
|
|
|
|
|
const query = generateSubscriptionQuery(typeName);
|
|
|
|
|
|
|
|
client.subscribe(
|
|
|
|
{
|
|
|
|
query: query,
|
2023-08-23 06:53:31 +00:00
|
|
|
},
|
2023-08-23 10:37:30 +00:00
|
|
|
{
|
|
|
|
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`],
|
|
|
|
},
|
|
|
|
};
|
|
|
|
};
|
2023-08-23 06:53:31 +00:00
|
|
|
|
2023-08-23 10:44:05 +00:00
|
|
|
// 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) };
|
|
|
|
}, {});
|
|
|
|
|
2023-08-23 06:53:31 +00:00
|
|
|
module.exports = {
|
2023-08-23 10:44:05 +00:00
|
|
|
Subscription: subscriptions,
|
2023-08-23 06:53:31 +00:00
|
|
|
};
|