@hyper-fetch/graphql 6.0.0 → 7.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.
- package/.eslintrc.json +8 -3
- package/README.md +5 -5
- package/dist/browser/index.js +191 -0
- package/dist/browser/index.js.map +7 -0
- package/dist/index.d.ts +15 -14
- package/dist/index.js +330 -0
- package/dist/index.js.map +7 -0
- package/package.json +18 -19
- package/src/adapter/adapter.constants.ts +3 -2
- package/src/adapter/adapter.ts +6 -22
- package/src/adapter/adapter.types.ts +30 -28
- package/src/adapter/adapter.utils.ts +46 -9
- package/src/adapter/http-adapter.browser.ts +148 -0
- package/src/adapter/http-adapter.server.ts +148 -0
- package/tsconfig.base.json +2 -3
- package/tsconfig.json +3 -3
- package/dist/browser/index.cjs.js +0 -160
- package/dist/browser/index.cjs.js.map +0 -7
- package/dist/browser/index.esm.js +0 -139
- package/dist/browser/index.esm.js.map +0 -7
- package/dist/index.cjs.js +0 -250
- package/dist/index.cjs.js.map +0 -7
- package/dist/index.esm.js +0 -215
- package/dist/index.esm.js.map +0 -7
- package/src/adapter/adapter.browser.ts +0 -90
- package/src/adapter/adapter.server.ts +0 -91
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/index.ts", "../src/adapter/http-adapter.browser.ts", "../src/adapter/http-adapter.server.ts", "../src/adapter/adapter.ts", "../src/adapter/adapter.types.ts", "../src/adapter/adapter.utils.ts", "../src/adapter/adapter.constants.ts"],
|
|
4
|
+
"sourcesContent": ["// rollup client entry point\n\nexport * from \"./adapter\";\n", "import {\n getResponseHeaders,\n parseResponse,\n getErrorMessage,\n Adapter,\n QueryParamsType,\n stringifyKey,\n} from \"@hyper-fetch/core\";\n\nimport {\n gqlExtra,\n GraphqlAdapterType,\n defaultTimeout,\n getRequestValues,\n GraphqlMethod,\n GraphQlExtraType,\n GraphQlEndpointType,\n gqlEndpointMapper,\n gqlEndpointNameMapper,\n} from \"adapter\";\n\nexport const getGqlAdapter = (): GraphqlAdapterType =>\n new Adapter<\n Partial<XMLHttpRequest>,\n GraphqlMethod,\n number,\n GraphQlExtraType,\n QueryParamsType | string,\n undefined,\n GraphQlEndpointType\n >({\n name: \"graphql-browser\",\n defaultMethod: GraphqlMethod.POST,\n defaultExtra: gqlExtra,\n systemErrorStatus: 0,\n systemErrorExtra: gqlExtra,\n })\n .onInitialize(({ client }) => {\n client.setCacheKeyMapper((request) => {\n return `${request.method}_${gqlEndpointNameMapper(request.endpoint)}-${stringifyKey(request.params)}-${stringifyKey(request.queryParams)}`;\n });\n client.setQueryKeyMapper((request) => {\n return `${request.method}_${gqlEndpointNameMapper(request.endpoint)}-${stringifyKey(request.params)}-${stringifyKey(request.queryParams)}`;\n });\n client.setAbortKeyMapper((request) => {\n return `${request.method}_${gqlEndpointNameMapper(request.endpoint)}-${request.cancelable}`;\n });\n })\n .setInternalErrorMapping((error) => [error])\n .setDevtoolsEndpointGetter(gqlEndpointNameMapper)\n .setEndpointMapper(gqlEndpointMapper)\n .setFetcher(\n async ({\n request,\n adapterOptions,\n headers,\n onError,\n onResponseEnd,\n onTimeoutError,\n onRequestEnd,\n createAbortListener,\n onResponseProgress,\n onRequestProgress,\n onResponseStart,\n onBeforeRequest,\n onRequestStart,\n onSuccess,\n }) => {\n const { fullUrl, payload } = getRequestValues(request);\n\n const xhr = new XMLHttpRequest();\n xhr.timeout = defaultTimeout;\n\n const onAbort = () => xhr.abort();\n\n // Inject xhr options\n if (adapterOptions) {\n Object.entries(adapterOptions).forEach(([name, value]) => {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n xhr[name] = value;\n });\n }\n\n // Open connection\n xhr.open(request.method, fullUrl, true);\n\n // Set Headers\n Object.entries(headers).forEach(([name, value]) => xhr.setRequestHeader(name, value as string));\n\n // Listen to abort signal\n const unmountListener = createAbortListener({ status: 0, extra: gqlExtra, onAbort });\n\n // Request handlers\n xhr.upload.onprogress = onRequestProgress;\n\n // Response handlers\n xhr.onloadstart = (): void => {\n onRequestEnd();\n onResponseStart();\n };\n\n xhr.onprogress = onResponseProgress;\n\n xhr.onloadend = () => {\n onResponseEnd();\n unmountListener();\n };\n\n /* istanbul ignore next */\n xhr.ontimeout = () => onTimeoutError({ status: 0, extra: gqlExtra });\n\n // Data handler\n xhr.onreadystatechange = (e: Event) => {\n const event = e as unknown as ProgressEvent<XMLHttpRequest>;\n const finishedState = 4;\n\n if (event.target && event.target.readyState === finishedState) {\n const { status } = event.target;\n const response = parseResponse(event.target.response);\n const data = response.data ?? null;\n const errors = response?.errors || null;\n const extensions = response?.extensions || {};\n const failure = response?.errors || status > 399 || status === 0;\n const responseHeaders = getResponseHeaders(xhr.getAllResponseHeaders());\n\n if (failure) {\n const error = errors || [getErrorMessage()];\n // delay to finish after onabort/ontimeout\n onError({ error, status, extra: { headers: responseHeaders, extensions } });\n } else {\n onSuccess({\n data,\n error: errors,\n status,\n extra: { headers: responseHeaders, extensions },\n });\n }\n }\n };\n\n // Start request\n onBeforeRequest();\n onRequestStart();\n\n xhr.send(payload);\n },\n );\n", "import { Adapter, getErrorMessage, parseErrorResponse, parseResponse, QueryParamsType } from \"@hyper-fetch/core\";\nimport http, { OutgoingHttpHeaders } from \"http\";\nimport https from \"https\";\n\nimport {\n gqlExtra,\n defaultTimeout,\n GraphqlAdapterType,\n getRequestValues,\n GraphQlExtraType,\n GraphqlMethod,\n GraphQlEndpointType,\n gqlEndpointMapper,\n gqlEndpointNameMapper,\n} from \"adapter\";\n\nexport const getGqlAdapter = (): GraphqlAdapterType =>\n new Adapter<\n Partial<XMLHttpRequest>,\n GraphqlMethod,\n number,\n GraphQlExtraType,\n QueryParamsType | string,\n undefined,\n GraphQlEndpointType\n >({\n name: \"graphql-server\",\n defaultMethod: GraphqlMethod.POST,\n defaultExtra: gqlExtra,\n systemErrorStatus: 0,\n systemErrorExtra: gqlExtra,\n })\n .onInitialize(({ client }) => {\n client.setCacheKeyMapper((request) => {\n return `${request.method}_${gqlEndpointNameMapper(request.endpoint)}-${JSON.stringify(request.params)}-${JSON.stringify(request.queryParams)}`;\n });\n client.setQueryKeyMapper((request) => {\n return `${request.method}_${gqlEndpointNameMapper(request.endpoint)}-${JSON.stringify(request.params)}-${JSON.stringify(request.queryParams)}`;\n });\n client.setAbortKeyMapper((request) => {\n return `${request.method}_${gqlEndpointNameMapper(request.endpoint)}-${request.cancelable}`;\n });\n })\n .setInternalErrorMapping((error) => [error])\n .setDevtoolsEndpointGetter(gqlEndpointNameMapper)\n .setEndpointMapper(gqlEndpointMapper)\n .setFetcher(\n async ({\n request,\n adapterOptions,\n headers,\n onError,\n onResponseEnd,\n onTimeoutError,\n onRequestEnd,\n createAbortListener,\n getAbortController,\n onResponseProgress,\n onResponseStart,\n onBeforeRequest,\n onRequestStart,\n onSuccess,\n }) => {\n const { fullUrl, payload } = getRequestValues(request);\n\n const httpClient = request.client.url.includes(\"https://\") ? https : http;\n const options = {\n method: request.method,\n headers: headers as OutgoingHttpHeaders,\n timeout: defaultTimeout,\n signal: getAbortController()?.signal,\n } satisfies https.RequestOptions;\n\n Object.entries(adapterOptions || {}).forEach(([name, value]) => {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n options[name] = value;\n });\n\n onBeforeRequest();\n\n const unmountListener = createAbortListener({\n status: 0,\n extra: gqlExtra,\n });\n\n const httpRequest = httpClient.request(fullUrl, options, (response) => {\n response.setEncoding(\"utf8\");\n\n let chunks = \"\";\n const totalDownloadBytes = Number(response.headers[\"content-length\"]);\n let downloadedBytes = 0;\n\n onRequestStart();\n\n response.on(\"data\", (chunk) => {\n /* istanbul ignore next */\n if (!chunks) {\n onRequestEnd();\n onResponseStart();\n }\n downloadedBytes += chunk.length;\n chunks += chunk;\n onResponseProgress({ total: totalDownloadBytes, loaded: downloadedBytes });\n });\n\n response.on(\"end\", () => {\n /* istanbul ignore next */\n const { statusCode = 0 } = response;\n const success = String(statusCode).startsWith(\"2\") || String(statusCode).startsWith(\"3\");\n\n if (success) {\n const { data, errors, extensions } = parseResponse(chunks);\n onSuccess({\n data: data ?? null,\n error: errors,\n status: statusCode,\n extra: { headers: response.headers as Record<string, string>, extensions: extensions ?? {} },\n });\n } else {\n // delay to finish after onabort/ontimeout\n const result = parseErrorResponse(chunks);\n /* istanbul ignore next */\n const error = \"errors\" in result ? result.errors : null;\n /* istanbul ignore next */\n const extensions = \"extensions\" in result ? result.extensions : {};\n\n onError({\n error: error ?? [getErrorMessage()],\n status: statusCode,\n extra: { headers: response.headers as Record<string, string>, extensions },\n });\n }\n\n unmountListener();\n onResponseEnd();\n });\n });\n\n /* istanbul ignore next */\n httpRequest.on(\"timeout\", () => onTimeoutError({ status: 0, extra: gqlExtra }));\n httpRequest.on(\"error\", (error) => onError({ error, status: 0, extra: gqlExtra }));\n if (payload) {\n httpRequest.write(payload);\n }\n httpRequest.end();\n },\n );\n", "import * as browser from \"@browser-adapter\";\nimport * as server from \"@server-adapter\";\n\nimport { GraphqlAdapterType } from \"./adapter.types\";\n\nexport const GraphqlAdapter = (): GraphqlAdapterType => {\n if (typeof XMLHttpRequest !== \"undefined\") {\n return browser.getGqlAdapter();\n }\n return server.getGqlAdapter();\n};\n", "import { Adapter, EmptyTypes, QueryParamsType } from \"@hyper-fetch/core\";\nimport { DocumentNode } from \"graphql/language/ast\";\n\nexport enum GraphqlMethod {\n POST = \"POST\",\n GET = \"GET\",\n}\n\nexport type GraphQlExtraType = { headers: HeadersInit; extensions: Record<string, any> };\n\nexport type GraphQlEndpointType = string | DocumentNode;\n\nexport type GraphqlAdapterType = Adapter<\n Partial<XMLHttpRequest>,\n GraphqlMethod,\n number,\n GraphQlExtraType,\n QueryParamsType | string,\n undefined,\n GraphQlEndpointType,\n (endpoint: GraphQlEndpointType) => string\n>;\n\n// Extract\n\ntype GqlParamType = boolean | string | number | Record<string, any> | EmptyTypes;\n\nexport type ExtractGqlRouteParams<T extends string> = string extends T\n ? EmptyTypes\n : T extends `${string}query ${infer Parameters} {${infer QueryRest}`\n ? Parameters extends `${string}$${infer Param},${infer Rest}`\n ? GqlParameter<Param, Rest> &\n // eslint-disable-next-line @typescript-eslint/ban-types\n (ExtractGqlRouteParams<QueryRest> extends EmptyTypes ? {} : ExtractGqlRouteParams<QueryRest>)\n : Parameters extends `${string}$${infer Param})${infer Rest}`\n ? GqlParameter<Param, Rest> &\n // eslint-disable-next-line @typescript-eslint/ban-types\n (ExtractGqlRouteParams<QueryRest> extends EmptyTypes ? {} : ExtractGqlRouteParams<QueryRest>)\n : EmptyTypes\n : T extends `${string}$${infer Parameters},${infer Rest}`\n ? GqlParameter<Parameters, Rest>\n : T extends `${string}$${infer Parameters})${infer Rest}`\n ? GqlParameter<Parameters, Rest>\n : EmptyTypes;\n\nexport type GqlParameter<T extends string, Rest extends string> = T extends `${infer Param}:${string}!`\n ? { [k in Param]: GqlParamType } & (ExtractGqlRouteParams<Rest> extends EmptyTypes\n ? // eslint-disable-next-line @typescript-eslint/ban-types\n {}\n : ExtractGqlRouteParams<Rest>)\n : T extends `${infer Param}:${string}`\n ? { [k in Param]?: GqlParamType } & (ExtractGqlRouteParams<Rest> extends EmptyTypes\n ? // eslint-disable-next-line @typescript-eslint/ban-types\n {}\n : ExtractGqlRouteParams<Rest>)\n : EmptyTypes;\n", "import { RequestInstance, HttpMethods, stringifyQueryParams } from \"@hyper-fetch/core\";\nimport { print, parse, OperationDefinitionNode } from \"graphql\";\n\nimport { GraphQlEndpointType } from \"adapter\";\n\nexport const getRequestValues = <R extends RequestInstance>(request: R) => {\n const isPostRequest = request.method === HttpMethods.POST;\n\n const query = request.endpoint;\n const variables = request.payload;\n\n const fullUrl = isPostRequest ? request.client.url : request.client.url + stringifyQueryParams({ query, variables });\n\n const payload = isPostRequest\n ? JSON.stringify({\n query,\n variables,\n })\n : null;\n\n return { fullUrl, payload };\n};\n\nexport const gqlEndpointMapper = <E extends GraphQlEndpointType>(endpoint: E): string => {\n if (typeof endpoint === \"string\") {\n return endpoint;\n }\n return print(endpoint);\n};\n\nexport const gqlEndpointNameMapper = (endpoint: string): string => {\n try {\n const ast = parse(endpoint);\n const operationDefinition = ast.definitions.find(\n (def): def is OperationDefinitionNode => def.kind === \"OperationDefinition\",\n );\n\n if (operationDefinition) {\n if (operationDefinition.name?.value) {\n return operationDefinition.name.value;\n }\n\n const selection = operationDefinition.selectionSet.selections[0];\n if (selection?.kind === \"Field\") {\n return selection.name.value;\n }\n }\n } catch (error) {\n // We can ignore this error and just return some fallback\n }\n\n // Fallback for invalid gql queries or something else\n const clearedQuery = endpoint\n .replace(/(query|mutation|subscription)/, \"\")\n .replace(/[{}().,:]/g, \" \")\n .trim();\n const [name] = clearedQuery.split(\" \");\n\n return name || \"graphql-request\";\n};\n", "import { Time } from \"@hyper-fetch/core\";\n\nimport { GraphQlExtraType } from \"./adapter.types\";\n\nexport const defaultTimeout = Time.SEC * 5;\n\nexport const gqlExtra: GraphQlExtraType = {\n headers: {},\n extensions: {},\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["import_core", "getGqlAdapter", "https", "http", "getGqlAdapter", "GraphqlMethod", "import_core", "import_core"]
|
|
7
|
+
}
|
package/package.json
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyper-fetch/graphql",
|
|
3
|
-
"version": "
|
|
4
|
-
"private": false,
|
|
3
|
+
"version": "7.0.0",
|
|
5
4
|
"description": "Simple graphql adapter",
|
|
6
|
-
"author": "Maciej Pyrc <
|
|
5
|
+
"author": "Maciej Pyrc <maciekpyrc@gmail.com>, Kacper Skawina <kacper.skawina@gmail.com>",
|
|
7
6
|
"homepage": "https://hyperfetch.bettertyped.com/",
|
|
8
7
|
"license": "Apache-2.0",
|
|
9
|
-
"main": "dist/index.
|
|
10
|
-
"module": "dist/index.
|
|
11
|
-
"client": "dist/browser/index.
|
|
12
|
-
"browser": "dist/browser/index.
|
|
13
|
-
"server": "dist/server/index.
|
|
14
|
-
"node": "dist/server/index.
|
|
8
|
+
"main": "dist/index.js",
|
|
9
|
+
"module": "dist/index.js",
|
|
10
|
+
"client": "dist/browser/index.js",
|
|
11
|
+
"browser": "dist/browser/index.js",
|
|
12
|
+
"server": "dist/server/index.js",
|
|
13
|
+
"node": "dist/server/index.js",
|
|
15
14
|
"types": "dist/index.d.ts",
|
|
16
15
|
"source": "src/index.ts",
|
|
17
16
|
"exports": {
|
|
@@ -20,26 +19,26 @@
|
|
|
20
19
|
"import": "./dist/index.d.ts"
|
|
21
20
|
},
|
|
22
21
|
"browser": {
|
|
23
|
-
"require": "./dist/browser/index.
|
|
24
|
-
"import": "./dist/browser/index.
|
|
22
|
+
"require": "./dist/browser/index.js",
|
|
23
|
+
"import": "./dist/browser/index.js"
|
|
25
24
|
},
|
|
26
25
|
"default": {
|
|
27
|
-
"require": "./dist/index.
|
|
28
|
-
"import": "./dist/index.
|
|
26
|
+
"require": "./dist/index.js",
|
|
27
|
+
"import": "./dist/index.js"
|
|
29
28
|
}
|
|
30
29
|
},
|
|
31
30
|
"./package.json": "./package.json"
|
|
32
31
|
},
|
|
33
32
|
"scripts": {
|
|
34
33
|
"clean": "npx rimraf dist",
|
|
35
|
-
"test": "jest --watchAll --maxWorkers=3",
|
|
36
|
-
"test-pipeline": "jest --watchAll=false --maxWorkers=1 --no-cache",
|
|
34
|
+
"test": "jest --watchAll --maxWorkers=3 --forceExit",
|
|
35
|
+
"test-pipeline": "jest --watchAll=false --maxWorkers=1 --no-cache --forceExit",
|
|
37
36
|
"start": "yarn build && npx run-when-changed --watch 'src/**/*.ts' --exec 'yarn build'",
|
|
38
37
|
"build": "yarn clean && node ../../scripts/build.js",
|
|
39
38
|
"postbuild": "rollup -c '../../rollup.config.js'",
|
|
40
39
|
"lint": "eslint . --ext .js,.jsx,.tsx,.ts --fix",
|
|
41
40
|
"format": "prettier --write .",
|
|
42
|
-
"
|
|
41
|
+
"typescheck": "tsc --noEmit --emitDeclarationOnly false",
|
|
43
42
|
"tests": "yarn lint-staged",
|
|
44
43
|
"release": "yarn semantic-release --extends ../../release.config.js -t 'hyper-fetch-graphql-v${version}'"
|
|
45
44
|
},
|
|
@@ -56,11 +55,11 @@
|
|
|
56
55
|
"url": "https://github.com/BetterTyped/hyper-fetch/issues"
|
|
57
56
|
},
|
|
58
57
|
"peerDependencies": {
|
|
59
|
-
"@hyper-fetch/core": "*"
|
|
60
|
-
"graphql": "*"
|
|
58
|
+
"@hyper-fetch/core": "*"
|
|
61
59
|
},
|
|
62
60
|
"dependencies": {
|
|
63
|
-
"events": "^3.3.0"
|
|
61
|
+
"events": "^3.3.0",
|
|
62
|
+
"graphql": "*"
|
|
64
63
|
},
|
|
65
64
|
"devDependencies": {
|
|
66
65
|
"abortcontroller-polyfill": "^1.7.5",
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Time } from "@hyper-fetch/core";
|
|
2
2
|
|
|
3
3
|
import { GraphQlExtraType } from "./adapter.types";
|
|
4
4
|
|
|
5
|
-
export const defaultTimeout =
|
|
5
|
+
export const defaultTimeout = Time.SEC * 5;
|
|
6
6
|
|
|
7
7
|
export const gqlExtra: GraphQlExtraType = {
|
|
8
8
|
headers: {},
|
|
9
|
+
extensions: {},
|
|
9
10
|
};
|
package/src/adapter/adapter.ts
CHANGED
|
@@ -1,27 +1,11 @@
|
|
|
1
1
|
import * as browser from "@browser-adapter";
|
|
2
2
|
import * as server from "@server-adapter";
|
|
3
|
-
import { HttpMethodsEnum, ClientInstance } from "@hyper-fetch/core";
|
|
4
|
-
import { print } from "graphql/language/printer";
|
|
5
3
|
|
|
6
|
-
import {
|
|
4
|
+
import { GraphqlAdapterType } from "./adapter.types";
|
|
7
5
|
|
|
8
|
-
export const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
return server.adapter(request, requestId);
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
const mapper = <E extends GraphQlEndpointType>(endpoint: E): string => {
|
|
17
|
-
if (typeof endpoint === "string") {
|
|
18
|
-
return endpoint;
|
|
19
|
-
}
|
|
20
|
-
return print(endpoint);
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
return client
|
|
24
|
-
.setDefaultMethod(HttpMethodsEnum.post)
|
|
25
|
-
.setEndpointMapper(mapper)
|
|
26
|
-
.setAdapter(() => adapter);
|
|
6
|
+
export const GraphqlAdapter = (): GraphqlAdapterType => {
|
|
7
|
+
if (typeof XMLHttpRequest !== "undefined") {
|
|
8
|
+
return browser.getGqlAdapter();
|
|
9
|
+
}
|
|
10
|
+
return server.getGqlAdapter();
|
|
27
11
|
};
|
|
@@ -1,54 +1,56 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Adapter, EmptyTypes, QueryParamsType } from "@hyper-fetch/core";
|
|
2
2
|
import { DocumentNode } from "graphql/language/ast";
|
|
3
3
|
|
|
4
|
-
export enum
|
|
4
|
+
export enum GraphqlMethod {
|
|
5
5
|
POST = "POST",
|
|
6
6
|
GET = "GET",
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
export type GraphQlExtraType = { headers: HeadersInit };
|
|
9
|
+
export type GraphQlExtraType = { headers: HeadersInit; extensions: Record<string, any> };
|
|
10
10
|
|
|
11
11
|
export type GraphQlEndpointType = string | DocumentNode;
|
|
12
12
|
|
|
13
|
-
export type
|
|
13
|
+
export type GraphqlAdapterType = Adapter<
|
|
14
14
|
Partial<XMLHttpRequest>,
|
|
15
|
-
|
|
15
|
+
GraphqlMethod,
|
|
16
16
|
number,
|
|
17
17
|
GraphQlExtraType,
|
|
18
18
|
QueryParamsType | string,
|
|
19
|
-
|
|
19
|
+
undefined,
|
|
20
|
+
GraphQlEndpointType,
|
|
21
|
+
(endpoint: GraphQlEndpointType) => string
|
|
20
22
|
>;
|
|
21
23
|
|
|
22
24
|
// Extract
|
|
23
25
|
|
|
24
|
-
type GqlParamType = boolean | string | number | Record<string, any> |
|
|
26
|
+
type GqlParamType = boolean | string | number | Record<string, any> | EmptyTypes;
|
|
25
27
|
|
|
26
28
|
export type ExtractGqlRouteParams<T extends string> = string extends T
|
|
27
|
-
?
|
|
29
|
+
? EmptyTypes
|
|
28
30
|
: T extends `${string}query ${infer Parameters} {${infer QueryRest}`
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
31
|
+
? Parameters extends `${string}$${infer Param},${infer Rest}`
|
|
32
|
+
? GqlParameter<Param, Rest> &
|
|
33
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
34
|
+
(ExtractGqlRouteParams<QueryRest> extends EmptyTypes ? {} : ExtractGqlRouteParams<QueryRest>)
|
|
35
|
+
: Parameters extends `${string}$${infer Param})${infer Rest}`
|
|
36
|
+
? GqlParameter<Param, Rest> &
|
|
37
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
38
|
+
(ExtractGqlRouteParams<QueryRest> extends EmptyTypes ? {} : ExtractGqlRouteParams<QueryRest>)
|
|
39
|
+
: EmptyTypes
|
|
40
|
+
: T extends `${string}$${infer Parameters},${infer Rest}`
|
|
41
|
+
? GqlParameter<Parameters, Rest>
|
|
42
|
+
: T extends `${string}$${infer Parameters})${infer Rest}`
|
|
43
|
+
? GqlParameter<Parameters, Rest>
|
|
44
|
+
: EmptyTypes;
|
|
43
45
|
|
|
44
46
|
export type GqlParameter<T extends string, Rest extends string> = T extends `${infer Param}:${string}!`
|
|
45
|
-
? { [k in Param]: GqlParamType } & (ExtractGqlRouteParams<Rest> extends
|
|
47
|
+
? { [k in Param]: GqlParamType } & (ExtractGqlRouteParams<Rest> extends EmptyTypes
|
|
46
48
|
? // eslint-disable-next-line @typescript-eslint/ban-types
|
|
47
49
|
{}
|
|
48
50
|
: ExtractGqlRouteParams<Rest>)
|
|
49
51
|
: T extends `${infer Param}:${string}`
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
? { [k in Param]?: GqlParamType } & (ExtractGqlRouteParams<Rest> extends EmptyTypes
|
|
53
|
+
? // eslint-disable-next-line @typescript-eslint/ban-types
|
|
54
|
+
{}
|
|
55
|
+
: ExtractGqlRouteParams<Rest>)
|
|
56
|
+
: EmptyTypes;
|
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
import { RequestInstance,
|
|
1
|
+
import { RequestInstance, HttpMethods, stringifyQueryParams } from "@hyper-fetch/core";
|
|
2
|
+
import { print, parse, OperationDefinitionNode } from "graphql";
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
const { method } = request;
|
|
4
|
+
import { GraphQlEndpointType } from "adapter";
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
export const getRequestValues = <R extends RequestInstance>(request: R) => {
|
|
7
|
+
const isPostRequest = request.method === HttpMethods.POST;
|
|
7
8
|
|
|
8
9
|
const query = request.endpoint;
|
|
9
|
-
const variables = request.
|
|
10
|
+
const variables = request.payload;
|
|
10
11
|
|
|
11
|
-
const fullUrl = isPostRequest
|
|
12
|
-
? request.client.url
|
|
13
|
-
: request.client.url + request.client.stringifyQueryParams({ query, variables });
|
|
12
|
+
const fullUrl = isPostRequest ? request.client.url : request.client.url + stringifyQueryParams({ query, variables });
|
|
14
13
|
|
|
15
14
|
const payload = isPostRequest
|
|
16
15
|
? JSON.stringify({
|
|
@@ -19,5 +18,43 @@ export const getRequestValues = (request: RequestInstance) => {
|
|
|
19
18
|
})
|
|
20
19
|
: null;
|
|
21
20
|
|
|
22
|
-
return { fullUrl, payload
|
|
21
|
+
return { fullUrl, payload };
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const gqlEndpointMapper = <E extends GraphQlEndpointType>(endpoint: E): string => {
|
|
25
|
+
if (typeof endpoint === "string") {
|
|
26
|
+
return endpoint;
|
|
27
|
+
}
|
|
28
|
+
return print(endpoint);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const gqlEndpointNameMapper = (endpoint: string): string => {
|
|
32
|
+
try {
|
|
33
|
+
const ast = parse(endpoint);
|
|
34
|
+
const operationDefinition = ast.definitions.find(
|
|
35
|
+
(def): def is OperationDefinitionNode => def.kind === "OperationDefinition",
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
if (operationDefinition) {
|
|
39
|
+
if (operationDefinition.name?.value) {
|
|
40
|
+
return operationDefinition.name.value;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const selection = operationDefinition.selectionSet.selections[0];
|
|
44
|
+
if (selection?.kind === "Field") {
|
|
45
|
+
return selection.name.value;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
} catch (error) {
|
|
49
|
+
// We can ignore this error and just return some fallback
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Fallback for invalid gql queries or something else
|
|
53
|
+
const clearedQuery = endpoint
|
|
54
|
+
.replace(/(query|mutation|subscription)/, "")
|
|
55
|
+
.replace(/[{}().,:]/g, " ")
|
|
56
|
+
.trim();
|
|
57
|
+
const [name] = clearedQuery.split(" ");
|
|
58
|
+
|
|
59
|
+
return name || "graphql-request";
|
|
23
60
|
};
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getResponseHeaders,
|
|
3
|
+
parseResponse,
|
|
4
|
+
getErrorMessage,
|
|
5
|
+
Adapter,
|
|
6
|
+
QueryParamsType,
|
|
7
|
+
stringifyKey,
|
|
8
|
+
} from "@hyper-fetch/core";
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
gqlExtra,
|
|
12
|
+
GraphqlAdapterType,
|
|
13
|
+
defaultTimeout,
|
|
14
|
+
getRequestValues,
|
|
15
|
+
GraphqlMethod,
|
|
16
|
+
GraphQlExtraType,
|
|
17
|
+
GraphQlEndpointType,
|
|
18
|
+
gqlEndpointMapper,
|
|
19
|
+
gqlEndpointNameMapper,
|
|
20
|
+
} from "adapter";
|
|
21
|
+
|
|
22
|
+
export const getGqlAdapter = (): GraphqlAdapterType =>
|
|
23
|
+
new Adapter<
|
|
24
|
+
Partial<XMLHttpRequest>,
|
|
25
|
+
GraphqlMethod,
|
|
26
|
+
number,
|
|
27
|
+
GraphQlExtraType,
|
|
28
|
+
QueryParamsType | string,
|
|
29
|
+
undefined,
|
|
30
|
+
GraphQlEndpointType
|
|
31
|
+
>({
|
|
32
|
+
name: "graphql-browser",
|
|
33
|
+
defaultMethod: GraphqlMethod.POST,
|
|
34
|
+
defaultExtra: gqlExtra,
|
|
35
|
+
systemErrorStatus: 0,
|
|
36
|
+
systemErrorExtra: gqlExtra,
|
|
37
|
+
})
|
|
38
|
+
.onInitialize(({ client }) => {
|
|
39
|
+
client.setCacheKeyMapper((request) => {
|
|
40
|
+
return `${request.method}_${gqlEndpointNameMapper(request.endpoint)}-${stringifyKey(request.params)}-${stringifyKey(request.queryParams)}`;
|
|
41
|
+
});
|
|
42
|
+
client.setQueryKeyMapper((request) => {
|
|
43
|
+
return `${request.method}_${gqlEndpointNameMapper(request.endpoint)}-${stringifyKey(request.params)}-${stringifyKey(request.queryParams)}`;
|
|
44
|
+
});
|
|
45
|
+
client.setAbortKeyMapper((request) => {
|
|
46
|
+
return `${request.method}_${gqlEndpointNameMapper(request.endpoint)}-${request.cancelable}`;
|
|
47
|
+
});
|
|
48
|
+
})
|
|
49
|
+
.setInternalErrorMapping((error) => [error])
|
|
50
|
+
.setDevtoolsEndpointGetter(gqlEndpointNameMapper)
|
|
51
|
+
.setEndpointMapper(gqlEndpointMapper)
|
|
52
|
+
.setFetcher(
|
|
53
|
+
async ({
|
|
54
|
+
request,
|
|
55
|
+
adapterOptions,
|
|
56
|
+
headers,
|
|
57
|
+
onError,
|
|
58
|
+
onResponseEnd,
|
|
59
|
+
onTimeoutError,
|
|
60
|
+
onRequestEnd,
|
|
61
|
+
createAbortListener,
|
|
62
|
+
onResponseProgress,
|
|
63
|
+
onRequestProgress,
|
|
64
|
+
onResponseStart,
|
|
65
|
+
onBeforeRequest,
|
|
66
|
+
onRequestStart,
|
|
67
|
+
onSuccess,
|
|
68
|
+
}) => {
|
|
69
|
+
const { fullUrl, payload } = getRequestValues(request);
|
|
70
|
+
|
|
71
|
+
const xhr = new XMLHttpRequest();
|
|
72
|
+
xhr.timeout = defaultTimeout;
|
|
73
|
+
|
|
74
|
+
const onAbort = () => xhr.abort();
|
|
75
|
+
|
|
76
|
+
// Inject xhr options
|
|
77
|
+
if (adapterOptions) {
|
|
78
|
+
Object.entries(adapterOptions).forEach(([name, value]) => {
|
|
79
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
80
|
+
// @ts-ignore
|
|
81
|
+
xhr[name] = value;
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Open connection
|
|
86
|
+
xhr.open(request.method, fullUrl, true);
|
|
87
|
+
|
|
88
|
+
// Set Headers
|
|
89
|
+
Object.entries(headers).forEach(([name, value]) => xhr.setRequestHeader(name, value as string));
|
|
90
|
+
|
|
91
|
+
// Listen to abort signal
|
|
92
|
+
const unmountListener = createAbortListener({ status: 0, extra: gqlExtra, onAbort });
|
|
93
|
+
|
|
94
|
+
// Request handlers
|
|
95
|
+
xhr.upload.onprogress = onRequestProgress;
|
|
96
|
+
|
|
97
|
+
// Response handlers
|
|
98
|
+
xhr.onloadstart = (): void => {
|
|
99
|
+
onRequestEnd();
|
|
100
|
+
onResponseStart();
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
xhr.onprogress = onResponseProgress;
|
|
104
|
+
|
|
105
|
+
xhr.onloadend = () => {
|
|
106
|
+
onResponseEnd();
|
|
107
|
+
unmountListener();
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
/* istanbul ignore next */
|
|
111
|
+
xhr.ontimeout = () => onTimeoutError({ status: 0, extra: gqlExtra });
|
|
112
|
+
|
|
113
|
+
// Data handler
|
|
114
|
+
xhr.onreadystatechange = (e: Event) => {
|
|
115
|
+
const event = e as unknown as ProgressEvent<XMLHttpRequest>;
|
|
116
|
+
const finishedState = 4;
|
|
117
|
+
|
|
118
|
+
if (event.target && event.target.readyState === finishedState) {
|
|
119
|
+
const { status } = event.target;
|
|
120
|
+
const response = parseResponse(event.target.response);
|
|
121
|
+
const data = response.data ?? null;
|
|
122
|
+
const errors = response?.errors || null;
|
|
123
|
+
const extensions = response?.extensions || {};
|
|
124
|
+
const failure = response?.errors || status > 399 || status === 0;
|
|
125
|
+
const responseHeaders = getResponseHeaders(xhr.getAllResponseHeaders());
|
|
126
|
+
|
|
127
|
+
if (failure) {
|
|
128
|
+
const error = errors || [getErrorMessage()];
|
|
129
|
+
// delay to finish after onabort/ontimeout
|
|
130
|
+
onError({ error, status, extra: { headers: responseHeaders, extensions } });
|
|
131
|
+
} else {
|
|
132
|
+
onSuccess({
|
|
133
|
+
data,
|
|
134
|
+
error: errors,
|
|
135
|
+
status,
|
|
136
|
+
extra: { headers: responseHeaders, extensions },
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
// Start request
|
|
143
|
+
onBeforeRequest();
|
|
144
|
+
onRequestStart();
|
|
145
|
+
|
|
146
|
+
xhr.send(payload);
|
|
147
|
+
},
|
|
148
|
+
);
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { Adapter, getErrorMessage, parseErrorResponse, parseResponse, QueryParamsType } from "@hyper-fetch/core";
|
|
2
|
+
import http, { OutgoingHttpHeaders } from "http";
|
|
3
|
+
import https from "https";
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
gqlExtra,
|
|
7
|
+
defaultTimeout,
|
|
8
|
+
GraphqlAdapterType,
|
|
9
|
+
getRequestValues,
|
|
10
|
+
GraphQlExtraType,
|
|
11
|
+
GraphqlMethod,
|
|
12
|
+
GraphQlEndpointType,
|
|
13
|
+
gqlEndpointMapper,
|
|
14
|
+
gqlEndpointNameMapper,
|
|
15
|
+
} from "adapter";
|
|
16
|
+
|
|
17
|
+
export const getGqlAdapter = (): GraphqlAdapterType =>
|
|
18
|
+
new Adapter<
|
|
19
|
+
Partial<XMLHttpRequest>,
|
|
20
|
+
GraphqlMethod,
|
|
21
|
+
number,
|
|
22
|
+
GraphQlExtraType,
|
|
23
|
+
QueryParamsType | string,
|
|
24
|
+
undefined,
|
|
25
|
+
GraphQlEndpointType
|
|
26
|
+
>({
|
|
27
|
+
name: "graphql-server",
|
|
28
|
+
defaultMethod: GraphqlMethod.POST,
|
|
29
|
+
defaultExtra: gqlExtra,
|
|
30
|
+
systemErrorStatus: 0,
|
|
31
|
+
systemErrorExtra: gqlExtra,
|
|
32
|
+
})
|
|
33
|
+
.onInitialize(({ client }) => {
|
|
34
|
+
client.setCacheKeyMapper((request) => {
|
|
35
|
+
return `${request.method}_${gqlEndpointNameMapper(request.endpoint)}-${JSON.stringify(request.params)}-${JSON.stringify(request.queryParams)}`;
|
|
36
|
+
});
|
|
37
|
+
client.setQueryKeyMapper((request) => {
|
|
38
|
+
return `${request.method}_${gqlEndpointNameMapper(request.endpoint)}-${JSON.stringify(request.params)}-${JSON.stringify(request.queryParams)}`;
|
|
39
|
+
});
|
|
40
|
+
client.setAbortKeyMapper((request) => {
|
|
41
|
+
return `${request.method}_${gqlEndpointNameMapper(request.endpoint)}-${request.cancelable}`;
|
|
42
|
+
});
|
|
43
|
+
})
|
|
44
|
+
.setInternalErrorMapping((error) => [error])
|
|
45
|
+
.setDevtoolsEndpointGetter(gqlEndpointNameMapper)
|
|
46
|
+
.setEndpointMapper(gqlEndpointMapper)
|
|
47
|
+
.setFetcher(
|
|
48
|
+
async ({
|
|
49
|
+
request,
|
|
50
|
+
adapterOptions,
|
|
51
|
+
headers,
|
|
52
|
+
onError,
|
|
53
|
+
onResponseEnd,
|
|
54
|
+
onTimeoutError,
|
|
55
|
+
onRequestEnd,
|
|
56
|
+
createAbortListener,
|
|
57
|
+
getAbortController,
|
|
58
|
+
onResponseProgress,
|
|
59
|
+
onResponseStart,
|
|
60
|
+
onBeforeRequest,
|
|
61
|
+
onRequestStart,
|
|
62
|
+
onSuccess,
|
|
63
|
+
}) => {
|
|
64
|
+
const { fullUrl, payload } = getRequestValues(request);
|
|
65
|
+
|
|
66
|
+
const httpClient = request.client.url.includes("https://") ? https : http;
|
|
67
|
+
const options = {
|
|
68
|
+
method: request.method,
|
|
69
|
+
headers: headers as OutgoingHttpHeaders,
|
|
70
|
+
timeout: defaultTimeout,
|
|
71
|
+
signal: getAbortController()?.signal,
|
|
72
|
+
} satisfies https.RequestOptions;
|
|
73
|
+
|
|
74
|
+
Object.entries(adapterOptions || {}).forEach(([name, value]) => {
|
|
75
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
76
|
+
// @ts-ignore
|
|
77
|
+
options[name] = value;
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
onBeforeRequest();
|
|
81
|
+
|
|
82
|
+
const unmountListener = createAbortListener({
|
|
83
|
+
status: 0,
|
|
84
|
+
extra: gqlExtra,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
const httpRequest = httpClient.request(fullUrl, options, (response) => {
|
|
88
|
+
response.setEncoding("utf8");
|
|
89
|
+
|
|
90
|
+
let chunks = "";
|
|
91
|
+
const totalDownloadBytes = Number(response.headers["content-length"]);
|
|
92
|
+
let downloadedBytes = 0;
|
|
93
|
+
|
|
94
|
+
onRequestStart();
|
|
95
|
+
|
|
96
|
+
response.on("data", (chunk) => {
|
|
97
|
+
/* istanbul ignore next */
|
|
98
|
+
if (!chunks) {
|
|
99
|
+
onRequestEnd();
|
|
100
|
+
onResponseStart();
|
|
101
|
+
}
|
|
102
|
+
downloadedBytes += chunk.length;
|
|
103
|
+
chunks += chunk;
|
|
104
|
+
onResponseProgress({ total: totalDownloadBytes, loaded: downloadedBytes });
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
response.on("end", () => {
|
|
108
|
+
/* istanbul ignore next */
|
|
109
|
+
const { statusCode = 0 } = response;
|
|
110
|
+
const success = String(statusCode).startsWith("2") || String(statusCode).startsWith("3");
|
|
111
|
+
|
|
112
|
+
if (success) {
|
|
113
|
+
const { data, errors, extensions } = parseResponse(chunks);
|
|
114
|
+
onSuccess({
|
|
115
|
+
data: data ?? null,
|
|
116
|
+
error: errors,
|
|
117
|
+
status: statusCode,
|
|
118
|
+
extra: { headers: response.headers as Record<string, string>, extensions: extensions ?? {} },
|
|
119
|
+
});
|
|
120
|
+
} else {
|
|
121
|
+
// delay to finish after onabort/ontimeout
|
|
122
|
+
const result = parseErrorResponse(chunks);
|
|
123
|
+
/* istanbul ignore next */
|
|
124
|
+
const error = "errors" in result ? result.errors : null;
|
|
125
|
+
/* istanbul ignore next */
|
|
126
|
+
const extensions = "extensions" in result ? result.extensions : {};
|
|
127
|
+
|
|
128
|
+
onError({
|
|
129
|
+
error: error ?? [getErrorMessage()],
|
|
130
|
+
status: statusCode,
|
|
131
|
+
extra: { headers: response.headers as Record<string, string>, extensions },
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
unmountListener();
|
|
136
|
+
onResponseEnd();
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
/* istanbul ignore next */
|
|
141
|
+
httpRequest.on("timeout", () => onTimeoutError({ status: 0, extra: gqlExtra }));
|
|
142
|
+
httpRequest.on("error", (error) => onError({ error, status: 0, extra: gqlExtra }));
|
|
143
|
+
if (payload) {
|
|
144
|
+
httpRequest.write(payload);
|
|
145
|
+
}
|
|
146
|
+
httpRequest.end();
|
|
147
|
+
},
|
|
148
|
+
);
|
package/tsconfig.base.json
CHANGED
|
@@ -4,10 +4,9 @@
|
|
|
4
4
|
"rootDir": "./src",
|
|
5
5
|
"baseUrl": "./src",
|
|
6
6
|
"paths": {
|
|
7
|
-
"@browser-adapter": ["./adapter/adapter.browser.ts"],
|
|
8
|
-
"@server-adapter": ["./adapter/adapter.browser.ts"]
|
|
7
|
+
"@browser-adapter": ["./adapter/http-adapter.browser.ts"],
|
|
8
|
+
"@server-adapter": ["./adapter/http-adapter.browser.ts"]
|
|
9
9
|
}
|
|
10
10
|
},
|
|
11
|
-
"include": ["./src/index.ts", "__tests__/*"],
|
|
12
11
|
"exclude": ["dist", "jest.config.ts"]
|
|
13
12
|
}
|
package/tsconfig.json
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
"rootDir": ".",
|
|
5
5
|
"baseUrl": "./src",
|
|
6
6
|
"paths": {
|
|
7
|
-
"@browser-adapter": ["./adapter/adapter.browser.ts"],
|
|
8
|
-
"@server-adapter": ["./adapter/adapter.server.ts"]
|
|
7
|
+
"@browser-adapter": ["./adapter/http-adapter.browser.ts"],
|
|
8
|
+
"@server-adapter": ["./adapter/http-adapter.server.ts"]
|
|
9
9
|
}
|
|
10
10
|
},
|
|
11
|
-
"exclude": ["dist", "jest.config.ts"]
|
|
11
|
+
"exclude": ["node_modules", "dist", "jest.config.ts", "__tests__"]
|
|
12
12
|
}
|