@equinor/fusion-framework-vite-plugin-spa 3.1.6 → 3.1.8

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
@@ -1,5 +1,19 @@
1
1
  # @equinor/fusion-framework-vite-plugin-spa
2
2
 
3
+ ## 3.1.8
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [[`1594ed8`](https://github.com/equinor/fusion-framework/commit/1594ed879579d0db6e42c5052a33174f7bf9346c), [`1594ed8`](https://github.com/equinor/fusion-framework/commit/1594ed879579d0db6e42c5052a33174f7bf9346c)]:
8
+ - @equinor/fusion-framework-module-msal@7.2.1
9
+
10
+ ## 3.1.7
11
+
12
+ ### Patch Changes
13
+
14
+ - Updated dependencies [[`dcf51aa`](https://github.com/equinor/fusion-framework/commit/dcf51aa87ac79200893ec4909632554464e75055)]:
15
+ - @equinor/fusion-framework-module-msal@7.2.0
16
+
3
17
  ## 3.1.6
4
18
 
5
19
  ### Patch Changes
@@ -1,3 +1,3 @@
1
1
  // Generated by genversion.
2
- export const version = '3.1.6';
2
+ export const version = '3.1.8';
3
3
  //# sourceMappingURL=version.js.map
@@ -40463,7 +40463,7 @@ const createClientLogCallback = (provider, metadata, scope) => {
40463
40463
  };
40464
40464
 
40465
40465
  // Generated by genversion.
40466
- const version$2 = '7.1.0';
40466
+ const version$2 = '7.2.1';
40467
40467
 
40468
40468
  /**
40469
40469
  * Zod schema for telemetry configuration validation.
@@ -40488,6 +40488,7 @@ const MsalConfigSchema = z.object({
40488
40488
  provider: z.custom().optional(),
40489
40489
  requiresAuth: z.boolean().optional(),
40490
40490
  redirectUri: z.string().optional(),
40491
+ loginHint: z.string().optional(),
40491
40492
  authCode: z.string().optional(),
40492
40493
  version: z.string().transform((x) => String(semver.coerce(x))),
40493
40494
  telemetry: TelemetryConfigSchema,
@@ -40610,6 +40611,24 @@ class MsalConfigurator extends BaseConfigBuilder {
40610
40611
  this._set('requiresAuth', async () => requiresAuth);
40611
40612
  return this;
40612
40613
  }
40614
+ /**
40615
+ * Sets a default login hint for authentication flows.
40616
+ *
40617
+ * The login hint is used to pre-fill the username during authentication and
40618
+ * enables silent SSO when no account is available.
40619
+ *
40620
+ * @param loginHint - The preferred username/email to use as login hint
40621
+ * @returns The configurator instance for method chaining
40622
+ *
40623
+ * @example
40624
+ * ```typescript
40625
+ * configurator.setLoginHint('user@company.com');
40626
+ * ```
40627
+ */
40628
+ setLoginHint(loginHint) {
40629
+ this._set('loginHint', async () => loginHint);
40630
+ return this;
40631
+ }
40613
40632
  /**
40614
40633
  * @deprecated - since version 5.1.0, use setClient instead
40615
40634
  */
@@ -41474,6 +41493,16 @@ class MsalProvider extends BaseModuleProvider {
41474
41493
  #telemetry;
41475
41494
  #requiresAuth;
41476
41495
  #authCode;
41496
+ #loginHint;
41497
+ /**
41498
+ * Default OAuth scopes used when the caller provides no scopes.
41499
+ *
41500
+ * Resolves to the app's Entra ID configured permissions via the `/.default` scope.
41501
+ */
41502
+ get defaultScopes() {
41503
+ const clientId = this.#client.clientId;
41504
+ return clientId ? [`${clientId}/.default`] : [];
41505
+ }
41477
41506
  /**
41478
41507
  * The MSAL module version enum value indicating the API compatibility level.
41479
41508
  *
@@ -41531,6 +41560,7 @@ class MsalProvider extends BaseModuleProvider {
41531
41560
  });
41532
41561
  this.#requiresAuth = config.requiresAuth;
41533
41562
  this.#telemetry = config.telemetry;
41563
+ this.#loginHint = config.loginHint;
41534
41564
  // Extract auth code from config if present
41535
41565
  // This will be used during initialize to exchange for tokens
41536
41566
  this.#authCode = config.authCode;
@@ -41631,9 +41661,9 @@ class MsalProvider extends BaseModuleProvider {
41631
41661
  else if (!this.#client.hasValidClaims) {
41632
41662
  // Priority 2: No valid session found - attempt automatic login
41633
41663
  // This handles first-time app load when no authentication state exists
41634
- // Note: Using empty scopes here as we don't know what scopes the app needs yet
41664
+ // Note: Using default scopes here as we don't know what scopes the app needs yet
41635
41665
  // App should call acquireToken with actual scopes after initialization
41636
- const loginResult = await this.login({ request: { scopes: [] } });
41666
+ const loginResult = await this.login({ request: { scopes: this.defaultScopes } });
41637
41667
  if (loginResult?.account) {
41638
41668
  // Automatic login successful - set as active account
41639
41669
  this.#client.setActiveAccount(loginResult.account);
@@ -41699,37 +41729,52 @@ class MsalProvider extends BaseModuleProvider {
41699
41729
  * ```
41700
41730
  */
41701
41731
  async acquireToken(options) {
41702
- const { behavior = 'redirect', silent = true, request = {}, } = options;
41703
- const account = request.account ?? this.account ?? undefined;
41704
- // Extract scopes from either new format (request.scopes) or legacy format (scopes)
41705
- const scopes = options.request?.scopes ?? options?.scopes ?? [];
41732
+ // Determine behavior and silent options, with defaults (redirect and true respectively)
41733
+ const behavior = options?.behavior ?? 'redirect';
41734
+ // Silent mode defaults to true, meaning the provider will attempt silent token acquisition first
41735
+ const silent = options?.silent ?? true;
41736
+ const defaultScopes = this.defaultScopes;
41737
+ const inputRequest = options?.request;
41738
+ // Determine the account to use for token acquisition, prioritizing request-specific account, then active account
41739
+ const account = inputRequest?.account ?? this.account ?? undefined;
41740
+ // Extract caller-provided scopes from either new format (request.scopes) or legacy format (scopes)
41741
+ const candidateScopes = inputRequest?.scopes ?? options?.scopes ?? [];
41742
+ const scopes = candidateScopes.length > 0 ? candidateScopes : defaultScopes.length > 0 ? defaultScopes : [];
41743
+ // Prepare telemetry properties for this token acquisition attempt
41706
41744
  const telemetryProperties = { behavior, silent, scopes };
41707
41745
  // Track usage of deprecated legacy scopes format for migration monitoring
41708
- if (options.scopes) {
41746
+ if (options?.scopes) {
41709
41747
  this._trackEvent('acquireToken.legacy-scopes-provided', TelemetryLevel.Warning, {
41710
41748
  properties: telemetryProperties,
41711
41749
  });
41712
41750
  }
41713
41751
  // Handle empty scopes - currently monitoring for telemetry, will throw in future
41714
- if (scopes.length === 0) {
41715
- const exception = new Error('Empty scopes provided, not allowed');
41716
- this._trackException('acquireToken.missing-scope', TelemetryLevel.Warning, {
41717
- exception,
41718
- properties: telemetryProperties,
41719
- });
41720
- // TODO: throw exception when sufficient metrics are collected
41721
- // This allows us to monitor how often empty scopes are provided before enforcing validation
41752
+ if (candidateScopes.length === 0) {
41753
+ if (defaultScopes.length > 0) {
41754
+ this._trackEvent('acquireToken.missing-scope.defaulted', TelemetryLevel.Warning, {
41755
+ properties: { ...telemetryProperties, defaultScopes },
41756
+ });
41757
+ }
41758
+ else {
41759
+ const exception = new Error('Empty scopes provided and clientId is missing for default scope');
41760
+ this._trackException('acquireToken.missing-scope', TelemetryLevel.Warning, {
41761
+ exception,
41762
+ properties: telemetryProperties,
41763
+ });
41764
+ // TODO: throw exception when sufficient metrics are collected
41765
+ // This allows us to monitor how often empty scopes are provided before enforcing validation
41766
+ }
41722
41767
  }
41723
41768
  try {
41724
41769
  const measurement = this._trackMeasurement('acquireToken', TelemetryLevel.Information, {
41725
41770
  properties: telemetryProperties,
41726
41771
  });
41727
- // Merge account, original request options, and resolved scopes
41728
- // Account ensures context awareness, request preserves custom options, scopes uses resolved value
41772
+ // Merge account, original request options, and resolved scopes.
41773
+ // Account ensures context awareness, request preserves custom options, scopes uses resolved value.
41729
41774
  const result = await this.#client.acquireToken({
41730
41775
  behavior,
41731
41776
  silent,
41732
- request: { ...options.request, account, scopes },
41777
+ request: { ...inputRequest, account, scopes },
41733
41778
  });
41734
41779
  measurement?.measure();
41735
41780
  return result;
@@ -41791,6 +41836,13 @@ class MsalProvider extends BaseModuleProvider {
41791
41836
  */
41792
41837
  async login(options) {
41793
41838
  const { behavior = 'redirect', silent = true, request } = options;
41839
+ request.loginHint ??=
41840
+ this.#loginHint ?? this.account?.username ?? this.account?.loginHint ?? undefined;
41841
+ const defaultScopes = this.defaultScopes;
41842
+ // Fallback to app default scope when possible; empty scopes tracked for monitoring
41843
+ if (!request.scopes || request.scopes.length === 0) {
41844
+ request.scopes = defaultScopes.length > 0 ? defaultScopes : [];
41845
+ }
41794
41846
  // Determine if silent login is possible based on available account/hint information
41795
41847
  // Silent login requires either an account object or a loginHint to work
41796
41848
  const canLoginSilently = silent && (request.account || request.loginHint);
@@ -41798,10 +41850,9 @@ class MsalProvider extends BaseModuleProvider {
41798
41850
  // Default to active account if no account/hint provided in request
41799
41851
  // This allows silent login to work automatically with existing authentication state
41800
41852
  request.account ??= this.account ?? undefined;
41801
- // Default to empty scopes if none provided
41802
- // Empty scopes are tracked for monitoring but allowed for compatibility
41803
- if (!request.scopes) {
41804
- request.scopes = [];
41853
+ // If scopes are still empty here, we couldn't derive a default scope (e.g. missing clientId).
41854
+ // Track for monitoring; behavior will be enforced once we have sufficient metrics.
41855
+ if (request.scopes.length === 0) {
41805
41856
  this._trackEvent('login.missing-scope', TelemetryLevel.Warning, {
41806
41857
  properties: telemetryProperties,
41807
41858
  });
@@ -44905,7 +44956,7 @@ async function registerServiceWorker(framework) {
44905
44956
  }
44906
44957
 
44907
44958
  // Generated by genversion.
44908
- const version = '3.1.6';
44959
+ const version = '3.1.8';
44909
44960
 
44910
44961
  // Allow dynamic import without vite
44911
44962
  const importWithoutVite = (path) => import(/* @vite-ignore */ path);