@openstax/ts-utils 1.19.0 → 1.20.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,8 @@
1
+ import { GenericFetch } from '.';
2
+ interface Options {
3
+ status?: number[];
4
+ onFail?: boolean;
5
+ retries: number;
6
+ }
7
+ export declare const fetchStatusRetry: (base: GenericFetch, options: Options) => GenericFetch;
8
+ export {};
@@ -0,0 +1,20 @@
1
+ export const fetchStatusRetry = (base, options) => {
2
+ const fetchTry = (retries, ...params) => {
3
+ return base(...params)
4
+ .catch(e => options.onFail && retries > 0
5
+ ? fetchTry(retries - 1, ...params)
6
+ : Promise.reject(e))
7
+ .then(async (r) => {
8
+ var _a;
9
+ const shouldHandleStatus = (_a = options.status) === null || _a === void 0 ? void 0 : _a.includes(r.status);
10
+ if (shouldHandleStatus && retries > 0) {
11
+ return fetchTry(retries - 1, ...params);
12
+ }
13
+ else if (shouldHandleStatus) {
14
+ throw new Error(`fetch failed after ${options.retries} retries. ${params[0]} -- ${r.status}: ${await r.text()}`);
15
+ }
16
+ return r;
17
+ });
18
+ };
19
+ return (...params) => fetchTry(options.retries, ...params);
20
+ };
@@ -3,6 +3,7 @@ import queryString from 'query-string';
3
3
  import { merge } from '../..';
4
4
  import { resolveConfigValue } from '../../config';
5
5
  import { SessionExpiredError, UnauthorizedError } from '../../errors';
6
+ import { fetchStatusRetry } from '../../fetch/fetchStatusRetry';
6
7
  /** Pulls the content out of a response based on the content type */
7
8
  export const loadResponse = (response) => () => {
8
9
  const [contentType] = (response.headers.get('content-type') || '').split(';');
@@ -27,7 +28,8 @@ const makeRouteClient = (initializer, config, route, authProvider) => {
27
28
  const url = await renderUrl({ params, query });
28
29
  const body = payload ? JSON.stringify(payload) : undefined;
29
30
  const baseOptions = merge((await (authProvider === null || authProvider === void 0 ? void 0 : authProvider.getAuthorizedFetchConfig())) || {}, fetchConfig || {});
30
- return initializer.fetch(url, merge(baseOptions, {
31
+ const fetcher = fetchStatusRetry(initializer.fetch, { retries: 1, status: [502], onFail: true });
32
+ return fetcher(url, merge(baseOptions, {
31
33
  method: route.method,
32
34
  body,
33
35
  headers: {
@@ -4,12 +4,14 @@ import { once, retryWithDelay } from '../..';
4
4
  import { assertDefined } from '../../assertions';
5
5
  import { resolveConfigValue } from '../../config';
6
6
  import { UnauthorizedError } from '../../errors';
7
+ import { fetchStatusRetry } from '../../fetch/fetchStatusRetry';
7
8
  import { ifDefined } from '../../guards';
8
9
  import { METHOD } from '../../routing';
9
10
  export const lrsGateway = (initializer) => (configProvider) => {
10
11
  const config = configProvider[ifDefined(initializer.configSpace, 'lrs')];
11
12
  const lrsHost = once(() => resolveConfigValue(config.lrsHost));
12
13
  const lrsAuthorization = once(() => resolveConfigValue(config.lrsAuthorization));
14
+ const fetcher = fetchStatusRetry(initializer.fetch, { retries: 1, status: [502], onFail: true });
13
15
  return (authProvider) => {
14
16
  // Note: This method actually uses POST
15
17
  const putXapiStatements = async (statements) => {
@@ -25,7 +27,7 @@ export const lrsGateway = (initializer) => (configProvider) => {
25
27
  },
26
28
  timestamp: formatISO(new Date())
27
29
  }));
28
- const response = await initializer.fetch((await lrsHost()).replace(/\/+$/, '') + '/data/xAPI/statements', {
30
+ const response = await fetcher((await lrsHost()).replace(/\/+$/, '') + '/data/xAPI/statements', {
29
31
  body: JSON.stringify(statementsWithDefaults),
30
32
  headers: {
31
33
  Authorization: await lrsAuthorization(),
@@ -53,13 +55,13 @@ ${await response.text()}`);
53
55
  }
54
56
  return response.json();
55
57
  };
56
- const getMoreXapiStatements = async (more) => formatGetXapiStatementsResponse(initializer.fetch((await lrsHost()).replace(/\/+$/, '') + more, {
58
+ const getMoreXapiStatements = async (more) => formatGetXapiStatementsResponse(fetcher((await lrsHost()).replace(/\/+$/, '') + more, {
57
59
  headers: {
58
60
  Authorization: await lrsAuthorization(),
59
61
  'X-Experience-API-Version': '1.0.0',
60
62
  },
61
63
  }));
62
- const fetchXapiStatements = async ({ user, anyUser, ...options }) => initializer.fetch((await lrsHost()).replace(/\/+$/, '') + '/data/xAPI/statements?' + queryString.stringify({
64
+ const fetchXapiStatements = async ({ user, anyUser, ...options }) => fetcher((await lrsHost()).replace(/\/+$/, '') + '/data/xAPI/statements?' + queryString.stringify({
63
65
  ...options,
64
66
  ...(anyUser === true ? {} : {
65
67
  agent: JSON.stringify({