@photostructure/sqlite 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -10
- package/README.md +3 -0
- package/SECURITY.md +1 -0
- package/package.json +1 -1
- package/prebuilds/darwin-arm64/@photostructure+sqlite.glibc.node +0 -0
- package/prebuilds/darwin-x64/@photostructure+sqlite.glibc.node +0 -0
- package/prebuilds/linux-arm64/@photostructure+sqlite.glibc.node +0 -0
- package/prebuilds/linux-arm64/@photostructure+sqlite.musl.node +0 -0
- package/prebuilds/linux-x64/@photostructure+sqlite.glibc.node +0 -0
- package/prebuilds/linux-x64/@photostructure+sqlite.musl.node +0 -0
- package/prebuilds/test_extension.so +0 -0
- package/prebuilds/win32-arm64/@photostructure+sqlite.glibc.node +0 -0
- package/prebuilds/win32-x64/@photostructure+sqlite.glibc.node +0 -0
- package/src/shims/node_errors.h +3 -1
- package/src/shims/sqlite_errors.h +9 -3
- package/src/sqlite_impl.cpp +32 -9
package/CHANGELOG.md
CHANGED
|
@@ -2,28 +2,30 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
-
## [0.2.
|
|
5
|
+
## [0.2.1] (2025-12-01)
|
|
6
6
|
|
|
7
7
|
### Added
|
|
8
8
|
|
|
9
|
-
-
|
|
9
|
+
- Windows ARM64 prebuilt binaries
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
### Fixed
|
|
12
12
|
|
|
13
|
-
-
|
|
13
|
+
- Error message handling on Windows ARM64 (ABI compatibility)
|
|
14
|
+
- Error handling consistency across platforms
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
## [0.2.0] (2025-12-01)
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
### Added
|
|
18
19
|
|
|
20
|
+
- **Node.js v25 API sync**: SQLite 3.51.1, native `Symbol.dispose` in C++, Session class exposed in public API
|
|
21
|
+
- **New database open options**: `readBigInts`, `returnArrays`, `allowBareNamedParameters`, `allowUnknownNamedParameters`, `defensive`, `open`
|
|
22
|
+
- **Defensive mode**: `enableDefensive()` method to prevent SQL from deliberately corrupting the database
|
|
23
|
+
- **Statement enhancements**: `setAllowUnknownNamedParameters()` method, `finalized` property
|
|
24
|
+
- **Type identification**: `sqlite-type` symbol property on DatabaseSync (Node.js PR #59405)
|
|
19
25
|
- **Enhanced SQLite errors**: New properties `sqliteCode`, `sqliteExtendedCode`, `code`, `sqliteErrorString`, `systemErrno`
|
|
20
|
-
|
|
21
26
|
- **ARM64 prebuilds**: macOS Apple Silicon and Windows ARM64 binaries
|
|
22
|
-
|
|
23
27
|
- **Tagged template literals**: `db.createTagStore()` for cached prepared statements (Node.js PR #58748)
|
|
24
|
-
|
|
25
28
|
- **Authorization API**: `db.setAuthorizer()` for security callbacks (Node.js PR #59928)
|
|
26
|
-
|
|
27
29
|
- **Standalone backup**: `backup(srcDb, destFile, options?)` for one-liner database backups with progress callbacks
|
|
28
30
|
|
|
29
31
|
### Fixed
|
package/README.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# @photostructure/sqlite
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@photostructure/sqlite)
|
|
4
|
+
[](https://github.com/photostructure/node-sqlite/actions/workflows/build.yml)
|
|
5
|
+
|
|
3
6
|
Native SQLite for Node.js 20+ without the experimental flag. Drop-in replacement for `node:sqlite`. Updated to Node.js v25 for latest features and native Symbol.dispose resource management.
|
|
4
7
|
|
|
5
8
|
## Installation
|
package/SECURITY.md
CHANGED
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/src/shims/node_errors.h
CHANGED
|
@@ -34,7 +34,9 @@ inline void THROW_ERR_INVALID_ARG_VALUE(Napi::Env env,
|
|
|
34
34
|
|
|
35
35
|
inline void THROW_ERR_SQLITE_ERROR(Napi::Env env,
|
|
36
36
|
const char *message = nullptr) {
|
|
37
|
-
|
|
37
|
+
// Check for both null and empty string - on Windows (MSVC),
|
|
38
|
+
// std::exception::what() can sometimes return an empty string
|
|
39
|
+
const char *msg = (message && message[0] != '\0') ? message : "SQLite error";
|
|
38
40
|
Napi::Error::New(env, msg).ThrowAsJavaScriptException();
|
|
39
41
|
}
|
|
40
42
|
|
|
@@ -84,7 +84,10 @@ inline const char *GetSqliteErrorCodeName(int code) {
|
|
|
84
84
|
inline void ThrowEnhancedSqliteError(Napi::Env env, sqlite3 *db,
|
|
85
85
|
int sqlite_code,
|
|
86
86
|
const std::string &message) {
|
|
87
|
-
|
|
87
|
+
// Use c_str() explicitly to avoid potential ABI issues on Windows ARM
|
|
88
|
+
// where passing std::string directly to Napi::Error::New can result in
|
|
89
|
+
// truncated or corrupted error messages
|
|
90
|
+
Napi::Error error = Napi::Error::New(env, message.c_str());
|
|
88
91
|
|
|
89
92
|
// Add SQLite error code information
|
|
90
93
|
error.Set("sqliteCode", Napi::Number::New(env, sqlite_code));
|
|
@@ -127,7 +130,8 @@ inline void ThrowSqliteError(Napi::Env env, sqlite3 *db,
|
|
|
127
130
|
ThrowEnhancedSqliteError(env, db, errcode, message);
|
|
128
131
|
} else {
|
|
129
132
|
// Fallback to simple error when no db handle available
|
|
130
|
-
|
|
133
|
+
// Use c_str() explicitly to avoid potential ABI issues on Windows ARM
|
|
134
|
+
Napi::Error::New(env, message.c_str()).ThrowAsJavaScriptException();
|
|
131
135
|
}
|
|
132
136
|
}
|
|
133
137
|
|
|
@@ -150,8 +154,10 @@ ThrowFromSqliteException(Napi::Env env,
|
|
|
150
154
|
error.Set("code", Napi::String::New(env, code_name));
|
|
151
155
|
|
|
152
156
|
// Also set the human-readable error string
|
|
157
|
+
// Use c_str() explicitly to avoid potential ABI issues on Windows ARM
|
|
153
158
|
if (!ex.error_string().empty()) {
|
|
154
|
-
error.Set("sqliteErrorString",
|
|
159
|
+
error.Set("sqliteErrorString",
|
|
160
|
+
Napi::String::New(env, ex.error_string().c_str()));
|
|
155
161
|
}
|
|
156
162
|
|
|
157
163
|
error.ThrowAsJavaScriptException();
|
package/src/sqlite_impl.cpp
CHANGED
|
@@ -22,7 +22,8 @@ inline void ThrowErrSqliteErrorWithDb(Napi::Env env,
|
|
|
22
22
|
if (db->HasDeferredAuthorizerException()) {
|
|
23
23
|
std::string deferred_msg = db->GetDeferredAuthorizerException();
|
|
24
24
|
db->ClearDeferredAuthorizerException();
|
|
25
|
-
|
|
25
|
+
// Use c_str() explicitly to avoid potential ABI issues on Windows ARM
|
|
26
|
+
Napi::Error::New(env, deferred_msg.c_str()).ThrowAsJavaScriptException();
|
|
26
27
|
}
|
|
27
28
|
return; // Don't throw SQLite error, JavaScript exception takes precedence
|
|
28
29
|
}
|
|
@@ -42,7 +43,8 @@ inline void ThrowEnhancedSqliteErrorWithDB(
|
|
|
42
43
|
if (db_sync->HasDeferredAuthorizerException()) {
|
|
43
44
|
std::string deferred_msg = db_sync->GetDeferredAuthorizerException();
|
|
44
45
|
db_sync->ClearDeferredAuthorizerException();
|
|
45
|
-
|
|
46
|
+
// Use c_str() explicitly to avoid potential ABI issues on Windows ARM
|
|
47
|
+
Napi::Error::New(env, deferred_msg.c_str()).ThrowAsJavaScriptException();
|
|
46
48
|
}
|
|
47
49
|
return; // Don't throw SQLite error, JavaScript exception takes precedence
|
|
48
50
|
}
|
|
@@ -576,6 +578,19 @@ Napi::Value DatabaseSync::Prepare(const Napi::CallbackInfo &info) {
|
|
|
576
578
|
stmt->InitStatement(this, sql);
|
|
577
579
|
|
|
578
580
|
return stmt_obj;
|
|
581
|
+
} catch (const SqliteException &e) {
|
|
582
|
+
// SqliteException stores message in std::string, avoiding Windows ARM ABI
|
|
583
|
+
// issues where std::exception::what() can return corrupted strings
|
|
584
|
+
if (HasDeferredAuthorizerException()) {
|
|
585
|
+
std::string deferred_msg = GetDeferredAuthorizerException();
|
|
586
|
+
ClearDeferredAuthorizerException();
|
|
587
|
+
SetIgnoreNextSQLiteError(false);
|
|
588
|
+
// Use c_str() explicitly to avoid potential ABI issues on Windows ARM
|
|
589
|
+
Napi::Error::New(env, deferred_msg.c_str()).ThrowAsJavaScriptException();
|
|
590
|
+
return env.Undefined();
|
|
591
|
+
}
|
|
592
|
+
node::ThrowFromSqliteException(env, e);
|
|
593
|
+
return env.Undefined();
|
|
579
594
|
} catch (const std::exception &e) {
|
|
580
595
|
// Handle deferred authorizer exceptions:
|
|
581
596
|
//
|
|
@@ -586,14 +601,17 @@ Napi::Value DatabaseSync::Prepare(const Napi::CallbackInfo &info) {
|
|
|
586
601
|
// empty string, causing message loss.
|
|
587
602
|
//
|
|
588
603
|
// 2. By storing the message in the DatabaseSync instance, we can retrieve
|
|
589
|
-
// it here and throw a proper JavaScript exception with the original
|
|
604
|
+
// it here and throw a proper JavaScript exception with the original
|
|
605
|
+
// text.
|
|
590
606
|
//
|
|
591
|
-
// See also: StatementSync::InitStatement for the other half of this
|
|
607
|
+
// See also: StatementSync::InitStatement for the other half of this
|
|
608
|
+
// pattern.
|
|
592
609
|
if (HasDeferredAuthorizerException()) {
|
|
593
610
|
std::string deferred_msg = GetDeferredAuthorizerException();
|
|
594
611
|
ClearDeferredAuthorizerException();
|
|
595
612
|
SetIgnoreNextSQLiteError(false);
|
|
596
|
-
|
|
613
|
+
// Use c_str() explicitly to avoid potential ABI issues on Windows ARM
|
|
614
|
+
Napi::Error::New(env, deferred_msg.c_str()).ThrowAsJavaScriptException();
|
|
597
615
|
return env.Undefined();
|
|
598
616
|
}
|
|
599
617
|
node::THROW_ERR_SQLITE_ERROR(env, e.what());
|
|
@@ -636,7 +654,8 @@ Napi::Value DatabaseSync::Exec(const Napi::CallbackInfo &info) {
|
|
|
636
654
|
std::string deferred_msg = GetDeferredAuthorizerException();
|
|
637
655
|
ClearDeferredAuthorizerException();
|
|
638
656
|
SetIgnoreNextSQLiteError(false);
|
|
639
|
-
|
|
657
|
+
// Use c_str() explicitly to avoid potential ABI issues on Windows ARM
|
|
658
|
+
Napi::Error::New(env, deferred_msg.c_str()).ThrowAsJavaScriptException();
|
|
640
659
|
return env.Undefined();
|
|
641
660
|
}
|
|
642
661
|
std::string error = error_msg ? error_msg : "Unknown SQLite error";
|
|
@@ -1495,7 +1514,8 @@ void StatementSync::InitStatement(DatabaseSync *database,
|
|
|
1495
1514
|
// empty string, causing message loss.
|
|
1496
1515
|
//
|
|
1497
1516
|
// 2. By storing the message in the DatabaseSync instance, the caller can
|
|
1498
|
-
// retrieve it and throw a proper JavaScript exception with the original
|
|
1517
|
+
// retrieve it and throw a proper JavaScript exception with the original
|
|
1518
|
+
// text.
|
|
1499
1519
|
//
|
|
1500
1520
|
// 3. This matches Node.js's behavior where JavaScript exceptions from
|
|
1501
1521
|
// authorizer callbacks propagate correctly to the caller.
|
|
@@ -1504,8 +1524,11 @@ void StatementSync::InitStatement(DatabaseSync *database,
|
|
|
1504
1524
|
// object and will be retrieved by the caller.
|
|
1505
1525
|
throw std::runtime_error("");
|
|
1506
1526
|
}
|
|
1507
|
-
std::string error =
|
|
1508
|
-
|
|
1527
|
+
std::string error = "Failed to prepare statement: ";
|
|
1528
|
+
error += sqlite3_errmsg(database->connection());
|
|
1529
|
+
// Use SqliteException to capture error info - avoids Windows ARM ABI issues
|
|
1530
|
+
// with std::runtime_error::what() returning corrupted strings
|
|
1531
|
+
throw SqliteException(database->connection(), result, error);
|
|
1509
1532
|
}
|
|
1510
1533
|
}
|
|
1511
1534
|
|