@gen3/core 0.12.51 → 0.12.53
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/dist/cjs/index.js +166 -95
- package/dist/cjs/index.js.map +1 -1
- package/dist/dts/types/types.d.ts +5 -0
- package/dist/dts/types/types.d.ts.map +1 -1
- package/dist/dts/utils/httpUserFriendlyErrorMessages.d.ts +2 -0
- package/dist/dts/utils/httpUserFriendlyErrorMessages.d.ts.map +1 -0
- package/dist/dts/utils/index.d.ts +3 -2
- package/dist/dts/utils/index.d.ts.map +1 -1
- package/dist/dts/utils/normalizeRtkError.d.ts.map +1 -1
- package/dist/esm/index.js +165 -96
- package/dist/esm/index.js.map +1 -1
- package/dist/index.d.ts +19 -13
- package/package.json +2 -2
package/dist/cjs/index.js
CHANGED
|
@@ -997,96 +997,6 @@ const ExtractValueFromObject = (obj, key, valueIfNotFound)=>{
|
|
|
997
997
|
return obj?.[key] ?? valueIfNotFound;
|
|
998
998
|
};
|
|
999
999
|
|
|
1000
|
-
const DAYS_IN_YEAR = 365.25;
|
|
1001
|
-
/**
|
|
1002
|
-
* Converts HistogramData to HistogramDataAsStringKey by ensuring the key is a string.
|
|
1003
|
-
* If the key is already a string, it's used as is.
|
|
1004
|
-
* If the key is a number tuple [min, max], it's converted to a string in the format "min-max".
|
|
1005
|
-
*
|
|
1006
|
-
* @param data The HistogramData object to convert
|
|
1007
|
-
* @returns HistogramDataAsStringKey with the converted key
|
|
1008
|
-
*/ const convertToHistogramDataAsStringKey = (data)=>{
|
|
1009
|
-
return {
|
|
1010
|
-
key: typeof data.key === 'string' ? data.key : `${data.key[0]}-${data.key[1]}`,
|
|
1011
|
-
count: data.count
|
|
1012
|
-
};
|
|
1013
|
-
};
|
|
1014
|
-
const calculatePercentageAsNumber = (count, total)=>count ? count / total * 100 : 0;
|
|
1015
|
-
const calculatePercentageAsString = (count, total)=>`${(count / total * 100).toFixed(2)}%`;
|
|
1016
|
-
const capitalize$1 = (original)=>{
|
|
1017
|
-
const customCapitalizations = {
|
|
1018
|
-
id: 'ID',
|
|
1019
|
-
uuid: 'UUID',
|
|
1020
|
-
dna: 'DNA',
|
|
1021
|
-
dbsnp: 'dbSNP',
|
|
1022
|
-
cosmic: 'COSMIC',
|
|
1023
|
-
civic: 'CIViC',
|
|
1024
|
-
dbgap: 'dbGaP',
|
|
1025
|
-
ecog: 'ECOG',
|
|
1026
|
-
bmi: 'BMI',
|
|
1027
|
-
gdc: 'GDC',
|
|
1028
|
-
cnv: 'CNV',
|
|
1029
|
-
ssm: 'SSM',
|
|
1030
|
-
aa: 'AA'
|
|
1031
|
-
};
|
|
1032
|
-
return original.split(' ').map((word)=>customCapitalizations[word.toLowerCase()] || `${word.charAt(0).toUpperCase()}${word.slice(1)}`).join(' ');
|
|
1033
|
-
};
|
|
1034
|
-
const humanify = ({ term = '', capitalize: cap = true, facetTerm = false })=>{
|
|
1035
|
-
let original;
|
|
1036
|
-
let humanified;
|
|
1037
|
-
if (facetTerm) {
|
|
1038
|
-
// Splits on capital letters followed by lowercase letters to find
|
|
1039
|
-
// words squished together in a string.
|
|
1040
|
-
original = term?.split(/(?=[A-Z][a-z])/).join(' ');
|
|
1041
|
-
humanified = term?.replace(/\./g, ' ').replace(/_/g, ' ').trim();
|
|
1042
|
-
} else {
|
|
1043
|
-
const split = (original || term)?.split('.');
|
|
1044
|
-
humanified = split[split.length - 1]?.replace(/_/g, ' ').trim();
|
|
1045
|
-
// Special case 'name' to include any parent nested for sake of
|
|
1046
|
-
// specificity in the UI
|
|
1047
|
-
if (humanified === 'name' && split?.length > 1) {
|
|
1048
|
-
humanified = `${split[split?.length - 2]} ${humanified}`;
|
|
1049
|
-
}
|
|
1050
|
-
}
|
|
1051
|
-
return cap ? capitalize$1(humanified) : humanified;
|
|
1052
|
-
};
|
|
1053
|
-
/*https://github.com/NCI-GDC/portal-ui/blob/develop/src/packages/%40ncigdc/utils/ageDisplay.js*/ /**
|
|
1054
|
-
* Converts age in days into a human-readable format.
|
|
1055
|
-
*
|
|
1056
|
-
* @param ageInDays - The age in days.
|
|
1057
|
-
* @param yearsOnly - If true, only display years.
|
|
1058
|
-
* @defaultValue false
|
|
1059
|
-
* @param defaultValue - The default value to return if ageInDays is falsy.
|
|
1060
|
-
* @defaultValue "--"
|
|
1061
|
-
* @returns The formatted age string.
|
|
1062
|
-
*/ const ageDisplay = (ageInDays, yearsOnly = false, defaultValue = '--')=>{
|
|
1063
|
-
if (ageInDays !== 0 && !ageInDays) {
|
|
1064
|
-
return defaultValue;
|
|
1065
|
-
}
|
|
1066
|
-
const calculateYearsAndDays = (years, days)=>days === 365 ? [
|
|
1067
|
-
years + 1,
|
|
1068
|
-
0
|
|
1069
|
-
] : [
|
|
1070
|
-
years,
|
|
1071
|
-
days
|
|
1072
|
-
];
|
|
1073
|
-
const ABS_AGE_DAYS = Math.abs(ageInDays);
|
|
1074
|
-
const [years, remainingDays] = calculateYearsAndDays(Math.floor(ABS_AGE_DAYS / DAYS_IN_YEAR), Math.ceil(ABS_AGE_DAYS % DAYS_IN_YEAR));
|
|
1075
|
-
const formattedYears = years === 0 ? '' : `${years} ${years === 1 ? 'year' : 'years'}`;
|
|
1076
|
-
const formattedDays = !yearsOnly && remainingDays > 0 ? `${remainingDays} ${remainingDays === 1 ? 'day' : 'days'}` : years === 0 && remainingDays === 0 ? '0 days' : '';
|
|
1077
|
-
const ageString = [
|
|
1078
|
-
formattedYears,
|
|
1079
|
-
formattedDays
|
|
1080
|
-
].filter(Boolean).join(' ');
|
|
1081
|
-
return ageInDays >= 0 ? ageString : `-${ageString}`;
|
|
1082
|
-
};
|
|
1083
|
-
/**
|
|
1084
|
-
* Given an object of JSON, stringify it into a string.
|
|
1085
|
-
* @param obj - the object to stringify
|
|
1086
|
-
* @param defaults - the default value to return if the object is undefined
|
|
1087
|
-
* @category Utility
|
|
1088
|
-
*/ const stringifyJSONParam = (obj, defaults = '{}')=>obj ? JSON.stringify(obj) : defaults;
|
|
1089
|
-
|
|
1090
1000
|
// type guard functions
|
|
1091
1001
|
const isHistogramRangeData = (key)=>{
|
|
1092
1002
|
return Array.isArray(key) && key.length === 2 && key.every((item)=>typeof item === 'number');
|
|
@@ -1183,7 +1093,75 @@ function isHttpStatusError(error) {
|
|
|
1183
1093
|
*/ function isFetchParseError(error) {
|
|
1184
1094
|
return typeof error === 'object' && error != null && 'originalStatus' in error && 'status' in error && error['status'] === 'PARSING_ERROR';
|
|
1185
1095
|
}
|
|
1096
|
+
/**
|
|
1097
|
+
* Type predicate to narrow an unknown error to a `SerializedError`
|
|
1098
|
+
*/ function isSerializedError(error) {
|
|
1099
|
+
return typeof error === 'object' && error != null && !('status' in error) && ('message' in error || 'name' in error || 'code' in error || 'stack' in error);
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
const HTTPUserFriendlyErrorMessages = {
|
|
1103
|
+
// 4xx Client Errors
|
|
1104
|
+
400: 'Sorry, there was a problem with your request. Please check the information you provided and try again.',
|
|
1105
|
+
401: 'Please sign in to access this content. If you need to create an account, please contact support.',
|
|
1106
|
+
402: 'This feature requires payment to continue. Please update your subscription.',
|
|
1107
|
+
403: "You don't have permission to access this. If you think this is a mistake, please contact support.",
|
|
1108
|
+
404: "We couldn't find what you're looking for. The link might be broken or the content may have been moved.",
|
|
1109
|
+
405: 'This action is not supported. Please try a different approach.',
|
|
1110
|
+
406: "Your browser sent a request that this server couldn't understand. Try updating your browser.",
|
|
1111
|
+
407: 'Please authenticate with the network proxy first.',
|
|
1112
|
+
408: 'The request took too long to complete. Please check your internet connection and try again.',
|
|
1113
|
+
409: 'There was a conflict with your request. Someone might have modified the same content.',
|
|
1114
|
+
410: 'This content has been permanently removed and is no longer available.',
|
|
1115
|
+
411: 'There was a technical problem with your request. Please try again.',
|
|
1116
|
+
412: "Some conditions for this request weren't met. Please try again.",
|
|
1117
|
+
413: "The file you're trying to upload is too large. Please choose a smaller file.",
|
|
1118
|
+
414: 'The web address is too long. Please try a shorter URL.',
|
|
1119
|
+
415: 'This type of file is not supported. Please try a different format.',
|
|
1120
|
+
416: 'The requested content range is not available.',
|
|
1121
|
+
417: "Your request couldn't be completed as expected. Please try again.",
|
|
1122
|
+
418: 'Unusual error occurred. Please try again or contact support if the problem persists.',
|
|
1123
|
+
421: 'Your request was sent to the wrong server. Please try again.',
|
|
1124
|
+
422: "We couldn't process your request. Please check the information and try again.",
|
|
1125
|
+
423: 'This resource is temporarily locked. Please try again in a few moments.',
|
|
1126
|
+
424: 'The request failed because it depends on another request that failed.',
|
|
1127
|
+
425: 'Your request was processed too early. Please try again in a moment.',
|
|
1128
|
+
426: 'You need to upgrade your browser or app to continue.',
|
|
1129
|
+
428: "Some required conditions weren't met. Please check all requirements and try again.",
|
|
1130
|
+
429: "You've made too many requests. Please wait a while before trying again.",
|
|
1131
|
+
431: 'Request failed because the headers are too large. Please simplify your request.',
|
|
1132
|
+
451: 'This content is not available for legal reasons.',
|
|
1133
|
+
// 5xx Server Errors
|
|
1134
|
+
500: 'Something went wrong with the service. Please try again later.',
|
|
1135
|
+
501: "This feature isn't available yet. Check back later.",
|
|
1136
|
+
502: "We're having trouble connecting to our servers. Please try again in a few minutes.",
|
|
1137
|
+
503: "Our service is temporarily unavailable. We're working to restore it as quickly as possible.",
|
|
1138
|
+
504: 'The server took too long to respond. Please try again later.',
|
|
1139
|
+
505: "Your browser's HTTP version isn't supported. Please try updating your browser.",
|
|
1140
|
+
506: 'We encountered a configuration error.',
|
|
1141
|
+
507: "We're out of storage space.",
|
|
1142
|
+
508: 'We detected an infinite loop in our servers.',
|
|
1143
|
+
510: 'This server requires additional extensions to process your request.',
|
|
1144
|
+
511: 'Please sign in to the network before continuing.'
|
|
1145
|
+
};
|
|
1186
1146
|
|
|
1147
|
+
const MAX_ERROR_LENGTH = 256;
|
|
1148
|
+
const DEFAULT_API_ERROR_MESSAGE = 'API Query Error';
|
|
1149
|
+
/**
|
|
1150
|
+
* Checks if a string appears to be an HTML page
|
|
1151
|
+
*/ function isHtmlContent(str) {
|
|
1152
|
+
const trimmed = str.trim().toLowerCase();
|
|
1153
|
+
return trimmed.startsWith('<!doctype html') || trimmed.startsWith('<html') || /<html[\s>]/i.test(str);
|
|
1154
|
+
}
|
|
1155
|
+
/**
|
|
1156
|
+
* Sanitizes an error message - returns DEFAULT_API_ERROR_MESSAGE if
|
|
1157
|
+
* the message is too long or contains HTML content
|
|
1158
|
+
*/ function sanitizeErrorMessage(message) {
|
|
1159
|
+
if (!message) return DEFAULT_API_ERROR_MESSAGE;
|
|
1160
|
+
if (message.length > MAX_ERROR_LENGTH || isHtmlContent(message)) {
|
|
1161
|
+
return DEFAULT_API_ERROR_MESSAGE;
|
|
1162
|
+
}
|
|
1163
|
+
return message;
|
|
1164
|
+
}
|
|
1187
1165
|
/** Best-effort message extraction from an HTTP error body */ function extractMessage(data) {
|
|
1188
1166
|
if (typeof data === 'string') return data;
|
|
1189
1167
|
if (typeof data === 'object' && data != null) {
|
|
@@ -1210,10 +1188,11 @@ function normalizeRtkError(error) {
|
|
|
1210
1188
|
if (isFetchBaseQueryError(error)) {
|
|
1211
1189
|
// status is number for HTTP errors, string literal for the others
|
|
1212
1190
|
if (typeof error.status === 'number') {
|
|
1191
|
+
const extractedMessage = extractMessage(error.data);
|
|
1213
1192
|
return {
|
|
1214
1193
|
type: 'HTTP_ERROR',
|
|
1215
1194
|
status: error.status,
|
|
1216
|
-
message:
|
|
1195
|
+
message: sanitizeErrorMessage(extractedMessage) !== DEFAULT_API_ERROR_MESSAGE ? sanitizeErrorMessage(extractedMessage) : HTTPUserFriendlyErrorMessages[error.status] ?? `Request failed with status ${error.status}`,
|
|
1217
1196
|
data: error.data
|
|
1218
1197
|
};
|
|
1219
1198
|
}
|
|
@@ -1227,18 +1206,18 @@ function normalizeRtkError(error) {
|
|
|
1227
1206
|
return {
|
|
1228
1207
|
type: 'PARSING_ERROR',
|
|
1229
1208
|
status: error.originalStatus,
|
|
1230
|
-
message: error.error
|
|
1209
|
+
message: HTTPUserFriendlyErrorMessages[error.originalStatus] ?? `Request failed with status ${error.originalStatus}`,
|
|
1231
1210
|
data: error.data
|
|
1232
1211
|
};
|
|
1233
1212
|
case 'TIMEOUT_ERROR':
|
|
1234
1213
|
return {
|
|
1235
1214
|
type: 'TIMEOUT_ERROR',
|
|
1236
|
-
message: error.error
|
|
1215
|
+
message: sanitizeErrorMessage(error.error)
|
|
1237
1216
|
};
|
|
1238
1217
|
case 'CUSTOM_ERROR':
|
|
1239
1218
|
return {
|
|
1240
1219
|
type: 'CUSTOM_ERROR',
|
|
1241
|
-
message: error.error,
|
|
1220
|
+
message: sanitizeErrorMessage(error.error),
|
|
1242
1221
|
data: error.data
|
|
1243
1222
|
};
|
|
1244
1223
|
}
|
|
@@ -1247,7 +1226,7 @@ function normalizeRtkError(error) {
|
|
|
1247
1226
|
if ('message' in error || 'name' in error) {
|
|
1248
1227
|
return {
|
|
1249
1228
|
type: 'SERIALIZED_ERROR',
|
|
1250
|
-
message: error.message
|
|
1229
|
+
message: sanitizeErrorMessage(error.message) || 'An error occurred'
|
|
1251
1230
|
};
|
|
1252
1231
|
}
|
|
1253
1232
|
return {
|
|
@@ -1256,6 +1235,96 @@ function normalizeRtkError(error) {
|
|
|
1256
1235
|
};
|
|
1257
1236
|
}
|
|
1258
1237
|
|
|
1238
|
+
const DAYS_IN_YEAR = 365.25;
|
|
1239
|
+
/**
|
|
1240
|
+
* Converts HistogramData to HistogramDataAsStringKey by ensuring the key is a string.
|
|
1241
|
+
* If the key is already a string, it's used as is.
|
|
1242
|
+
* If the key is a number tuple [min, max], it's converted to a string in the format "min-max".
|
|
1243
|
+
*
|
|
1244
|
+
* @param data The HistogramData object to convert
|
|
1245
|
+
* @returns HistogramDataAsStringKey with the converted key
|
|
1246
|
+
*/ const convertToHistogramDataAsStringKey = (data)=>{
|
|
1247
|
+
return {
|
|
1248
|
+
key: typeof data.key === 'string' ? data.key : `${data.key[0]}-${data.key[1]}`,
|
|
1249
|
+
count: data.count
|
|
1250
|
+
};
|
|
1251
|
+
};
|
|
1252
|
+
const calculatePercentageAsNumber = (count, total)=>count ? count / total * 100 : 0;
|
|
1253
|
+
const calculatePercentageAsString = (count, total)=>`${(count / total * 100).toFixed(2)}%`;
|
|
1254
|
+
const capitalize$1 = (original)=>{
|
|
1255
|
+
const customCapitalizations = {
|
|
1256
|
+
id: 'ID',
|
|
1257
|
+
uuid: 'UUID',
|
|
1258
|
+
dna: 'DNA',
|
|
1259
|
+
dbsnp: 'dbSNP',
|
|
1260
|
+
cosmic: 'COSMIC',
|
|
1261
|
+
civic: 'CIViC',
|
|
1262
|
+
dbgap: 'dbGaP',
|
|
1263
|
+
ecog: 'ECOG',
|
|
1264
|
+
bmi: 'BMI',
|
|
1265
|
+
gdc: 'GDC',
|
|
1266
|
+
cnv: 'CNV',
|
|
1267
|
+
ssm: 'SSM',
|
|
1268
|
+
aa: 'AA'
|
|
1269
|
+
};
|
|
1270
|
+
return original.split(' ').map((word)=>customCapitalizations[word.toLowerCase()] || `${word.charAt(0).toUpperCase()}${word.slice(1)}`).join(' ');
|
|
1271
|
+
};
|
|
1272
|
+
const humanify = ({ term = '', capitalize: cap = true, facetTerm = false })=>{
|
|
1273
|
+
let original;
|
|
1274
|
+
let humanified;
|
|
1275
|
+
if (facetTerm) {
|
|
1276
|
+
// Splits on capital letters followed by lowercase letters to find
|
|
1277
|
+
// words squished together in a string.
|
|
1278
|
+
original = term?.split(/(?=[A-Z][a-z])/).join(' ');
|
|
1279
|
+
humanified = term?.replace(/\./g, ' ').replace(/_/g, ' ').trim();
|
|
1280
|
+
} else {
|
|
1281
|
+
const split = (original || term)?.split('.');
|
|
1282
|
+
humanified = split[split.length - 1]?.replace(/_/g, ' ').trim();
|
|
1283
|
+
// Special case 'name' to include any parent nested for sake of
|
|
1284
|
+
// specificity in the UI
|
|
1285
|
+
if (humanified === 'name' && split?.length > 1) {
|
|
1286
|
+
humanified = `${split[split?.length - 2]} ${humanified}`;
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
return cap ? capitalize$1(humanified) : humanified;
|
|
1290
|
+
};
|
|
1291
|
+
/*https://github.com/NCI-GDC/portal-ui/blob/develop/src/packages/%40ncigdc/utils/ageDisplay.js*/ /**
|
|
1292
|
+
* Converts age in days into a human-readable format.
|
|
1293
|
+
*
|
|
1294
|
+
* @param ageInDays - The age in days.
|
|
1295
|
+
* @param yearsOnly - If true, only display years.
|
|
1296
|
+
* @defaultValue false
|
|
1297
|
+
* @param defaultValue - The default value to return if ageInDays is falsy.
|
|
1298
|
+
* @defaultValue "--"
|
|
1299
|
+
* @returns The formatted age string.
|
|
1300
|
+
*/ const ageDisplay = (ageInDays, yearsOnly = false, defaultValue = '--')=>{
|
|
1301
|
+
if (ageInDays !== 0 && !ageInDays) {
|
|
1302
|
+
return defaultValue;
|
|
1303
|
+
}
|
|
1304
|
+
const calculateYearsAndDays = (years, days)=>days === 365 ? [
|
|
1305
|
+
years + 1,
|
|
1306
|
+
0
|
|
1307
|
+
] : [
|
|
1308
|
+
years,
|
|
1309
|
+
days
|
|
1310
|
+
];
|
|
1311
|
+
const ABS_AGE_DAYS = Math.abs(ageInDays);
|
|
1312
|
+
const [years, remainingDays] = calculateYearsAndDays(Math.floor(ABS_AGE_DAYS / DAYS_IN_YEAR), Math.ceil(ABS_AGE_DAYS % DAYS_IN_YEAR));
|
|
1313
|
+
const formattedYears = years === 0 ? '' : `${years} ${years === 1 ? 'year' : 'years'}`;
|
|
1314
|
+
const formattedDays = !yearsOnly && remainingDays > 0 ? `${remainingDays} ${remainingDays === 1 ? 'day' : 'days'}` : years === 0 && remainingDays === 0 ? '0 days' : '';
|
|
1315
|
+
const ageString = [
|
|
1316
|
+
formattedYears,
|
|
1317
|
+
formattedDays
|
|
1318
|
+
].filter(Boolean).join(' ');
|
|
1319
|
+
return ageInDays >= 0 ? ageString : `-${ageString}`;
|
|
1320
|
+
};
|
|
1321
|
+
/**
|
|
1322
|
+
* Given an object of JSON, stringify it into a string.
|
|
1323
|
+
* @param obj - the object to stringify
|
|
1324
|
+
* @param defaults - the default value to return if the object is undefined
|
|
1325
|
+
* @category Utility
|
|
1326
|
+
*/ const stringifyJSONParam = (obj, defaults = '{}')=>obj ? JSON.stringify(obj) : defaults;
|
|
1327
|
+
|
|
1259
1328
|
const queryWTSFederatedLoginStatus = async (signal)=>{
|
|
1260
1329
|
try {
|
|
1261
1330
|
const results = await fetchJSONDataFromURL(`${GEN3_WTS_API}/external_oidc/`, false, HttpMethod.GET, undefined, signal);
|
|
@@ -6956,6 +7025,7 @@ exports.GEN3_SUBMISSION_API = GEN3_SUBMISSION_API;
|
|
|
6956
7025
|
exports.GEN3_WORKSPACE_API = GEN3_WORKSPACE_API;
|
|
6957
7026
|
exports.HTTPError = HTTPError;
|
|
6958
7027
|
exports.HTTPErrorMessages = HTTPErrorMessages;
|
|
7028
|
+
exports.HTTPUserFriendlyErrorMessages = HTTPUserFriendlyErrorMessages;
|
|
6959
7029
|
exports.HttpMethod = HttpMethod;
|
|
6960
7030
|
exports.MissingServiceConfigurationError = MissingServiceConfigurationError;
|
|
6961
7031
|
exports.Modals = Modals;
|
|
@@ -7095,6 +7165,7 @@ exports.isOperatorWithFieldAndArrayOfOperands = isOperatorWithFieldAndArrayOfOpe
|
|
|
7095
7165
|
exports.isPending = isPending;
|
|
7096
7166
|
exports.isProgramUrl = isProgramUrl;
|
|
7097
7167
|
exports.isRootUrl = isRootUrl;
|
|
7168
|
+
exports.isSerializedError = isSerializedError;
|
|
7098
7169
|
exports.isStatsValue = isStatsValue;
|
|
7099
7170
|
exports.isStatsValuesArray = isStatsValuesArray;
|
|
7100
7171
|
exports.isString = isString;
|