git submodule update --init --recursive
dart pub global activate -spath packages/aft
aft bootstrapChanges MUST pass:
flutter analyze
dart pub get # crucial to run this!
dart fix --apply .
dart format .
- Language: Dart (Flutter + pure Dart)
- Architecture: Monorepo with ~25+ packages under
packages/ - Tooling: Custom
aft(Amplify Flutter Tool) for bootstrapping, formatting, analysis, testing - Root
pubspec.yaml- Flutter/Dart monorepo configuration with multiple packages
- snake_case for all Dart files:
auth_plugin_impl.dart,state_machine.dart,amplify_exception.dart - snake_case for directories:
amplify_core,aws_common,amplify_auth_cognito_dart - Package names follow pattern:
amplify_<category>for Flutter,amplify_<category>_dartfor pure Dart - Generated files use
.g.dartsuffix (json_serializable) - Platform-conditional files use suffixes:
globals.flutter.dart,globals.dart.dart,initial_parameters_stub.dart/initial_parameters_html.dart
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0Enforced via tool/license.sh and CI checks.
- Every
analysis_options.yamlMUST include a shared lint profile frompackages/amplify_lints/:- Library packages:
include: package:amplify_lints/library.yaml - Example/app packages:
include: package:amplify_lints/app.yaml
- Library packages:
- The profiles handle all lint rules, strict mode settings, and enforced conventions. Packages may add local overrides (e.g., excluding
.g.dartfiles) but must not replace the base include.
- Dartdoc template/macro system used extensively:
Then referenced elsewhere:
/// {@template amplify_core.amplify_exception} /// Description here. /// {@endtemplate}
/// {@macro amplify_core.amplify_exception} - Category tags for dartdoc categorization:
/// {@category Auth} - All public APIs have doc comments (enforced by
public_member_api_docs) - Code examples in docs use
<?code-excerpt>syntax for verified code excerpts
- Categories: Abstract interfaces (
AuthCategory,StorageCategory, etc.) define the public API - Plugins: Concrete implementations (
AmplifyAuthCognitoDart) implement category interfaces - Plugin Key pattern: Static
pluginKeyconstant for type-safe plugin retrieval:static const AuthPluginKey<AmplifyAuthCognitoDart> pluginKey = _AmplifyAuthCognitoDartPluginKey();
- Extensive use of typed state machines for complex flows (auth, sign-in, sign-out, etc.)
- Hierarchy:
StateMachineManager→StateMachine→StateMachineEvent/StateMachineState - States are
sealedclasses with named constructors for each variant:sealed class SignInState extends AuthState<SignInStateType> { const factory SignInState.notStarted() = SignInNotStarted; const factory SignInState.success(AuthUser user) = SignInSuccess; const factory SignInState.failure({...}) = SignInFailure; }
- State types expressed as enums:
SignInStateType { notStarted, initiating, challenge, success, failure } SuccessStateandErrorStatemixins for terminal statesEventCompleter<E, S>for async event tracking withaccepted/completedfutures- Events have
checkPrecondition()method for guard conditions
DependencyManager(service locator pattern) withaddBuilder(),addInstance(),get(),getOrCreate()Token<T>for type-safe dependency keys_ScopedDependencyManagerfor hierarchical scope
- Pure Dart packages (
_dartsuffix) for cross-platform logic - Flutter packages wrap Dart packages for platform integration
- Conditional imports for web vs. VM:
if (dart.library.js_interop)
AWSEquatable<T>— Value equality viapropslist (like Equatable package)AWSDebuggable— SafetoString()viaruntimeTypeName(prevents runtime reflection)AWSSerializable<T>—toJson()contractAmplifyLoggerMixin— Logging integration- Classes commonly compose multiple mixins:
class AmplifyOutputs with AWSEquatable<AmplifyOutputs>, AWSSerializable, AWSDebuggable { ... }
- Heavy use of Dart 3 sealed classes for states and results:
sealed class AWSResult<V, E extends Exception> { ... } final class AWSSuccessResult<V, E> extends AWSResult<V, E> { ... } final class AWSErrorResult<V, E> extends AWSResult<V, E> { ... }
final classfor concrete implementations (prevent extension)base class/base mixinfor state machine types (controlled hierarchy)- Dart 3 pattern matching (
switchexpressions,casepatterns) used throughout
@immutableannotation on value typesconstconstructors used wherever possibleprefer_final_localsenforced by lints
AmplifyException(recoverable) vsAmplifyError(non-recoverable) distinction- Exceptions include
message,recoverySuggestion,underlyingException - Category-specific exception hierarchies via
partfiles PreconditionExceptionfor state machine guard failuresonly_throw_errorslint: only throwException/Errorsubclasses
json_serializable+json_annotationfor JSON serialization- Shared serialization options via constants:
zAmplifySerializable— Standard Amplify types (includeIfNull: false,explicitToJson: true)zAwsSerializable— AWS types (fieldRename: FieldRename.pascal)zAmplifyOutputsSerializable— Amplify Outputs (fieldRename: FieldRename.snake)
- Generated code in
.g.dartfiles, excluded from analysis
- Constants:
lowerCamelCasewithzprefix for internal/library-wide constants:zAmplifySerializable,zIsFlutter,zDefaultLogLevel,zAssertsEnabled - Enums:
PascalCasetype,lowerCamelCasevalues - Use visibility annotations (
@protected,@visibleForTesting,@internal) frompackage:meta - Factory constructors: Named after source —
fromJson,fromMap
- Tests use
package:test(notflutter_test) for pure Dart - Standard
group/teststructure @TestOn('vm')or@TestOn('browser')for platform-specific testsMockAWSHttpClientfor HTTP mocking@visibleForTestingsetters/properties for test hookszAssertsEnabledguard for test-only code paths
- Modern
library;syntax (unnamed libraries) in Dart 3 part/part ofused for tightly-coupled files (e.g., state machine states/events grouped via parts)- Barrel files use explicit
exportwithshow/hidefor API control
- Root
pubspec.yamldefines shared dependency versions aft bootstrapcreatespubspec_overrides.yamlfor local development- Components are grouped for coordinated versioning (e.g., all
Amplify Flutterpackages version together) - Semantic versioning followed; new enum cases = minor version bump
- Packages shipping a
version.dartmust includebuild_runnerandbuild_versionin theirdev_dependencies(align versions with existing packages in the repo) version.dartfiles (typicallylib/src/version.dart) MUST always be autogenerated- The generated file must be excluded from analysis in
analysis_options.yamlunderanalyzer: exclude: - Generate with
dart run build_runner build