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 2026Releases
latest 60 of 351-
1.15.212 Aug 2026Release notes
Open source →-
The placeholder pruning added in 1.15.1 no longer runs on every encoded
condition.Rewriting
field == ?bound to null intofield IS NULLleaves 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 NULLcan 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.
Release notes
Open source →-
The placeholder pruning added in 1.15.1 no longer runs on every encoded condition.
Rewriting
field == ?bound to null intofield IS NULLleaves 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 NULLcan 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.
-
-
1.15.112 Aug 2026Release notes
Open source →-
Fixed: a condition comparing a field to
nullpassed as a parameter was
encoded asfield = ?bound tonull.= NULLis never true in SQL, so the
query returned no rows instead of the rows whose column is null.ConditionSQLEncoderdid turn=/INagainst null intoIS NULL(and
!=/NOT INintoIS 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_styleto the formatter bundled with Dart 3.12, so on
Dart 3.13 the generated*.reflection.g.dartno longer matched this
package's owndart format, makingdart format --set-exit-if-changedand
test/ensure_build_test.dartmutually exclusive. 2.9.0 tracks the
formatter the SDK ships.
- 2.8.1 pinned
Release notes
Open source →-
Fixed: a condition comparing a field to
nullpassed as a parameter was encoded asfield = ?bound tonull.= NULLis never true in SQL, so the query returned no rows instead of the rows whose column is null.ConditionSQLEncoderdid turn=/INagainst null intoIS NULL(and!=/NOT INintoIS 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_styleto the formatter bundled with Dart 3.12, so on Dart 3.13 the generated*.reflection.g.dartno longer matched this package's owndart format, makingdart format --set-exit-if-changedandtest/ensure_build_test.dartmutually exclusive. 2.9.0 tracks the formatter the SDK ships.
- 2.8.1 pinned
-
-
1.15.012 Aug 2026Release notes
Open source →-
Faster request dispatch. A logged route call is ~2.9x faster
(measured in-process,APIRoot.callon a trivial route: 2.76us -> 0.90us).LoggerHandlerno 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
Zonelookup for the currentAPIRequestid — 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>andRESPONSE>).APIRouteHandlercaches itsCALL>message andRESPONSE>prefix. Both
are fixed once a route is registered, but were re-interpolated per request
(including stringifying the declaredparametersMap).APIRoot._callImplno longer copies the path parts list just to read the
first one.APIServer.toAPIRequestno longer copies the query-parametersMapa
second time.
-
The
routesbuilder now acceptsconfig:onany/get/post/put/
delete/patch/head, matchingAPIModule.addRoute. Previously an
APIRouteConfigcould only be set throughaddRoute, 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. Seebenchmark/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 pathThey 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 baredart:convertencode, and request bodies usedart:convert
directly, so no JSON optimization came out of that suite. -
DBSQLMemoryAdapternow answers a select by ID with a direct lookup in the
tableMap, which is already keyed by ID, instead of scanning it. A miss
still falls through to the scan, so results are unchanged.selectByIDwas 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.
Release notes
Open source →-
Faster request dispatch. A logged route call is ~2.9x faster (measured in-process,
APIRoot.callon a trivial route: 2.76us -> 0.90us).LoggerHandlerno 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 aZonelookup for the currentAPIRequestid — 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>andRESPONSE>).APIRouteHandlercaches itsCALL>message andRESPONSE>prefix. Both are fixed once a route is registered, but were re-interpolated per request (including stringifying the declaredparametersMap).APIRoot._callImplno longer copies the path parts list just to read the first one.APIServer.toAPIRequestno longer copies the query-parametersMapa second time.
-
The
routesbuilder now acceptsconfig:onany/get/post/put/delete/patch/head, matchingAPIModule.addRoute. Previously anAPIRouteConfigcould only be set throughaddRoute, 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. Seebenchmark/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 pathThey 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:convertencode, and request bodies usedart:convertdirectly, so no JSON optimization came out of that suite. -
DBSQLMemoryAdapternow answers a select by ID with a direct lookup in the tableMap, which is already keyed by ID, instead of scanning it. A miss still falls through to the scan, so results are unchanged.selectByIDwas 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.
-
-
1.14.011 Aug 2026Release notes
Open source →-
New
DBSQLiteAdapter: an embedded SQLite DB adapter, backed by the
sqlite3package.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.sqliteandsql.sqlite3, so a
config blockdb: { sqlite: {...} }resolves it. -
fromConfigacceptspath/file/database/dbfor the database file,
andmemory: true(or the path:memory:) for an in-memory database, plus
the usualgenerateTables/checkTables/populate/log.sqlkeys.
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
sqlite3package
bundles SQLite (3.53.4) through Dart's build hooks. -
Runs the same entity test-suite as the PostgreSQL and MySQL adapters, and
needs noDockercontainer to do it. NewAPITestConfigSQLite, 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 noSERIAL/AUTO_INCREMENT, only a column declared exactly
INTEGER PRIMARY KEYaliases therowid, and withoutAUTOINCREMENT
SQLite reuses the ID of a deleted row. ENUMis emulated with aVARCHAR CHECK (col IN (...))constraint.- Since
sqlite3is 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 useSAVEPOINT.
- An auto-assigning ID is declared
-
-
New
SQLDialect.returningAcceptsTableWildcard(defaulttrue, so the
PostgreSQL/MySQL/memory dialects are unchanged). SQLite rejects the
table-qualified wildcard thatDELETE ... RETURNINGemits
("RETURNING may not use TABLE.* wildcards") and needs a bare
RETURNING *. -
Fixed
DBObjectDirectoryAdapterlosing objects written just before a read:
_saveObjectwasasyncand itsFuturewas dropped bydoInsert/
doUpdate, while every reader in the adapter inspects the filesystem
synchronously. Astorecould therefore return before its object was on
disk, andselectAllwould silently omit it (a not-yet-written file reads
back asnulland was discarded). The write is now synchronous. -
Breaking: the minimum Dart SDK is now 3.10.0 (was 3.7.0), required by
sqlite3and its build hooks. -
Dependencies:
- Added
sqlite3: ^3.5.1
- Added
Release notes
Open source →-
New
DBSQLiteAdapter: an embedded SQLite DB adapter, backed by thesqlite3package.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.sqliteandsql.sqlite3, so a config blockdb: { sqlite: {...} }resolves it. -
fromConfigacceptspath/file/database/dbfor the database file, andmemory: true(or the path:memory:) for an in-memory database, plus the usualgenerateTables/checkTables/populate/log.sqlkeys. 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
sqlite3package 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
Dockercontainer to do it. NewAPITestConfigSQLite, exported bypackage:bones_api/bones_api_test_sqlite.dart. -
Notes on the SQLite dialect:
- An auto-assigning ID is declared
INTEGER PRIMARY KEY AUTOINCREMENT: SQLite has noSERIAL/AUTO_INCREMENT, only a column declared exactlyINTEGER PRIMARY KEYaliases therowid, and withoutAUTOINCREMENTSQLite reuses the ID of a deleted row. ENUMis emulated with aVARCHAR CHECK (col IN (...))constraint.- Since
sqlite3is 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 useSAVEPOINT.
- An auto-assigning ID is declared
-
-
New
SQLDialect.returningAcceptsTableWildcard(defaulttrue, so the PostgreSQL/MySQL/memory dialects are unchanged). SQLite rejects the table-qualified wildcard thatDELETE ... RETURNINGemits ("RETURNING may not use TABLE.* wildcards") and needs a bareRETURNING *. -
Fixed
DBObjectDirectoryAdapterlosing objects written just before a read:_saveObjectwasasyncand itsFuturewas dropped bydoInsert/doUpdate, while every reader in the adapter inspects the filesystem synchronously. Astorecould therefore return before its object was on disk, andselectAllwould silently omit it (a not-yet-written file reads back asnulland was discarded). The write is now synchronous. -
Breaking: the minimum Dart SDK is now 3.10.0 (was 3.7.0), required by
sqlite3and its build hooks. -
Dependencies:
- Added
sqlite3: ^3.5.1
- Added
-
-
1.13.002 Aug 2026Release notes
Open source →-
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 synchronousEntityPageLoader(aStreamwould
only deliver in a later microtask, after a sync read already finished).
To consume it as a stream, forward it:onEvent: myEventStream.add. onEventis notfinal, 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
Zoneand
does not break the fetch. - Nothing is allocated (not even the fetch timer) while
onEventisnull.
- Delivered synchronously, at the point where it happens and in order, so
-
New
EntityPaginationEvent<O>, asealedhierarchy so aswitchover it is
exhaustive, withEntityPaginationListener<O>as the callback type:EntityPaginationPageLoading: a fetch is about to start. Emitted once per
actual fetch.EntityPaginationPageLoaded: a fetch finished, with theentries, the
entriesLength, theelapsedTimeof thepageLoaderandisFinalPage.EntityPaginationPageError: a fetch failed, with theerror, the
stackTraceand theelapsedTime. 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) orknownEmpty(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 thefinalPageand the
totalLength. Emitted once, immediately after the
EntityPaginationPageLoadedthat resolved it — which is not necessarily
the final page itself, since an empty page can pin the end at its
predecessor.EntityPaginationReset:reset()orrefresh()discarded the loaded
pages, with thediscardedPages, thediscardedEntitiesLengthand
isRefresh—truewhile it is the reset of arefresh(), 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
EntityPaginationResetis about a page, and is an
EntityPaginationPageEvent(alsosealed) carrying thepage.Note that concurrent page loads interleave:
getRangeandrefreshstart
every page at once, so all the fetches are announced before any completes. -
paginateByQuery,paginateandpaginateAllgained the optionalonEvent
parameter, onEntitySource,EntityRepositoryandAPIRepository, so the
hook is reachable without building anEntityPaginationby 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/refreshevents).
Release notes
Open source →-
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(aStreamwould only deliver in a later microtask, after a sync read already finished). To consume it as a stream, forward it:onEvent: myEventStream.add. onEventis notfinal, so it can also be attached to an already builtEntityPagination. Only events emitted afterwards are seen.- An exception thrown by the listener is reported to the current
Zoneand does not break the fetch. - Nothing is allocated (not even the fetch timer) while
onEventisnull.
- Delivered synchronously, at the point where it happens and in order, so
it is also correct for a synchronous
-
New
EntityPaginationEvent<O>, asealedhierarchy so aswitchover it is exhaustive, withEntityPaginationListener<O>as the callback type:EntityPaginationPageLoading: a fetch is about to start. Emitted once per actual fetch.EntityPaginationPageLoaded: a fetch finished, with theentries, theentriesLength, theelapsedTimeof thepageLoaderandisFinalPage.EntityPaginationPageError: a fetch failed, with theerror, thestackTraceand theelapsedTime. The error is rethrown to the caller right after the event.EntityPaginationPageSkipped: a page was served without a fetch, with anEntityPaginationSkipReason:alreadyLoaded,inFlight(a concurrent request shares the fetch) orknownEmpty(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 thefinalPageand thetotalLength. Emitted once, immediately after theEntityPaginationPageLoadedthat resolved it — which is not necessarily the final page itself, since an empty page can pin the end at its predecessor.EntityPaginationReset:reset()orrefresh()discarded the loaded pages, with thediscardedPages, thediscardedEntitiesLengthandisRefresh—truewhile it is the reset of arefresh(), 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
EntityPaginationResetis about a page, and is anEntityPaginationPageEvent(alsosealed) carrying thepage.Note that concurrent page loads interleave:
getRangeandrefreshstart every page at once, so all the fetches are announced before any completes. -
paginateByQuery,paginateandpaginateAllgained the optionalonEventparameter, onEntitySource,EntityRepositoryandAPIRepository, so the hook is reachable without building anEntityPaginationby 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 thereset/refreshevents).
-
-
1.12.001 Aug 2026Release notes
Open source →-
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
pageparameter of theselect*
methods); entry indexes are 0-based (matching a DartList). See
indexOfPage/pageOfIndex. - Pages can be loaded out of order, leaving gaps:
getAt(45)with alimit
of 20 loads only page 3. - Synchronous access (
operator [],loadedEntities) never fetches;
only theFutureOrmethods (getAt,getPage,getRange,
loadNextPage,loadPage,loadAll,stream) do.operator []returns
nullfor a gap, an unloaded page or an out-of-range index alike; use
isPageLoaded/isIndexKnownOutOfRangeto tell them apart. - It is deliberately not a
Listor anIterable: both require a
length, which is exactly what a paginated select can't answer until it
reaches the end. UseloadAllwhen a complete list is really needed.
What it knows:
loadedPages,loadedPagesLength,loadedEntities,
loadedEntitiesLength,maxLoadedPage,maxLoadedIndex,maxKnownPage,
isFinalPageResolved,finalPage,totalLength,isKnownEmpty,
andinformation().Since every page except the last holds exactly
limitentries, 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. - Pages are 1-based (matching the
-
New
paginateByQuery,paginateandpaginateAllonEntitySource,
EntityRepository(withresolutionRules) andAPIRepository. They return
immediately without loading anything.orderByIDdefaults totruethere,
rather than following theoffset != nullrule of theselect*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.
Release notes
Open source →-
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
pageparameter of theselect*methods); entry indexes are 0-based (matching a DartList). SeeindexOfPage/pageOfIndex. - Pages can be loaded out of order, leaving gaps:
getAt(45)with alimitof 20 loads only page 3. - Synchronous access (
operator [],loadedEntities) never fetches; only theFutureOrmethods (getAt,getPage,getRange,loadNextPage,loadPage,loadAll,stream) do.operator []returnsnullfor a gap, an unloaded page or an out-of-range index alike; useisPageLoaded/isIndexKnownOutOfRangeto tell them apart. - It is deliberately not a
Listor anIterable: both require alength, which is exactly what a paginated select can't answer until it reaches the end. UseloadAllwhen a complete list is really needed.
What it knows:
loadedPages,loadedPagesLength,loadedEntities,loadedEntitiesLength,maxLoadedPage,maxLoadedIndex,maxKnownPage,isFinalPageResolved,finalPage,totalLength,isKnownEmpty, andinformation().Since every page except the last holds exactly
limitentries, 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.
- Pages are 1-based (matching the
-
New
paginateByQuery,paginateandpaginateAllonEntitySource,EntityRepository(withresolutionRules) andAPIRepository. They return immediately without loading anything.orderByIDdefaults totruethere, rather than following theoffset != nullrule of theselect*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.
-
-
1.11.001 Aug 2026Release notes
Open source →-
selectByQueryand its siblings gained 4 optional parameters, for pagination
and ordering:offset: the return offset.page: the 1-based page to return, an ergonomic alternative tooffset
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, orEntityHandler.idFieldName).orderDirection: the newOrderDirectionenum,ascending(default) or
descending.
Semantics:
- The effective ordering is
orderByID ?? (offset != null): a non-null
offsetturns the ordering on by default, since an offset-based
pagination needs a stable order to be correct. PassorderByID: falseto
opt out and get a bareOFFSET. orderDirectionis ignored while the ordering is not active.pageis a public convenience resolved to anoffsetat the repository
layer (seeresolveSelectOffset); the adapter contract keeps taking only
offset. It throws anArgumentErrorwhen combined with anoffset(two
spellings of one thing), when there is no positivelimitto use as the
page size, or when it is< 1.page: 1resolves tooffset: 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/allincluded),DBEntityRepository,DBRelationalAdapter/
DBRelationalRepositoryAdapter/DBRelationalEntityRepository,
DBAdapter.doSelectAll/doSelectByIDs,DBSQLAdapter.doSelect/
doSelectIDsBy/generateSelectSQL/generateSelectIDsSQLand
DBSQLRepositoryAdapter.generateSelectSQL. -
New
OrderDirectionenum (bones_api_types.dart), withsqlKeyword,
parseand the resolversresolveandresolveOrderByIDthat state the
semantics above exactly once. -
New
compareEntityIDsandapplySelectOrderAndPagination
(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): resolvespageto an
offset, and states thepage/offset/limitvalidation rules once. -
SQLDialect:- New
orderBySQLandlimitOffsetSQLclause builders, so all the
dialect-specificSELECTtail syntax lives in one place. - New
offsetRequiresLimitandoffsetMaxLimitValuecapabilities. MySQL sets
offsetRequiresLimit: truesince it can't parse anOFFSETthat is not
preceded by aLIMIT; an offset-only select there emits
LIMIT 18446744073709551615 OFFSET n. PostgreSQL and thegeneric
(in-memory) dialect emit a bareOFFSET n.
- New
-
SQL: newoffset,orderByIDandorderDirectionfields (carried by
copy()), read byDBSQLMemoryAdapterto apply the same semantics in Dart. -
APIDBModule.select(/db/select/<table>): newLIMIT=<n>,OFFSET=<n>,
PAGE=<n>andORDER=asc|descquery directives
(seeAPIDBModule.selectQueryDirectives),
parsed from the queryStringalongside the pre-existingEAGER=trueand
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 invalidPAGE
becomes an error response rather than an uncaughtArgumentError. -
Behavior change:
limitis now honored on the paths that previously
accepted and silently ignored it —DBEntityRepository.select's
ConditionID/ConditionIdIN/ConditionANY/KeyConditionEQfast paths,
DBAdapter.doSelectAll/doSelectByIDs, and theDBObjectMemoryAdapter,
DBObjectDirectoryAdapterandDBObjectGCSAdapteradapters. 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/DBAdapterimplementations must widen their overrides. -
Known limitation: a query over a to-many relationship generates a
JOIN
without aDISTINCT, 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,SQLDialectclause
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 ofAPIDBModule). 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.
- New
Release notes
Open source →-
selectByQueryand its siblings gained 4 optional parameters, for pagination and ordering:offset: the return offset.page: the 1-based page to return, an ergonomic alternative tooffsetthat 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, orEntityHandler.idFieldName).orderDirection: the newOrderDirectionenum,ascending(default) ordescending.
Semantics:
- The effective ordering is
orderByID ?? (offset != null): a non-nulloffsetturns the ordering on by default, since an offset-based pagination needs a stable order to be correct. PassorderByID: falseto opt out and get a bareOFFSET. orderDirectionis ignored while the ordering is not active.pageis a public convenience resolved to anoffsetat the repository layer (seeresolveSelectOffset); the adapter contract keeps taking onlyoffset. It throws anArgumentErrorwhen combined with anoffset(two spellings of one thing), when there is no positivelimitto use as the page size, or when it is< 1.page: 1resolves tooffset: 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/allincluded),DBEntityRepository,DBRelationalAdapter/DBRelationalRepositoryAdapter/DBRelationalEntityRepository,DBAdapter.doSelectAll/doSelectByIDs,DBSQLAdapter.doSelect/doSelectIDsBy/generateSelectSQL/generateSelectIDsSQLandDBSQLRepositoryAdapter.generateSelectSQL. -
New
OrderDirectionenum (bones_api_types.dart), withsqlKeyword,parseand the resolversresolveandresolveOrderByIDthat state the semantics above exactly once. -
New
compareEntityIDsandapplySelectOrderAndPagination(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): resolvespageto anoffset, and states thepage/offset/limitvalidation rules once. -
SQLDialect:- New
orderBySQLandlimitOffsetSQLclause builders, so all the dialect-specificSELECTtail syntax lives in one place. - New
offsetRequiresLimitandoffsetMaxLimitValuecapabilities. MySQL setsoffsetRequiresLimit: truesince it can't parse anOFFSETthat is not preceded by aLIMIT; an offset-only select there emitsLIMIT 18446744073709551615 OFFSET n. PostgreSQL and thegeneric(in-memory) dialect emit a bareOFFSET n.
- New
-
SQL: newoffset,orderByIDandorderDirectionfields (carried bycopy()), read byDBSQLMemoryAdapterto apply the same semantics in Dart. -
APIDBModule.select(/db/select/<table>): newLIMIT=<n>,OFFSET=<n>,PAGE=<n>andORDER=asc|descquery directives (seeAPIDBModule.selectQueryDirectives), parsed from the queryStringalongside the pre-existingEAGER=trueand 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 invalidPAGEbecomes an error response rather than an uncaughtArgumentError. -
Behavior change:
limitis now honored on the paths that previously accepted and silently ignored it —DBEntityRepository.select'sConditionID/ConditionIdIN/ConditionANY/KeyConditionEQfast paths,DBAdapter.doSelectAll/doSelectByIDs, and theDBObjectMemoryAdapter,DBObjectDirectoryAdapterandDBObjectGCSAdapteradapters. 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-partyEntityRepository/DBAdapterimplementations must widen their overrides. -
Known limitation: a query over a to-many relationship generates a
JOINwithout aDISTINCT, 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,SQLDialectclause builders),bones_api_entity_db_sql_select_test.dart(exact generated SQL per case + end-to-end paging over the in-memory SQL adapter) andbones_api_db_module_test.dart(first coverage ofAPIDBModule). 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.
- New
-
-
1.10.013 Jul 2026Release notes
Open source →-
docker_commander:^2.1.8→^3.0.0.- Removes
wasm_runandflutter_rust_bridge1.x from the dependency graph
(they came in viadocker_commander→apollovm, and were only ever needed
to execute Wasm — which nothing here does). - Those packages pinned
shelf_web_socket ^1.0.2and
web_socket_channel ^2.2.0, so everybones_apiapplication 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
DockerHosttypes exposed by the test utils keep the same shape.
- Removes
-
petitparser:^6.1.0→^7.0.2(required byapollovm2.0.0).JsonGrammarLexer.token:flatten()takes its message as a named
parameter in petitparser 7. Same behaviour, new call shape.
Release notes
Open source →-
docker_commander:^2.1.8→^3.0.0.- Removes
wasm_runandflutter_rust_bridge1.x from the dependency graph (they came in viadocker_commander→apollovm, and were only ever needed to execute Wasm — which nothing here does). - Those packages pinned
shelf_web_socket ^1.0.2andweb_socket_channel ^2.2.0, so everybones_apiapplication 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: theDockerHosttypes exposed by the test utils keep the same shape.
- Removes
-
petitparser:^6.1.0→^7.0.2(required byapollovm2.0.0).JsonGrammarLexer.token:flatten()takes its message as a named parameter in petitparser 7. Same behaviour, new call shape.
-
-
1.9.3110 Jun 2026Release notes
Open source →1.9.31
-
Bug fixes:
ConditionSQLEncoder.valueToParameterValue: fixed encoding of aListof values containingConditionParameters; each element is now resolved individually instead of passing the whole list to every element.ConditionEncoder.resolveValueToType: fixed resolution of a single-elementIterableto a primitive type (was a no-op comparison instead of an assignment, leaving the value as aList).MapGetterExtension.matchKeyIgnoreCase: fixed case-insensitive key matching that always returnednull(empty loop body); now returns the matching key. Also fixessetMultiValue(..., ignoreCase: true).Time:millisecond/microsecondrange validation now correctly rejects1000(valid range is0..999).Time._bytesInStringFormat: fixed the second-byte digit check that was effectively disabled (length < 2instead oflength >= 2).APISession.isExpired: now honors the providednowargument instead of always usingDateTime.now().APIServerResponseCachecached entry:replaceFileStatno 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 (
Timerange/string parsing,matchKeyIgnoreCase/getIgnoreCase/setMultiValue,APISession.isExpired, andConditionSQLEncoder/ConditionEncodervalue resolution).
- Added tests covering the bug fixes above (
Release notes
Open source →-
Bug fixes:
ConditionSQLEncoder.valueToParameterValue: fixed encoding of aListof values containingConditionParameters; each element is now resolved individually instead of passing the whole list to every element.ConditionEncoder.resolveValueToType: fixed resolution of a single-elementIterableto a primitive type (was a no-op comparison instead of an assignment, leaving the value as aList).MapGetterExtension.matchKeyIgnoreCase: fixed case-insensitive key matching that always returnednull(empty loop body); now returns the matching key. Also fixessetMultiValue(..., ignoreCase: true).Time:millisecond/microsecondrange validation now correctly rejects1000(valid range is0..999).Time._bytesInStringFormat: fixed the second-byte digit check that was effectively disabled (length < 2instead oflength >= 2).APISession.isExpired: now honors the providednowargument instead of always usingDateTime.now().APIServerResponseCachecached entry:replaceFileStatno 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 (
Timerange/string parsing,matchKeyIgnoreCase/getIgnoreCase/setMultiValue,APISession.isExpired, andConditionSQLEncoder/ConditionEncodervalue resolution).
- Added tests covering the bug fixes above (
-
-
1.9.3030 Apr 2026Release notes
Open source →v1.9.30
-
APIRootStarter:start:- Added logging of severe errors when
apiRoot.ensureInitialized()returns a failure with an error.
- Added logging of severe errors when
-
Project template:
update_project_template.sh:- Updated
project_template preparecommand to exclude IDE module files matching^\w+\.iml$from the template archive.
- Updated
-
Dependencies:
- Updated
build_runnerto ^2.15.0. - Updated
testto ^1.31.1. - Updated
vm_serviceto ^15.2.0.
- Updated
Release notes
Open source →-
APIRootStarter:start:- Added logging of severe errors when
apiRoot.ensureInitialized()returns a failure with an error.
- Added logging of severe errors when
-
Project template:
update_project_template.sh:- Updated
project_template preparecommand to exclude IDE module files matching^\w+\.iml$from the template archive.
- Updated
-
Dependencies:
- Updated
build_runnerto ^2.15.0. - Updated
testto ^1.31.1. - Updated
vm_serviceto ^15.2.0.
- Updated
-
-
1.9.2916 Apr 2026Release notes
Open source →-
ConditionID:- Added method
resolveIDValueto resolve the ID value from parameters orConditionParameter.
- Added method
-
DBEntityRepository:- Updated
selectIDsByand_selectByIDto useConditionID.resolveIDValuefor ID resolution. select:- Added optimization for
KeyConditionEQmatcher with a single key matching the entity ID field. - When matched, uses
_selectByIDto fetch the entity by ID and returns a single-element list or empty list accordingly.
- Added optimization for
- Updated
-
DBObjectDirectoryAdapter:- Updated
_doCountImpland_doDeleteImplto useConditionID.resolveIDValuefor ID resolution. - Updated public methods to pass combined parameters (
parameters ?? namedParameters) to internal implementations.
- Updated
-
DBObjectGCSAdapter:- Updated
_doCountImpland_doDeleteImplto useConditionID.resolveIDValuefor ID resolution. - Updated public methods to pass combined parameters (
parameters ?? namedParameters) to internal implementations.
- Updated
-
DBObjectMemoryAdapter:- Updated
_doCountImpland_doDeleteImplto useConditionID.resolveIDValuefor ID resolution. - Updated public methods to pass combined parameters (
parameters ?? namedParameters) to internal implementations.
- Updated
-
Dependency updates:
vm_service: ^15.0.2 → ^15.1.0
-
-
1.9.2808 Apr 2026Release notes
Open source →-
SQLGenerator:- Fixed
referenceTableandreferenceColumnassignment in unique constraint SQL entries to allow nullable references. - Updated unique and enum constraint names in
generateAddUniqueConstraintAlterTableSQLandgenerateAddEnumConstraintAlterTableSQLto use normalized column names with double underscores for consistency.
- Fixed
-
Dependency updates:
async_extension: ^1.2.22reflection_factory: ^2.7.5swiss_knife: ^3.3.14meta: ^1.18.2hotreloader: ^4.4.0googleapis_auth: ^2.3.0build_runner: ^2.13.1test: ^1.31.0
-
-
1.9.2718 Feb 2026Release notes
Open source →-
Added
bones_api_utils_fast_checksum.dart:- Provides functions
getAdler32Uint8List,getAdler32Hex,getCrc32Uint8List, andgetCrc32Hexfor Adler-32 and CRC-32 checksums as byte arrays and hex strings. - Implements internal helpers for big-endian byte conversion and hex encoding.
- Exports
getAdler32andgetCrc32fromarchivepackage for checksum calculation.
- Provides functions
-
WeakEtagclass (bones_api_base.dart):- Updated
WeakEtag.adler32andWeakEtag.crc32factories to usegetAdler32HexandgetCrc32Hexfrombones_api_utils_fast_checksum.dartinstead of deprecatedAdler32andCrc32classes.
- Updated
-
bones_api.dart:- Exported new
bones_api_utils_fast_checksum.dartutility.
- Exported new
-
Dependencies:
- Updated
async_extensionfrom ^1.2.20 to ^1.2.21. - Updated
swiss_knifefrom ^3.3.3 to ^3.3.5. - Updated
archivefrom ^4.0.7 to ^4.0.9. - Updated
build_runnerfrom ^2.10.5 to ^2.11.1. - docker_commander: ^2.1.8
- Updated
-
-
1.9.2603 Feb 2026Release notes
Open source →Initializablemixin:ensureInitialized: addedonErrorhandler tothencall to route errors to_onInitializationError.executeInitializedCallback:- Added
onErrorhandler tothencall on async initialization result to throwInitializationErrorwith stack trace.
- Added
_FutureExtension:toCompleter: addedonErrorhandler tothento complete completer with error and stack trace if not completed.
-
1.9.2530 Jan 2026Release notes
Open source →-
TableFieldReference:- Added nullable field
indexNameto represent the name of the index if one exists.
- Added nullable field
-
Added new class
TableRelationshipReferenceEntityTypedextendingTableRelationshipReference:- Adds
sourceFieldEntityTypeandtargetFieldEntityTypefields of typeTypeInfo. - Provides
copyWithEntityTypesmethod to create typed copies.
- Adds
-
TableRelationshipReference:- Added nullable fields
sourceRelationshipFieldIndexandtargetRelationshipFieldIndex. - Added
copyWithEntityTypesmethod returningTableRelationshipReferenceEntityTyped.
- Added nullable fields
-
EntityHandler:- Added
getFieldsListEntityTypesmethod to return a map of fields that are list entities or references with theirTypeInfo.
- Added
-
SQLDialect:- Added
foreignKeyCreatesImplicitIndexboolean flag with defaulttrue. - Added field
createIndexIfNotExiststo indicate support forIF NOT EXISTSinCREATE INDEX(defaulttrue).
- Added
-
CreateIndexSQL:- Updated
buildSQLmethod to conditionally includeIF NOT EXISTSonly if dialect supports it.
- Updated
-
DBPostgreSQLAdapter:- Added
foreignKeyCreatesImplicitIndexflag to PostgreSQL dialect set tofalse. - Updated
_findAllTableFieldsReferencesquery to include foreign key index name (fk_index_name) by joining withpg_indexandpg_class. - Populated
indexNameinTableFieldReferenceinstances from query result. - Updated relationship references to include
sourceRelationshipFieldIndexandtargetRelationshipFieldIndexfromindexName.
- Added
-
DBMySQLAdapter:- Set
createIndexIfNotExiststofalsein MySQL dialect capabilities.
- Set
-
DBSQLAdapter:parseConfigDBGenerateTablesAndCheckTables: changed return type fromList<bool>to a record with named fields(generateTables, checkTables).extractTableSQLs: updated regex to also matchCREATE INDEXstatements in addition toCREATEandALTER TABLE._populateTablesFromSQLsImpl: fixed error handling forCREATE INDEXstatements when the SQL dialect does not supportIF 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
_checkDBTableSchemeReferenceFieldto returnTableRelationshipReferenceEntityTypedwith entity types. - Added generation of missing reference indexes and missing relationship reference indexes SQL statements.
- Updated
_DBTableCheckclass:- Added fields
missingReferenceIndexesandmissingRelationshipReferenceIndexes. - Added methods to generate missing reference indexes and relationship reference indexes SQL.
- Added fields
- Added
_DBRelationshipTableColumnsubclass of_DBTableColumnto 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.
- Added index creation after foreign key constraints in
-
Dependency updates:
async_extension: ^1.2.19 → ^1.2.20meta: ^1.18.0 → ^1.18.1
-
-
1.9.2422 Jan 2026Release notes
Open source →-
GZipSink:- Added override for
addSliceto handle partial chunk addition and update_inputLengthaccordingly. - Optimized
addSliceto call_gzipSink.close()whenisLastis true and full chunk is added.
- Added override for
-
BytesSink:- Updated
addSliceto use newaddPartmethod for partial chunk addition.
- Updated
-
BytesBuffer:- Added
addPartmethod to add a slice of bytes from a given offset and length, resizing buffer if needed. - Refactored
addmethod to delegate toaddPart. - Improved buffer range setting to support offset and length parameters in
addPart.
- Added
-
async_extension: ^1.2.18 -> ^1.2.19
-
-
1.9.2320 Jan 2026Release notes
Open source →DBPostgreSQLAdapter:mapDataTypeToDartType: added support for PostgreSQL typessmallintandsmallserialmapping toint.
-
1.9.2220 Jan 2026Release notes
Open source →-
Initializablemixin:- Added calls to
_forceLogFlushMessages()before throwingInitializationErrorin:_checkDependency_setInitializedDependenciesCompleters_onInitializationError_checkAllDependenciesOk_finalizeInitializationcheckInitializedexecuteInitialized
- Added calls to
-
Logging:
- Added
_forceLogFlushMessages()function to calllogging.Logger.root.forceFlushMessages(). Loggerextension:- Added
forceFlushMessages()method to invokeLoggerHandler.forceFlushMessages().
- Added
LoggerHandlerabstract class:- Added
forceFlushMessages()method.
- Added
LoggerHandlerGenericimplementation:- Implemented
forceFlushMessages()returningfalse.
- Implemented
LoggerHandlerIOimplementation:- Implemented
forceFlushMessages()to flush the print message queue immediately if not empty.
- Implemented
- Added
-
-
1.9.2117 Jan 2026Release notes
Open source →-
EntityHandler:- Updated all
Map.unmodifiableusages to explicitly specify type arguments, e.g.Map<String, TypeInfo>.unmodifiable. - Updated methods including
fieldsWithEntityReference,fieldsWithEntityReferenceList,fieldsEntityAnnotations,fieldsWithType,getFieldsTypes,getFieldsEnumTypes,getFieldsEntityTypes, andconstructorsto use typed unmodifiable maps. - Improved type safety in map constructions by adding explicit generic parameters.
- Updated all
-
Dependency updates:
meta: ^1.18.0
-
-
1.9.2015 Jan 2026Release notes
Open source →-
ConditionSQLEncoder:keyToSQL: added check to throwConditionEncodingErrorifkeysis empty.- Refactored
keyFieldReferenceToSQLto recursively resolve multi-level key references by walking keys and resolving intermediate tables and relationships. - Added helper methods
_resolveReferenceFieldand_resolveFinalFieldto modularize reference resolution logic.
-
DBSQLAdapter:- Introduced
_JoinEntrytypedef to represent SQL JOIN fragments with explicit alias dependencies (defsandrefs). - 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
_JoinEntrywith defined and referenced aliases. - Sort JOINs by alias dependencies before concatenation.
- Log a warning if not all JOIN references could be resolved.
- Collect JOINs as
- This improves correctness and ordering of JOIN clauses in generated SQL.
- Introduced
-
Dependencies:
- Updated
async_extensionfrom ^1.2.17 to ^1.2.18. - Updated
build_runnerfrom ^2.10.4 to ^2.10.5.
- Updated
-
-
1.9.1909 Jan 2026Release notes
Open source →- Dependency updates:
- Updated
reflection_factorydependency from^2.7.2to^2.7.3.
- Updated
- Dependency updates:
-
1.9.1809 Jan 2026Release notes
Open source →-
DBAdapter:- Improved error messages in instantiation methods to include a list of instantiator function keys.
-
Dependencies:
- Updated
async_extensionfrom ^1.2.15 to ^1.2.17. - Updated
testfrom ^1.28.0 to ^1.29.0.
- Updated
-
-
1.9.1719 Dec 2025Release notes
Open source →-
APIServer:_resolvePayloadFromString: Improved JSON payload parsing:- Trim input before decoding.
- Return
nullfor empty bodies. - Catch decode errors and log them without throwing.
-
statistics: ^1.2.1
-
-
1.9.1626 Nov 2025Release notes
Open source →-
New
FileLimited: exposeFililimit handling. -
FileLimitExtension: useFileLimited.global. -
APIServerResponseCache:- Use a local
_fileLimitedfor file operations. - Optimize
Fileoperations to prioritize async and limited operations.
- Use a local
-
shelf_letsencrypt: ^2.0.3
-
build_runner: ^2.10.4
-
test: ^1.28.0
-
-
1.9.1512 Nov 2025Release notes
Open source →-
FileLimitExtension:- Added
statLimited,deleteLimited.
- Added
-
DBObjectGCSAdapter:- Replaced direct file operations with the new limited I/O methods:
deleteLimited()instead ofdelete()statLimited()instead ofstat()
- Improves concurrency control and prevents
Too many open fileserrors during cache cleanup and maintenance...
- Replaced direct file operations with the new limited I/O methods:
-
-
1.9.1412 Nov 2025Release notes
Open source →-
FileLimitExtension:- Added
readAsBytesLimited()andwriteAsBytesLimited()methods to safely limit concurrent file I/O operations and preventToo many open fileserrors.
- Added
-
DBObjectGCSAdapter:- Replaced direct file reads with the new
FileLimitExtension.readAsBytesLimited()to control concurrent I/O and preventToo many open fileserrors during cache access.
- Replaced direct file reads with the new
-
async_locks: ^4.0.2
-
build_runner: ^2.10.2
-
test: ^1.27.0
-
-
1.9.1311 Nov 2025Release notes
Open source →DBObjectGCSAdapter:_checkCacheDirectoryLimit:- Improve logging.
- Fix calculation of needed deleting and extra 20%.
-
1.9.1211 Nov 2025Release notes
Open source →-
DBObjectGCSAdapter:- Added properties:
cacheDevelopment,cacheFilesLimit,cacheCheckMaxSkipsandcacheCheckTimeout. - Auto-created
cacheDirectoryoncacheDevelopment. _checkCacheDirectoryLimit:- Optimize and also use
cacheFilesLimit. - Log check time.
- Optimize and also use
- Added properties:
-
DBObjectDirectoryAdapter:- Added property
development. - Auto-created
directoryondevelopment.
- Added property
-
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
-
-
1.9.1119 Sep 2025Release notes
Open source →-
EntityHandler:resolveFieldsValues: when resolving anEntityReferenceand the value can't be resolved, pass the ID to the EntityReference.resolveValueByType: optimize for nullvalue.
-
LoggerHandler:_buildMsg: handle long debugName starting withtest_suite:.
-
ClassProxyListener:onCall: On response error, throw an exception usingresponse.stackTracewhen available.
-
-
1.9.1019 Sep 2025 -
1.9.919 Aug 2025Release notes
Open source →-
APISecurity:- Added
notifyAPITokenInfoChange,disposeAuthenticationPermission,disposeAuthenticationDataAndPermission.
- Added
-
APITokenStore:- Added
removeTokenPermissions,removeTokenDataAndPermissions.
- Added
-
APIRequest:- Add
APIRequestandgetPayloadParameterIgnoreCase.
- Add
-
-
1.9.818 Aug 2025Release notes
Open source →-
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.
-
-
1.9.710 Aug 2025Release notes
Open source →-
EntityAccessRules: addedtotalRules. -
APIModule:- Added
addRouteHandler.
- Added
-
APIRouteBuilder:- Added
addRouteHandler. apiMethod: optimize the builtrouteHandler.
- Added
-
Now
APIRouteHandleris abstract:- Removed field
function. - Public implementation
APIRouteHandlerFunction.
- Removed field
-
MethodReflectionExtension:returnsAPIResponse: do not acceptdynamic.
-
APIServer:- Improve error logging when start fails.
-
reflection_factory: ^2.5.3
-
-
1.9.627 Jul 2025Release notes
Open source →APIServer:_defineGZipEncodedHeaders:- Fix
serverTimingEntryNamedefault value fromobj->json->gziptoobj-json-gzip.
- Fix
-
1.9.527 Jul 2025Release notes
Open source →-
APIServer:_resolveBodyImpl:- Log errors while encoding payload to JSON.
- Catch
OutOfMemoryErrorand log. - Return
apiResponse.asErroron errors.
_jsonEncodePayload:- Now uses
AutoGZipSinkandJson.encodeToSinkto stream JSON encoding with automatic GZip compression based on output size.
- Now uses
-
Added
AutoGZipSink,GZipSinkandBytesSinkandBytesBuffer. -
Json:- Added
encodeToSink.
- Added
-
reflection_factory: ^2.5.2
-
swiss_knife: ^3.3.3
-
test: ^1.26.3
-
-
1.9.411 Jul 2025Release notes
Open source →-
Main updates (see
v1.9.4-beta.*for more):-
APIServerConfig:defaultStaticFilesCacheControl: removedmust-revalidate(conflicts withstale-while-revalidate).- Added
longLivedStaticFilesCacheControlandlongLivedStaticFilesCached- Default values are for PWA bootstrap files:
/,/index.html,styles.css,/pwa_sw.js
- Default values are for PWA bootstrap files:
- Constructor:
- Improved parameters that can be passed through
apiConfig:
- Improved parameters that can be passed through
-
CacheControl:- Removed
mustRevalidatefrom the defaultdirectives(conflicts withstaleWhileRevalidate).
- Removed
-
-
coverage: ^1.15.0
-
-
1.9.4-beta.310 Jul 2025 pre-releaseRelease notes
Open source →APIServerConfig:- Fix
normalizeHeaderValueresolution when usingapiConfig.
- Fix
-
1.9.4-beta.210 Jul 2025 pre-releaseRelease notes
Open source →APIServerConfig:defaultLongLivedStaticFilesCacheControl: changedmax-agefrom 86400 (1 day) to 3600 (1 hour).- Constructor:
- Improved parameters that can be passed through
apiConfig:cookieless,useSessionID.maxPayloadLength,decompressPayload.apiCacheControl,staticFilesCacheControl.longLivedStaticFilesCacheControl,longLivedStaticFilesCached.
- Improved parameters that can be passed through
-
1.9.4-beta.104 Jul 2025 pre-releaseRelease notes
Open source →-
CacheControl:- Removed
mustRevalidatefrom the defaultdirectives(conflicts withstaleWhileRevalidate).
- Removed
-
APIServerConfig:defaultStaticFilesCacheControl: removedmust-revalidate(conflicts withstale-while-revalidate).- Added
longLivedStaticFilesCacheControlandlongLivedStaticFilesCached- Default values are for PWA bootstrap files:
/,/index.html,styles.css,/pwa_sw.js
- Default values are for PWA bootstrap files:
-
APIServerResponseCache:- Improve headers of cached responses:
- Added
Cache-ControlandServer. - Added
Last-Modifiedon 304 responses.
- Added
- Improve headers of cached responses:
-
-
1.9.329 Jun 2025Release notes
Open source →-
DBPostgreSQLAdapter:- Upgrade to
postgresAPI v3. - Allow SSL connections.
- Upgrade to
-
DBEntityRepositoryProvider: check for duplicated repositories. -
APIServerConfig,APIServerWorker,APIServer:- Add
maxPayloadLengthanddecompressPayloadoptions for request handling.
- Add
-
APIServer:_loadPayloadBytes:- Added support for compressed payload in gzip and deflate.
- Added
_decodePayloadGzipto handled GZip decompression and check the decompressed size in header before decompression.
-
Time.parse: accept formatTime(hh:mm:ss.sss) -
Fix SQL column generation type if min/max is defined for the field.
-
postgres: ^3.5.6
-
-
1.9.3-beta.1128 Jun 2025 pre-releaseRelease notes
Open source →-
DBEntityRepositoryProvider:- Added
_checkDuplicatedRepositories: check for duplicated repositores, byTypeandname.
- Added
-
Initializable:_doInitializationImpl: add extra timeout when new parents are added.
-
-
1.9.3-beta.1028 Jun 2025 pre-releaseRelease notes
Open source →DBMySQLAdapter,DBPostgreSQLAdapter:typeToSQLType: fix forint/BigIntID (isID: true).
-
1.9.3-beta.928 Jun 2025 pre-releaseRelease notes
Open source →-
DBMySQLAdapter:typeToSQLType:- Fix for
int: useentityFieldAnnotationsmin/max to define SQL type (TINYINT,SMALLINT,MEDIUMINT,INT,BIGINT). - Fix for
BigIntandDynamicInt:DECIMAL(65, 0)
- Fix for
-
DBPostgreSQLAdapter:typeToSQLType:- Fix
int: useentityFieldAnnotationsmin/max to define SQL type (SMALLINT,INT,BIGINT). - Fix for
BigIntandDynamicInt:NUMERIC
- Fix
-
-
1.9.3-beta.818 Jun 2025 pre-releaseRelease notes
Open source →-
APIServerConfig,APIServerWorker,APIServer:- Add
maxPayloadLengthanddecompressPayloadoptions for request handling.
- Add
-
APIServer:_loadPayloadBytes:- Added support for compressed payload in gzip and deflate.
- Added
_decodePayloadGzipto handled GZip decompression and check the decompressed size in header before decompression.
-
-
1.9.3-beta.705 Jun 2025 pre-releaseRelease notes
Open source →-
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
-
-
1.9.3-beta.614 May 2025 pre-releaseRelease notes
Open source →-
TypeInfoEntityExtension,TypeReflectionEntityExtension:entityType: also handleList<E>, returning theListgeneric type (E).
-
TypeInfoEntityExtension:- Added
toCastedList.
- Added
-
DBSQLAdapter:_checkDBTableScheme:- Separate references and collection references in
referenceFieldsandcollectionReferenceFields.
- Separate references and collection references in
_DBTableCheck: added fieldmissingCollectionReferenceColumns.
-
EntityHandler:resolveFieldsValues: ensure thatList<E>fields are casted to the list, usingentityType.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
-
-
1.9.3-beta.510 Mar 2025 pre-releaseRelease notes
Open source →-
DBPostgreSQLAdapter: -
PostgreSQLConnectionWrapper:- Remove field
_endpoint. - Added fields
username,host,port,database,secure. connectionURL: appended query string withsslmode.
- Remove field
-
-
1.9.3-beta.410 Mar 2025 pre-releaseRelease notes
Open source →DBPostgreSQLAdapter:_connectSSLImpl,_connectNoSSLImpl: simplify error handling.
-
1.9.3-beta.310 Mar 2025 pre-releaseRelease notes
Open source →-
New
DBAdapterConnectivity. -
DBAdapter:- Added field
connectivity.
- Added field
-
DBPostgreSQLAdapter:- Remove filed
onlySecureConnections. - Added support to
connectivityfield.
- Remove filed
-
-
1.9.3-beta.210 Mar 2025 pre-releaseRelease notes
Open source →-
New
DBAdapterCapabilityConnectivity. -
DBAdapterCapability:- Added field
connectivity.
- Added field
-
DBPostgreSQLAdapter:- Added field
onlySecureConnections.
- Added field
-
dependency_validator: ^4.1.3
-
-
1.9.3-beta.106 Mar 2025 pre-releaseRelease notes
Open source →-
DBPostgreSQLAdapter:- Upgrade to
postgresAPI v3. - Allow SSL connections.
- Upgrade to
-
Time.parse: accept formatTime(hh:mm:ss.sss) -
postgres: ^3.5.4
-
project_template: ^1.1.1
-
archive: ^4.0.4
-
-
1.9.204 Mar 2025Release notes
Open source →-
FieldsFromMap:resolveFiledName: improve field matching.
-
EntityHandlergetFieldType: added parameterresolveFiledName: false.- Optimize field and types resolution.
-
GenericEntityHandler,ClassReflectionEntityHandler:- Optimize field and types resolution.
-
-
1.9.127 Feb 2025 -
1.9.025 Feb 2025Release notes
Open source →-
APIPlatformBrowser:- Change use of
dart:html(deprecated) to packageweb.
- Change use of
-
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
-
-
1.8.712 Feb 2025Release notes
Open source →-
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
-
-
1.8.625 Dec 2024Release notes
Open source →- ✨♻️ Improve cast method in APIResponse
- Add error parameter to cast method for more flexibility
- Include additional requires authentication in the copied APIResponse object.
- ✨♻️ Improve cast method in APIResponse
-
1.8.525 Dec 2024Release notes
Open source →-
refactor(api):
- 🔨 improve payload handling in resolveBody and resolveBodySync
- 🔨
UNAUTHORIZED,BAD_REQUEST: Allowerroraspayloadin response generation.
-
swiss_knife: ^3.2.3
-
yaml: ^3.1.3
-
stream_channel: ^2.1.3
-
-
1.8.420 Dec 2024 -
1.8.320 Dec 2024Release notes
Open source →-
ZoneField:createContextZone: added parameterzoneValues.createSafeContextZone:- Added named parameters
zoneSpecificationandzoneValues - Changed
handleUncaughtErrorto named parameter.
- Added named parameters
-
APIRoot:_callZoned:- Fix closure memory leak.
- Optimize and avoid a new closure on parameter
handleUncaughtErrorfor everyZonecreated throughcurrentAPIRequest.createSafeContextZone. Now using a singleZoneSpecificationinstance. - Ensure that
currentAPIRequest.disposeContextZone(callZone)is always called.
- Optimize and avoid a new closure on parameter
- Fix closure memory leak.
-
async_extension: ^1.2.14
-
test: ^1.25.14
-
-
1.8.219 Dec 2024Release notes
Open source →✨♻️ Add
Timeoperators 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
-