@nsxbet/react-relay-network-modern 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.
- package/LICENSE.md +10 -0
- package/README.md +324 -0
- package/dist/RRNLError.cjs +9 -0
- package/dist/RRNLError.d.cts +6 -0
- package/dist/RRNLError.d.ts +6 -0
- package/dist/RRNLError.js +9 -0
- package/dist/RelayNetworkLayer.cjs +54 -0
- package/dist/RelayNetworkLayer.d.cts +21 -0
- package/dist/RelayNetworkLayer.d.ts +21 -0
- package/dist/RelayNetworkLayer.js +54 -0
- package/dist/RelayRequest.cjs +90 -0
- package/dist/RelayRequest.d.cts +26 -0
- package/dist/RelayRequest.d.ts +26 -0
- package/dist/RelayRequest.js +90 -0
- package/dist/RelayRequestBatch.cjs +56 -0
- package/dist/RelayRequestBatch.d.cts +23 -0
- package/dist/RelayRequestBatch.d.ts +23 -0
- package/dist/RelayRequestBatch.js +56 -0
- package/dist/RelayResponse.cjs +56 -0
- package/dist/RelayResponse.d.cts +27 -0
- package/dist/RelayResponse.d.ts +27 -0
- package/dist/RelayResponse.js +56 -0
- package/dist/createRequestError.cjs +48 -0
- package/dist/createRequestError.d.cts +18 -0
- package/dist/createRequestError.d.ts +18 -0
- package/dist/createRequestError.js +46 -0
- package/dist/definition.d.cts +95 -0
- package/dist/definition.d.ts +95 -0
- package/dist/express-middleware/graphqlBatchHTTPWrapper.cjs +60 -0
- package/dist/express-middleware/graphqlBatchHTTPWrapper.d.cts +5 -0
- package/dist/express-middleware/graphqlBatchHTTPWrapper.d.ts +5 -0
- package/dist/express-middleware/graphqlBatchHTTPWrapper.js +60 -0
- package/dist/fetchWithMiddleware.cjs +43 -0
- package/dist/fetchWithMiddleware.js +43 -0
- package/dist/index.cjs +49 -0
- package/dist/index.d.cts +21 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +20 -0
- package/dist/middlewares/auth.cjs +47 -0
- package/dist/middlewares/auth.d.cts +18 -0
- package/dist/middlewares/auth.d.ts +18 -0
- package/dist/middlewares/auth.js +46 -0
- package/dist/middlewares/batch.cjs +136 -0
- package/dist/middlewares/batch.d.cts +34 -0
- package/dist/middlewares/batch.d.ts +34 -0
- package/dist/middlewares/batch.js +135 -0
- package/dist/middlewares/cache.cjs +43 -0
- package/dist/middlewares/cache.d.cts +17 -0
- package/dist/middlewares/cache.d.ts +17 -0
- package/dist/middlewares/cache.js +43 -0
- package/dist/middlewares/error.cjs +71 -0
- package/dist/middlewares/error.d.cts +11 -0
- package/dist/middlewares/error.d.ts +11 -0
- package/dist/middlewares/error.js +71 -0
- package/dist/middlewares/logger.cjs +43 -0
- package/dist/middlewares/logger.d.cts +9 -0
- package/dist/middlewares/logger.d.ts +9 -0
- package/dist/middlewares/logger.js +43 -0
- package/dist/middlewares/perf.cjs +13 -0
- package/dist/middlewares/perf.d.cts +9 -0
- package/dist/middlewares/perf.d.ts +9 -0
- package/dist/middlewares/perf.js +13 -0
- package/dist/middlewares/persistedQueries.cjs +33 -0
- package/dist/middlewares/persistedQueries.d.cts +9 -0
- package/dist/middlewares/persistedQueries.d.ts +9 -0
- package/dist/middlewares/persistedQueries.js +33 -0
- package/dist/middlewares/progress.cjs +35 -0
- package/dist/middlewares/progress.d.cts +10 -0
- package/dist/middlewares/progress.d.ts +10 -0
- package/dist/middlewares/progress.js +35 -0
- package/dist/middlewares/retry.cjs +146 -0
- package/dist/middlewares/retry.d.cts +34 -0
- package/dist/middlewares/retry.d.ts +34 -0
- package/dist/middlewares/retry.js +145 -0
- package/dist/middlewares/upload.cjs +32 -0
- package/dist/middlewares/upload.d.cts +6 -0
- package/dist/middlewares/upload.d.ts +6 -0
- package/dist/middlewares/upload.js +32 -0
- package/dist/middlewares/url.cjs +19 -0
- package/dist/middlewares/url.d.cts +19 -0
- package/dist/middlewares/url.d.ts +19 -0
- package/dist/middlewares/url.js +19 -0
- package/dist/utils.cjs +6 -0
- package/dist/utils.js +6 -0
- package/package.json +88 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Middleware } from "../definition.js";
|
|
2
|
+
|
|
3
|
+
//#region src/middlewares/logger.d.ts
|
|
4
|
+
interface LoggerMiddlewareOpts {
|
|
5
|
+
logger?: Function;
|
|
6
|
+
}
|
|
7
|
+
declare function loggerMiddleware(opts?: LoggerMiddlewareOpts): Middleware;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { LoggerMiddlewareOpts, loggerMiddleware };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import RelayRequest from "../RelayRequest.js";
|
|
2
|
+
import RelayRequestBatch from "../RelayRequestBatch.js";
|
|
3
|
+
//#region src/middlewares/logger.ts
|
|
4
|
+
function loggerMiddleware(opts) {
|
|
5
|
+
const logger = opts && opts.logger || console.log.bind(console, "[RELAY-NETWORK]");
|
|
6
|
+
return (next) => (req) => {
|
|
7
|
+
const start = (/* @__PURE__ */ new Date()).getTime();
|
|
8
|
+
logger(`Run ${req.getID()}`, req);
|
|
9
|
+
return next(req).then((res) => {
|
|
10
|
+
const end = (/* @__PURE__ */ new Date()).getTime();
|
|
11
|
+
let queryId;
|
|
12
|
+
let queryData;
|
|
13
|
+
if (req instanceof RelayRequest) {
|
|
14
|
+
queryId = req.getID();
|
|
15
|
+
queryData = {
|
|
16
|
+
query: req.getQueryString(),
|
|
17
|
+
variables: req.getVariables()
|
|
18
|
+
};
|
|
19
|
+
} else if (req instanceof RelayRequestBatch) {
|
|
20
|
+
queryId = req.getID();
|
|
21
|
+
queryData = {
|
|
22
|
+
requestList: req.requests,
|
|
23
|
+
responseList: res.json
|
|
24
|
+
};
|
|
25
|
+
} else {
|
|
26
|
+
queryId = "CustomRequest";
|
|
27
|
+
queryData = {};
|
|
28
|
+
}
|
|
29
|
+
logger(`Done ${queryId} in ${end - start}ms`, {
|
|
30
|
+
...queryData,
|
|
31
|
+
req,
|
|
32
|
+
res
|
|
33
|
+
});
|
|
34
|
+
if (res.status !== 200) logger(`Status ${res.status}: ${res.statusText || ""} for ${queryId}`);
|
|
35
|
+
return res;
|
|
36
|
+
}, (error) => {
|
|
37
|
+
if (error && error.name && error.name === "AbortError") logger(`Cancelled ${req.getID()}`);
|
|
38
|
+
throw error;
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
export { loggerMiddleware as default };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region src/middlewares/perf.ts
|
|
2
|
+
function performanceMiddleware(opts) {
|
|
3
|
+
const logger = opts && opts.logger || console.log.bind(console, "[RELAY-NETWORK]");
|
|
4
|
+
return (next) => (req) => {
|
|
5
|
+
const start = (/* @__PURE__ */ new Date()).getTime();
|
|
6
|
+
return next(req).then((res) => {
|
|
7
|
+
logger(`[${(/* @__PURE__ */ new Date()).getTime() - start}ms] ${req.getID()}`, req, res);
|
|
8
|
+
return res;
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
//#endregion
|
|
13
|
+
exports.default = performanceMiddleware;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Middleware } from "../definition.cjs";
|
|
2
|
+
|
|
3
|
+
//#region src/middlewares/perf.d.ts
|
|
4
|
+
interface PerfMiddlewareOpts {
|
|
5
|
+
logger?: Function;
|
|
6
|
+
}
|
|
7
|
+
declare function performanceMiddleware(opts?: PerfMiddlewareOpts): Middleware;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { PerfMiddlewareOpts, performanceMiddleware };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Middleware } from "../definition.js";
|
|
2
|
+
|
|
3
|
+
//#region src/middlewares/perf.d.ts
|
|
4
|
+
interface PerfMiddlewareOpts {
|
|
5
|
+
logger?: Function;
|
|
6
|
+
}
|
|
7
|
+
declare function performanceMiddleware(opts?: PerfMiddlewareOpts): Middleware;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { PerfMiddlewareOpts, performanceMiddleware };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region src/middlewares/perf.ts
|
|
2
|
+
function performanceMiddleware(opts) {
|
|
3
|
+
const logger = opts && opts.logger || console.log.bind(console, "[RELAY-NETWORK]");
|
|
4
|
+
return (next) => (req) => {
|
|
5
|
+
const start = (/* @__PURE__ */ new Date()).getTime();
|
|
6
|
+
return next(req).then((res) => {
|
|
7
|
+
logger(`[${(/* @__PURE__ */ new Date()).getTime() - start}ms] ${req.getID()}`, req, res);
|
|
8
|
+
return res;
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
//#endregion
|
|
13
|
+
export { performanceMiddleware as default };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//#region src/middlewares/persistedQueries.ts
|
|
2
|
+
async function makePersistedQueryRequestWithFallback(o, original = false, hasRunFallback = false) {
|
|
3
|
+
const makeFallback = async (prevError) => {
|
|
4
|
+
if (hasRunFallback) throw prevError;
|
|
5
|
+
return makePersistedQueryRequestWithFallback(o, true, true);
|
|
6
|
+
};
|
|
7
|
+
const makeRequest = async () => {
|
|
8
|
+
try {
|
|
9
|
+
const persistedQueriesReq = JSON.parse(JSON.stringify(o.req));
|
|
10
|
+
const { cacheID, id, text: queryText } = persistedQueriesReq.operation;
|
|
11
|
+
const queryId = id || cacheID;
|
|
12
|
+
if (!queryId && (!o.options?.hash || !queryText)) throw new Error("Either query id or hashing function & query must be defined!");
|
|
13
|
+
const body = JSON.parse(persistedQueriesReq.fetchOpts.body);
|
|
14
|
+
delete body.query;
|
|
15
|
+
body.doc_id = queryId;
|
|
16
|
+
persistedQueriesReq.fetchOpts.body = JSON.stringify(body);
|
|
17
|
+
delete persistedQueriesReq.operation.text;
|
|
18
|
+
return await o.next(original ? o.req : persistedQueriesReq);
|
|
19
|
+
} catch (e) {
|
|
20
|
+
return makeFallback(e);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
return makeRequest();
|
|
24
|
+
}
|
|
25
|
+
function persistedQueriesMiddleware(options) {
|
|
26
|
+
return (next) => (req) => makePersistedQueryRequestWithFallback({
|
|
27
|
+
req,
|
|
28
|
+
next,
|
|
29
|
+
options
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
//#endregion
|
|
33
|
+
exports.default = persistedQueriesMiddleware;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Middleware } from "../definition.cjs";
|
|
2
|
+
|
|
3
|
+
//#region src/middlewares/persistedQueries.d.ts
|
|
4
|
+
interface PersistedQueriesMiddlewareOpts {
|
|
5
|
+
hash: string;
|
|
6
|
+
}
|
|
7
|
+
declare function persistedQueriesMiddleware(options?: PersistedQueriesMiddlewareOpts): Middleware;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { PersistedQueriesMiddlewareOpts, persistedQueriesMiddleware };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Middleware } from "../definition.js";
|
|
2
|
+
|
|
3
|
+
//#region src/middlewares/persistedQueries.d.ts
|
|
4
|
+
interface PersistedQueriesMiddlewareOpts {
|
|
5
|
+
hash: string;
|
|
6
|
+
}
|
|
7
|
+
declare function persistedQueriesMiddleware(options?: PersistedQueriesMiddlewareOpts): Middleware;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { PersistedQueriesMiddlewareOpts, persistedQueriesMiddleware };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//#region src/middlewares/persistedQueries.ts
|
|
2
|
+
async function makePersistedQueryRequestWithFallback(o, original = false, hasRunFallback = false) {
|
|
3
|
+
const makeFallback = async (prevError) => {
|
|
4
|
+
if (hasRunFallback) throw prevError;
|
|
5
|
+
return makePersistedQueryRequestWithFallback(o, true, true);
|
|
6
|
+
};
|
|
7
|
+
const makeRequest = async () => {
|
|
8
|
+
try {
|
|
9
|
+
const persistedQueriesReq = JSON.parse(JSON.stringify(o.req));
|
|
10
|
+
const { cacheID, id, text: queryText } = persistedQueriesReq.operation;
|
|
11
|
+
const queryId = id || cacheID;
|
|
12
|
+
if (!queryId && (!o.options?.hash || !queryText)) throw new Error("Either query id or hashing function & query must be defined!");
|
|
13
|
+
const body = JSON.parse(persistedQueriesReq.fetchOpts.body);
|
|
14
|
+
delete body.query;
|
|
15
|
+
body.doc_id = queryId;
|
|
16
|
+
persistedQueriesReq.fetchOpts.body = JSON.stringify(body);
|
|
17
|
+
delete persistedQueriesReq.operation.text;
|
|
18
|
+
return await o.next(original ? o.req : persistedQueriesReq);
|
|
19
|
+
} catch (e) {
|
|
20
|
+
return makeFallback(e);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
return makeRequest();
|
|
24
|
+
}
|
|
25
|
+
function persistedQueriesMiddleware(options) {
|
|
26
|
+
return (next) => (req) => makePersistedQueryRequestWithFallback({
|
|
27
|
+
req,
|
|
28
|
+
next,
|
|
29
|
+
options
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
//#endregion
|
|
33
|
+
export { persistedQueriesMiddleware as default };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
//#region src/middlewares/progress.ts
|
|
2
|
+
function createProgressHandler(opts) {
|
|
3
|
+
const { onProgress, sizeHeader = "Content-Length" } = opts || {};
|
|
4
|
+
return async (res) => {
|
|
5
|
+
const { body, headers } = res;
|
|
6
|
+
if (!body) return;
|
|
7
|
+
const totalResponseSize = headers.get(sizeHeader);
|
|
8
|
+
let totalSize = null;
|
|
9
|
+
if (totalResponseSize !== null) totalSize = parseInt(totalResponseSize, 10);
|
|
10
|
+
const reader = body.getReader();
|
|
11
|
+
let completed = false;
|
|
12
|
+
let runningTotal = 0;
|
|
13
|
+
do {
|
|
14
|
+
const { done, value } = await reader.read();
|
|
15
|
+
const length = value && value.length || 0;
|
|
16
|
+
completed = done;
|
|
17
|
+
if (!completed) {
|
|
18
|
+
runningTotal += length;
|
|
19
|
+
onProgress(runningTotal, totalSize);
|
|
20
|
+
}
|
|
21
|
+
} while (!completed);
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function progressMiddleware(opts) {
|
|
25
|
+
const progressHandler = createProgressHandler(opts);
|
|
26
|
+
const mw = (next) => async (req) => {
|
|
27
|
+
const res = await next(req);
|
|
28
|
+
progressHandler(res.clone());
|
|
29
|
+
return res;
|
|
30
|
+
};
|
|
31
|
+
mw.isRawMiddleware = true;
|
|
32
|
+
return mw;
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
exports.default = progressMiddleware;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { MiddlewareRaw } from "../definition.cjs";
|
|
2
|
+
|
|
3
|
+
//#region src/middlewares/progress.d.ts
|
|
4
|
+
interface ProgressOpts {
|
|
5
|
+
sizeHeader?: string;
|
|
6
|
+
onProgress: (runningTotal: number, totalSize: number | null) => any;
|
|
7
|
+
}
|
|
8
|
+
declare function progressMiddleware(opts: ProgressOpts): MiddlewareRaw;
|
|
9
|
+
//#endregion
|
|
10
|
+
export { ProgressOpts, progressMiddleware };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { MiddlewareRaw } from "../definition.js";
|
|
2
|
+
|
|
3
|
+
//#region src/middlewares/progress.d.ts
|
|
4
|
+
interface ProgressOpts {
|
|
5
|
+
sizeHeader?: string;
|
|
6
|
+
onProgress: (runningTotal: number, totalSize: number | null) => any;
|
|
7
|
+
}
|
|
8
|
+
declare function progressMiddleware(opts: ProgressOpts): MiddlewareRaw;
|
|
9
|
+
//#endregion
|
|
10
|
+
export { ProgressOpts, progressMiddleware };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
//#region src/middlewares/progress.ts
|
|
2
|
+
function createProgressHandler(opts) {
|
|
3
|
+
const { onProgress, sizeHeader = "Content-Length" } = opts || {};
|
|
4
|
+
return async (res) => {
|
|
5
|
+
const { body, headers } = res;
|
|
6
|
+
if (!body) return;
|
|
7
|
+
const totalResponseSize = headers.get(sizeHeader);
|
|
8
|
+
let totalSize = null;
|
|
9
|
+
if (totalResponseSize !== null) totalSize = parseInt(totalResponseSize, 10);
|
|
10
|
+
const reader = body.getReader();
|
|
11
|
+
let completed = false;
|
|
12
|
+
let runningTotal = 0;
|
|
13
|
+
do {
|
|
14
|
+
const { done, value } = await reader.read();
|
|
15
|
+
const length = value && value.length || 0;
|
|
16
|
+
completed = done;
|
|
17
|
+
if (!completed) {
|
|
18
|
+
runningTotal += length;
|
|
19
|
+
onProgress(runningTotal, totalSize);
|
|
20
|
+
}
|
|
21
|
+
} while (!completed);
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function progressMiddleware(opts) {
|
|
25
|
+
const progressHandler = createProgressHandler(opts);
|
|
26
|
+
const mw = (next) => async (req) => {
|
|
27
|
+
const res = await next(req);
|
|
28
|
+
progressHandler(res.clone());
|
|
29
|
+
return res;
|
|
30
|
+
};
|
|
31
|
+
mw.isRawMiddleware = true;
|
|
32
|
+
return mw;
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
export { progressMiddleware as default };
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
const require_RRNLError = require("../RRNLError.cjs");
|
|
2
|
+
const require_utils = require("../utils.cjs");
|
|
3
|
+
//#region src/middlewares/retry.ts
|
|
4
|
+
function noopFn() {}
|
|
5
|
+
var RRNLRetryMiddlewareError = class extends require_RRNLError.default {
|
|
6
|
+
constructor(msg) {
|
|
7
|
+
super(msg);
|
|
8
|
+
this.name = "RRNLRetryMiddlewareError";
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
function retryMiddleware(options) {
|
|
12
|
+
const opts = options || {};
|
|
13
|
+
const timeout = opts.fetchTimeout || 15e3;
|
|
14
|
+
const retryDelays = opts.retryDelays || [1e3, 3e3];
|
|
15
|
+
const statusCodes = opts.statusCodes || false;
|
|
16
|
+
const logger = opts.logger === false ? () => {} : opts.logger || console.log.bind(console, "[RELAY-NETWORK]");
|
|
17
|
+
const allowMutations = opts.allowMutations || false;
|
|
18
|
+
const allowFormData = opts.allowFormData || false;
|
|
19
|
+
const forceRetryFn = opts.forceRetry || false;
|
|
20
|
+
const beforeRetry = opts.beforeRetry || false;
|
|
21
|
+
let retryAfterMs = () => false;
|
|
22
|
+
if (retryDelays) {
|
|
23
|
+
if (Array.isArray(retryDelays)) retryAfterMs = (attempt) => {
|
|
24
|
+
if (retryDelays.length >= attempt) return retryDelays[attempt];
|
|
25
|
+
return false;
|
|
26
|
+
};
|
|
27
|
+
else if (require_utils.isFunction(retryDelays)) retryAfterMs = retryDelays;
|
|
28
|
+
}
|
|
29
|
+
let timeoutAfterMs;
|
|
30
|
+
if (typeof timeout === "number") timeoutAfterMs = () => timeout;
|
|
31
|
+
else timeoutAfterMs = timeout;
|
|
32
|
+
let retryOnStatusCode = (status, req, res) => {
|
|
33
|
+
return res.status < 200 || res.status > 300;
|
|
34
|
+
};
|
|
35
|
+
if (statusCodes) {
|
|
36
|
+
if (Array.isArray(statusCodes)) retryOnStatusCode = (status, req, res) => statusCodes.indexOf(res.status) !== -1;
|
|
37
|
+
else if (require_utils.isFunction(statusCodes)) retryOnStatusCode = statusCodes;
|
|
38
|
+
}
|
|
39
|
+
return (next) => (req) => {
|
|
40
|
+
if (req.isMutation() && !allowMutations) return next(req);
|
|
41
|
+
if (req.isFormData() && !allowFormData) return next(req);
|
|
42
|
+
return makeRetriableRequest({
|
|
43
|
+
req,
|
|
44
|
+
next,
|
|
45
|
+
timeoutAfterMs,
|
|
46
|
+
retryAfterMs,
|
|
47
|
+
retryOnStatusCode,
|
|
48
|
+
forceRetryFn,
|
|
49
|
+
beforeRetry,
|
|
50
|
+
logger
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
async function makeRetriableRequest(o, delay = 0, attempt = 0, lastError = null) {
|
|
55
|
+
const makeRetry = async (prevError) => {
|
|
56
|
+
const retryDelay = o.retryAfterMs(attempt);
|
|
57
|
+
if (retryDelay) {
|
|
58
|
+
o.logger(prevError.message);
|
|
59
|
+
o.logger(`will retry in ${retryDelay} milliseconds`);
|
|
60
|
+
return makeRetriableRequest(o, retryDelay, attempt + 1, prevError);
|
|
61
|
+
}
|
|
62
|
+
throw prevError;
|
|
63
|
+
};
|
|
64
|
+
const makeRequest = async () => {
|
|
65
|
+
try {
|
|
66
|
+
const timeout = o.timeoutAfterMs(attempt);
|
|
67
|
+
return await promiseWithTimeout(o.next(o.req), timeout, () => {
|
|
68
|
+
return makeRetry(new RRNLRetryMiddlewareError(`Reached request timeout in ${timeout} ms`));
|
|
69
|
+
});
|
|
70
|
+
} catch (e) {
|
|
71
|
+
if (e && !e.res && !(e instanceof RRNLRetryMiddlewareError) && e.name !== "AbortError") return makeRetry(e);
|
|
72
|
+
if (e && e.res && o.retryOnStatusCode(e.res.status, o.req, e.res)) return makeRetry(new RRNLRetryMiddlewareError(`Wrong response status ${e.res.status}, retrying...`));
|
|
73
|
+
throw e;
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
if (attempt === 0) return makeRequest();
|
|
77
|
+
else {
|
|
78
|
+
const { promise, forceExec, abort } = delayedExecution(makeRequest, delay);
|
|
79
|
+
if (o.forceRetryFn) o.forceRetryFn(forceExec, delay);
|
|
80
|
+
if (o.beforeRetry) o.beforeRetry({
|
|
81
|
+
abort,
|
|
82
|
+
forceRetry: forceExec,
|
|
83
|
+
attempt,
|
|
84
|
+
delay,
|
|
85
|
+
lastError,
|
|
86
|
+
req: o.req
|
|
87
|
+
});
|
|
88
|
+
return promise;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* This function delays execution of some function for some period of time.
|
|
93
|
+
* Returns a promise, with ability to run execution immidiately, or abort it.
|
|
94
|
+
*/
|
|
95
|
+
function delayedExecution(execFn, delay = 0) {
|
|
96
|
+
let abort = noopFn;
|
|
97
|
+
let forceExec = noopFn;
|
|
98
|
+
if (delay <= 0) return {
|
|
99
|
+
abort,
|
|
100
|
+
forceExec,
|
|
101
|
+
promise: execFn()
|
|
102
|
+
};
|
|
103
|
+
const promise = new Promise((resolve, reject) => {
|
|
104
|
+
let delayId;
|
|
105
|
+
abort = (msg) => {
|
|
106
|
+
if (delayId) {
|
|
107
|
+
clearTimeout(delayId);
|
|
108
|
+
delayId = null;
|
|
109
|
+
}
|
|
110
|
+
reject(new RRNLRetryMiddlewareError(msg || "Aborted in beforeRetry() callback"));
|
|
111
|
+
};
|
|
112
|
+
forceExec = () => {
|
|
113
|
+
if (delayId) {
|
|
114
|
+
clearTimeout(delayId);
|
|
115
|
+
delayId = null;
|
|
116
|
+
resolve(execFn());
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
delayId = setTimeout(() => {
|
|
120
|
+
resolve(execFn());
|
|
121
|
+
}, delay);
|
|
122
|
+
});
|
|
123
|
+
return {
|
|
124
|
+
forceExec,
|
|
125
|
+
abort,
|
|
126
|
+
promise
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function promiseWithTimeout(promise, timeoutMS, onTimeout) {
|
|
130
|
+
if (!timeoutMS) return promise;
|
|
131
|
+
return new Promise((resolve, reject) => {
|
|
132
|
+
const timeoutId = setTimeout(() => {
|
|
133
|
+
onTimeout().then(resolve).catch(reject);
|
|
134
|
+
}, timeoutMS);
|
|
135
|
+
promise.then((res) => {
|
|
136
|
+
clearTimeout(timeoutId);
|
|
137
|
+
resolve(res);
|
|
138
|
+
}).catch((err) => {
|
|
139
|
+
clearTimeout(timeoutId);
|
|
140
|
+
reject(err);
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
//#endregion
|
|
145
|
+
exports.RRNLRetryMiddlewareError = RRNLRetryMiddlewareError;
|
|
146
|
+
exports.default = retryMiddleware;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { RelayResponse } from "../RelayResponse.cjs";
|
|
2
|
+
import { Middleware, RelayRequestAny } from "../definition.cjs";
|
|
3
|
+
import { RRNLError } from "../RRNLError.cjs";
|
|
4
|
+
|
|
5
|
+
//#region src/middlewares/retry.d.ts
|
|
6
|
+
type RetryAfterFn = (attempt: number) => number | false;
|
|
7
|
+
type TimeoutAfterFn = (attempt: number) => number;
|
|
8
|
+
type ForceRetryFn = (runNow: Function, delay: number) => any;
|
|
9
|
+
type AbortFn = (msg?: string | null) => any;
|
|
10
|
+
type BeforeRetryCb = (meta: {
|
|
11
|
+
forceRetry: Function;
|
|
12
|
+
abort: AbortFn;
|
|
13
|
+
delay: number;
|
|
14
|
+
attempt: number;
|
|
15
|
+
lastError: Error | null;
|
|
16
|
+
req: RelayRequestAny;
|
|
17
|
+
}) => any;
|
|
18
|
+
type StatusCheckFn = (statusCode: number, req: RelayRequestAny, res: RelayResponse) => boolean;
|
|
19
|
+
interface RetryMiddlewareOpts {
|
|
20
|
+
fetchTimeout?: number | TimeoutAfterFn;
|
|
21
|
+
retryDelays?: number[] | RetryAfterFn;
|
|
22
|
+
statusCodes?: number[] | false | StatusCheckFn;
|
|
23
|
+
logger?: Function | false;
|
|
24
|
+
allowMutations?: boolean;
|
|
25
|
+
allowFormData?: boolean;
|
|
26
|
+
forceRetry?: ForceRetryFn | false;
|
|
27
|
+
beforeRetry?: BeforeRetryCb | false;
|
|
28
|
+
}
|
|
29
|
+
declare class RRNLRetryMiddlewareError extends RRNLError {
|
|
30
|
+
constructor(msg: string);
|
|
31
|
+
}
|
|
32
|
+
declare function retryMiddleware(options?: RetryMiddlewareOpts): Middleware;
|
|
33
|
+
//#endregion
|
|
34
|
+
export { AbortFn, BeforeRetryCb, ForceRetryFn, RRNLRetryMiddlewareError, RetryAfterFn, RetryMiddlewareOpts, StatusCheckFn, retryMiddleware };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { RelayResponse } from "../RelayResponse.js";
|
|
2
|
+
import { Middleware, RelayRequestAny } from "../definition.js";
|
|
3
|
+
import { RRNLError } from "../RRNLError.js";
|
|
4
|
+
|
|
5
|
+
//#region src/middlewares/retry.d.ts
|
|
6
|
+
type RetryAfterFn = (attempt: number) => number | false;
|
|
7
|
+
type TimeoutAfterFn = (attempt: number) => number;
|
|
8
|
+
type ForceRetryFn = (runNow: Function, delay: number) => any;
|
|
9
|
+
type AbortFn = (msg?: string | null) => any;
|
|
10
|
+
type BeforeRetryCb = (meta: {
|
|
11
|
+
forceRetry: Function;
|
|
12
|
+
abort: AbortFn;
|
|
13
|
+
delay: number;
|
|
14
|
+
attempt: number;
|
|
15
|
+
lastError: Error | null;
|
|
16
|
+
req: RelayRequestAny;
|
|
17
|
+
}) => any;
|
|
18
|
+
type StatusCheckFn = (statusCode: number, req: RelayRequestAny, res: RelayResponse) => boolean;
|
|
19
|
+
interface RetryMiddlewareOpts {
|
|
20
|
+
fetchTimeout?: number | TimeoutAfterFn;
|
|
21
|
+
retryDelays?: number[] | RetryAfterFn;
|
|
22
|
+
statusCodes?: number[] | false | StatusCheckFn;
|
|
23
|
+
logger?: Function | false;
|
|
24
|
+
allowMutations?: boolean;
|
|
25
|
+
allowFormData?: boolean;
|
|
26
|
+
forceRetry?: ForceRetryFn | false;
|
|
27
|
+
beforeRetry?: BeforeRetryCb | false;
|
|
28
|
+
}
|
|
29
|
+
declare class RRNLRetryMiddlewareError extends RRNLError {
|
|
30
|
+
constructor(msg: string);
|
|
31
|
+
}
|
|
32
|
+
declare function retryMiddleware(options?: RetryMiddlewareOpts): Middleware;
|
|
33
|
+
//#endregion
|
|
34
|
+
export { AbortFn, BeforeRetryCb, ForceRetryFn, RRNLRetryMiddlewareError, RetryAfterFn, RetryMiddlewareOpts, StatusCheckFn, retryMiddleware };
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import RRNLError from "../RRNLError.js";
|
|
2
|
+
import { isFunction } from "../utils.js";
|
|
3
|
+
//#region src/middlewares/retry.ts
|
|
4
|
+
function noopFn() {}
|
|
5
|
+
var RRNLRetryMiddlewareError = class extends RRNLError {
|
|
6
|
+
constructor(msg) {
|
|
7
|
+
super(msg);
|
|
8
|
+
this.name = "RRNLRetryMiddlewareError";
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
function retryMiddleware(options) {
|
|
12
|
+
const opts = options || {};
|
|
13
|
+
const timeout = opts.fetchTimeout || 15e3;
|
|
14
|
+
const retryDelays = opts.retryDelays || [1e3, 3e3];
|
|
15
|
+
const statusCodes = opts.statusCodes || false;
|
|
16
|
+
const logger = opts.logger === false ? () => {} : opts.logger || console.log.bind(console, "[RELAY-NETWORK]");
|
|
17
|
+
const allowMutations = opts.allowMutations || false;
|
|
18
|
+
const allowFormData = opts.allowFormData || false;
|
|
19
|
+
const forceRetryFn = opts.forceRetry || false;
|
|
20
|
+
const beforeRetry = opts.beforeRetry || false;
|
|
21
|
+
let retryAfterMs = () => false;
|
|
22
|
+
if (retryDelays) {
|
|
23
|
+
if (Array.isArray(retryDelays)) retryAfterMs = (attempt) => {
|
|
24
|
+
if (retryDelays.length >= attempt) return retryDelays[attempt];
|
|
25
|
+
return false;
|
|
26
|
+
};
|
|
27
|
+
else if (isFunction(retryDelays)) retryAfterMs = retryDelays;
|
|
28
|
+
}
|
|
29
|
+
let timeoutAfterMs;
|
|
30
|
+
if (typeof timeout === "number") timeoutAfterMs = () => timeout;
|
|
31
|
+
else timeoutAfterMs = timeout;
|
|
32
|
+
let retryOnStatusCode = (status, req, res) => {
|
|
33
|
+
return res.status < 200 || res.status > 300;
|
|
34
|
+
};
|
|
35
|
+
if (statusCodes) {
|
|
36
|
+
if (Array.isArray(statusCodes)) retryOnStatusCode = (status, req, res) => statusCodes.indexOf(res.status) !== -1;
|
|
37
|
+
else if (isFunction(statusCodes)) retryOnStatusCode = statusCodes;
|
|
38
|
+
}
|
|
39
|
+
return (next) => (req) => {
|
|
40
|
+
if (req.isMutation() && !allowMutations) return next(req);
|
|
41
|
+
if (req.isFormData() && !allowFormData) return next(req);
|
|
42
|
+
return makeRetriableRequest({
|
|
43
|
+
req,
|
|
44
|
+
next,
|
|
45
|
+
timeoutAfterMs,
|
|
46
|
+
retryAfterMs,
|
|
47
|
+
retryOnStatusCode,
|
|
48
|
+
forceRetryFn,
|
|
49
|
+
beforeRetry,
|
|
50
|
+
logger
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
async function makeRetriableRequest(o, delay = 0, attempt = 0, lastError = null) {
|
|
55
|
+
const makeRetry = async (prevError) => {
|
|
56
|
+
const retryDelay = o.retryAfterMs(attempt);
|
|
57
|
+
if (retryDelay) {
|
|
58
|
+
o.logger(prevError.message);
|
|
59
|
+
o.logger(`will retry in ${retryDelay} milliseconds`);
|
|
60
|
+
return makeRetriableRequest(o, retryDelay, attempt + 1, prevError);
|
|
61
|
+
}
|
|
62
|
+
throw prevError;
|
|
63
|
+
};
|
|
64
|
+
const makeRequest = async () => {
|
|
65
|
+
try {
|
|
66
|
+
const timeout = o.timeoutAfterMs(attempt);
|
|
67
|
+
return await promiseWithTimeout(o.next(o.req), timeout, () => {
|
|
68
|
+
return makeRetry(new RRNLRetryMiddlewareError(`Reached request timeout in ${timeout} ms`));
|
|
69
|
+
});
|
|
70
|
+
} catch (e) {
|
|
71
|
+
if (e && !e.res && !(e instanceof RRNLRetryMiddlewareError) && e.name !== "AbortError") return makeRetry(e);
|
|
72
|
+
if (e && e.res && o.retryOnStatusCode(e.res.status, o.req, e.res)) return makeRetry(new RRNLRetryMiddlewareError(`Wrong response status ${e.res.status}, retrying...`));
|
|
73
|
+
throw e;
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
if (attempt === 0) return makeRequest();
|
|
77
|
+
else {
|
|
78
|
+
const { promise, forceExec, abort } = delayedExecution(makeRequest, delay);
|
|
79
|
+
if (o.forceRetryFn) o.forceRetryFn(forceExec, delay);
|
|
80
|
+
if (o.beforeRetry) o.beforeRetry({
|
|
81
|
+
abort,
|
|
82
|
+
forceRetry: forceExec,
|
|
83
|
+
attempt,
|
|
84
|
+
delay,
|
|
85
|
+
lastError,
|
|
86
|
+
req: o.req
|
|
87
|
+
});
|
|
88
|
+
return promise;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* This function delays execution of some function for some period of time.
|
|
93
|
+
* Returns a promise, with ability to run execution immidiately, or abort it.
|
|
94
|
+
*/
|
|
95
|
+
function delayedExecution(execFn, delay = 0) {
|
|
96
|
+
let abort = noopFn;
|
|
97
|
+
let forceExec = noopFn;
|
|
98
|
+
if (delay <= 0) return {
|
|
99
|
+
abort,
|
|
100
|
+
forceExec,
|
|
101
|
+
promise: execFn()
|
|
102
|
+
};
|
|
103
|
+
const promise = new Promise((resolve, reject) => {
|
|
104
|
+
let delayId;
|
|
105
|
+
abort = (msg) => {
|
|
106
|
+
if (delayId) {
|
|
107
|
+
clearTimeout(delayId);
|
|
108
|
+
delayId = null;
|
|
109
|
+
}
|
|
110
|
+
reject(new RRNLRetryMiddlewareError(msg || "Aborted in beforeRetry() callback"));
|
|
111
|
+
};
|
|
112
|
+
forceExec = () => {
|
|
113
|
+
if (delayId) {
|
|
114
|
+
clearTimeout(delayId);
|
|
115
|
+
delayId = null;
|
|
116
|
+
resolve(execFn());
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
delayId = setTimeout(() => {
|
|
120
|
+
resolve(execFn());
|
|
121
|
+
}, delay);
|
|
122
|
+
});
|
|
123
|
+
return {
|
|
124
|
+
forceExec,
|
|
125
|
+
abort,
|
|
126
|
+
promise
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function promiseWithTimeout(promise, timeoutMS, onTimeout) {
|
|
130
|
+
if (!timeoutMS) return promise;
|
|
131
|
+
return new Promise((resolve, reject) => {
|
|
132
|
+
const timeoutId = setTimeout(() => {
|
|
133
|
+
onTimeout().then(resolve).catch(reject);
|
|
134
|
+
}, timeoutMS);
|
|
135
|
+
promise.then((res) => {
|
|
136
|
+
clearTimeout(timeoutId);
|
|
137
|
+
resolve(res);
|
|
138
|
+
}).catch((err) => {
|
|
139
|
+
clearTimeout(timeoutId);
|
|
140
|
+
reject(err);
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
//#endregion
|
|
145
|
+
export { RRNLRetryMiddlewareError, retryMiddleware as default };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const require_RelayRequestBatch = require("../RelayRequestBatch.cjs");
|
|
2
|
+
let extract_files = require("extract-files");
|
|
3
|
+
//#region src/middlewares/upload.ts
|
|
4
|
+
function uploadMiddleware() {
|
|
5
|
+
return (next) => async (req) => {
|
|
6
|
+
if (req instanceof require_RelayRequestBatch.default) throw new Error("RelayRequestBatch is not supported");
|
|
7
|
+
const { clone: extractedOperations, files } = (0, extract_files.extractFiles)({
|
|
8
|
+
query: req.operation.text,
|
|
9
|
+
variables: req.variables
|
|
10
|
+
});
|
|
11
|
+
if (files.size) {
|
|
12
|
+
const formData = new FormData();
|
|
13
|
+
formData.append("operations", JSON.stringify(extractedOperations));
|
|
14
|
+
const pathMap = {};
|
|
15
|
+
let i = 0;
|
|
16
|
+
files.forEach((paths) => {
|
|
17
|
+
pathMap[++i] = paths;
|
|
18
|
+
});
|
|
19
|
+
formData.append("map", JSON.stringify(pathMap));
|
|
20
|
+
i = 0;
|
|
21
|
+
files.forEach((paths, file) => {
|
|
22
|
+
formData.append(`${++i}`, file, file.name);
|
|
23
|
+
});
|
|
24
|
+
req.fetchOpts.method = "POST";
|
|
25
|
+
req.fetchOpts.body = formData;
|
|
26
|
+
delete req.fetchOpts.headers["Content-Type"];
|
|
27
|
+
}
|
|
28
|
+
return await next(req);
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
exports.default = uploadMiddleware;
|