Shaunebu.Data.SQLite
1.1.0
dotnet add package Shaunebu.Data.SQLite --version 1.1.0
NuGet\Install-Package Shaunebu.Data.SQLite -Version 1.1.0
<PackageReference Include="Shaunebu.Data.SQLite" Version="1.1.0" />
<PackageVersion Include="Shaunebu.Data.SQLite" Version="1.1.0" />
<PackageReference Include="Shaunebu.Data.SQLite" />
paket add Shaunebu.Data.SQLite --version 1.1.0
#r "nuget: Shaunebu.Data.SQLite, 1.1.0"
#:package Shaunebu.Data.SQLite@1.1.0
#addin nuget:?package=Shaunebu.Data.SQLite&version=1.1.0
#tool nuget:?package=Shaunebu.Data.SQLite&version=1.1.0
Shaunebu.Data.SQLite
Shaunebu.Data.SQLite is a lightweight convenience layer over sqlite-net-pcl for .NET and .NET MAUI applications that need simple asynchronous CRUD, table management, fluent table queries, dependency injection, lifecycle management, interceptors, and structured operation logging.
It keeps sqlite-net close at hand, but wraps the repetitive production plumbing that application teams usually have to build themselves.
๐ก Tip
UseSQLiteManagerService.GetInstance(...)for a shared path-based manager, orAddShaunebuSQLite(...)when your app is already composed withIServiceCollection.
โจ Features
| Feature | Supported |
|---|---|
| โ Async CRUD | Yes |
| โ Async aliases | Yes |
| โ Batch operations | Yes |
| โ Query builder | Yes |
โ
TableContext<T> |
Yes |
| โ Dependency injection | Yes |
| โ Configurable connection options | Yes |
| โ Write-ahead logging | Yes |
| โ Busy timeout | Yes |
| โ Observability | Yes |
| โ Interceptors | Yes |
| โ Microsoft logging | Yes |
| โ Shaunebu.Common.Logging | Yes |
| โ Custom sqlite-net mappings | Yes |
| โ .NET MAUI | Yes |
| โ .NET 9 / .NET 10 | Yes |
| โ XML documentation | Yes |
| โ NuGet distribution | Yes |
๐งญ Why Shaunebu.Data.SQLite?
sqlite-net-pcl is excellent. Shaunebu.Data.SQLite is for teams that want a focused, application-level manager around it.
| Capability | What this package adds |
|---|---|
| Cleaner API | A compact service for CRUD, table management, batch operations, and fluent queries. |
| MAUI-ready setup | Works naturally in .NET MAUI apps and validates against MAUI consumer builds. |
| Built-in DI | AddShaunebuSQLite(...) supports singleton, scoped, and transient registrations. |
| Lifecycle management | Path-based singleton lookup, idempotent close, dispose support, and recreate-after-close behavior. |
| Production defaults | Sensible default open flags and explicit configuration for WAL, busy timeout, mutex, shared cache, and date storage. |
| Observability | Structured operation logs through Microsoft.Extensions.Logging. |
| Interceptors | Ordered operation callbacks for metrics, audit, diagnostics, and failure observation. |
| Async naming | Existing compatibility methods plus conventional InsertAsync, UpdateAsync, and DeleteAsync aliases. |
๐ Comparison
| Feature / Library | Shaunebu.Data.SQLite | SQLite-net direct usage | Entity Framework Core |
|---|---|---|---|
| Fluent table API | โ
TableContext<T> and TableQueryBuilder<T> |
โ ๏ธ Manual composition over .Table<T>() |
โ
LINQ + DbSet |
| Batch insert/update/delete | โ Supported with transaction-backed execution | โ ๏ธ Usually implemented manually | โ Supported |
| Reset / ensure table exists | โ
EnsureTableExistsAsync<T>() / ResetTableAsync<T>() |
โ ๏ธ Manual setup required | โ ๏ธ EnsureCreated() or migrations |
| Dependency injection | โ Built into the core package | โ ๏ธ Application-owned wiring | โ Built in |
| Operation logging | โ
Structured ILogger events |
โ ๏ธ Application-owned logging | โ
ILogger support |
| Interceptors | โ SQLite operation callbacks | โ ๏ธ Application-owned wrapper logic | โ Interceptor model |
| Thread-safe manager lookup | โ Singleton per normalized database path | โ ๏ธ Depends on application code | โ ๏ธ DbContext lifetime rules |
| Weight and complexity | โ Lightweight wrapper, no EF Core dependency | โ Very lightweight | โ Heavier ORM model |
| Recommended use | Lightweight to medium .NET / MAUI applications | Micro-projects and prototypes | Large data models, migrations, relational projections |
๐ฆ Installation
Install-Package Shaunebu.Data.SQLite
The package currently targets:
| Target Framework | Status |
|---|---|
net9.0 |
Supported |
net10.0 |
Supported |
โน๏ธ Note
Version1.3.0is standardized on modern .NET target frameworks. Oldernet8.0assets are not included in this package version.
๐ Quick Start
using Microsoft.Extensions.Logging;
using Shaunebu.Data.SQLite;
var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole());
var logger = loggerFactory.CreateLogger<SQLiteManagerService>();
var db = SQLiteManagerService.GetInstance("mydatabase.db", logger);
await db.EnsureTableExistsAsync<User>();
GetInstance keeps one live manager per normalized database path. Calls are safe for concurrent instance lookup, and the first logger supplied for a live path is the logger used by that shared instance. After CloseAsync, a later GetInstance call recreates a new manager for that path.
flowchart TD
A["Application / .NET MAUI App"] --> B["SQLiteManagerService"]
B --> C["sqlite-net-pcl"]
C --> D["SQLite"]
โ๏ธ Configuration
Use SQLiteManagerOptions when you need to configure sqlite-net open flags or startup behavior:
var db = SQLiteManagerService.GetInstance(new SQLiteManagerOptions
{
DatabasePath = "mydatabase.db",
OpenFlags = SQLiteOpenFlags.ReadWrite |
SQLiteOpenFlags.Create |
SQLiteOpenFlags.SharedCache,
EnableWriteAheadLogging = true,
BusyTimeout = TimeSpan.FromSeconds(30),
StoreDateTimeAsTicks = true,
FullMutex = true,
SharedCache = true
});
OpenFlags is the source of truth for connection flags. FullMutex and SharedCache are convenience accessors that add or remove their corresponding SQLiteOpenFlags values from OpenFlags.
Existing path-based APIs continue to use default options: ReadWrite, Create, FullMutex, and StoreDateTimeAsTicks = true. When using GetInstance(SQLiteManagerOptions), the live singleton is still keyed by normalized DatabasePath; changing options after the first live instance is created does not reconfigure that instance. Close it before recreating the manager with different options for the same path.
๐ Lifecycle
Close pooled SQLite connections when the database is no longer needed and all database operations have completed:
await db.CloseAsync();
or:
await using var db = SQLiteManagerService.GetInstance("mydatabase.db");
CloseAsync() is idempotent, so repeated calls are safe. Treat close/dispose as an application shutdown boundary for that database manager. Do not close the manager while other threads are actively using it.
โ ๏ธ Important
After close, using the manager, or anyTableContext<T>orTableQueryBuilder<T>created by that manager, throwsObjectDisposedException. Closing does not cancel SQLite operations that were already in flight.
๐ก Best Practices
- Use
GetInstance(dbPath)or singleton DI registration when one shared manager per database file is the right lifetime for your application. - Use scoped or transient DI registration when a manager must be isolated from the global singleton registry.
- Use
SQLiteManagerOptionsrather than ad hoc setup calls when WAL, busy timeout, open flags, or observability should be applied during construction. - Use
ResetTableAsync<T>()for tests, demos, and explicit table reset workflows; avoid it for user data unless destructive reset is intentional. - Use
TableContext<T>for table-scoped CRUD workflows andTableQueryBuilder<T>when fluent query composition is the focus. - Keep
CloseAsync()as a shutdown boundary after database work has completed. - Keep sensitive values out of log messages and let structured logging carry operation metadata.
๐๏ธ Table Management
| Method | Description |
|---|---|
EnsureTableExistsAsync<T>() |
Creates the mapped table if it does not exist. |
ResetTableAsync<T>() |
Drops and recreates the mapped table, including custom [Table] names. |
For<T>().DeleteAllAsync() |
Deletes all rows from the mapped table. |
await db.EnsureTableExistsAsync<User>();
await db.ResetTableAsync<User>();
await db.For<User>().DeleteAllAsync();
Custom sqlite-net mappings are honored by table creation, reset, query, and delete-all operations.
๐ CRUD Operations
await db.Insert(new User { Name = "Alice" });
await db.InsertAsync(new User { Name = "Alice Async" });
await db.Insert(new List<User>
{
new() { Name = "Bob" },
new() { Name = "Charlie" }
});
await db.InsertAsync(new List<User>
{
new() { Name = "Dana" },
new() { Name = "Eve" }
});
var alice = await db.For<User>()
.Where(user => user.Name == "Alice")
.FirstOrDefaultAsync();
if (alice is not null)
{
alice.Name = "Alice Updated";
await db.Update(alice);
await db.UpdateAsync(alice);
await db.Delete(alice);
}
The SQLiteManagerService method names Insert, Update, and Delete are kept for compatibility. The InsertAsync, UpdateAsync, and DeleteAsync aliases are available for conventional .NET async naming and delegate to the existing methods.
โน๏ธ Note
The compatibility method names are asynchronous even though their names do not end withAsync. New code can use theAsyncaliases for clarity.
๐ Query Builder
Use For<T>() for table-scoped operations:
var users = await db.For<User>()
.Where(user => user.Name.Contains("Alice"))
.OrderBy(user => user.Name)
.ToListAsync();
Use Table<T>() when you want the wrapper query builder and its CountAsync helper:
var count = await db.Table<User>()
.Where(user => user.Name.Contains("Alice"))
.CountAsync();
| API | Best for |
|---|---|
TableContext<T> |
Table-scoped CRUD, delete-all, and simple query workflows. |
TableQueryBuilder<T> |
Fluent query composition with Where, ordering, ToListAsync, FirstOrDefaultAsync, and CountAsync. |
๐ TableContext Helper
Create a table-specific context from the manager when the surrounding code is focused on one model:
var usersTable = db.For<User>();
await usersTable.InsertAsync(new User { Name = "Diana" });
var allUsers = await usersTable.ToListAsync();
Supported table-context query methods:
| Method | Description |
|---|---|
Where(Expression<Func<T, bool>>) |
Filters results. |
OrderBy<TKey>(Expression<Func<T, TKey>>) |
Sorts ascending. |
OrderByDescending<TKey>(Expression<Func<T, TKey>>) |
Sorts descending. |
ToListAsync() |
Executes the query and returns a list. |
FirstOrDefaultAsync() |
Returns the first matching row or null. |
๐ Dependency Injection
The core Shaunebu.Data.SQLite package includes dependency injection extensions. Register the manager in a .NET or .NET MAUI app with AddShaunebuSQLite():
using Microsoft.Extensions.DependencyInjection;
builder.Services.AddShaunebuSQLite(options =>
{
options.DatabasePath = databasePath;
options.EnableWriteAheadLogging = true;
options.BusyTimeout = TimeSpan.FromSeconds(30);
});
The default lifetime is singleton. Scoped and transient registrations are supported:
builder.Services.AddShaunebuSQLite(
options => options.DatabasePath = databasePath,
ServiceLifetime.Scoped);
Singleton DI registration uses the same path-based shared manager as SQLiteManagerService.GetInstance. Scoped and transient registrations create independent managers. The DI container disposes resolved managers when their configured lifetime ends; manually calling CloseAsync is still valid, and the operation is idempotent.
Registered interceptors are resolved automatically by the core package DI extensions:
builder.Services.AddSingleton<ISQLiteInterceptor, MetricsInterceptor>();
builder.Services.AddSingleton<ISQLiteInterceptor, AuditInterceptor>();
Interceptors are resolved once per manager construction and preserve registration order. Scoped and transient SQLite managers do not use the global singleton registry. Scoped interceptors are rejected for singleton manager registration; use scoped or transient manager registration when interceptors need scoped dependencies.
๐ Observability
Enable operation logging through SQLiteManagerOptions:
builder.Services.AddShaunebuSQLite(options =>
{
options.DatabasePath = databasePath;
options.EnableObservability = true;
options.LogLevel = LogLevel.Information;
options.SlowOperationThreshold = TimeSpan.FromMilliseconds(500);
});
EnableObservability = true enables routine completion logs at LogLevel and slow-operation warnings at warning level. EnableObservability = false disables those routine operation logs, but it does not silently skip registered interceptors and it does not suppress error logs that are accepted by the configured ILogger filters.
The library logs through Microsoft.Extensions.Logging.ILogger. It does not implement a separate logging pipeline. If your application uses Shaunebu.Common.Logging, configure its existing Microsoft logging provider and SQLite logs will flow through that pipeline:
builder.Services
.AddShaunebuLogging(options =>
{
options.ApplicationName = "MyMauiApp";
options.Redaction.Enabled = true;
})
.AddShaunebuMicrosoftLogging();
flowchart TD
A["Application"] --> B["ILogger / ILogger<T>"]
B --> C["Shaunebu.Common.Logging Microsoft Adapter"]
C --> D["Shaunebu.Common.Logging"]
D --> E["Console Provider"]
D --> F["File Provider"]
D --> G["Custom Providers"]
Operation logs include operation type, table name when known, duration, slow-operation warnings, and exception details. Entity values, SQL parameter values, connection strings, encryption keys, tokens, and absolute database paths are not logged by default. SQLiteManagerOptions.LogLevel chooses the requested level for successful completion logs; normal Microsoft.Extensions.Logging filters still decide whether that level is emitted.
๐งพ Sample Log Output
[Information] OperationCompleted
Table: Users
Duration: 14 ms
With Shaunebu.Common.Logging, SQLite logs flow through its provider pipeline:
INFORMATION [Shaunebu.Data.SQLite.SQLiteManagerService] SQLite operation Insert completed in 7.3 ms for table users
PROPERTIES: {"OperationType":4,"DurationMs":7.3,"TableName":"users","EventName":"OperationCompleted"}
SQLite logs use stable event names:
| Event name | When emitted |
|---|---|
DatabaseOpened |
Startup open observation completed. |
DatabaseClosed |
CloseAsync completed. |
OperationCompleted |
A non-special SQLite operation completed. |
SlowOperation |
A completed operation met or exceeded SlowOperationThreshold. |
OperationFailed |
A SQLite operation failed. |
InterceptorFailed |
OnExecutedAsync or OnExceptionAsync threw. |
WriteAheadLoggingEnabled |
WAL was enabled. |
BusyTimeoutConfigured |
Busy timeout was configured. |
๐ก Tip
Keep application-level redaction enabled in your logging stack when logs may leave the device or workstation.
๐งฉ Interceptors
Implement ISQLiteInterceptor to observe operations:
public sealed class MetricsInterceptor : ISQLiteInterceptor
{
public ValueTask OnExecutingAsync(SQLiteOperationContext context)
=> ValueTask.CompletedTask;
public ValueTask OnExecutedAsync(SQLiteOperationContext context)
{
var duration = context.Duration;
return ValueTask.CompletedTask;
}
public ValueTask OnExceptionAsync(SQLiteOperationExceptionContext context)
{
var exception = context.OperationException;
return ValueTask.CompletedTask;
}
}
The operation context exposes a generated operation id, operation type, sanitized database identifier, table name, entity type, item count, start/completion timestamps, duration, exception, and sanitized metadata. It never exposes entity values or SQL parameters.
Interceptor failure behavior is deterministic:
| Callback | Failure behavior |
|---|---|
OnExecutingAsync |
Prevents the SQLite operation from running and propagates the interceptor exception. |
OnExecutedAsync |
Does not turn a successful SQLite operation into a failed operation; the interceptor failure is reported through ILogger. |
OnExceptionAsync |
Does not replace the original SQLite exception; interceptor failure is reported separately through ILogger. |
Callbacks are invoked in registration order and exactly once for the applicable phase.
๐งพ Operation Mapping
| Public operation | SQLiteOperationType |
|---|---|
| Constructor startup observation | Open |
CloseAsync, DisposeAsync |
Close |
EnsureTableExistsAsync<T>() |
CreateTable |
ResetTableAsync<T>() |
ResetTable |
Insert<T>(T), InsertAsync<T>(T), TableContext<T>.InsertAsync(T) |
Insert |
Insert<T>(List<T>), InsertAsync<T>(List<T>), TableContext<T>.InsertAsync(List<T>) |
BatchInsert |
Update<T>(T), UpdateAsync<T>(T), TableContext<T>.UpdateAsync(T) |
Update |
Update<T>(List<T>), UpdateAsync<T>(List<T>), TableContext<T>.UpdateAsync(List<T>) |
BatchUpdate |
Delete<T>(T), DeleteAsync<T>(T), TableContext<T>.DeleteAsync(T) |
Delete |
Delete<T>(List<T>), DeleteAsync<T>(List<T>), TableContext<T>.DeleteAsync(List<T>) |
BatchDelete |
TableContext<T>.DeleteAllAsync() |
DeleteAll |
For<T>().ToListAsync(), Table<T>().ToListAsync() |
Query |
For<T>().FirstOrDefaultAsync(), Table<T>().FirstOrDefaultAsync() |
FirstOrDefault |
Table<T>().CountAsync() |
Count |
| Internal transaction-backed batch execution | Surfaced as BatchInsert, BatchUpdate, or BatchDelete |
EnableWriteAheadLoggingAsync() |
EnableWriteAheadLogging |
SetBusyTimeoutAsync(TimeSpan) |
BusyTimeout |
๐งฐ SQLite Options
The manager exposes common SQLite connection settings:
await db.SetBusyTimeoutAsync(TimeSpan.FromSeconds(5));
await db.EnableWriteAheadLoggingAsync();
The same settings can be applied at creation time through SQLiteManagerOptions:
var db = SQLiteManagerService.GetInstance(new SQLiteManagerOptions
{
DatabasePath = "mydatabase.db",
EnableWriteAheadLogging = true,
BusyTimeout = TimeSpan.FromSeconds(5)
});
| Option | Purpose |
|---|---|
DatabasePath |
Database file path used to create or locate the manager. |
OpenFlags |
sqlite-net open flags used by the underlying connection. |
EnableWriteAheadLogging |
Enables WAL during manager startup. |
BusyTimeout |
Configures SQLite busy timeout during manager startup. |
StoreDateTimeAsTicks |
Controls sqlite-net date/time storage behavior. |
FullMutex |
Convenience flag for SQLiteOpenFlags.FullMutex. |
SharedCache |
Convenience flag for SQLiteOpenFlags.SharedCache. |
EnableObservability |
Enables routine structured operation logging. |
LogLevel |
Completion log level requested by the manager. |
SlowOperationThreshold |
Duration threshold for slow-operation warnings. |
Interceptors |
Ordered SQLite operation interceptors. |
๐งฑ Example Model
using SQLite;
public sealed class User
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string Name { get; set; } = "";
}
Custom sqlite-net mappings are honored:
[Table("app_users")]
public sealed class User
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string Name { get; set; } = "";
}
๐ ๏ธ Full Flow Example
var userDb = SQLiteManagerService.GetInstance("users.db");
var productDb = SQLiteManagerService.GetInstance("products.db");
await userDb.EnsureTableExistsAsync<User>();
await productDb.EnsureTableExistsAsync<Product>();
await productDb.ResetTableAsync<Product>();
await userDb.Insert(new User { Name = "Alice" });
await productDb.Insert(new Product { Name = "Laptop", Price = 1200 });
var moreUsers = new List<User>
{
new() { Name = "Bob" },
new() { Name = "Charlie" }
};
await userDb.Insert(moreUsers);
var users = await userDb.For<User>().ToListAsync();
Console.WriteLine($"Users count: {users.Count}");
var userAlice = await userDb.For<User>()
.Where(user => user.Name == "Alice")
.FirstOrDefaultAsync();
if (userAlice is not null)
{
userAlice.Name = "Alice Updated";
await userDb.Update(userAlice);
await userDb.Delete(userAlice);
}
var sortedProducts = await productDb.For<Product>()
.OrderByDescending(product => product.Price)
.ToListAsync();
foreach (var product in sortedProducts)
{
Console.WriteLine($"{product.Name} - {product.Price}");
}
โก Performance
Shaunebu.Data.SQLite keeps the wrapper thin and delegates database execution to sqlite-net-pcl. Benchmark coverage is maintained for release validation across common operations.
| Benchmark area | Covered |
|---|---|
| Single insert | Yes |
| Batch insert | Yes |
| Delete | Yes |
| Delete all | Yes |
| First-or-default | Yes |
| To-list query | Yes |
| Count | Yes |
| Create table | Yes |
| Reset table | Yes |
| WAL enablement | Yes |
| Batch-size comparison | Yes |
โน๏ธ Note
Benchmarks are intended to establish measurable baselines. They are not a substitute for testing your app's real database shape, device class, storage, and concurrency profile.
๐งช Console Client
The public samples include Shaunebu.Data.SQLite.Client, a net10.0 interactive console showcase for the current public API. It demonstrates manager CRUD, async aliases, batch operations, query builder, TableContext, connection options, dependency injection, lifecycle, WAL and busy timeout, interceptors, observability, Shaunebu.Common.Logging, concurrency, and expected failures.
| Mode | Command | Purpose |
|---|---|---|
| Interactive | dotnet run --project Shaunebu.Data.SQLite.Client/Shaunebu.Data.SQLite.Client.csproj -c Release |
Opens the menu-driven showcase. |
| Validation | dotnet run --project Shaunebu.Data.SQLite.Client/Shaunebu.Data.SQLite.Client.csproj -c Release -- --validate-all |
Runs the deterministic validation suite with concise output. |
| Scenario list | dotnet run --project Shaunebu.Data.SQLite.Client/Shaunebu.Data.SQLite.Client.csproj -c Release -- --list-scenarios |
Prints available scenario keys. |
| Single scenario | dotnet run --project Shaunebu.Data.SQLite.Client/Shaunebu.Data.SQLite.Client.csproj -c Release -- --scenario crud |
Runs one scenario by key. |
Interactive mode and single-scenario mode display SQLite log output where relevant. Validation mode intentionally suppresses live console logging so automated output remains concise.
The client stores demo databases under the current user's local application data folder and prints a sanitized database identifier by default. It is a manual showcase and release-validation helper, not a replacement for automated unit tests.
๐ Public Assets
The public GitHub presence for Shaunebu.Data.SQLite is documentation- and sample-focused. Applications consume the compiled library through NuGet.
| Asset | Purpose |
|---|---|
| README | Primary NuGet and GitHub usage guide. |
| Console Client / Samples | Interactive examples and validation scenarios for the public API. |
| Documentation | Feature guidance, lifecycle notes, observability guidance, and release-readiness notes. |
| NuGet package | Compiled commercial library package for application consumption. |
๐ References
- Shaunebu.Data.SQLite on NuGet
- Shaunebu.Data.SQLite documentation and samples
- sqlite-net-pcl
- .NET MAUI SQLite guidance
๐ License
Shaunebu.Data.SQLite is a closed-source commercial library distributed through NuGet. Review the license terms provided with the NuGet package or your commercial agreement.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.10)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.10)
- SourceGear.sqlite3 (>= 3.53.4)
- sqlite-net-pcl (>= 1.11.285)
- SQLitePCLRaw.core (>= 3.0.5)
- SQLitePCLRaw.provider.e_sqlite3 (>= 3.0.5)
-
net9.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.10)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.10)
- SourceGear.sqlite3 (>= 3.53.4)
- sqlite-net-pcl (>= 1.11.285)
- SQLitePCLRaw.core (>= 3.0.5)
- SQLitePCLRaw.provider.e_sqlite3 (>= 3.0.5)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Add observability, structured operation logging, SQLite operation interceptors, and built-in dependency injection extensions while preserving existing APIs.