@xh/hoist 76.0.0-SNAPSHOT.1758215282397 → 76.0.0-SNAPSHOT.1758297294348

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.
Files changed (84) hide show
  1. package/CHANGELOG.md +1 -3
  2. package/admin/tabs/userData/roles/graph/RoleGraph.ts +1 -2
  3. package/appcontainer/AppContainerModel.ts +1 -2
  4. package/appcontainer/ExceptionDialogModel.ts +2 -1
  5. package/build/types/appcontainer/ExceptionDialogModel.d.ts +2 -1
  6. package/build/types/cmp/grid/Grid.d.ts +3 -3
  7. package/build/types/core/{exception/ExceptionHandler.d.ts → ExceptionHandler.d.ts} +2 -1
  8. package/build/types/core/XH.d.ts +3 -2
  9. package/build/types/core/index.d.ts +1 -3
  10. package/build/types/core/types/Types.d.ts +0 -10
  11. package/build/types/desktop/cmp/appOption/AutoRefreshAppOption.d.ts +5 -5
  12. package/build/types/desktop/cmp/appOption/ThemeAppOption.d.ts +5 -5
  13. package/build/types/desktop/cmp/rest/impl/RestFormModel.d.ts +1 -1
  14. package/build/types/exception/Exception.d.ts +24 -0
  15. package/build/types/{core/exception → exception}/Types.d.ts +1 -18
  16. package/build/types/exception/index.d.ts +2 -0
  17. package/build/types/kit/swiper/index.d.ts +1 -1
  18. package/build/types/svc/FetchService.d.ts +55 -0
  19. package/build/types/utils/js/LangUtils.d.ts +1 -27
  20. package/build/types/utils/{log → js}/LogUtils.d.ts +37 -1
  21. package/build/types/utils/js/index.d.ts +2 -0
  22. package/cmp/ag-grid/AgGrid.ts +1 -1
  23. package/cmp/chart/Chart.ts +1 -2
  24. package/cmp/chart/impl/ChartContextMenuItems.ts +1 -1
  25. package/cmp/grid/columns/Column.ts +1 -2
  26. package/cmp/grid/helpers/GridCountLabel.ts +1 -2
  27. package/cmp/grid/impl/ColumnWidthCalculator.ts +1 -2
  28. package/cmp/grid/impl/Utils.ts +1 -1
  29. package/cmp/relativetimestamp/RelativeTimestamp.ts +1 -2
  30. package/cmp/treemap/TreeMap.ts +1 -2
  31. package/core/{exception/ExceptionHandler.ts → ExceptionHandler.ts} +3 -4
  32. package/core/HoistBase.ts +3 -2
  33. package/core/HoistBaseDecorators.ts +1 -2
  34. package/core/HoistComponent.ts +1 -2
  35. package/core/XH.ts +3 -4
  36. package/core/index.ts +1 -3
  37. package/core/load/LoadSupport.ts +1 -2
  38. package/core/persist/PersistenceProvider.ts +1 -2
  39. package/core/types/Types.ts +0 -6
  40. package/data/filter/Utils.ts +1 -1
  41. package/data/impl/RecordSet.ts +1 -2
  42. package/desktop/cmp/button/grid/ColAutosizeButton.ts +1 -2
  43. package/desktop/cmp/button/grid/ColChooserButton.ts +1 -2
  44. package/desktop/cmp/button/grid/ExpandToLevelButton.ts +1 -2
  45. package/desktop/cmp/button/grid/ExportButton.ts +1 -2
  46. package/desktop/cmp/button/panel/ModalToggleButton.ts +1 -2
  47. package/desktop/cmp/button/zoneGrid/ZoneMapperButton.ts +1 -2
  48. package/desktop/cmp/dash/container/impl/DashContainerUtils.ts +1 -2
  49. package/desktop/cmp/form/FormField.ts +1 -2
  50. package/desktop/cmp/grid/editors/BooleanEditor.ts +1 -1
  51. package/desktop/cmp/panel/Panel.ts +1 -1
  52. package/desktop/hooks/UseContextMenu.ts +1 -1
  53. package/exception/Exception.ts +81 -0
  54. package/{core/exception → exception}/Types.ts +1 -22
  55. package/{utils/log → exception}/index.ts +2 -2
  56. package/kit/ag-grid/index.ts +1 -2
  57. package/kit/highcharts/index.ts +1 -2
  58. package/mobile/cmp/button/grid/ColAutosizeButton.ts +1 -2
  59. package/mobile/cmp/button/grid/ColChooserButton.ts +1 -2
  60. package/mobile/cmp/button/grid/ExpandCollapseButton.ts +1 -2
  61. package/mobile/cmp/button/grid/ExpandToLevelButton.ts +1 -2
  62. package/mobile/cmp/button/zoneGrid/ZoneMapperButton.ts +1 -2
  63. package/mobile/cmp/panel/Panel.ts +1 -1
  64. package/mobx/overrides.ts +1 -1
  65. package/package.json +1 -1
  66. package/promise/Promise.ts +3 -3
  67. package/security/BaseOAuthClient.ts +3 -3
  68. package/security/msal/MsalClient.ts +1 -2
  69. package/svc/ChangelogService.ts +1 -1
  70. package/svc/EnvironmentService.ts +1 -2
  71. package/svc/FetchService.ts +208 -16
  72. package/tsconfig.tsbuildinfo +1 -1
  73. package/utils/async/Timer.ts +1 -2
  74. package/utils/js/Decorators.ts +4 -4
  75. package/utils/js/LangUtils.ts +2 -66
  76. package/utils/{log → js}/LogUtils.ts +77 -19
  77. package/utils/js/index.ts +2 -0
  78. package/build/types/core/exception/Exception.d.ts +0 -61
  79. package/build/types/utils/log/index.d.ts +0 -1
  80. package/build/types/utils/version/index.d.ts +0 -1
  81. package/core/exception/Exception.ts +0 -256
  82. package/utils/version/index.ts +0 -8
  83. /package/build/types/utils/{version → js}/VersionUtils.d.ts +0 -0
  84. /package/utils/{version → js}/VersionUtils.ts +0 -0
