@graphql-mesh/http 0.1.0-alpha-20220905180614-53fadb778
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/graphqlHandler.d.ts +3 -0
- package/index.d.ts +4 -0
- package/index.js +110 -0
- package/index.mjs +106 -0
- package/package.json +42 -0
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { MeshInstance } from '@graphql-mesh/runtime';
|
|
2
|
+
import { CORSOptions } from 'graphql-yoga';
|
|
3
|
+
export declare const graphqlHandler: (mesh$: Promise<MeshInstance>, playgroundTitle: string, playgroundEnabled: boolean, graphqlEndpoint: string, corsConfig: CORSOptions) => (request: Request, ...args: any[]) => Promise<Response>;
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { ServeMeshOptions } from '@graphql-mesh/runtime';
|
|
2
|
+
import { ServerAdapter } from '@whatwg-node/server';
|
|
3
|
+
import { Router } from 'itty-router';
|
|
4
|
+
export declare function createMeshHTTPHandler<TServerContext>({ baseDir, getBuiltMesh, logger, rawServeConfig, playgroundTitle, }: ServeMeshOptions): ServerAdapter<TServerContext, Router<Request>>;
|
package/index.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
const crossHelpers = require('@graphql-mesh/cross-helpers');
|
|
6
|
+
const utils = require('@graphql-mesh/utils');
|
|
7
|
+
const server = require('@whatwg-node/server');
|
|
8
|
+
const ittyRouter = require('itty-router');
|
|
9
|
+
const ittyRouterExtras = require('itty-router-extras');
|
|
10
|
+
const graphqlYoga = require('graphql-yoga');
|
|
11
|
+
|
|
12
|
+
const graphqlHandler = (mesh$, playgroundTitle, playgroundEnabled, graphqlEndpoint, corsConfig) => {
|
|
13
|
+
const yoga$ = mesh$.then(mesh => graphqlYoga.createYoga({
|
|
14
|
+
parserCache: false,
|
|
15
|
+
validationCache: false,
|
|
16
|
+
plugins: [
|
|
17
|
+
...mesh.plugins,
|
|
18
|
+
graphqlYoga.useLogger({
|
|
19
|
+
skipIntrospection: true,
|
|
20
|
+
logFn: (eventName, { args }) => {
|
|
21
|
+
if (eventName.endsWith('-start')) {
|
|
22
|
+
mesh.logger.debug(`\t headers: `, args.contextValue.headers);
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
}),
|
|
26
|
+
],
|
|
27
|
+
logging: mesh.logger,
|
|
28
|
+
maskedErrors: false,
|
|
29
|
+
graphiql: playgroundEnabled && {
|
|
30
|
+
title: playgroundTitle,
|
|
31
|
+
},
|
|
32
|
+
cors: corsConfig,
|
|
33
|
+
graphqlEndpoint,
|
|
34
|
+
}));
|
|
35
|
+
return async (request, ...args) => {
|
|
36
|
+
const yoga = await yoga$;
|
|
37
|
+
return yoga.handleRequest(request, ...args);
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
function createMeshHTTPHandler({ baseDir, getBuiltMesh, logger, rawServeConfig = {}, playgroundTitle, }) {
|
|
42
|
+
let readyFlag = false;
|
|
43
|
+
const mesh$ = getBuiltMesh().then(mesh => {
|
|
44
|
+
readyFlag = true;
|
|
45
|
+
return mesh;
|
|
46
|
+
});
|
|
47
|
+
const { cors: corsConfig, staticFiles, playground: playgroundEnabled = crossHelpers.process.env.NODE_ENV !== 'production', endpoint: graphqlPath = '/graphql',
|
|
48
|
+
// TODO
|
|
49
|
+
// trustProxy = 'loopback',
|
|
50
|
+
} = rawServeConfig;
|
|
51
|
+
const router = ittyRouter.Router();
|
|
52
|
+
const requestHandler = server.createServerAdapter({
|
|
53
|
+
handleRequest: router.handle,
|
|
54
|
+
baseObject: router,
|
|
55
|
+
});
|
|
56
|
+
router.all('/healthcheck', () => new Response(null, {
|
|
57
|
+
status: readyFlag ? 204 : 503,
|
|
58
|
+
}));
|
|
59
|
+
router.all('/readiness', () => new Response(null, {
|
|
60
|
+
status: readyFlag ? 204 : 503,
|
|
61
|
+
}));
|
|
62
|
+
router.post('*', async (request) => {
|
|
63
|
+
if (readyFlag) {
|
|
64
|
+
const { pubsub } = await mesh$;
|
|
65
|
+
for (const eventName of pubsub.getEventNames()) {
|
|
66
|
+
const { pathname } = new URL(request.url);
|
|
67
|
+
if (eventName === `webhook:${request.method.toLowerCase()}:${pathname}`) {
|
|
68
|
+
const body = await request.text();
|
|
69
|
+
logger.debug(`Received webhook request for ${pathname}`, body);
|
|
70
|
+
pubsub.publish(eventName, request.headers.get('application/json') === 'application/json' ? JSON.parse(body) : body);
|
|
71
|
+
return new Response(null, {
|
|
72
|
+
status: 204,
|
|
73
|
+
statusText: 'OK',
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return undefined;
|
|
79
|
+
});
|
|
80
|
+
if (staticFiles) {
|
|
81
|
+
const indexPath = crossHelpers.path.join(baseDir, staticFiles, 'index.html');
|
|
82
|
+
router.get('*', async (request) => {
|
|
83
|
+
const url = new URL(request.url);
|
|
84
|
+
if (url.pathname === '/' && (await utils.pathExists(indexPath))) {
|
|
85
|
+
const indexFile = await crossHelpers.fs.promises.readFile(indexPath, 'utf-8');
|
|
86
|
+
router.get('/', () => new Response(indexFile, {
|
|
87
|
+
status: 200,
|
|
88
|
+
headers: {
|
|
89
|
+
'Content-Type': 'text/html',
|
|
90
|
+
},
|
|
91
|
+
}));
|
|
92
|
+
}
|
|
93
|
+
const filePath = crossHelpers.path.join(baseDir, staticFiles, url.pathname);
|
|
94
|
+
if (await utils.pathExists(filePath)) {
|
|
95
|
+
const body = await crossHelpers.fs.promises.readFile(filePath);
|
|
96
|
+
return new Response(body, {
|
|
97
|
+
status: 200,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
return undefined;
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
router.get('/', request => Response.redirect(new URL(graphqlPath, request.url)));
|
|
105
|
+
}
|
|
106
|
+
router.all(graphqlPath, ittyRouterExtras.withCookies, graphqlHandler(mesh$, playgroundTitle, playgroundEnabled, graphqlPath, corsConfig));
|
|
107
|
+
return requestHandler;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
exports.createMeshHTTPHandler = createMeshHTTPHandler;
|
package/index.mjs
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { process, path, fs } from '@graphql-mesh/cross-helpers';
|
|
2
|
+
import { pathExists } from '@graphql-mesh/utils';
|
|
3
|
+
import { createServerAdapter } from '@whatwg-node/server';
|
|
4
|
+
import { Router } from 'itty-router';
|
|
5
|
+
import { withCookies } from 'itty-router-extras';
|
|
6
|
+
import { createYoga, useLogger } from 'graphql-yoga';
|
|
7
|
+
|
|
8
|
+
const graphqlHandler = (mesh$, playgroundTitle, playgroundEnabled, graphqlEndpoint, corsConfig) => {
|
|
9
|
+
const yoga$ = mesh$.then(mesh => createYoga({
|
|
10
|
+
parserCache: false,
|
|
11
|
+
validationCache: false,
|
|
12
|
+
plugins: [
|
|
13
|
+
...mesh.plugins,
|
|
14
|
+
useLogger({
|
|
15
|
+
skipIntrospection: true,
|
|
16
|
+
logFn: (eventName, { args }) => {
|
|
17
|
+
if (eventName.endsWith('-start')) {
|
|
18
|
+
mesh.logger.debug(`\t headers: `, args.contextValue.headers);
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
}),
|
|
22
|
+
],
|
|
23
|
+
logging: mesh.logger,
|
|
24
|
+
maskedErrors: false,
|
|
25
|
+
graphiql: playgroundEnabled && {
|
|
26
|
+
title: playgroundTitle,
|
|
27
|
+
},
|
|
28
|
+
cors: corsConfig,
|
|
29
|
+
graphqlEndpoint,
|
|
30
|
+
}));
|
|
31
|
+
return async (request, ...args) => {
|
|
32
|
+
const yoga = await yoga$;
|
|
33
|
+
return yoga.handleRequest(request, ...args);
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
function createMeshHTTPHandler({ baseDir, getBuiltMesh, logger, rawServeConfig = {}, playgroundTitle, }) {
|
|
38
|
+
let readyFlag = false;
|
|
39
|
+
const mesh$ = getBuiltMesh().then(mesh => {
|
|
40
|
+
readyFlag = true;
|
|
41
|
+
return mesh;
|
|
42
|
+
});
|
|
43
|
+
const { cors: corsConfig, staticFiles, playground: playgroundEnabled = process.env.NODE_ENV !== 'production', endpoint: graphqlPath = '/graphql',
|
|
44
|
+
// TODO
|
|
45
|
+
// trustProxy = 'loopback',
|
|
46
|
+
} = rawServeConfig;
|
|
47
|
+
const router = Router();
|
|
48
|
+
const requestHandler = createServerAdapter({
|
|
49
|
+
handleRequest: router.handle,
|
|
50
|
+
baseObject: router,
|
|
51
|
+
});
|
|
52
|
+
router.all('/healthcheck', () => new Response(null, {
|
|
53
|
+
status: readyFlag ? 204 : 503,
|
|
54
|
+
}));
|
|
55
|
+
router.all('/readiness', () => new Response(null, {
|
|
56
|
+
status: readyFlag ? 204 : 503,
|
|
57
|
+
}));
|
|
58
|
+
router.post('*', async (request) => {
|
|
59
|
+
if (readyFlag) {
|
|
60
|
+
const { pubsub } = await mesh$;
|
|
61
|
+
for (const eventName of pubsub.getEventNames()) {
|
|
62
|
+
const { pathname } = new URL(request.url);
|
|
63
|
+
if (eventName === `webhook:${request.method.toLowerCase()}:${pathname}`) {
|
|
64
|
+
const body = await request.text();
|
|
65
|
+
logger.debug(`Received webhook request for ${pathname}`, body);
|
|
66
|
+
pubsub.publish(eventName, request.headers.get('application/json') === 'application/json' ? JSON.parse(body) : body);
|
|
67
|
+
return new Response(null, {
|
|
68
|
+
status: 204,
|
|
69
|
+
statusText: 'OK',
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return undefined;
|
|
75
|
+
});
|
|
76
|
+
if (staticFiles) {
|
|
77
|
+
const indexPath = path.join(baseDir, staticFiles, 'index.html');
|
|
78
|
+
router.get('*', async (request) => {
|
|
79
|
+
const url = new URL(request.url);
|
|
80
|
+
if (url.pathname === '/' && (await pathExists(indexPath))) {
|
|
81
|
+
const indexFile = await fs.promises.readFile(indexPath, 'utf-8');
|
|
82
|
+
router.get('/', () => new Response(indexFile, {
|
|
83
|
+
status: 200,
|
|
84
|
+
headers: {
|
|
85
|
+
'Content-Type': 'text/html',
|
|
86
|
+
},
|
|
87
|
+
}));
|
|
88
|
+
}
|
|
89
|
+
const filePath = path.join(baseDir, staticFiles, url.pathname);
|
|
90
|
+
if (await pathExists(filePath)) {
|
|
91
|
+
const body = await fs.promises.readFile(filePath);
|
|
92
|
+
return new Response(body, {
|
|
93
|
+
status: 200,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
return undefined;
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
router.get('/', request => Response.redirect(new URL(graphqlPath, request.url)));
|
|
101
|
+
}
|
|
102
|
+
router.all(graphqlPath, withCookies, graphqlHandler(mesh$, playgroundTitle, playgroundEnabled, graphqlPath, corsConfig));
|
|
103
|
+
return requestHandler;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export { createMeshHTTPHandler };
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@graphql-mesh/http",
|
|
3
|
+
"version": "0.1.0-alpha-20220905180614-53fadb778",
|
|
4
|
+
"sideEffects": false,
|
|
5
|
+
"peerDependencies": {
|
|
6
|
+
"graphql": "*"
|
|
7
|
+
},
|
|
8
|
+
"dependencies": {
|
|
9
|
+
"@graphql-mesh/cross-helpers": "0.2.3",
|
|
10
|
+
"@graphql-mesh/runtime": "0.43.3-alpha-20220905180614-53fadb778",
|
|
11
|
+
"@graphql-mesh/utils": "0.41.3-alpha-20220905180614-53fadb778",
|
|
12
|
+
"@whatwg-node/fetch": "0.3.2",
|
|
13
|
+
"@whatwg-node/server": "0.1.2",
|
|
14
|
+
"graphql-yoga": "3.0.0-alpha-20220905163021-e923bb34",
|
|
15
|
+
"itty-router": "2.6.1",
|
|
16
|
+
"itty-router-extras": "0.4.2",
|
|
17
|
+
"tslib": "^2.4.0"
|
|
18
|
+
},
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "Urigo/graphql-mesh",
|
|
22
|
+
"directory": "packages/http"
|
|
23
|
+
},
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"main": "index.js",
|
|
26
|
+
"module": "index.mjs",
|
|
27
|
+
"typings": "index.d.ts",
|
|
28
|
+
"typescript": {
|
|
29
|
+
"definition": "index.d.ts"
|
|
30
|
+
},
|
|
31
|
+
"exports": {
|
|
32
|
+
".": {
|
|
33
|
+
"require": "./index.js",
|
|
34
|
+
"import": "./index.mjs"
|
|
35
|
+
},
|
|
36
|
+
"./*": {
|
|
37
|
+
"require": "./*.js",
|
|
38
|
+
"import": "./*.mjs"
|
|
39
|
+
},
|
|
40
|
+
"./package.json": "./package.json"
|
|
41
|
+
}
|
|
42
|
+
}
|