@trackunit/react-core-contexts 1.12.18 → 1.13.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/index.cjs.js CHANGED
@@ -3,13 +3,13 @@
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
4
  var client = require('@apollo/client');
5
5
  var context = require('@apollo/client/link/context');
6
- var error = require('@apollo/client/link/error');
7
6
  var removeTypename = require('@apollo/client/link/remove-typename');
8
7
  var utilities = require('@apollo/client/utilities');
9
8
  var reactCoreHooks = require('@trackunit/react-core-hooks');
10
9
  var graphql = require('graphql');
11
10
  var graphqlSse = require('graphql-sse');
12
11
  var react = require('react');
12
+ var error = require('@apollo/client/link/error');
13
13
  var irisAppRuntimeCore = require('@trackunit/iris-app-runtime-core');
14
14
  var reactCoreContextsApi = require('@trackunit/react-core-contexts-api');
15
15
  require('@js-temporal/polyfill');
@@ -17,6 +17,80 @@ var i18nLibraryTranslation = require('@trackunit/i18n-library-translation');
17
17
  var reactComponents = require('@trackunit/react-components');
18
18
  var irisAppRuntimeCoreApi = require('@trackunit/iris-app-runtime-core-api');
19
19
 
20
+ /**
21
+ * This error link is used to capture error information, i. e. traceId, graphQL errors, network errors, etc.
22
+ */
23
+ const createErrorLink = ({ errorHandler, token, }) => {
24
+ return error.onError(({ graphQLErrors, networkError, operation, forward }) => {
25
+ if (networkError) {
26
+ // We skip the error logging if the error is an AbortError
27
+ if (networkError.name === "AbortError") {
28
+ return;
29
+ }
30
+ // eslint-disable-next-line no-console
31
+ console.error(networkError);
32
+ }
33
+ // Forward the operation to the next link in the chain, capturing response extensions and handling GraphQL errors
34
+ return forward(operation).map(response => {
35
+ if (graphQLErrors) {
36
+ // Collect traceIds from graphQLErrors
37
+ const traceIds = [];
38
+ graphQLErrors.forEach(error => {
39
+ if ("extensions" in error && error.extensions && typeof error.extensions.traceId === "string") {
40
+ traceIds.push(error.extensions.traceId);
41
+ }
42
+ });
43
+ // Fallback to response.extensions.traceId if no traceIds found in errors
44
+ const traceId = response.extensions?.traceId;
45
+ if (traceIds.length === 0 && typeof traceId === "string") {
46
+ traceIds.push(traceId);
47
+ }
48
+ const code = graphQLErrors[0]?.extensions?.code;
49
+ if (code === "FORCE_RELOAD_BROWSER") {
50
+ window.location.reload();
51
+ }
52
+ // eslint-disable-next-line no-console
53
+ console.error(`Error calling: '${operation.getContext().clientAwareness.name}' fetching Data for: ${operation.operationName}`, graphQLErrors);
54
+ /**
55
+ * We want to see the full graphQL error since
56
+ * it contains extra details like the query/mutation
57
+ * name.
58
+ */
59
+ if (traceIds.length) {
60
+ errorHandler.setTag("traceIds", traceIds.join(", "));
61
+ }
62
+ errorHandler.addBreadcrumb({
63
+ category: "GraphQL",
64
+ message: "GraphQL Error",
65
+ level: "error",
66
+ data: {
67
+ log: JSON.stringify(graphQLErrors),
68
+ },
69
+ });
70
+ const invalidToken = graphQLErrors.some(x => {
71
+ return (x.extensions?.code === "UNAUTHENTICATED" ||
72
+ x.message.includes("Invalid token specified") ||
73
+ x.message.includes("Access denied! You need to be authorized to perform this action!"));
74
+ });
75
+ if (invalidToken && token) {
76
+ errorHandler.captureException(new Error(JSON.stringify({
77
+ category: "GraphQL",
78
+ info: "GraphQL Error - invalidToken",
79
+ level: "warning",
80
+ data: {
81
+ log: JSON.stringify(graphQLErrors),
82
+ },
83
+ })), {
84
+ level: "warning",
85
+ fingerprint: ["GraphQL Error - invalidToken"],
86
+ });
87
+ }
88
+ }
89
+ return response;
90
+ });
91
+ });
92
+ };
93
+
20
94
  const generateHeaders = (token, tracingHeaders) => {
21
95
  const headers = {
22
96
  ...Object.entries(tracingHeaders).reduce((acc, [key, value]) => {
@@ -64,68 +138,7 @@ const createApolloClient = ({ graphqlPublicUrl, graphqlInternalUrl, graphqlRepor
64
138
  },
65
139
  };
66
140
  });
67
- const errorLink = error.onError(({ graphQLErrors, networkError, operation, forward }) => {
68
- const traceIds = []; // Used to hold id's for use in Sentry
69
- if (graphQLErrors) {
70
- const code = graphQLErrors[0]?.extensions?.code;
71
- if (code === "FORCE_RELOAD_BROWSER") {
72
- window.location.reload();
73
- }
74
- // eslint-disable-next-line no-console
75
- console.error(`Error calling: '${operation.getContext().clientAwareness.name}' fetching Data for: ${operation.operationName}`, graphQLErrors);
76
- graphQLErrors.forEach(error => {
77
- if ("extensions" in error) {
78
- error.extensions.traceId = operation.getContext().response?.extensions?.traceId;
79
- const traceId = error.extensions.traceId;
80
- traceIds.push(traceId);
81
- }
82
- });
83
- /**
84
- * We want to see the full graphQL error since
85
- * it contains extra details like the query/mutation
86
- * name.
87
- */
88
- if (traceIds.length) {
89
- errorHandler.setTag("traceIds", traceIds.join(", "));
90
- }
91
- errorHandler.addBreadcrumb({
92
- category: "GraphQL",
93
- message: "GraphQL Error",
94
- level: "error",
95
- data: {
96
- log: JSON.stringify(graphQLErrors),
97
- },
98
- });
99
- const invalidToken = graphQLErrors.some(x => {
100
- return (x.extensions?.code === "UNAUTHENTICATED" ||
101
- x.message.includes("Invalid token specified") ||
102
- x.message.includes("Access denied! You need to be authorized to perform this action!"));
103
- });
104
- if (invalidToken && token) {
105
- errorHandler.captureException(new Error(JSON.stringify({
106
- category: "GraphQL",
107
- info: "GraphQL Error - invalidToken",
108
- level: "warning",
109
- data: {
110
- log: JSON.stringify(graphQLErrors),
111
- },
112
- })), {
113
- level: "warning",
114
- fingerprint: ["GraphQL Error - invalidToken"],
115
- });
116
- }
117
- }
118
- if (networkError) {
119
- // We skip the error logging if the error is an AbortError
120
- if (networkError.name === "AbortError") {
121
- return;
122
- }
123
- // eslint-disable-next-line no-console
124
- console.error(networkError);
125
- }
126
- // Forward the operation to the next link in the chain
127
- return forward(operation);
128
- });
141
+ const errorLink = createErrorLink({ errorHandler, token });
129
142
  const defaultOptions = {
130
143
  watchQuery: {
131
144
  fetchPolicy: "no-cache",
package/index.esm.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import { jsx, Fragment } from 'react/jsx-runtime';
2
2
  import { ApolloProvider, createHttpLink, from, split, ApolloClient, InMemoryCache, ApolloLink } from '@apollo/client';
3
3
  import { setContext } from '@apollo/client/link/context';
4
- import { onError } from '@apollo/client/link/error';
5
4
  import { removeTypenameFromVariables } from '@apollo/client/link/remove-typename';
6
5
  import { getMainDefinition, Observable } from '@apollo/client/utilities';
7
6
  import { useEnvironment, useToken, useErrorHandler } from '@trackunit/react-core-hooks';
8
7
  import { print } from 'graphql';
9
8
  import { createClient } from 'graphql-sse';
10
9
  import { useState, useMemo, useEffect, useCallback, Suspense } from 'react';
10
+ import { onError } from '@apollo/client/link/error';
11
11
  import { ToastRuntime, AnalyticsRuntime, setupHostConnector, AssetSortingRuntime, ConfirmationDialogRuntime, EnvironmentRuntime, ExportDataRuntime, AssetsFilterBarRuntime, CustomersFilterBarRuntime, SitesFilterBarRuntime, ModalDialogRuntime, NavigationRuntime, OemBrandingRuntime, ThemeCssRuntime, TimeRangeRuntime, TokenRuntime, CurrentUserRuntime, CurrentUserPreferenceRuntime, UserSubscriptionRuntime, WidgetConfigRuntime } from '@trackunit/iris-app-runtime-core';
12
12
  import { ToastProvider, AnalyticsContextProvider, AssetSortingProvider, ConfirmationDialogProvider, EnvironmentContextProvider, ErrorHandlingContextProvider, ExportDataContext, FilterBarProvider, ModalDialogContextProvider, NavigationContextProvider, OemBrandingContextProvider, TimeRangeProvider, TokenProvider, CurrentUserProvider, CurrentUserPreferenceProvider, UserSubscriptionProvider, WidgetConfigProvider } from '@trackunit/react-core-contexts-api';
13
13
  import '@js-temporal/polyfill';
@@ -15,6 +15,80 @@ import { registerTranslations, initializeTranslationsForApp } from '@trackunit/i
15
15
  import { Spinner } from '@trackunit/react-components';
16
16
  import { AssetSortByProperty, SortOrder } from '@trackunit/iris-app-runtime-core-api';
17
17
 
18
+ /**
19
+ * This error link is used to capture error information, i. e. traceId, graphQL errors, network errors, etc.
20
+ */
21
+ const createErrorLink = ({ errorHandler, token, }) => {
22
+ return onError(({ graphQLErrors, networkError, operation, forward }) => {
23
+ if (networkError) {
24
+ // We skip the error logging if the error is an AbortError
25
+ if (networkError.name === "AbortError") {
26
+ return;
27
+ }
28
+ // eslint-disable-next-line no-console
29
+ console.error(networkError);
30
+ }
31
+ // Forward the operation to the next link in the chain, capturing response extensions and handling GraphQL errors
32
+ return forward(operation).map(response => {
33
+ if (graphQLErrors) {
34
+ // Collect traceIds from graphQLErrors
35
+ const traceIds = [];
36
+ graphQLErrors.forEach(error => {
37
+ if ("extensions" in error && error.extensions && typeof error.extensions.traceId === "string") {
38
+ traceIds.push(error.extensions.traceId);
39
+ }
40
+ });
41
+ // Fallback to response.extensions.traceId if no traceIds found in errors
42
+ const traceId = response.extensions?.traceId;
43
+ if (traceIds.length === 0 && typeof traceId === "string") {
44
+ traceIds.push(traceId);
45
+ }
46
+ const code = graphQLErrors[0]?.extensions?.code;
47
+ if (code === "FORCE_RELOAD_BROWSER") {
48
+ window.location.reload();
49
+ }
50
+ // eslint-disable-next-line no-console
51
+ console.error(`Error calling: '${operation.getContext().clientAwareness.name}' fetching Data for: ${operation.operationName}`, graphQLErrors);
52
+ /**
53
+ * We want to see the full graphQL error since
54
+ * it contains extra details like the query/mutation
55
+ * name.
56
+ */
57
+ if (traceIds.length) {
58
+ errorHandler.setTag("traceIds", traceIds.join(", "));
59
+ }
60
+ errorHandler.addBreadcrumb({
61
+ category: "GraphQL",
62
+ message: "GraphQL Error",
63
+ level: "error",
64
+ data: {
65
+ log: JSON.stringify(graphQLErrors),
66
+ },
67
+ });
68
+ const invalidToken = graphQLErrors.some(x => {
69
+ return (x.extensions?.code === "UNAUTHENTICATED" ||
70
+ x.message.includes("Invalid token specified") ||
71
+ x.message.includes("Access denied! You need to be authorized to perform this action!"));
72
+ });
73
+ if (invalidToken && token) {
74
+ errorHandler.captureException(new Error(JSON.stringify({
75
+ category: "GraphQL",
76
+ info: "GraphQL Error - invalidToken",
77
+ level: "warning",
78
+ data: {
79
+ log: JSON.stringify(graphQLErrors),
80
+ },
81
+ })), {
82
+ level: "warning",
83
+ fingerprint: ["GraphQL Error - invalidToken"],
84
+ });
85
+ }
86
+ }
87
+ return response;
88
+ });
89
+ });
90
+ };
91
+
18
92
  const generateHeaders = (token, tracingHeaders) => {
19
93
  const headers = {
20
94
  ...Object.entries(tracingHeaders).reduce((acc, [key, value]) => {
@@ -62,68 +136,7 @@ const createApolloClient = ({ graphqlPublicUrl, graphqlInternalUrl, graphqlRepor
62
136
  },
63
137
  };
64
138
  });
65
- const errorLink = onError(({ graphQLErrors, networkError, operation, forward }) => {
66
- const traceIds = []; // Used to hold id's for use in Sentry
67
- if (graphQLErrors) {
68
- const code = graphQLErrors[0]?.extensions?.code;
69
- if (code === "FORCE_RELOAD_BROWSER") {
70
- window.location.reload();
71
- }
72
- // eslint-disable-next-line no-console
73
- console.error(`Error calling: '${operation.getContext().clientAwareness.name}' fetching Data for: ${operation.operationName}`, graphQLErrors);
74
- graphQLErrors.forEach(error => {
75
- if ("extensions" in error) {
76
- error.extensions.traceId = operation.getContext().response?.extensions?.traceId;
77
- const traceId = error.extensions.traceId;
78
- traceIds.push(traceId);
79
- }
80
- });
81
- /**
82
- * We want to see the full graphQL error since
83
- * it contains extra details like the query/mutation
84
- * name.
85
- */
86
- if (traceIds.length) {
87
- errorHandler.setTag("traceIds", traceIds.join(", "));
88
- }
89
- errorHandler.addBreadcrumb({
90
- category: "GraphQL",
91
- message: "GraphQL Error",
92
- level: "error",
93
- data: {
94
- log: JSON.stringify(graphQLErrors),
95
- },
96
- });
97
- const invalidToken = graphQLErrors.some(x => {
98
- return (x.extensions?.code === "UNAUTHENTICATED" ||
99
- x.message.includes("Invalid token specified") ||
100
- x.message.includes("Access denied! You need to be authorized to perform this action!"));
101
- });
102
- if (invalidToken && token) {
103
- errorHandler.captureException(new Error(JSON.stringify({
104
- category: "GraphQL",
105
- info: "GraphQL Error - invalidToken",
106
- level: "warning",
107
- data: {
108
- log: JSON.stringify(graphQLErrors),
109
- },
110
- })), {
111
- level: "warning",
112
- fingerprint: ["GraphQL Error - invalidToken"],
113
- });
114
- }
115
- }
116
- if (networkError) {
117
- // We skip the error logging if the error is an AbortError
118
- if (networkError.name === "AbortError") {
119
- return;
120
- }
121
- // eslint-disable-next-line no-console
122
- console.error(networkError);
123
- }
124
- // Forward the operation to the next link in the chain
125
- return forward(operation);
126
- });
139
+ const errorLink = createErrorLink({ errorHandler, token });
127
140
  const defaultOptions = {
128
141
  watchQuery: {
129
142
  fetchPolicy: "no-cache",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trackunit/react-core-contexts",
3
- "version": "1.12.18",
3
+ "version": "1.13.0",
4
4
  "repository": "https://github.com/Trackunit/manager",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "engines": {
@@ -0,0 +1,9 @@
1
+ import { ApolloLink } from "@apollo/client";
2
+ import { ErrorHandlingContextValue } from "@trackunit/iris-app-runtime-core-api";
3
+ /**
4
+ * This error link is used to capture error information, i. e. traceId, graphQL errors, network errors, etc.
5
+ */
6
+ export declare const createErrorLink: ({ errorHandler, token, }: {
7
+ errorHandler: ErrorHandlingContextValue;
8
+ token: string | undefined;
9
+ }) => ApolloLink;