@equinor/fusion-framework-module-msal 11.0.0-next.1 → 11.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/CHANGELOG.md CHANGED
@@ -1,179 +1,114 @@
1
1
  # Change Log
2
2
 
3
- ## 11.0.0-next.1
3
+ ## 11.0.0
4
4
 
5
5
  ### Minor Changes
6
6
 
7
- - 53d5e4c: `MsalMockConfigurator` gains a `setToken(token, skipResolve?)` method. When set, `MsalMockClient`
8
- returns that exact access/id token instead of generating one from the account's claims — useful
9
- when a backend mock validates the token itself (specific claims, audience, or signature) and
10
- needs to see the token it expects rather than a mock-shaped substitute. By default, `setToken`
11
- also signs in the account derived from the token's own claims (`name`, `preferred_username`,
12
- `oid`, `tid`, `scp`) via the new `createMockUserFromToken` helper — pass `skipResolve: true` to
13
- keep a separately declared account while still returning this token.
14
-
15
- ## 11.0.0-next.0
16
-
17
- ### Minor Changes
18
-
19
- - 2836e0b: Move the MSAL configuration schema into `MsalConfig.schema.ts` and add `MsalConfigExtension`, an extension point for variants of this module.
20
-
7
+ - f663b46: Move the MSAL configuration schema into `MsalConfig.schema.ts` and add `MsalConfigExtension`, an extension point for variants of this module.
8
+
21
9
  `MsalConfig` is now the schema's inferred type intersected with `MsalConfigExtension`, an empty interface a variant merges its own configuration into:
22
-
10
+
23
11
  ```typescript
24
- declare module "@equinor/fusion-framework-module-msal" {
12
+ declare module '@equinor/fusion-framework-module-msal' {
25
13
  interface MsalConfigExtension {
26
14
  mock?: { account?: MsalMockUser };
27
15
  }
28
16
  }
29
17
  ```
30
-
18
+
31
19
  `BaseConfigBuilder._set` derives its target from `MsalConfig`, so before this a key the type did not know about could only be set by casting past the builder. Making the configurator generic over its configuration cannot solve that: a dot-path union over an unresolved type parameter defers, which takes every existing literal path down with it.
32
-
20
+
33
21
  The schema is unchanged and still describes exactly what reaches `MsalProvider` — it strips anything merged in, so an extension carries a declaration across the builder and stops there. `MsalConfigSchema`, `TelemetryConfigSchema` and their types are re-exported from `MsalConfigurator` as before.
34
-
35
- - 2836e0b: Extract client construction from `MsalConfigurator._processConfig` into overridable seams.
36
-
37
- `_processConfig` now only decides _whether_ a client is needed; `protected _createClient(config, init)` decides _what_ to build, and `protected _createClientConfig(config)` resolves the `MsalClientConfig` it is built from — authority derived from the tenant, cache location, telemetry-backed logging and cache lookup policy included.
38
-
22
+ - f663b46: Extract client construction from `MsalConfigurator._processConfig` into overridable seams.
23
+
24
+ `_processConfig` now only decides *whether* a client is needed; `protected _createClient(config, init)` decides *what* to build, and `protected _createClientConfig(config)` resolves the `MsalClientConfig` it is built from — authority derived from the tenant, cache location, telemetry-backed logging and cache lookup policy included.
25
+
39
26
  Behaviour is unchanged for consumers: the client is still auto-created from `setClientConfig`, and a client supplied through `setClient` still wins, because `_createClient` is consulted only when no client was set.
40
-
27
+
41
28
  This gives a supported seam for authenticating through something other than Entra ID:
42
-
29
+
43
30
  ```typescript
44
31
  class MyConfigurator extends MsalConfigurator {
45
- protected override async _createClient(
46
- config: MsalConfig,
47
- ): Promise<IMsalClient> {
32
+ protected override async _createClient(config: MsalConfig): Promise<IMsalClient> {
48
33
  // same fully resolved configuration the real client is built from
49
34
  return new MyOwnMsalClient(this._createClientConfig(config));
50
35
  }
51
36
  }
52
37
  ```
