executeHooks method

Future<Map<String, dynamic>> executeHooks(
  1. HookStage stage,
  2. String flagKey,
  3. Map<String, dynamic>? context, {
  4. dynamic result,
  5. Exception? error,
  6. EvaluationDetails? evaluationDetails,
  7. HookHints? hints,
  8. ClientMetadata? clientMetadata,
  9. ProviderMetadata? providerMetadata,
  10. dynamic defaultValue,
  11. FlagValueType? flagValueType,
  12. HookData? hookData,
  13. Iterable<Hook> additionalHooks = const [],
  14. List<Hook>? executionHooks,
  15. void onContextChanged(
    1. Map<String, dynamic>
    )?,
})

Execute hooks for a specific stage

Implementation

Future<Map<String, dynamic>> executeHooks(
  HookStage stage,
  String flagKey,
  Map<String, dynamic>? context, {
  dynamic result,
  Exception? error,
  EvaluationDetails? evaluationDetails,
  HookHints? hints,
  ClientMetadata? clientMetadata,
  ProviderMetadata? providerMetadata,
  dynamic defaultValue,
  FlagValueType? flagValueType,
  HookData? hookData,
  Iterable<Hook> additionalHooks = const [],
  List<Hook>? executionHooks,
  void Function(Map<String, dynamic>)? onContextChanged,
}) async {
  var currentContext = Map<String, dynamic>.from(context ?? const {});
  final evaluationHookData = hookData ?? HookData();
  final suppliedHints = hints ?? const HookHints();
  final cleanup = stage == HookStage.ERROR || stage == HookStage.FINALLY;
  for (final hook in _hooksForStage(stage, additionalHooks, executionHooks)) {
    try {
      final typed = hook is EvaluationHook;
      final scopedData = evaluationHookData._scopeFor(hook);
      // Capture before the provider await, including hooks with no before
      // callback. Legacy hooks retain their original values and types.
      final hookDefault = typed
          ? scopedData._captureDefault(defaultValue, cleanup: cleanup)
          : defaultValue;
      if (hook is EvaluationHook && !hook.stages.contains(stage)) continue;
      final hookHints = typed ? suppliedHints.snapshot() : suppliedHints;
      final hookDetails = typed
          ? evaluationDetails?._snapshot(cleanup: cleanup)
          : evaluationDetails;
      final hookContext = HookContext(
        flagKey: flagKey,
        evaluationContext: typed
            ? _snapshotHookValue(
                currentContext,
                cleanup: cleanup,
                evaluationContext: true,
              )
            : currentContext,
        result: typed ? _snapshotHookValue(result, cleanup: cleanup) : result,
        error: error,
        clientMetadata: clientMetadata,
        providerMetadata: providerMetadata == null
            ? null
            : ProviderMetadata(
                name: providerMetadata.name,
                version: providerMetadata.version,
                attributes: Map.unmodifiable(providerMetadata.attributes),
              ),
        defaultValue: hookDefault,
        flagValueType: flagValueType,
        hookData: scopedData,
        hints: hookHints,
        evaluationDetails: hookDetails,
      );

      final contextUpdates = await _executeHookWithTimeout(
        hook,
        stage,
        hookContext,
        hook.metadata.config.timeout,
        hookDetails,
        hints == null ? null : hookHints,
      );

      if (stage == HookStage.BEFORE &&
          contextUpdates != null &&
          contextUpdates.isNotEmpty) {
        currentContext = {...currentContext, ...contextUpdates};
        onContextChanged?.call(currentContext);
      }
    } catch (e) {
      if (stage == HookStage.BEFORE || stage == HookStage.AFTER) {
        rethrow;
      }
      // Error/finally failures cannot suppress remaining cleanup hooks.
    }
  }

  return currentContext;
}