@equinor/fusion-framework-vite-plugin-spa 4.0.8 → 4.0.9
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 +12 -0
- package/dist/esm/version.js +1 -1
- package/dist/html/bootstrap.js +1074 -582
- package/dist/html/bootstrap.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/html/index.html.d.ts +1 -1
- package/dist/types/version.d.ts +1 -1
- package/package.json +6 -6
- package/src/version.ts +1 -1
package/dist/html/bootstrap.js
CHANGED
|
@@ -5218,6 +5218,79 @@ class BaseConfigBuilder {
|
|
|
5218
5218
|
}
|
|
5219
5219
|
}
|
|
5220
5220
|
|
|
5221
|
+
/**
|
|
5222
|
+
* Error thrown when a required module fails to initialize within the expected
|
|
5223
|
+
* timeout window.
|
|
5224
|
+
*
|
|
5225
|
+
* Indicates a circular dependency or a module that never resolves.
|
|
5226
|
+
*/
|
|
5227
|
+
class RequiredModuleTimeoutError extends Error {
|
|
5228
|
+
constructor() {
|
|
5229
|
+
super('Module initialization timed out');
|
|
5230
|
+
this.name = 'RequiredModuleTimeoutError';
|
|
5231
|
+
}
|
|
5232
|
+
}
|
|
5233
|
+
|
|
5234
|
+
/** Shared base segment for module configurator lifecycle event names. */
|
|
5235
|
+
const ModuleConfiguratorEventBaseName = 'ModuleConfigurator';
|
|
5236
|
+
/**
|
|
5237
|
+
* Event names emitted by `ModulesConfigurator` and its lifecycle phase helpers.
|
|
5238
|
+
*
|
|
5239
|
+
* Use this map instead of inline string literals when emitting or filtering
|
|
5240
|
+
* configurator lifecycle events. Each value follows the
|
|
5241
|
+
* `ModuleConfigurator.{name}.{state}` convention. The emitted names are still
|
|
5242
|
+
* prefixed by `ModulesConfigurator::_registerEvent` at runtime.
|
|
5243
|
+
*/
|
|
5244
|
+
const ModuleConfiguratorEventName = {
|
|
5245
|
+
ModuleConfigAdded: `${ModuleConfiguratorEventBaseName}.module.configAdded`,
|
|
5246
|
+
OnConfiguredAdded: `${ModuleConfiguratorEventBaseName}.onConfigured.added`,
|
|
5247
|
+
OnInitializedAdded: `${ModuleConfiguratorEventBaseName}.onInitialized.added`,
|
|
5248
|
+
PluginAdded: `${ModuleConfiguratorEventBaseName}.plugin.added`,
|
|
5249
|
+
InitializeConfigLoaded: `${ModuleConfiguratorEventBaseName}.config.loaded`,
|
|
5250
|
+
InitializeInstanceInitialized: `${ModuleConfiguratorEventBaseName}.instance.initialized`,
|
|
5251
|
+
Initialize: `${ModuleConfiguratorEventBaseName}.initialize.complete`,
|
|
5252
|
+
ConfiguratorCreated: `${ModuleConfiguratorEventBaseName}.configurator.created`,
|
|
5253
|
+
ConfiguratorFailed: `${ModuleConfiguratorEventBaseName}.configurator.failed`,
|
|
5254
|
+
ModulePostConfigured: `${ModuleConfiguratorEventBaseName}.module.postConfigured`,
|
|
5255
|
+
ModulePostConfigureError: `${ModuleConfiguratorEventBaseName}.module.postConfigureError`,
|
|
5256
|
+
PostConfigureHooks: `${ModuleConfiguratorEventBaseName}.postConfigureHooks.started`,
|
|
5257
|
+
PostConfigureHooksComplete: `${ModuleConfiguratorEventBaseName}.postConfigureHooks.complete`,
|
|
5258
|
+
PostConfigureHooksError: `${ModuleConfiguratorEventBaseName}.postConfigureHooks.error`,
|
|
5259
|
+
ModuleInitializeError: `${ModuleConfiguratorEventBaseName}.module.initializeError`,
|
|
5260
|
+
ModuleInitializing: `${ModuleConfiguratorEventBaseName}.module.initializing`,
|
|
5261
|
+
ProviderNotBaseModuleProvider: `${ModuleConfiguratorEventBaseName}.provider.invalidBase`,
|
|
5262
|
+
ProviderVersionWarning: `${ModuleConfiguratorEventBaseName}.provider.versionMissing`,
|
|
5263
|
+
ModuleInitialized: `${ModuleConfiguratorEventBaseName}.module.initialized`,
|
|
5264
|
+
RequireInstanceModuleNotDefined: `${ModuleConfiguratorEventBaseName}.requireInstance.moduleNotDefined`,
|
|
5265
|
+
RequireInstanceModuleAlreadyInitialized: `${ModuleConfiguratorEventBaseName}.requireInstance.moduleAlreadyInitialized`,
|
|
5266
|
+
RequireInstanceAwaitingModule: `${ModuleConfiguratorEventBaseName}.requireInstance.awaitingModule`,
|
|
5267
|
+
RequireInstanceTimeout: `${ModuleConfiguratorEventBaseName}.requireInstance.timeout`,
|
|
5268
|
+
RequireInstanceModuleResolved: `${ModuleConfiguratorEventBaseName}.requireInstance.moduleResolved`,
|
|
5269
|
+
ModuleInitializeComplete: `${ModuleConfiguratorEventBaseName}.modules.initializeComplete`,
|
|
5270
|
+
InitializeComplete: `${ModuleConfiguratorEventBaseName}.initialize.instanceComplete`,
|
|
5271
|
+
ConfiguratorPostInitializeStart: `${ModuleConfiguratorEventBaseName}.postInitialize.started`,
|
|
5272
|
+
ModulePostInitializeStart: `${ModuleConfiguratorEventBaseName}.modulePostInitialize.started`,
|
|
5273
|
+
ModulePostInitializeComplete: `${ModuleConfiguratorEventBaseName}.modulePostInitialize.complete`,
|
|
5274
|
+
ModulePostInitializeError: `${ModuleConfiguratorEventBaseName}.modulePostInitialize.error`,
|
|
5275
|
+
PostInitializeComplete: `${ModuleConfiguratorEventBaseName}.postInitialize.complete`,
|
|
5276
|
+
PostInitializeCompleteNoHooks: `${ModuleConfiguratorEventBaseName}.postInitialize.noHooks`,
|
|
5277
|
+
PostInitializeHooks: `${ModuleConfiguratorEventBaseName}.postInitializeHooks.started`,
|
|
5278
|
+
PostInitializeHooksComplete: `${ModuleConfiguratorEventBaseName}.postInitializeHooks.complete`,
|
|
5279
|
+
PostInitializeHooksError: `${ModuleConfiguratorEventBaseName}.postInitializeHooks.error`,
|
|
5280
|
+
PluginsRegister: `${ModuleConfiguratorEventBaseName}.plugins.registering`,
|
|
5281
|
+
PluginRegistered: `${ModuleConfiguratorEventBaseName}.plugin.registered`,
|
|
5282
|
+
PluginRegisterError: `${ModuleConfiguratorEventBaseName}.plugin.registerError`,
|
|
5283
|
+
PluginsRegistered: `${ModuleConfiguratorEventBaseName}.plugins.registered`,
|
|
5284
|
+
Dispose: `${ModuleConfiguratorEventBaseName}.dispose.started`,
|
|
5285
|
+
PluginsDisposing: `${ModuleConfiguratorEventBaseName}.plugins.disposing`,
|
|
5286
|
+
PluginDisposed: `${ModuleConfiguratorEventBaseName}.plugin.disposed`,
|
|
5287
|
+
PluginDisposeError: `${ModuleConfiguratorEventBaseName}.plugin.disposeError`,
|
|
5288
|
+
ModulesDispose: `${ModuleConfiguratorEventBaseName}.modules.disposing`,
|
|
5289
|
+
ModuleDisposed: `${ModuleConfiguratorEventBaseName}.module.disposed`,
|
|
5290
|
+
ModuleDisposeError: `${ModuleConfiguratorEventBaseName}.module.disposeError`,
|
|
5291
|
+
ModulesDisposed: `${ModuleConfiguratorEventBaseName}.modules.disposed`,
|
|
5292
|
+
};
|
|
5293
|
+
|
|
5221
5294
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
5222
5295
|
/**
|
|
5223
5296
|
* Defines the severity levels for module events.
|
|
@@ -5238,6 +5311,170 @@ var ModuleEventLevel;
|
|
|
5238
5311
|
ModuleEventLevel[ModuleEventLevel["Critical"] = 4] = "Critical";
|
|
5239
5312
|
})(ModuleEventLevel || (ModuleEventLevel = {}));
|
|
5240
5313
|
|
|
5314
|
+
// biome-ignore-all lint/suspicious/noExplicitAny: internal type-erased dispatch — the configure phase coordinates opaque module configs without knowing their concrete shapes
|
|
5315
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
5316
|
+
/**
|
|
5317
|
+
* Creates the raw module config map by calling each module's `configure` factory.
|
|
5318
|
+
*
|
|
5319
|
+
* Runs all module `configure(ref)` calls concurrently via `mergeMap` and
|
|
5320
|
+
* accumulates results into a single config object. The object is seeded with
|
|
5321
|
+
* `onAfterConfiguration` and `onAfterInit` helpers that allow modules to
|
|
5322
|
+
* register additional post-phase callbacks during configuration.
|
|
5323
|
+
*
|
|
5324
|
+
* @param ctx - The configure phase context.
|
|
5325
|
+
* @param ref - Optional reference forwarded to each module's configure factory.
|
|
5326
|
+
* @returns A promise resolving to the merged module config map.
|
|
5327
|
+
* @internal
|
|
5328
|
+
*/
|
|
5329
|
+
async function createModuleConfigs(ctx, ref) {
|
|
5330
|
+
const { modules, afterConfiguration, afterInit, registerEvent } = ctx;
|
|
5331
|
+
const config$ = from(modules).pipe(mergeMap(async (module) => {
|
|
5332
|
+
const configStart = performance.now();
|
|
5333
|
+
try {
|
|
5334
|
+
const configurator = await module.configure?.(ref);
|
|
5335
|
+
const configLoadTime = Math.round(performance.now() - configStart);
|
|
5336
|
+
registerEvent({
|
|
5337
|
+
level: ModuleEventLevel.Debug,
|
|
5338
|
+
name: ModuleConfiguratorEventName.ConfiguratorCreated,
|
|
5339
|
+
message: `Configurator created for ${module.name} in ${configLoadTime}ms`,
|
|
5340
|
+
properties: {
|
|
5341
|
+
moduleName: module.name,
|
|
5342
|
+
moduleVersion: module.version?.toString() || 'unknown',
|
|
5343
|
+
configLoadTime,
|
|
5344
|
+
},
|
|
5345
|
+
metric: configLoadTime,
|
|
5346
|
+
});
|
|
5347
|
+
return { [module.name]: configurator };
|
|
5348
|
+
}
|
|
5349
|
+
catch (err) {
|
|
5350
|
+
registerEvent({
|
|
5351
|
+
level: ModuleEventLevel.Error,
|
|
5352
|
+
name: ModuleConfiguratorEventName.ConfiguratorFailed,
|
|
5353
|
+
message: `Failed to create configurator for ${module.name}`,
|
|
5354
|
+
properties: {
|
|
5355
|
+
moduleName: module.name,
|
|
5356
|
+
moduleVersion: module.version?.toString() || 'unknown',
|
|
5357
|
+
},
|
|
5358
|
+
metric: Math.round(performance.now() - configStart),
|
|
5359
|
+
error: err,
|
|
5360
|
+
});
|
|
5361
|
+
throw err;
|
|
5362
|
+
}
|
|
5363
|
+
}), reduce((acc, module) => Object.assign(acc, module),
|
|
5364
|
+
// Seed the config object with hooks so modules can register post-phase callbacks
|
|
5365
|
+
// during their own configure factory (a common pattern for cross-module wiring).
|
|
5366
|
+
{
|
|
5367
|
+
onAfterConfiguration(cb) {
|
|
5368
|
+
afterConfiguration.push(cb);
|
|
5369
|
+
},
|
|
5370
|
+
onAfterInit(cb) {
|
|
5371
|
+
afterInit.push(cb);
|
|
5372
|
+
},
|
|
5373
|
+
}));
|
|
5374
|
+
return lastValueFrom(config$);
|
|
5375
|
+
}
|
|
5376
|
+
/**
|
|
5377
|
+
* Runs the post-configure phase: calls each module's `postConfigure` hook and
|
|
5378
|
+
* then invokes all registered `afterConfiguration` callbacks.
|
|
5379
|
+
*
|
|
5380
|
+
* Module `postConfigure` failures are caught individually and emitted as
|
|
5381
|
+
* Warning events so one failing module cannot block others.
|
|
5382
|
+
*
|
|
5383
|
+
* @param ctx - The configure phase context.
|
|
5384
|
+
* @param config - The merged module config map produced by {@link createModuleConfigs}.
|
|
5385
|
+
* @returns A promise resolving when all post-configure hooks have settled.
|
|
5386
|
+
* @internal
|
|
5387
|
+
*/
|
|
5388
|
+
async function runPostConfigureHooks(ctx, config) {
|
|
5389
|
+
const { modules, afterConfiguration, registerEvent } = ctx;
|
|
5390
|
+
// Run each module's postConfigure hook; failures are isolated so one
|
|
5391
|
+
// failing module does not prevent others from completing post-configure.
|
|
5392
|
+
await Promise.allSettled(modules
|
|
5393
|
+
.filter((module) => !!module.postConfigure)
|
|
5394
|
+
.map(async (module) => {
|
|
5395
|
+
try {
|
|
5396
|
+
const postConfigStart = performance.now();
|
|
5397
|
+
await module.postConfigure?.(config);
|
|
5398
|
+
registerEvent({
|
|
5399
|
+
level: ModuleEventLevel.Debug,
|
|
5400
|
+
name: ModuleConfiguratorEventName.ModulePostConfigured,
|
|
5401
|
+
message: `Module ${module.name} post-configured successfully`,
|
|
5402
|
+
properties: {
|
|
5403
|
+
moduleName: module.name,
|
|
5404
|
+
moduleVersion: module.version?.toString() || 'unknown',
|
|
5405
|
+
postConfigTime: Math.round(performance.now() - postConfigStart),
|
|
5406
|
+
},
|
|
5407
|
+
});
|
|
5408
|
+
}
|
|
5409
|
+
catch (err) {
|
|
5410
|
+
registerEvent({
|
|
5411
|
+
level: ModuleEventLevel.Warning,
|
|
5412
|
+
name: ModuleConfiguratorEventName.ModulePostConfigureError,
|
|
5413
|
+
message: `Module ${module.name} post-configure failed`,
|
|
5414
|
+
properties: {
|
|
5415
|
+
moduleName: module.name,
|
|
5416
|
+
moduleVersion: module.version?.toString() || 'unknown',
|
|
5417
|
+
},
|
|
5418
|
+
error: err,
|
|
5419
|
+
});
|
|
5420
|
+
}
|
|
5421
|
+
}));
|
|
5422
|
+
if (!afterConfiguration.length)
|
|
5423
|
+
return;
|
|
5424
|
+
// Run all registered afterConfiguration callbacks. These were added either
|
|
5425
|
+
// by addConfig's afterConfig or via config.onAfterConfiguration inside a
|
|
5426
|
+
// module's configure factory.
|
|
5427
|
+
try {
|
|
5428
|
+
registerEvent({
|
|
5429
|
+
level: ModuleEventLevel.Debug,
|
|
5430
|
+
name: ModuleConfiguratorEventName.PostConfigureHooks,
|
|
5431
|
+
message: `Post configure hooks [${afterConfiguration.length}] called`,
|
|
5432
|
+
});
|
|
5433
|
+
const postConfigHooksStart = performance.now();
|
|
5434
|
+
await Promise.allSettled(afterConfiguration.map((x) => Promise.resolve(x(config))));
|
|
5435
|
+
const postConfigHooksTime = Math.round(performance.now() - postConfigHooksStart);
|
|
5436
|
+
registerEvent({
|
|
5437
|
+
level: ModuleEventLevel.Debug,
|
|
5438
|
+
name: ModuleConfiguratorEventName.PostConfigureHooksComplete,
|
|
5439
|
+
message: 'Post configure hooks complete',
|
|
5440
|
+
properties: {
|
|
5441
|
+
count: afterConfiguration.length,
|
|
5442
|
+
postConfigHooksTime,
|
|
5443
|
+
},
|
|
5444
|
+
metric: postConfigHooksTime,
|
|
5445
|
+
});
|
|
5446
|
+
}
|
|
5447
|
+
catch (err) {
|
|
5448
|
+
registerEvent({
|
|
5449
|
+
level: ModuleEventLevel.Warning,
|
|
5450
|
+
name: ModuleConfiguratorEventName.PostConfigureHooksError,
|
|
5451
|
+
message: 'Post configure hook failed',
|
|
5452
|
+
error: err,
|
|
5453
|
+
});
|
|
5454
|
+
}
|
|
5455
|
+
}
|
|
5456
|
+
/**
|
|
5457
|
+
* Runs the full configure lifecycle phase for a set of modules.
|
|
5458
|
+
*
|
|
5459
|
+
* Orchestrates three sub-steps in order:
|
|
5460
|
+
* 1. {@link createModuleConfigs} — call each module's `configure(ref)` factory.
|
|
5461
|
+
* 2. Apply all user-registered config callbacks (`_configs`) sequentially.
|
|
5462
|
+
* 3. {@link runPostConfigureHooks} — call `postConfigure` and `afterConfiguration` hooks.
|
|
5463
|
+
*
|
|
5464
|
+
* @param ctx - The configure phase context.
|
|
5465
|
+
* @param ref - Optional reference forwarded through all configure hooks.
|
|
5466
|
+
* @returns A promise resolving to the fully configured module config map.
|
|
5467
|
+
*/
|
|
5468
|
+
async function runConfigurePhase(ctx, ref) {
|
|
5469
|
+
// Step 1: Create raw config objects for all registered modules
|
|
5470
|
+
const config = await createModuleConfigs(ctx, ref);
|
|
5471
|
+
// Step 2: Apply all user-registered configuration callbacks concurrently.
|
|
5472
|
+
await Promise.all(ctx.configs.map((cb) => Promise.resolve(cb(config, ref))));
|
|
5473
|
+
// Step 3: Run module postConfigure hooks and afterConfiguration callbacks
|
|
5474
|
+
await runPostConfigureHooks(ctx, config);
|
|
5475
|
+
return config;
|
|
5476
|
+
}
|
|
5477
|
+
|
|
5241
5478
|
/**
|
|
5242
5479
|
* Abstract base class for Fusion Framework module providers.
|
|
5243
5480
|
*
|
|
@@ -5325,37 +5562,624 @@ class BaseModuleProvider {
|
|
|
5325
5562
|
}
|
|
5326
5563
|
}
|
|
5327
5564
|
|
|
5328
|
-
|
|
5329
|
-
|
|
5565
|
+
/**
|
|
5566
|
+
* Initializes a single module and emits a `[name, instance]` tuple when complete.
|
|
5567
|
+
*
|
|
5568
|
+
* Validates that the module exposes an `initialize` method, calls it with the
|
|
5569
|
+
* provided context, and emits lifecycle events for start, completion, and any
|
|
5570
|
+
* provider contract warnings.
|
|
5571
|
+
*
|
|
5572
|
+
* @internal
|
|
5573
|
+
*/
|
|
5574
|
+
async function initializeModule(module, ctx) {
|
|
5575
|
+
const { config, ref, requireInstance, hasModule, registerEvent } = ctx;
|
|
5576
|
+
const key = module.name;
|
|
5577
|
+
if (!module.initialize) {
|
|
5578
|
+
const error = new Error(`Module ${module.name} does not have initialize method`);
|
|
5579
|
+
error.name = 'ModuleInitializeError';
|
|
5580
|
+
registerEvent({
|
|
5581
|
+
level: ModuleEventLevel.Error,
|
|
5582
|
+
name: ModuleConfiguratorEventName.ModuleInitializeError,
|
|
5583
|
+
message: error.message,
|
|
5584
|
+
properties: {
|
|
5585
|
+
moduleName: module.name,
|
|
5586
|
+
moduleVersion: module.version?.toString() || 'unknown',
|
|
5587
|
+
},
|
|
5588
|
+
error,
|
|
5589
|
+
});
|
|
5590
|
+
throw error;
|
|
5591
|
+
}
|
|
5592
|
+
registerEvent({
|
|
5593
|
+
level: ModuleEventLevel.Debug,
|
|
5594
|
+
name: ModuleConfiguratorEventName.ModuleInitializing,
|
|
5595
|
+
message: `Initializing module ${module.name}`,
|
|
5596
|
+
properties: {
|
|
5597
|
+
moduleName: module.name,
|
|
5598
|
+
moduleVersion: module.version?.toString() || 'unknown',
|
|
5599
|
+
},
|
|
5600
|
+
});
|
|
5601
|
+
const moduleInitStart = performance.now();
|
|
5602
|
+
const instance = await module.initialize({
|
|
5603
|
+
ref,
|
|
5604
|
+
config: config[key],
|
|
5605
|
+
requireInstance,
|
|
5606
|
+
hasModule,
|
|
5607
|
+
});
|
|
5608
|
+
// Warn when providers deviate from the expected base class — these modules
|
|
5609
|
+
// may lack version tracking and standard provider interfaces.
|
|
5610
|
+
if (!(instance instanceof BaseModuleProvider)) {
|
|
5611
|
+
registerEvent({
|
|
5612
|
+
level: ModuleEventLevel.Warning,
|
|
5613
|
+
name: ModuleConfiguratorEventName.ProviderNotBaseModuleProvider,
|
|
5614
|
+
message: `Provider for module ${module.name} does not extend BaseModuleProvider`,
|
|
5615
|
+
properties: {
|
|
5616
|
+
moduleName: module.name,
|
|
5617
|
+
moduleVersion: module.version?.toString() || 'unknown',
|
|
5618
|
+
},
|
|
5619
|
+
});
|
|
5620
|
+
}
|
|
5621
|
+
// Providers should expose a version string for diagnostics and compatibility checks.
|
|
5622
|
+
// Warn when absent so module authors catch missing version early rather than at runtime.
|
|
5623
|
+
const maybeVersioned = instance;
|
|
5624
|
+
if (!maybeVersioned.version) {
|
|
5625
|
+
registerEvent({
|
|
5626
|
+
level: ModuleEventLevel.Warning,
|
|
5627
|
+
name: ModuleConfiguratorEventName.ProviderVersionWarning,
|
|
5628
|
+
message: `Provider for module ${module.name} does not expose version`,
|
|
5629
|
+
properties: {
|
|
5630
|
+
moduleName: module.name,
|
|
5631
|
+
moduleVersion: module.version?.toString() || 'unknown',
|
|
5632
|
+
},
|
|
5633
|
+
});
|
|
5634
|
+
}
|
|
5635
|
+
const moduleInitTime = Math.round(performance.now() - moduleInitStart);
|
|
5636
|
+
registerEvent({
|
|
5637
|
+
level: ModuleEventLevel.Debug,
|
|
5638
|
+
name: ModuleConfiguratorEventName.ModuleInitialized,
|
|
5639
|
+
message: `Module ${module.name} initialized in ${moduleInitTime}ms`,
|
|
5640
|
+
properties: {
|
|
5641
|
+
moduleName: module.name,
|
|
5642
|
+
moduleVersion: module.version?.toString() || 'unknown',
|
|
5643
|
+
providerName: typeof instance,
|
|
5644
|
+
providerVersion: maybeVersioned.version?.toString() || 'unknown',
|
|
5645
|
+
moduleInitTime,
|
|
5646
|
+
},
|
|
5647
|
+
metric: moduleInitTime,
|
|
5648
|
+
});
|
|
5649
|
+
return [key, instance];
|
|
5650
|
+
}
|
|
5651
|
+
/**
|
|
5652
|
+
* Creates a `requireInstance` resolver for use during module initialization.
|
|
5653
|
+
*
|
|
5654
|
+
* `requireInstance` is passed into each module's `initialize` call so it can
|
|
5655
|
+
* declare dependencies on other modules without knowing whether those modules
|
|
5656
|
+
* have already finished initializing. The resolver waits up to `wait` seconds
|
|
5657
|
+
* for the target module to appear in the shared `instance$` subject.
|
|
5658
|
+
*
|
|
5659
|
+
* @param moduleNames - Names of all modules registered in this initialization run.
|
|
5660
|
+
* @param instance$ - Shared subject accumulating initialized module instances.
|
|
5661
|
+
* @param registerEvent - Function to emit lifecycle events.
|
|
5662
|
+
* @returns A `requireInstance` function matching the shape expected by `ModuleInitializerArgs`.
|
|
5663
|
+
* @internal
|
|
5664
|
+
*/
|
|
5665
|
+
function createRequireInstance(moduleNames, instance$, registerEvent) {
|
|
5666
|
+
// The implementation signature is concrete (name: string) but the public contract
|
|
5667
|
+
// must be the generic shape expected by ModuleInitializerArgs. Module names are
|
|
5668
|
+
// always strings at runtime — the keyof-derived `string | number` constraint comes
|
|
5669
|
+
// from TypeScript's keyof semantics, not actual usage.
|
|
5670
|
+
return function requireInstance(name, wait = 60) {
|
|
5671
|
+
// Fail fast if the caller requests a module that was never registered —
|
|
5672
|
+
// this almost always indicates a misconfiguration rather than a timing issue.
|
|
5673
|
+
if (!moduleNames.includes(name)) {
|
|
5674
|
+
const error = new Error(`Cannot require [${String(name)}] since module is not defined!`);
|
|
5675
|
+
error.name = 'ModuleNotDefinedError';
|
|
5676
|
+
registerEvent({
|
|
5677
|
+
level: ModuleEventLevel.Error,
|
|
5678
|
+
name: ModuleConfiguratorEventName.RequireInstanceModuleNotDefined,
|
|
5679
|
+
message: error.message,
|
|
5680
|
+
properties: { moduleName: String(name), wait },
|
|
5681
|
+
error,
|
|
5682
|
+
});
|
|
5683
|
+
throw error;
|
|
5684
|
+
}
|
|
5685
|
+
// Short-circuit: module is already in the accumulated instance object
|
|
5686
|
+
if (instance$.value[name]) {
|
|
5687
|
+
registerEvent({
|
|
5688
|
+
level: ModuleEventLevel.Debug,
|
|
5689
|
+
name: ModuleConfiguratorEventName.RequireInstanceModuleAlreadyInitialized,
|
|
5690
|
+
message: `Module [${String(name)}] is already initialized, skipping queue`,
|
|
5691
|
+
properties: { moduleName: String(name), wait },
|
|
5692
|
+
});
|
|
5693
|
+
return Promise.resolve(instance$.value[name]);
|
|
5694
|
+
}
|
|
5695
|
+
const requireStart = performance.now();
|
|
5696
|
+
registerEvent({
|
|
5697
|
+
level: ModuleEventLevel.Debug,
|
|
5698
|
+
name: ModuleConfiguratorEventName.RequireInstanceAwaitingModule,
|
|
5699
|
+
message: `Awaiting module [${String(name)}] initialization, timeout ${wait}s`,
|
|
5700
|
+
properties: { moduleName: String(name), wait },
|
|
5701
|
+
});
|
|
5702
|
+
// Wait for the module to appear in the shared instance subject, up to `wait` seconds.
|
|
5703
|
+
return firstValueFrom(instance$.pipe(
|
|
5704
|
+
// Ignore emissions until the requested module has been added to the instance map.
|
|
5705
|
+
filter((x) => !!x[name]),
|
|
5706
|
+
// Resolve the dependency promise with the provider instance, not the full module map.
|
|
5707
|
+
map$1((x) => x[name]),
|
|
5708
|
+
// Convert unresolved dependencies into a typed timeout error with lifecycle diagnostics.
|
|
5709
|
+
timeout({
|
|
5710
|
+
// requireInstance accepts seconds; RxJS timeout expects milliseconds.
|
|
5711
|
+
each: wait * 1000,
|
|
5712
|
+
with: () => throwError(() => {
|
|
5713
|
+
const error = new RequiredModuleTimeoutError();
|
|
5714
|
+
registerEvent({
|
|
5715
|
+
level: ModuleEventLevel.Error,
|
|
5716
|
+
name: ModuleConfiguratorEventName.RequireInstanceTimeout,
|
|
5717
|
+
message: `Module [${String(name)}] initialization timed out after ${wait}s`,
|
|
5718
|
+
properties: { moduleName: String(name), wait },
|
|
5719
|
+
error,
|
|
5720
|
+
});
|
|
5721
|
+
return error;
|
|
5722
|
+
}),
|
|
5723
|
+
}),
|
|
5724
|
+
// Emit timing diagnostics only after the dependency has actually resolved.
|
|
5725
|
+
tap(() => {
|
|
5726
|
+
const requireTime = Math.round(performance.now() - requireStart);
|
|
5727
|
+
registerEvent({
|
|
5728
|
+
level: ModuleEventLevel.Debug,
|
|
5729
|
+
name: ModuleConfiguratorEventName.RequireInstanceModuleResolved,
|
|
5730
|
+
message: `Module [${String(name)}] required in ${requireTime}ms`,
|
|
5731
|
+
properties: { moduleName: String(name), wait, requireTime },
|
|
5732
|
+
metric: requireTime,
|
|
5733
|
+
});
|
|
5734
|
+
})));
|
|
5735
|
+
};
|
|
5736
|
+
}
|
|
5737
|
+
/**
|
|
5738
|
+
* Runs the initialize lifecycle phase for all registered modules.
|
|
5739
|
+
*
|
|
5740
|
+
* Initializes all modules **concurrently** using `mergeMap`. Cross-module
|
|
5741
|
+
* dependency ordering is handled lazily through `requireInstance`, which
|
|
5742
|
+
* waits for a peer module's `initialize` call to complete before resolving.
|
|
5743
|
+
*
|
|
5744
|
+
* Each initialized provider is accumulated into a shared `BehaviorSubject` so
|
|
5745
|
+
* that `requireInstance` callers see updates as soon as a dependency is ready.
|
|
5746
|
+
*
|
|
5747
|
+
* @param ctx - The initialize phase context.
|
|
5748
|
+
* @param config - The merged module config map produced by the configure phase.
|
|
5749
|
+
* @param ref - Optional reference forwarded to each module's `initialize` call.
|
|
5750
|
+
* @returns A promise resolving to the sealed map of initialized module providers.
|
|
5751
|
+
* @throws {Error} When a module's `initialize` method is missing.
|
|
5752
|
+
* @throws {RequiredModuleTimeoutError} When a required dependency does not
|
|
5753
|
+
* initialize within its timeout window.
|
|
5754
|
+
*/
|
|
5755
|
+
async function runInitializePhase(ctx, config, ref) {
|
|
5756
|
+
const { modules, registerEvent } = ctx;
|
|
5757
|
+
// Fast-path: no modules registered — return a sealed empty instance immediately
|
|
5758
|
+
// to avoid a subscribe/lastValueFrom race on an already-completed observable.
|
|
5759
|
+
if (modules.length === 0) {
|
|
5760
|
+
return Object.seal({});
|
|
5761
|
+
}
|
|
5762
|
+
const moduleNames = modules.map((m) => m.name);
|
|
5763
|
+
// Accumulates initialized module providers; BehaviorSubject lets requireInstance
|
|
5764
|
+
// reactively wait for a dependency to appear without polling.
|
|
5765
|
+
const instance$ = new BehaviorSubject({});
|
|
5766
|
+
const hasModule = (name) => moduleNames.includes(name);
|
|
5767
|
+
const requireInstance = createRequireInstance(moduleNames, instance$, registerEvent);
|
|
5768
|
+
// Initialize all modules concurrently; modules that depend on peers will
|
|
5769
|
+
// suspend inside requireInstance until the dependency resolves.
|
|
5770
|
+
const init$ = from(modules).pipe(mergeMap((module) => initializeModule(module, { config, ref, requireInstance, hasModule, registerEvent })));
|
|
5771
|
+
const initStart = performance.now();
|
|
5772
|
+
// Accumulate module providers into the shared instance subject as each resolves.
|
|
5773
|
+
// Completing the subject signals that all modules are initialized.
|
|
5774
|
+
init$.subscribe({
|
|
5775
|
+
next: ([name, module]) => {
|
|
5776
|
+
instance$.next(Object.assign(instance$.value, { [name]: module }));
|
|
5777
|
+
},
|
|
5778
|
+
error: (err) => {
|
|
5779
|
+
registerEvent({
|
|
5780
|
+
level: ModuleEventLevel.Error,
|
|
5781
|
+
name: ModuleConfiguratorEventName.ModuleInitializeError,
|
|
5782
|
+
message: `Failed to initialize module ${err.name || 'unknown'}`,
|
|
5783
|
+
error: err,
|
|
5784
|
+
});
|
|
5785
|
+
instance$.error(err);
|
|
5786
|
+
},
|
|
5787
|
+
complete: () => {
|
|
5788
|
+
const loadTime = Math.round(performance.now() - initStart);
|
|
5789
|
+
registerEvent({
|
|
5790
|
+
level: ModuleEventLevel.Debug,
|
|
5791
|
+
name: ModuleConfiguratorEventName.ModuleInitializeComplete,
|
|
5792
|
+
message: `All modules initialized in ${loadTime}ms`,
|
|
5793
|
+
properties: {
|
|
5794
|
+
modules: Object.keys(instance$.value).join(', '),
|
|
5795
|
+
loadTime,
|
|
5796
|
+
},
|
|
5797
|
+
metric: loadTime,
|
|
5798
|
+
});
|
|
5799
|
+
instance$.complete();
|
|
5800
|
+
},
|
|
5801
|
+
});
|
|
5802
|
+
const instanceInitStart = performance.now();
|
|
5803
|
+
const instance = await lastValueFrom(instance$);
|
|
5804
|
+
const initTime = Math.round(performance.now() - instanceInitStart);
|
|
5805
|
+
registerEvent({
|
|
5806
|
+
level: ModuleEventLevel.Debug,
|
|
5807
|
+
name: ModuleConfiguratorEventName.InitializeComplete,
|
|
5808
|
+
message: `Modules instance created in ${initTime}ms`,
|
|
5809
|
+
properties: {
|
|
5810
|
+
modules: Object.keys(instance).join(', '),
|
|
5811
|
+
initTime,
|
|
5812
|
+
},
|
|
5813
|
+
metric: initTime,
|
|
5814
|
+
});
|
|
5815
|
+
Object.seal(instance);
|
|
5816
|
+
return instance;
|
|
5817
|
+
}
|
|
5818
|
+
|
|
5819
|
+
// biome-ignore-all lint/suspicious/noExplicitAny: internal type-erased dispatch — the post-initialize phase forwards opaque instances without inspecting their concrete shapes
|
|
5820
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
5821
|
+
/**
|
|
5822
|
+
* Runs the post-initialize lifecycle phase for all registered modules.
|
|
5823
|
+
*
|
|
5824
|
+
* Executes two sub-steps in order:
|
|
5825
|
+
* 1. Calls each module's `postInitialize` hook (if defined) concurrently.
|
|
5826
|
+
* Individual failures are caught and emitted as Warning events so one
|
|
5827
|
+
* failing module cannot block others.
|
|
5828
|
+
* 2. Runs all registered `afterInit` callbacks concurrently via `Promise.allSettled`.
|
|
5829
|
+
*
|
|
5830
|
+
* @param ctx - The post-initialize phase context.
|
|
5831
|
+
* @param instance - The sealed module instance map produced by the initialize phase.
|
|
5832
|
+
* @param ref - Optional reference forwarded to each module's `postInitialize` call.
|
|
5833
|
+
* @returns A promise resolving when all post-initialize hooks and callbacks have settled.
|
|
5834
|
+
*/
|
|
5835
|
+
async function runPostInitializePhase(ctx, instance, ref) {
|
|
5836
|
+
const { modules, afterInit, registerEvent } = ctx;
|
|
5837
|
+
registerEvent({
|
|
5838
|
+
level: ModuleEventLevel.Debug,
|
|
5839
|
+
name: ModuleConfiguratorEventName.ConfiguratorPostInitializeStart,
|
|
5840
|
+
message: `Post-initializing all modules [${Object.keys(instance).length}]`,
|
|
5841
|
+
properties: { modules: Object.keys(instance).join(', ') },
|
|
5842
|
+
});
|
|
5843
|
+
// Run postInitialize hooks for modules that declare them. Failures are caught
|
|
5844
|
+
// per-module via catchError so one failure does not abort the others.
|
|
5845
|
+
const postInitialize$ = from(modules).pipe(filter((module) => !!module.postInitialize), tap((module) => {
|
|
5846
|
+
registerEvent({
|
|
5847
|
+
level: ModuleEventLevel.Debug,
|
|
5848
|
+
name: ModuleConfiguratorEventName.ModulePostInitializeStart,
|
|
5849
|
+
message: `Module ${module.name} is being post-initialized`,
|
|
5850
|
+
properties: {
|
|
5851
|
+
moduleName: module.name,
|
|
5852
|
+
moduleVersion: module.version?.toString() || 'unknown',
|
|
5853
|
+
},
|
|
5854
|
+
});
|
|
5855
|
+
}), mergeMap((module) => {
|
|
5856
|
+
const postInitStart = performance.now();
|
|
5857
|
+
return from(module.postInitialize({
|
|
5858
|
+
ref,
|
|
5859
|
+
modules: instance,
|
|
5860
|
+
instance: instance[module.name],
|
|
5861
|
+
})).pipe(tap(() => {
|
|
5862
|
+
const postInitTime = Math.round(performance.now() - postInitStart);
|
|
5863
|
+
registerEvent({
|
|
5864
|
+
level: ModuleEventLevel.Debug,
|
|
5865
|
+
name: ModuleConfiguratorEventName.ModulePostInitializeComplete,
|
|
5866
|
+
message: `Module ${module.name} has been post-initialized in ${postInitTime}ms`,
|
|
5867
|
+
metric: postInitTime,
|
|
5868
|
+
properties: {
|
|
5869
|
+
moduleName: module.name,
|
|
5870
|
+
moduleVersion: module.version?.toString() || 'unknown',
|
|
5871
|
+
postInitTime,
|
|
5872
|
+
},
|
|
5873
|
+
});
|
|
5874
|
+
}), defaultIfEmpty(null), catchError((err) => {
|
|
5875
|
+
registerEvent({
|
|
5876
|
+
level: ModuleEventLevel.Warning,
|
|
5877
|
+
name: ModuleConfiguratorEventName.ModulePostInitializeError,
|
|
5878
|
+
message: `Module ${module.name} post-initialize failed`,
|
|
5879
|
+
properties: {
|
|
5880
|
+
moduleName: module.name,
|
|
5881
|
+
moduleVersion: module.version?.toString() || 'unknown',
|
|
5882
|
+
},
|
|
5883
|
+
error: err,
|
|
5884
|
+
});
|
|
5885
|
+
// Swallow module-level errors — a failing postInitialize should not
|
|
5886
|
+
// prevent other modules from completing their post-initialize work.
|
|
5887
|
+
return EMPTY;
|
|
5888
|
+
}));
|
|
5889
|
+
}), defaultIfEmpty(null));
|
|
5890
|
+
const postInitStart = performance.now();
|
|
5891
|
+
await lastValueFrom(postInitialize$);
|
|
5892
|
+
const postInitTime = Math.round(performance.now() - postInitStart);
|
|
5893
|
+
registerEvent({
|
|
5894
|
+
level: ModuleEventLevel.Debug,
|
|
5895
|
+
name: ModuleConfiguratorEventName.PostInitializeComplete,
|
|
5896
|
+
message: `Post-initialization of all modules completed in ${postInitTime}ms`,
|
|
5897
|
+
properties: { modules: Object.keys(instance).join(', '), postInitTime },
|
|
5898
|
+
metric: postInitTime,
|
|
5899
|
+
});
|
|
5900
|
+
if (!afterInit.length) {
|
|
5901
|
+
registerEvent({
|
|
5902
|
+
level: ModuleEventLevel.Debug,
|
|
5903
|
+
name: ModuleConfiguratorEventName.PostInitializeCompleteNoHooks,
|
|
5904
|
+
message: 'Post-initialization complete',
|
|
5905
|
+
properties: { modules: Object.keys(instance).join(', '), postInitCompleteTime: postInitTime },
|
|
5906
|
+
});
|
|
5907
|
+
return;
|
|
5908
|
+
}
|
|
5909
|
+
// Run all registered afterInit callbacks. These were added either by
|
|
5910
|
+
// addConfig's afterInit or via onInitialized on the configurator.
|
|
5911
|
+
try {
|
|
5912
|
+
registerEvent({
|
|
5913
|
+
level: ModuleEventLevel.Debug,
|
|
5914
|
+
name: ModuleConfiguratorEventName.PostInitializeHooks,
|
|
5915
|
+
message: `Executing post-initialize hooks [${afterInit.length}]`,
|
|
5916
|
+
properties: { hooks: afterInit.map((x) => x.name || 'anonymous').join(', ') },
|
|
5917
|
+
});
|
|
5918
|
+
const afterInitStart = performance.now();
|
|
5919
|
+
await Promise.allSettled(afterInit.map((x) => Promise.resolve(x(instance))));
|
|
5920
|
+
const afterInitTime = Math.round(performance.now() - afterInitStart);
|
|
5921
|
+
registerEvent({
|
|
5922
|
+
level: ModuleEventLevel.Debug,
|
|
5923
|
+
name: ModuleConfiguratorEventName.PostInitializeHooksComplete,
|
|
5924
|
+
message: `Post-initialize hooks completed in ${afterInitTime}ms`,
|
|
5925
|
+
properties: {
|
|
5926
|
+
hooks: afterInit.map((x) => x.name || 'anonymous').join(', '),
|
|
5927
|
+
afterInitTime,
|
|
5928
|
+
},
|
|
5929
|
+
metric: afterInitTime,
|
|
5930
|
+
});
|
|
5931
|
+
}
|
|
5932
|
+
catch (err) {
|
|
5933
|
+
registerEvent({
|
|
5934
|
+
level: ModuleEventLevel.Warning,
|
|
5935
|
+
name: ModuleConfiguratorEventName.PostInitializeHooksError,
|
|
5936
|
+
message: 'Post-initialize hooks failed',
|
|
5937
|
+
properties: { hooks: afterInit.map((x) => x.name || 'anonymous').join(', ') },
|
|
5938
|
+
error: err,
|
|
5939
|
+
});
|
|
5940
|
+
}
|
|
5941
|
+
const postInitCompleteTime = Math.round(performance.now() - postInitStart);
|
|
5942
|
+
registerEvent({
|
|
5943
|
+
level: ModuleEventLevel.Debug,
|
|
5944
|
+
name: ModuleConfiguratorEventName.PostInitializeComplete,
|
|
5945
|
+
message: 'Post-initialization complete',
|
|
5946
|
+
properties: { modules: Object.keys(instance).join(', '), postInitCompleteTime },
|
|
5947
|
+
});
|
|
5948
|
+
}
|
|
5330
5949
|
|
|
5950
|
+
// biome-ignore-all lint/suspicious/noExplicitAny: internal type-erased dispatch — plugins are registered with concrete module maps but stored erased by the orchestrator
|
|
5331
5951
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
5332
5952
|
/**
|
|
5333
|
-
*
|
|
5953
|
+
* Checks whether a plugin return value should be treated as dispose-time cleanup.
|
|
5954
|
+
*
|
|
5955
|
+
* Plugins may return either a plain callback or an object with a `dispose` method.
|
|
5956
|
+
* Any other value is ignored so plugin authors can return `undefined` when no
|
|
5957
|
+
* cleanup is needed.
|
|
5334
5958
|
*
|
|
5335
|
-
*
|
|
5336
|
-
*
|
|
5959
|
+
* @param value - Value returned by a registered plugin callback.
|
|
5960
|
+
* @returns True when the value is a valid plugin teardown registration.
|
|
5337
5961
|
*/
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5962
|
+
function isPluginTeardown(value) {
|
|
5963
|
+
return (typeof value === 'function' ||
|
|
5964
|
+
(typeof value === 'object' &&
|
|
5965
|
+
value !== null &&
|
|
5966
|
+
'dispose' in value &&
|
|
5967
|
+
typeof value.dispose === 'function'));
|
|
5968
|
+
}
|
|
5969
|
+
/**
|
|
5970
|
+
* Runs configurator plugins after modules are ready.
|
|
5971
|
+
*
|
|
5972
|
+
* The plugin phase is the final initialization step before `initialize()`
|
|
5973
|
+
* resolves. Each plugin receives the sealed module instance map and optional
|
|
5974
|
+
* initialization reference, which makes this phase suitable for application
|
|
5975
|
+
* side effects such as telemetry bridges, global event listeners, and runtime
|
|
5976
|
+
* subscriptions that require multiple initialized module providers.
|
|
5977
|
+
*
|
|
5978
|
+
* Plugin callbacks run concurrently. Failures are isolated and emitted as
|
|
5979
|
+
* warning events so one failing side effect cannot block application rendering.
|
|
5980
|
+
* Returned teardown callbacks are stored for the dispose phase and are invoked
|
|
5981
|
+
* before module `dispose` hooks.
|
|
5982
|
+
*
|
|
5983
|
+
* @param ctx - The plugin phase context.
|
|
5984
|
+
* @param modules - The initialized module instance map.
|
|
5985
|
+
* @param ref - Optional reference forwarded from module initialization.
|
|
5986
|
+
* @returns A promise resolving when all plugin callbacks have settled.
|
|
5987
|
+
*/
|
|
5988
|
+
async function runPluginPhase(ctx, modules, ref) {
|
|
5989
|
+
const { plugins, teardowns, registerEvent } = ctx;
|
|
5990
|
+
if (!plugins.length)
|
|
5991
|
+
return;
|
|
5992
|
+
registerEvent({
|
|
5993
|
+
level: ModuleEventLevel.Debug,
|
|
5994
|
+
name: ModuleConfiguratorEventName.PluginsRegister,
|
|
5995
|
+
message: `Registering plugins [${plugins.length}]`,
|
|
5996
|
+
properties: { count: plugins.length },
|
|
5997
|
+
});
|
|
5998
|
+
const pluginRegistrations = await Promise.all(plugins.map(async (plugin) => {
|
|
5999
|
+
const pluginStart = performance.now();
|
|
6000
|
+
const name = plugin.name || 'anonymous';
|
|
6001
|
+
try {
|
|
6002
|
+
const teardown = await plugin({ modules, ref });
|
|
6003
|
+
const pluginTime = Math.round(performance.now() - pluginStart);
|
|
6004
|
+
registerEvent({
|
|
6005
|
+
level: ModuleEventLevel.Debug,
|
|
6006
|
+
name: ModuleConfiguratorEventName.PluginRegistered,
|
|
6007
|
+
message: `Plugin ${name} registered in ${pluginTime}ms`,
|
|
6008
|
+
properties: { name, pluginTime },
|
|
6009
|
+
metric: pluginTime,
|
|
6010
|
+
});
|
|
6011
|
+
return isPluginTeardown(teardown) ? teardown : undefined;
|
|
6012
|
+
}
|
|
6013
|
+
catch (err) {
|
|
6014
|
+
registerEvent({
|
|
6015
|
+
level: ModuleEventLevel.Warning,
|
|
6016
|
+
name: ModuleConfiguratorEventName.PluginRegisterError,
|
|
6017
|
+
message: `Plugin ${name} registration failed`,
|
|
6018
|
+
properties: { name },
|
|
6019
|
+
error: err,
|
|
6020
|
+
});
|
|
6021
|
+
return undefined;
|
|
6022
|
+
}
|
|
6023
|
+
}));
|
|
6024
|
+
for (const teardown of pluginRegistrations) {
|
|
6025
|
+
if (teardown) {
|
|
6026
|
+
teardowns.push(teardown);
|
|
6027
|
+
}
|
|
6028
|
+
}
|
|
6029
|
+
registerEvent({
|
|
6030
|
+
level: ModuleEventLevel.Debug,
|
|
6031
|
+
name: ModuleConfiguratorEventName.PluginsRegistered,
|
|
6032
|
+
message: 'Plugin registration complete',
|
|
6033
|
+
properties: { count: plugins.length, teardowns: teardowns.length },
|
|
6034
|
+
});
|
|
6035
|
+
}
|
|
6036
|
+
|
|
6037
|
+
function getPluginTeardownName(teardown) {
|
|
6038
|
+
return typeof teardown === 'function' ? teardown.name || 'anonymous' : 'dispose';
|
|
6039
|
+
}
|
|
6040
|
+
async function runPluginTeardown(teardown) {
|
|
6041
|
+
if (typeof teardown === 'function') {
|
|
6042
|
+
await teardown();
|
|
6043
|
+
return;
|
|
5342
6044
|
}
|
|
6045
|
+
await teardown.dispose();
|
|
5343
6046
|
}
|
|
6047
|
+
/**
|
|
6048
|
+
* Runs the dispose lifecycle phase for all registered modules.
|
|
6049
|
+
*
|
|
6050
|
+
* Calls each module's `dispose` hook (if defined) concurrently via
|
|
6051
|
+
* `Promise.allSettled` so one failing module cannot block others from
|
|
6052
|
+
* being torn down. After all hooks settle, the event stream is completed.
|
|
6053
|
+
*
|
|
6054
|
+
* @param ctx - The dispose phase context.
|
|
6055
|
+
* @param instance - The initialized module instance map to tear down.
|
|
6056
|
+
* @param ref - Optional reference forwarded to each module's `dispose` call.
|
|
6057
|
+
* @returns A promise resolving when all module dispose hooks have settled and
|
|
6058
|
+
* the event stream has been completed.
|
|
6059
|
+
*/
|
|
6060
|
+
async function runDisposePhase(ctx, instance, ref) {
|
|
6061
|
+
const { modules, registerEvent, event$, pluginTeardowns = [] } = ctx;
|
|
6062
|
+
registerEvent({
|
|
6063
|
+
level: ModuleEventLevel.Debug,
|
|
6064
|
+
name: ModuleConfiguratorEventName.Dispose,
|
|
6065
|
+
message: 'Disposing modules instance',
|
|
6066
|
+
properties: { modules: Object.keys(instance).join(', ') },
|
|
6067
|
+
});
|
|
6068
|
+
if (pluginTeardowns.length) {
|
|
6069
|
+
registerEvent({
|
|
6070
|
+
level: ModuleEventLevel.Debug,
|
|
6071
|
+
name: ModuleConfiguratorEventName.PluginsDisposing,
|
|
6072
|
+
message: `Disposing plugins [${pluginTeardowns.length}]`,
|
|
6073
|
+
properties: { count: pluginTeardowns.length },
|
|
6074
|
+
});
|
|
6075
|
+
// Tear down plugins before module providers so side effects can still access
|
|
6076
|
+
// live providers while unsubscribing. LIFO mirrors common subscription stacks.
|
|
6077
|
+
for (const teardown of pluginTeardowns.splice(0).reverse()) {
|
|
6078
|
+
const name = getPluginTeardownName(teardown);
|
|
6079
|
+
try {
|
|
6080
|
+
await runPluginTeardown(teardown);
|
|
6081
|
+
registerEvent({
|
|
6082
|
+
level: ModuleEventLevel.Debug,
|
|
6083
|
+
name: ModuleConfiguratorEventName.PluginDisposed,
|
|
6084
|
+
message: `Plugin ${name} disposed successfully`,
|
|
6085
|
+
properties: { name },
|
|
6086
|
+
});
|
|
6087
|
+
}
|
|
6088
|
+
catch (err) {
|
|
6089
|
+
registerEvent({
|
|
6090
|
+
level: ModuleEventLevel.Warning,
|
|
6091
|
+
name: ModuleConfiguratorEventName.PluginDisposeError,
|
|
6092
|
+
message: `Plugin ${name} dispose failed`,
|
|
6093
|
+
properties: { name },
|
|
6094
|
+
error: err,
|
|
6095
|
+
});
|
|
6096
|
+
}
|
|
6097
|
+
}
|
|
6098
|
+
}
|
|
6099
|
+
registerEvent({
|
|
6100
|
+
level: ModuleEventLevel.Debug,
|
|
6101
|
+
name: ModuleConfiguratorEventName.ModulesDispose,
|
|
6102
|
+
message: 'Disposing modules',
|
|
6103
|
+
properties: { count: modules.length },
|
|
6104
|
+
});
|
|
6105
|
+
// Dispose all modules concurrently; failures are isolated per module so
|
|
6106
|
+
// one bad teardown cannot leave other modules in an inconsistent state.
|
|
6107
|
+
await Promise.allSettled(modules
|
|
6108
|
+
.filter((module) => !!module.dispose)
|
|
6109
|
+
.map(async (module) => {
|
|
6110
|
+
if (!module.dispose)
|
|
6111
|
+
return;
|
|
6112
|
+
try {
|
|
6113
|
+
await module.dispose({
|
|
6114
|
+
ref,
|
|
6115
|
+
modules: instance,
|
|
6116
|
+
instance: instance[module.name],
|
|
6117
|
+
});
|
|
6118
|
+
registerEvent({
|
|
6119
|
+
level: ModuleEventLevel.Debug,
|
|
6120
|
+
name: ModuleConfiguratorEventName.ModuleDisposed,
|
|
6121
|
+
message: `Module ${module.name} disposed successfully`,
|
|
6122
|
+
properties: {
|
|
6123
|
+
moduleName: module.name,
|
|
6124
|
+
moduleVersion: module.version?.toString() || 'unknown',
|
|
6125
|
+
},
|
|
6126
|
+
});
|
|
6127
|
+
}
|
|
6128
|
+
catch (err) {
|
|
6129
|
+
registerEvent({
|
|
6130
|
+
level: ModuleEventLevel.Warning,
|
|
6131
|
+
name: ModuleConfiguratorEventName.ModuleDisposeError,
|
|
6132
|
+
message: `Module ${module.name} dispose failed`,
|
|
6133
|
+
properties: {
|
|
6134
|
+
moduleName: module.name,
|
|
6135
|
+
moduleVersion: module.version?.toString() || 'unknown',
|
|
6136
|
+
},
|
|
6137
|
+
error: err,
|
|
6138
|
+
});
|
|
6139
|
+
}
|
|
6140
|
+
}));
|
|
6141
|
+
registerEvent({
|
|
6142
|
+
level: ModuleEventLevel.Debug,
|
|
6143
|
+
name: ModuleConfiguratorEventName.ModulesDisposed,
|
|
6144
|
+
message: 'Module dispose complete',
|
|
6145
|
+
properties: { count: modules.length },
|
|
6146
|
+
});
|
|
6147
|
+
// Complete the event stream last so all dispose events are captured before
|
|
6148
|
+
// any subscriber teardown triggered by completion.
|
|
6149
|
+
event$.complete();
|
|
6150
|
+
}
|
|
6151
|
+
|
|
6152
|
+
// Generated by genversion.
|
|
6153
|
+
const version$8 = '6.1.0';
|
|
6154
|
+
|
|
6155
|
+
// 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
|
|
6156
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
5344
6157
|
/**
|
|
5345
6158
|
* Core orchestrator that drives the module lifecycle in Fusion Framework.
|
|
5346
6159
|
*
|
|
5347
|
-
* `ModulesConfigurator` manages the full configure
|
|
5348
|
-
* for a set of modules. Consumers
|
|
5349
|
-
* {@link
|
|
5350
|
-
* {@link
|
|
6160
|
+
* `ModulesConfigurator` manages the full **configure → post-configure → initialize →
|
|
6161
|
+
* post-initialize → plugin → dispose** pipeline for a set of modules. Consumers
|
|
6162
|
+
* register modules via {@link addConfig} or {@link configure}, then call
|
|
6163
|
+
* {@link initialize} to produce a sealed {@link ModulesInstance} whose properties
|
|
6164
|
+
* are the initialized module providers.
|
|
5351
6165
|
*
|
|
5352
|
-
*
|
|
6166
|
+
* ### Lifecycle phases (in execution order)
|
|
5353
6167
|
*
|
|
5354
|
-
*
|
|
5355
|
-
*
|
|
5356
|
-
*
|
|
5357
|
-
*
|
|
5358
|
-
* 3
|
|
6168
|
+
* | # | Phase | Entry point | Description |
|
|
6169
|
+
* |---|-------|-------------|-------------|
|
|
6170
|
+
* | 1 | **Configure** | `_configure` | Each module's `configure()` factory creates a config builder; registered callbacks mutate it. |
|
|
6171
|
+
* | 2 | **Post-configure** | `_postConfigure` (inside `_configure`) | `postConfigure()` hooks and `onConfigured` callbacks run. |
|
|
6172
|
+
* | 3 | **Initialize** | `_initialize` | Modules are initialized concurrently; cross-module dependencies are resolved through `requireInstance`. |
|
|
6173
|
+
* | 4 | **Post-initialize** | `_postInitialize` | `postInitialize()` hooks and `onInitialized` callbacks run. |
|
|
6174
|
+
* | 5 | **Plugin** | `_registerPlugins` (inside `initialize`) | Registered application plugins connect side effects after modules are ready. |
|
|
6175
|
+
* | 6 | **Dispose** | `dispose` | Plugin teardowns and module `dispose()` hooks run; the event stream is completed. |
|
|
6176
|
+
*
|
|
6177
|
+
* ### Registering phase callbacks
|
|
6178
|
+
*
|
|
6179
|
+
* - **Per-module callbacks**: use `addConfig({ module, configure, afterConfig, afterInit })`.
|
|
6180
|
+
* - **Global post-configure**: use `onConfigured(cb)`.
|
|
6181
|
+
* - **Global post-initialize**: use `onInitialized(cb)`.
|
|
6182
|
+
* - **Plugins**: use `registerPlugin(cb)` to connect side effects before render.
|
|
5359
6183
|
*
|
|
5360
6184
|
* All lifecycle transitions emit {@link ModuleEvent} entries on the {@link event$}
|
|
5361
6185
|
* observable for telemetry and debugging.
|
|
@@ -5376,57 +6200,97 @@ class RequiredModuleTimeoutError extends Error {
|
|
|
5376
6200
|
*/
|
|
5377
6201
|
class ModulesConfigurator {
|
|
5378
6202
|
/**
|
|
5379
|
-
*
|
|
5380
|
-
*
|
|
6203
|
+
* Class name used as a namespace prefix for all emitted lifecycle events.
|
|
6204
|
+
* Preserved as a static string so minification cannot change it at runtime.
|
|
5381
6205
|
*/
|
|
5382
6206
|
static className = 'ModulesConfigurator';
|
|
5383
6207
|
get version() {
|
|
5384
6208
|
return version$8;
|
|
5385
6209
|
}
|
|
5386
|
-
// Buffer up to 100 events to prevent memory leaks while ensuring telemetry
|
|
5387
|
-
//
|
|
5388
|
-
//
|
|
5389
|
-
//
|
|
6210
|
+
// Buffer up to 100 events to prevent memory leaks while ensuring telemetry
|
|
6211
|
+
// can capture events that fire before a telemetry subscriber attaches.
|
|
6212
|
+
// mapConfiguratorEvents relies on replay to receive events emitted during
|
|
6213
|
+
// configuration before telemetry is wired up.
|
|
6214
|
+
// Memory bound: ~24 KB at ~240 bytes/event × 100 events.
|
|
5390
6215
|
#event$ = new ReplaySubject(100);
|
|
5391
6216
|
get event$() {
|
|
5392
6217
|
return this.#event$.asObservable();
|
|
5393
6218
|
}
|
|
5394
6219
|
/**
|
|
5395
|
-
*
|
|
6220
|
+
* Registered configure-phase callbacks.
|
|
6221
|
+
* Each entry is added by {@link addConfig} when a `configure` callback is provided.
|
|
5396
6222
|
* @protected
|
|
5397
|
-
* @sealed
|
|
5398
6223
|
*/
|
|
5399
6224
|
_configs = [];
|
|
5400
6225
|
/**
|
|
5401
|
-
*
|
|
6226
|
+
* Registered post-configure callbacks.
|
|
6227
|
+
* Populated by {@link onConfigured} and by `afterConfig` entries in {@link addConfig}.
|
|
6228
|
+
* Also exposed on the config object as `config.onAfterConfiguration` so modules
|
|
6229
|
+
* can register additional hooks during their own configure factory.
|
|
6230
|
+
*
|
|
6231
|
+
* Typed as `any` because this is an internal dispatch array: callbacks are registered
|
|
6232
|
+
* with concrete module-specific types but stored erased — the orchestrator never
|
|
6233
|
+
* inspects the config shape itself, it only forwards it at call time.
|
|
6234
|
+
* @protected
|
|
5402
6235
|
*/
|
|
5403
6236
|
_afterConfiguration = [];
|
|
5404
6237
|
/**
|
|
5405
|
-
*
|
|
6238
|
+
* Registered post-initialize callbacks.
|
|
6239
|
+
* Populated by {@link onInitialized} and by `afterInit` entries in {@link addConfig}.
|
|
6240
|
+
* Also exposed on the config object as `config.onAfterInit`.
|
|
6241
|
+
*
|
|
6242
|
+
* Typed as `any` for the same reason as {@link _afterConfiguration} — type-erased
|
|
6243
|
+
* internal dispatch; concrete instance types are known at registration but not stored.
|
|
6244
|
+
* @protected
|
|
5406
6245
|
*/
|
|
5407
6246
|
_afterInit = [];
|
|
5408
6247
|
/**
|
|
5409
|
-
*
|
|
6248
|
+
* Registered plugin callbacks.
|
|
6249
|
+
*
|
|
6250
|
+
* Plugins run after all modules have initialized and before initialize resolves.
|
|
6251
|
+
* Typed as `any` because callbacks are registered with concrete module maps but
|
|
6252
|
+
* stored erased by the base orchestrator.
|
|
6253
|
+
* @protected
|
|
6254
|
+
*/
|
|
6255
|
+
_plugins = [];
|
|
6256
|
+
/**
|
|
6257
|
+
* Teardown callbacks returned by registered plugins.
|
|
6258
|
+
*
|
|
6259
|
+
* Consumed during dispose and cleared after execution so repeated dispose calls
|
|
6260
|
+
* do not run plugin cleanup more than once.
|
|
6261
|
+
* @protected
|
|
6262
|
+
*/
|
|
6263
|
+
_pluginTeardowns = [];
|
|
6264
|
+
/**
|
|
6265
|
+
* Set of all registered module descriptors.
|
|
6266
|
+
* Uses a `Set` for automatic deduplication — the same module registered twice
|
|
6267
|
+
* is treated as a single registration.
|
|
6268
|
+
* @protected
|
|
5410
6269
|
*/
|
|
5411
6270
|
_modules;
|
|
5412
6271
|
/**
|
|
5413
|
-
*
|
|
5414
|
-
*
|
|
6272
|
+
* Creates a new `ModulesConfigurator` with an optional initial set of modules.
|
|
6273
|
+
*
|
|
6274
|
+
* @param modules - Optional array of module descriptors to pre-register.
|
|
5415
6275
|
*/
|
|
5416
6276
|
constructor(modules) {
|
|
5417
|
-
// Use Set for efficient lookups and automatic deduplication of modules
|
|
5418
6277
|
this._modules = new Set(modules);
|
|
5419
6278
|
}
|
|
5420
6279
|
/**
|
|
5421
|
-
*
|
|
5422
|
-
*
|
|
6280
|
+
* Returns all registered module descriptors as an ordered array.
|
|
6281
|
+
*
|
|
6282
|
+
* @returns Array of registered modules in insertion order.
|
|
5423
6283
|
*/
|
|
5424
6284
|
get modules() {
|
|
5425
6285
|
return [...this._modules];
|
|
5426
6286
|
}
|
|
5427
6287
|
/**
|
|
5428
|
-
*
|
|
5429
|
-
*
|
|
6288
|
+
* Registers one or more module configurators.
|
|
6289
|
+
*
|
|
6290
|
+
* Convenience wrapper around {@link addConfig} for registering multiple
|
|
6291
|
+
* modules in a single call.
|
|
6292
|
+
*
|
|
6293
|
+
* @param configs - One or more module configurator descriptors.
|
|
5430
6294
|
*/
|
|
5431
6295
|
configure(...configs) {
|
|
5432
6296
|
for (const x of configs) {
|
|
@@ -5434,15 +6298,21 @@ class ModulesConfigurator {
|
|
|
5434
6298
|
}
|
|
5435
6299
|
}
|
|
5436
6300
|
/**
|
|
5437
|
-
*
|
|
5438
|
-
*
|
|
6301
|
+
* Registers a single module configurator.
|
|
6302
|
+
*
|
|
6303
|
+
* Adds the module to the known module set and registers the optional
|
|
6304
|
+
* `configure`, `afterConfig`, and `afterInit` callbacks into their
|
|
6305
|
+
* respective lifecycle phase arrays.
|
|
6306
|
+
*
|
|
6307
|
+
* @param config - The module configurator descriptor to register.
|
|
6308
|
+
* @template T - The module type being registered.
|
|
5439
6309
|
*/
|
|
5440
6310
|
addConfig(config) {
|
|
5441
6311
|
const { module, afterConfig, afterInit, configure } = config;
|
|
5442
6312
|
this._modules.add(module);
|
|
5443
6313
|
this._registerEvent({
|
|
5444
6314
|
level: ModuleEventLevel.Debug,
|
|
5445
|
-
name:
|
|
6315
|
+
name: ModuleConfiguratorEventName.ModuleConfigAdded,
|
|
5446
6316
|
message: `Module configurator added for ${module.name}`,
|
|
5447
6317
|
properties: {
|
|
5448
6318
|
moduleName: module.name,
|
|
@@ -5452,19 +6322,28 @@ class ModulesConfigurator {
|
|
|
5452
6322
|
afterInit: !!afterInit,
|
|
5453
6323
|
},
|
|
5454
6324
|
});
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
|
|
6325
|
+
// Register each optional callback into its corresponding lifecycle phase array
|
|
6326
|
+
if (configure)
|
|
6327
|
+
this._configs.push((cfg, ref) => configure(cfg[module.name], ref));
|
|
6328
|
+
if (afterConfig)
|
|
6329
|
+
this._afterConfiguration.push((cfg) => afterConfig(cfg[module.name]));
|
|
6330
|
+
if (afterInit)
|
|
6331
|
+
this._afterInit.push((instances) => afterInit(instances[module.name]));
|
|
5458
6332
|
}
|
|
5459
6333
|
/**
|
|
5460
|
-
* Registers a callback
|
|
5461
|
-
*
|
|
6334
|
+
* Registers a callback for the post-configure phase.
|
|
6335
|
+
*
|
|
6336
|
+
* The callback receives the merged module config map after all `configure`
|
|
6337
|
+
* callbacks have run and before module initialization begins.
|
|
6338
|
+
*
|
|
6339
|
+
* @param cb - Callback receiving the merged module config map.
|
|
6340
|
+
* @template T - Additional modules to include in the config type.
|
|
5462
6341
|
*/
|
|
5463
6342
|
onConfigured(cb) {
|
|
5464
6343
|
this._afterConfiguration.push(cb);
|
|
5465
6344
|
this._registerEvent({
|
|
5466
6345
|
level: ModuleEventLevel.Debug,
|
|
5467
|
-
name:
|
|
6346
|
+
name: ModuleConfiguratorEventName.OnConfiguredAdded,
|
|
5468
6347
|
message: 'Added onConfigured callback',
|
|
5469
6348
|
properties: {
|
|
5470
6349
|
count: this._afterConfiguration.length,
|
|
@@ -5473,14 +6352,19 @@ class ModulesConfigurator {
|
|
|
5473
6352
|
});
|
|
5474
6353
|
}
|
|
5475
6354
|
/**
|
|
5476
|
-
* Registers a callback
|
|
5477
|
-
*
|
|
6355
|
+
* Registers a callback for the post-initialize phase.
|
|
6356
|
+
*
|
|
6357
|
+
* The callback receives the sealed module instance after all modules have
|
|
6358
|
+
* been initialized and their `postInitialize` hooks have run.
|
|
6359
|
+
*
|
|
6360
|
+
* @param cb - Callback receiving the sealed module instance.
|
|
6361
|
+
* @template T - Additional modules to include in the instance type.
|
|
5478
6362
|
*/
|
|
5479
6363
|
onInitialized(cb) {
|
|
5480
6364
|
this._afterInit.push(cb);
|
|
5481
6365
|
this._registerEvent({
|
|
5482
6366
|
level: ModuleEventLevel.Debug,
|
|
5483
|
-
name:
|
|
6367
|
+
name: ModuleConfiguratorEventName.OnInitializedAdded,
|
|
5484
6368
|
message: 'Added onInitialized callback',
|
|
5485
6369
|
properties: {
|
|
5486
6370
|
count: this._afterInit.length,
|
|
@@ -5489,9 +6373,51 @@ class ModulesConfigurator {
|
|
|
5489
6373
|
});
|
|
5490
6374
|
}
|
|
5491
6375
|
/**
|
|
5492
|
-
*
|
|
5493
|
-
*
|
|
5494
|
-
*
|
|
6376
|
+
* Registers a plugin that connects side effects after modules are initialized.
|
|
6377
|
+
*
|
|
6378
|
+
* The callback runs after `postInitialize` and `onInitialized` callbacks have
|
|
6379
|
+
* settled, but before {@link initialize} resolves. Return a teardown callback
|
|
6380
|
+
* to clean up subscriptions or listeners during {@link dispose}.
|
|
6381
|
+
*
|
|
6382
|
+
* @param cb - Plugin callback receiving the initialized module map and optional ref.
|
|
6383
|
+
* @template T - Additional modules to include in the plugin module map.
|
|
6384
|
+
* @example
|
|
6385
|
+
* ```typescript
|
|
6386
|
+
* function connectContextTelemetry(args: FrameworkPluginArgs<[EventModule, TelemetryModule]>) {
|
|
6387
|
+
* const teardown = args.modules.event.addEventListener('context:changed', (event) => {
|
|
6388
|
+
* args.modules.telemetry.track('context.changed', event.detail);
|
|
6389
|
+
* });
|
|
6390
|
+
*
|
|
6391
|
+
* return teardown;
|
|
6392
|
+
* }
|
|
6393
|
+
*
|
|
6394
|
+
* configurator.registerPlugin(connectContextTelemetry);
|
|
6395
|
+
* ```
|
|
6396
|
+
*/
|
|
6397
|
+
registerPlugin(cb) {
|
|
6398
|
+
this._plugins.push(cb);
|
|
6399
|
+
this._registerEvent({
|
|
6400
|
+
level: ModuleEventLevel.Debug,
|
|
6401
|
+
name: ModuleConfiguratorEventName.PluginAdded,
|
|
6402
|
+
message: 'Added plugin callback',
|
|
6403
|
+
properties: {
|
|
6404
|
+
count: this._plugins.length,
|
|
6405
|
+
name: cb.name || 'anonymous',
|
|
6406
|
+
},
|
|
6407
|
+
});
|
|
6408
|
+
}
|
|
6409
|
+
/**
|
|
6410
|
+
* Runs the full configure → initialize pipeline and returns a sealed module instance.
|
|
6411
|
+
*
|
|
6412
|
+
* Execution order:
|
|
6413
|
+
* 1. {@link _configure} — configure phase (creates config, applies callbacks, post-configure hooks).
|
|
6414
|
+
* 2. {@link _initialize} — initialize phase (concurrent module init with `requireInstance`).
|
|
6415
|
+
* 3. {@link _postInitialize} — post-initialize phase (`postInitialize` hooks + `onInitialized` callbacks).
|
|
6416
|
+
* 4. {@link _registerPlugins} — plugin phase (`registerPlugin` callbacks connect side effects).
|
|
6417
|
+
*
|
|
6418
|
+
* @param ref - Optional reference forwarded to all module lifecycle hooks.
|
|
6419
|
+
* @returns A promise resolving to the sealed, initialized module instance.
|
|
6420
|
+
* @template T - Additional modules to merge into the instance type.
|
|
5495
6421
|
*/
|
|
5496
6422
|
async initialize(ref) {
|
|
5497
6423
|
const configStart = performance.now();
|
|
@@ -5499,7 +6425,7 @@ class ModulesConfigurator {
|
|
|
5499
6425
|
const configLoadTime = Math.round(performance.now() - configStart);
|
|
5500
6426
|
this._registerEvent({
|
|
5501
6427
|
level: ModuleEventLevel.Debug,
|
|
5502
|
-
name:
|
|
6428
|
+
name: ModuleConfiguratorEventName.InitializeConfigLoaded,
|
|
5503
6429
|
message: `Modules configured in ${configLoadTime}ms`,
|
|
5504
6430
|
properties: {
|
|
5505
6431
|
modules: this.modules.map((m) => m.name).join(', '),
|
|
@@ -5513,7 +6439,7 @@ class ModulesConfigurator {
|
|
|
5513
6439
|
const instanceLoadTime = Math.round(performance.now() - instanceStart);
|
|
5514
6440
|
this._registerEvent({
|
|
5515
6441
|
level: ModuleEventLevel.Debug,
|
|
5516
|
-
name:
|
|
6442
|
+
name: ModuleConfiguratorEventName.InitializeInstanceInitialized,
|
|
5517
6443
|
message: `Modules initialized in ${instanceLoadTime}ms`,
|
|
5518
6444
|
properties: {
|
|
5519
6445
|
modules: this.modules.map((m) => m.name).join(', '),
|
|
@@ -5525,7 +6451,7 @@ class ModulesConfigurator {
|
|
|
5525
6451
|
const totalLoadTime = configLoadTime + instanceLoadTime;
|
|
5526
6452
|
this._registerEvent({
|
|
5527
6453
|
level: ModuleEventLevel.Information,
|
|
5528
|
-
name:
|
|
6454
|
+
name: ModuleConfiguratorEventName.Initialize,
|
|
5529
6455
|
message: `initialize in ${totalLoadTime}ms`,
|
|
5530
6456
|
properties: {
|
|
5531
6457
|
modules: this.modules.map((m) => m.name).join(', '),
|
|
@@ -5536,560 +6462,126 @@ class ModulesConfigurator {
|
|
|
5536
6462
|
metric: totalLoadTime,
|
|
5537
6463
|
});
|
|
5538
6464
|
await this._postInitialize(instance, ref);
|
|
5539
|
-
|
|
6465
|
+
const modules = Object.seal(Object.assign({}, instance, {
|
|
5540
6466
|
dispose: () => this.dispose(instance),
|
|
5541
6467
|
}));
|
|
6468
|
+
await this._registerPlugins(modules, ref);
|
|
6469
|
+
return modules;
|
|
5542
6470
|
}
|
|
5543
6471
|
/**
|
|
5544
|
-
*
|
|
6472
|
+
* Namespaces and emits a lifecycle event into the internal event stream.
|
|
5545
6473
|
*
|
|
5546
|
-
*
|
|
5547
|
-
*
|
|
5548
|
-
*
|
|
6474
|
+
* The event name is prefixed with the configurator class name (e.g.
|
|
6475
|
+
* `"ModulesConfigurator::ModuleConfigurator.module.configAdded"`) to prevent
|
|
6476
|
+
* name collisions between nested configurators.
|
|
5549
6477
|
*
|
|
5550
|
-
* @param event - The
|
|
6478
|
+
* @param event - The lifecycle event to emit.
|
|
5551
6479
|
* @protected
|
|
5552
6480
|
*/
|
|
5553
6481
|
_registerEvent(event) {
|
|
5554
|
-
// Split
|
|
6482
|
+
// Split on '::' to avoid double-prefixing already-namespaced event names
|
|
5555
6483
|
const nameParts = event.name.split('::');
|
|
5556
6484
|
this.#event$.next({
|
|
5557
6485
|
...event,
|
|
5558
|
-
// Prefix the event name with the configurator class name
|
|
5559
6486
|
name: `${this.constructor.className}::${nameParts[nameParts.length - 1]}`,
|
|
5560
6487
|
});
|
|
5561
6488
|
}
|
|
5562
6489
|
/**
|
|
5563
|
-
*
|
|
5564
|
-
*
|
|
5565
|
-
*
|
|
6490
|
+
* Runs the configure lifecycle phase.
|
|
6491
|
+
*
|
|
6492
|
+
* Delegates to {@link runConfigurePhase} which creates module config builders,
|
|
6493
|
+
* applies registered callbacks, and runs post-configure hooks.
|
|
6494
|
+
*
|
|
6495
|
+
* Override this method in a subclass to customize the configure phase.
|
|
6496
|
+
*
|
|
6497
|
+
* @param ref - Optional reference forwarded to module configure factories.
|
|
6498
|
+
* @returns A promise resolving to the merged module config map.
|
|
6499
|
+
* @protected
|
|
5566
6500
|
*/
|
|
5567
6501
|
async _configure(ref) {
|
|
5568
|
-
|
|
5569
|
-
|
|
5570
|
-
|
|
5571
|
-
|
|
6502
|
+
return runConfigurePhase({
|
|
6503
|
+
modules: this.modules,
|
|
6504
|
+
configs: this._configs,
|
|
6505
|
+
afterConfiguration: this._afterConfiguration,
|
|
6506
|
+
afterInit: this._afterInit,
|
|
6507
|
+
registerEvent: this._registerEvent.bind(this),
|
|
6508
|
+
}, ref);
|
|
5572
6509
|
}
|
|
5573
6510
|
/**
|
|
5574
|
-
*
|
|
5575
|
-
*
|
|
5576
|
-
*
|
|
6511
|
+
* Runs the initialize lifecycle phase.
|
|
6512
|
+
*
|
|
6513
|
+
* Delegates to {@link runInitializePhase} which initializes all modules
|
|
6514
|
+
* concurrently and resolves cross-module dependencies through `requireInstance`.
|
|
6515
|
+
*
|
|
6516
|
+
* Override this method in a subclass to customize the initialize phase.
|
|
6517
|
+
*
|
|
6518
|
+
* @param config - The merged module config map from the configure phase.
|
|
6519
|
+
* @param ref - Optional reference forwarded to each module's `initialize` call.
|
|
6520
|
+
* @returns A promise resolving to the sealed map of initialized module providers.
|
|
6521
|
+
* @protected
|
|
5577
6522
|
*/
|
|
5578
|
-
|
|
5579
|
-
|
|
5580
|
-
|
|
5581
|
-
|
|
5582
|
-
|
|
5583
|
-
const configStart = performance.now();
|
|
5584
|
-
try {
|
|
5585
|
-
const configurator = await module.configure?.(ref);
|
|
5586
|
-
const configLoadTime = Math.round(performance.now() - configStart);
|
|
5587
|
-
this._registerEvent({
|
|
5588
|
-
level: ModuleEventLevel.Debug,
|
|
5589
|
-
name: '_createConfig.configuratorCreated',
|
|
5590
|
-
message: `Configurator created for ${module.name} in ${configLoadTime}ms`,
|
|
5591
|
-
properties: {
|
|
5592
|
-
moduleName: module.name,
|
|
5593
|
-
moduleVersion: module.version?.toString() || 'unknown',
|
|
5594
|
-
configLoadTime,
|
|
5595
|
-
},
|
|
5596
|
-
metric: configLoadTime,
|
|
5597
|
-
});
|
|
5598
|
-
return { [module.name]: configurator };
|
|
5599
|
-
}
|
|
5600
|
-
catch (err) {
|
|
5601
|
-
this._registerEvent({
|
|
5602
|
-
level: ModuleEventLevel.Error,
|
|
5603
|
-
name: '_createConfig.configuratorFailed',
|
|
5604
|
-
message: `Failed to create configurator for ${module.name}`,
|
|
5605
|
-
properties: {
|
|
5606
|
-
moduleName: module.name,
|
|
5607
|
-
moduleVersion: module.version?.toString() || 'unknown',
|
|
5608
|
-
},
|
|
5609
|
-
metric: Math.round(performance.now() - configStart),
|
|
5610
|
-
error: err,
|
|
5611
|
-
});
|
|
5612
|
-
throw err;
|
|
5613
|
-
}
|
|
5614
|
-
}), reduce((acc, module) => Object.assign(acc, module), {
|
|
5615
|
-
onAfterConfiguration(cb) {
|
|
5616
|
-
_afterConfiguration.push(cb);
|
|
5617
|
-
},
|
|
5618
|
-
onAfterInit(cb) {
|
|
5619
|
-
_afterInit.push(cb);
|
|
5620
|
-
},
|
|
5621
|
-
}));
|
|
5622
|
-
return lastValueFrom(config$);
|
|
6523
|
+
async _initialize(config, ref) {
|
|
6524
|
+
return runInitializePhase({
|
|
6525
|
+
modules: this.modules,
|
|
6526
|
+
registerEvent: this._registerEvent.bind(this),
|
|
6527
|
+
}, config, ref);
|
|
5623
6528
|
}
|
|
5624
6529
|
/**
|
|
5625
|
-
*
|
|
5626
|
-
*
|
|
5627
|
-
*
|
|
6530
|
+
* Runs the post-initialize lifecycle phase.
|
|
6531
|
+
*
|
|
6532
|
+
* Delegates to {@link runPostInitializePhase} which calls each module's
|
|
6533
|
+
* `postInitialize` hook and then runs all `onInitialized` callbacks.
|
|
6534
|
+
*
|
|
6535
|
+
* Override this method in a subclass to customize the post-initialize phase.
|
|
6536
|
+
*
|
|
6537
|
+
* @param instance - The sealed module instance from the initialize phase.
|
|
6538
|
+
* @param ref - Optional reference forwarded to each module's `postInitialize` call.
|
|
6539
|
+
* @protected
|
|
5628
6540
|
*/
|
|
5629
|
-
async
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
.
|
|
5634
|
-
|
|
5635
|
-
const postConfigStart = performance.now();
|
|
5636
|
-
await module.postConfigure?.(config);
|
|
5637
|
-
this._registerEvent({
|
|
5638
|
-
level: ModuleEventLevel.Debug,
|
|
5639
|
-
name: '_postConfigure.modulePostConfigured',
|
|
5640
|
-
message: `Module ${module.name} post-configured successfully`,
|
|
5641
|
-
properties: {
|
|
5642
|
-
moduleName: module.name,
|
|
5643
|
-
moduleVersion: module.version?.toString() || 'unknown',
|
|
5644
|
-
postConfigTime: Math.round(performance.now() - postConfigStart),
|
|
5645
|
-
},
|
|
5646
|
-
});
|
|
5647
|
-
}
|
|
5648
|
-
catch (err) {
|
|
5649
|
-
this._registerEvent({
|
|
5650
|
-
level: ModuleEventLevel.Warning,
|
|
5651
|
-
name: '_postConfigure.modulePostConfigureError',
|
|
5652
|
-
message: `Module ${module.name} post-configure failed`,
|
|
5653
|
-
properties: {
|
|
5654
|
-
moduleName: module.name,
|
|
5655
|
-
moduleVersion: module.version?.toString() || 'unknown',
|
|
5656
|
-
},
|
|
5657
|
-
error: err,
|
|
5658
|
-
});
|
|
5659
|
-
}
|
|
5660
|
-
}));
|
|
5661
|
-
/** call all added post config hooks */
|
|
5662
|
-
if (afterConfiguration.length) {
|
|
5663
|
-
try {
|
|
5664
|
-
this._registerEvent({
|
|
5665
|
-
level: ModuleEventLevel.Debug,
|
|
5666
|
-
name: '_postConfigure.hooks',
|
|
5667
|
-
message: `Post configure hooks [${afterConfiguration.length}] called`,
|
|
5668
|
-
});
|
|
5669
|
-
const postConfigHooksStart = performance.now();
|
|
5670
|
-
await Promise.allSettled(afterConfiguration.map((x) => Promise.resolve(x(config))));
|
|
5671
|
-
const postConfigHooksTime = Math.round(performance.now() - postConfigHooksStart);
|
|
5672
|
-
this._registerEvent({
|
|
5673
|
-
level: ModuleEventLevel.Debug,
|
|
5674
|
-
name: '_postConfigure.hooksComplete',
|
|
5675
|
-
message: 'Post configure hooks complete',
|
|
5676
|
-
properties: {
|
|
5677
|
-
count: afterConfiguration.length,
|
|
5678
|
-
postConfigHooksTime,
|
|
5679
|
-
},
|
|
5680
|
-
metric: postConfigHooksTime,
|
|
5681
|
-
});
|
|
5682
|
-
}
|
|
5683
|
-
catch (err) {
|
|
5684
|
-
this._registerEvent({
|
|
5685
|
-
level: ModuleEventLevel.Warning,
|
|
5686
|
-
name: '_postConfigure.hooksError',
|
|
5687
|
-
message: 'Post configure hook failed',
|
|
5688
|
-
error: err,
|
|
5689
|
-
});
|
|
5690
|
-
}
|
|
5691
|
-
}
|
|
6541
|
+
async _postInitialize(instance, ref) {
|
|
6542
|
+
return runPostInitializePhase({
|
|
6543
|
+
modules: this.modules,
|
|
6544
|
+
afterInit: this._afterInit,
|
|
6545
|
+
registerEvent: this._registerEvent.bind(this),
|
|
6546
|
+
}, instance, ref);
|
|
5692
6547
|
}
|
|
5693
6548
|
/**
|
|
5694
|
-
*
|
|
5695
|
-
*
|
|
5696
|
-
* @
|
|
5697
|
-
*
|
|
6549
|
+
* Runs the plugin lifecycle phase.
|
|
6550
|
+
*
|
|
6551
|
+
* Delegates to {@link runPluginPhase} which calls each registered plugin and
|
|
6552
|
+
* stores returned teardown callbacks for dispose.
|
|
6553
|
+
*
|
|
6554
|
+
* Override this method in a subclass to customize plugin registration.
|
|
6555
|
+
*
|
|
6556
|
+
* @param instance - The sealed module instance from the initialize phase.
|
|
6557
|
+
* @param ref - Optional reference forwarded to each plugin callback.
|
|
6558
|
+
* @protected
|
|
5698
6559
|
*/
|
|
5699
|
-
async
|
|
5700
|
-
|
|
5701
|
-
|
|
5702
|
-
|
|
5703
|
-
|
|
5704
|
-
|
|
5705
|
-
* Requires and returns an initialized module instance by its name.
|
|
5706
|
-
*
|
|
5707
|
-
* If the requested module is already initialized, returns it immediately as a resolved Promise.
|
|
5708
|
-
* If the module is not yet initialized, waits for its initialization and resolves with the instance,
|
|
5709
|
-
* or rejects with a timeout error if the module is not initialized within the specified time.
|
|
5710
|
-
*
|
|
5711
|
-
* Throws an error immediately if the requested module name is not defined in the current configuration.
|
|
5712
|
-
* Also logs relevant events for debugging and error tracking.
|
|
5713
|
-
*
|
|
5714
|
-
* @template TKey - The key of the module to require, constrained to the keys of the combined modules instance type.
|
|
5715
|
-
* @param name - The name of the module to require.
|
|
5716
|
-
* @param wait - The maximum time to wait (in seconds) for the module to initialize before timing out. Defaults to 60 seconds.
|
|
5717
|
-
* @returns A Promise that resolves with the initialized module instance of type `ModulesInstanceType<CombinedModules<T, TModules>>[TKey]`.
|
|
5718
|
-
* @throws {Error} If the module name is not defined.
|
|
5719
|
-
* @throws {RequiredModuleTimeoutError} If the module does not initialize within the specified timeout.
|
|
5720
|
-
*
|
|
5721
|
-
* @example
|
|
5722
|
-
* ```typescript
|
|
5723
|
-
* const myModule = await requireInstance('myModuleName', 30);
|
|
5724
|
-
* ```
|
|
5725
|
-
*/
|
|
5726
|
-
const requireInstance = (name, wait = 60) => {
|
|
5727
|
-
/** if module name is not defined, throw error */
|
|
5728
|
-
if (!moduleNames.includes(name)) {
|
|
5729
|
-
const error = new Error(`Cannot require [${String(name)}] since module is not defined!`);
|
|
5730
|
-
error.name = 'ModuleNotDefinedError';
|
|
5731
|
-
this._registerEvent({
|
|
5732
|
-
level: ModuleEventLevel.Error,
|
|
5733
|
-
name: '_initialize.requireInstance.moduleNotDefined',
|
|
5734
|
-
message: error.message,
|
|
5735
|
-
properties: {
|
|
5736
|
-
moduleName: String(name),
|
|
5737
|
-
wait,
|
|
5738
|
-
},
|
|
5739
|
-
error,
|
|
5740
|
-
});
|
|
5741
|
-
throw error;
|
|
5742
|
-
}
|
|
5743
|
-
/** if module is already initialized, return it */
|
|
5744
|
-
if (instance$.value[name]) {
|
|
5745
|
-
this._registerEvent({
|
|
5746
|
-
level: ModuleEventLevel.Debug,
|
|
5747
|
-
name: '_initialize.requireInstance.moduleAlreadyInitialized',
|
|
5748
|
-
message: `Module [${String(name)}] is already initialized, skipping queue`,
|
|
5749
|
-
properties: {
|
|
5750
|
-
moduleName: String(name),
|
|
5751
|
-
wait,
|
|
5752
|
-
},
|
|
5753
|
-
});
|
|
5754
|
-
return Promise.resolve(instance$.value[name]);
|
|
5755
|
-
}
|
|
5756
|
-
const requireStart = performance.now();
|
|
5757
|
-
this._registerEvent({
|
|
5758
|
-
level: ModuleEventLevel.Debug,
|
|
5759
|
-
name: '_initialize.requireInstance.awaiting',
|
|
5760
|
-
message: `Awaiting module [${String(name)}] initialization, timeout ${wait}s`,
|
|
5761
|
-
properties: {
|
|
5762
|
-
moduleName: String(name),
|
|
5763
|
-
wait,
|
|
5764
|
-
},
|
|
5765
|
-
});
|
|
5766
|
-
return firstValueFrom(instance$.pipe(filter((x) => !!x[name]), map$1((x) => x[name]), timeout({
|
|
5767
|
-
each: wait * 1000,
|
|
5768
|
-
with: () => throwError(() => {
|
|
5769
|
-
const error = new RequiredModuleTimeoutError();
|
|
5770
|
-
this._registerEvent({
|
|
5771
|
-
level: ModuleEventLevel.Error,
|
|
5772
|
-
name: '_initialize.requireInstance.timeout',
|
|
5773
|
-
message: `Module [${String(name)}] initialization timed out after ${wait}s`,
|
|
5774
|
-
properties: {
|
|
5775
|
-
moduleName: String(name),
|
|
5776
|
-
wait,
|
|
5777
|
-
},
|
|
5778
|
-
error,
|
|
5779
|
-
});
|
|
5780
|
-
return error;
|
|
5781
|
-
}),
|
|
5782
|
-
}), tap(() => {
|
|
5783
|
-
const requireTime = Math.round(performance.now() - requireStart);
|
|
5784
|
-
this._registerEvent({
|
|
5785
|
-
level: ModuleEventLevel.Debug,
|
|
5786
|
-
name: '_initialize.requireInstance.moduleResolved',
|
|
5787
|
-
message: `Module [${String(name)}] required in ${requireTime}ms`,
|
|
5788
|
-
properties: {
|
|
5789
|
-
moduleName: String(name),
|
|
5790
|
-
wait,
|
|
5791
|
-
requireTime,
|
|
5792
|
-
},
|
|
5793
|
-
metric: requireTime,
|
|
5794
|
-
});
|
|
5795
|
-
})));
|
|
5796
|
-
};
|
|
5797
|
-
// Create observable stream to initialize modules concurrently
|
|
5798
|
-
// Each module goes through: validation -> initialization -> result mapping
|
|
5799
|
-
const init$ = from(this.modules).pipe(
|
|
5800
|
-
/** Process each module individually through initialization pipeline */
|
|
5801
|
-
mergeMap((module) => {
|
|
5802
|
-
const key = module.name;
|
|
5803
|
-
if (!module.initialize) {
|
|
5804
|
-
const error = new Error(`Module ${module.name} does not have initialize method`);
|
|
5805
|
-
error.name = 'ModuleInitializeError';
|
|
5806
|
-
this._registerEvent({
|
|
5807
|
-
level: ModuleEventLevel.Error,
|
|
5808
|
-
name: '_initialize.moduleInitializeError',
|
|
5809
|
-
message: error.message,
|
|
5810
|
-
properties: {
|
|
5811
|
-
moduleName: module.name,
|
|
5812
|
-
moduleVersion: module.version?.toString() || 'unknown',
|
|
5813
|
-
},
|
|
5814
|
-
error,
|
|
5815
|
-
});
|
|
5816
|
-
throw error;
|
|
5817
|
-
}
|
|
5818
|
-
this._registerEvent({
|
|
5819
|
-
level: ModuleEventLevel.Debug,
|
|
5820
|
-
name: '_initialize.moduleInitializing',
|
|
5821
|
-
message: `Initializing module ${module.name}`,
|
|
5822
|
-
properties: {
|
|
5823
|
-
moduleName: module.name,
|
|
5824
|
-
moduleVersion: module.version?.toString() || 'unknown',
|
|
5825
|
-
},
|
|
5826
|
-
});
|
|
5827
|
-
const moduleInitStart = performance.now();
|
|
5828
|
-
return from(
|
|
5829
|
-
// TODO: Replace Promise.resolve + from() with toObservable() for better RxJS patterns
|
|
5830
|
-
Promise.resolve(module.initialize({
|
|
5831
|
-
ref,
|
|
5832
|
-
config: config[key],
|
|
5833
|
-
// @ts-ignore
|
|
5834
|
-
requireInstance,
|
|
5835
|
-
hasModule,
|
|
5836
|
-
}))).pipe(map$1((instance) => {
|
|
5837
|
-
if (!(instance instanceof BaseModuleProvider)) {
|
|
5838
|
-
this._registerEvent({
|
|
5839
|
-
level: ModuleEventLevel.Warning,
|
|
5840
|
-
name: '_initialize.providerNotBaseModuleProvider',
|
|
5841
|
-
message: `Provider for module ${module.name} does not extend BaseModuleProvider`,
|
|
5842
|
-
properties: {
|
|
5843
|
-
moduleName: module.name,
|
|
5844
|
-
moduleVersion: module.version?.toString() || 'unknown',
|
|
5845
|
-
},
|
|
5846
|
-
});
|
|
5847
|
-
}
|
|
5848
|
-
if (!instance.version) {
|
|
5849
|
-
this._registerEvent({
|
|
5850
|
-
level: ModuleEventLevel.Warning,
|
|
5851
|
-
name: '_initialize.providerVersionWarning',
|
|
5852
|
-
message: `Provider for module ${module.name} does not expose version`,
|
|
5853
|
-
properties: {
|
|
5854
|
-
moduleName: module.name,
|
|
5855
|
-
moduleVersion: module.version?.toString() || 'unknown',
|
|
5856
|
-
},
|
|
5857
|
-
});
|
|
5858
|
-
}
|
|
5859
|
-
const moduleInitTime = Math.round(performance.now() - moduleInitStart);
|
|
5860
|
-
this._registerEvent({
|
|
5861
|
-
level: ModuleEventLevel.Debug,
|
|
5862
|
-
name: '_initialize.moduleInitialized',
|
|
5863
|
-
message: `Module ${module.name} initialized in ${moduleInitTime}ms`,
|
|
5864
|
-
properties: {
|
|
5865
|
-
moduleName: module.name,
|
|
5866
|
-
moduleVersion: module.version?.toString() || 'unknown',
|
|
5867
|
-
providerName: typeof instance,
|
|
5868
|
-
providerVersion: instance.version?.toString() || 'unknown',
|
|
5869
|
-
moduleInitTime,
|
|
5870
|
-
},
|
|
5871
|
-
metric: moduleInitTime,
|
|
5872
|
-
});
|
|
5873
|
-
return [key, instance];
|
|
5874
|
-
}));
|
|
5875
|
-
}));
|
|
5876
|
-
const initStart = performance.now();
|
|
5877
|
-
// Subscribe to module initialization stream and accumulate results
|
|
5878
|
-
// Each successful initialization updates the shared instance object
|
|
5879
|
-
init$
|
|
5880
|
-
.pipe(
|
|
5881
|
-
/** ensure that the stream is completed even if there are no modules to initialize */
|
|
5882
|
-
defaultIfEmpty([]))
|
|
5883
|
-
.subscribe({
|
|
5884
|
-
next: ([name, module]) => {
|
|
5885
|
-
// Accumulate initialized modules into the shared instance object
|
|
5886
|
-
instance$.next(Object.assign(instance$.value, { [name]: module }));
|
|
5887
|
-
},
|
|
5888
|
-
error: (err) => {
|
|
5889
|
-
this._registerEvent({
|
|
5890
|
-
level: ModuleEventLevel.Error,
|
|
5891
|
-
name: '_initialize.moduleInitializationError',
|
|
5892
|
-
message: `Failed to initialize module ${err.name || 'unknown'}`,
|
|
5893
|
-
error: err,
|
|
5894
|
-
});
|
|
5895
|
-
instance$.error(err);
|
|
5896
|
-
},
|
|
5897
|
-
complete: () => {
|
|
5898
|
-
const loadTime = Math.round(performance.now() - initStart);
|
|
5899
|
-
this._registerEvent({
|
|
5900
|
-
level: ModuleEventLevel.Debug,
|
|
5901
|
-
name: '_initialize.moduleInitializationComplete',
|
|
5902
|
-
message: `All modules initialized in ${loadTime}ms`,
|
|
5903
|
-
properties: {
|
|
5904
|
-
modules: Object.keys(instance$.value).join(', '),
|
|
5905
|
-
loadTime,
|
|
5906
|
-
},
|
|
5907
|
-
metric: loadTime,
|
|
5908
|
-
});
|
|
5909
|
-
return instance$.complete();
|
|
5910
|
-
},
|
|
5911
|
-
});
|
|
5912
|
-
/** await creation of all instances */
|
|
5913
|
-
const initStartTime = performance.now();
|
|
5914
|
-
const instance = await lastValueFrom(instance$);
|
|
5915
|
-
const initTime = Math.round(performance.now() - initStartTime);
|
|
5916
|
-
this._registerEvent({
|
|
5917
|
-
level: ModuleEventLevel.Debug,
|
|
5918
|
-
name: '_initialize.complete',
|
|
5919
|
-
message: `Modules instance created in ${initTime}ms`,
|
|
5920
|
-
properties: {
|
|
5921
|
-
modules: Object.keys(instance).join(', '),
|
|
5922
|
-
initTime,
|
|
5923
|
-
},
|
|
5924
|
-
metric: initTime,
|
|
5925
|
-
});
|
|
5926
|
-
Object.seal(instance);
|
|
5927
|
-
return instance;
|
|
6560
|
+
async _registerPlugins(instance, ref) {
|
|
6561
|
+
return runPluginPhase({
|
|
6562
|
+
plugins: this._plugins,
|
|
6563
|
+
teardowns: this._pluginTeardowns,
|
|
6564
|
+
registerEvent: this._registerEvent.bind(this),
|
|
6565
|
+
}, instance, ref);
|
|
5928
6566
|
}
|
|
5929
6567
|
/**
|
|
5930
|
-
*
|
|
5931
|
-
*
|
|
5932
|
-
* @
|
|
6568
|
+
* Tears down all modules managed by this configurator.
|
|
6569
|
+
*
|
|
6570
|
+
* Delegates to {@link runDisposePhase} which calls each module's `dispose`
|
|
6571
|
+
* hook and then completes the internal event stream.
|
|
6572
|
+
*
|
|
6573
|
+
* @param instance - The initialized module instance to tear down.
|
|
6574
|
+
* @param ref - Optional reference forwarded to module dispose hooks.
|
|
6575
|
+
* @returns A promise resolving when all modules have been disposed.
|
|
5933
6576
|
*/
|
|
5934
|
-
async _postInitialize(instance, ref) {
|
|
5935
|
-
const { modules, _afterInit: afterInit } = this;
|
|
5936
|
-
const postInitialize$ = from(modules).pipe(filter((module) => !!module.postInitialize), tap((module) => {
|
|
5937
|
-
this._registerEvent({
|
|
5938
|
-
level: ModuleEventLevel.Debug,
|
|
5939
|
-
name: '_postInitialize.modulePostInitializing',
|
|
5940
|
-
message: `Module ${module.name} is being post-initialized`,
|
|
5941
|
-
properties: {
|
|
5942
|
-
moduleName: module.name,
|
|
5943
|
-
moduleVersion: module.version?.toString() || 'unknown',
|
|
5944
|
-
},
|
|
5945
|
-
});
|
|
5946
|
-
}), mergeMap((module) => {
|
|
5947
|
-
const postInitStart = performance.now();
|
|
5948
|
-
return from(module.postInitialize({
|
|
5949
|
-
ref,
|
|
5950
|
-
modules: instance,
|
|
5951
|
-
instance: instance[module.name],
|
|
5952
|
-
})).pipe(tap(() => {
|
|
5953
|
-
const postInitTime = Math.round(performance.now() - postInitStart);
|
|
5954
|
-
this._registerEvent({
|
|
5955
|
-
level: ModuleEventLevel.Debug,
|
|
5956
|
-
name: '_postInitialize.modulePostInitialized',
|
|
5957
|
-
message: `Module ${module.name} has been post-initialized in ${postInitTime}ms`,
|
|
5958
|
-
metric: postInitTime,
|
|
5959
|
-
properties: {
|
|
5960
|
-
moduleName: module.name,
|
|
5961
|
-
moduleVersion: module.version?.toString() || 'unknown',
|
|
5962
|
-
postInitTime,
|
|
5963
|
-
},
|
|
5964
|
-
});
|
|
5965
|
-
}), defaultIfEmpty(null), catchError((err) => {
|
|
5966
|
-
this._registerEvent({
|
|
5967
|
-
level: ModuleEventLevel.Warning,
|
|
5968
|
-
name: '_postInitialize.modulePostInitializeError',
|
|
5969
|
-
message: `Module ${module.name} post-initialize failed`,
|
|
5970
|
-
properties: {
|
|
5971
|
-
moduleName: module.name,
|
|
5972
|
-
moduleVersion: module.version?.toString() || 'unknown',
|
|
5973
|
-
},
|
|
5974
|
-
error: err,
|
|
5975
|
-
});
|
|
5976
|
-
return EMPTY;
|
|
5977
|
-
}));
|
|
5978
|
-
}), defaultIfEmpty(null));
|
|
5979
|
-
this._registerEvent({
|
|
5980
|
-
level: ModuleEventLevel.Debug,
|
|
5981
|
-
name: '_postInitialize.modulesPostInitializing',
|
|
5982
|
-
message: `Post-initializing all modules [${Object.keys(instance).length}]`,
|
|
5983
|
-
properties: {
|
|
5984
|
-
modules: Object.keys(instance).join(', '),
|
|
5985
|
-
},
|
|
5986
|
-
});
|
|
5987
|
-
const postInitStart = performance.now();
|
|
5988
|
-
await lastValueFrom(postInitialize$);
|
|
5989
|
-
const postInitTime = Math.round(performance.now() - postInitStart);
|
|
5990
|
-
this._registerEvent({
|
|
5991
|
-
level: ModuleEventLevel.Debug,
|
|
5992
|
-
name: '_postInitialize.modulesPostInitializeComplete',
|
|
5993
|
-
message: `Post-initialization of all modules completed in ${postInitTime}ms`,
|
|
5994
|
-
properties: {
|
|
5995
|
-
modules: Object.keys(instance).join(', '),
|
|
5996
|
-
postInitTime: postInitTime,
|
|
5997
|
-
},
|
|
5998
|
-
metric: postInitTime,
|
|
5999
|
-
});
|
|
6000
|
-
if (afterInit.length) {
|
|
6001
|
-
try {
|
|
6002
|
-
this._registerEvent({
|
|
6003
|
-
level: ModuleEventLevel.Debug,
|
|
6004
|
-
name: '_postInitialize.afterInitHooks',
|
|
6005
|
-
message: `Executing post-initialize hooks [${afterInit.length}]`,
|
|
6006
|
-
properties: {
|
|
6007
|
-
hooks: afterInit.map((x) => x.name || 'anonymous').join(', '),
|
|
6008
|
-
},
|
|
6009
|
-
});
|
|
6010
|
-
const afterInitStart = performance.now();
|
|
6011
|
-
await Promise.allSettled(afterInit.map((x) => Promise.resolve(x(instance))));
|
|
6012
|
-
const afterInitTime = Math.round(performance.now() - afterInitStart);
|
|
6013
|
-
this._registerEvent({
|
|
6014
|
-
level: ModuleEventLevel.Debug,
|
|
6015
|
-
name: '_postInitialize.afterInitHooksComplete',
|
|
6016
|
-
message: `Post-initialize hooks completed in ${afterInitTime}ms`,
|
|
6017
|
-
properties: {
|
|
6018
|
-
hooks: afterInit.map((x) => x.name || 'anonymous').join(', '),
|
|
6019
|
-
afterInitTime,
|
|
6020
|
-
},
|
|
6021
|
-
metric: afterInitTime,
|
|
6022
|
-
});
|
|
6023
|
-
}
|
|
6024
|
-
catch (err) {
|
|
6025
|
-
this._registerEvent({
|
|
6026
|
-
level: ModuleEventLevel.Warning,
|
|
6027
|
-
name: '_postInitialize.afterInitHooksError',
|
|
6028
|
-
message: 'Post-initialize hooks failed',
|
|
6029
|
-
properties: {
|
|
6030
|
-
hooks: afterInit.map((x) => x.name || 'anonymous').join(', '),
|
|
6031
|
-
},
|
|
6032
|
-
error: err,
|
|
6033
|
-
});
|
|
6034
|
-
}
|
|
6035
|
-
}
|
|
6036
|
-
const postInitCompleteTime = Math.round(performance.now() - postInitStart);
|
|
6037
|
-
this._registerEvent({
|
|
6038
|
-
level: ModuleEventLevel.Debug,
|
|
6039
|
-
name: '_postInitialize.complete',
|
|
6040
|
-
message: 'Post-initialization complete',
|
|
6041
|
-
properties: {
|
|
6042
|
-
modules: Object.keys(instance).join(', '),
|
|
6043
|
-
postInitCompleteTime,
|
|
6044
|
-
},
|
|
6045
|
-
});
|
|
6046
|
-
}
|
|
6047
|
-
/**
|
|
6048
|
-
* Disposes all modules managed by this configurator.\n *\n * Calls each module\u2019s `dispose` hook (if defined) and completes the\n * internal event stream. After disposal the configurator should not be reused.\n *\n * @param instance - The initialized modules instance to tear down.\n * @param ref - Optional reference object forwarded to module dispose hooks.\n */
|
|
6049
6577
|
async dispose(instance, ref) {
|
|
6050
|
-
|
|
6051
|
-
|
|
6052
|
-
|
|
6053
|
-
|
|
6054
|
-
|
|
6055
|
-
|
|
6056
|
-
|
|
6057
|
-
});
|
|
6058
|
-
await Promise.allSettled(this.modules
|
|
6059
|
-
.filter((module) => !!module.dispose)
|
|
6060
|
-
.map(async (module) => {
|
|
6061
|
-
if (!module.dispose)
|
|
6062
|
-
return;
|
|
6063
|
-
try {
|
|
6064
|
-
await module.dispose({
|
|
6065
|
-
ref,
|
|
6066
|
-
modules: instance,
|
|
6067
|
-
instance: instance[module.name],
|
|
6068
|
-
});
|
|
6069
|
-
this._registerEvent({
|
|
6070
|
-
level: ModuleEventLevel.Debug,
|
|
6071
|
-
name: 'dispose.moduleDisposed',
|
|
6072
|
-
message: `Module ${module.name} disposed successfully`,
|
|
6073
|
-
properties: {
|
|
6074
|
-
moduleName: module.name,
|
|
6075
|
-
moduleVersion: module.version?.toString() || 'unknown',
|
|
6076
|
-
},
|
|
6077
|
-
});
|
|
6078
|
-
}
|
|
6079
|
-
catch (err) {
|
|
6080
|
-
this._registerEvent({
|
|
6081
|
-
level: ModuleEventLevel.Warning,
|
|
6082
|
-
name: 'dispose.moduleDisposeError',
|
|
6083
|
-
message: `Module ${module.name} dispose failed`,
|
|
6084
|
-
properties: {
|
|
6085
|
-
moduleName: module.name,
|
|
6086
|
-
moduleVersion: module.version?.toString() || 'unknown',
|
|
6087
|
-
},
|
|
6088
|
-
error: err,
|
|
6089
|
-
});
|
|
6090
|
-
}
|
|
6091
|
-
}));
|
|
6092
|
-
this.#event$.complete();
|
|
6578
|
+
return runDisposePhase({
|
|
6579
|
+
modules: this.modules,
|
|
6580
|
+
registerEvent: this._registerEvent.bind(this),
|
|
6581
|
+
// ReplaySubject extends Subject — dispose only needs .complete() which both have.
|
|
6582
|
+
event$: this.#event$,
|
|
6583
|
+
pluginTeardowns: this._pluginTeardowns,
|
|
6584
|
+
}, instance, ref);
|
|
6093
6585
|
}
|
|
6094
6586
|
}
|
|
6095
6587
|
|
|
@@ -21820,7 +22312,7 @@ class HttpClientConfigurator {
|
|
|
21820
22312
|
}
|
|
21821
22313
|
|
|
21822
22314
|
// Generated by genversion.
|
|
21823
|
-
const version$6 = '8.0.
|
|
22315
|
+
const version$6 = '8.0.2';
|
|
21824
22316
|
|
|
21825
22317
|
/**
|
|
21826
22318
|
* Thrown when `createClient(name)` is called with an unknown client key.
|
|
@@ -24129,7 +24621,7 @@ class TelemetryConfigurator extends BaseConfigBuilder {
|
|
|
24129
24621
|
}
|
|
24130
24622
|
|
|
24131
24623
|
// Generated by genversion.
|
|
24132
|
-
const version$5 = '
|
|
24624
|
+
const version$5 = '6.0.0';
|
|
24133
24625
|
|
|
24134
24626
|
/**
|
|
24135
24627
|
* Enum representing the severity levels of telemetry items.
|
|
@@ -42227,7 +42719,7 @@ const createClientLogCallback = (provider, metadata, scope) => {
|
|
|
42227
42719
|
};
|
|
42228
42720
|
|
|
42229
42721
|
// Generated by genversion.
|
|
42230
|
-
const version$2 = '
|
|
42722
|
+
const version$2 = '9.0.0';
|
|
42231
42723
|
|
|
42232
42724
|
/**
|
|
42233
42725
|
* Zod schema for telemetry configuration validation.
|
|
@@ -47044,7 +47536,7 @@ async function registerServiceWorker(framework) {
|
|
|
47044
47536
|
}
|
|
47045
47537
|
|
|
47046
47538
|
// Generated by genversion.
|
|
47047
|
-
const version = '4.0.
|
|
47539
|
+
const version = '4.0.9';
|
|
47048
47540
|
|
|
47049
47541
|
// Allow dynamic import without vite
|
|
47050
47542
|
const importWithoutVite = (path) => import(/* @vite-ignore */ path);
|