@equinor/fusion-framework-vite-plugin-spa 4.0.15 → 4.0.17-next.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.
@@ -6314,7 +6314,7 @@ async function runDisposePhase(ctx, instance, ref) {
6314
6314
  }
6315
6315
 
6316
6316
  // Generated by genversion.
6317
- const version$8 = '6.1.1';
6317
+ const version$8 = '6.1.3-next.0';
6318
6318
 
6319
6319
  // biome-ignore-all lint/suspicious/noExplicitAny: internal type-erased dispatch arrays — callbacks are registered with concrete module types but stored erased; the orchestrator never inspects these shapes itself
6320
6320
  /* eslint-disable @typescript-eslint/no-explicit-any */
@@ -6449,7 +6449,34 @@ class ModulesConfigurator {
6449
6449
  * @param modules - Optional array of module descriptors to pre-register.
6450
6450
  */
6451
6451
  constructor(modules) {
6452
- this._modules = new Set(modules);
6452
+ this._modules = new Set(modules ? this._dedupeModulesByName(modules) : []);
6453
+ }
6454
+ /**
6455
+ * Keeps the last registration for each module name.
6456
+ *
6457
+ * @param modules - Module descriptors to deduplicate.
6458
+ * @returns The deduplicated module descriptors.
6459
+ */
6460
+ _dedupeModulesByName(modules) {
6461
+ const lastByName = new Map();
6462
+ // Iterate in registration order so later descriptors intentionally override earlier ones.
6463
+ for (const module of modules) {
6464
+ lastByName.set(module.name, module);
6465
+ }
6466
+ return Array.from(lastByName.values());
6467
+ }
6468
+ /**
6469
+ * Removes lifecycle callbacks belonging to a replaced module.
6470
+ *
6471
+ * @param moduleName - Name of the module whose callbacks are removed.
6472
+ */
6473
+ _removeModuleCallbacks(moduleName) {
6474
+ // Remove callbacks from each lifecycle phase so replaced modules cannot run stale behavior.
6475
+ this._configs = this._configs.filter((callback) => callback.moduleName !== moduleName);
6476
+ // Keep cleanup callbacks aligned with the module replacement.
6477
+ this._afterConfiguration = this._afterConfiguration.filter((callback) => callback.moduleName !== moduleName);
6478
+ // Remove initialization callbacks as well, preventing the old module from being initialized.
6479
+ this._afterInit = this._afterInit.filter((callback) => callback.moduleName !== moduleName);
6453
6480
  }
6454
6481
  /**
6455
6482
  * Returns all registered module descriptors as an ordered array.
@@ -6476,6 +6503,9 @@ class ModulesConfigurator {
6476
6503
  /**
6477
6504
  * Registers a single module configurator.
6478
6505
  *
6506
+ * If a module with the same `name` was already registered, the previous
6507
+ * registration is replaced so the last added module wins.
6508
+ *
6479
6509
  * Adds the module to the known module set and registers the optional
6480
6510
  * `configure`, `afterConfig`, and `afterInit` callbacks into their
6481
6511
  * respective lifecycle phase arrays.
@@ -6486,7 +6516,26 @@ class ModulesConfigurator {
6486
6516
  */
6487
6517
  addConfig(config) {
6488
6518
  const { module, afterConfig, afterInit, configure } = config;
6489
- this._modules.add(module);
6519
+ // Find an existing descriptor so re-registering a name can replace all of its lifecycle hooks.
6520
+ const existingModule = Array.from(this._modules).find((m) => m.name === module.name);
6521
+ // Only handle replacement/dedupe when a descriptor is already registered under this name.
6522
+ if (existingModule) {
6523
+ // Only a genuinely different descriptor for this name is a replacement that must
6524
+ // discard the old callbacks. Re-registering the SAME descriptor object (as helpers
6525
+ // like `configureHttpClient`/`useFrameworkServiceClient` do on every call, since they
6526
+ // all share one module singleton) must stay additive so multiple calls can register
6527
+ // multiple named clients without clobbering each other.
6528
+ if (existingModule !== module) {
6529
+ this._removeModuleCallbacks(module.name);
6530
+ const modules = Array.from(this._modules)
6531
+ // Preserve every descriptor while substituting the newly registered module.
6532
+ .map((m) => (m.name === module.name ? module : m));
6533
+ this._modules = new Set(modules);
6534
+ }
6535
+ }
6536
+ else {
6537
+ this._modules.add(module);
6538
+ }
6490
6539
  this._registerEvent({
6491
6540
  level: ModuleEventLevel.Debug,
6492
6541
  name: ModuleConfiguratorEventName.ModuleConfigAdded,
@@ -6499,15 +6548,26 @@ class ModulesConfigurator {
6499
6548
  afterInit: !!afterInit,
6500
6549
  },
6501
6550
  });
6502
- // Register each optional callback into its corresponding lifecycle phase array
6503
- if (configure)
6504
- this._configs.push((cfg, ref) => configure(cfg[module.name], ref));
6505
- // Register the afterConfig callback, if provided
6506
- if (afterConfig)
6507
- this._afterConfiguration.push((cfg) => afterConfig(cfg[module.name]));
6508
- // Register the afterInit callback, if provided
6509
- if (afterInit)
6510
- this._afterInit.push((instances) => afterInit(instances[module.name]));
6551
+ // Register each optional callback into its corresponding lifecycle phase array.
6552
+ // When the same module name is re-registered, previous callbacks are removed
6553
+ // so the latest configuration wins.
6554
+ if (configure) {
6555
+ const callback = ((cfg, ref) => configure(cfg[module.name], ref));
6556
+ callback.moduleName = module.name;
6557
+ this._configs.push(callback);
6558
+ }
6559
+ // Register the afterConfig callback, if provided.
6560
+ if (afterConfig) {
6561
+ const callback = ((cfg) => afterConfig(cfg[module.name]));
6562
+ callback.moduleName = module.name;
6563
+ this._afterConfiguration.push(callback);
6564
+ }
6565
+ // Register the afterInit callback, if provided.
6566
+ if (afterInit) {
6567
+ const callback = ((instances) => afterInit(instances[module.name]));
6568
+ callback.moduleName = module.name;
6569
+ this._afterInit.push(callback);
6570
+ }
6511
6571
  }
6512
6572
  /**
6513
6573
  * Registers a callback for the post-configure phase.
@@ -6929,6 +6989,49 @@ class HttpRequestHandler extends ProcessOperators {
6929
6989
  class HttpResponseHandler extends ProcessOperators {
6930
6990
  }
6931
6991
 
6992
+ /**
6993
+ * Normalizes a step's result to a `Promise`, so a middleware calling `next(...)` never has to
6994
+ * branch on whether the next step short-circuited with a plain `Response` or reached all the
6995
+ * way to an Observable-returning network call.
6996
+ */
6997
+ function toPromise(result) {
6998
+ return result instanceof Response ? Promise.resolve(result) : firstValueFrom(from(result));
6999
+ }
7000
+ /**
7001
+ * Composes registered {@link HttpMiddleware} into a single execution pipeline wrapping the
7002
+ * network call, so retries, caching, telemetry, or circuit-breaking can wrap `_performFetch`
7003
+ * without touching request or response payload transforms.
7004
+ *
7005
+ * @see {@link HttpClient}
7006
+ */
7007
+ class HttpMiddlewareHandler {
7008
+ #middleware;
7009
+ /**
7010
+ * Constructs a handler, optionally cloning another handler's registered middleware.
7011
+ * @param source - An existing handler to clone the registered middleware from.
7012
+ */
7013
+ constructor(source) {
7014
+ this.#middleware = source ? [...source.middleware] : [];
7015
+ }
7016
+ /** @inheritdoc */
7017
+ get middleware() {
7018
+ return this.#middleware;
7019
+ }
7020
+ /** @inheritdoc */
7021
+ use(middleware) {
7022
+ this.#middleware.push(middleware);
7023
+ return this;
7024
+ }
7025
+ /** @inheritdoc */
7026
+ process(uri, init, terminal) {
7027
+ // wrap outward-in so the first-registered middleware is outermost, matching a conventional middleware chain
7028
+ const chain = this.#middleware.reduceRight((next, middleware) => (nextUri, nextInit) => middleware(nextUri, nextInit, (u, i) => toPromise(next(u, i))), terminal);
7029
+ const result = chain(uri, init);
7030
+ // a middleware may short-circuit with a plain Response (no ObservableInput wrapping needed)
7031
+ return result instanceof Response ? of(result) : from(result);
7032
+ }
7033
+ }
7034
+
6932
7035
  var _a$1;
6933
7036
  /** A special constant with type `never` */
6934
7037
  const NEVER = /*@__PURE__*/ Object.freeze({
@@ -22530,6 +22633,8 @@ class HttpClientConfigurator {
22530
22633
  // validate the request object
22531
22634
  'request-validation': requestValidationOperator(),
22532
22635
  });
22636
+ /** Default middleware chain cloned into each created client instance. */
22637
+ defaultHttpMiddlewareHandler = new HttpMiddlewareHandler();
22533
22638
  /**
22534
22639
  * Creates a configurator with the default client constructor.
22535
22640
  * @param client - The default client constructor used when `ctor` is not configured per client.
@@ -22542,6 +22647,11 @@ class HttpClientConfigurator {
22542
22647
  return Object.keys(this._clients).includes(name);
22543
22648
  }
22544
22649
  /** @inheritdoc */
22650
+ addMiddleware(middleware) {
22651
+ this.defaultHttpMiddlewareHandler.use(middleware);
22652
+ return this;
22653
+ }
22654
+ /** @inheritdoc */
22545
22655
  configureClient(name, args) {
22546
22656
  const argFn = typeof args === 'string' ? { baseUri: args } : args;
22547
22657
  const options = typeof argFn === 'function' ? { onCreate: argFn } : argFn;
@@ -22556,7 +22666,7 @@ class HttpClientConfigurator {
22556
22666
  }
22557
22667
 
22558
22668
  // Generated by genversion.
22559
- const version$6 = '8.0.5';
22669
+ const version$6 = '8.1.0-next.0';
22560
22670
 
22561
22671
  /** URL protocols accepted as valid ad-hoc base URIs. */
22562
22672
  const SUPPORTED_PROTOCOLS = ['http:', 'https:', 'ws:', 'wss:'];
@@ -22595,6 +22705,13 @@ class HttpClientProvider extends BaseModuleProvider {
22595
22705
  get defaultHttpRequestHandler() {
22596
22706
  return this.config.defaultHttpRequestHandler;
22597
22707
  }
22708
+ /**
22709
+ * Gets the default middleware chain for the HTTP client provider.
22710
+ * @returns The default middleware chain.
22711
+ */
22712
+ get defaultHttpMiddlewareHandler() {
22713
+ return this.config.defaultHttpMiddlewareHandler;
22714
+ }
22598
22715
  /**
22599
22716
  * Creates a new `HttpClientProvider`.
22600
22717
  * @param config - The configurator providing client definitions and defaults.
@@ -22632,8 +22749,8 @@ class HttpClientProvider extends BaseModuleProvider {
22632
22749
  */
22633
22750
  createClient(keyOrConfig) {
22634
22751
  const config = this._resolveConfig(keyOrConfig);
22635
- const { baseUri, defaultScopes = [], onCreate, ctor = this.config.defaultHttpClientCtor, requestHandler = this.defaultHttpRequestHandler, responseHandler, } = config;
22636
- const options = { requestHandler, responseHandler };
22752
+ const { baseUri, defaultScopes = [], onCreate, ctor = this.config.defaultHttpClientCtor, requestHandler = this.defaultHttpRequestHandler, responseHandler, middlewareHandler = this.defaultHttpMiddlewareHandler, } = config;
22753
+ const options = { requestHandler, responseHandler, middlewareHandler };
22637
22754
  const instance = new ctor(baseUri || '', options);
22638
22755
  // attach the resolved default scopes onto the instance without overwriting other own properties
22639
22756
  Object.assign(instance, { defaultScopes });
@@ -22832,6 +22949,12 @@ class HttpClient {
22832
22949
  * This property is part of the `HttpClientCreateOptions` configuration object used to create an `HttpClient` instance.
22833
22950
  */
22834
22951
  responseHandler;
22952
+ /**
22953
+ * Middleware wrapping the network call, for cross-cutting concerns such as retries,
22954
+ * caching, or telemetry. This property is part of the `HttpClientCreateOptions`
22955
+ * configuration object used to create an `HttpClient` instance.
22956
+ */
22957
+ middlewareHandler;
22835
22958
  /**
22836
22959
  * A stream of requests that are about to be executed.
22837
22960
  * This property is used internally by the `HttpClient` class to manage the lifecycle of requests.
@@ -22870,6 +22993,7 @@ class HttpClient {
22870
22993
  this.uri = uri;
22871
22994
  this.requestHandler = new HttpRequestHandler(options?.requestHandler);
22872
22995
  this.responseHandler = new HttpResponseHandler(options?.responseHandler);
22996
+ this.middlewareHandler = new HttpMiddlewareHandler(options?.middlewareHandler);
22873
22997
  this._init();
22874
22998
  }
22875
22999
  /**
@@ -23041,7 +23165,9 @@ class HttpClient {
23041
23165
  /**
23042
23166
  * Aborts any ongoing HTTP requests made by this `IHttpClient` instance.
23043
23167
  * This will trigger the `takeUntil` operator in the `_fetch$` method,
23044
- * causing any in-flight requests to be cancelled.
23168
+ * causing any in-flight requests to be cancelled, and abort the
23169
+ * per-request `AbortSignal` passed through to `_performFetch`, so the
23170
+ * underlying network call is cancelled even behind registered middleware.
23045
23171
  */
23046
23172
  abort() {
23047
23173
  this._abort$.next();
@@ -23066,11 +23192,26 @@ class HttpClient {
23066
23192
  */
23067
23193
  _fetch$(path, args) {
23068
23194
  const { selector, ...options } = args || {};
23195
+ // A registered middleware's `next(...)` resolves through a `Promise` (see
23196
+ // `HttpMiddlewareHandler`), which `firstValueFrom` fulfils via its own independent
23197
+ // subscription to `_performFetch` — one the `takeUntil(this._abort$)` below never reaches,
23198
+ // since it sits outside the subscription tree that `takeUntil` tears down. Combining this
23199
+ // controller's signal into the request `init` lets `_performFetch` (`fromFetch` by default)
23200
+ // abort the underlying network call directly, regardless of whether middleware severed the
23201
+ // RxJS teardown chain.
23202
+ const abortController = new AbortController();
23203
+ // abort only fires once per request; the subscription is torn down in `finalize` below
23204
+ const abort = this._abort$.pipe(take(1)).subscribe(() => abortController.abort());
23205
+ const callerSignal = options.signal;
23206
+ const signal = callerSignal
23207
+ ? AbortSignal.any([callerSignal, abortController.signal])
23208
+ : abortController.signal;
23069
23209
  // `fromFetch` yields the raw fetch `Response`, but `responseHandler.process()` (called via
23070
23210
  // `_prepareResponse`) expects the pipeline's generic `TResponse` shape — cast through
23071
23211
  // `unknown` since the two are only compatible after that processing step.
23072
23212
  const response$ = of({
23073
23213
  ...options,
23214
+ signal,
23074
23215
  path,
23075
23216
  uri: this._resolveUrl(path),
23076
23217
  }).pipe(
@@ -23078,8 +23219,8 @@ class HttpClient {
23078
23219
  switchMap((x) => this._prepareRequest(x)),
23079
23220
  /** push request to event buss */
23080
23221
  tap((x) => this._request$.next(x)),
23081
- /** execute request */
23082
- switchMap(({ uri, path: _path, ...init }) => fromFetch(uri, init)),
23222
+ /** execute request through registered middleware, terminating at _performFetch */
23223
+ switchMap(({ uri, path: _path, ...init }) => this.middlewareHandler.process(uri, init, (u, i) => this._performFetch(u, i))),
23083
23224
  /** prepare response, allow extensions to modify response */
23084
23225
  switchMap((x) => this._prepareResponse(x)),
23085
23226
  /** push response to event buss */
@@ -23100,11 +23241,30 @@ class HttpClient {
23100
23241
  return of(response);
23101
23242
  }),
23102
23243
  /** cancel request on abort signal */
23103
- takeUntil(this._abort$));
23244
+ takeUntil(this._abort$),
23245
+ /** the abort signal subscription only ever fires once; tear it down once this request settles either way */
23246
+ finalize$2(() => abort.unsubscribe()));
23104
23247
  // The pipe above resolves to the per-call generic `T` (via the optional `selector`), but
23105
23248
  // the observable's static type tracks the class-level `TResponse` — cast to the caller's `T`.
23106
23249
  return response$;
23107
23250
  }
23251
+ /**
23252
+ * Performs the actual network call for a prepared request.
23253
+ *
23254
+ * @remarks
23255
+ * Isolated from {@link _fetch$} so a test double can replace only this step —
23256
+ * matching a request against registered route handlers instead of reaching
23257
+ * the network — while everything around it (request preparation, the
23258
+ * response pipeline, abort handling) runs unchanged. See
23259
+ * `@equinor/fusion-framework-module-http/mock`.
23260
+ *
23261
+ * @param uri - The fully resolved URL for the request.
23262
+ * @param init - The prepared `fetch` request options.
23263
+ * @returns An observable of the raw `Response`, ahead of {@link _prepareResponse}.
23264
+ */
23265
+ _performFetch(uri, init) {
23266
+ return fromFetch(uri, init);
23267
+ }
23108
23268
  /**
23109
23269
  * Prepares the request by passing it through the `requestHandler.process()` method.
23110
23270
  * This method is an implementation detail of the `_fetch$()` method, and is not part of the public API.
@@ -23761,7 +23921,7 @@ var objectTraps = {
23761
23921
  ) && isArrayIndex(prop)) {
23762
23922
  return value;
23763
23923
  }
23764
- if (value === peek(state.base_, prop) || isRelocatedBaseRef(state, prop, value)) {
23924
+ if (value === peek(state.base_, prop)) {
23765
23925
  prepareCopy(state);
23766
23926
  const childKey = state.type_ === 1 /* Array */ ? +prop : prop;
23767
23927
  const childDraft = createProxy(state.scope_, value, state, childKey);
@@ -23795,7 +23955,7 @@ var objectTraps = {
23795
23955
  markChanged(state);
23796
23956
  }
23797
23957
  if (state.copy_[prop] === value && // special case: handle new props with value 'undefined'
23798
- (value !== void 0 || has(state.copy_, prop, state.type_)) || // special case: NaN
23958
+ (value !== void 0 || prop in state.copy_) || // special case: NaN
23799
23959
  Number.isNaN(value) && Number.isNaN(state.copy_[prop]))
23800
23960
  return true;
23801
23961
  state.copy_[prop] = value;
@@ -23864,12 +24024,6 @@ function peek(draft, prop) {
23864
24024
  const source = state ? latest(state) : draft;
23865
24025
  return source[prop];
23866
24026
  }
23867
- function isRelocatedBaseRef(state, prop, value) {
23868
- if (state.type_ !== 1 /* Array */ || !state.allIndicesReassigned_ || state.assigned_?.get(prop) || !isDraftable(value) || value[DRAFT_STATE]) {
23869
- return false;
23870
- }
23871
- return state.baseRefs_.has(value);
23872
- }
23873
24027
  function readPropFromProto(state, source, prop) {
23874
24028
  const desc = getDescriptorFromProto(source, prop);
23875
24029
  return desc ? VALUE in desc ? desc[VALUE] : (
@@ -25014,7 +25168,7 @@ class TelemetryConfigurator extends BaseConfigBuilder {
25014
25168
  }
25015
25169
 
25016
25170
  // Generated by genversion.
25017
- const version$5 = '7.0.1';
25171
+ const version$5 = '8.0.0-next.0';
25018
25172
 
25019
25173
  /**
25020
25174
  * Enum representing the severity levels of telemetry items.
@@ -43867,7 +44021,7 @@ const createClientLogCallback = (provider, metadata, scope) => {
43867
44021
  };
43868
44022
 
43869
44023
  // Generated by genversion.
43870
- const version$2 = '10.0.2';
44024
+ const version$2 = '11.0.0-next.0';
43871
44025
 
43872
44026
  /**
43873
44027
  * Zod schema for telemetry configuration validation.
@@ -43882,10 +44036,15 @@ const TelemetryConfigSchema = z.object({
43882
44036
  }),
43883
44037
  scope: z.array(z.string()).optional().default(['framework', 'authentication']),
43884
44038
  });
44039
+
43885
44040
  /**
43886
44041
  * Zod schema for MSAL module configuration validation.
43887
44042
  *
43888
- * @internal
44043
+ * @remarks
44044
+ * Kept in its own module so the configuration can be extended at its source.
44045
+ * The schema itself describes what reaches `MsalProvider` and strips anything
44046
+ * else; keys a variant of this module needs only while the configuration is
44047
+ * being built are declared on {@link MsalConfigExtension} instead.
43889
44048
  */
43890
44049
  const MsalConfigSchema = z.object({
43891
44050
  client: z.custom().optional(),
@@ -43898,9 +44057,19 @@ const MsalConfigSchema = z.object({
43898
44057
  .custom((val) => typeof val === 'number' &&
43899
44058
  Object.values(CacheLookupPolicy).includes(val))
43900
44059
  .optional(),
43901
- version: z.string().transform((x) => String(semver.coerce(x))),
44060
+ version: z.string().transform((value, ctx) => {
44061
+ const coerced = semver.coerce(value);
44062
+ // `semver.coerce` returns `null` for an unparseable version; without this guard it
44063
+ // would silently become the literal string "null" instead of failing validation.
44064
+ if (!coerced) {
44065
+ ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Invalid MSAL module version' });
44066
+ return z.NEVER;
44067
+ }
44068
+ return coerced.version;
44069
+ }),
43902
44070
  telemetry: TelemetryConfigSchema,
43903
44071
  });
44072
+
43904
44073
  /**
43905
44074
  * Configuration builder for MSAL v4 authentication module.
43906
44075
  *
@@ -43916,6 +44085,7 @@ const MsalConfigSchema = z.object({
43916
44085
  */
43917
44086
  class MsalConfigurator extends BaseConfigBuilder {
43918
44087
  #msalConfig;
44088
+ #client;
43919
44089
  /**
43920
44090
  * The MSAL module version being configured.
43921
44091
  *
@@ -43942,6 +44112,9 @@ class MsalConfigurator extends BaseConfigBuilder {
43942
44112
  return telemetry;
43943
44113
  }
43944
44114
  });
44115
+ // Always resolve the configured client instance through the builder.
44116
+ // This keeps the client getter live and avoids re-registering the same config key.
44117
+ this._set('client', async () => this.#client);
43945
44118
  // Default cache lookup policy to AccessTokenAndRefreshToken to avoid iframe fallback delays
43946
44119
  this._set('cacheLookupPolicy', async () => CacheLookupPolicy.AccessTokenAndRefreshToken);
43947
44120
  }
@@ -43969,6 +44142,22 @@ class MsalConfigurator extends BaseConfigBuilder {
43969
44142
  this.#msalConfig = config;
43970
44143
  return this;
43971
44144
  }
44145
+ /**
44146
+ * Returns the client configuration declared through
44147
+ * {@link MsalConfigurator.setClientConfig | setClientConfig}, if any.
44148
+ *
44149
+ * @remarks
44150
+ * This is the configuration as declared, not the resolved one a client is
44151
+ * built from — see
44152
+ * {@link MsalConfigurator._createClientConfig | _createClientConfig} for that.
44153
+ * Reading it is how a subclass can tell "nothing was declared" apart from
44154
+ * "declared, and here it is", without re-deriving that from a resolved value.
44155
+ *
44156
+ * @returns The declared client configuration, or `undefined` when none was declared.
44157
+ */
44158
+ getClientConfig() {
44159
+ return this.#msalConfig;
44160
+ }
43972
44161
  /**
43973
44162
  * Sets the cache lookup policy used for every silent token acquisition.
43974
44163
  *
@@ -44102,9 +44291,21 @@ class MsalConfigurator extends BaseConfigBuilder {
44102
44291
  * ```
44103
44292
  */
44104
44293
  setClient(client) {
44105
- this._set('client', async () => client);
44294
+ this.#client = client;
44106
44295
  return this;
44107
44296
  }
44297
+ /**
44298
+ * Returns the currently configured MSAL client, if one has been set.
44299
+ *
44300
+ * @remarks
44301
+ * This is useful in tests when a mock client has been provided and the test
44302
+ * wants to adjust its state after it has been assigned to the configurator.
44303
+ *
44304
+ * @returns The configured client, or `undefined` when none has been set.
44305
+ */
44306
+ getClient() {
44307
+ return this.#client;
44308
+ }
44108
44309
  /**
44109
44310
  * Sets telemetry provider for MSAL authentication events.
44110
44311
  *
@@ -44152,64 +44353,151 @@ class MsalConfigurator extends BaseConfigBuilder {
44152
44353
  /**
44153
44354
  * Processes and validates the configuration.
44154
44355
  *
44155
- * @param config - Raw configuration object
44356
+ * @param rawConfig - Raw configuration object
44357
+ * @param init - The builder arguments, carrying the host reference when hoisted
44156
44358
  * @returns Processed and validated configuration
44157
44359
  */
44158
- async _processConfig(rawConfig) {
44360
+ async _processConfig(rawConfig, init) {
44159
44361
  // Validate and coerce configuration using Zod schema
44160
44362
  const config = await MsalConfigSchema.parseAsync(rawConfig);
44161
- // Auto-create client if config provided but no client instance
44363
+ // Auto-create client if no client instance was supplied
44162
44364
  // This allows users to provide configuration without manually instantiating the client
44163
- if (!config.client && this.#msalConfig) {
44164
- const clientConfig = this.#msalConfig;
44165
- config.telemetry.provider?.trackEvent({
44166
- name: 'module-msal.configurator._processConfig.creating-client',
44365
+ // A hoisted module authenticates through the host's provider, so any client built here
44366
+ // would be discarded — gate it here rather than in `_createClient`, so a substituted
44367
+ // client (see `MsalMockConfigurator`) cannot shadow the host's signed-in user
44368
+ if (!config.client && !this._isHoisted(init)) {
44369
+ config.client = await this._createClient(config, init);
44370
+ }
44371
+ return config;
44372
+ }
44373
+ /**
44374
+ * Creates the client to authenticate through, when none was supplied.
44375
+ *
44376
+ * @remarks
44377
+ * Called by {@link MsalConfigurator._processConfig | _processConfig} only when
44378
+ * no client was set, so a client supplied through
44379
+ * {@link MsalConfigurator.setClient | setClient} always wins. It is likewise
44380
+ * not called when the module is hoisted onto a host application's provider —
44381
+ * see {@link MsalConfigurator._isHoisted | _isHoisted}.
44382
+ *
44383
+ * This is the seam for authenticating through something other than Entra ID.
44384
+ * Overriding it replaces only the client, leaving the builder, the schema
44385
+ * validation and `MsalProvider` untouched — which is how
44386
+ * `MsalMockConfigurator` substitutes an in-process client for tests.
44387
+ *
44388
+ * An override normally builds from
44389
+ * {@link MsalConfigurator._createClientConfig | _createClientConfig}, so it
44390
+ * receives the same fully-resolved {@link MsalClientConfig} the real client is
44391
+ * built from rather than re-deriving it.
44392
+ *
44393
+ * Returning `undefined` is legitimate and means "there is nothing to build a
44394
+ * client from", which leaves the module without one.
44395
+ *
44396
+ * @param config - The validated configuration the client is built from.
44397
+ * @param init - The builder arguments, carrying the host reference when hoisted.
44398
+ * @returns The client, or `undefined` when there is nothing to build one from.
44399
+ */
44400
+ async _createClient(config, _init) {
44401
+ const clientConfig = this._createClientConfig(config);
44402
+ // A client can be omitted for a hoisted module or an intentionally incomplete setup.
44403
+ if (!clientConfig) {
44404
+ return undefined;
44405
+ }
44406
+ // Instantiate MSAL client with fully configured options
44407
+ return new MsalClient(clientConfig);
44408
+ }
44409
+ /**
44410
+ * Whether this module is hoisted onto a host application's authentication.
44411
+ *
44412
+ * @remarks
44413
+ * When an application runs inside a host — a portal loading an app, or an app
44414
+ * loading a widget — the module initializer returns a proxy of the host's
44415
+ * provider instead of building its own (see the host-provider branch of the
44416
+ * module initializer). A client built during configuration would therefore be
44417
+ * constructed and immediately discarded.
44418
+ *
44419
+ * Detecting this during configuration lets the configurator skip building a
44420
+ * client entirely, which matters most for substituted clients: a mock client
44421
+ * built here would otherwise silently shadow the host's real signed-in user.
44422
+ *
44423
+ * @param init - The builder arguments, carrying the host reference when hoisted.
44424
+ * @returns `true` when a host provider will be used instead of a locally built client.
44425
+ */
44426
+ _isHoisted(init) {
44427
+ return !!init?.ref?.auth;
44428
+ }
44429
+ /**
44430
+ * Resolves the full MSAL client configuration to build a client from.
44431
+ *
44432
+ * @remarks
44433
+ * Applies the defaults a client is expected to be built with — authority
44434
+ * derived from the tenant, cache location, telemetry-backed logging and the
44435
+ * configured cache lookup policy.
44436
+ *
44437
+ * Kept separate from {@link MsalConfigurator._createClient | _createClient} so
44438
+ * that substituting the client does not also mean re-implementing this
44439
+ * resolution. `MsalMockConfigurator` relies on it to hand its mock client the
44440
+ * very same configuration the real client would have received.
44441
+ *
44442
+ * @param config - The validated configuration.
44443
+ * @returns The client configuration, or `undefined` when none was declared.
44444
+ */
44445
+ _createClientConfig(config) {
44446
+ const declared = this.#msalConfig;
44447
+ // Do not construct a client when configuration has not supplied client settings.
44448
+ if (!declared) {
44449
+ return undefined;
44450
+ }
44451
+ config.telemetry.provider?.trackEvent({
44452
+ name: 'module-msal.configurator._processConfig.creating-client',
44453
+ level: TelemetryLevel.Debug,
44454
+ scope: config.telemetry.scope,
44455
+ metadata: { ...config.telemetry.metadata, clientConfig: declared },
44456
+ });
44457
+ // Copied rather than enriched in place, so the object a caller passed to
44458
+ // `setClientConfig` is never rewritten behind its back — a caller may well
44459
+ // be reusing or asserting on it
44460
+ const clientConfig = {
44461
+ ...declared,
44462
+ auth: { ...declared.auth },
44463
+ // Default to localStorage: MSAL supports sessionStorage too, but
44464
+ // localStorage is the standard for persistent auth in browsers
44465
+ cache: declared.cache ?? { cacheLocation: 'localStorage' },
44466
+ };
44467
+ // Auto-generate authority URL from tenant ID if not explicitly provided
44468
+ // This simplifies configuration for most common cases
44469
+ if (!clientConfig.auth.authority && clientConfig.auth.tenantId) {
44470
+ clientConfig.auth.authority = `https://login.microsoftonline.com/${clientConfig.auth.tenantId}`;
44471
+ }
44472
+ // Integrate framework telemetry with MSAL logging system
44473
+ // This allows MSAL events to flow through the framework's telemetry pipeline
44474
+ if (!clientConfig.system?.loggerOptions && config.telemetry?.provider) {
44475
+ const { provider, metadata, scope } = config.telemetry;
44476
+ provider.trackEvent({
44477
+ name: 'module-msal.configurator._processConfig.client-telemetry-connected',
44167
44478
  level: TelemetryLevel.Debug,
44168
- scope: config.telemetry.scope,
44169
- metadata: { ...config.telemetry.metadata, clientConfig },
44479
+ scope,
44480
+ metadata,
44170
44481
  });
44171
- // Auto-generate authority URL from tenant ID if not explicitly provided
44172
- // This simplifies configuration for most common cases
44173
- if (!clientConfig.auth.authority && clientConfig.auth.tenantId) {
44174
- clientConfig.auth.authority = `https://login.microsoftonline.com/${clientConfig.auth.tenantId}`;
44175
- }
44176
- // Set default cache location to localStorage for browser environments
44177
- // MSAL supports sessionStorage as well, but localStorage is the standard for persistent auth
44178
- if (!clientConfig.cache) {
44179
- clientConfig.cache = { cacheLocation: 'localStorage' };
44180
- }
44181
- // Integrate framework telemetry with MSAL logging system
44182
- // This allows MSAL events to flow through the framework's telemetry pipeline
44183
- if (!clientConfig.system?.loggerOptions && config.telemetry?.provider) {
44184
- const { provider, metadata, scope } = config.telemetry;
44185
- provider.trackEvent({
44186
- name: 'module-msal.configurator._processConfig.client-telemetry-connected',
44187
- level: TelemetryLevel.Debug,
44188
- scope,
44189
- metadata,
44190
- });
44191
- clientConfig.system = {
44192
- ...clientConfig.system,
44193
- loggerOptions: {
44194
- // Only log PII in development to protect user privacy in production
44195
- piiLoggingEnabled: process.env.NODE_ENV === 'development',
44196
- // Bridge MSAL log events to framework telemetry system
44197
- loggerCallback: createClientLogCallback(provider, metadata, [...scope, '3rd-party']),
44198
- // Use Warning level by default - captures errors and warnings without being verbose
44199
- logLevel: LogLevel.Warning,
44200
- // Preserve any user-provided logger options (allows customization)
44201
- ...clientConfig.system?.loggerOptions,
44202
- },
44203
- };
44204
- }
44205
- // Apply silent cache lookup policy if configured
44206
- if (config.cacheLookupPolicy !== undefined) {
44207
- clientConfig.cacheLookupPolicy = config.cacheLookupPolicy;
44208
- }
44209
- // Instantiate MSAL client with fully configured options
44210
- config.client = new MsalClient(clientConfig);
44482
+ clientConfig.system = {
44483
+ ...clientConfig.system,
44484
+ loggerOptions: {
44485
+ // Only log PII in development to protect user privacy in production
44486
+ piiLoggingEnabled: process.env.NODE_ENV === 'development',
44487
+ // Bridge MSAL log events to framework telemetry system
44488
+ loggerCallback: createClientLogCallback(provider, metadata, [...scope, '3rd-party']),
44489
+ // Use Warning level by default - captures errors and warnings without being verbose
44490
+ logLevel: LogLevel.Warning,
44491
+ // Preserve any user-provided logger options (allows customization)
44492
+ ...clientConfig.system?.loggerOptions,
44493
+ },
44494
+ };
44211
44495
  }
44212
- return config;
44496
+ // Apply silent cache lookup policy if configured
44497
+ if (config.cacheLookupPolicy !== undefined) {
44498
+ clientConfig.cacheLookupPolicy = config.cacheLookupPolicy;
44499
+ }
44500
+ return clientConfig;
44213
44501
  }
44214
44502
  }
44215
44503
 
@@ -44327,7 +44615,6 @@ class VersionError extends Error {
44327
44615
  * ```
44328
44616
  */
44329
44617
  function mapVersionToEnumVersion(version) {
44330
- console.log('Resolving version:', version);
44331
44618
  const coercedVersion = semver.coerce(version);
44332
44619
  // An uncoercible version string cannot be mapped to a module version
44333
44620
  if (!coercedVersion) {
@@ -48214,7 +48501,7 @@ class ServiceDiscoveryConfigurator extends BaseConfigBuilder {
48214
48501
  }
48215
48502
 
48216
48503
  // Generated by genversion.
48217
- const version$1 = '10.0.2';
48504
+ const version$1 = '10.1.0-next.0';
48218
48505
 
48219
48506
  /**
48220
48507
  * Default implementation of {@link IServiceDiscoveryProvider}.
@@ -48238,6 +48525,10 @@ class ServiceDiscoveryProvider extends BaseModuleProvider {
48238
48525
  this.config = config;
48239
48526
  this._http = _http;
48240
48527
  }
48528
+ /** {@inheritDoc IServiceDiscoveryProvider.client} */
48529
+ get client() {
48530
+ return this.config.discoveryClient;
48531
+ }
48241
48532
  /** {@inheritDoc IServiceDiscoveryProvider.resolveServices} */
48242
48533
  resolveServices() {
48243
48534
  return this.config.discoveryClient.resolveServices();
@@ -48352,8 +48643,9 @@ const configureServiceDiscovery = (callback) => ({
48352
48643
  *
48353
48644
  * @param configurator - The modules configurator to register the module on.
48354
48645
  * Must already include {@link HttpModule}.
48355
- * @param callback - Optional async callback receiving a
48356
- * {@link ServiceDiscoveryConfigurator} for advanced setup.
48646
+ * @param callback - Optional callback receiving a
48647
+ * {@link ServiceDiscoveryConfigurator} for advanced setup. May be synchronous
48648
+ * or asynchronous.
48357
48649
  *
48358
48650
  * @example
48359
48651
  * ```typescript
@@ -48848,7 +49140,7 @@ async function registerServiceWorker(framework) {
48848
49140
  }
48849
49141
 
48850
49142
  // Generated by genversion.
48851
- const version = '4.0.15';
49143
+ const version = '4.0.17-next.0';
48852
49144
 
48853
49145
  // Allow dynamic import without vite
48854
49146
  const importWithoutVite = (path) => import(/* @vite-ignore */ path);