53
-
38
+
54
39
  Overriding it replaces only the client, leaving the builder, the schema validation and `MsalProvider` untouched.
55
-
40
+
56
41
  No client is built when the module is hoisted onto a host application's provider — an app running inside a portal authenticates through the host, so a client built during configuration would be discarded, or worse, shadow the host's signed-in user. `protected _isHoisted(init)` exposes that decision to subclasses.
57
-
42
+
58
43
  Also adds `getClientConfig()`, the counterpart to `setClientConfig`, so a subclass can tell "nothing was declared" apart from "declared, and here it is".
59
-
44
+
60
45
  `_createClientConfig` applies its defaults to a copy of the declared configuration, not the object itself, so a caller reusing or asserting on it never sees it rewritten, and a shared constant can be used as a default without one configurator's client contaminating the next.
61
-
62
- - 2836e0b: Give `MsalMockClient` a real account cache, so its account APIs agree with each other and with MSAL.
63
-
64
- Previously the client held a single nullable account, which made its surface inconsistent: `getAccount(filter)` ignored the filter, `getAllAccounts()` reported an account even after one had only been made active, and signing out merely blanked a field.
65
-
66
- The client now keeps a cache keyed by `homeAccountId` alongside an active account, matching MSAL:
67
-
68
- - `getAccount(filter)` matches on `homeAccountId`, `localAccountId`, `username` and `tenantId`.
69
- - `getAllAccounts()` returns everything cached.
70
- - Signing in adds the account and activates it; signing out removes it, rather than leaving a stale entry behind.
71
- - `setUser` replaces the session, so declaring a second user never leaves two accounts cached.
72
-
73
- `setActiveAccount` deliberately departs from MSAL in one respect: an account that was never issued by a sign-in is accepted and added to the cache. That makes swapping the user between tests a single line, without rebuilding the framework:
74
-
46
+ - f663b46: Add a `./mock` entry point so applications can run against the auth module without credentials or
47
+ network access.
48
+
49
+ ```ts
50
+ import { enableMsalMock } from '@equinor/fusion-framework-module-msal/mock';
51
+
52
+ enableMsalMock(configurator, (builder) => {
53
+ builder.setAccount({ name: 'Ada Lovelace' });
54
+ });
55
+ ```
56
+
57
+ Only the MSAL **client** is substituted — `MsalMockClient` resolves tokens in-process from the same
58
+ `MsalClientConfig` the real `MsalClient` takes, built through the `_createClient` seam, so
59
+ `MsalProvider`, schema validation and the whole start-up path run exactly as they do in production.
60
+ Tokens are structurally valid, unsigned JWTs, identical between runs, and are rejected by any real
61
+ service.
62
+
63
+ `MsalMockConfigurator.setAccount(user | null | callback)` declares the signed-in user on the
64
+ builder instead of baking it into a client: `null` starts signed out and forgets the identity,
65
+ `{ signedOut: true }` starts signed out but keeps it for a later `login()` to resolve. The
66
+ declaration is applied to whichever client the module ends up authenticating through — including a
67
+ host framework's client when this module is hoisted into a portal — so pairing
68
+ `{ signedOut: true }` with `setRequiresAuth(true)` exercises the real automatic login.
69
+
70
+ `MsalMockConfigurator.setToken(token, skipResolve?)` returns that exact access/id token instead of
71
+ one generated from the account's claims, for a backend mock that validates specific claims,
72
+ audience or signature. By default it also signs in the account derived from the token's own claims
73
+ (`name`, `preferred_username`, `oid`, `tid`, `scp`) via `createMockUserFromToken`; pass
74
+ `skipResolve: true` to keep a separately declared account while still returning this token.
75
+
76
+ `MsalMockClient` keeps a real account cache keyed by `homeAccountId` alongside an active account,
77
+ matching MSAL: `getAccount(filter)` matches on `homeAccountId`/`localAccountId`/`username`/`tenantId`,
78
+ `getAllAccounts()` returns everything cached, sign-in/sign-out add and remove cache entries instead
79
+ of leaving stale ones behind, and `setActiveAccount` accepts an account that was never issued by a
80
+ sign-in (added to the cache), so swapping the user between tests is a single line:
81
+
75
82
  ```typescript
76
83
  beforeEach(() => {
77
84
  fusion.modules.auth.client.setActiveAccount(account);
78
85
  });
79
86
  ```