@@ -7,8 +7,7 @@
7
7
  import {XH} from '@xh/hoist/core';
8
8
  import {wait} from '@xh/hoist/promise';
9
9
  import {MILLISECONDS, MINUTES, olderThan} from '@xh/hoist/utils/datetime';
10
- import {throwIf} from '@xh/hoist/utils/js';
11
- import {logError, logWarn} from '@xh/hoist/utils/log';
10
+ import {logError, logWarn, throwIf} from '@xh/hoist/utils/js';
12
11
  import {isBoolean, isFinite, isFunction, isNil, isString, pull} from 'lodash';
13
12
 
14
13
  /**
@@ -4,10 +4,10 @@
4
4
  *
5
5
  * Copyright © 2025 Extremely Heavy Industries Inc.
6
6
  */
7
- import {XH} from '@xh/hoist/core';
7
+ import {Exception} from '@xh/hoist/exception';
8
8
  import {debounce, isFunction} from 'lodash';
9
- import {getOrCreate, throwIf, warnIf} from './LangUtils';
10
- import {withDebug, withInfo} from '../log/LogUtils';
9
+ import {getOrCreate, throwIf} from './LangUtils';
10
+ import {withDebug, warnIf, withInfo} from './LogUtils';
11
11
 
12
12
  /**
13
13
  * Decorates a class method so that it is debounced by the specified duration.
@@ -106,7 +106,7 @@ export function abstract(target, key, descriptor) {
106
106
  return {
107
107
  ...descriptor,
108
108
  [baseFnName]: function () {
109
- throw XH.exception(`${key} must be implemented by ${this.constructor.name}`);
109
+ throw Exception.create(`${key} must be implemented by ${this.constructor.name}`);
110
110
  }
111
111
  };
112
112
  }
@@ -4,8 +4,8 @@
4
4
  *
5
5
  * Copyright © 2025 Extremely Heavy Industries Inc.
6
6
  */
7
- import type {PlainObject, Thunkable, LogSource} from '@xh/hoist/core';
8
- import {Exception} from '@xh/hoist/core/exception/Exception';
7
+ import type {PlainObject, Thunkable} from '@xh/hoist/core';
8
+ import {Exception} from '@xh/hoist/exception';
9
9
  import {
10
10
  flatMap,
11
11
  forOwn,
@@ -125,24 +125,6 @@ export function throwIf(condition: any, message: unknown) {
125
125
  }
126
126
  }
127
127
 
