@graphql-mesh/transport-http-callback 0.5.4 → 0.5.5-alpha-74ce70ffa76773d89e7e68c4b984a188ea1d816b

Sign up to get free protection for your applications and to get access to all the features.
package/esm/index.js DELETED
@@ -1,196 +0,0 @@
1
- import { process } from '@graphql-mesh/cross-helpers';
2
- import { getInterpolatedHeadersFactory } from '@graphql-mesh/string-interpolation';
3
- import { defaultPrintFn, } from '@graphql-mesh/transport-common';
4
- import { makeDisposable, mapMaybePromise } from '@graphql-mesh/utils';
5
- import { createGraphQLError } from '@graphql-tools/utils';
6
- import { Repeater } from '@repeaterjs/repeater';
7
- import { crypto } from '@whatwg-node/fetch';
8
- function createTimeoutError() {
9
- return createGraphQLError('Subscription timed out', {
10
- extensions: {
11
- code: 'TIMEOUT_ERROR',
12
- },
13
- });
14
- }
15
- export default {
16
- getSubgraphExecutor({ transportEntry, fetch, pubsub, logger }) {
17
- let headersInConfig;
18
- if (typeof transportEntry.headers === 'string') {
19
- headersInConfig = JSON.parse(transportEntry.headers);
20
- }
21
- if (Array.isArray(transportEntry.headers)) {
22
- headersInConfig = Object.fromEntries(transportEntry.headers);
23
- }
24
- const headersFactory = getInterpolatedHeadersFactory(headersInConfig);
25
- const verifier = crypto.randomUUID();
26
- if (!pubsub) {
27
- throw new Error(`You must provide a pubsub instance to http-callbacks transport!
28
- Example:
29
- export const gatewayConfig = defineConfig({
30
- pubsub: new PubSub(),
31
- })
32
- See documentation: https://the-guild.dev/docs/mesh/pubsub`);
33
- }
34
- const reqAbortCtrls = new Set();
35
- const heartbeats = new Map();
36
- const stopFnSet = new Set();
37
- const publicUrl = transportEntry.options?.public_url || 'http://localhost:4000';
38
- const callbackPath = transportEntry.options?.path || '/callback';
39
- const heartbeatIntervalMs = transportEntry.options.heartbeat_interval || 50000;
40
- const httpCallbackExecutor = function httpCallbackExecutor(execReq) {
41
- const query = defaultPrintFn(execReq.document);
42
- const subscriptionId = crypto.randomUUID();
43
- const subscriptionLogger = logger.child(subscriptionId);
44
- const callbackUrl = `${publicUrl}${callbackPath}/${subscriptionId}`;
45
- const subscriptionCallbackPath = `${callbackPath}/${subscriptionId}`;
46
- const fetchBody = JSON.stringify({
47
- query,
48
- variables: execReq.variables,
49
- operationName: execReq.operationName,
50
- extensions: {
51
- ...(execReq.extensions || {}),
52
- subscription: {
53
- callbackUrl,
54
- subscriptionId,
55
- verifier,
56
- heartbeatIntervalMs,
57
- },
58
- },
59
- });
60
- let stopSubscription = error => {
61
- if (error) {
62
- throw error;
63
- }
64
- };
65
- heartbeats.set(subscriptionId, setTimeout(() => {
66
- stopSubscription(createTimeoutError());
67
- }, heartbeatIntervalMs));
68
- subscriptionLogger.debug(`Subscribing to ${transportEntry.location} with callbackUrl: ${callbackUrl}`);
69
- let pushFn = () => {
70
- throw new Error(`Subgraph does not look like configured correctly. Check your subgraph setup.`);
71
- };
72
- const reqAbortCtrl = new AbortController();
73
- const subFetchCall$ = mapMaybePromise(fetch(transportEntry.location, {
74
- method: 'POST',
75
- headers: {
76
- 'Content-Type': 'application/json',
77
- ...headersFactory({
78
- env: process.env,
79
- root: execReq.rootValue,
80
- context: execReq.context,
81
- info: execReq.info,
82
- }),
83
- Accept: 'application/json;callbackSpec=1.0; charset=utf-8',
84
- },
85
- body: fetchBody,
86
- signal: reqAbortCtrl.signal,
87
- }, execReq.context, execReq.info), res => mapMaybePromise(res.text(), resText => {
88
- let resJson;
89
- try {
90
- resJson = JSON.parse(resText);
91
- }
92
- catch (e) {
93
- if (!res.ok) {
94
- stopSubscription(new Error(`Subscription request failed with an HTTP Error: ${res.status} ${resText}`));
95
- }
96
- else {
97
- stopSubscription(e);
98
- }
99
- return;
100
- }
101
- logger.debug(`Subscription request received`, resJson);
102
- if (resJson.errors) {
103
- if (resJson.errors.length === 1) {
104
- stopSubscription(createGraphQLError(resJson.errors[0].message, resJson.errors[0]));
105
- }
106
- else {
107
- stopSubscription(new AggregateError(resJson.errors.map(err => createGraphQLError(err.message, err)), resJson.errors.map(err => err.message).join('\n')));
108
- }
109
- }
110
- else if (resJson.data != null) {
111
- pushFn(resJson.data);
112
- stopSubscription();
113
- }
114
- }), e => {
115
- logger.debug(`Subscription request failed`, e);
116
- stopSubscription(e);
117
- });
118
- execReq.context?.waitUntil?.(subFetchCall$);
119
- return new Repeater((push, stop) => {
120
- pushFn = push;
121
- stopSubscription = stop;
122
- stopFnSet.add(stop);
123
- logger.debug(`Listening to ${subscriptionCallbackPath}`);
124
- const subId = pubsub.subscribe(`webhook:post:${subscriptionCallbackPath}`, (message) => {
125
- logger.debug(`Received message from ${subscriptionCallbackPath}`, message);
126
- if (message.verifier !== verifier) {
127
- return;
128
- }
129
- const existingHeartbeat = heartbeats.get(subscriptionId);
130
- if (existingHeartbeat) {
131
- clearTimeout(existingHeartbeat);
132
- }
133
- heartbeats.set(subscriptionId, setTimeout(() => {
134
- stopSubscription(createTimeoutError());
135
- }, heartbeatIntervalMs));
136
- switch (message.action) {
137
- case 'check':
138
- break;
139
- case 'next':
140
- push(message.payload);
141
- break;
142
- case 'complete':
143
- if (message.errors) {
144
- if (message.errors.length === 1) {
145
- const error = message.errors[0];
146
- stopSubscription(createGraphQLError(error.message, {
147
- ...error,
148
- extensions: {
149
- ...error.extensions,
150
- code: 'DOWNSTREAM_SERVICE_ERROR',
151
- },
152
- }));
153
- }
154
- else {
155
- stopSubscription(new AggregateError(message.errors.map(err => createGraphQLError(err.message, {
156
- ...err,
157
- extensions: {
158
- ...err.extensions,
159
- code: 'DOWNSTREAM_SERVICE_ERROR',
160
- },
161
- }))));
162
- }
163
- }
164
- else {
165
- stopSubscription();
166
- }
167
- break;
168
- }
169
- });
170
- stop.finally(() => {
171
- pubsub.unsubscribe(subId);
172
- clearTimeout(heartbeats.get(subscriptionId));
173
- heartbeats.delete(subscriptionId);
174
- stopFnSet.delete(stop);
175
- if (!reqAbortCtrl.signal.aborted) {
176
- reqAbortCtrl.abort();
177
- }
178
- });
179
- });
180
- };
181
- function disposeFn() {
182
- for (const stop of stopFnSet) {
183
- stop();
184
- }
185
- for (const interval of heartbeats.values()) {
186
- clearTimeout(interval);
187
- }
188
- for (const ctrl of reqAbortCtrls) {
189
- if (!ctrl.signal.aborted) {
190
- ctrl.abort();
191
- }
192
- }
193
- }
194
- return makeDisposable(httpCallbackExecutor, disposeFn);
195
- },
196
- };
@@ -1,23 +0,0 @@
1
- import { type DisposableExecutor } from '@graphql-mesh/transport-common';
2
- export interface HTTPCallbackTransportOptions {
3
- /**
4
- * The gateway's public URL, which your subgraphs access, must include the path configured on the gateway.
5
- *
6
- * @default http://localhost:4000/callback
7
- */
8
- public_url?: string;
9
- /**
10
- * The path of the router's callback endpoint
11
- *
12
- * @default /callback
13
- */
14
- path?: string;
15
- /**
16
- * @default 5000
17
- */
18
- heartbeat_interval?: number;
19
- }
20
- declare const _default: {
21
- getSubgraphExecutor({ transportEntry, fetch, pubsub, logger }: import("@graphql-mesh/transport-common").TransportGetSubgraphExecutorOptions<HTTPCallbackTransportOptions>): DisposableExecutor;
22
- };
23
- export default _default;
@@ -1,23 +0,0 @@
1
- import { type DisposableExecutor } from '@graphql-mesh/transport-common';
2
- export interface HTTPCallbackTransportOptions {
3
- /**
4
- * The gateway's public URL, which your subgraphs access, must include the path configured on the gateway.
5
- *
6
- * @default http://localhost:4000/callback
7
- */
8
- public_url?: string;
9
- /**
10
- * The path of the router's callback endpoint
11
- *
12
- * @default /callback
13
- */
14
- path?: string;
15
- /**
16
- * @default 5000
17
- */
18
- heartbeat_interval?: number;
19
- }
20
- declare const _default: {
21
- getSubgraphExecutor({ transportEntry, fetch, pubsub, logger }: import("@graphql-mesh/transport-common").TransportGetSubgraphExecutorOptions<HTTPCallbackTransportOptions>): DisposableExecutor;
22
- };
23
- export default _default;