80
-
81
- - 2836e0b: Added a `./mock` entry point so applications can run against the auth module without credentials or network access.
82
-
83
- ```ts
84
- import {
85
- enableMsalMock,
86
- createMsalMockClient,
87
- } from "@equinor/fusion-framework-module-msal/mock";
88
-
89
- // default mock user
90
- enableMsalMock(configurator);
91
-
92
- // or a specific one
93
- enableMsalMock(configurator, (builder) => {
94
- builder.setAccount({ name: "Ada Lovelace" });
95
- });
96
- ```
97
-
98
- Only the MSAL **client** is substituted. `MsalMockClient` resolves tokens in-process and takes the same `MsalClientConfig` as the real `MsalClient`, so `setClientConfig` means the same thing whether a test runs against Entra ID or in-process. `MsalMockConfigurator` builds it through the `_createClient` seam, and `msalMockModule` differs from the real module in its `configure` alone — `initialize` is the production one, untouched, so `MsalProvider`, schema validation and the whole start-up path run exactly as they do in production. `IMsalProvider` and `MsalConfigurator` are untouched.
99
-
100
- The same client works with the plain module, without the mock module:
101
-
87
+
88
+ The same client works with the plain (non-mock) module:
89
+
102
90
  ```ts
103
91
  enableMSAL(configurator, (builder) =>
104
- builder.setClient(
105
- createMsalMockClient(
106
- { auth: { clientId: "my-app" } },
107
- { name: "Ada Lovelace" },
108
- ),
109
- ),
92
+ builder.setClient(createMsalMockClient({ auth: { clientId: 'my-app' } }, { name: 'Ada Lovelace' })),
110
93
  );
111
94
  ```
112
-
113
- Tokens are structurally valid, unsigned JWTs and are identical between runs. They are not cryptographically valid and are rejected by any real service.
114
-
115
- Exports `enableMsalMock`, `msalMockModule`, `MsalMockConfigurator`, `MsalMockClient`, `createMsalMockClient` and `createMockToken`. The entry point has no test-runner dependency.
116
-
117
- - 2836e0b: Add `setAccount` to `MsalMockConfigurator`, so a test declares the signed-in user on the builder instead of baking it into a client.
118
-
119
- ```typescript
120
- enableMsalMock(configurator, (builder) => {
121
- builder.setAccount({ name: "Ada Lovelace", username: "ada@equinor.com" });
122
- });
123
- ```
124
-
125
- It takes an object, `null` when nobody is signed in, or an ordinary `ConfigBuilderCallback` resolving either:
126
-
127
- ```typescript
128
- builder.setAccount(null);
129
- builder.setAccount(async ({ hasModule }) => ({
130
- name: hasModule("app") ? "App User" : "Portal User",
131
- }));
132
- ```
133
-
134
- The callback is the builder's own type rather than a bespoke one, so it is handed the same arguments every other configuration callback receives and is resolved by the same machinery.
135
-
136
- `null` and `{ signedOut: true }` both start without a session, and differ in what a later login resolves to: `null` forgets the identity, `signedOut` keeps it. A declared `null` is a declaration in its own right, so it overrides the default signed-in user — only an absent declaration means the test said nothing.
137
-
138
- `setAccount` writes to `mock.account` on the configuration rather than to a field on the builder, so the user travels the ordinary builder pipeline: a callback is resolved by `_buildConfig` with the same arguments every other configuration callback receives, and the result is on the raw configuration before validation. The schema strips the key, so nothing about a test reaches `MsalProvider` — the branch exists purely to carry the declaration across the builder. `MsalMockConfig` is exported for code that reads it.
139
-
140
- `setAccount` records configuration only — the user is signed in on the client as it is built, so it may be declared at any point before initialization and the last declaration wins. Keeping the user off `MsalClientConfig` is what lets `MsalMockClient` take the same argument the real `MsalClient` takes: a client is configured with _what it talks to_, never with _who is signed in_.
141
-
142
- Because the user is in place before `MsalProvider.initialize()` runs, the provider's own start-up path acts on it. Pairing `{ signedOut: true }` with `setRequiresAuth(true)` therefore exercises the real automatic login, rather than a state assigned after initialization had already finished.
143
-
144
- Because who is signed in is session state rather than client configuration, the user is applied to whichever client the module ends up authenticating through — wherever that client was built. When the module is hoisted onto a host application's provider, no client is built here, so the user is signed in on the _host's_ client instead. Without that, a declaration made in an application's test would silently do nothing precisely when the application is being tested inside a portal. The session is shared, so the host sees the same user, as it does in production; when the host does not authenticate through a mock client the declaration throws rather than failing quietly.
145
-
146
- `setClient` replaces the client, but not the rule: a mock client supplied that way receives the declared user too.
95
+
96
+ Exports `enableMsalMock`, `msalMockModule`, `MsalMockConfigurator`, `MsalMockClient`,
97
+ `createMsalMockClient` and `createMockToken`. Does not change or replace `token_only` mode, which
98
+ remains the right choice for CI/CD scenarios needing a static token.
147
99
 
