โ† Core
In the workslicense: BSD-3-Clause

tom_core_flutter

tom_core_flutter ยท v1.2.1

The thin binding layer that brings the kernel onto a Flutter target: it re-exports the whole kernel barrel and tom_reflection, and adds widgets that bind to observable kernel state, form primitives, typed UI properties, client-side platform detection and client auth helpers.

See License
Status
In the works
LOC
2.4k
Tests
558
Test LOC
326.7k

Overview

From the module readme.md file:

What it enables

Enables Flutter clients on the kernel, Observable-bound widgets, Client-side auth.

Relationships

Standalone โ€” no declared relationships.

tom_core_flutter

> Attribution. The Tom Framework is developed by Peter Nicolai Alexis Kyaw. > These packages are BSD-3-Clause licensed and internal (publish_to: none).

> โš ๏ธ Work in progress โ€” unstable API. The Tom Core packages are under active > development and not yet stable. Their version numbers carry no promise about > API maturity: they are publishing counters, not semver. The patch number is > bumped on every change โ€” including breaking changes โ€” so a patch bump may > break you. Expect the public surface to shift without notice. Not recommended > for production use yet.

Flutter integration layer for the Tom Framework โ€” re-exports tom_core_kernel and adds Flutter widgets and client utilities.

Overview

tom_core_flutter is the thin binding layer that brings the platform-neutral tom_core_kernel onto a Flutter target. It re-exports the entire kernel barrel (observable state, dependency injection, security, resources, runtime utilities) plus tom_reflection, so a Flutter app that depends on tom_core_flutter gets both the kernel API and the Flutter-specific extensions through a single import.

What it adds on top of the kernel is deliberately small:

  • Observing widgets that rebuild when a kernel TomObservable notifies.
  • UI-bound properties โ€” typed TomProperty<T> accessors over the kernel

resource tree. - Client configuration โ€” a machine-scoped settings holder that resolves from the shipped config resources, persists this install's overrides, and is observable per field and as a whole. - Preferences โ€” machine-local user preferences behind one platform-independent API, with the storage backend chosen by DI rather than by an if (kIsWeb) at the call site, plus the typed client for the account-level preferences the server holds. - Client platform detection โ€” the Flutter/web/IO variant selector for TomPlatformUtils. - Client security โ€” the framework-owned second-factor flow: a ready-made enrol-and-challenge panel over a seam onto the application's own auth client, pluggable per-mechanism rendering resolved through a registry, and the shipped TOTP mechanism.

Relationship to tom_flutter_ui

tom_core_flutter is the low-level binding layer; it is not the application widget toolkit. The rich, ACL-aware widget set โ€” the declarative forms framework, the advanced-container-layout engine, theming, and resource_auth โ€” lives in tom_flutter_ui. Any UI or forms work should reach for tom_flutter_ui; tom_core_flutter only carries the kernel binding helpers.

The two demo/test harnesses make the split concrete: tom_flutter_form_test and tom_flutter_ui_test target tom_flutter_ui + tom_core_kernel directly โ€” they do not depend on tom_core_flutter. Reach for tom_core_flutter when you want the kernel on Flutter with the minimal binding helpers; reach for tom_flutter_ui when you want the full UI/forms/ACL toolkit.

Installation

This package is internal to the Tom workspace and consumed by path (it is publish_to: none), so there is no dart pub add line:

dependencies:
  tom_core_flutter:
    path: ../tom_core_flutter

Then import the single barrel โ€” it re-exports tom_core_kernel and tom_reflection, so you rarely import those directly:

import 'package:tom_core_flutter/tom_core_flutter.dart';

SDK: Dart ^3.10.4 with the Flutter SDK. Modules that use reflection (security adaptors) require dart run build_runner build to generate *.reflection.dart.

Features

Observing widgets (observing)

TypeWhat it is
TomObservingWidget<T extends TomObservable> A StatefulWidget that rebuilds its child builder whenever the bound subState notifies
TomObservingWidgetState<T> The TomObserver state behind the widget (registers/rebuilds on notify)
ValueListenableObserver<T extends TomObservable> Bridges a kernel TomObservable to a Flutter Listenable/listener

Resources (resources)

TypeWhat it is
TomProperty<T> Typed accessor over the kernel resource/config tree, with .withDefault fallback
TomStringProperty / TomIntProperty / TomDoubleProperty / TomBoolProperty Concrete typed property variants

Client configuration (configuration)

TypeWhat it is
TomBaseClientConfiguration Base class for a client app's machine-scoped settings holder โ€” declare, load, observe, persist
TomSetting<T> One observable setting: a TomObject<T> plus its dotted key and its baseline
TomClientConfigurationStore Two-method interface (read / write) for where overrides are persisted
TomMemoryClientConfigurationStore / TomFileClientConfigurationStore Process-lifetime and JSON-file stores
TomClientConfigurationException Module failures, with stable dotted keys

