graphql-http 0.2.0 → 1.0.0

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.
@@ -0,0 +1,206 @@
1
+ (function (global, factory) {
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3
+ typeof define === 'function' && define.amd ? define(['exports'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.graphqlHttp = {}));
5
+ })(this, (function (exports) { 'use strict';
6
+
7
+ /**
8
+ *
9
+ * utils
10
+ *
11
+ */
12
+ /** @private */
13
+ function isObject(val) {
14
+ return typeof val === 'object' && val !== null;
15
+ }
16
+
17
+ /**
18
+ *
19
+ * common
20
+ *
21
+ */
22
+ /**
23
+ * Checks whether the passed value is the `graphql-http` server agnostic response.
24
+ *
25
+ * @category Common
26
+ */
27
+ function isResponse(val) {
28
+ // TODO: make sure the contents of init match ResponseInit
29
+ return Array.isArray(val) && typeof val[0] === 'string' && isObject(val[1]);
30
+ }
31
+
32
+ /**
33
+ *
34
+ * client
35
+ *
36
+ */
37
+ /**
38
+ * Creates a disposable GraphQL over HTTP client to transmit
39
+ * GraphQL operation results.
40
+ *
41
+ * @category Client
42
+ */
43
+ function createClient(options) {
44
+ const { credentials = 'same-origin', referrer, referrerPolicy, shouldRetry = () => false, } = options;
45
+ const fetchFn = (options.fetchFn || fetch);
46
+ const AbortControllerImpl = (options.abortControllerImpl ||
47
+ AbortController);
48
+ // we dont use yet another AbortController here because of
49
+ // node's max EventEmitters listeners being only 10
50
+ const client = (() => {
51
+ let disposed = false;
52
+ const listeners = [];
53
+ return {
54
+ get disposed() {
55
+ return disposed;
56
+ },
57
+ onDispose(cb) {
58
+ if (disposed) {
59
+ // empty the call stack and then call the cb
60
+ setTimeout(() => cb(), 0);
61
+ return () => {
62
+ // noop
63
+ };
64
+ }
65
+ listeners.push(cb);
66
+ return () => {
67
+ listeners.splice(listeners.indexOf(cb), 1);
68
+ };
69
+ },
70
+ dispose() {
71
+ if (disposed)
72
+ return;
73
+ disposed = true;
74
+ // we copy the listeners so that onDispose unlistens dont "pull the rug under our feet"
75
+ for (const listener of [...listeners]) {
76
+ listener();
77
+ }
78
+ },
79
+ };
80
+ })();
81
+ return {
82
+ subscribe(request, sink) {
83
+ if (client.disposed)
84
+ throw new Error('Client has been disposed');
85
+ const control = new AbortControllerImpl();
86
+ const unlisten = client.onDispose(() => {
87
+ unlisten();
88
+ control.abort();
89
+ });
90
+ (async () => {
91
+ var _a;
92
+ let retryingErr = null, retries = 0;
93
+ for (;;) {
94
+ if (retryingErr) {
95
+ const should = await shouldRetry(retryingErr, retries);
96
+ // requst might've been canceled while waiting for retry
97
+ if (control.signal.aborted)
98
+ return;
99
+ if (!should)
100
+ throw retryingErr;
101
+ retries++;
102
+ }
103
+ try {
104
+ const url = typeof options.url === 'function'
105
+ ? await options.url()
106
+ : options.url;
107
+ if (control.signal.aborted)
108
+ return;
109
+ const headers = typeof options.headers === 'function'
110
+ ? await options.headers()
111
+ : (_a = options.headers) !== null && _a !== void 0 ? _a : {};
112
+ if (control.signal.aborted)
113
+ return;
114
+ let res;
115
+ try {
116
+ res = await fetchFn(url, {
117
+ signal: control.signal,
118
+ method: 'POST',
119
+ headers: Object.assign(Object.assign({}, headers), { 'content-type': 'application/json; charset=utf-8', accept: 'application/graphql+json, application/json' }),
120
+ credentials,
121
+ referrer,
122
+ referrerPolicy,
123
+ body: JSON.stringify(request),
124
+ });
125
+ }
126
+ catch (err) {
127
+ throw new NetworkError(err);
128
+ }
129
+ if (!res.ok)
130
+ throw new NetworkError(res);
131
+ if (!res.body)
132
+ throw new Error('Missing response body');
133
+ const contentType = res.headers.get('content-type');
134
+ if (!contentType)
135
+ throw new Error('Missing response content-type');
136
+ if (!contentType.includes('application/graphql+json') &&
137
+ !contentType.includes('application/json')) {
138
+ throw new Error(`Unsupported response content-type ${contentType}`);
139
+ }
140
+ const result = await res.json();
141
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
142
+ sink.next(result);
143
+ return control.abort();
144
+ }
145
+ catch (err) {
146
+ if (control.signal.aborted)
147
+ return;
148
+ // all non-network errors are worth reporting immediately
149
+ if (!(err instanceof NetworkError))
150
+ throw err;
151
+ // try again
152
+ retryingErr = err;
153
+ }
154
+ }
155
+ })()
156
+ .then(() => sink.complete())
157
+ .catch((err) => sink.error(err));
158
+ return () => control.abort();
159
+ },
160
+ dispose() {
161
+ client.dispose();
162
+ },
163
+ };
164
+ }
165
+ /**
166
+ * A network error caused by the client or an unexpected response from the server.
167
+ *
168
+ * To avoid bundling DOM typings (because the client can run in Node env too),
169
+ * you should supply the `Response` generic depending on your Fetch implementation.
170
+ *
171
+ * @category Client
172
+ */
173
+ class NetworkError extends Error {
174
+ constructor(msgOrErrOrResponse) {
175
+ let message, response;
176
+ if (isResponseLike(msgOrErrOrResponse)) {
177
+ response = msgOrErrOrResponse;
178
+ message =
179
+ 'Server responded with ' +
180
+ msgOrErrOrResponse.status +
181
+ ': ' +
182
+ msgOrErrOrResponse.statusText;
183
+ }
184
+ else if (msgOrErrOrResponse instanceof Error)
185
+ message = msgOrErrOrResponse.message;
186
+ else
187
+ message = String(msgOrErrOrResponse);
188
+ super(message);
189
+ this.name = this.constructor.name;
190
+ this.response = response;
191
+ }
192
+ }
193
+ function isResponseLike(val) {
194
+ return (isObject(val) &&
195
+ typeof val['ok'] === 'boolean' &&
196
+ typeof val['status'] === 'number' &&
197
+ typeof val['statusText'] === 'string');
198
+ }
199
+
200
+ exports.NetworkError = NetworkError;
201
+ exports.createClient = createClient;
202
+ exports.isResponse = isResponse;
203
+
204
+ Object.defineProperty(exports, '__esModule', { value: true });
205
+
206
+ }));
@@ -0,0 +1 @@
1
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).graphqlHttp={})}(this,(function(e){"use strict";function t(e){return"object"==typeof e&&null!==e}class r extends Error{constructor(e){let r,o;var n;t(n=e)&&"boolean"==typeof n.ok&&"number"==typeof n.status&&"string"==typeof n.statusText?(o=e,r="Server responded with "+e.status+": "+e.statusText):r=e instanceof Error?e.message:String(e),super(r),this.name=this.constructor.name,this.response=o}}e.NetworkError=r,e.createClient=function(e){const{credentials:t="same-origin",referrer:o,referrerPolicy:n,shouldRetry:s=(()=>!1)}=e,i=e.fetchFn||fetch,a=e.abortControllerImpl||AbortController,c=(()=>{let e=!1;const t=[];return{get disposed(){return e},onDispose:r=>e?(setTimeout((()=>r()),0),()=>{}):(t.push(r),()=>{t.splice(t.indexOf(r),1)}),dispose(){if(!e){e=!0;for(const e of[...t])e()}}}})();return{subscribe(p,f){if(c.disposed)throw new Error("Client has been disposed");const l=new a,u=c.onDispose((()=>{u(),l.abort()}));return(async()=>{var a;let c=null,u=0;for(;;){if(c){const e=await s(c,u);if(l.signal.aborted)return;if(!e)throw c;u++}try{const s="function"==typeof e.url?await e.url():e.url;if(l.signal.aborted)return;const c="function"==typeof e.headers?await e.headers():null!==(a=e.headers)&&void 0!==a?a:{};if(l.signal.aborted)return;let u;try{u=await i(s,{signal:l.signal,method:"POST",headers:Object.assign(Object.assign({},c),{"content-type":"application/json; charset=utf-8",accept:"application/graphql+json, application/json"}),credentials:t,referrer:o,referrerPolicy:n,body:JSON.stringify(p)})}catch(e){throw new r(e)}if(!u.ok)throw new r(u);if(!u.body)throw new Error("Missing response body");const d=u.headers.get("content-type");if(!d)throw new Error("Missing response content-type");if(!d.includes("application/graphql+json")&&!d.includes("application/json"))throw new Error(`Unsupported response content-type ${d}`);const h=await u.json();return f.next(h),l.abort()}catch(e){if(l.signal.aborted)return;if(!(e instanceof r))throw e;c=e}}})().then((()=>f.complete())).catch((e=>f.error(e))),()=>l.abort()},dispose(){c.dispose()}}},e.isResponse=function(e){return Array.isArray(e)&&"string"==typeof e[0]&&t(e[1])},Object.defineProperty(e,"__esModule",{value:!0})}));
Binary file
package/.eslintrc.json DELETED
@@ -1,8 +0,0 @@
1
- {
2
- "ecmaVersion": 5,
3
- "sourceType": "module",
4
- "env": {
5
- "browser": true,
6
- "node": true
7
- }
8
- }
package/.npmignore DELETED
@@ -1,33 +0,0 @@
1
- # Logs
2
- logs
3
- *.log
4
- npm-debug.log*
5
-
6
- # Runtime data
7
- pids
8
- *.pid
9
- *.seed
10
-
11
- # Directory for instrumented libs generated by jscoverage/JSCover
12
- lib-cov
13
-
14
- # Coverage directory used by tools like istanbul
15
- coverage
16
-
17
- # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
18
- .grunt
19
-
20
- # node-waf configuration
21
- .lock-wscript
22
-
23
- # Compiled binary addons (http://nodejs.org/api/addons.html)
24
- build/Release
25
-
26
- # Dependency directory
27
- node_modules
28
-
29
- # Optional npm cache directory
30
- .npm
31
-
32
- # Optional REPL history
33
- .node_repl_history
package/index.js DELETED
@@ -1 +0,0 @@
1
- module.exports = require('./lib');
@@ -1,90 +0,0 @@
1
- 'use strict';
2
-
3
- var url = require('url');
4
- var fetchMock = require('fetch-mock');
5
-
6
- var GQL = require('../');
7
-
8
- describe('GQLClient', function() {
9
- afterEach(function () {
10
- fetchMock.restore();
11
- });
12
-
13
- pit('should work', function () {
14
- fetchMock.get('*', {
15
- body: {data: {whatwhat: true}},
16
- headers: {
17
- 'Content-Type': 'application/json; charset=utf-8'
18
- }
19
- });
20
-
21
- var client = GQL.GQLClient('https://example.com/gql');
22
-
23
- return client.query('query{whatwhat}').then(function (result) {
24
- expect(result).toEqual({
25
- data: {whatwhat: true}
26
- });
27
- });
28
- });
29
-
30
- pit('should properly not work with 200', function () {
31
- fetchMock.get('*', {
32
- body: {errors: [{message: 'you don fucked up'}]},
33
- headers: {
34
- 'Content-Type': 'application/json; charset=utf-8'
35
- }
36
- });
37
-
38
- var client = GQL.GQLClient('https://example.com/gql');
39
-
40
- return client.query('query{whatwhat}').then(fail, function (error) {
41
- expect(error instanceof GQL.GraphQLResponseError).toBe(true);
42
-
43
- expect(error.message).toMatch(/1 error\(s\)/);
44
- expect(error.message).toMatch(/you don fucked up/);
45
- });
46
- });
47
-
48
- pit('should properly not work with different status code', function () {
49
- fetchMock.get('*', {
50
- body: {errors: [{message: 'you don fucked up'}]},
51
- headers: {
52
- 'Content-Type': 'application/json; charset=utf-8'
53
- },
54
- status: 400
55
- });
56
-
57
- var client = GQL.GQLClient('https://example.com/gql');
58
-
59
- return client.query('query{whatwhat}').then(fail, function (error) {
60
- expect(error instanceof GQL.GraphQLResponseError).toBe(true);
61
-
62
- expect(error.message).not.toMatch(/1 error\(s\)/);
63
- expect(error.message).toMatch(/Received status 400/);
64
- expect(error.message).toMatch(/you don fucked up/);
65
- });
66
- });
67
-
68
- pit('should work with onlyBody mutate', function () {
69
- fetchMock.post('*', {
70
- body: {data: {whatwhat: true}},
71
- headers: {
72
- 'Content-Type': 'application/json; charset=utf-8'
73
- }
74
- });
75
-
76
- var client = GQL.GQLClient('https://example.com/gql');
77
-
78
- return client.configure({onlyBody: true})
79
- .mutate('mutation foo{bar(){baz}}')
80
- .then(function (result) {
81
- expect(result).toEqual({
82
- data: {whatwhat: true}
83
- });
84
-
85
- var request = fetchMock.lastCall();
86
-
87
- expect(url.parse(request[0]).search).toBe(null);
88
- });
89
- });
90
- });