@equinor/fusion-framework-module-msal 7.0.0-next.0 → 7.0.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@equinor/fusion-framework-module-msal",
3
- "version": "7.0.0-next.0",
3
+ "version": "7.0.0",
4
4
  "description": "Microsoft Authentication Library (MSAL) integration module for Fusion Framework",
5
5
  "main": "dist/esm/index.js",
6
6
  "types": "dist/types/index.d.ts",
@@ -12,6 +12,10 @@
12
12
  "./v2": {
13
13
  "import": "./dist/esm/v2/index.js",
14
14
  "types": "./dist/types/v2/index.d.ts"
15
+ },
16
+ "./v4": {
17
+ "import": "./dist/esm/v4/index.js",
18
+ "types": "./dist/types/v4/index.d.ts"
15
19
  }
16
20
  },
17
21
  "typesVersions": {
@@ -21,6 +25,9 @@
21
25
  ],
22
26
  "v2": [
23
27
  "dist/types/v2/index.d.ts"
28
+ ],
29
+ "v4": [
30
+ "dist/types/v4/index.d.ts"
24
31
  ]
25
32
  }
26
33
  },
@@ -36,23 +43,23 @@
36
43
  "directory": "packages/modules/msal"
37
44
  },
38
45
  "dependencies": {
39
- "@azure/msal-browser": "^2.21.0"
46
+ "@azure/msal-browser": "^5.0.2"
40
47
  },
41
48
  "devDependencies": {
42
49
  "@types/semver": "^7.5.0",
43
50
  "semver": "^7.5.4",
44
51
  "typescript": "^5.8.2",
45
52
  "zod": "^4.1.8",
46
- "@equinor/fusion-framework-module": "^5.0.6-next.0",
47
- "@equinor/fusion-framework-module-telemetry": "^5.0.0-next.0"
53
+ "@equinor/fusion-framework-module-telemetry": "^4.6.1",
54
+ "@equinor/fusion-framework-module": "^5.0.5"
48
55
  },
49
56
  "peerDependencies": {
50
57
  "@types/semver": "^7.5.0",
51
58
  "semver": "^7.5.4",
52
59
  "typescript": "^5.8.2",
53
60
  "zod": "^4.1.8",
54
- "@equinor/fusion-framework-module": "^5.0.6-next.0",
55
- "@equinor/fusion-framework-module-telemetry": "^5.0.0-next.0"
61
+ "@equinor/fusion-framework-module": "^5.0.5",
62
+ "@equinor/fusion-framework-module-telemetry": "^4.6.1"
56
63
  },
