Skip to content

Commit b58d28f

Browse files
Add dart_node_sql_js as a publishable package (sql.js bindings)
Promote dart_node_sql_js from a publish_to:none stub to a full tier-2 publishable package for the 0.13.0-beta release. - Rewrite database/statement interop with typed extension types (no nullable casts), passing austerity analyze. - Fix a correctness bug: sql.js export() frees all live prepared statements, so the old auto-save-after-every-write broke statement reuse and transactions. Persist on close()/save() instead and add an explicit save() to the Database API. - Add 32 integration tests (100% line coverage), README, CHANGELOG, LICENSE, analysis_options, dart_test.yaml, package.json. - Wire into tooling: tools/lib/packages.dart (tier 2, node), test.sh (NODE_PACKAGES + TIER2), coverage-thresholds.json (100.0), publish-tier1 changelog validation, publish-tier2 publish list, release skill.
1 parent ea21c4d commit b58d28f

18 files changed

Lines changed: 869 additions & 149 deletions

.claude/skills/release/SKILL.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ Every publishable package must have a `## $ARGUMENTS` entry in its CHANGELOG.md.
8585
| 2 | dart_node_express |
8686
| 2 | dart_node_ws |
8787
| 2 | dart_node_better_sqlite3 |
88+
| 2 | dart_node_sql_js |
8889
| 2 | dart_node_mcp |
8990
| 3 | dart_node_react |
9091
| 3 | dart_node_react_native |
@@ -93,7 +94,7 @@ Check each changelog:
9394

9495
```bash
9596
VERSION="$ARGUMENTS"
96-
for pkg in dart_logging dart_node_core reflux dart_node_express dart_node_ws dart_node_better_sqlite3 dart_node_mcp dart_node_react dart_node_react_native; do
97+
for pkg in dart_logging dart_node_core reflux dart_node_express dart_node_ws dart_node_better_sqlite3 dart_node_sql_js dart_node_mcp dart_node_react dart_node_react_native; do
9798
if grep -q "^## $VERSION" "packages/$pkg/CHANGELOG.md" 2>/dev/null; then
9899
echo "$pkg"
99100
else
@@ -109,7 +110,7 @@ If any are missing, **stop and update the changelogs** before proceeding.
109110
Each package should have a README.md. Quick sanity check:
110111

111112
```bash
112-
for pkg in dart_logging dart_node_core reflux dart_node_express dart_node_ws dart_node_better_sqlite3 dart_node_mcp dart_node_react dart_node_react_native; do
113+
for pkg in dart_logging dart_node_core reflux dart_node_express dart_node_ws dart_node_better_sqlite3 dart_node_sql_js dart_node_mcp dart_node_react dart_node_react_native; do
113114
if [[ -f "packages/$pkg/README.md" ]]; then
114115
LINES=$(wc -l < "packages/$pkg/README.md")
115116
echo "$pkg - $LINES lines"
@@ -124,7 +125,7 @@ done
124125
Verify which versions are currently published:
125126

126127
```bash
127-
for pkg in dart_logging dart_node_core reflux dart_node_express dart_node_ws dart_node_better_sqlite3 dart_node_mcp dart_node_react dart_node_react_native; do
128+
for pkg in dart_logging dart_node_core reflux dart_node_express dart_node_ws dart_node_better_sqlite3 dart_node_sql_js dart_node_mcp dart_node_react dart_node_react_native; do
128129
LATEST=$(curl -s "https://pub.dev/api/packages/$pkg" | grep -o '"version":"[^"]*"' | head -1 | cut -d'"' -f4)
129130
echo "$pkg: $LATEST"
130131
done
@@ -185,7 +186,7 @@ git tag "Release-Tier2/$ARGUMENTS"
185186
git push origin "Release-Tier2/$ARGUMENTS"
186187
```
187188

