stem_flutter_sqlite 0.4.0 copy "stem_flutter_sqlite: ^0.4.0" to clipboard
stem_flutter_sqlite: ^0.4.0 copied to clipboard

SQLite adapter helpers for Flutter-hosted Stem runtimes.

stem_flutter_sqlite #

Durable local SQLite storage for the ordinary Stem API in Flutter.

StemFlutterSqlite.createApp() returns a core StemApp with its producer, worker, and result observer sharing managed SQLite stores. There is no required custom worker isolate, port protocol, second task registry, or manual database handle lifecycle.

The current source version, 0.4.0, requires Dart >=3.13.0 <4.0.0, Stem >=0.5.0 <1.0.0, stem_flutter >=0.4.0 <1.0.0, and stem_sqlite >=0.3.0 <1.0.0. Use a Flutter SDK that includes a compatible Dart SDK. It replaces the legacy runtime helpers.

Repository documentation can lead the published release. If you use version 0.3.1 from pub.dev, follow that release's documentation and dependency bounds instead of mixing it with the current source examples.

Getting started #

import 'package:stem_flutter_sqlite/stem_flutter_sqlite.dart';

final syncTask = TaskDefinition<String, String>(
  name: 'sync',
  encodeArgs: (account) => {'account': account},
  decodeArgs: (args) => args['account']! as String,
);

Future<StemApp> openApp() async {
  final app = await StemFlutterSqlite.createApp(
    module: StemModule(
      tasks: [
        syncTask.handler(
          entrypoint: (context, account) async {
            // Perform your asynchronous, idempotent sync here.
            return 'Synced $account';
          },
        ),
      ],
    ),
  );
  try {
    await app.start(); // Creating an app never starts consumption implicitly.
    return app;
  } catch (_) {
    await app.shutdown();
    rethrow;
  }
}

Future<void> enqueueSync(StemApp app) async {
  final id = await syncTask.enqueue(app, 'account-123');
  final result = await syncTask.waitFor(app, id);
  print(result?.value);
}

Keep the returned app at application scope, inject it into screens/services, and call app.shutdown() when that owner is finished. Shutdown closes the worker, backend, and broker once. A new app can reopen the same files.

The package re-exports stem_flutter and the stable core Stem API. Existing app.enqueue, app.enqueueCall, app.waitForTask, app.getTaskStatus, app.registerModule, and app.canvas code works unchanged.

Storage and configuration #

By default, files live under the application support directory:

stem_flutter/
  broker.sqlite
  backend.sqlite

The separate files preserve the adapter's existing layout and reduce competition between queue and result writes. Existing default-layout data does not need to be moved. To reuse a custom directory, supply its existing layout.

final app = await StemFlutterSqlite.createApp(
  module: myModule,
  layout: myExistingLayout, // Optional; defaults to application support.
  storage: const StemFlutterSqliteConfig(
    namespace: 'my-app',
    resultTtl: Duration(days: 7),
  ),
  workerConfig: const StemWorkerConfig(concurrency: 2),
);

StemFlutterSqliteConfig is the single source for broker/backend namespace, visibility timeout, polling, maintenance, and retention. Defaults match the underlying SQLite adapter rather than the old example's short leases and effectively disabled result cleanup. Worker settings use core StemWorkerConfig; queues are inferred from modules as in Stem.

Application-support directory names and helper file names must be single names, not paths. Use StemFlutterStorageLayout.forRoot for an explicit root, or the explicit layout constructor for advanced file paths.

Mobile behavior #

  • The worker coordinator and database connections live in the calling isolate. Async inline handlers can use Flutter plugins. For CPU-heavy task bodies, select core Stem's isolate execution mode instead of blocking the UI isolate. The SQLite driver itself is synchronous; expensive database work still affects the isolate that owns the coordinator.
  • Persisted queued tasks and results survive reopening, subject to retention.
  • Interrupted deliveries become eligible for recovery after their visibility lease expires. A handler may run again even if its previous side effect succeeded. Use idempotent handlers.
  • OS suspension and process termination are normal. Neither SQLite persistence nor a Dart isolate guarantees background execution. OS scheduling is outside this package.
  • Do not call shutdown() on every inactive/paused transition. It is final teardown, not a resumable pause.

Background scheduler integration #

The app owns Workmanager or other native scheduler registration; Stem should own execution within the granted window. SQLite is the shared durable queue, not the OS scheduler. A callback must open its own handles with the same paths, namespace, and task module; it cannot reuse a foreground Ormed data source across isolates.

Use the returned core app directly:

final app = await StemFlutterSqlite.createApp(module: myModule);
final outcome = await app.runUntilIdle(
  budget: const Duration(seconds: 30),
  shutdownReserve: const Duration(seconds: 5),
);
// Inspect outcome.reason; this app and its owned stores are now closed.

Do not call start() before runUntilIdle. Its budget limits new admissions, not arbitrary active handler duration; active work must drain safely. See the background execution guide for callback-local initialization, cancellation, retry/wakeup ownership, and limits on heavy workloads while minimized.

For diagnostics, use core Stem APIs such as app.backend.listTaskStatuses, app.broker.pendingCount, app.broker.inflightCount, and app.worker.events. The example owns its debug dashboard and presentation lifecycle. No Flutter monitor, snapshot model, or worker-status protocol is required.

Migration #

The following legacy APIs and wiring have been removed:

  • StemFlutterSqliteRuntime.open for a producer-only client;
  • an app-written worker bootstrap/command loop;
  • root isolate tokens, dependency-asset payloads, and duplicated store options;
  • manually binding worker-host signals to a queue monitor.

Use StemFlutterSqlite.createApp instead and register tasks once. Keep your existing TaskDefinition, StemModule, and task invocation APIs. The old producer runtime, launcher, worker stores, and bootstrap types are not retained as compatibility wrappers. If you supply stores manually, use core StemBrokerFactory/StemBackendFactory with StemFlutter.createApp or core bootstrap directly. Caller-owned Ormed data sources can still be wrapped by SqliteBroker.fromDataSource and SqliteResultBackend.fromDataSource from stem_sqlite; the factories determine adapter disposal, and the data source remains caller-owned.

Call await StemFlutterSqlite.initialize() before manually opening those Ormed-backed stores. Ormed initializes Carbonized, which needs Flutter assets for its TimeMachine dependency. The convenience createApp handles this automatically; adapter-neutral StemFlutter.createApp does not initialize ORM dependencies.

Workflow composition remains available through core Stem APIs. Durable workflows also require a workflow store such as sqliteWorkflowStoreFactory from stem_sqlite; the task result backend alone is not a workflow store. No workflow storage is silently substituted by this task bootstrap.

See packages/stem/example/flutter_stem_example for the complete mobile example.

Tests #

Run Flutter tests from this package directory so Flutter includes dependency assets and SQLite native assets:

cd packages/stem_flutter_sqlite
flutter test
0
likes
140
points
251
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

SQLite adapter helpers for Flutter-hosted Stem runtimes.

Repository (GitHub)
View/report issues
Contributing

License

MIT (license)

Dependencies

flutter, path_provider, stem, stem_flutter, stem_sqlite, time_machine2

More

Packages that depend on stem_flutter_sqlite