run method
Future<BootstrapReport>
run({
- required Map<
String, dynamic> config, - List<
BackendAdapter> adapters = const [], - List<
FeaturePlugin Function()> plugins = const [],
Executes the full startup sequence and returns a BootstrapReport.
Provide config as the raw configuration map (typically parsed from
environment.json). Pass adapters and plugins in the order they
should be registered — registration order determines hook priority
tie-breaking and plugin dependency resolution.
The returned BootstrapReport is safe to inspect immediately after
await; it is never null and always contains timing data for every step
that completed, even if later steps failed.
// Inside AppBootstrap.initState
final report = await MooseBootstrapper(appContext: ctx).run(
config: {'plugins': {'products': {'active': true}}},
adapters: [WooCommerceAdapter()],
plugins: [() => ProductsPlugin()],
);
setState(() => _bootstrapReport = report);
See also:
- BootstrapReport.succeeded, for a quick pass/fail check.
- BootstrapReport.failures, for per-adapter and per-plugin error details.
Implementation
Future<BootstrapReport> run({
required Map<String, dynamic> config,
List<BackendAdapter> adapters = const [],
List<FeaturePlugin Function()> plugins = const [],
}) async {
final sw = Stopwatch()..start();
final timings = <String, Duration>{};
final startTimings = <String, Duration>{};
final failures = <String, Object>{};
// Step 1: Initialize configuration.
appContext.configManager.initialize(config);
// Step 2: Initialize the scoped persistent cache layer.
await appContext.cache.initPersistent();
// Step 2b: Restore last-known auth state from persistent cache so the UI
// can show user-specific content on the first frame, before any
// adapter's authStateChanges stream confirms the session.
await appContext.restoreAuthState();
// Step 3: Wire AppNavigator to the scoped EventBus so that navigation
// events flow through this context's bus (not a global singleton).
AppNavigator.setEventBus(appContext.eventBus);
// Step 4: Register and initialize adapters.
for (final adapter in adapters) {
try {
await appContext.adapterRegistry.registerAdapter(() => adapter);
} catch (e) {
failures['adapter:${adapter.name}'] = e;
appContext.logger.error(
'Adapter "${adapter.name}" failed to register',
e,
);
}
}
// Step 5: Register plugins (sync — injects appContext, calls onRegister).
for (final factory in plugins) {
FeaturePlugin? plugin;
try {
plugin = factory();
appContext.pluginRegistry.register(plugin, appContext: appContext);
} catch (e) {
final name = plugin?.name ?? 'unknown';
failures['plugin:$name'] = e;
appContext.logger.error('Plugin "$name" failed to register', e);
}
}
// Step 6: Initialize all registered plugins (async).
try {
await appContext.pluginRegistry.initAll(timings: timings);
} catch (e) {
failures['plugin:initAll'] = e;
appContext.logger.error('Plugin init phase failed', e);
}
// Step 7: Start all registered plugins (async).
try {
await appContext.pluginRegistry.startAll(timings: startTimings);
} catch (e) {
failures['plugin:startAll'] = e;
appContext.logger.error('Plugin start phase failed', e);
}
sw.stop();
appContext.logger.info(
'Bootstrap complete in ${sw.elapsed.inMilliseconds}ms '
'(${timings.length} plugins inited, ${startTimings.length} plugins started, ${failures.length} failures)',
);
appContext.logger.debug('Plugin timings: $timings');
appContext.logger.debug('Plugin start timings: $startTimings');
return BootstrapReport(
totalTime: sw.elapsed,
pluginTimings: timings,
pluginStartTimings: startTimings,
failures: failures,
);
}