57
64
  "peerDependenciesMeta": {
58
65
  "@equinor/fusion-framework-module-telemetry": {
package/src/MsalClient.ts CHANGED
@@ -18,6 +18,12 @@ import type {
18
18
 
19
19
  export type { IMsalClient };
20
20
 
21
+ /**
22
+ * Fallback correlation ID for logger calls when request doesn't provide one.
23
+ * Empty string indicates a non-request-specific log (validation, configuration warnings).
24
+ */
25
+ const FUSION_CORRELATION_ID = '';
26
+
21
27
  /**
22
28
  * MSAL client configuration extending the standard MSAL Configuration.
23
29
  *
@@ -127,13 +133,17 @@ export class MsalClient extends PublicClientApplication implements IMsalClient {
127
133
  if (!options.request.account && !options.request.loginHint) {
128
134
  this.getLogger().warning(
129
135
  'No account or login hint provided, please provide an account or login hint in the request',
136
+ options.request.correlationId || FUSION_CORRELATION_ID,
130
137
  );
131
138
  }
132
139
  try {
133
140
  return await this.ssoSilent(options.request as SilentRequest);
134
141
  } catch {
135
142
  // Silent login failed - continue to interactive flow
136
- this.getLogger().warning('Silent login failed, falling back to interactive');
143
+ this.getLogger().warning(
144
+ 'Silent login failed, falling back to interactive',
145
+ options.request.correlationId || FUSION_CORRELATION_ID,
146
+ );
137
147
  }
138
148
  }
139
149
 
@@ -189,6 +199,7 @@ export class MsalClient extends PublicClientApplication implements IMsalClient {
189
199
  if (!options?.account) {
190
200
  this.getLogger().warning(
191
201
  'No account available for logout, please provide an account in the options',
202
+ FUSION_CORRELATION_ID,
192
203
  );
193
204
  }
194
205
 
@@ -233,6 +244,7 @@ export class MsalClient extends PublicClientApplication implements IMsalClient {
233
244
  if (request.scopes.length === 0) {
234
245
  this.getLogger().warning(
235
246
  'No scopes provided, please provide scopes in the request option, see options.request for more information.',
247
+ request.correlationId || FUSION_CORRELATION_ID,
236
248
  );
237
249
  }
238
250
 
@@ -241,15 +253,22 @@ export class MsalClient extends PublicClientApplication implements IMsalClient {
241
253
  if (silent) {
242
254
  if (request.account) {
243
255
  try {
244
- this.getLogger().verbose('Attempting to acquire token silently');
256
+ this.getLogger().verbose(
257
+ 'Attempting to acquire token silently',
258
+ request.correlationId || FUSION_CORRELATION_ID,
259
+ );
245
260
  return await this.acquireTokenSilent(request as SilentRequest);
246
261
  } catch {
247
262
  // Silent acquisition failed - fall back to interactive
248
- this.getLogger().warning('Silent token acquisition failed, falling back to interactive');
263
+ this.getLogger().warning(
264
+ 'Silent token acquisition failed, falling back to interactive',
265
+ request.correlationId || FUSION_CORRELATION_ID,
266
+ );
249
267
  }
250
268
  } else {
251
269
  this.getLogger().warning(
252
270
  'Cannot acquire token silently, no account provided, falling back to interactive.',
271
+ request.correlationId || FUSION_CORRELATION_ID,
253
272
  );
254
273
  }
255
274
  }
@@ -15,6 +15,7 @@ import type { IMsalProvider as IMsalProvider_v2 } from './v2/MsalProvider.interf
15
15
  type ProxyProviderMap = {
16
16
  [MsalModuleVersion.V2]: IMsalProvider_v2;
17
17
  [MsalModuleVersion.V4]: IMsalProvider;
18
+ [MsalModuleVersion.V5]: IMsalProvider;
18
19
  };
19
20
 
20
21
  /**
@@ -2,6 +2,7 @@ import type { IMsalProvider } from './MsalProvider.interface';
2
2
  import { MsalModuleVersion } from './static';
3
3
  import { resolveVersion } from './versioning/resolve-version';
4
4
  import { createProxyProvider as createProxyProvider_v2 } from './v2/create-proxy-provider';
5
+ import { createProxyProvider as createProxyProvider_v4 } from './v4/create-proxy-provider';
5
6
 
6
7
  /**
7
8
  * Creates a proxy provider for version compatibility.
@@ -32,8 +33,10 @@ export function createProxyProvider<T = IMsalProvider>(
32
33
  // Create v2-compatible proxy with legacy API adapters
33
34
  return createProxyProvider_v2(provider) as T;
34
35
  case MsalModuleVersion.V4:
35
- // Create transparent proxy for v4 - passes through to original provider
36
- // This allows v4 code to be used where any version is expected
36
+ // Create v4-compatible proxy (passthrough with v4 version metadata)
37
+ return createProxyProvider_v4(provider) as T;
38
+ case MsalModuleVersion.V5:
39
+ // Create transparent proxy for v5 - passes through to original provider
37
40
  return new Proxy(provider, {
38
41
  get: (target: IMsalProvider, prop: keyof IMsalProvider) => {
39
42
  switch (prop) {
package/src/static.ts CHANGED
@@ -9,20 +9,19 @@ export const ModuleName = 'msal' as const;
9
9
  * Enumeration of supported MSAL module versions.
10
10
  *
11
11
  * This enum defines the available MSAL versions and provides type-safe access to version identifiers.
12
- * The `Latest` value is automatically set to the current module version at build time.
13
12
  *
14
13
  * @remarks
15
14
  * - `V2`: MSAL v2 compatibility (legacy support)
16
- * - `V4`: MSAL v4 (current major version)
17
- * - `Latest`: Always points to the current module version (5.1.0)
15
+ * - `V4`: MSAL v4 compatibility (supports @azure/msal-browser 4.x)
16
+ * - `V5`: MSAL v5 compatibility (supports @azure/msal-browser 5.x)
18
17
  *
19
18
  * @example
20
19
  * ```typescript
21
20
  * import { MsalModuleVersion } from '@equinor/fusion-framework-module-msal';
22
21
  *
23
22
  * // Check version
24
- * if (version === MsalModuleVersion.Latest) {
25
- * console.log('Using latest MSAL version');
23
+ * if (version === MsalModuleVersion.V5) {
24
+ * console.log('Using MSAL v5 compatible version');
26
25
  * }
27
26
  *
28
27
  * // Create version-specific proxy
@@ -30,8 +29,10 @@ export const ModuleName = 'msal' as const;
30
29
  * ```
31
30
  */
32
31
  export enum MsalModuleVersion {
33
- /** MSAL v2 compatibility version */
32
+ /** MSAL v2 compatibility version (legacy support) */
34
33
  V2 = 'v2',
35
- /** MSAL v4 (current major version) */
34
+ /** MSAL v4 compatibility version (supports @azure/msal-browser 4.x) */
36
35
  V4 = 'v4',
36
+ /** MSAL v5 compatibility version (supports @azure/msal-browser 5.x) */
37
+ V5 = 'v5',
37
38
  }
@@ -0,0 +1,74 @@
1
+ import type { IMsalProvider } from '../MsalProvider.interface';
2
+ import { MsalModuleVersion } from '../static';
3
+
4
+ /**
5
+ * Creates a v4-compatible proxy provider.
6
+ *
7
+ * Since v4 and v5 are API compatible, this creates a simple passthrough proxy
8
+ * that only adjusts the msalVersion property to report V4 compatibility.
9
+ *
10
+ * @param provider - The base MSAL v5 provider instance to wrap
11
+ * @returns A proxy provider reporting v4 compatibility
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * const baseProvider = new MsalProvider(config);
16
+ * const v4Proxy = createProxyProvider(baseProvider);
17
+ *
18
+ * // Use with v4-compatible API (same as v5)
19
+ * await v4Proxy.login({ request: { scopes: ['User.Read'] } });
20
+ * ```
21
+ */
22
+ export function createProxyProvider(provider: IMsalProvider): IMsalProvider {
23
+ // Create passthrough proxy that only overrides msalVersion
24
+ return new Proxy(provider, {
25
+ get: (target: IMsalProvider, prop: keyof IMsalProvider) => {
26
+ switch (prop) {
27
+ case 'msalVersion': {
28
+ // Report as V4 for compatibility tracking
29
+ return MsalModuleVersion.V4;
30
+ }
31
+ case 'version': {
32
+ return target.version;
33
+ }
34
+ case 'client': {
35
+ return target.client;
36
+ }
37
+ case 'account': {
38
+ return target.account;
39
+ }
40
+ case 'acquireAccessToken': {
41
+ return target.acquireAccessToken.bind(target);
42
+ }
43
+ case 'acquireToken': {
44
+ return target.acquireToken.bind(target);
45
+ }
46
+ case 'login': {
47
+ return target.login.bind(target);
48
+ }
49
+ case 'logout': {
50
+ return target.logout.bind(target);
51
+ }
52
+ case 'handleRedirect': {
53
+ return target.handleRedirect.bind(target);
54
+ }
55
+ case 'createProxyProvider': {
56
+ return target.createProxyProvider.bind(target);
57
+ }
58
+ case 'initialize': {
59
+ return () => {
60
+ // noop - initialize is handled by the provider, not the proxy
61
+ };
62
+ }
63
+ default: {
64
+ // Prevent 'then' from being called - this is not an async operation
65
+ if (prop === 'then') return undefined;
66
+
67
+ // Exhaustive check: TypeScript-only guard to ensure all IMsalProvider keys are handled
68
+ const exhausted: never = prop;
69
+ return (target as IMsalProvider)[exhausted];
70
+ }
71
+ }
72
+ },
73
+ }) as IMsalProvider;
74
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * MSAL v4 compatibility layer for v5 implementation.
3
+ *
4
+ * @remarks
5
+ * This module provides v4-compatible proxies when running on v5.
6
+ * Since v4 and v5 are API compatible, this is primarily a passthrough
7
+ * with version metadata adjustments.
8
+ *
9
+ * @module v4
10
+ */
11
+
12
+ export { createProxyProvider } from './create-proxy-provider';
13
+ export type * from './types';