Only the install's overrides are persisted, so shipping a new default in an app update still reaches installs that never touched that key. See doc/configuration.md.

Preferences (preferences)

TypeWhat it is
TomDevicePreferences The typed API for this device's preferences โ€” resolved as a bean, never constructed at the call site
TomStoredDevicePreferences The shipped implementation: the typed API over a store, holding the single encode/decode decision
TomDevicePreferenceStore Two-method ( read / write ) backend interface โ€” the only platform-specific part
TomPlatformDevicePreferenceStore The backend for the current target (JSON file / localStorage / loud failure), selected at compile time
TomMemoryDevicePreferenceStore A store that persists nothing beyond the process
TomDevicePreferenceJson The stored JSON document, written once for every persistent backend
TomDevicePreferenceException Device-store failures, with stable dotted keys
TomUserPreferencesClient The typed client for the account's preferences โ€” the same method set, over the server's /preferences/* routes
TomUserPreferencesClientException Client failures, with stable dotted keys

Two stores, one vocabulary. Preferences that must not follow the user โ€” the last account used here, whether biometric unlock is on this device โ€” stay on the device; the ones that should follow the user live server-side and are reached through TomUserPreferencesClient. The keys, the DTO and the codec are the kernel's and both stores carry the same method set, so a preference can move between them without a call site changing. The client writes no URIs: every request is resolved from the kernel's tomUserPreferencesApi declaration, so it and the server are two readings of one contract. See doc/preferences.md.

Runtime (runtime)

TypeWhat it is
clientPlatformUtils Returns the platform-appropriate TomPlatformUtils (Flutter/web/IO/neutral), selected at compile time

Security (security)

TypeWhat it is
Tom2FAFlowPanel Renders whichever stop of a second-factor login the controller reports โ€” chooser, enrolment or challenge
Tom2FAFlowController The seam an application implements over its own auth client: five moves, two pieces of read-only state
Tom2FAClientMechanism One mechanism's client-side rendering, paired with its server adaptor by mechanism key alone
Tom2FAClientRegistry The process-wide mechanism catalog the flow dispatches through
Tom2FAEnrolmentPanelContext / Tom2FAChallengePanelContext What a mechanism's two panels are given to render themselves
TomTotp2FAClientMechanism The shipped authenticator-app mechanism, registered under 'totp'
Tom2FATexts Every resource key the second-factor UI resolves, and the helpers that resolve them
TomQrCodeView A QR code painted from the pure-Dart qr encoder, themed like any other widget

Little things (little_things)

TypeWhat it is
TomClientException Client-side exception extending the kernel TomException
TomClientUIException UI-surfaced client exception (extends TomClientException)

Quick start

Rebuild a widget automatically whenever an observable kernel value changes:

import 'package:tom_core_flutter/tom_core_flutter.dart';

final counter = TomInt(0);

final widget = TomObservingWidget<TomInt>(
  subState: counter,
  builder: (state, _) => Text('Count: ${~state}'), // ~ reads the value
);

counter | 5; // | sets the value โ†’ the widget rebuilds with "Count: 5"

Example projects

Each module ships a self-contained example under example/. Because the barrel pulls in flutter/material (and thus dart:ui), run them under the Flutter toolchain (flutter test / a Flutter entry point).

ExampleDemonstrates
example/observing/ ValueListenableObserver bridging a TomObservable to a Flutter listener
example/resources/ Resolving typed config via TomProperty subclasses and .withDefault , and both construction-time failures โ€” an unconfigured obligatory key and a value of the wrong type
example/configuration/ Declaring a client settings holder, loading overrides, observing, and persisting only what changed
example/preferences/ Registering a device store once, typed reads/writes, persistence across a restart, reading and writing the account store over a real socket, and the device-over-server precedence
example/runtime/ Obtaining the platform-appropriate TomPlatformUtils , querying its predicates beside the Flutter target that decides them, and taking an HTTP client from it
example/security/ Walking a Tom2FAFlowController through all three stops of a second-factor login โ€” chooser, enrolment and challenge โ€” plus the registry rule that decides what the chooser may list, and resource resolution with its missing-key behaviour
example/little_things/ The two client exception types and the type-based discrimination pattern

> Cross-package sample. The > tom_core_samples/core_client_sample > project builds a login-gated todo client on this package โ€” CRUD forms whose > fields render hidden / read-only / disabled / editable straight from the > role's four-state authorization matrix. See the > samples map for the full learning path.

Usage

Observing kernel state in a widget

final name = TomString('Ada');

TomObservingWidget<TomString>(
  subState: name,
  builder: (state, _) => Text(~state), // rebuilds on every notify
);

name | 'Grace'; // widget now shows "Grace"

Reading typed configuration

final timeout = TomIntProperty.withDefault('http.timeoutSeconds', 30);
final seconds = ~timeout; // 30 when the key is unset

Holding this install's settings

class AppConfiguration extends TomBaseClientConfiguration {
  AppConfiguration({super.store});

  late final TomSetting<bool> darkMode;

  @override
  void declareSettings() {
    darkMode = boolSetting('client.ui.darkMode', false);
  }
}

final config = AppConfiguration(store: TomFileClientConfigurationStore(path));
await config.load();     // adopt this install's persisted overrides
config.darkMode | true;  // observers fire, per field and holder-wide
await config.save();     // persist the overrides โ€” and only those

Storing a preference on this device, and on the account

// The one line in an application that knows where machine-local state lives.
TomBean.withType(
  TomDevicePreferences,
  TomStoredDevicePreferences(TomPlatformDevicePreferenceStore(location)),
);

final preferences = TomDevicePreferences.resolve()!;
await preferences.set('device.biometricUnlock', true);

// The account store: the same method set, no URI written by the caller.
final account = TomUserPreferencesClient(baseUri: Uri.parse(serverRoot));
await account.set(TomUserPreferenceKeys.theme, 'dark');

// Device value wins while it exists; the account value is the cross-device
// default, consulted only for a key this device has never written. The account
// side stays a callback so a device-only app need not carry an HTTP client.
final theme = await preferences.getPreferred<String>(
  TomUserPreferenceKeys.theme,
  () => account.get<String>(TomUserPreferenceKeys.theme),
);

Selecting the client platform utils

TomPlatformUtils.setCurrentPlatform(clientPlatformUtils);
// concrete variant (Flutter IO / web / neutral) chosen at compile time

Architecture

        Flutter app
             โ”‚
   import 'package:tom_core_flutter/tom_core_flutter.dart'
             โ”‚  (re-exports the kernel + tom_reflection)
   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
 observing  resources   runtime     security   configuration   preferences
 (rebuild) (TomProperty) (platform) (2FA marker) (install       (device-local
                                                  settings)      values)
             โ”‚
       tom_core_kernel  (TomObservable, TomObject,
                         TomUserPreferenceDto / Keys / Codec, โ€ฆ)
             โ”‚  (re-exports the whole of tom_basics)
         tom_basics     (TomPlatformUtils, TomFallbackPlatformUtils, โ€ฆ)
TypeResponsibility
TomObservingWidgetRebuilds a subtree when its observable notifies
ValueListenableObserver Adapts a TomObservable to a Flutter listener
TomProperty<T>Typed accessor over the kernel resource tree
TomBaseClientConfiguration Owns the machine-scoped settings of one install
TomSetting<T>One observable, persistable setting
TomClientConfigurationStorePersists the install's overrides
TomDevicePreferences The typed, platform-independent API for this device's preferences
TomDevicePreferenceStore Persists the device's preferences (file / localStorage)
clientPlatformUtils Selects the concrete TomPlatformUtils for Flutter
TomClientExceptionBase client-side exception type

Ecosystem

tom_basics ยท tom_crypto ยท tom_reflection
                 โ”‚
          tom_core_kernel
                 โ”‚
        โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
 tom_core_flutter     tom_flutter_ui
 (kernel-on-Flutter   (rich widgets, forms,
  binding layer)       ACL, theming)
        โ† you are here

tom_core_flutter sits directly on tom_core_kernel and re-exports it, so Flutter apps get the full kernel API through one dependency. The richer widget toolkit lives in tom_flutter_ui. See the repository map for the full picture.

Further documentation

  • Per-module guides under doc/ โ€” one markdown file per module

(doc/observing.md, doc/resources.md, doc/configuration.md, doc/preferences.md, doc/runtime.md, doc/security.md, doc/little_things.md). - Per-module API reference under doc/api_reference/ โ€” start at doc/api_reference/api_summary_index.md for the type index and one api_summary_{module}.md per module. (doc/api/ is reserved for generated dart doc HTML and is gitignored.) - tom_core_kernel โ€” the platform-neutral building blocks re-exported here. - tom_flutter_ui โ€” the full UI/forms/ACL toolkit the demo apps target.

Status

  • Version: 1.2.1
  • Tests: a module suite per module, each of which also runs the example

it documents, plus three guards over what the package says about itself: one over the markdown โ€” its links, its anchors, its tables of contents and the dependencies each module document claims โ€” one over the command each example tells a reader to run, and one over the comments in the test files themselves, which may state the contract under test but neither the phase of their own authorship nor a numbered section of a document that was never committed (all with flutter test). Two module suites additionally hold their own documents to what the code does: the preferences store's list-ownership contract, and โ€” in resources โ€” the recommendation to prefer a typed subclass together with its nullable-T exception, and the wording and number of the failures the module throws.

No count is given: a count is a claim nothing checks, and every added test would be a README edit nobody makes. What the suites do is the part worth stating, and it does not drift with the count. - License: BSD-3-Clause โ€” see LICENSE.

License
BSD 3-Clause License

Copyright (c) 2024-2026, Peter Nicolai Alexis Kyaw
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its
   contributors may be used to endorse or promote products derived from
   this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.