148
100
  ### Patch Changes
149
101
 
150
- - e8aae1f: Internal: publish every package on the `next` pre-release tag so the whole framework can be installed as a coherent set.
151
-
152
- Packages without their own changes are bumped only to receive a `-next.N` version and the `next` dist-tag on npm. Install with:
153
-
154
- ```bash
155
- pnpm add @equinor/fusion-framework-react-app@next
156
- ```
157
-
158
- - 2836e0b: Restructure documentation so each README is an entry point rather than a manual.
159
-
102
+ - f663b46: Restructure documentation so each README is an entry point rather than a manual.
103
+
160
104
  Long-form content moved into per-package `docs/` folders, matching the convention already used by `@equinor/fusion-framework-module` and `@equinor/fusion-framework-module-http`. Each README now keeps the elevator pitch, the shortest working example and a documentation table linking to the rest.
161
-
105
+
162
106
  - **msal** — `docs/api-reference.md`, `docs/auth-code-flow.md`, `docs/testing.md`, `docs/version-management.md`, `docs/migration-v2-to-v4.md`, `docs/troubleshooting.md`. The README also gained the top-level heading it was missing.
163
107
  - **service-discovery** — `docs/configuration.md`, `docs/testing.md`, `docs/session-overrides.md`, `docs/api-reference.md`.
164
108
  - **framework** — `docs/testing-choosing-a-layer.md`, `docs/testing.md`, `docs/testing-design.md`, `docs/testing-extending.md`, `docs/testing-api.md`.
165
-
109
+
166
110
  Both module READMEs now document their `/mock` entry point, which was previously undocumented, and state that spying on an individual call is the test runner's job rather than something these packages provide.
167
-
168
- - 2836e0b: Remove a stray `console.log` left in `resolveVersion`'s minor-version-mismatch warning path.
169
- - Updated dependencies [e8aae1f]
170
- - Updated dependencies [2836e0b]
171
- - Updated dependencies [2836e0b]
172
- - Updated dependencies [2836e0b]
173
- - Updated dependencies [2836e0b]
174
- - Updated dependencies [2836e0b]
175
- - @equinor/fusion-framework-module@6.1.3-next.0
176
- - @equinor/fusion-framework-module-telemetry@8.0.0-next.0
111
+ - f663b46: Remove a stray `console.log` left in `resolveVersion`'s minor-version-mismatch warning path.
177
112
 
178
113
  ## 10.0.2
179
114
 
@@ -1,3 +1,3 @@
1
1
  // Generated by genversion.
2
- export const version = '11.0.0-next.1';
2
+ export const version = '11.0.0';
3
3
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,MAAM,CAAC,MAAM,OAAO,GAAG,eAAe,CAAC"}
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,MAAM,CAAC,MAAM,OAAO,GAAG,QAAQ,CAAC"}