diff --git a/.meshrc.yml b/.meshrc.yml index dcff1f2..b043be5 100644 --- a/.meshrc.yml +++ b/.meshrc.yml @@ -8,21 +8,20 @@ sources: endpoint: https://directus.andert.me/graphql source: ./src/schemas/directus.graphql operationHeaders: - Authorization: Bearer {env.DIRECTUS_API} -additionalResolvers: - - ./src/resolvers/subs_directus.js - - # - name: Cloudron - # handler: - # openapi: - # endpoint: https://my.andert.me/api/v1 - # source: ./src/schemas/cloudron.json - # operationHeaders: - # Authorization: Bearer {env.CLOUDRON_API} - # - name: Gitea - # handler: - # openapi: - # endpoint: https://git.andert.me/api/v1 - # source: ./src/schemas/gitea.yml - # operationHeaders: - # Authorization: Bearer {env.GITEA_API} + Authorization: "Bearer {env.DIRECTUS_API}" + connectionParams: + access_token: "Bv5RknRvv5AZouxcYdBJgVOe3ZC493Y3" +# - name: Cloudron +# handler: +# openapi: +# endpoint: https://my.andert.me/api/v1 +# source: ./src/schemas/cloudron.json +# operationHeaders: +# Authorization: Bearer {env.CLOUDRON_API} +# - name: Gitea +# handler: +# openapi: +# endpoint: https://git.andert.me/api/v1 +# source: ./src/schemas/gitea.yml +# operationHeaders: +# Authorization: Bearer {env.GITEA_API} diff --git a/package.json b/package.json index bb75e83..2695674 100644 --- a/package.json +++ b/package.json @@ -33,8 +33,10 @@ "fs": "0.0.1-security", "graphql": "^16.7.1", "graphql-request": "^6.1.0", + "graphql-sse": "^2.2.3", "graphql-subscriptions": "^2.0.0", "graphql-ws": "^5.14.0", + "isomorphic-ws": "^5.0.0", "next": "13.4.9", "node-fetch": "^3.3.2", "path": "^0.12.7", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8387067..d8426aa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -58,12 +58,18 @@ dependencies: graphql-request: specifier: ^6.1.0 version: 6.1.0(graphql@16.7.1) + graphql-sse: + specifier: ^2.2.3 + version: 2.2.3(graphql@16.7.1) graphql-subscriptions: specifier: ^2.0.0 version: 2.0.0(graphql@16.7.1) graphql-ws: specifier: ^5.14.0 version: 5.14.0(graphql@16.7.1) + isomorphic-ws: + specifier: ^5.0.0 + version: 5.0.0(ws@8.13.0) next: specifier: 13.4.9 version: 13.4.9(@babel/core@7.22.8)(react-dom@18.2.0)(react@18.2.0) @@ -5808,6 +5814,15 @@ packages: tslib: 2.6.0 dev: false + /graphql-sse@2.2.3(graphql@16.7.1): + resolution: {integrity: sha512-pcSbaPa2IAFm/oT5e7tu4kE0FaaZ32mWMQZa2hh+08bbjhmTlHInCGousYEYohWMUSKOrOFpFifpdWHms51JbA==} + engines: {node: '>=12'} + peerDependencies: + graphql: '>=0.11 <=16' + dependencies: + graphql: 16.7.1 + dev: false + /graphql-subscriptions@2.0.0(graphql@16.7.1): resolution: {integrity: sha512-s6k2b8mmt9gF9pEfkxsaO1lTxaySfKoEJzEfmwguBbQ//Oq23hIXCfR1hm4kdh5hnR20RdwB+s3BCb+0duHSZA==} peerDependencies: diff --git a/src/resolvers/subs_directus.js b/src/resolvers/subs_directus.js deleted file mode 100644 index 02acd35..0000000 --- a/src/resolvers/subs_directus.js +++ /dev/null @@ -1,108 +0,0 @@ -const { createClient } = require('graphql-ws'); -const WebSocket = require('ws'); -const { PubSub } = require('graphql-subscriptions'); -const { parse } = require('graphql'); - -const pubsub = new PubSub(); - -const schema = require('raw-loader!../schemas/directus.graphql').default; - -// 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, -}; \ No newline at end of file