128
- /**
129
- * Log a warning to the console if a condition evaluates as truthy.
130
- */
131
- export function warnIf(condition: any, message: any) {
132
- if (condition) {
133
- console.warn(message);
134
- }
135
- }
136
-
137
- /**
138
- * Log an error to the console if a condition evaluates as truthy.
139
- */
140
- export function errorIf(condition: any, message: any) {
141
- if (condition) {
142
- console.error(message);
143
- }
144
- }
145
-
146
128
  /**
147
129
  * Instantiate a singleton object of a class, and place a reference to the created
148
130
  * object in a static property on the class.
@@ -156,52 +138,6 @@ export function createSingleton<T>(clazz: new () => T): T {
156
138
  return (clazz['instance'] = new clazz());
157
139
  }
158
140
 
159
- export interface APIWarnOptions {
160
- /**
161
- * If provided and undefined, this method will be a no-op.
162
- * Useful for testing if a parameter has been provided in caller.
163
- */
164
- test?: any;
165
-
166
- /** Version when this API will no longer be supported or this warning should be removed. */
167
- v?: string;
168
-
169
- /** An additional message. Can contain suggestions for alternatives. */
170
- msg?: string;
171
-
172
- /** Source of message for labeling log message. */
173
- source?: LogSource;
174
- }
175
-
176
- /**
177
- * Document and prevent usage of a removed parameter.
178
- */
179
- export function apiRemoved(name: string, opts: APIWarnOptions = {}) {
180
- if ('test' in opts && isUndefined(opts.test)) return;
181
-
182
- const src = opts.source ? `[${opts.source}] ` : '',
183
- msg = opts.msg ? ` ${opts.msg}.` : '';
184
- throw Exception.create(`${src}The use of '${name}' is no longer supported.${msg}`);
185
- }
186
-
187
- /**
188
- * Document and warn on usage of a deprecated API
189
- *
190
- * @param name - the name of the deprecated parameter
191
- */
192
- const _seenWarnings = {};
193
- export function apiDeprecated(name: string, opts: APIWarnOptions = {}) {
194
- if ('test' in opts && isUndefined(opts.test)) return;
195
-
196
- const v = opts.v ?? 'a future release',
197
- msg = opts.msg ?? '',
198
- warn = `The use of '${name}' has been deprecated and will be removed in ${v}. ${msg}`;
199
- if (!_seenWarnings[warn]) {
200
- console.warn(warn, opts.source);
201
- _seenWarnings[warn] = true;
202
- }
203
- }
204
-
205
141
  /**
206
142
  * Throw an exception if the provided object or collection is empty, as per lodash isEmpty().
207
143
  *
@@ -4,9 +4,11 @@
4
4
  *
5
5
  * Copyright © 2025 Extremely Heavy Industries Inc.
6
6
  */
7
- import type {Some, LogLevel, LogSource} from '@xh/hoist/core';
8
- import {castArray, flatMap, isString} from 'lodash';
7
+ import type {Some} from '@xh/hoist/core';
8
+ import {Exception} from '@xh/hoist/exception';
9
+ import {castArray, isString, isUndefined} from 'lodash';
9
10
  import store from 'store2';
11
+ import {intersperse} from './LangUtils';
10
12
 
11
13
  /**
12
14
  * Utility functions providing managed, structured logging to Hoist apps.
@@ -22,6 +24,29 @@ import store from 'store2';
22
24
  * XH.logLevel from the console.
23
25
  */
24
26
 
27
+ /** Severity Level for log statement */
28
+ export type LogLevel = 'error' | 'warn' | 'info' | 'debug';
29
+
30
+ /** Object identifying the source of log statement. Typically, a javascript class */
31
+ export type LogSource = string | {displayName: string} | {constructor: {name: string}};
32
+
33
+ export interface APIWarnOptions {
34
+ /**
35
+ * If provided and undefined, this method will be a no-op.
36
+ * Useful for testing if a parameter has been provided in caller.
37
+ */
38
+ test?: any;
39
+
40
+ /** Version when this API will no longer be supported or this warning should be removed. */
41
+ v?: string;
42
+
43
+ /** An additional message. Can contain suggestions for alternatives. */
44
+ msg?: string;
45
+
46
+ /** Source of message for labelling log message. */
47
+ source?: LogSource;
48
+ }
49
+
25
50
  /**
26
51
  * Current minimum severity for Hoist log utils (default 'info').
27
52
  * Messages logged via managed Hoist log utils with lower severity will be ignored.
@@ -29,11 +54,7 @@ import store from 'store2';
29
54
  * @internal - use public `XH.logLevel`.
30
55
  */
