PackageTrack
Sign in Get early access

bones_api

Bones_API - A powerful API backend framework for Dart. It comes with a built-in HTTP Server, route handler, entity handler, SQL translator, and DB adapters.

1.15.2 3.2K downloads/mo #4543 most downloaded on pub.dev Colossus-Services/bones_api

What this package is like to depend on

Last release 12 days ago

12 Aug 2026

Ships fairly regularly

a new release about every 3 weeks

Nearly every release is documented

notes for 331 of 331 stable releases

Nothing withdrawn

no release was ever pulled

5 years old

351 releases · first in 2021

30 releases in the last 12 months

see the full history below

Release timeline

351 releases · Jul 2021 to Aug 2026
2022 2023 2024 2025 2026
Release Pre-release

Releases

latest 60 of 351
  1. 1.15.2 12 Aug 2026
    Release notes
    • The placeholder pruning added in 1.15.1 no longer runs on every encoded
      condition.

      Rewriting field == ? bound to null into field IS NULL leaves that
      parameter unreferenced, and 1.15.1 found it by materializing the encoded
      output and scanning it for every placeholder. That cost was paid by every
      query, including the overwhelmingly common one that compares nothing against
      null: ~0.30us per encoded condition (measured on a 3-placeholder
      condition), against the ~0.90us of a whole logged route call after the 1.15.0
      dispatch work.

      Only a placeholder actually rewritten to IS NULL/IS NOT NULL can become
      unreferenced, so those keys are now recorded as they are written, and a
      condition that compares nothing against null returns immediately — without
      materializing the output or scanning it. The output is materialized lazily
      even then, since a recorded key may still be referenced by another operator.

      No behaviour change: same statements, same bound parameters.

    Open source →
    Release notes
    • The placeholder pruning added in 1.15.1 no longer runs on every encoded condition.

      Rewriting field == ? bound to null into field IS NULL leaves that parameter unreferenced, and 1.15.1 found it by materializing the encoded output and scanning it for every placeholder. That cost was paid by every query, including the overwhelmingly common one that compares nothing against null: ~0.30us per encoded condition (measured on a 3-placeholder condition), against the ~0.90us of a whole logged route call after the 1.15.0 dispatch work.

      Only a placeholder actually rewritten to IS NULL/IS NOT NULL can become unreferenced, so those keys are now recorded as they are written, and a condition that compares nothing against null returns immediately — without materializing the output or scanning it. The output is materialized lazily even then, since a recorded key may still be referenced by another operator.

      No behaviour change: same statements, same bound parameters.

    Open source →
    Release notes

    v1.15.2 Latest

    Latest

    Compare

    Choose a tag to compare

    Open source →
  2. 1.15.1 12 Aug 2026
    Release notes
    • Fixed: a condition comparing a field to null passed as a parameter was
      encoded as field = ? bound to null. = NULL is never true in SQL, so the
      query returned no rows instead of the rows whose column is null.

      ConditionSQLEncoder did turn =/IN against null into IS NULL (and
      !=/NOT IN into IS NOT NULL), but only when the null was written
      straight into the statement. A null arriving as a parameter is encoded as a
      placeholder, whose text never equals 'null', so the conversion was skipped.
      Entity queries take the parameter form, which is why it surfaced there:

      // Returned [] with matching rows present; now returns the rows whose
      // `state` is null.
      repository.selectByQuery(' state == ? && active == ? ',
          parameters: {'state': null, 'active': true});

      The encoder is shared, so this affected every SQL adapter — SQLite,
      PostgreSQL and MySQL alike — and any condition compared against a null
      parameter, including compound ones whose other terms matched.

      Rewriting the comparison also leaves the parameter unmentioned by the
      statement, so it is now dropped once the condition is encoded: PostgreSQL
      rejects a statement carrying variables it does not use. A placeholder still
      referenced by another operator (field > ? bound to null) keeps its binding.

      Covered now by the shared adapter test suite, so all three adapters exercise
      it.

    • reflection_factory: ^2.8.1^2.9.0.

      • 2.8.1 pinned dart_style to the formatter bundled with Dart 3.12, so on
        Dart 3.13 the generated *.reflection.g.dart no longer matched this
        package's own dart format, making dart format --set-exit-if-changed and
        test/ensure_build_test.dart mutually exclusive. 2.9.0 tracks the
        formatter the SDK ships.
    Open source →
    Release notes
    • Fixed: a condition comparing a field to null passed as a parameter was encoded as field = ? bound to null. = NULL is never true in SQL, so the query returned no rows instead of the rows whose column is null.

      ConditionSQLEncoder did turn =/IN against null into IS NULL (and !=/NOT IN into IS NOT NULL), but only when the null was written straight into the statement. A null arriving as a parameter is encoded as a placeholder, whose text never equals 'null', so the conversion was skipped. Entity queries take the parameter form, which is why it surfaced there:

      // Returned [] with matching rows present; now returns the rows whose
      // `state` is null.
      repository.selectByQuery(' state == ? && active == ? ',
          parameters: {'state': null, 'active': true});
      

      The encoder is shared, so this affected every SQL adapter — SQLite, PostgreSQL and MySQL alike — and any condition compared against a null parameter, including compound ones whose other terms matched.

      Rewriting the comparison also leaves the parameter unmentioned by the statement, so it is now dropped once the condition is encoded: PostgreSQL rejects a statement carrying variables it does not use. A placeholder still referenced by another operator (field > ? bound to null) keeps its binding.

      Covered now by the shared adapter test suite, so all three adapters exercise it.

    • reflection_factory: ^2.8.1^2.9.0.

      • 2.8.1 pinned dart_style to the formatter bundled with Dart 3.12, so on Dart 3.13 the generated *.reflection.g.dart no longer matched this package's own dart format, making dart format --set-exit-if-changed and test/ensure_build_test.dart mutually exclusive. 2.9.0 tracks the formatter the SDK ships.
    Open source →
    Release notes

    v1.15.1

    Compare

    Choose a tag to compare

    Open source →
  3. 1.15.0 12 Aug 2026
    Release notes
    • Faster request dispatch. A logged route call is ~2.9x faster
      (measured in-process, APIRoot.call on a trivial route: 2.76us -> 0.90us).

      • LoggerHandler no longer builds the formatted log message when nothing
        would consume it. Every record reaching the root listener was fully
        formatted — timestamp, padded/truncated isolate and logger names, plus a
        Zone lookup for the current APIRequest id — and then discarded when no
        destination (logAllTo/logErrorTo/logDbTo/console) was configured,
        which is the default. This was ~1us per record, and a route call emits two
        (CALL> and RESPONSE>).
      • APIRouteHandler caches its CALL> message and RESPONSE> prefix. Both
        are fixed once a route is registered, but were re-interpolated per request
        (including stringifying the declared parameters Map).
      • APIRoot._callImpl no longer copies the path parts list just to read the
        first one.
      • APIServer.toAPIRequest no longer copies the query-parameters Map a
        second time.
    • The routes builder now accepts config: on any/get/post/put/
      delete/patch/head, matching APIModule.addRoute. Previously an
      APIRouteConfig could only be set through addRoute, so per-route logging
      could not be turned off through the usual API:

      routes.get('ping', handler, config: const APIRouteConfig(log: false));

      Route logging is on by default and costs roughly 4x the rest of a trivial
      dispatch, so this is worth setting on hot routes.

    • New benchmark/ suites, with layered breakdowns so a regression can be
      attributed rather than just observed. See benchmark/README.md.

      dart run benchmark/bones_api_benchmark.dart   # request path
      dart run benchmark/json_benchmark.dart        # JSON request/response
      dart run benchmark/db_benchmark.dart          # DB entity path
      

      They record that query parsing is well cached (~300x cheaper than parsing)
      and SQL generation is under a microsecond. JSON encoding already runs close
      to a bare dart:convert encode, and request bodies use dart:convert
      directly, so no JSON optimization came out of that suite.

    • DBSQLMemoryAdapter now answers a select by ID with a direct lookup in the
      table Map, which is already keyed by ID, instead of scanning it. A miss
      still falls through to the scan, so results are unchanged.

      selectByID was O(rows) and is now flat: 7.8us -> 7.1us at 10 rows,
      9.7us -> 7.2us at 50, and 25.3us -> 7.2us at 400. This mostly speeds up the
      test suite and development, since the memory adapter is where those run.

    Open source →
    Release notes
    • Faster request dispatch. A logged route call is ~2.9x faster (measured in-process, APIRoot.call on a trivial route: 2.76us -> 0.90us).

      • LoggerHandler no longer builds the formatted log message when nothing would consume it. Every record reaching the root listener was fully formatted — timestamp, padded/truncated isolate and logger names, plus a Zone lookup for the current APIRequest id — and then discarded when no destination (logAllTo/logErrorTo/logDbTo/console) was configured, which is the default. This was ~1us per record, and a route call emits two (CALL> and RESPONSE>).
      • APIRouteHandler caches its CALL> message and RESPONSE> prefix. Both are fixed once a route is registered, but were re-interpolated per request (including stringifying the declared parameters Map).
      • APIRoot._callImpl no longer copies the path parts list just to read the first one.
      • APIServer.toAPIRequest no longer copies the query-parameters Map a second time.
    • The routes builder now accepts config: on any/get/post/put/ delete/patch/head, matching APIModule.addRoute. Previously an APIRouteConfig could only be set through addRoute, so per-route logging could not be turned off through the usual API:

      routes.get('ping', handler, config: const APIRouteConfig(log: false));
      

      Route logging is on by default and costs roughly 4x the rest of a trivial dispatch, so this is worth setting on hot routes.

    • New benchmark/ suites, with layered breakdowns so a regression can be attributed rather than just observed. See benchmark/README.md.

      dart run benchmark/bones_api_benchmark.dart   # request path
      dart run benchmark/json_benchmark.dart        # JSON request/response
      dart run benchmark/db_benchmark.dart          # DB entity path
      

      They record that query parsing is well cached (~300x cheaper than parsing) and SQL generation is under a microsecond. JSON encoding already runs close to a bare dart:convert encode, and request bodies use dart:convert directly, so no JSON optimization came out of that suite.

    • DBSQLMemoryAdapter now answers a select by ID with a direct lookup in the table Map, which is already keyed by ID, instead of scanning it. A miss still falls through to the scan, so results are unchanged.

      selectByID was O(rows) and is now flat: 7.8us -> 7.1us at 10 rows, 9.7us -> 7.2us at 50, and 25.3us -> 7.2us at 400. This mostly speeds up the test suite and development, since the memory adapter is where those run.

    Open source →
    Release notes

    v1.15.0

    Compare

    Choose a tag to compare

    Open source →
  4. 1.14.0 11 Aug 2026
    Release notes
    • New DBSQLiteAdapter: an embedded SQLite DB adapter, backed by the
      sqlite3 package.

      import 'package:bones_api/bones_api_db_sqlite.dart';
      
      var adapter = DBSQLiteAdapter('/var/lib/myapp/db.sqlite',
          generateTables: true);
      
      // Or an in-memory database:
      var memoryAdapter = DBSQLiteAdapter(':memory:', generateTables: true);
      • Registered as sqlite, sqlite3, sql.sqlite and sql.sqlite3, so a
        config block db: { sqlite: {...} } resolves it.

      • fromConfig accepts path/file/database/db for the database file,
        and memory: true (or the path :memory:) for an in-memory database, plus
        the usual generateTables/checkTables/populate/log.sql keys.
        Irrelevant keys (host, port, username, password) are accepted and
        ignored, so a config can be pointed at SQLite without being rewritten.

      • No server and no native library to install: the sqlite3 package
        bundles SQLite (3.53.4) through Dart's build hooks.

      • Runs the same entity test-suite as the PostgreSQL and MySQL adapters, and
        needs no Docker container to do it. New APITestConfigSQLite, exported by
        package:bones_api/bones_api_test_sqlite.dart.

      • Notes on the SQLite dialect:

        • An auto-assigning ID is declared INTEGER PRIMARY KEY AUTOINCREMENT:
          SQLite has no SERIAL/AUTO_INCREMENT, only a column declared exactly
          INTEGER PRIMARY KEY aliases the rowid, and without AUTOINCREMENT
          SQLite reuses the ID of a deleted row.
        • ENUM is emulated with a VARCHAR CHECK (col IN (...)) constraint.
        • Since sqlite3 is a synchronous driver, and SQLite allows a single
          writer, the adapter uses one native handle shared by every pooled
          connection: a second handle blocking on a lock would stall the isolate
          holding it, and offers nothing to gain when there is no I/O to overlap.
          Nested transactions use SAVEPOINT.
    • New SQLDialect.returningAcceptsTableWildcard (default true, so the
      PostgreSQL/MySQL/memory dialects are unchanged). SQLite rejects the
      table-qualified wildcard that DELETE ... RETURNING emits
      ("RETURNING may not use TABLE.* wildcards") and needs a bare
      RETURNING *.

    • Fixed DBObjectDirectoryAdapter losing objects written just before a read:
      _saveObject was async and its Future was dropped by doInsert/
      doUpdate, while every reader in the adapter inspects the filesystem
      synchronously. A store could therefore return before its object was on
      disk, and selectAll would silently omit it (a not-yet-written file reads
      back as null and was discarded). The write is now synchronous.

    • Breaking: the minimum Dart SDK is now 3.10.0 (was 3.7.0), required by
      sqlite3 and its build hooks.

    • Dependencies:

      • Added sqlite3: ^3.5.1
    Open source →
    Release notes
    • New DBSQLiteAdapter: an embedded SQLite DB adapter, backed by the sqlite3 package.

      import 'package:bones_api/bones_api_db_sqlite.dart';
      
      var adapter = DBSQLiteAdapter('/var/lib/myapp/db.sqlite',
          generateTables: true);
      
      // Or an in-memory database:
      var memoryAdapter = DBSQLiteAdapter(':memory:', generateTables: true);
      
      • Registered as sqlite, sqlite3, sql.sqlite and sql.sqlite3, so a config block db: { sqlite: {...} } resolves it.

      • fromConfig accepts path/file/database/db for the database file, and memory: true (or the path :memory:) for an in-memory database, plus the usual generateTables/checkTables/populate/log.sql keys. Irrelevant keys (host, port, username, password) are accepted and ignored, so a config can be pointed at SQLite without being rewritten.

      • No server and no native library to install: the sqlite3 package bundles SQLite (3.53.4) through Dart's build hooks.

      • Runs the same entity test-suite as the PostgreSQL and MySQL adapters, and needs no Docker container to do it. New APITestConfigSQLite, exported by package:bones_api/bones_api_test_sqlite.dart.

      • Notes on the SQLite dialect:

        • An auto-assigning ID is declared INTEGER PRIMARY KEY AUTOINCREMENT: SQLite has no SERIAL/AUTO_INCREMENT, only a column declared exactly INTEGER PRIMARY KEY aliases the rowid, and without AUTOINCREMENT SQLite reuses the ID of a deleted row.
        • ENUM is emulated with a VARCHAR CHECK (col IN (...)) constraint.
        • Since sqlite3 is a synchronous driver, and SQLite allows a single writer, the adapter uses one native handle shared by every pooled connection: a second handle blocking on a lock would stall the isolate holding it, and offers nothing to gain when there is no I/O to overlap. Nested transactions use SAVEPOINT.
    • New SQLDialect.returningAcceptsTableWildcard (default true, so the PostgreSQL/MySQL/memory dialects are unchanged). SQLite rejects the table-qualified wildcard that DELETE ... RETURNING emits ("RETURNING may not use TABLE.* wildcards") and needs a bare RETURNING *.

    • Fixed DBObjectDirectoryAdapter losing objects written just before a read: _saveObject was async and its Future was dropped by doInsert/ doUpdate, while every reader in the adapter inspects the filesystem synchronously. A store could therefore return before its object was on disk, and selectAll would silently omit it (a not-yet-written file reads back as null and was discarded). The write is now synchronous.

    • Breaking: the minimum Dart SDK is now 3.10.0 (was 3.7.0), required by sqlite3 and its build hooks.

    • Dependencies:

      • Added sqlite3: ^3.5.1
    Open source →
    Release notes

    v1.14.0

    Compare

    Choose a tag to compare

    Open source →
  5. 1.13.0 02 Aug 2026
    Release notes
    • New EntityPagination.onEvent: an optional hook notified of what is being
      fetched, for progress reporting and logging.

      var p = userRepository.paginateByQuery(' state == ? ',
          parameters: ['NY'], limit: 20, onEvent: (event) {
        switch (event) {
          case EntityPaginationPageLoading(:var page):
            print('fetching page $page...');
          case EntityPaginationPageLoaded(:var page, :var entriesLength):
            print('page $page: $entriesLength entries');
          case EntityPaginationPageError(:var page, :var error):
            print('page $page failed: $error');
          case EntityPaginationPageSkipped(:var page, :var reason):
            print('page $page not fetched: ${reason.name}');
          case EntityPaginationEnd(:var totalLength):
            print('done: $totalLength entries');
          case EntityPaginationReset(:var discardedPages):
            print('discarded ${discardedPages.length} pages');
        }
      });
      • Delivered synchronously, at the point where it happens and in order, so
        it is also correct for a synchronous EntityPageLoader (a Stream would
        only deliver in a later microtask, after a sync read already finished).
        To consume it as a stream, forward it: onEvent: myEventStream.add.
      • onEvent is not final, so it can also be attached to an already built
        EntityPagination. Only events emitted afterwards are seen.
      • An exception thrown by the listener is reported to the current Zone and
        does not break the fetch.
      • Nothing is allocated (not even the fetch timer) while onEvent is null.
    • New EntityPaginationEvent<O>, a sealed hierarchy so a switch over it is
      exhaustive, with EntityPaginationListener<O> as the callback type:

      • EntityPaginationPageLoading: a fetch is about to start. Emitted once per
        actual fetch.
      • EntityPaginationPageLoaded: a fetch finished, with the entries, the
        entriesLength, the elapsedTime of the pageLoader and isFinalPage.
      • EntityPaginationPageError: a fetch failed, with the error, the
        stackTrace and the elapsedTime. The error is rethrown to the caller
        right after the event.
      • EntityPaginationPageSkipped: a page was served without a fetch, with an
        EntityPaginationSkipReason: alreadyLoaded, inFlight (a concurrent
        request shares the fetch) or knownEmpty (past the resolved end). Not an
        error — it is what makes a repeated, concurrent or past-the-end read free.
      • EntityPaginationEnd: the end was resolved, with the finalPage and the
        totalLength. Emitted once, immediately after the
        EntityPaginationPageLoaded that resolved it — which is not necessarily
        the final page itself, since an empty page can pin the end at its
        predecessor.
      • EntityPaginationReset: reset() or refresh() discarded the loaded
        pages, with the discardedPages, the discardedEntitiesLength and
        isRefreshtrue while it is the reset of a refresh(), which
        re-fetches those pages right after, so a consumer can tell an in-progress
        refresh from a pagination that was simply emptied. Emitted after the
        state is cleared, so the pagination already reads as empty and the
        discarded state is on the event.

      Every event but EntityPaginationReset is about a page, and is an
      EntityPaginationPageEvent (also sealed) carrying the page.

      Note that concurrent page loads interleave: getRange and refresh start
      every page at once, so all the fetches are announced before any completes.

    • paginateByQuery, paginate and paginateAll gained the optional onEvent
      parameter, on EntitySource, EntityRepository and APIRepository, so the
      hook is reachable without building an EntityPagination by hand.

    • Tests: 15 new cases in bones_api_entity_pagination_test.dart (the event
      sequence of a full read, of an exact multiple of the page size, of an empty
      result and of a failure; the 3 skip reasons; the synchronous delivery; a
      listener attached after construction; a throwing listener; and the
      reset/refresh events).

    Open source →
    Release notes
    • New EntityPagination.onEvent: an optional hook notified of what is being fetched, for progress reporting and logging.

      var p = userRepository.paginateByQuery(' state == ? ',
          parameters: ['NY'], limit: 20, onEvent: (event) {
        switch (event) {
          case EntityPaginationPageLoading(:var page):
            print('fetching page $page...');
          case EntityPaginationPageLoaded(:var page, :var entriesLength):
            print('page $page: $entriesLength entries');
          case EntityPaginationPageError(:var page, :var error):
            print('page $page failed: $error');
          case EntityPaginationPageSkipped(:var page, :var reason):
            print('page $page not fetched: ${reason.name}');
          case EntityPaginationEnd(:var totalLength):
            print('done: $totalLength entries');
          case EntityPaginationReset(:var discardedPages):
            print('discarded ${discardedPages.length} pages');
        }
      });
      
      • Delivered synchronously, at the point where it happens and in order, so it is also correct for a synchronous EntityPageLoader (a Stream would only deliver in a later microtask, after a sync read already finished). To consume it as a stream, forward it: onEvent: myEventStream.add.
      • onEvent is not final, so it can also be attached to an already built EntityPagination. Only events emitted afterwards are seen.
      • An exception thrown by the listener is reported to the current Zone and does not break the fetch.
      • Nothing is allocated (not even the fetch timer) while onEvent is null.
    • New EntityPaginationEvent<O>, a sealed hierarchy so a switch over it is exhaustive, with EntityPaginationListener<O> as the callback type:

      • EntityPaginationPageLoading: a fetch is about to start. Emitted once per actual fetch.
      • EntityPaginationPageLoaded: a fetch finished, with the entries, the entriesLength, the elapsedTime of the pageLoader and isFinalPage.
      • EntityPaginationPageError: a fetch failed, with the error, the stackTrace and the elapsedTime. The error is rethrown to the caller right after the event.
      • EntityPaginationPageSkipped: a page was served without a fetch, with an EntityPaginationSkipReason: alreadyLoaded, inFlight (a concurrent request shares the fetch) or knownEmpty (past the resolved end). Not an error — it is what makes a repeated, concurrent or past-the-end read free.
      • EntityPaginationEnd: the end was resolved, with the finalPage and the totalLength. Emitted once, immediately after the EntityPaginationPageLoaded that resolved it — which is not necessarily the final page itself, since an empty page can pin the end at its predecessor.
      • EntityPaginationReset: reset() or refresh() discarded the loaded pages, with the discardedPages, the discardedEntitiesLength and isRefreshtrue while it is the reset of a refresh(), which re-fetches those pages right after, so a consumer can tell an in-progress refresh from a pagination that was simply emptied. Emitted after the state is cleared, so the pagination already reads as empty and the discarded state is on the event.

      Every event but EntityPaginationReset is about a page, and is an EntityPaginationPageEvent (also sealed) carrying the page.

      Note that concurrent page loads interleave: getRange and refresh start every page at once, so all the fetches are announced before any completes.

    • paginateByQuery, paginate and paginateAll gained the optional onEvent parameter, on EntitySource, EntityRepository and APIRepository, so the hook is reachable without building an EntityPagination by hand.

    • Tests: 15 new cases in bones_api_entity_pagination_test.dart (the event sequence of a full read, of an exact multiple of the page size, of an empty result and of a failure; the 3 skip reasons; the synchronous delivery; a listener attached after construction; a throwing listener; and the reset/refresh events).

    Open source →
    Release notes

    v1.13.0

    Compare

    Choose a tag to compare

    Open source →
  6. 1.12.0 01 Aug 2026
    Release notes
    • New EntityPagination<O>: a lazily loaded, paginated view over a select,
      for reading a result page by page without knowing its total length upfront.

      var p = userRepository.paginateByQuery(' state == ? ',
          parameters: ['NY'], limit: 20);
      
      await p.loadNextPage();   // page 1
      p[0];                     // sync, already loaded
      await p.getAt(45);        // loads page 3 on demand, leaving page 2 a gap
      await p.loadAll();        // fills the gaps and resolves the total
      • Pages are 1-based (matching the page parameter of the select*
        methods); entry indexes are 0-based (matching a Dart List). See
        indexOfPage / pageOfIndex.
      • Pages can be loaded out of order, leaving gaps: getAt(45) with a limit
        of 20 loads only page 3.
      • Synchronous access (operator [], loadedEntities) never fetches;
        only the FutureOr methods (getAt, getPage, getRange,
        loadNextPage, loadPage, loadAll, stream) do. operator [] returns
        null for a gap, an unloaded page or an out-of-range index alike; use
        isPageLoaded / isIndexKnownOutOfRange to tell them apart.
      • It is deliberately not a List or an Iterable: both require a
        length, which is exactly what a paginated select can't answer until it
        reaches the end. Use loadAll when a complete list is really needed.

      What it knows: loadedPages, loadedPagesLength, loadedEntities,
      loadedEntitiesLength, maxLoadedPage, maxLoadedIndex, maxKnownPage,
      isFinalPageResolved, finalPage, totalLength, isKnownEmpty,
      and information().

      Since every page except the last holds exactly limit entries, identifying
      the final page yields the total even with gaps:
      totalLength == (finalPage - 1) * limit + entries(finalPage).
      The end resolves when a page comes back short, when an empty page has a
      loaded and full predecessor, or when page 1 comes back empty. An empty page
      without a loaded predecessor does not resolve it — jumping to page 50
      of a 3-page result only proves the end is somewhere before page 50 — but it
      is still recorded, to avoid re-fetching that page or any page after it.

      Concurrent requests for the same page share a single fetch, and a failed
      load is evicted so a retry actually retries.

    • New paginateByQuery, paginate and paginateAll on EntitySource,
      EntityRepository (with resolutionRules) and APIRepository. They return
      immediately without loading anything. orderByID defaults to true there,
      rather than following the offset != null rule of the select* methods:
      a paginated read is only meaningful over a stable order.

    • Note: each page is an independent select, without a shared Transaction.
      Entries inserted or deleted between two page loads shift the offsets, so a
      page loaded later can repeat or skip entries. This is inherent to
      offset-based pagination; ordering by ID makes it as stable as it can be.

    Open source →
    Release notes
    • New EntityPagination<O>: a lazily loaded, paginated view over a select, for reading a result page by page without knowing its total length upfront.

      var p = userRepository.paginateByQuery(' state == ? ',
          parameters: ['NY'], limit: 20);
      
      await p.loadNextPage();   // page 1
      p[0];                     // sync, already loaded
      await p.getAt(45);        // loads page 3 on demand, leaving page 2 a gap
      await p.loadAll();        // fills the gaps and resolves the total
      
      • Pages are 1-based (matching the page parameter of the select* methods); entry indexes are 0-based (matching a Dart List). See indexOfPage / pageOfIndex.
      • Pages can be loaded out of order, leaving gaps: getAt(45) with a limit of 20 loads only page 3.
      • Synchronous access (operator [], loadedEntities) never fetches; only the FutureOr methods (getAt, getPage, getRange, loadNextPage, loadPage, loadAll, stream) do. operator [] returns null for a gap, an unloaded page or an out-of-range index alike; use isPageLoaded / isIndexKnownOutOfRange to tell them apart.
      • It is deliberately not a List or an Iterable: both require a length, which is exactly what a paginated select can't answer until it reaches the end. Use loadAll when a complete list is really needed.

      What it knows: loadedPages, loadedPagesLength, loadedEntities, loadedEntitiesLength, maxLoadedPage, maxLoadedIndex, maxKnownPage, isFinalPageResolved, finalPage, totalLength, isKnownEmpty, and information().

      Since every page except the last holds exactly limit entries, identifying the final page yields the total even with gaps: totalLength == (finalPage - 1) * limit + entries(finalPage). The end resolves when a page comes back short, when an empty page has a loaded and full predecessor, or when page 1 comes back empty. An empty page without a loaded predecessor does not resolve it — jumping to page 50 of a 3-page result only proves the end is somewhere before page 50 — but it is still recorded, to avoid re-fetching that page or any page after it.

      Concurrent requests for the same page share a single fetch, and a failed load is evicted so a retry actually retries.

    • New paginateByQuery, paginate and paginateAll on EntitySource, EntityRepository (with resolutionRules) and APIRepository. They return immediately without loading anything. orderByID defaults to true there, rather than following the offset != null rule of the select* methods: a paginated read is only meaningful over a stable order.

    • Note: each page is an independent select, without a shared Transaction. Entries inserted or deleted between two page loads shift the offsets, so a page loaded later can repeat or skip entries. This is inherent to offset-based pagination; ordering by ID makes it as stable as it can be.

    Open source →
    Release notes

    v1.12.0

    Compare

    Choose a tag to compare

    Open source →
  7. 1.11.0 01 Aug 2026
    Release notes
    • selectByQuery and its siblings gained 4 optional parameters, for pagination
      and ordering:

      • offset: the return offset.
      • page: the 1-based page to return, an ergonomic alternative to offset
        that computes it from the page size: (page - 1) * limit.
      • orderByID: orders the result by the table's ID column, resolved
        automatically from the existing scheme machinery (TableScheme.idFieldName
        EncodingContext.tableFieldID, or EntityHandler.idFieldName).
      • orderDirection: the new OrderDirection enum, ascending (default) or
        descending.

      Semantics:

      • The effective ordering is orderByID ?? (offset != null): a non-null
        offset turns the ordering on by default, since an offset-based
        pagination needs a stable order to be correct. Pass orderByID: false to
        opt out and get a bare OFFSET.
      • orderDirection is ignored while the ordering is not active.
      • page is a public convenience resolved to an offset at the repository
        layer (see resolveSelectOffset); the adapter contract keeps taking only
        offset. It throws an ArgumentError when combined with an offset (two
        spellings of one thing), when there is no positive limit to use as the
        page size, or when it is < 1. page: 1 resolves to offset: 0, which
        still activates the ordering, so even the first page is stable.
      • All 4 are optional and default to the previous behavior: with them unset the
        generated SQL is character-identical to 1.10.0.

      Added to EntitySource/EntityRepository (selectByQuery,
      selectFirstByQuery, select, selectIDsByQuery, selectIDsBy,
      selectAll), APIRepository, IterableEntityRepository
      (matches/all included), DBEntityRepository, DBRelationalAdapter/
      DBRelationalRepositoryAdapter/DBRelationalEntityRepository,
      DBAdapter.doSelectAll/doSelectByIDs, DBSQLAdapter.doSelect/
      doSelectIDsBy/generateSelectSQL/generateSelectIDsSQL and
      DBSQLRepositoryAdapter.generateSelectSQL.

    • New OrderDirection enum (bones_api_types.dart), with sqlKeyword,
      parse and the resolvers resolve and resolveOrderByID that state the
      semantics above exactly once.

    • New compareEntityIDs and applySelectOrderAndPagination
      (bones_api_entity.dart): the shared Dart-side "order by ID → skip → take"
      used by every adapter that can't delegate the ordering to a DB engine.

    • New resolveSelectOffset (bones_api_entity.dart): resolves page to an
      offset, and states the page/offset/limit validation rules once.

    • SQLDialect:

      • New orderBySQL and limitOffsetSQL clause builders, so all the
        dialect-specific SELECT tail syntax lives in one place.
      • New offsetRequiresLimit and offsetMaxLimitValue capabilities. MySQL sets
        offsetRequiresLimit: true since it can't parse an OFFSET that is not
        preceded by a LIMIT; an offset-only select there emits
        LIMIT 18446744073709551615 OFFSET n. PostgreSQL and the generic
        (in-memory) dialect emit a bare OFFSET n.
    • SQL: new offset, orderByID and orderDirection fields (carried by
      copy()), read by DBSQLMemoryAdapter to apply the same semantics in Dart.

    • APIDBModule.select (/db/select/<table>): new LIMIT=<n>, OFFSET=<n>,
      PAGE=<n> and ORDER=asc|desc query directives
      (see APIDBModule.selectQueryDirectives),
      parsed from the query String alongside the pre-existing EAGER=true and
      stripped before the remainder is parsed as the entity condition query. The
      endpoint no longer selects the whole table and sorts it in Dart — the ordering
      is now resolved by the DB. Its output order is unchanged. An invalid PAGE
      becomes an error response rather than an uncaught ArgumentError.

    • Behavior change: limit is now honored on the paths that previously
      accepted and silently ignored it — DBEntityRepository.select's
      ConditionID/ConditionIdIN/ConditionANY/KeyConditionEQ fast paths,
      DBAdapter.doSelectAll/doSelectByIDs, and the DBObjectMemoryAdapter,
      DBObjectDirectoryAdapter and DBObjectGCSAdapter adapters. For example,
      selectAll(limit: 2) on an object adapter returned every row before this
      release; it now returns 2.

    • Source-breaking for external subclasses: new named parameters were added
      to abstract members (EntitySource.select/selectIDsBy/selectAll,
      DBAdapter.doSelectAll/doSelectByIDs,
      DBRelationalAdapter.doSelect/doSelectIDsBy). Dart requires an override to
      accept every named parameter of the supertype, so third-party
      EntityRepository/DBAdapter implementations must widen their overrides.

    • Known limitation: a query over a to-many relationship generates a JOIN
      without a DISTINCT, so it can return the same entity more than once
      (pre-existing). Paginating such a query is therefore best-effort.

    • Tests:

      • New bones_api_entity_select_order_test.dart (OrderDirection,
        compareEntityIDs, applySelectOrderAndPagination, SQLDialect clause
        builders), bones_api_entity_db_sql_select_test.dart (exact generated SQL
        per case + end-to-end paging over the in-memory SQL adapter) and
        bones_api_db_module_test.dart (first coverage of APIDBModule).
      • bones_api_entity_db_tests_base.dart: 3 new tests in the shared adapter
        template, so the generated SQL and real page-by-page reads are asserted for
        the in-memory, PostgreSQL, MySQL, object-memory and object-directory
        adapters. Verified against real PostgreSQL and MySQL containers.
    Open source →
    Release notes
    • selectByQuery and its siblings gained 4 optional parameters, for pagination and ordering:

      • offset: the return offset.
      • page: the 1-based page to return, an ergonomic alternative to offset that computes it from the page size: (page - 1) * limit.
      • orderByID: orders the result by the table's ID column, resolved automatically from the existing scheme machinery (TableScheme.idFieldNameEncodingContext.tableFieldID, or EntityHandler.idFieldName).
      • orderDirection: the new OrderDirection enum, ascending (default) or descending.

      Semantics:

      • The effective ordering is orderByID ?? (offset != null): a non-null offset turns the ordering on by default, since an offset-based pagination needs a stable order to be correct. Pass orderByID: false to opt out and get a bare OFFSET.
      • orderDirection is ignored while the ordering is not active.
      • page is a public convenience resolved to an offset at the repository layer (see resolveSelectOffset); the adapter contract keeps taking only offset. It throws an ArgumentError when combined with an offset (two spellings of one thing), when there is no positive limit to use as the page size, or when it is < 1. page: 1 resolves to offset: 0, which still activates the ordering, so even the first page is stable.
      • All 4 are optional and default to the previous behavior: with them unset the generated SQL is character-identical to 1.10.0.

      Added to EntitySource/EntityRepository (selectByQuery, selectFirstByQuery, select, selectIDsByQuery, selectIDsBy, selectAll), APIRepository, IterableEntityRepository (matches/all included), DBEntityRepository, DBRelationalAdapter/ DBRelationalRepositoryAdapter/DBRelationalEntityRepository, DBAdapter.doSelectAll/doSelectByIDs, DBSQLAdapter.doSelect/ doSelectIDsBy/generateSelectSQL/generateSelectIDsSQL and DBSQLRepositoryAdapter.generateSelectSQL.

    • New OrderDirection enum (bones_api_types.dart), with sqlKeyword, parse and the resolvers resolve and resolveOrderByID that state the semantics above exactly once.

    • New compareEntityIDs and applySelectOrderAndPagination (bones_api_entity.dart): the shared Dart-side "order by ID → skip → take" used by every adapter that can't delegate the ordering to a DB engine.

    • New resolveSelectOffset (bones_api_entity.dart): resolves page to an offset, and states the page/offset/limit validation rules once.

    • SQLDialect:

      • New orderBySQL and limitOffsetSQL clause builders, so all the dialect-specific SELECT tail syntax lives in one place.
      • New offsetRequiresLimit and offsetMaxLimitValue capabilities. MySQL sets offsetRequiresLimit: true since it can't parse an OFFSET that is not preceded by a LIMIT; an offset-only select there emits LIMIT 18446744073709551615 OFFSET n. PostgreSQL and the generic (in-memory) dialect emit a bare OFFSET n.
    • SQL: new offset, orderByID and orderDirection fields (carried by copy()), read by DBSQLMemoryAdapter to apply the same semantics in Dart.

    • APIDBModule.select (/db/select/<table>): new LIMIT=<n>, OFFSET=<n>, PAGE=<n> and ORDER=asc|desc query directives (see APIDBModule.selectQueryDirectives), parsed from the query String alongside the pre-existing EAGER=true and stripped before the remainder is parsed as the entity condition query. The endpoint no longer selects the whole table and sorts it in Dart — the ordering is now resolved by the DB. Its output order is unchanged. An invalid PAGE becomes an error response rather than an uncaught ArgumentError.

    • Behavior change: limit is now honored on the paths that previously accepted and silently ignored it — DBEntityRepository.select's ConditionID/ConditionIdIN/ConditionANY/KeyConditionEQ fast paths, DBAdapter.doSelectAll/doSelectByIDs, and the DBObjectMemoryAdapter, DBObjectDirectoryAdapter and DBObjectGCSAdapter adapters. For example, selectAll(limit: 2) on an object adapter returned every row before this release; it now returns 2.

    • Source-breaking for external subclasses: new named parameters were added to abstract members (EntitySource.select/selectIDsBy/selectAll, DBAdapter.doSelectAll/doSelectByIDs, DBRelationalAdapter.doSelect/doSelectIDsBy). Dart requires an override to accept every named parameter of the supertype, so third-party EntityRepository/DBAdapter implementations must widen their overrides.

    • Known limitation: a query over a to-many relationship generates a JOIN without a DISTINCT, so it can return the same entity more than once (pre-existing). Paginating such a query is therefore best-effort.

    • Tests:

      • New bones_api_entity_select_order_test.dart (OrderDirection, compareEntityIDs, applySelectOrderAndPagination, SQLDialect clause builders), bones_api_entity_db_sql_select_test.dart (exact generated SQL per case + end-to-end paging over the in-memory SQL adapter) and bones_api_db_module_test.dart (first coverage of APIDBModule).
      • bones_api_entity_db_tests_base.dart: 3 new tests in the shared adapter template, so the generated SQL and real page-by-page reads are asserted for the in-memory, PostgreSQL, MySQL, object-memory and object-directory adapters. Verified against real PostgreSQL and MySQL containers.
    Open source →
    Release notes

    v1.11.0

    Compare

    Choose a tag to compare

    Open source →
  8. 1.10.0 13 Jul 2026
    Release notes
    • docker_commander: ^2.1.8^3.0.0.

      • Removes wasm_run and flutter_rust_bridge 1.x from the dependency graph
        (they came in via docker_commanderapollovm, and were only ever needed
        to execute Wasm — which nothing here does).
      • Those packages pinned shelf_web_socket ^1.0.2 and
        web_socket_channel ^2.2.0, so every bones_api application was locked
        out of a modern shelf/WebSocket stack. That constraint is now gone.
      • docker_commander's own API is unchanged, so this is a minor release: the
        DockerHost types exposed by the test utils keep the same shape.
    • petitparser: ^6.1.0^7.0.2 (required by apollovm 2.0.0).

      • JsonGrammarLexer.token: flatten() takes its message as a named
        parameter in petitparser 7. Same behaviour, new call shape.
    Open source →
    Release notes
    • docker_commander: ^2.1.8^3.0.0.

      • Removes wasm_run and flutter_rust_bridge 1.x from the dependency graph (they came in via docker_commanderapollovm, and were only ever needed to execute Wasm — which nothing here does).
      • Those packages pinned shelf_web_socket ^1.0.2 and web_socket_channel ^2.2.0, so every bones_api application was locked out of a modern shelf/WebSocket stack. That constraint is now gone.
      • docker_commander's own API is unchanged, so this is a minor release: the DockerHost types exposed by the test utils keep the same shape.
    • petitparser: ^6.1.0^7.0.2 (required by apollovm 2.0.0).

      • JsonGrammarLexer.token: flatten() takes its message as a named parameter in petitparser 7. Same behaviour, new call shape.
    Open source →
    Release notes

    v1.10.0

    Compare

    Choose a tag to compare

    Open source →
  9. 1.9.31 10 Jun 2026
    Release notes

    1.9.31

    • Bug fixes:

      • ConditionSQLEncoder.valueToParameterValue: fixed encoding of a List of values containing ConditionParameters; each element is now resolved individually instead of passing the whole list to every element.
      • ConditionEncoder.resolveValueToType: fixed resolution of a single-element Iterable to a primitive type (was a no-op comparison instead of an assignment, leaving the value as a List).
      • MapGetterExtension.matchKeyIgnoreCase: fixed case-insensitive key matching that always returned null (empty loop body); now returns the matching key. Also fixes setMultiValue(..., ignoreCase: true).
      • Time: millisecond/microsecond range validation now correctly rejects 1000 (valid range is 0..999).
      • Time._bytesInStringFormat: fixed the second-byte digit check that was effectively disabled (length < 2 instead of length >= 2).
      • APISession.isExpired: now honors the provided now argument instead of always using DateTime.now().
      • APIServerResponseCache cached entry: replaceFileStat no longer compares a variable to itself (identical(myFileStat, myFileStat)), so the file stat is correctly replaced.
      • WeakList.set: now increments the internal modification counter, consistent with the other mutating methods.
    • Tests:

      • Added tests covering the bug fixes above (Time range/string parsing, matchKeyIgnoreCase/getIgnoreCase/setMultiValue, APISession.isExpired, and ConditionSQLEncoder/ConditionEncoder value resolution).
    Open source →
    Release notes
    • Bug fixes:

      • ConditionSQLEncoder.valueToParameterValue: fixed encoding of a List of values containing ConditionParameters; each element is now resolved individually instead of passing the whole list to every element.
      • ConditionEncoder.resolveValueToType: fixed resolution of a single-element Iterable to a primitive type (was a no-op comparison instead of an assignment, leaving the value as a List).
      • MapGetterExtension.matchKeyIgnoreCase: fixed case-insensitive key matching that always returned null (empty loop body); now returns the matching key. Also fixes setMultiValue(..., ignoreCase: true).
      • Time: millisecond/microsecond range validation now correctly rejects 1000 (valid range is 0..999).
      • Time._bytesInStringFormat: fixed the second-byte digit check that was effectively disabled (length < 2 instead of length >= 2).
      • APISession.isExpired: now honors the provided now argument instead of always using DateTime.now().
      • APIServerResponseCache cached entry: replaceFileStat no longer compares a variable to itself (identical(myFileStat, myFileStat)), so the file stat is correctly replaced.
      • WeakList.set: now increments the internal modification counter, consistent with the other mutating methods.
    • Tests:

      • Added tests covering the bug fixes above (Time range/string parsing, matchKeyIgnoreCase/getIgnoreCase/setMultiValue, APISession.isExpired, and ConditionSQLEncoder/ConditionEncoder value resolution).
    Open source →
    Release notes

    v1.9.31

    Compare

    Choose a tag to compare

    Open source →
  10. 1.9.30 30 Apr 2026
    Release notes

    v1.9.30

    • APIRootStarter:

      • start:
        • Added logging of severe errors when apiRoot.ensureInitialized() returns a failure with an error.
    • Project template:

      • update_project_template.sh:
        • Updated project_template prepare command to exclude IDE module files matching ^\w+\.iml$ from the template archive.
    • Dependencies:

      • Updated build_runner to ^2.15.0.
      • Updated test to ^1.31.1.
      • Updated vm_service to ^15.2.0.
    Open source →
    Release notes
    • APIRootStarter:

      • start:
        • Added logging of severe errors when apiRoot.ensureInitialized() returns a failure with an error.
    • Project template:

      • update_project_template.sh:
        • Updated project_template prepare command to exclude IDE module files matching ^\w+\.iml$ from the template archive.
    • Dependencies:

      • Updated build_runner to ^2.15.0.
      • Updated test to ^1.31.1.
      • Updated vm_service to ^15.2.0.
    Open source →
    Release notes

    v1.9.30

    Compare

    Choose a tag to compare

    Open source →
  11. 1.9.29 16 Apr 2026
    Release notes
    • ConditionID:

      • Added method resolveIDValue to resolve the ID value from parameters or ConditionParameter.
    • DBEntityRepository:

      • Updated selectIDsBy and _selectByID to use ConditionID.resolveIDValue for ID resolution.
      • select:
        • Added optimization for KeyConditionEQ matcher with a single key matching the entity ID field.
        • When matched, uses _selectByID to fetch the entity by ID and returns a single-element list or empty list accordingly.
    • DBObjectDirectoryAdapter:

      • Updated _doCountImpl and _doDeleteImpl to use ConditionID.resolveIDValue for ID resolution.
      • Updated public methods to pass combined parameters (parameters ?? namedParameters) to internal implementations.
    • DBObjectGCSAdapter:

      • Updated _doCountImpl and _doDeleteImpl to use ConditionID.resolveIDValue for ID resolution.
      • Updated public methods to pass combined parameters (parameters ?? namedParameters) to internal implementations.
    • DBObjectMemoryAdapter:

      • Updated _doCountImpl and _doDeleteImpl to use ConditionID.resolveIDValue for ID resolution.
      • Updated public methods to pass combined parameters (parameters ?? namedParameters) to internal implementations.
    • Dependency updates:

      • vm_service: ^15.0.2 → ^15.1.0
    Open source →
  12. 1.9.28 08 Apr 2026
    Release notes
    • SQLGenerator:

      • Fixed referenceTable and referenceColumn assignment in unique constraint SQL entries to allow nullable references.
      • Updated unique and enum constraint names in generateAddUniqueConstraintAlterTableSQL and generateAddEnumConstraintAlterTableSQL to use normalized column names with double underscores for consistency.
    • Dependency updates:

      • async_extension: ^1.2.22
      • reflection_factory: ^2.7.5
      • swiss_knife: ^3.3.14
      • meta: ^1.18.2
      • hotreloader: ^4.4.0
      • googleapis_auth: ^2.3.0
      • build_runner: ^2.13.1
      • test: ^1.31.0
    Open source →
  13. 1.9.27 18 Feb 2026
    Release notes
    • Added bones_api_utils_fast_checksum.dart:

      • Provides functions getAdler32Uint8List, getAdler32Hex, getCrc32Uint8List, and getCrc32Hex for Adler-32 and CRC-32 checksums as byte arrays and hex strings.
      • Implements internal helpers for big-endian byte conversion and hex encoding.
      • Exports getAdler32 and getCrc32 from archive package for checksum calculation.
    • WeakEtag class (bones_api_base.dart):

      • Updated WeakEtag.adler32 and WeakEtag.crc32 factories to use getAdler32Hex and getCrc32Hex from bones_api_utils_fast_checksum.dart instead of deprecated Adler32 and Crc32 classes.
    • bones_api.dart:

      • Exported new bones_api_utils_fast_checksum.dart utility.
    • Dependencies:

      • Updated async_extension from ^1.2.20 to ^1.2.21.
      • Updated swiss_knife from ^3.3.3 to ^3.3.5.
      • Updated archive from ^4.0.7 to ^4.0.9.
      • Updated build_runner from ^2.10.5 to ^2.11.1.
      • docker_commander: ^2.1.8
    Open source →
  14. 1.9.26 03 Feb 2026
    Release notes
    • Initializable mixin:
      • ensureInitialized: added onError handler to then call to route errors to _onInitializationError.
      • executeInitializedCallback:
        • Added onError handler to then call on async initialization result to throw InitializationError with stack trace.
      • _FutureExtension:
        • toCompleter: added onError handler to then to complete completer with error and stack trace if not completed.
    Open source →
  15. 1.9.25 30 Jan 2026
    Release notes
    • TableFieldReference:

      • Added nullable field indexName to represent the name of the index if one exists.
    • Added new class TableRelationshipReferenceEntityTyped extending TableRelationshipReference:

      • Adds sourceFieldEntityType and targetFieldEntityType fields of type TypeInfo.
      • Provides copyWithEntityTypes method to create typed copies.
    • TableRelationshipReference:

      • Added nullable fields sourceRelationshipFieldIndex and targetRelationshipFieldIndex.
      • Added copyWithEntityTypes method returning TableRelationshipReferenceEntityTyped.
    • EntityHandler:

      • Added getFieldsListEntityTypes method to return a map of fields that are list entities or references with their TypeInfo.
    • SQLDialect:

      • Added foreignKeyCreatesImplicitIndex boolean flag with default true.
      • Added field createIndexIfNotExists to indicate support for IF NOT EXISTS in CREATE INDEX (default true).
    • CreateIndexSQL:

      • Updated buildSQL method to conditionally include IF NOT EXISTS only if dialect supports it.
    • DBPostgreSQLAdapter:

      • Added foreignKeyCreatesImplicitIndex flag to PostgreSQL dialect set to false.
      • Updated _findAllTableFieldsReferences query to include foreign key index name (fk_index_name) by joining with pg_index and pg_class.
      • Populated indexName in TableFieldReference instances from query result.
      • Updated relationship references to include sourceRelationshipFieldIndex and targetRelationshipFieldIndex from indexName.
    • DBMySQLAdapter:

      • Set createIndexIfNotExists to false in MySQL dialect capabilities.
    • DBSQLAdapter:

      • parseConfigDBGenerateTablesAndCheckTables: changed return type from List<bool> to a record with named fields (generateTables, checkTables).
      • extractTableSQLs: updated regex to also match CREATE INDEX statements in addition to CREATE and ALTER TABLE.
      • _populateTablesFromSQLsImpl: fixed error handling for CREATE INDEX statements when the SQL dialect does not support IF NOT EXISTS.
        • Now logs a warning and ignores the error instead of throwing.
      • Added detection of missing foreign key indexes when dialect does not create implicit indexes.
      • Added detection of missing relationship reference indexes for collection reference fields.
      • Updated error reporting and logging to include missing reference indexes and relationship reference indexes.
      • Updated _checkDBTableSchemeReferenceField to return TableRelationshipReferenceEntityTyped with entity types.
      • Added generation of missing reference indexes and missing relationship reference indexes SQL statements.
      • Updated _DBTableCheck class:
        • Added fields missingReferenceIndexes and missingRelationshipReferenceIndexes.
        • Added methods to generate missing reference indexes and relationship reference indexes SQL.
      • Added _DBRelationshipTableColumn subclass of _DBTableColumn to represent relationship table columns with relationship table name.
      • Updated SQL generation to create indexes for foreign keys if dialect does not create implicit indexes:
        • Added index creation after foreign key constraints in generateAddColumnAlterTableSQL.
        • Added index creation for relationship table foreign keys in relationship table creation SQL.
    • Dependency updates:

      • async_extension: ^1.2.19 → ^1.2.20
      • meta: ^1.18.0 → ^1.18.1
    Open source →
  16. 1.9.24 22 Jan 2026
    Release notes
    • GZipSink:

      • Added override for addSlice to handle partial chunk addition and update _inputLength accordingly.
      • Optimized addSlice to call _gzipSink.close() when isLast is true and full chunk is added.
    • BytesSink:

      • Updated addSlice to use new addPart method for partial chunk addition.
    • BytesBuffer:

      • Added addPart method to add a slice of bytes from a given offset and length, resizing buffer if needed.
      • Refactored add method to delegate to addPart.
      • Improved buffer range setting to support offset and length parameters in addPart.
    • async_extension: ^1.2.18 -> ^1.2.19

    Open source →
  17. 1.9.23 20 Jan 2026
    Release notes
    • DBPostgreSQLAdapter:
      • mapDataTypeToDartType: added support for PostgreSQL types smallint and smallserial mapping to int.
    Open source →
  18. 1.9.22 20 Jan 2026
    Release notes
    • Initializable mixin:

      • Added calls to _forceLogFlushMessages() before throwing InitializationError in:
        • _checkDependency
        • _setInitializedDependenciesCompleters
        • _onInitializationError
        • _checkAllDependenciesOk
        • _finalizeInitialization
        • checkInitialized
        • executeInitialized
    • Logging:

      • Added _forceLogFlushMessages() function to call logging.Logger.root.forceFlushMessages().
      • Logger extension:
        • Added forceFlushMessages() method to invoke LoggerHandler.forceFlushMessages().
      • LoggerHandler abstract class:
        • Added forceFlushMessages() method.
      • LoggerHandlerGeneric implementation:
        • Implemented forceFlushMessages() returning false.
      • LoggerHandlerIO implementation:
        • Implemented forceFlushMessages() to flush the print message queue immediately if not empty.
    Open source →
  19. 1.9.21 17 Jan 2026
    Release notes
    • EntityHandler:

      • Updated all Map.unmodifiable usages to explicitly specify type arguments, e.g. Map<String, TypeInfo>.unmodifiable.
      • Updated methods including fieldsWithEntityReference, fieldsWithEntityReferenceList, fieldsEntityAnnotations, fieldsWithType, getFieldsTypes, getFieldsEnumTypes, getFieldsEntityTypes, and constructors to use typed unmodifiable maps.
      • Improved type safety in map constructions by adding explicit generic parameters.
    • Dependency updates:

      • meta: ^1.18.0
    Open source →
  20. 1.9.20 15 Jan 2026
    Release notes
    • ConditionSQLEncoder:

      • keyToSQL: added check to throw ConditionEncodingError if keys is empty.
      • Refactored keyFieldReferenceToSQL to recursively resolve multi-level key references by walking keys and resolving intermediate tables and relationships.
      • Added helper methods _resolveReferenceField and _resolveFinalField to modularize reference resolution logic.
    • DBSQLAdapter:

      • Introduced _JoinEntry typedef to represent SQL JOIN fragments with explicit alias dependencies (defs and refs).
      • Added local extension methods on List<_JoinEntry> to perform dependency-aware sorting of JOINs ensuring referenced aliases are resolved before use.
      • Refactored JOIN construction logic in SQL query building to:
        • Collect JOINs as _JoinEntry with defined and referenced aliases.
        • Sort JOINs by alias dependencies before concatenation.
        • Log a warning if not all JOIN references could be resolved.
      • This improves correctness and ordering of JOIN clauses in generated SQL.
    • Dependencies:

      • Updated async_extension from ^1.2.17 to ^1.2.18.
      • Updated build_runner from ^2.10.4 to ^2.10.5.
    Open source →
  21. 1.9.19 09 Jan 2026
    Release notes
    • Dependency updates:
      • Updated reflection_factory dependency from ^2.7.2 to ^2.7.3.
    Open source →
  22. 1.9.18 09 Jan 2026
    Release notes
    • DBAdapter:

      • Improved error messages in instantiation methods to include a list of instantiator function keys.
    • Dependencies:

      • Updated async_extension from ^1.2.15 to ^1.2.17.
      • Updated test from ^1.28.0 to ^1.29.0.
    Open source →
  23. 1.9.17 19 Dec 2025
    Release notes
    • APIServer:

      • _resolvePayloadFromString: Improved JSON payload parsing:
        • Trim input before decoding.
        • Return null for empty bodies.
        • Catch decode errors and log them without throwing.
    • statistics: ^1.2.1

    Open source →
  24. 1.9.16 26 Nov 2025
    Release notes
    • New FileLimited: expose Fili limit handling.

    • FileLimitExtension: use FileLimited.global.

    • APIServerResponseCache:

      • Use a local _fileLimited for file operations.
      • Optimize File operations to prioritize async and limited operations.
    • shelf_letsencrypt: ^2.0.3

    • build_runner: ^2.10.4

    • test: ^1.28.0

    Open source →
  25. 1.9.15 12 Nov 2025
    Release notes
    • FileLimitExtension:

      • Added statLimited, deleteLimited.
    • DBObjectGCSAdapter:

      • Replaced direct file operations with the new limited I/O methods:
        • deleteLimited() instead of delete()
        • statLimited() instead of stat()
      • Improves concurrency control and prevents Too many open files errors during cache cleanup and maintenance...
    Open source →
  26. 1.9.14 12 Nov 2025
    Release notes
    • FileLimitExtension:

      • Added readAsBytesLimited() and writeAsBytesLimited() methods to safely limit concurrent file I/O operations and prevent Too many open files errors.
    • DBObjectGCSAdapter:

      • Replaced direct file reads with the new FileLimitExtension.readAsBytesLimited() to control concurrent I/O and prevent Too many open files errors during cache access.
    • async_locks: ^4.0.2

    • build_runner: ^2.10.2

    • test: ^1.27.0

    Open source →
  27. 1.9.13 11 Nov 2025
    Release notes
    • DBObjectGCSAdapter:
      • _checkCacheDirectoryLimit:
        • Improve logging.
        • Fix calculation of needed deleting and extra 20%.
    Open source →
  28. 1.9.12 11 Nov 2025
    Release notes
    • DBObjectGCSAdapter:

      • Added properties: cacheDevelopment, cacheFilesLimit, cacheCheckMaxSkips and cacheCheckTimeout.
      • Auto-created cacheDirectory on cacheDevelopment.
      • _checkCacheDirectoryLimit:
        • Optimize and also use cacheFilesLimit.
        • Log check time.
    • DBObjectDirectoryAdapter:

      • Added property development.
      • Auto-created directory on development.
    • reflection_factory: ^2.7.2

    • postgres: ^3.5.9

    • crypto: ^3.0.7

    • http: ^1.6.0

    • _discoveryapis_commons: ^1.0.7

    • build_runner: ^2.10.1

    Open source →
  29. 1.9.11 19 Sep 2025
    Release notes
    • EntityHandler:

      • resolveFieldsValues: when resolving an EntityReference and the value can't be resolved, pass the ID to the EntityReference.
      • resolveValueByType: optimize for null value.
    • LoggerHandler:

      • _buildMsg: handle long debugName starting with test_suite:.
    • ClassProxyListener:

      • onCall: On response error, throw an exception using response.stackTrace when available.
    Open source →
  30. 1.9.10 19 Sep 2025
    Release notes
    • DBEntityRepository:

      • Optimize resolveEntities.
    • build_runner: ^2.7.1

    Open source →
  31. 1.9.9 19 Aug 2025
    Release notes
    • APISecurity:

      • Added notifyAPITokenInfoChange, disposeAuthenticationPermission, disposeAuthenticationDataAndPermission.
    • APITokenStore:

      • Added removeTokenPermissions, removeTokenDataAndPermissions.
    • APIRequest:

      • Add APIRequest and getPayloadParameterIgnoreCase.
    Open source →
  32. 1.9.8 18 Aug 2025
    Release notes
    • sdk: '>=3.7.0 <4.0.0'

    • reflection_factory: ^2.6.0

    • collection: ^1.19.1

    • mime: ^2.0.0

    • http: ^1.5.0

    • build_runner: ^2.7.0

    • Comment: dependency_validator: ^4.1.3.

    Open source →
  33. 1.9.7 10 Aug 2025
    Release notes
    • EntityAccessRules: added totalRules.

    • APIModule:

      • Added addRouteHandler.
    • APIRouteBuilder:

      • Added addRouteHandler.
      • apiMethod: optimize the built routeHandler.
    • Now APIRouteHandler is abstract:

      • Removed field function.
      • Public implementation APIRouteHandlerFunction.
    • MethodReflectionExtension:

      • returnsAPIResponse: do not accept dynamic.
    • APIServer:

      • Improve error logging when start fails.
    • reflection_factory: ^2.5.3

    Open source →
  34. 1.9.6 27 Jul 2025
    Release notes
    • APIServer:
      • _defineGZipEncodedHeaders:
        • Fix serverTimingEntryName default value from obj->json->gzip to obj-json-gzip.
    Open source →
  35. 1.9.5 27 Jul 2025
    Release notes
    • APIServer:

      • _resolveBodyImpl:
        • Log errors while encoding payload to JSON.
        • Catch OutOfMemoryError and log.
        • Return apiResponse.asError on errors.
      • _jsonEncodePayload:
        • Now uses AutoGZipSink and Json.encodeToSink to stream JSON encoding with automatic GZip compression based on output size.
    • Added AutoGZipSink, GZipSink and BytesSink and BytesBuffer.

    • Json:

      • Added encodeToSink.
    • reflection_factory: ^2.5.2

    • swiss_knife: ^3.3.3

    • test: ^1.26.3

    Open source →
  36. 1.9.4 11 Jul 2025
    Release notes
    • Main updates (see v1.9.4-beta.* for more):

      • APIServerConfig:

        • defaultStaticFilesCacheControl: removed must-revalidate (conflicts with stale-while-revalidate).
        • Added longLivedStaticFilesCacheControl and longLivedStaticFilesCached
          • Default values are for PWA bootstrap files: /, /index.html, styles.css, /pwa_sw.js
        • Constructor:
          • Improved parameters that can be passed through apiConfig:
      • CacheControl:

        • Removed mustRevalidate from the default directives (conflicts with staleWhileRevalidate).
    • coverage: ^1.15.0

    Open source →
  37. 1.9.4-beta.3 10 Jul 2025 pre-release
    Release notes
    • APIServerConfig:
      • Fix normalizeHeaderValue resolution when using apiConfig.
    Open source →
  38. 1.9.4-beta.2 10 Jul 2025 pre-release
    Release notes
    • APIServerConfig:
      • defaultLongLivedStaticFilesCacheControl: changed max-age from 86400 (1 day) to 3600 (1 hour).
      • Constructor:
        • Improved parameters that can be passed through apiConfig:
          • cookieless, useSessionID.
          • maxPayloadLength, decompressPayload.
          • apiCacheControl, staticFilesCacheControl.
          • longLivedStaticFilesCacheControl, longLivedStaticFilesCached.
    Open source →
  39. 1.9.4-beta.1 04 Jul 2025 pre-release
    Release notes
    • CacheControl:

      • Removed mustRevalidate from the default directives (conflicts with staleWhileRevalidate).
    • APIServerConfig:

      • defaultStaticFilesCacheControl: removed must-revalidate (conflicts with stale-while-revalidate).
      • Added longLivedStaticFilesCacheControl and longLivedStaticFilesCached
        • Default values are for PWA bootstrap files: /, /index.html, styles.css, /pwa_sw.js
    • APIServerResponseCache:

      • Improve headers of cached responses:
        • Added Cache-Control and Server.
        • Added Last-Modified on 304 responses.
    Open source →
  40. 1.9.3 29 Jun 2025
    Release notes
    • DBPostgreSQLAdapter:

      • Upgrade to postgres API v3.
      • Allow SSL connections.
    • DBEntityRepositoryProvider: check for duplicated repositories.

    • APIServerConfig, APIServerWorker, APIServer:

      • Add maxPayloadLength and decompressPayload options for request handling.
    • APIServer:

      • _loadPayloadBytes:
        • Added support for compressed payload in gzip and deflate.
        • Added _decodePayloadGzip to handled GZip decompression and check the decompressed size in header before decompression.
    • Time.parse: accept format Time(hh:mm:ss.sss)

    • Fix SQL column generation type if min/max is defined for the field.

    • postgres: ^3.5.6

    Open source →
  41. 1.9.3-beta.11 28 Jun 2025 pre-release
    Release notes
    • DBEntityRepositoryProvider:

      • Added _checkDuplicatedRepositories: check for duplicated repositores, by Type and name.
    • Initializable:

      • _doInitializationImpl: add extra timeout when new parents are added.
    Open source →
  42. 1.9.3-beta.10 28 Jun 2025 pre-release
    Release notes
    • DBMySQLAdapter, DBPostgreSQLAdapter:
      • typeToSQLType: fix for int/BigInt ID (isID: true).
    Open source →
  43. 1.9.3-beta.9 28 Jun 2025 pre-release
    Release notes
    • DBMySQLAdapter:

      • typeToSQLType:
        • Fix for int: use entityFieldAnnotations min/max to define SQL type (TINYINT,SMALLINT,MEDIUMINT,INT,BIGINT).
        • Fix for BigInt and DynamicInt: DECIMAL(65, 0)
    • DBPostgreSQLAdapter:

      • typeToSQLType:
        • Fix int: use entityFieldAnnotations min/max to define SQL type (SMALLINT,INT,BIGINT).
        • Fix for BigInt and DynamicInt: NUMERIC
    Open source →
  44. 1.9.3-beta.8 18 Jun 2025 pre-release
    Release notes
    • APIServerConfig, APIServerWorker, APIServer:

      • Add maxPayloadLength and decompressPayload options for request handling.
    • APIServer:

      • _loadPayloadBytes:
        • Added support for compressed payload in gzip and deflate.
        • Added _decodePayloadGzip to handled GZip decompression and check the decompressed size in header before decompression.
    Open source →
  45. 1.9.3-beta.7 05 Jun 2025 pre-release
    Release notes
    • GenericEntityHandler, ClassReflectionEntityHandler:

      • getFieldType: if the field doesn't have a setter do not use cached fields types.
    • meta: ^1.17.0

    • gcloud: ^0.8.19

    • http: ^1.4.0

    • googleapis_auth: ^2.0.0

    • test: ^1.26.2

    • coverage: ^1.14.1

    • vm_service: ^15.0.2

    Open source →
  46. 1.9.3-beta.6 14 May 2025 pre-release
    Release notes
    • TypeInfoEntityExtension, TypeReflectionEntityExtension:

      • entityType: also handle List<E>, returning the List generic type (E).
    • TypeInfoEntityExtension:

      • Added toCastedList.
    • DBSQLAdapter:

      • _checkDBTableScheme:
        • Separate references and collection references in referenceFields and collectionReferenceFields.
      • _DBTableCheck: added field missingCollectionReferenceColumns.
    • EntityHandler:

      • resolveFieldsValues: ensure that List<E> fields are casted to the list, using entityType.toCastedList(val).
    • New InitializationError.

    • Initializable: better handling of errors of dependencies while initializing.

    • async_extension: ^1.2.15

    • args: ^2.7.0

    • postgres: ^3.5.6

    • archive: ^4.0.7

    • coverage: ^1.12.0

    Open source →
  47. 1.9.3-beta.5 10 Mar 2025 pre-release
    Release notes
    • DBPostgreSQLAdapter:

    • PostgreSQLConnectionWrapper:

      • Remove field _endpoint.
      • Added fields username, host, port, database, secure.
      • connectionURL: appended query string with sslmode.
    Open source →
  48. 1.9.3-beta.4 10 Mar 2025 pre-release
    Release notes
    • DBPostgreSQLAdapter:
      • _connectSSLImpl, _connectNoSSLImpl: simplify error handling.
    Open source →
  49. 1.9.3-beta.3 10 Mar 2025 pre-release
    Release notes
    • New DBAdapterConnectivity.

    • DBAdapter:

      • Added field connectivity.
    • DBPostgreSQLAdapter:

      • Remove filed onlySecureConnections.
      • Added support to connectivity field.
    Open source →
  50. 1.9.3-beta.2 10 Mar 2025 pre-release
    Release notes
    • New DBAdapterCapabilityConnectivity.

    • DBAdapterCapability:

      • Added field connectivity.
    • DBPostgreSQLAdapter:

      • Added field onlySecureConnections.
    • dependency_validator: ^4.1.3

    Open source →
  51. 1.9.3-beta.1 06 Mar 2025 pre-release
    Release notes
    • DBPostgreSQLAdapter:

      • Upgrade to postgres API v3.
      • Allow SSL connections.
    • Time.parse: accept format Time(hh:mm:ss.sss)

    • postgres: ^3.5.4

    • project_template: ^1.1.1

    • archive: ^4.0.4

    Open source →
  52. 1.9.2 04 Mar 2025
    Release notes
    • FieldsFromMap:

      • resolveFiledName: improve field matching.
    • EntityHandler

      • getFieldType: added parameter resolveFiledName: false.
      • Optimize field and types resolution.
    • GenericEntityHandler, ClassReflectionEntityHandler:

      • Optimize field and types resolution.
    Open source →
  53. 1.9.1 27 Feb 2025
    Release notes
    • async_events: ^1.3.0
    • reflection_factory: ^2.5.1
    • web: ^1.1.1
    Open source →
  54. 1.9.0 25 Feb 2025
    Release notes
    • APIPlatformBrowser:

      • Change use of dart:html (deprecated) to package web.
    • Json:

      • defaultFieldValueResolver: optimize primitives parsing (String, bool, int, double, num) .
      • Added dumpRuntimeTypes.
    • sdk: '>=3.6.0 <4.0.0'

    • reflection_factory: ^2.5.0

    • statistics: ^1.2.0

    • swiss_knife: ^3.3.0

    • yaml_writer: ^2.1.0

    • mercury_client: ^2.3.0

    • resource_portable: ^3.1.2

    • collection: ^1.19.0

    • web: ^1.1.0

    Open source →
  55. 1.8.7 12 Feb 2025
    Release notes
    • reflection_factory: ^2.4.10

    • petitparser: ^6.1.0

    • hotreloader: ^4.3.0

    • stream_channel: ^2.1.4

    • http: ^1.3.0

    • lints: ^5.1.1

    • build_runner: ^2.4.15

    • test: ^1.25.15

    Open source →
  56. 1.8.6 25 Dec 2024
    Release notes
    • ✨♻️ Improve cast method in APIResponse
      • Add error parameter to cast method for more flexibility
      • Include additional requires authentication in the copied APIResponse object.
    Open source →
  57. 1.8.5 25 Dec 2024
    Release notes
    • refactor(api):

      • 🔨 improve payload handling in resolveBody and resolveBodySync
      • 🔨 UNAUTHORIZED, BAD_REQUEST: Allow error as payload in response generation.
    • swiss_knife: ^3.2.3

    • yaml: ^3.1.3

    • stream_channel: ^2.1.3

    Open source →
  58. 1.8.4 20 Dec 2024
    Release notes
    • APIRoot:
      • _callZoned: allow an APIResponse to be thrown as response.
    Open source →
  59. 1.8.3 20 Dec 2024
    Release notes
    • ZoneField:

      • createContextZone: added parameter zoneValues.
      • createSafeContextZone:
        • Added named parameters zoneSpecification and zoneValues
        • Changed handleUncaughtError to named parameter.
    • APIRoot:

      • _callZoned:
        • Fix closure memory leak.
          • Optimize and avoid a new closure on parameter handleUncaughtError for every Zone created through currentAPIRequest.createSafeContextZone. Now using a single ZoneSpecification instance.
          • Ensure that currentAPIRequest.disposeContextZone(callZone) is always called.
    • async_extension: ^1.2.14

    • test: ^1.25.14

    Open source →
  60. 1.8.2 19 Dec 2024
    Release notes

    ✨♻️ Add Time operators for addition + and subtraction -.

    • New DurationToTimeExtension: Duration.toTime()

    • async_extension: ^1.2.13

    • reflection_factory: ^2.4.8

    • build_runner: ^2.4.14

    • test: ^1.25.13

    Open source →

Every package, every release, already written down.

The archive is open and free. Watching your own project is what we are building next.

Browse the archive