@xh/hoist 79.0.0-SNAPSHOT.1766260837143 → 79.0.0-SNAPSHOT.1766500045639

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 CHANGED
@@ -43,6 +43,8 @@
43
43
  * `GroupingChooserProps.popoverTitle` - use `editorTitle`
44
44
  * `RelativeTimestampProps.options` - provide directly as top-level props
45
45
 
46
+ * Improved the efficiency and logging of MsalClient.
47
+ *
46
48
  ## 78.1.4 - 2025-12-05
47
49
 
48
50
  ### 🐞 Bug Fixes
@@ -197,7 +197,7 @@ export class AppContainerModel extends HoistModel {
197
197
 
198
198
  // Check auth, locking out, or showing login if possible
199
199
  this.setAppState('AUTHENTICATING');
200
- XH.authModel = createSingleton(this.appSpec.authModelClass);
200
+ XH.authModel = createSingleton(appSpec.authModelClass);
201
201
  const isAuthenticated = await XH.authModel.completeAuthAsync();
202
202
  if (!isAuthenticated) {
203
203
  throwIf(
@@ -28,8 +28,8 @@ export class AppStateModel extends HoistModel {
28
28
  * Read from timestamp set on window within index.html.
29
29
  */
30
30
  readonly loadStarted: number = window['_xhLoadTimestamp'];
31
+ readonly timings: Record<AppState, number> = {} as Record<AppState, number>;
31
32
 
32
- private timings: Record<AppState, number> = {} as Record<AppState, number>;
33
33
  private lastStateChangeTime: number = this.loadStarted;
34
34
 
35
35
  constructor() {
@@ -85,7 +85,7 @@ export class AppStateModel extends HoistModel {
85
85
  const {timings, loadStarted} = this;
86
86
  this.addReaction({
87
87
  when: () => this.state === 'RUNNING',
88
- run: () =>
88
+ run: () => {
89
89
  XH.track({
90
90
  category: 'App',
91
91
  message: `Loaded ${XH.clientAppCode}`,
@@ -98,7 +98,9 @@ export class AppStateModel extends HoistModel {
98
98
  screen: this.getScreenData()
99
99
  },
100
100
  omit: !XH.appSpec.trackAppLoad
101
- })
101
+ });
102
+ this.logDebug('Load timings', this.timings);
103
+ }
102
104
  });
103
105
  }
104
106
 
@@ -15,7 +15,7 @@ export declare class AppStateModel extends HoistModel {
15
15
  * Read from timestamp set on window within index.html.
16
16
  */
17
17
  readonly loadStarted: number;
18
- private timings;
18
+ readonly timings: Record<AppState, number>;
19
19
  private lastStateChangeTime;
20
20
  constructor();
21
21
  setAppState(nextState: AppState): void;
@@ -31,7 +31,9 @@ export function installHighcharts(HighchartsImpl) {
31
31
  timezone: undefined
32
32
  },
33
33
  lang: {
34
- thousandsSep: ','
34
+ thousandsSep: ',',
35
+ // Repace default SI abbrev "G" (giga) with "b" for billions and lowercase "m" + "t"
36
+ numericSymbols: ['k', 'm', 'b', 't']
35
37
  }
36
38
  });
37
39
  Highcharts = HighchartsImpl;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xh/hoist",
3
- "version": "79.0.0-SNAPSHOT.1766260837143",
3
+ "version": "79.0.0-SNAPSHOT.1766500045639",
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",
@@ -170,17 +170,19 @@ export class MsalClient extends BaseOAuthClient<MsalClientConfig, MsalTokenSpec>
170
170
  const account =
171
171
  accounts.length == 1
172
172
  ? accounts[0]
173
- : accounts.find(a => (a.username = this.getSelectedUsername()));
173
+ : accounts.find(a => a.username == this.getSelectedUsername());
174
+ let trySsoSilent = enableSsoSilent;
174
175
  if (account) {
175
176
  this.setAccount(account);
176
177
  try {
177
- this.initialTokenLoad = true;
178
178
  this.logDebug('Attempting silent token load.');
179
+ this.initialTokenLoad = true;
179
180
  const ret = await this.fetchAllTokensAsync({eagerOnly: true});
180
181
  this.noteAuthComplete('acquireSilent');
181
182
  return ret;
182
183
  } catch (e) {
183
- this.logDebug('Failed to load tokens on init, fall back to login', e.message ?? e);
184
+ if (e instanceof InteractionRequiredAuthError) trySsoSilent = false;
185
+ this.logDebug('AcquireSilent failed', e.message ?? e);
184
186
  } finally {
185
187
  this.initialTokenLoad = false;
186
188
  }
@@ -189,15 +191,18 @@ export class MsalClient extends BaseOAuthClient<MsalClientConfig, MsalTokenSpec>
189
191
  // 2) Try `ssoSilent` API to potentially reuse logged-in user on other apps
190
192
  // in same domain without interaction. This should never trigger popup/redirect, and will
191
193
  // use an iFrame (3rd party cookies required). Must fail gently.
192
- if (enableSsoSilent) {
194
+ if (trySsoSilent) {
193
195
  try {
194
196
  this.logDebug('Attempting SSO');
195
197
  await this.loginSsoAsync();
198
+ this.initialTokenLoad = true;
196
199
  const ret = await this.fetchAllTokensAsync({eagerOnly: true});
197
200
  this.noteAuthComplete('ssoSilent');
198
201
  return ret;
199
202
  } catch (e) {
200
203
  this.logDebug('SSO failed', e.message ?? e);
204
+ } finally {
205
+ this.initialTokenLoad = false;
201
206
  }
202
207
  }
203
208
 
@@ -453,7 +458,7 @@ export class MsalClient extends BaseOAuthClient<MsalClientConfig, MsalTokenSpec>
453
458
 
454
459
  private noteAuthComplete(authMethod: AuthMethod) {
455
460
  if (this.telemetry) this.telemetry.authMethod = authMethod;
456
- this.logInfo(`Authenticated user ${this.account.username} via ${authMethod}`);
461
+ this.logInfo(`Authenticated user '${this.account.username}' via ${authMethod}`);
457
462
  }
458
463
 
459
464
  private authRequestCore(): AuthRequestCore {