@xh/hoist 75.0.0-SNAPSHOT.1753720955374 → 75.0.0-SNAPSHOT.1753726213836
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/CHANGELOG.md +4 -0
- package/build/types/core/AppSpec.d.ts +72 -53
- package/build/types/core/HoistAuthModel.d.ts +2 -2
- package/build/types/svc/WebSocketService.d.ts +2 -2
- package/core/AppSpec.ts +104 -73
- package/core/HoistAuthModel.ts +2 -2
- package/core/XH.ts +0 -1
- package/package.json +1 -1
- package/svc/WebSocketService.ts +4 -4
- package/tsconfig.tsbuildinfo +1 -1
- package/utils/js/LangUtils.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -37,6 +37,10 @@
|
|
|
37
37
|
|
|
38
38
|
### ⚙️ Technical
|
|
39
39
|
|
|
40
|
+
* WebSockets are now enabled by default for client apps, as they have been on the server since Hoist
|
|
41
|
+
Core v20.2. Maintaining a WebSocket connection back to the Hoist server enables useful Admin
|
|
42
|
+
Console functionality and is recommended, but clients that must disable WebSockets can do so via
|
|
43
|
+
`AppSpec.disableWebSockets`. Note `AppSpec.enableWebSockets` is deprecated and can be removed.
|
|
40
44
|
* Hoist now sets a reference to an app's singleton `AuthModel` on a static `instance` property of
|
|
41
45
|
the app-specified class. App developers can declare a typed static `instance` property on their
|
|
42
46
|
model class and use it to access the singleton with its proper type, vs. `XH.authModel`.
|
|
@@ -1,85 +1,103 @@
|
|
|
1
|
-
import { HoistAppModel, HoistAuthModel,
|
|
1
|
+
import { ElementFactory, HoistAppModel, HoistAuthModel, HoistProps } from '@xh/hoist/core';
|
|
2
2
|
import { Component, ComponentClass, FunctionComponent } from 'react';
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Spec for a client-side Hoist application. A config matching this class's shape is provided
|
|
5
|
+
* to {@link XHApi.renderApp} to kick-off app rendering and is available thereafter as `XH.appSpec`.
|
|
6
6
|
*/
|
|
7
7
|
export declare class AppSpec<T extends HoistAppModel = HoistAppModel> {
|
|
8
|
+
/**
|
|
9
|
+
* AuthModel class for the application. Note this is a reference to the class itself, not an
|
|
10
|
+
* instance, and must extend {@link HoistAuthModel}. If not provided, Hoist will fallback to
|
|
11
|
+
* the superclass implementation, but note that class would only be suitable for fully
|
|
12
|
+
* transparent SSO based solutions such as NTLM. Common patterns such as OAuth will require an
|
|
13
|
+
* extended implementation.
|
|
14
|
+
*/
|
|
15
|
+
authModelClass?: new () => HoistAuthModel;
|
|
16
|
+
/**
|
|
17
|
+
* Method for determining if user may access the app. If a string, will be interpreted as the
|
|
18
|
+
* role required for basic UI access. Return false to show a generated lockout message, or use
|
|
19
|
+
* the object form to provide a custom message.
|
|
20
|
+
*/
|
|
21
|
+
checkAccess: string | ((user: object) => boolean | {
|
|
22
|
+
hasAccess: boolean;
|
|
23
|
+
message: string;
|
|
24
|
+
});
|
|
8
25
|
/**
|
|
9
26
|
* Short code for this particular JS client application.
|
|
27
|
+
*
|
|
10
28
|
* Will default to the `appCode` specified within the project's Webpack config, but can be
|
|
11
29
|
* set to a more specific value (e.g. 'myAppMobile') to identify the client app in common
|
|
12
|
-
* code or configs.
|
|
30
|
+
* code or configs that support distinct settings for different client apps.
|
|
13
31
|
*/
|
|
14
32
|
clientAppCode?: string;
|
|
15
33
|
/**
|
|
16
34
|
* Display name for this particular JS client application.
|
|
35
|
+
*
|
|
17
36
|
* As with `clientAppCode` above, this will default to the global `appName` specified by
|
|
18
37
|
* the project's Webpack config, but can be set here to a more specific value (e.g.
|
|
19
38
|
* 'MyApp Mobile').
|
|
20
39
|
*/
|
|
21
40
|
clientAppName?: string;
|
|
22
41
|
/**
|
|
23
|
-
* Root
|
|
24
|
-
*
|
|
25
|
-
*/
|
|
26
|
-
modelClass: new () => T;
|
|
27
|
-
/**
|
|
28
|
-
* AuthModel class for the application. Note this is a reference to the class itself, not an
|
|
29
|
-
* instance, and must extend {@link HoistAuthModel}.
|
|
30
|
-
*/
|
|
31
|
-
authModelClass?: new () => HoistAuthModel;
|
|
32
|
-
/**
|
|
33
|
-
* Root HoistComponent for the application. Despite the name, functional components are fully
|
|
34
|
-
* supported and expected.
|
|
42
|
+
* Root HoistComponent for the application.
|
|
43
|
+
* Despite the name, functional components are fully supported and expected.
|
|
35
44
|
*/
|
|
36
45
|
componentClass: ComponentClass<HoistProps> | FunctionComponent<HoistProps>;
|
|
37
46
|
/**
|
|
38
47
|
* Container component to be used to host this application.
|
|
39
|
-
*
|
|
48
|
+
*
|
|
49
|
+
* This class determines the platform used by Hoist - almost all apps will import and specify
|
|
40
50
|
* either `@xh/hoist/desktop/AppContainer` or `@xh/hoist/mobile/AppContainer`.
|
|
41
51
|
*/
|
|
42
52
|
containerClass: ComponentClass<HoistProps> | FunctionComponent<HoistProps>;
|
|
43
|
-
/** True if the app should use the Hoist mobile toolkit.*/
|
|
44
|
-
isMobileApp: boolean;
|
|
45
|
-
/** True to show a login form on initialization when not authenticated. (default false) */
|
|
46
|
-
enableLoginForm?: boolean;
|
|
47
53
|
/**
|
|
48
|
-
* True to
|
|
49
|
-
*
|
|
54
|
+
* True to disable Hoist's built-in WebSocket support for this client app. Even if the app
|
|
55
|
+
* itself is not using WebSockets for business data, the Hoist Admin Console's "Clients" tab and
|
|
56
|
+
* related functionality benefit from having them enabled, so disable only if there is a good
|
|
57
|
+
* reason to do so.
|
|
50
58
|
*/
|
|
51
|
-
|
|
59
|
+
disableWebSockets?: boolean;
|
|
52
60
|
/**
|
|
53
|
-
*
|
|
54
|
-
*
|
|
61
|
+
* True to disable Field-level XSS protection by default across all Stores/Fields in the app.
|
|
62
|
+
* For use with secure, internal apps that do not display arbitrary/external user input and
|
|
63
|
+
* have tight performance tolerances and/or load very large record sets.
|
|
64
|
+
* @see FieldSpec.disableXssProtection
|
|
55
65
|
*/
|
|
56
|
-
|
|
57
|
-
hasAccess: boolean;
|
|
58
|
-
message: string;
|
|
59
|
-
});
|
|
66
|
+
disableXssProtection?: boolean;
|
|
60
67
|
/**
|
|
61
|
-
*
|
|
62
|
-
*
|
|
68
|
+
* True to show a login form on initialization when not authenticated. Default is `false` as
|
|
69
|
+
* most Hoist applications are expected to use OAuth or SSO for authn.
|
|
63
70
|
*/
|
|
64
|
-
|
|
65
|
-
/** True to enable Hoist websocket connectivity. (default false) */
|
|
66
|
-
webSocketsEnabled?: boolean;
|
|
71
|
+
enableLoginForm?: boolean;
|
|
67
72
|
/**
|
|
68
|
-
*
|
|
69
|
-
*
|
|
73
|
+
* True to show logout options in the app, for apps with auth schemes that can support this
|
|
74
|
+
* operation (e.g. OAuth). Default is `false` as most Hoist applications are expected to use
|
|
75
|
+
* SSO or to run in internal environments where logout is not required / typical.
|
|
76
|
+
*/
|
|
77
|
+
enableLogout?: boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Optional custom Component to display when the app has been suspended. The component will
|
|
80
|
+
* receive a single `onReactivate` prop, a no-arg callback fired when the user has acknowledged
|
|
70
81
|
* the suspension and wishes to reload the app.
|
|
71
82
|
*/
|
|
72
83
|
idlePanel?: ElementFactory | FunctionComponent | Component;
|
|
84
|
+
/** True if the app should use the Hoist mobile toolkit.*/
|
|
85
|
+
isMobileApp: boolean;
|
|
73
86
|
/**
|
|
74
87
|
* Optional custom Component to display when the user is denied access to app. Intended for
|
|
75
88
|
* apps that implement custom auth flows. See also `lockoutMessage` for a more lightweight
|
|
76
89
|
* customization option.
|
|
77
90
|
*/
|
|
78
91
|
lockoutPanel?: ElementFactory | FunctionComponent | Component;
|
|
79
|
-
/** Optional message to show on login form (see showLoginForm). */
|
|
80
|
-
loginMessage?: string;
|
|
81
92
|
/** Optional message to show users when denied access to app. */
|
|
82
93
|
lockoutMessage?: string;
|
|
94
|
+
/** Optional message to show on login form, if `showLoginForm: true`. */
|
|
95
|
+
loginMessage?: string;
|
|
96
|
+
/**
|
|
97
|
+
* Root Model class for the application. Note this is a reference to the class itself, not an
|
|
98
|
+
* instance, and must extend {@link HoistAppModel}.
|
|
99
|
+
*/
|
|
100
|
+
modelClass: new () => T;
|
|
83
101
|
/**
|
|
84
102
|
* True to show the built-in browser context menu when no app-specific menu would be shown
|
|
85
103
|
* (e.g. from a Grid). False (the default) prevents the browser menu from being shown anywhere
|
|
@@ -87,30 +105,31 @@ export declare class AppSpec<T extends HoistAppModel = HoistAppModel> {
|
|
|
87
105
|
*/
|
|
88
106
|
showBrowserContextMenu?: boolean;
|
|
89
107
|
/**
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
* have tight performance tolerances and/or load very large record sets.
|
|
93
|
-
* @see FieldConfig.disableXssProtection
|
|
108
|
+
* True (default) to write a track log statement after the app has loaded and fully
|
|
109
|
+
* initialized, including a breakdown of elapsed time throughout the init process.
|
|
94
110
|
*/
|
|
95
|
-
|
|
96
|
-
|
|
111
|
+
trackAppLoad?: boolean;
|
|
112
|
+
/** @deprecated - use {@link AppSpec.disableWebSockets} instead. */
|
|
113
|
+
webSocketsEnabled?: boolean;
|
|
114
|
+
constructor({ authModelClass, checkAccess, clientAppCode, clientAppName, componentClass, containerClass, disableWebSockets, disableXssProtection, enableLoginForm, enableLogout, idlePanel, isMobileApp, lockoutMessage, lockoutPanel, loginMessage, modelClass, showBrowserContextMenu, trackAppLoad, webSocketsEnabled }: {
|
|
115
|
+
authModelClass?: typeof HoistAuthModel;
|
|
116
|
+
checkAccess: any;
|
|
97
117
|
clientAppCode?: string;
|
|
98
118
|
clientAppName?: string;
|
|
99
|
-
modelClass: any;
|
|
100
119
|
componentClass: any;
|
|
101
120
|
containerClass: any;
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
checkAccess: any;
|
|
121
|
+
disableWebSockets?: boolean;
|
|
122
|
+
disableXssProtection?: boolean;
|
|
105
123
|
enableLoginForm?: boolean;
|
|
106
124
|
enableLogout?: boolean;
|
|
107
|
-
trackAppLoad?: boolean;
|
|
108
|
-
webSocketsEnabled?: boolean;
|
|
109
125
|
idlePanel?: any;
|
|
126
|
+
isMobileApp: any;
|
|
127
|
+
lockoutMessage?: any;
|
|
110
128
|
lockoutPanel?: any;
|
|
111
129
|
loginMessage?: any;
|
|
112
|
-
|
|
130
|
+
modelClass: any;
|
|
113
131
|
showBrowserContextMenu?: boolean;
|
|
114
|
-
|
|
132
|
+
trackAppLoad?: boolean;
|
|
133
|
+
webSocketsEnabled: any;
|
|
115
134
|
});
|
|
116
135
|
}
|
|
@@ -2,13 +2,13 @@ import { HoistModel, PlainObject } from './';
|
|
|
2
2
|
/**
|
|
3
3
|
* Base class for managing authentication lifecycle.
|
|
4
4
|
*
|
|
5
|
-
* Hoist will consult this model early in
|
|
5
|
+
* Hoist will consult this model early in the initialization sequence, prior to full Hoist
|
|
6
6
|
* initialization. This means that several core services (identity, configs, prefs) will *not* be
|
|
7
7
|
* available, but it provides the app a hook to do early service initialization or other work to
|
|
8
8
|
* support flows such as OAuth.
|
|
9
9
|
*
|
|
10
10
|
* The base implementation of this class is minimal and would be adequate only for fully
|
|
11
|
-
* transparent SSO based solutions such as NTLM.
|
|
11
|
+
* transparent SSO based solutions such as NTLM. Applications wishing to provide custom
|
|
12
12
|
* authentication should spec an extended version of this class in the {@link AppSpec} passed to
|
|
13
13
|
* {@link XHApi#renderApp}.
|
|
14
14
|
*/
|
|
@@ -24,14 +24,14 @@ import { HoistService, PlainObject } from '@xh/hoist/core';
|
|
|
24
24
|
*/
|
|
25
25
|
export declare class WebSocketService extends HoistService {
|
|
26
26
|
static instance: WebSocketService;
|
|
27
|
-
readonly HEARTBEAT_TOPIC = "xhHeartbeat";
|
|
28
27
|
/** Check connection and send a new heartbeat (which should be promptly ack'd) every 10s. */
|
|
28
|
+
readonly HEARTBEAT_TOPIC = "xhHeartbeat";
|
|
29
29
|
readonly HEARTBEAT_INTERVAL: number;
|
|
30
30
|
readonly REG_SUCCESS_TOPIC = "xhRegistrationSuccess";
|
|
31
31
|
readonly FORCE_APP_SUSPEND_TOPIC = "xhForceAppSuspend";
|
|
32
32
|
readonly REQ_CLIENT_HEALTH_RPT_TOPIC = "xhRequestClientHealthReport";
|
|
33
33
|
readonly METADATA_FOR_HANDSHAKE: string[];
|
|
34
|
-
/** True if WebSockets
|
|
34
|
+
/** True if WebSockets not explicitly disabled via {@link AppSpec.disableWebSockets}. */
|
|
35
35
|
enabled: boolean;
|
|
36
36
|
/** Unique channel assigned by server upon successful connection. */
|
|
37
37
|
channelKey: string;
|
package/core/AppSpec.ts
CHANGED
|
@@ -4,26 +4,44 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Copyright © 2025 Extremely Heavy Industries Inc.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
8
|
-
import {throwIf} from '@xh/hoist/utils/js';
|
|
9
|
-
import {isFunction, isNil, isString} from 'lodash';
|
|
7
|
+
import {ElementFactory, HoistAppModel, HoistAuthModel, HoistProps, XH} from '@xh/hoist/core';
|
|
8
|
+
import {apiDeprecated, throwIf} from '@xh/hoist/utils/js';
|
|
9
|
+
import {isFunction, isNil, isString, isUndefined} from 'lodash';
|
|
10
10
|
import {Component, ComponentClass, FunctionComponent} from 'react';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
13
|
+
* Spec for a client-side Hoist application. A config matching this class's shape is provided
|
|
14
|
+
* to {@link XHApi.renderApp} to kick-off app rendering and is available thereafter as `XH.appSpec`.
|
|
15
15
|
*/
|
|
16
16
|
export class AppSpec<T extends HoistAppModel = HoistAppModel> {
|
|
17
|
+
/**
|
|
18
|
+
* AuthModel class for the application. Note this is a reference to the class itself, not an
|
|
19
|
+
* instance, and must extend {@link HoistAuthModel}. If not provided, Hoist will fallback to
|
|
20
|
+
* the superclass implementation, but note that class would only be suitable for fully
|
|
21
|
+
* transparent SSO based solutions such as NTLM. Common patterns such as OAuth will require an
|
|
22
|
+
* extended implementation.
|
|
23
|
+
*/
|
|
24
|
+
authModelClass?: new () => HoistAuthModel;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Method for determining if user may access the app. If a string, will be interpreted as the
|
|
28
|
+
* role required for basic UI access. Return false to show a generated lockout message, or use
|
|
29
|
+
* the object form to provide a custom message.
|
|
30
|
+
*/
|
|
31
|
+
checkAccess: string | ((user: object) => boolean | {hasAccess: boolean; message: string});
|
|
32
|
+
|
|
17
33
|
/**
|
|
18
34
|
* Short code for this particular JS client application.
|
|
35
|
+
*
|
|
19
36
|
* Will default to the `appCode` specified within the project's Webpack config, but can be
|
|
20
37
|
* set to a more specific value (e.g. 'myAppMobile') to identify the client app in common
|
|
21
|
-
* code or configs.
|
|
38
|
+
* code or configs that support distinct settings for different client apps.
|
|
22
39
|
*/
|
|
23
40
|
clientAppCode?: string;
|
|
24
41
|
|
|
25
42
|
/**
|
|
26
43
|
* Display name for this particular JS client application.
|
|
44
|
+
*
|
|
27
45
|
* As with `clientAppCode` above, this will default to the global `appName` specified by
|
|
28
46
|
* the project's Webpack config, but can be set here to a more specific value (e.g.
|
|
29
47
|
* 'MyApp Mobile').
|
|
@@ -31,64 +49,58 @@ export class AppSpec<T extends HoistAppModel = HoistAppModel> {
|
|
|
31
49
|
clientAppName?: string;
|
|
32
50
|
|
|
33
51
|
/**
|
|
34
|
-
* Root
|
|
35
|
-
*
|
|
36
|
-
*/
|
|
37
|
-
modelClass: new () => T;
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* AuthModel class for the application. Note this is a reference to the class itself, not an
|
|
41
|
-
* instance, and must extend {@link HoistAuthModel}.
|
|
42
|
-
*/
|
|
43
|
-
authModelClass?: new () => HoistAuthModel;
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Root HoistComponent for the application. Despite the name, functional components are fully
|
|
47
|
-
* supported and expected.
|
|
52
|
+
* Root HoistComponent for the application.
|
|
53
|
+
* Despite the name, functional components are fully supported and expected.
|
|
48
54
|
*/
|
|
49
55
|
componentClass: ComponentClass<HoistProps> | FunctionComponent<HoistProps>;
|
|
50
56
|
|
|
51
57
|
/**
|
|
52
58
|
* Container component to be used to host this application.
|
|
53
|
-
*
|
|
59
|
+
*
|
|
60
|
+
* This class determines the platform used by Hoist - almost all apps will import and specify
|
|
54
61
|
* either `@xh/hoist/desktop/AppContainer` or `@xh/hoist/mobile/AppContainer`.
|
|
55
62
|
*/
|
|
56
63
|
containerClass: ComponentClass<HoistProps> | FunctionComponent<HoistProps>;
|
|
57
64
|
|
|
58
|
-
/** True if the app should use the Hoist mobile toolkit.*/
|
|
59
|
-
isMobileApp: boolean;
|
|
60
|
-
|
|
61
|
-
/** True to show a login form on initialization when not authenticated. (default false) */
|
|
62
|
-
enableLoginForm?: boolean;
|
|
63
|
-
|
|
64
65
|
/**
|
|
65
|
-
* True to
|
|
66
|
-
*
|
|
66
|
+
* True to disable Hoist's built-in WebSocket support for this client app. Even if the app
|
|
67
|
+
* itself is not using WebSockets for business data, the Hoist Admin Console's "Clients" tab and
|
|
68
|
+
* related functionality benefit from having them enabled, so disable only if there is a good
|
|
69
|
+
* reason to do so.
|
|
67
70
|
*/
|
|
68
|
-
|
|
71
|
+
disableWebSockets?: boolean;
|
|
69
72
|
|
|
70
73
|
/**
|
|
71
|
-
*
|
|
72
|
-
*
|
|
74
|
+
* True to disable Field-level XSS protection by default across all Stores/Fields in the app.
|
|
75
|
+
* For use with secure, internal apps that do not display arbitrary/external user input and
|
|
76
|
+
* have tight performance tolerances and/or load very large record sets.
|
|
77
|
+
* @see FieldSpec.disableXssProtection
|
|
73
78
|
*/
|
|
74
|
-
|
|
79
|
+
disableXssProtection?: boolean;
|
|
75
80
|
|
|
76
81
|
/**
|
|
77
|
-
*
|
|
78
|
-
*
|
|
82
|
+
* True to show a login form on initialization when not authenticated. Default is `false` as
|
|
83
|
+
* most Hoist applications are expected to use OAuth or SSO for authn.
|
|
79
84
|
*/
|
|
80
|
-
|
|
85
|
+
enableLoginForm?: boolean;
|
|
81
86
|
|
|
82
|
-
/**
|
|
83
|
-
|
|
87
|
+
/**
|
|
88
|
+
* True to show logout options in the app, for apps with auth schemes that can support this
|
|
89
|
+
* operation (e.g. OAuth). Default is `false` as most Hoist applications are expected to use
|
|
90
|
+
* SSO or to run in internal environments where logout is not required / typical.
|
|
91
|
+
*/
|
|
92
|
+
enableLogout?: boolean;
|
|
84
93
|
|
|
85
94
|
/**
|
|
86
|
-
* Optional custom Component to display when
|
|
87
|
-
* receive a single
|
|
95
|
+
* Optional custom Component to display when the app has been suspended. The component will
|
|
96
|
+
* receive a single `onReactivate` prop, a no-arg callback fired when the user has acknowledged
|
|
88
97
|
* the suspension and wishes to reload the app.
|
|
89
98
|
*/
|
|
90
99
|
idlePanel?: ElementFactory | FunctionComponent | Component;
|
|
91
100
|
|
|
101
|
+
/** True if the app should use the Hoist mobile toolkit.*/
|
|
102
|
+
isMobileApp: boolean;
|
|
103
|
+
|
|
92
104
|
/**
|
|
93
105
|
* Optional custom Component to display when the user is denied access to app. Intended for
|
|
94
106
|
* apps that implement custom auth flows. See also `lockoutMessage` for a more lightweight
|
|
@@ -96,12 +108,18 @@ export class AppSpec<T extends HoistAppModel = HoistAppModel> {
|
|
|
96
108
|
*/
|
|
97
109
|
lockoutPanel?: ElementFactory | FunctionComponent | Component;
|
|
98
110
|
|
|
99
|
-
/** Optional message to show on login form (see showLoginForm). */
|
|
100
|
-
loginMessage?: string;
|
|
101
|
-
|
|
102
111
|
/** Optional message to show users when denied access to app. */
|
|
103
112
|
lockoutMessage?: string;
|
|
104
113
|
|
|
114
|
+
/** Optional message to show on login form, if `showLoginForm: true`. */
|
|
115
|
+
loginMessage?: string;
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Root Model class for the application. Note this is a reference to the class itself, not an
|
|
119
|
+
* instance, and must extend {@link HoistAppModel}.
|
|
120
|
+
*/
|
|
121
|
+
modelClass: new () => T;
|
|
122
|
+
|
|
105
123
|
/**
|
|
106
124
|
* True to show the built-in browser context menu when no app-specific menu would be shown
|
|
107
125
|
* (e.g. from a Grid). False (the default) prevents the browser menu from being shown anywhere
|
|
@@ -110,67 +128,80 @@ export class AppSpec<T extends HoistAppModel = HoistAppModel> {
|
|
|
110
128
|
showBrowserContextMenu?: boolean;
|
|
111
129
|
|
|
112
130
|
/**
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
* have tight performance tolerances and/or load very large record sets.
|
|
116
|
-
* @see FieldConfig.disableXssProtection
|
|
131
|
+
* True (default) to write a track log statement after the app has loaded and fully
|
|
132
|
+
* initialized, including a breakdown of elapsed time throughout the init process.
|
|
117
133
|
*/
|
|
118
|
-
|
|
134
|
+
trackAppLoad?: boolean;
|
|
135
|
+
|
|
136
|
+
/** @deprecated - use {@link AppSpec.disableWebSockets} instead. */
|
|
137
|
+
webSocketsEnabled?: boolean;
|
|
119
138
|
|
|
120
139
|
constructor({
|
|
140
|
+
authModelClass = HoistAuthModel,
|
|
141
|
+
checkAccess,
|
|
121
142
|
clientAppCode = XH.appCode,
|
|
122
143
|
clientAppName = XH.appName,
|
|
123
|
-
modelClass,
|
|
124
144
|
componentClass,
|
|
125
145
|
containerClass,
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
checkAccess,
|
|
146
|
+
disableWebSockets = false,
|
|
147
|
+
disableXssProtection = false,
|
|
129
148
|
enableLoginForm = false,
|
|
130
149
|
enableLogout = false,
|
|
131
|
-
trackAppLoad = true,
|
|
132
|
-
webSocketsEnabled = false,
|
|
133
150
|
idlePanel = null,
|
|
151
|
+
isMobileApp,
|
|
152
|
+
lockoutMessage = null,
|
|
134
153
|
lockoutPanel = null,
|
|
135
154
|
loginMessage = null,
|
|
136
|
-
|
|
155
|
+
modelClass,
|
|
137
156
|
showBrowserContextMenu = false,
|
|
138
|
-
|
|
157
|
+
trackAppLoad = true,
|
|
158
|
+
webSocketsEnabled
|
|
139
159
|
}) {
|
|
140
|
-
throwIf(!modelClass, 'A Hoist App must define a modelClass.');
|
|
141
160
|
throwIf(!componentClass, 'A Hoist App must define a componentClass');
|
|
142
|
-
|
|
161
|
+
|
|
143
162
|
throwIf(
|
|
144
163
|
!containerClass,
|
|
145
|
-
`Please import and provide containerClass from "@xh/hoist/${
|
|
146
|
-
isMobileApp ? 'mobile' : 'desktop'
|
|
147
|
-
}/AppContainer".`
|
|
164
|
+
`Please import and provide containerClass from "@xh/hoist/${isMobileApp ? 'mobile' : 'desktop'}/AppContainer".`
|
|
148
165
|
);
|
|
149
166
|
|
|
167
|
+
throwIf(!modelClass, 'A Hoist App must define a modelClass.');
|
|
168
|
+
|
|
169
|
+
throwIf(isNil(isMobileApp), 'A Hoist App must define isMobileApp');
|
|
170
|
+
|
|
150
171
|
throwIf(
|
|
151
172
|
!isString(checkAccess) && !isFunction(checkAccess),
|
|
152
173
|
'A Hoist App must specify a required role string or a function for checkAccess.'
|
|
153
174
|
);
|
|
154
175
|
|
|
176
|
+
if (!isUndefined(webSocketsEnabled)) {
|
|
177
|
+
let msg: string;
|
|
178
|
+
if (webSocketsEnabled === false) {
|
|
179
|
+
disableWebSockets = true;
|
|
180
|
+
msg = `Specify disableWebSockets: true to continue actively disabling WebSockets if required.`;
|
|
181
|
+
} else {
|
|
182
|
+
msg = `WebSockets are now enabled by default - this property can be safely removed from your appSpec.`;
|
|
183
|
+
}
|
|
184
|
+
apiDeprecated('webSocketsEnabled', {msg, v: 'v78'});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
this.authModelClass = authModelClass;
|
|
188
|
+
this.checkAccess = checkAccess;
|
|
155
189
|
this.clientAppCode = clientAppCode;
|
|
156
190
|
this.clientAppName = clientAppName;
|
|
157
|
-
|
|
158
|
-
this.modelClass = modelClass;
|
|
159
191
|
this.componentClass = componentClass;
|
|
160
192
|
this.containerClass = containerClass;
|
|
161
|
-
this.
|
|
162
|
-
this.
|
|
163
|
-
this.
|
|
164
|
-
|
|
165
|
-
this.trackAppLoad = trackAppLoad;
|
|
166
|
-
this.webSocketsEnabled = webSocketsEnabled;
|
|
193
|
+
this.disableWebSockets = disableWebSockets;
|
|
194
|
+
this.disableXssProtection = disableXssProtection;
|
|
195
|
+
this.enableLoginForm = enableLoginForm;
|
|
196
|
+
this.enableLogout = enableLogout;
|
|
167
197
|
this.idlePanel = idlePanel;
|
|
198
|
+
this.isMobileApp = isMobileApp;
|
|
199
|
+
this.lockoutMessage = lockoutMessage;
|
|
168
200
|
this.lockoutPanel = lockoutPanel;
|
|
169
|
-
this.enableLogout = enableLogout;
|
|
170
|
-
this.enableLoginForm = enableLoginForm;
|
|
171
201
|
this.loginMessage = loginMessage;
|
|
172
|
-
this.
|
|
202
|
+
this.modelClass = modelClass;
|
|
173
203
|
this.showBrowserContextMenu = showBrowserContextMenu;
|
|
174
|
-
this.
|
|
204
|
+
this.trackAppLoad = trackAppLoad;
|
|
205
|
+
this.webSocketsEnabled = !disableWebSockets;
|
|
175
206
|
}
|
|
176
207
|
}
|
package/core/HoistAuthModel.ts
CHANGED
|
@@ -9,13 +9,13 @@ import {HoistModel, PlainObject, XH} from './';
|
|
|
9
9
|
/**
|
|
10
10
|
* Base class for managing authentication lifecycle.
|
|
11
11
|
*
|
|
12
|
-
* Hoist will consult this model early in
|
|
12
|
+
* Hoist will consult this model early in the initialization sequence, prior to full Hoist
|
|
13
13
|
* initialization. This means that several core services (identity, configs, prefs) will *not* be
|
|
14
14
|
* available, but it provides the app a hook to do early service initialization or other work to
|
|
15
15
|
* support flows such as OAuth.
|
|
16
16
|
*
|
|
17
17
|
* The base implementation of this class is minimal and would be adequate only for fully
|
|
18
|
-
* transparent SSO based solutions such as NTLM.
|
|
18
|
+
* transparent SSO based solutions such as NTLM. Applications wishing to provide custom
|
|
19
19
|
* authentication should spec an extended version of this class in the {@link AppSpec} passed to
|
|
20
20
|
* {@link XHApi#renderApp}.
|
|
21
21
|
*/
|
package/core/XH.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xh/hoist",
|
|
3
|
-
"version": "75.0.0-SNAPSHOT.
|
|
3
|
+
"version": "75.0.0-SNAPSHOT.1753726213836",
|
|
4
4
|
"description": "Hoist add-on for building and deploying React Applications.",
|
|
5
5
|
"repository": "github:xh/hoist-react",
|
|
6
6
|
"homepage": "https://xh.io",
|
package/svc/WebSocketService.ts
CHANGED
|
@@ -38,8 +38,8 @@ import {find, pull} from 'lodash';
|
|
|
38
38
|
export class WebSocketService extends HoistService {
|
|
39
39
|
static instance: WebSocketService;
|
|
40
40
|
|
|
41
|
-
readonly HEARTBEAT_TOPIC = 'xhHeartbeat';
|
|
42
41
|
/** Check connection and send a new heartbeat (which should be promptly ack'd) every 10s. */
|
|
42
|
+
readonly HEARTBEAT_TOPIC = 'xhHeartbeat';
|
|
43
43
|
readonly HEARTBEAT_INTERVAL = 10 * SECONDS;
|
|
44
44
|
|
|
45
45
|
readonly REG_SUCCESS_TOPIC = 'xhRegistrationSuccess';
|
|
@@ -47,8 +47,8 @@ export class WebSocketService extends HoistService {
|
|
|
47
47
|
readonly REQ_CLIENT_HEALTH_RPT_TOPIC = 'xhRequestClientHealthReport';
|
|
48
48
|
readonly METADATA_FOR_HANDSHAKE = ['appVersion', 'appBuild', 'loadId', 'tabId'];
|
|
49
49
|
|
|
50
|
-
/** True if WebSockets
|
|
51
|
-
enabled: boolean = XH.appSpec.
|
|
50
|
+
/** True if WebSockets not explicitly disabled via {@link AppSpec.disableWebSockets}. */
|
|
51
|
+
enabled: boolean = !XH.appSpec.disableWebSockets;
|
|
52
52
|
|
|
53
53
|
/** Unique channel assigned by server upon successful connection. */
|
|
54
54
|
@observable channelKey: string = null;
|
|
@@ -84,7 +84,7 @@ export class WebSocketService extends HoistService {
|
|
|
84
84
|
const {environmentService} = XH;
|
|
85
85
|
if (environmentService.get('webSocketsEnabled') === false) {
|
|
86
86
|
this.logError(
|
|
87
|
-
`WebSockets enabled on this client app but disabled on server
|
|
87
|
+
`WebSockets enabled on this client app but disabled on server - unexpected! WebSockets will not be available, review and reconcile your server configuration.`
|
|
88
88
|
);
|
|
89
89
|
this.enabled = false;
|
|
90
90
|
return;
|