bifrosted
The rainbow bridge connecting your app to APIs. A lightweight REST API client and repository pattern with caching, offline support, and error handling.
0.12.1
colbymaloy/bifrost
What this package is like to depend on
Last release 21 days ago
02 Aug 2026
Release timing varies
gaps range from 2 weeks to 5 months
Nearly every release is documented
notes for 15 of 16 stable releases
Nothing withdrawn
no release was ever pulled
6 months old
16 releases · first in 2026
16 releases in the last 12 months
see the full history below
Release timeline
16 releases · Feb 2026 to Aug 2026Releases
latest 16-
0.12.102 Aug 2026Release notes
Open source →- Fixed the serialized cache-mutation queue retaining its completed
Futureacross Flutter's per-testFakeAsynczones. A first widget test could cache successfully, while the next received its response and then waited forever on a completion owned by the previous test's inactive zone. The queue now clears its tail when the last mutation completes while preserving ordering for concurrent mutations.
- Fixed the serialized cache-mutation queue retaining its completed
-
0.12.002 Aug 2026Release notes
Open source →-
Breaking: replaced the shipped
BifrostTestEnvservice graph withBifrostTestRuntime. Test setup now resets only Bifrost's transport, preferences, clock, decoder, performance tracker, fake mode, notifications, and internal diagnostics. It never replacesbifrostServiceLocator; apps rebuild their own production container throughinitializeApplication.BifrostTestRuntime.install( responseFactory: (_) => const <Object>[], notifications: notifications, diagnostics: diagnostics, initializeApplication: AppBinding.reinitialize, );responseFactory,shouldFail, andrespondernow share the same per-request responder seam, so overrides reach HTTP clients retained by vendor SDKs such as Supabase. Notification tests record outcomes without replacing the app's realSystemNotifierregistration. -
Added non-recoverable
FailureReason.internal. Unexpected defects thrown by source adapters, REST hooks, or repository callbacks no longer masquerade asnetworkand get rescued by stale cache.fetchandmutatereturn an internal failure; the source-compatible booleansendreturnsfalseand records an internal diagnostic. Internal failures never invokeSystemNotifier. -
RestAPInow bounds header resolution, each HTTP attempt, and unauthorized refresh. OverriderequestTimeoutorrefreshTimeoutfor API-specific budgets. OperationalClientExceptionand timeout failures still returnnull; unexpected hook/client defects preserve their original error and stack inBifrostInternalExceptionfor repository containment. Timed-out refreshes remain single-flight until the underlying refresh actually ends. -
Serialized the complete cache save, per-key clear, and clear-all mutations behind one failure-resilient queue shared by every repository instance. Two concurrent reads can no longer lose a registry entry and leave cached payloads that
clearAllCache()cannot enumerate. -
Added
postgrestErrorResponsetopackage:bifrosted/testing.dart. It builds a complete PostgREST error envelope for tests that exercise a real retained Supabase/PostgREST client; production SQLSTATE/PGRST mapping remains app-owned. -
Simplified Bifrost's private package test fixture: its locator is installed once per test file while its mutable services still reset before every test.
-
-
0.11.001 Aug 2026Release notes
Open source →-
Breaking:
BifrostTestEnv.reset()no longer assignsbifrostServiceLocator. It was a second dependency-injection system running against the app's own. An app's bindings already point the locator at its container, soreset()and those bindings overwrote each other and which one won depended on call order — a repository test that ranreset()last silently stopped resolving the services its production code uses, while a widget test resolved them normally. Tests should exercise the same injection production does.Register the doubles through the app's own container instead:
bifrostTestEnv.reset(); Bind.delete<SystemNotifier>(force: true); // GetX keeps the first permanent registration Bind.put<SystemNotifier>(bifrostTestEnv.notifier, permanent: true);A package with no container of its own — bifrosted included — can call
bifrostTestEnv.installDoubles(), which does whatreset()used to. It is documented as exactly that: a shim for the no-DI case, not something an app should reach for.Migration: if your tests broke with
"…" not foundafter upgrading, addinstallDoubles()afterreset()to restore the old behaviour, then move to container registration when convenient.
-
-
0.10.230 Jul 2026Release notes
Open source →-
Fixed:
RestAPI.hostrejected any value containing a colon._buildUripassedhoststraight intoUri(scheme: 'https', host: host), andUri'shostparameter reads a colon as an IPv6 literal — so a scheme-qualified URL, a port, and therefore any local dev server threwFormatException: Illegal IPv6 address, invalid character (at character 1), an error naming none of the actual causes.hostnow accepts what you'd reasonably put in a config value:hostRequest URL api.example.comhttps://api.example.com/...https://api.example.comas given http://localhost:8080as given — scheme and port preserved 10.0.2.2:3000https://10.0.2.2:3000/...https://example.com/v1base path preserved, not dropped Backward compatible: a bare hostname still resolves to
https. -
An empty
hostnow throwsArgumentErrornaming the likely cause — an app launched without--dart-define-from-file— instead of silently buildinghttps:///pathand failing at the transport layer.
-
-
0.10.130 Jul 2026Release notes
Open source →- Widened the
loggerre-export.LoggerandLevelalone were not enough to reconfigurebifrostLogger: its defaultDevelopmentFilterdrops every log in release builds and ignoreslevel, so keeping warnings in release meant namingProductionFilter— which required adding a directloggerdependency just to reassign our own global. Now also exportsProductionFilter,DevelopmentFilter,LogFilter,LogPrinter,LogOutput,PrettyPrinter, andSimplePrinter.bifrostLogger = Logger( level: kReleaseMode ? Level.warning : Level.debug, filter: ProductionFilter(), // required; DevelopmentFilter ignores `level` );
- Widened the
-
0.10.030 Jul 2026Release notes
Open source →- Fixed: nothing persisted across app launches.
SharedPrefService.init()calledSharedPreferences.setMockInitialValues({}), which replaces the platform store with an empty in-memory map (SharedPreferencesStorePlatform.instance = InMemorySharedPreferencesStore.withData(...)). Becauseinit()runs on every launch, no preference, token, onboarding flag, or cached response survived a cold start.init()now only reads. If your app appeared to "forget everything," this was why. - Breaking: removed
SharedPrefService.updateInitialMock. It was test scaffolding on a production class, and it set the mock store as a side effect. Replace it withuseMockStorage. - Added
useMockStorage({values})topackage:bifrosted/testing.dart— the storage counterpart touseMockClient. Tests need it for two reasons: there is no SharedPreferences platform plugin in a test process, sogetInstance()otherwise throwsMissingPluginException; and the mock store is a static platform instance, so a value written by one test is still readable in the next unless it is reset. Call it insetUp(or once per file, beforeinitServices):useMockStorage(); // clean slate useMockStorage(values: {'onboarding_done': true}); // seeded state - Added [OnboardingController], a reusable multi-step flow controller. Subclass it, implement
buildResult, and inheritnext/back/skip, answer collection, completion, and the analytics funnel. - It is a plain
ChangeNotifier— no state-management dependency — matching the documented exception for one-time flows that run before the app's main state exists. - Emits the events a funnel is computed from:
started,step_viewed,answered,skipped,back,completed(with duration, reach and skip count), andabandonedon dispose-before-completion, naming the step the user quit on. The event prefix is configurable. step_viewedfires once per step per session, on first arrival only. Re-counting a revisit afterback()would inflate early steps and overstate the funnel's health.- The controller reports events, not rates: a completion rate is a population statistic that one session cannot know.
completed ÷ startedis a query in your analytics tool. back()never clears answers — losing input on a back tap is the most reliable way to cause abandonment.
- Fixed: nothing persisted across app launches.
-
0.5.415 Feb 2026Release notes
Open source →- Breaking: Simplified [SystemNotifier] to three UI-only callbacks:
onNetworkError(),onUnauthorized(),onRequestFailed({statusCode, body})- Removed
onForbidden,onServerError,onApiError
- Docs: notifiers must handle user-facing UI only; use
bifrostLoggerfor diagnostics
- Breaking: Simplified [SystemNotifier] to three UI-only callbacks:
-
0.5.307 Feb 2026Release notes
Open source →- Breaking: Removed
fetchList— usefetch<List<T>>with the samefromJson - Breaking: Removed
endpointonfetch— usecacheKeyonly (it was only used for caching) fetch<R, M>auto-detects top-level JSON array vs object;fromJsonis always the item parser (User.fromJson), return type isUserorList<User>
- Breaking: Removed
-
0.4.605 Feb 2026Nothing published for this version
-
0.4.505 Feb 2026 -
0.4.004 Feb 2026Release notes
Open source →- Breaking: Removed generics from
BifrostRepository - Added
bifrostServiceLocator- Set once, used everywhere// At app startup: bifrostServiceLocator = <T>() => Get.find<T>(); - Repositories now have zero boilerplate:
class UserRepo extends BifrostRepository { Future<User?> getUser(String id) => fetch<User>(...); }
- Breaking: Removed generics from
-
0.3.004 Feb 2026Release notes
Open source →- Added global mock client support for testing
useMockClient()- Enable mock responses for all RestAPI instancesuseRealClient()- Reset to real HTTP clientssetClientFactory()- Set custom client factory- No more per-API client overrides needed
- Added global mock client support for testing
-
0.2.204 Feb 2026Release notes
Open source →- Fixed build.yaml to correctly combine generated code into
.g.dartfiles- Changed
build_to: cacheandbuild_extensions: .fake.g.part - Generator output now properly merges with json_serializable/freezed
- Changed
- Fixed build.yaml to correctly combine generated code into
-
0.2.104 Feb 2026Release notes
Open source →- Added
build.yamlfor auto-discovery by build_runner- No manual configuration needed - just add the dependency and run build_runner
- Works like freezed/json_serializable out of the box
- Added
-
0.2.004 Feb 2026Release notes
Open source →- Added
@generateFakeannotation for code generation - Added
FakeUtilsutility class (usesfakerpackage)fakeForKey(String key)- generates fake data based on field namecreate<T>()- generates fake model from factoryfakeJson()/fakeJsonList()- generic JSON generators
- Added
FakeGeneratorfor build_runner integration- Generates
.fake()extension methods for annotated classes - Works with freezed models
- Generates
- Added
-
0.1.003 Feb 2026Release notes
Open source →- Initial release
RestAPIabstract class for REST API clients- GET, POST, PUT, PATCH, DELETE methods
- Automatic error handling and logging
- Header management with extra headers support
BifrostRepositoryfor repository pattern with cachingfetch<T>()andfetchList<T>()for automatic deserialization- Offline-first with cache fallback
- Automatic cache expiration
SystemNotifierinterface for global error handlingonNetworkError(),onUnauthorized(),onForbidden()onServerError(),onApiError()
StorageServiceinterface for pluggable storage backendsConnectionCheckerinterface for connectivity detection- Uses
loggerpackage for logging - Comprehensive test suite