188-
Publishes: reflux, dart_node_express, dart_node_ws, dart_node_better_sqlite3, dart_node_mcp
189+
Publishes: reflux, dart_node_express, dart_node_ws, dart_node_better_sqlite3, dart_node_sql_js, dart_node_mcp
189190

190191
## Step 10: Tier 3 publishing
191192

@@ -214,7 +215,7 @@ After release, verify all packages are available:
214215

215216
```bash
216217
VERSION="$ARGUMENTS"
217-
for pkg in dart_logging dart_node_core reflux dart_node_express dart_node_ws dart_node_better_sqlite3 dart_node_mcp dart_node_react dart_node_react_native; do
218+
for pkg in dart_logging dart_node_core reflux dart_node_express dart_node_ws dart_node_better_sqlite3 dart_node_sql_js dart_node_mcp dart_node_react dart_node_react_native; do
218219
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "https://pub.dev/api/packages/$pkg/versions/$VERSION")
219220
if [[ "$HTTP_CODE" == "200" ]]; then
220221
echo "$pkg@$VERSION published"

.github/workflows/publish-tier1.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ jobs:
5959
"dart_node_express"
6060
"dart_node_ws"
6161
"dart_node_better_sqlite3"
62+
"dart_node_sql_js"
6263
"dart_node_mcp"
6364
"dart_node_react"
6465
"dart_node_react_native"

.github/workflows/publish-tier2.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,4 @@ jobs:
3535
- name: Publish packages
3636
run: |
3737
chmod +x .github/scripts/publish-packages.sh
38-
.github/scripts/publish-packages.sh "${{ steps.version.outputs.VERSION }}" reflux dart_node_express dart_node_ws dart_node_better_sqlite3 dart_node_mcp
38+
.github/scripts/publish-packages.sh "${{ steps.version.outputs.VERSION }}" reflux dart_node_express dart_node_ws dart_node_better_sqlite3 dart_node_sql_js dart_node_mcp

coverage-thresholds.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"dart_node_express": 100.0,
1010
"dart_node_ws": 100.0,
1111
"dart_node_better_sqlite3": 100.0,
12+
"dart_node_sql_js": 100.0,
1213
"dart_node_mcp": 100.0,
1314
"dart_node_react_native": 100.0,
1415
"dart_jsx": 82.5,
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Changelog
2+
3+
## 0.13.0-beta
4+
5+
- Initial beta release
6+
- Typed Dart bindings for sql.js (SQLite compiled to WebAssembly)
7+
- Synchronous in-memory SQLite with file persistence on Node.js
8+
- `Result`-based API: open, prepare, exec, run, get, all, pragma

packages/dart_node_sql_js/LICENSE

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
BSD 3-Clause License
2+
3+
Copyright (c) 2025, Christian Findlay
4+
5+
Redistribution and use in source and binary forms, with or without
6+
modification, are permitted provided that the following conditions are met:
7+
8+
1. Redistributions of source code must retain the above copyright notice, this
9+
list of conditions and the following disclaimer.
10+
11+
2. Redistributions in binary form must reproduce the above copyright notice,
12+
this list of conditions and the following disclaimer in the documentation
13+
and/or other materials provided with the distribution.
14+
15+
3. Neither the name of the copyright holder nor the names of its
16+
contributors may be used to endorse or promote products derived from
17+
this software without specific prior written permission.
18+
19+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
Typed Dart bindings for [sql.js](https://github.com/sql-js/sql.js) — SQLite
2+
compiled to WebAssembly. Provides synchronous, in-memory SQLite for Node.js
3+
applications, with explicit persistence to disk.
4+
5+
Unlike native bindings, sql.js needs no compilation and runs the same
6+
everywhere WebAssembly does. The database lives in memory; you persist it to a
7+
file with `save` or `close`.
8+
9+
## Installation
10+
11+
```yaml
12+
dependencies:
13+
dart_node_sql_js: ^0.13.0-beta
14+
nadz: ^0.0.7-beta
15+
```
16+
17+
Also install the npm package:
18+
19+
```bash
20+
npm install sql.js
21+
```
22+
23+
## Quick Start
24+
25+
```dart
26+
import 'package:dart_node_sql_js/dart_node_sql_js.dart';
27+
import 'package:nadz/nadz.dart';
28+
29+
Future<void> main() async {
30+
// Initialize the WebAssembly runtime once at startup.
31+
final runtime = switch (await initializeSqlJs()) {
32+
Success(:final value) => value,
33+
Error(:final error) => throw Exception(error),
34+
};
35+
36+
// Opens ./my.db if it exists, otherwise creates a new database.
37+
final db = switch (openDatabase('./my.db', sqlJs: runtime)) {
38+
Success(:final value) => value,
39+
Error(:final error) => throw Exception(error),
40+
};
41+
42+
db.exec('CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)');
43+
44+
final insert = switch (db.prepare('INSERT INTO users (name) VALUES (?)')) {
45+
Success(:final value) => value,
46+
Error(:final error) => throw Exception(error),
47+
};
48+
insert.run(['Alice']);
49+
50+
final query = switch (db.prepare('SELECT * FROM users')) {
51+
Success(:final value) => value,
52+
Error(:final error) => throw Exception(error),
53+
};
54+
final rows = switch (query.all()) {
55+
Success(:final value) => value,
56+
Error(:final error) => throw Exception(error),
57+
};
58+
print(rows); // [{id: 1, name: Alice}]
59+
60+
// Persist the in-memory database to ./my.db.
61+
db.close();
62+
}
63+
```
64+
65+
## Persistence
66+
67+
sql.js is entirely in-memory. The only way to serialize it (`export()`) frees
68+
every live prepared statement, so this binding does **not** write to disk after
69+
each statement. Instead:
70+
71+
- `db.save()` flushes the current state to the backing file on demand.
72+
- `db.close()` saves and then releases the database.
73+
74+
Reopening the same path loads the persisted bytes.
75+
76+
## API
77+
78+
`initializeSqlJs()` returns a `Future<Result<SqlJsRuntime, String>>`. Pass the
79+
runtime to every `openDatabase` call.
80+
81+
`openDatabase(path, sqlJs: runtime)` returns a `Result<Database, String>` with:
82+
83+
| Member | Description |
84+
|--------|-------------|
85+
| `prepare(sql)` | Prepare a reusable statement. |
86+
| `exec(sql)` | Run one or more statements, ignoring results. |
87+
| `pragma(value)` | Run a `PRAGMA`. |
88+
| `save()` | Persist the in-memory database to its file. |
89+
| `close()` | Persist, then close. |
90+
| `isOpen()` | Whether the database is still open. |
91+
92+
A prepared `Statement` exposes:
93+
94+
| Member | Description |
95+
|--------|-------------|
96+
| `all([params])` | All rows as a list of column-keyed maps. |
97+
| `get([params])` | The first row, or null. |
98+
| `run([params])` | Execute, returning `changes` and `lastInsertRowid`. |
99+
100+
Every operation returns a `Result` (from [nadz](https://pub.dev/packages/nadz))
101+
instead of throwing.
102+
103+
## License
104+
105+
BSD 3-Clause. See [LICENSE](LICENSE).
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
include: package:austerity/analysis_options.yaml
2+
3+
analyzer:
4+
errors:
5+
avoid_catches_without_on_clauses: ignore
6+
require_trailing_commas: ignore
7+
public_member_api_docs: error
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
platforms: [node]

packages/dart_node_sql_js/lib/dart_node_sql_js.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/// Typed Dart bindings for sql.js (SQLite compiled to WebAssembly).
22
///
33
/// Provides synchronous SQLite3 access via WebAssembly.
4-
/// Call [initializeSqlJs] once at startup, then use [openDatabase].
4+
/// Call `initializeSqlJs` once at startup, then use `openDatabase`.
55
library;
66

77
export 'src/database.dart';

0 commit comments

Comments
 (0)