31
56
  export function getLogLevel() {
32
- try {
33
- return _logLevel;
34
- } catch (e) {
35
- return 'info';
36
- }
57
+ return _logLevel;
37
58
  }
38
59
 
39
60
  /**
@@ -121,13 +142,58 @@ export function logWarn(msgs: Some<unknown>, source?: LogSource) {
121
142
  return loggedDo(msgs, null, source, 'warn');
122
143
  }
123
144
 
145
+ /**
146
+ * Log a warning to the console if a condition evaluates as truthy.
147
+ */
148
+ export function warnIf(condition: any, message: any) {
149
+ if (condition) {
150
+ logWarn(message);
151
+ }
152
+ }
153
+
154
+ /**
155
+ * Log an error to the console if a condition evaluates as truthy.
156
+ */
157
+ export function errorIf(condition: any, message: any) {
158
+ if (condition) {
159
+ logError(message);
160
+ }
161
+ }
162
+
163
+ /**
164
+ * Document and prevent usage of a removed parameter.
165
+ */
166
+ export function apiRemoved(name: string, opts: APIWarnOptions = {}) {
167
+ if ('test' in opts && isUndefined(opts.test)) return;
168
+
169
+ const src = opts.source ? `[${opts.source}] ` : '',
170
+ msg = opts.msg ? ` ${opts.msg}.` : '';
171
+ throw Exception.create(`${src}The use of '${name}' is no longer supported.${msg}`);
172
+ }
173
+
174
+ /**
175
+ * Document and warn on usage of a deprecated API
176
+ *
177
+ * @param name - the name of the deprecated parameter
178
+ */
179
+ const _seenWarnings = {};
180
+ export function apiDeprecated(name: string, opts: APIWarnOptions = {}) {
181
+ if ('test' in opts && isUndefined(opts.test)) return;
182
+
183
+ const v = opts.v ?? 'a future release',
184
+ msg = opts.msg ?? '',
185
+ warn = `The use of '${name}' has been deprecated and will be removed in ${v}. ${msg}`;
186
+ if (!_seenWarnings[warn]) {
187
+ logWarn(warn, opts.source);
188
+ _seenWarnings[warn] = true;
189
+ }
190
+ }
191
+
124
192
  //----------------------------------
125
193
  // Implementation
126
194
  //----------------------------------
