v2.0.0-beta — offline-first foundation (pre-release)
Pre-release
Pre-release
2.0.0-beta — offline-first foundation (PRE-RELEASE)
This is a pre-release.
1.2.0remains the latest stable release on both GitHub and pub.dev.
pub.dev will not resolve^1.2.0to this version — consumers must opt in explicitly
(e.g.frappe_mobile_sdk: ^2.0.0-beta).
Planned: ~1 month on beta, then a plain2.0.0.
pubspec: 2.0.0-beta · tagged at d66f8cd
Contents are the #102 offline-first release (444 files, +62,348/-2,789).
Bug Fixes
- api: drop response body from OAuth exceptions; add backoff delay cap (6867767)
- attachments: replace orphan sentinel docname with v16 relink flow (3a1c8ba)
- attachments: replace orphan sentinel docname with v16 relink flow (ceadfd8)
- attachments: use fileName ?? fileUrl fallback to prevent null-assert on missing serverFileName (fec859c)
- database: backfill mobile_uuid index on docs__ tables during v4->v5 (H4) (90c70e7)
- database: make security audit log resilient and bounded (7564437)
- database: reconcile schema on save + invalidate meta cache on refresh (ce2bdeb)
- error-log: keep capture resilient to non-String fields and large bodies (c4d5db0)
- example: remove call to deleted getDocumentsByDoctype method (33803c0)
- form: #52b — PhoneField StackOverflow recursion on input (df92de5), closes #52b
- form: avoid duplicate labels and helper texts in InputDecoration (d9d01d8)
- link-options: guard translate hook + parseBool meta flags (PR #80 round-2) (8b9f84f)
- model: read/write doctype_meta_modified_at (corrected key) (9c5e4c8)
- models: read legacy doctype_meta_modifed_at key as a fallback (c24a249)
- offline: DELETE writeback, logout race, drain timeout, meta-missing throw (c62a865)
- offline: never resolve DocType meta inside the write transaction (9041c29), closes #80
- offline: prevent splash deadlock when drain fails (P3 follow-up) (421be60)
- offline: stall guard in PullEngine + AC4 upgrade-pull wiring tests (6da6fcf)
- phone-field: revert toStored — prepend +91 dial code, not strip it (e5aa19d)
- resolve label overflows (#52) and multiple tickers crash (#72) (adb00f0)
- sdk: add multi-select translation tests, strengthen value-key assertion, trim options (411fe9d)
- sdk: app_guard deferrable default, rename tr→sdkTr, drop SearchableSelect doc, debugPrint→sdkLog (06880bb)
- sdk: bump AppDatabase to v4, add kv migration, harden tests (a8901f6)
- sdk: close initial-sync schema gap; expose push/pull/form hooks (811710d)
- sdk: dispose TranslationService and close DAO/stream on SDK teardown (856f85b)
- sdk: guard onChanged emit against closed controller, use in-memory DAO in forTesting (4af00e4)
- sdk: guard security getter and the fire-and-forget initial sync (f18cafb)
- sdk: patch critical FFI issues — instanceFuture retry, factory.getDatabasesPath, PRAGMA order, resetSingleton databaseName (c291244)
- sdk: PR#36 review #1 — push/conflict bugs + 2.0 doc gaps (2c95f2a)
- sdk: PR#36 review #2 — atomicity, async-error surfacing, SQLite < 3.24 compat (cfa82c0)
- sdk: PR#36 round-4 review — concurrency, atomicity & writeback fixes (4a52249)
- sdk: quote identifiers in schema DDL + harden ensureSchemaForClosure loop (3e952e0)
- sdk: replace all debugPrint with sdkLog in sync-critical files to prevent production log leakage (750d8d0)
- sdk: resolve SQLITE_CANTOPEN on Android by calling getDatabasesPath() before sqfliteFfiInit() (d97d44d)
- sdk: TranslationDao — singleInstance false, setUp/tearDown in tests (2a4d9fd)
- sdk: TranslationService — forTesting factory, drain microtask before dao close (290ef79)
- security: bump Android minSdkVersion to 24 (root_checker_plus requirement) (f02ba98)
- security: correct monotonic reboot false-positive + tolerance hardening (31d05dc)
- security: harden tamper-proofing checks and address PR #76 review (9cf6c87)
- security: make FrappeSecurityService typedef aliases public (5de5df3)
- security: make root verdict sticky to block Magisk-hide retry bypass (afecfe8)
- security: use CLOCK_MONOTONIC_RAW on iOS for sleep-inclusive parity with Android elapsedRealtime (e98a455)
- sync: address PR #78 round-1 review (B2, H3) + document dispositions (39658dc)
- sync: drop SyncStateNotifier writes after close (c7fbcf0)
- sync: gate bulk initial-sync path on clean-slate check to prevent dirty/tombstone/ghost-success data loss (7f13783)
- sync: initial-sync offset pagination, fast-fail boot probes, and UX polish (3cbb9e6)
- sync: initial-sync offset pagination, fast-fail boot probes, and UX polish (2705b56)
- sync: make error-log capture non-blocking and crash-safe (dd716ab)
- sync: map FrappeException onto PushError so push errors classify correctly (209f608)
- sync: resolve UUID-shaped local Links + retry server deadlocks on push (0b6538d)
- sync: Stamp server_name on diverged ghost-success inserts (91bc393)
- sync: stop cursor advance on applyServerPage failure and use real document ID in SyncError (80f1583)
- sync: surface paused rows, fix supersede pass, guard isOwnInsertRoundtrip, remove duplicate INSERT (22b9314), closes #4
- sync: treat paused outbox rows as terminal; log UUID-reuse tripwire (70cdc6d)
- test: update translation mock to get_list format; make sync page size configurable (89ff155)
- translation: revert to mobile_auth.get_translations + unconditional SQLite reload (3a533af)
- translations: add generation counter to prevent clearAll race (8a4f26e)
- translations: emit onChanged after _doRefresh even when bulkUpsert throws (70b68ed)
- translation: setLocale is SQLite-only; refreshAll awaited in meta sync (a4e5240)
- translations: guard loadFromCache/refreshAll against logout race (e0cc2eb)
- translations: suppress post-clearAll emit and fix forTesting handle leak (7f7315a)
- ui: call onSaveSuccess before Navigator.pop in FormScreen delete (M8) (3d16313)
- ui: extend didUpdateWidget meta guard to include tab-count change (981f3fe)
- ui: harden BaseField label against RenderFlex overflow on narrow screens (05a306a), closes #72
- ui: make the full dropdown box open the menu (92ed301)
- ui: rebuild reactive Link field when its link_filters source changes (3603480)
- ui: revert geolocation_field FormBuilderField regression from f02ba98 (427aece)
- ui: route paused-row retry through onRetryPaused in SyncErrorsScreen (380cdac)
- ui: use effective tab count for FrappeFormBuilder rebuild guard (M7) (037e221)
- validation: requiredValidator rejects empty Iterable (multi-select unselected) (45a7b34)
Features
- form-builder: programmatic computed-field cascade (Frappe set_value parity) (ab44aa2)
- form-screen: forward customFieldFactory to FrappeFormBuilder (634e792)
- form: add FormValidator for save-time validation and enhance form handling (83134a1)
- form: scroll to first invalid field by name + field robustness (fe6e42d)
- link-options: translate Link & Table MultiSelect option titles for translated_doctype (23ad158)
- link-options: translate Link & Table MultiSelect option titles for translated_doctype (4322332)
- offline-first: wire P3 pull, P4 push, P5 write-path, P6 UX scaffolding (162f238)
- offline: 2.0 release docs, ChildTableInfo consolidation, constructor API cleanup (2d915bf)
- offline: drain/wipe transition handler + UI (P3) (89036dc)
- offline: gate read/write paths on offline_enabled flag (P2) (c9f751c)
- offline: list reads via UnifiedResolver, count API, depends_on parens (5bd0a93)
- offline: OfflineModeNotifier for mid-session mode flip, syncComplete$ stream, system_columns/sqlite_utils DRY helpers (36754d0)
- offline: parallel closure pull + post-sync picker refresh (77eefa3)
- offline: persist server-driven offline_enabled flag (P1) (11aba92)
- offline: SDK 2.0.0 — collapse v2-to-v3 migration, sync engine refactor (f029b7c)
- offline: SyncMutex, SIG-2 push/pull coordination, dispose + SIG-1/9/12 fixes (04c6674)
- sdk: add TranslationDao — standalone KV SQLite cache for translations (b7c0d00)
- sdk: dynamic translation pipeline — tr helper, translateDelegate hook, ARB priority, full UI coverage (0a33fbe)
- sdk: FFI factory swap, WAL+PRAGMA bundle, singleton race guard (592d6b6)
- sdk: inject TranslationDao into TranslationService, replace blocking translation fetch (318c479)
- sdk: thread onFfiInitFailure through FrappeSDK constructor (3b4e069)
- sdk: translate select field display options while preserving English stored keys (a209843)
- sdk: TranslationService — SQLite persistence, refreshAsync, onChanged stream (f64c6c9)
- security: add Android native plugin scaffold + root_checker_plus dep (43c8ad8)
- security: add DB v4→v5 migration for security_state and security_events tables (59242b6)
- security: add FrappeSecurityGuard widget — blocking screen on tamper detection (d009d2c)
- security: add iOS native plugin (monotonic clock via ProcessInfo) (2949349)
- security: add SecurityCheck enum, exception, event model, platform channel (6488582)
- security: implement FrappeSecurityService with 5-check tamper detection (93df787)
- security: wire FrappeSecurityService into FrappeSDK; add public exports (7f9c17f)
- sync: #42 jitter backoff + #53 export outbox types & terminal-error pause (4047643), closes #52
- sync: add retryPaused() to SyncController to recover stuck SUBMIT/CANCEL rows (039194f)
- sync: capture terminal push failures into Mobile Error Log side-channel (b6d364f)
- sync: offline-sync hardening — push/pull race, sync modes, resumable pull, pre-flight manifest (aeefde0)
- translation: get_list API, refreshAllAsync, clearAll on logout, disposed guard, TOCTOU fix (b5ac45c), closes #13
- ui: add showWorkflowActions flag + initial fetch_from for prefilled forms (3905592)
- ui: app-controllable reactive form engine (FormController + FormBuilderMode) (9dbe403)
Performance Improvements
- sdk: batch SQL ops, inject TranslationDao, O(N)→1 link decoration (78146dc)