All notable changes to this project will be documented in this file.
- Eloquent:
Model.fillnow accepts astrictflag. Whentrue, any non-fillable key throwsMassAssignmentExceptioninstead of being silently dropped. Pair with validated request payloads to catch schema drift at the boundary. (#69) - Validation:
FormRequest— Laravel-style request object that collapses authorize → prepare → validate into a single class. ThrowsAuthorizationExceptionon denied access andValidationExceptionwith a field-keyed error map on rule failure. Pairs withModel.fill(validated, strict: true). (#66) - HTTP:
MagicController.authorize(ability, [arguments]), a Laravel-style controller helper that delegates toGate.allows()and throwsAuthorizationExceptionon denial. Avoids hand-rolling gate checks in every action. (#72) - Auth:
Gate.allowsAny(abilities, [arguments])andGate.allowsAll(abilities, [arguments]), short-circuiting sugar for checking multiple abilities at once. (#72) - Routing:
MagicRoute.resource(name, controller, {only, except})auto-wires up to four canonical routes (index, create, show, edit) to a controller that mixes inResourceController. Controllers declare supported methods viaresourceMethods;only/exceptnarrow the set further. Each route gets an auto-assigned{slug}.{method}name and title. (#67) - Validation:
AsyncRulecontract plusUnique(endpoint, field: ...)rule, an async uniqueness check with per-instance debounce (coalesces rapid calls) and a pluggable.via()resolver. Network errors log and pass so they never block submission.Validator.validateAsync()runs async rules after sync rules; sync failures short-circuit per field. (#68) - Session: Add
Sessionfacade with Laravel-style flash data —Session.flash(data),Session.flashErrors(errors),Session.old(field, [fallback]),Session.error(field),Session.errors(field),Session.hasError(field),Session.hasFlash,Session.tick(). Two-bucket store promotes flashed data exactly one navigation hop so forms can repopulate after a failed submit. Top-level helpersold()anderror()mirror Laravel's Blade API - UI:
MagicFormData.validate()automatically flashes form data on validation failure — downstream views can repopulate viaold('field')without manual wiring - Validation:
In<T>rule accepts a primitive whitelist (strings, ints, etc.) andInList<T extends Enum>validates enum-backed fields, accepting either the enum instance or a wire string.InListsupportscaseInsensitive:and an optionalwire:mapper for snake_case or custom representations. Both emit the sharedvalidation.inmessage with a comma-joined:valuesparameter. (#81)
- Routing: Add
currentPathgetter toMagicRouter— returns the current route path without query string, complementing the existingcurrentLocationproperty
- Routing: Use
GoRouter.pop()instead ofNavigator.pop()inback()— syncs router state and preserves custom page transitions on reverse animation. AddStateErrorguard when router is not initialized, consistent withto()andreplace()
- Skill: Optimize
magic-frameworkskill for Claude Code progressive disclosure — split frontmatter, extract templates to references, compress sections (669 → 416 lines). Add version frontmatter and source-to-skill mapping in release command - Deps: Bump magic version constraint in example app
- Broadcasting: Client-side activity monitor — detects silent connection loss using Pusher protocol
activity_timeoutandpusher:ping/pusher:pong. Automatically reconnects when the server stops responding - Broadcasting: Random jitter (up to 30%) on reconnection backoff delay — prevents thundering herd when many clients reconnect simultaneously after a server restart
- Broadcasting: Configurable connection establishment timeout (default 15s) — prevents indefinite hang when server doesn't complete the Pusher handshake. Automatically triggers reconnect on timeout
- Routing: Fix intermittent page title loss on web — Flutter's
Titlewidget was overwriting TitleManager's route-level title ondidChangeDependencies()rebuilds. UseonGenerateTitleto keep both in sync
- file_picker: Upgrade from
^10.3.10to^11.0.2— migrates to static API (FilePicker.platformremoved). Consumers usingFilePicker.platformdirectly (viamagic.dartre-export) must switch to static calls (FilePicker.pickFiles(),FilePicker.getDirectoryPath(),FilePicker.saveFile()). Includes Android path traversal security fix (CWE-22) and WASM web support
- Routing: Route-level page title management with
TitleManagersingleton. Per-route titles viaRouteDefinition.title(), automatic suffix pattern viaMagicApplication(titleSuffix:), declarativeMagicTitlewidget for data-dependent titles, and imperativeMagicRoute.setTitle()/MagicRoute.currentTitleAPI. Title resolution: MagicTitle > setTitle > RouteDefinition.title > MagicApplication.title. (#49)
- Dependencies: Bump
magic_clito^0.0.1-alpha.6(scaffold templates now include.title()andtitleSuffix)
- Broadcasting: Auth failures in private/presence channels now surface via
Log.error()and interceptoronError()chain instead of being silently swallowed. Reconnect resubscribes all channels withawait—onReconnectstream emits only after completion. Per-channel error handling ensures one auth failure does not block other channels. (#45) - Database:
sqlite3.wasmnow loads via absolute URI (/sqlite3.wasm) instead of relative — fixes 404s on deep routes when using path URL strategy. (#46)
- feat: config-driven path URL strategy for Flutter web (#40)
- Broadcasting:
Echofacade,BroadcastManager,ReverbBroadcastDriver(Pusher-compatible WebSocket with reconnection, dedup, heartbeat),NullBroadcastDriver,BroadcastInterceptorpipeline,FakeBroadcastManager,BroadcastServiceProvider. Laravel Echo equivalent for real-time channels. (#38) - Router Observers:
MagicRouter.instance.addObserver()enables NavigatorObserver integration for analytics/monitoring (Sentry, Firebase Analytics, custom observers). Observers are passed to GoRouter automatically. (#34) - Network Driver Plugin Hook:
DioNetworkDriver.configureDriver()exposes the underlying Dio instance for SDK integrations (sentry_dio, certificate pinning, custom adapters). (#35) - Custom Log Drivers:
LogManager.extend()enables custom LoggerDriver registration (Sentry, file, Slack). Config-driven resolution with built-in override support. (#36)
- Http Faking:
Http.fake()enables Laravel-style HTTP faking for testing. Swap the real network driver with aFakeNetworkDriverthat records requests and returns stubbed responses. Supports URL pattern stubs, callback stubs, and assertion methods (assertSent,assertNotSent,assertNothingSent,assertSentCount). (#18) - Facade Faking:
Auth.fake(),Cache.fake(),Vault.fake(),Log.fake()— Laravel-style facade faking for testing. Swap real service implementations with in-memory fakes that record operations and expose assertion helpers. (#19) - Fetch Helpers:
fetchList()/fetchOne()onMagicStateMixin— auto state management for HTTP fetches with defensive type guards against malformed responses (#20) - MagicTest:
MagicTest.init()/MagicTest.boot()— standardized test bootstrap helper,package:magic/testing.dartbarrel export (#21)
- Log.channel(): Now returns
LoggerDrivervia_manager.driver(name)instead ofLogManager, enablingLog.channel('slack').error(...)as documented (#27) - Http.response() null data: Sentinel pattern allows
Http.response(null, 204)for No Content stubs whileHttp.response()still returns mutable empty map (#26) - URL pattern escaping:
FakeNetworkDriverstub patterns now escape regex metacharacters (.,?,+) viaRegExp.escape()— only*is treated as wildcard (#26) - fetchList/fetchOne defensive guards: Type-check
response.dataasMapbefore indexing, filter non-Mapelements in lists viawhereType<Map>(), guardfetchOnedata cast (#28)
- Route Back Navigation:
MagicRoute.back()now works aftergo()-based navigation (cross-shell). Maintains lightweight history stack with automatic fallback. Optionalfallbackparameter for explicit control. (#11)
- Localization Hot Restart: Translation JSON changes now reflect on hot restart during development. Uses fetch with cache-busting on web and best-effort disk reads on desktop, bypassing Flutter's asset bundle cache. Zero impact on release builds.
- Logo on pub.dev: Use absolute URL for logo image so it renders correctly on pub.dev
- TDD Development Flow: Added strict TDD rules and verification cycle to CLAUDE.md
- Pub.dev Migration: Replaced git submodule path dependencies with pub.dev hosted packages (
fluttersdk_wind: ^1.0.0-alpha.4,magic_cli: ^0.0.1-alpha.3). Removedplugins/directory entirely. - SDK Bump: Dart
>=3.11.0 <4.0.0, Flutter>=3.41.0(previously Dart >=3.4.0, Flutter >=3.22.0)
- Launch Facade: URL, email, phone, and SMS launching via
url_launcherwithLaunch.url(),Launch.email(),Launch.phone(),Launch.sms() - Form Processing:
process(),isProcessing, andprocessingListenableonMagicFormDatafor form-scoped loading state - Reactive Auth State:
stateNotifieron Guard contract and BaseGuard for reactive auth state UI - Query Parameters:
Request.query(),Request.queryAll,MagicRouter.queryParameter()for URL query parameter access - Localization Interceptor: Automatic
Accept-LanguageandX-Timezoneheaders on HTTP requests - Theme Persistence: Auto-persist dark/light theme preference via Vault in
MagicApplication - Validation Helpers:
clearErrors()andclearFieldError()onValidatesRequestsmixin - Route Names: Route name registration on
RouteDefinition
- Auth Config: Default config now properly wrapped under
'auth'key - Session Restore: Guards against missing
userFactory— gracefully skips instead of throwing - Barrel Export:
FileStoreexported from barrel file - Package Name: Renamed internal references from
fluttersdk_magictomagic
- Dependency Upgrades: go_router ^17.1.0, sqlite3 ^3.2.0, share_plus ^12.0.1, file_picker ^10.3.10, flutter_lints ^6.0.0, and more
- CLI Docs: Rewrote Magic CLI documentation with all 16 commands and
dart run magic:magicsyntax - Wind UI Docs: Moved to wind.fluttersdk.com, removed local copy
- Example App: Rebuilt with fresh
flutter createandmagic install - CI Pipeline: Upgraded GitHub Actions, added validate gate to publish workflow
- Claude Code: Added path-scoped
.claude/rules/for 8 domains, auto-format and auto-analyze hooks
- Laravel-inspired MVC architecture
- Eloquent-style ORM with relationships
- GoRouter-based routing with middleware support
- Service Provider pattern
- Facade pattern for global access
- Policy-based authorization
- Complete model system with HasTimestamps, InteractsWithPersistence
- HTTP client with interceptors
- Form validation system
- Event/Listener system
- Magic CLI integration
- Hot reload support
- AI agent documentation