127
195
  function loggedDo<T>(messages: Some<unknown>, fn: () => T, source: LogSource, level: LogLevel): T {
128
- const _severity: Record<LogLevel, number> = {error: 3, warn: 2, info: 1, debug: 0};
129
-
130
- if (_severity[level] < _severity[getLogLevel()]) {
196
+ if (_severity[level] < _severity[_logLevel]) {
131
197
  return fn?.();
132
198
  }
133
199
 
@@ -202,19 +268,11 @@ function parseSource(source: LogSource): string {
202
268
  return null;
203
269
  }
204
270
 
205
- /**
206
- * Intersperse a separator between each item in an array.
207
- * Same method as in LangUtils, but duplicated here to avoid circular dependency.
208
- */
209
- function intersperse<T>(arr: T[], separator: T): T[] {
210
- return flatMap(arr, (it, idx) => {
211
- return idx > 0 ? [separator, it] : [it];
212
- });
213
- }
214
271
  //----------------------------------------------------------------
215
272
  // Initialization + Level/Severity support.
216
273
  // Initialize during parsing to make available immediately.
217
274
  //----------------------------------------------------------------
218
275
  let _logLevel: LogLevel = 'info';
276
+ const _severity: Record<LogLevel, number> = {error: 3, warn: 2, info: 1, debug: 0};
219
277
 
220
278
  setLogLevel(store.session.get('xhLogLevel', 'info'));
package/utils/js/index.ts CHANGED
@@ -7,5 +7,7 @@
7
7
  export * from './HtmlUtils';
8
8
  export * from './LangUtils';
9
9
  export * from './Decorators';
10
+ export * from './LogUtils';
10
11
  export * from './DomUtils';
11
12
  export * from './TestUtils';
13
+ export * from './VersionUtils';
@@ -1,61 +0,0 @@
1
- import { FetchOptions } from '@xh/hoist/svc';
2
- import { FetchException, HoistException, TimeoutException, TimeoutExceptionConfig } from './Types';
3
- /**
4
- * Standardized Exception/Error objects.
5
- *
6
- * The main entry point for this class is the create() method.
7
- * Applications can use this method to create various generic runtime exceptions.
8
- * @see ExceptionHandler.handleException
9
- */
10
- export declare class Exception {
11
- /**
12
- * Create and return a HoistException
13
- *
14
- * See {@link XH.exception} - an alias for this factory off of `XH`.
15
- *
16
- * @param src - If a native JS Error, it will be enhanced into a HoistException and returned.
17
- * If a plain object, all properties will be set on a new HoistException.
18
- * Other inputs will be treated as the `message` of a new HoistException.
19
- */
20
- static create(src: unknown): HoistException;
21
- /** Create an Error for when an operation (e.g. a Promise) times out. */
22
- static timeout(config: TimeoutExceptionConfig): TimeoutException;
23
- /**
24
- * Create an Error to throw when a fetch call returns a !ok response.
25
- * @param fetchOptions - original options passed to FetchService.
26
- * @param response - return value of native fetch.
27
- * @param responseText - optional additional details from the server.
28
- */
29
- static fetchError(fetchOptions: FetchOptions, response: Response, responseText?: string): FetchException;
30
- /**
31
- * Create an Error to throw when a fetchJson call encounters a SyntaxError.
32
- * @param fetchOptions - original options passed to FetchService.
33
- * @param cause - object thrown by native {@link response.json}.
34
- */
35
- static fetchJsonParseError(fetchOptions: FetchOptions, cause: any): FetchException;
36
- /**
37
- * Create an Error to throw when a fetch call is aborted.
38
- * @param fetchOptions - original options passed to FetchService.
39
- * @param cause - object thrown by native fetch
40
- */
41
- static fetchAborted(fetchOptions: FetchOptions, cause: any): FetchException;
42
- /**
43
- * Create an Error to throw when a fetch call times out.
44
- * @param fetchOptions - original options the app passed when calling FetchService.
45
- * @param cause - underlying timeout exception
46
- * @param message - optional custom message
47
- *
48
- * @returns an exception that is both a TimeoutException, and a FetchException, with the
49
- * underlying TimeoutException as its cause.
50
- */
51
- static fetchTimeout(fetchOptions: FetchOptions, cause: TimeoutException, message: string): FetchException & TimeoutException;
52
- /**
53
- * Create an Error for when the server called by fetch does not respond
54
- * @param fetchOptions - original options the app passed to FetchService.fetch
55
- * @param cause - object thrown by native fetch
56
- */
57
- static serverUnavailable(fetchOptions: FetchOptions, cause: any): FetchException;
58
- private static createFetchException;
59
- private static createInternal;
60
- }
61
- export declare function isHoistException(src: unknown): src is HoistException;
@@ -1 +0,0 @@
1
- export * from './LogUtils';
@@ -1 +0,0 @@
1
- export * from './VersionUtils';
@@ -1,256 +0,0 @@
1
- /*
2
- * This file belongs to Hoist, an application development toolkit
3
- * developed by Extremely Heavy Industries (www.xh.io | info@xh.io)
4
- *
5
- * Copyright © 2025 Extremely Heavy Industries Inc.
6
- */
7
- import {PlainObject, XH} from '@xh/hoist/core';
8
- import {FetchOptions} from '@xh/hoist/svc';
9
- import {pluralize} from '@xh/hoist/utils/js';
10
- import {isPlainObject, isString, truncate} from 'lodash';
11
- import {FetchException, HoistException, TimeoutException, TimeoutExceptionConfig} from './Types';
12
-
13
- /**
14
- * Standardized Exception/Error objects.
15
- *
16
- * The main entry point for this class is the create() method.
17
- * Applications can use this method to create various generic runtime exceptions.
18
- * @see ExceptionHandler.handleException
19
- */
20
- export class Exception {
21
- /**
22
- * Create and return a HoistException
23
- *
24
- * See {@link XH.exception} - an alias for this factory off of `XH`.
25
- *
26
- * @param src - If a native JS Error, it will be enhanced into a HoistException and returned.
27
- * If a plain object, all properties will be set on a new HoistException.
28
- * Other inputs will be treated as the `message` of a new HoistException.
29
- */
30
- static create(src: unknown): HoistException {
31
- if (isHoistException(src)) return src;
32
- if (src instanceof Error) return this.createInternal({}, src);
33
-
34
- const attributes: PlainObject = isPlainObject(src) ? src : {message: src?.toString()};
35
- return this.createInternal({
36
- name: 'Exception',
37
- message: 'An unknown error occurred',
38
- ...attributes
39
- });
40
- }
41
-
42
- /** Create an Error for when an operation (e.g. a Promise) times out. */
43
- static timeout(config: TimeoutExceptionConfig): TimeoutException {
44
- const {interval, ...rest} = config,
45
- // Display timeout in seconds if an even multiple (or very close to it).
46
- displayInterval =
47
- interval % 1000 < 5
48
- ? pluralize('second', Math.round(interval / 1000), true)
49
- : `${interval}ms`;
50
-
51
- return this.createInternal({
52
- name: 'Timeout Exception',
53
- // Note FetchService.managedFetchAsync appends to this message - review if changing.
54
- message: `Timed out after ${displayInterval}`,
55
- isTimeout: true,
56
- stack: null,
57
- interval,
58
- ...rest
59
- }) as TimeoutException;
60
- }
61
-
62
- /**
63
- * Create an Error to throw when a fetch call returns a !ok response.
64
- * @param fetchOptions - original options passed to FetchService.
65
- * @param response - return value of native fetch.
66
- * @param responseText - optional additional details from the server.
67
- */
68
- static fetchError(
69
- fetchOptions: FetchOptions,
70
- response: Response,
71
- responseText: string = null
72
- ): FetchException {
73
- const {headers, status, statusText} = response,
74
- defaults = {
75
- name: 'HTTP Error ' + (status || ''),
76
- message: statusText,
77
- httpStatus: status,
78
- serverDetails: responseText,
79
- fetchOptions
80
- };
81
-
82
- if (status === 401) {
83
- return this.createFetchException({
84
- ...defaults,
85
- name: 'Unauthorized',
86
- message: 'Your session may have timed out and you may need to log in again.'
87
- });
88
- }
89
-
90
- // Try to "smart" decode as server provided JSON Exception (with a name)
91
- try {
92
- const cType = headers.get('Content-Type');
93
- if (cType?.includes('application/json')) {
94
- const parsedResp = safeParseJson(responseText);
95
- return this.createFetchException({
96
- ...defaults,
97
- name: parsedResp?.name ?? defaults.name,
98
- message: extractMessage(parsedResp, responseText, statusText),
99
- isRoutine: parsedResp?.isRoutine ?? false,
100
- serverDetails: parsedResp ?? responseText
101
- });
102
- }
103
- } catch (ignored) {}
104
-
105
- // Fall back to raw defaults
106
- return this.createFetchException(defaults);
107
- }
108
-
109
- /**
110
- * Create an Error to throw when a fetchJson call encounters a SyntaxError.
111
- * @param fetchOptions - original options passed to FetchService.
112
- * @param cause - object thrown by native {@link response.json}.
113
- */
114
- static fetchJsonParseError(fetchOptions: FetchOptions, cause: any): FetchException {
115
- return this.createFetchException({
116
- name: 'JSON Parsing Error',
117
- message:
118
- 'Error parsing the response body as JSON. The server may have returned an invalid ' +
119
- 'or empty response. Use "XH.fetch()" to process the response manually.',
120
- fetchOptions,
121
- cause
122
- });
123
- }
124
-
125
- /**
126
- * Create an Error to throw when a fetch call is aborted.
127
- * @param fetchOptions - original options passed to FetchService.
128
- * @param cause - object thrown by native fetch
129
- */
130
- static fetchAborted(fetchOptions: FetchOptions, cause: any): FetchException {
131
- return this.createFetchException({
132
- name: 'Fetch Aborted',
133
- message: `Fetch request aborted, url: "${fetchOptions.url}"`,
134
- isRoutine: true,
135
- isFetchAborted: true,
136
- fetchOptions,
137
- cause
138
- });
139
- }
140
-
141
- /**
142
- * Create an Error to throw when a fetch call times out.
143
- * @param fetchOptions - original options the app passed when calling FetchService.
144
- * @param cause - underlying timeout exception
145
- * @param message - optional custom message
146
- *
147
- * @returns an exception that is both a TimeoutException, and a FetchException, with the
148
- * underlying TimeoutException as its cause.
149
- */
150
- static fetchTimeout(
151
- fetchOptions: FetchOptions,
152
- cause: TimeoutException,
153
- message: string
154
- ): FetchException & TimeoutException {
155
- return this.createFetchException({
156
- name: 'Fetch Timeout',
157
- message,
158
- isFetchTimeout: true,
159
- isTimeout: true,
160
- interval: cause.interval,
161
- fetchOptions,
162
- cause
163
- }) as FetchException & TimeoutException;
164
- }
165
-
166
- /**
167
- * Create an Error for when the server called by fetch does not respond
168
- * @param fetchOptions - original options the app passed to FetchService.fetch
169
- * @param cause - object thrown by native fetch
170
- */
171
- static serverUnavailable(fetchOptions: FetchOptions, cause: any): FetchException {
172
- const protocolPattern = /^[a-z]+:\/\//i,
173
- originPattern = /^[a-z]+:\/\/[^/]+/i,
174
- match = fetchOptions.url.match(originPattern),
175
- origin = match
176
- ? match[0]
177
- : protocolPattern.test(XH.baseUrl)
178
- ? XH.baseUrl
179
- : window.location.origin;
180
-
181
- return this.createFetchException({
182
- name: 'Server Unavailable',
183
- message: `Unable to contact the server at ${origin}`,
184
- isServerUnavailable: true,
185
- fetchOptions,
186
- cause
187
- });
188
- }
189
-
190
- //-----------------------
191
- // Implementation
192
- //-----------------------
193
- private static createFetchException(attributes: PlainObject) {
194
- let correlationId: string = null;
195
- const correlationIdHeaderKey = XH?.fetchService?.correlationIdHeaderKey;
196
- if (correlationIdHeaderKey) {
197
- correlationId = attributes.fetchOptions?.headers?.[correlationIdHeaderKey];
198
- }
199
-
200
- return this.createInternal({
201
- isFetchAborted: false,
202
- httpStatus: 0, // native fetch doesn't put status on its Error
203
- serverDetails: null,
204
- stack: null, // server-sourced exceptions do not include, neither should client, not relevant
205
- correlationId,
206
- ...attributes
207
- }) as FetchException;
208
- }
209
-
210
- private static createInternal(attributes: PlainObject, baseError?: Error) {
211
- const {message, ...rest} = attributes;
212
- const ret = Object.assign(
213
- baseError ?? new Error(message),
214
- {
215
- isRoutine: false,
216
- isHoistException: true
217
- },
218
- rest
219
- ) as HoistException;
220
-
221
- // statuses of 0, 4XX, 5XX are server errors, so stack irrelevant and potentially misleading
222
- if (ret.stack == null || /^[045]/.test(ret.httpStatus)) delete ret.stack;
223
-
224
- return ret;
225
- }
226
- }
227
-
228
- function safeParseJson(txt: string): PlainObject {
229
- try {
230
- return JSON.parse(txt);
231
- } catch (ignored) {
232
- return null;
233
- }
234
- }
235
-
236
- function extractMessage(parsedResp: PlainObject, responseText: string, statusText: string): string {
237
- let ret: string;
238
- if (parsedResp) {
239
- // From parsed response, including cause if provided (e.g. ExternalHttpException)
240
- ret = parsedResp.message;
241
- if (isString(parsedResp.cause)) {
242
- const cause = truncate(parsedResp.cause, {length: 255});
243
- ret = ret ? `${ret} (Caused by: ${cause})` : cause;
244
- }
245
- } else {
246
- // Use raw text if not JSON parseable
247
- ret = truncate(responseText?.trim(), {length: 255});
248
- }
249
-
250
- // Fallback to statusText if we have nothing else.
251
- return ret || statusText;
252
- }
253
-
254
- export function isHoistException(src: unknown): src is HoistException {
255
- return src?.['isHoistException'];
256
- }
@@ -1,8 +0,0 @@
1
- /*
2
- * This file belongs to Hoist, an application development toolkit
3
- * developed by Extremely Heavy Industries (www.xh.io | info@xh.io)
4
- *
5
- * Copyright © 2025 Extremely Heavy Industries Inc.
6
- */
7
-
8
- export * from './VersionUtils';
File without changes