Skip to content

Commit fbe69d1

Browse files
committed
feat(sync): sync upstream to Node.js v25.8.1 / SQLite 3.52.0
Add db.limits property for runtime get/set of SQLite limits, with constructor option support. Implement iterator invalidation via generation counter. run/get/all/iterate now throw ERR_INVALID_STATE on previously-active iterators. Update docs to reflect node:sqlite RC status (Stability 1.2 since v25.7.0): rewrite library-comparison.md, migrating-from-node-sqlite.md, and README to remove "experimental" language and add version matrix. Update deps: node-addon-api 8.6.0, eslint-plugin-security 4.0, typescript-eslint 8.56.1. Rename sqlite-vec dep to @photostructure scope.
1 parent ee6c287 commit fbe69d1

29 files changed

+7125
-4198
lines changed

.claude/settings.local.json

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,18 @@
6868
"WebFetch(domain:sqlite.org)",
6969
"WebFetch(domain:stackoverflow.com)",
7070
"WebFetch(domain:www.sqlite.org)",
71-
"WebFetch(domain:docs.anthropic.com)"
71+
"WebFetch(domain:docs.anthropic.com)",
72+
"WebFetch(domain:eslint.org)",
73+
"Bash(git -C /home/mrm/src/node log v25.6.1..HEAD --oneline -- lib/sqlite.js src/node_sqlite.cc src/node_sqlite.h deps/sqlite)",
74+
"Bash(git -C /home/mrm/src/node log -1 --oneline)",
75+
"Bash(git -C /home/mrm/src/node describe --tags --abbrev=0)",
76+
"Bash(git -C /home/mrm/src/node log v25.6.1..HEAD --oneline -- test/parallel/test-sqlite*)",
77+
"Bash(git -C /home/mrm/src/node log v25.6.1..HEAD -p -- lib/sqlite.js src/node_sqlite.cc src/node_sqlite.h)",
78+
"Bash(git -C /home/mrm/src/node log v25.6.1..HEAD -p -- test/parallel/test-sqlite*)",
79+
"Bash(git -C /home/mrm/src/node log v25.6.1..HEAD -p -- deps/sqlite)",
80+
"WebFetch(domain:photostructure.com)",
81+
"Bash(git -C /home/mrm/src/node log origin/v25.x-staging --oneline -20 -- src/node_sqlite.cc src/node_sqlite.h)",
82+
"Bash(npm pack --dry-run)"
7283
],
7384
"additionalDirectories": [
7485
"/home/mrm/src/node-addon-examples",

CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,21 @@
22

33
All notable changes to this project will be documented in this file.
44

5+
## [1.0.0] (2026-03-07)
6+
7+
Promotion to v1.0.0 following API stabilization and 0.5.0 release.
8+
9+
API compatible with `node:sqlite` from Node.js v25.8.1.
10+
11+
### Added
12+
13+
- **`db.limits` property**: Get and set SQLite limits (length, sqlLength, column, exprDepth, compoundSelect, vdbeOp, functionArg, attach, likePatternLength, variableNumber, triggerDepth) at runtime. Supports `Infinity` to reset to compile-time maximum. Also accepts `limits` option in `DatabaseSync` constructor.
14+
- **Statement iterator invalidation**: Calling `stmt.run()`, `stmt.get()`, `stmt.all()`, or `stmt.iterate()` now invalidates any active iterator on the same statement, throwing `ERR_INVALID_STATE`
15+
16+
### Changed
17+
18+
- **SQLite 3.52.0**: Updated from 3.51.2
19+
520
## [0.5.0] (2026-02-06)
621

722
### Added
@@ -130,6 +145,7 @@ API compatible with `node:sqlite` from Node.js v25.6.1.
130145
- macOS (x64, ARM64)
131146
- Linux (x64, ARM64), (glibc 2.28+, musl)
132147

148+
[1.0.0]: https://github.com/PhotoStructure/node-sqlite/releases/tag/v1.0.0
133149
[0.5.0]: https://github.com/PhotoStructure/node-sqlite/releases/tag/v0.5.0
134150
[0.4.0]: https://github.com/PhotoStructure/node-sqlite/releases/tag/v0.4.0
135151
[0.3.0]: https://github.com/PhotoStructure/node-sqlite/releases/tag/v0.3.0

CLAUDE.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
44

55
## Project Overview
66

7-
This is @photostructure/sqlite - a standalone npm package that extracts the experimental SQLite implementation from Node.js core. The goal is to make Node.js's native SQLite functionality available to all Node.js versions, not just those with the experimental flag enabled.
7+
This is @photostructure/sqlite - a standalone npm package that extracts the Node.js SQLite implementation from Node.js core. The goal is to make Node.js's native SQLite functionality available to all Node.js versions (20+), not just those supporting the built-in `node:sqlite` module (22.5.0+).
8+
9+
Note: `node:sqlite` was promoted to Release Candidate (Stability: 1.2) in Node.js v25.7.0. The `--experimental-sqlite` flag was required on 22.5.0–22.12.x; since 22.13.0 it works without a flag (but prints an ExperimentalWarning until v25.7.0).
810

911
### Key Features
1012

@@ -240,7 +242,7 @@ This approach reduces test brittleness while ensuring error handling works corre
240242

241243
### Upstream Synchronization
242244

243-
- Node.js SQLite is experimental and may change frequently
245+
- Node.js SQLite is Release Candidate (Stability: 1.2) since v25.7.0 — API is stable but minor changes remain possible
244246
- `sync-from-node.js` script maintains file synchronization
245247
- Changes should be reviewed for compatibility impact
246248
- Version tracking needed to correlate with Node.js releases
@@ -294,6 +296,7 @@ This approach reduces test brittleness while ensuring error handling works corre
294296
- **Run `npm run lint`** to check code quality
295297
- **Native rebuilds** use `npm run build:native:rebuild`
296298
- **Multi-platform prebuilds** are generated via GitHub Actions
299+
- **`package.json` version** is managed by the release GitHub Action — do not bump it manually
297300

298301
### Git Commit Messages
299302

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
[![npm version](https://img.shields.io/npm/v/@photostructure/sqlite.svg)](https://www.npmjs.com/package/@photostructure/sqlite)
66
[![CI](https://github.com/photostructure/node-sqlite/actions/workflows/build.yml/badge.svg)](https://github.com/photostructure/node-sqlite/actions/workflows/build.yml)
77

8-
Native SQLite for Node.js 20+ without the experimental flag. Drop-in replacement for `node:sqlite`. Synced with Node.js v25.6.2 for the latest features including native `Symbol.dispose` resource management.
8+
Native SQLite for Node.js 20+. Drop-in replacement for `node:sqlite`. Synced with Node.js v25.8.1 for the latest features including native `Symbol.dispose` resource management.
99

1010
## Installation
1111

@@ -29,7 +29,7 @@ db.close();
2929

3030
## Features
3131

32-
- 100% compatible with Node.js v25.6.2 built-in `node:sqlite` module\*
32+
- 100% compatible with Node.js v25.8.1 built-in `node:sqlite` module\*
3333
- Zero dependencies - native SQLite implementation
3434
- Synchronous API - no async overhead
3535
- Performance comparable to better-sqlite3
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# TPP: Sync upstream Node.js SQLite changes (v25.6.1 → v25.8.1)
2+
3+
## ✅ COMPLETED
4+
5+
## Goal Definition
6+
7+
- **What Success Looks Like**: Two upstream features are ported and all tests pass: (1) statement iterator invalidation, (2) DatabaseSync `limits` property
8+
- **Core Problem**: The project's native implementation was missing two features from v25.x-staging. SQLTagStore was already implemented in TypeScript
9+
- **Key Constraints**: API compatibility with `node:sqlite` is non-negotiable. Never modify `src/upstream/*` manually — use the sync script
10+
- **Success Validation**: `npm test` (839 pass), `npm run test:node` (295 pass), `npm run lint` (clean)
11+
12+
## Changes Made
13+
14+
### 1. Statement iterator invalidation
15+
16+
Added `reset_generation_` counter to `StatementSync` that increments on every statement reset. `StatementSyncIterator` captures the generation at creation and checks it in `Next()` — throws `ERR_INVALID_STATE` if the statement was reset by another call (run/get/all/iterate).
17+
18+
**Files**: `src/sqlite_impl.h`, `src/sqlite_impl.cpp`
19+
20+
Key details:
21+
22+
- `ResetStatement()` replaces direct `sqlite3_reset()` calls in Run/Get/All/Iterate/Reset
23+
- Iterator's own `sqlite3_reset(stmt_->statement_)` calls (in Next/Return/ToArray for end-of-iteration) are NOT changed — they bypass `ResetStatement()` intentionally
24+
- Generation is captured in `SetStatement()`, checked in `Next()`
25+
26+
### 2. DatabaseSync `limits` property
27+
28+
Added `getLimit(id)` and `setLimit(id, value)` native methods. TypeScript layer creates a lazily-cached object with `Object.defineProperty` getters/setters for all 11 SQLite limits.
29+
30+
**Files**: `src/sqlite_impl.h`, `src/sqlite_impl.cpp`, `src/index.ts`, `src/types/database-sync-instance.ts`, `src/types/database-sync-options.ts`
31+
32+
Key details:
33+
34+
- Constructor parses `options.limits` (integer-only, no Infinity, non-negative)
35+
- Runtime setter accepts `Infinity` to reset to compile-time max (`INT_MAX`)
36+
- `Object.keys(db.limits)` returns all 11 property names
37+
- Throws `ERR_INVALID_STATE` when database is closed (handled by native `getLimit`/`setLimit`)
38+
- Used `defineProperty` over `Proxy` — simpler, zero overhead, 11 fixed properties
39+
40+
### 3. Upstream files
41+
42+
Already synced via `npm run sync:node` — matches v25.x-staging (v25.8.1). Iterator invalidation hasn't landed on v25.x-staging yet, so we're ahead of upstream on that feature.
43+
44+
### 4. Test updates
45+
46+
- `test/invalid-operations.test.ts`: Updated iterator tests to match new invalidation behavior
47+
- All node-compat test files were already pre-written
48+
49+
## Validation Results
50+
51+
```bash
52+
$ npm test
53+
# 55 suites pass, 839 tests pass, 44 skipped
54+
55+
$ npm run test:node
56+
# 295 pass, 0 fail, 4 skipped
57+
58+
$ npm run lint
59+
# clean (0 errors)
60+
```
61+
62+
## Tribal Knowledge
63+
64+
### N-API has no NamedPropertyHandlerConfiguration
65+
66+
V8's `NamedPropertyHandlerConfiguration` (used by upstream for limits) intercepts arbitrary named property access. N-API deliberately omits this. We use `Object.defineProperty` getters/setters in TypeScript instead.
67+
68+
### SQLTagStore pattern: TypeScript over C++
69+
70+
Both SQLTagStore and limits use the same pattern: minimal native primitives (`getLimit`/`setLimit`, `prepare`/`run`/`get`/`all`) with TypeScript orchestration on top. This avoids complex V8-specific C++ (NamedPropertyHandlerConfiguration, DictionaryTemplate, etc.) while maintaining API compatibility.
71+
72+
### Iterator reset*generation* scope
73+
74+
Only `StatementSync::ResetStatement()` increments the generation counter. The iterator's own `sqlite3_reset()` calls for end-of-iteration cleanup do NOT go through `ResetStatement()`. This prevents self-invalidation when iteration completes naturally.

doc/features.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Features and capabilities in @photostructure/sqlite.
1414

1515
## SQLite version
1616

17-
This package includes SQLite 3.51.1 with extensive compile-time options enabled. For complete build flag documentation, comparison with Node.js, and customization options, see [Build Flags & Configuration](./build-flags.md).
17+
This package includes SQLite 3.52.0 with extensive compile-time options enabled. For complete build flag documentation, comparison with Node.js, and customization options, see [Build Flags & Configuration](./build-flags.md).
1818

1919
## Enabled SQLite features
2020

doc/internal/architecture.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ void QueueWork(std::function<void()> work) {
149149

150150
1. **Complete Rewrite**: Would lose compatibility and require extensive testing
151151
2. **Fork Node.js**: Would require users to use custom Node.js build
152-
3. **Wait for Public API**: Node.js SQLite is still experimental
152+
3. **Wait for Public API**: Node.js SQLite was experimental at the time; it reached Release Candidate (Stability: 1.2) in v25.7.0
153153

154154
## Conclusion
155155

0 commit comments

Comments
 (0)