web-sqlite-js 2.1.0 → 2.3.0
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/README.md +123 -102
- package/dist/index.d.ts +84 -14
- package/dist/index.js +3 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
<img src="https://img.shields.io/npm/v/web-sqlite-js.svg" alt="NPM Version" />
|
|
15
15
|
</a>
|
|
16
16
|
<a href="https://github.com/wuchuheng/web-sqlite-js/discussions" target="_blank">
|
|
17
|
-
<img src="https://img.shields.io/badge/v2.
|
|
17
|
+
<img src="https://img.shields.io/badge/v2.2.0-two--tier%20validation-brightgreen" alt="v2.2.0" />
|
|
18
18
|
</a>
|
|
19
19
|
<a href="https://github.com/wuchuheng/web-sqlite-js/blob/main/LICENSE" target="_blank">
|
|
20
20
|
<img src="https://img.shields.io/github/license/wuchuheng/web-sqlite-js.svg" alt="License" />
|
|
@@ -36,11 +36,10 @@ Designed to be truly effortless, it allows you to get a high-performance relatio
|
|
|
36
36
|
- [Quick start](#quick-start)
|
|
37
37
|
- [Setup HTTP headers](#setup-http-headers)
|
|
38
38
|
- [Usage](#usage)
|
|
39
|
-
- [Debug mode](#debug-mode)
|
|
40
39
|
- [Transactions](#transactions)
|
|
41
|
-
- [
|
|
42
|
-
- [
|
|
43
|
-
- [
|
|
40
|
+
- [Schema Migrations](#schema-migrations)
|
|
41
|
+
- [Debug mode](#debug-mode)
|
|
42
|
+
- [Structured Logging](#structured-logging)
|
|
44
43
|
|
|
45
44
|
## Features
|
|
46
45
|
|
|
@@ -49,10 +48,10 @@ Designed to be truly effortless, it allows you to get a high-performance relatio
|
|
|
49
48
|
- **Concurrency Safe**: Built-in mutex ensures safe, sequential execution of commands.
|
|
50
49
|
- **Type-Safe**: Written in TypeScript with full type definitions.
|
|
51
50
|
- **Transactions**: Supports atomic transactions with automatic rollback on error.
|
|
52
|
-
- **
|
|
53
|
-
- **
|
|
54
|
-
- **
|
|
55
|
-
- **
|
|
51
|
+
- **Schema Migrations**: Built-in versioning system for database schema changes.
|
|
52
|
+
- **Two-Tier Validation** (v2.2.0): Distinguishes between whitespace-only changes and actual SQL changes.
|
|
53
|
+
- **Enhanced Error Messages** (v2.2.0): SQL diffs and truncation for better debugging.
|
|
54
|
+
- **Structured Logging**: Subscribe to SQL execution logs via `onLog()`.
|
|
56
55
|
|
|
57
56
|
## Quick start
|
|
58
57
|
|
|
@@ -76,7 +75,7 @@ For quick demos or plain HTML pages you can load the prebuilt module directly:
|
|
|
76
75
|
|
|
77
76
|
```html
|
|
78
77
|
<script type="module">
|
|
79
|
-
import openDB from "https://cdn.jsdelivr.net/npm/web-sqlite-js@
|
|
78
|
+
import openDB from "https://cdn.jsdelivr.net/npm/web-sqlite-js@2.2.0/dist/index.js";
|
|
80
79
|
// ...
|
|
81
80
|
</script>
|
|
82
81
|
```
|
|
@@ -286,7 +285,120 @@ await db.transaction(async (tx) => {
|
|
|
286
285
|
});
|
|
287
286
|
```
|
|
288
287
|
|
|
289
|
-
##
|
|
288
|
+
## Schema Migrations
|
|
289
|
+
|
|
290
|
+
Manage database schema changes across releases using the built-in versioning system. Define releases with migration SQL and optional seed data.
|
|
291
|
+
|
|
292
|
+
### Basic Usage
|
|
293
|
+
|
|
294
|
+
```typescript
|
|
295
|
+
const db = await openDB("myapp", {
|
|
296
|
+
releases: [
|
|
297
|
+
{
|
|
298
|
+
version: "1.0.0",
|
|
299
|
+
migrationSQL: `
|
|
300
|
+
CREATE TABLE users (
|
|
301
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
302
|
+
name TEXT NOT NULL,
|
|
303
|
+
email TEXT UNIQUE
|
|
304
|
+
);
|
|
305
|
+
`,
|
|
306
|
+
seedSQL: `
|
|
307
|
+
INSERT INTO users (name, email) VALUES
|
|
308
|
+
('Alice', 'alice@example.com'),
|
|
309
|
+
('Bob', 'bob@example.com');
|
|
310
|
+
`,
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
version: "1.1.0",
|
|
314
|
+
migrationSQL: `
|
|
315
|
+
ALTER TABLE users ADD COLUMN created_at TEXT DEFAULT (datetime('now'));
|
|
316
|
+
`,
|
|
317
|
+
},
|
|
318
|
+
],
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
// Database is now at version 1.1.0 with all migrations applied
|
|
322
|
+
const users = await db.query("SELECT * FROM users");
|
|
323
|
+
console.log(users);
|
|
324
|
+
// Output: [{ id: 1, name: 'Alice', email: 'alice@example.com', created_at: '...' }, ...]
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### Two-Tier Validation (v2.2.0)
|
|
328
|
+
|
|
329
|
+
Starting with v2.2.0, web-sqlite-js uses a two-tier validation system that intelligently handles SQL formatting changes:
|
|
330
|
+
|
|
331
|
+
**Tier 1: Fast Path** (< 0.1ms)
|
|
332
|
+
|
|
333
|
+
- Trims whitespace and compares hashes
|
|
334
|
+
- Passes immediately if SQL hasn't changed
|
|
335
|
+
|
|
336
|
+
**Tier 2: Slow Path** (1-5ms, only on hash mismatch)
|
|
337
|
+
|
|
338
|
+
- Normalizes SQL using SQLite prepare
|
|
339
|
+
- Auto-updates hash for whitespace-only changes
|
|
340
|
+
- Throws enhanced error for actual SQL changes
|
|
341
|
+
|
|
342
|
+
**What this means for you:**
|
|
343
|
+
|
|
344
|
+
```typescript
|
|
345
|
+
// You can reformat your SQL without breaking migrations!
|
|
346
|
+
const db1 = await openDB("myapp", {
|
|
347
|
+
releases: [
|
|
348
|
+
{
|
|
349
|
+
version: "1.0.0",
|
|
350
|
+
migrationSQL: "CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT);",
|
|
351
|
+
},
|
|
352
|
+
],
|
|
353
|
+
});
|
|
354
|
+
await db1.close();
|
|
355
|
+
|
|
356
|
+
// Reopen with reformatted SQL (whitespace-only change)
|
|
357
|
+
const db2 = await openDB("myapp", {
|
|
358
|
+
releases: [
|
|
359
|
+
{
|
|
360
|
+
version: "1.0.0",
|
|
361
|
+
migrationSQL: `
|
|
362
|
+
CREATE TABLE items (
|
|
363
|
+
id INTEGER PRIMARY KEY,
|
|
364
|
+
name TEXT
|
|
365
|
+
);
|
|
366
|
+
`,
|
|
367
|
+
},
|
|
368
|
+
],
|
|
369
|
+
});
|
|
370
|
+
// ✅ Works! Hash auto-updated (no error)
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
**Enhanced Error Messages:**
|
|
374
|
+
|
|
375
|
+
If you accidentally change the SQL semantics, you'll get detailed error messages:
|
|
376
|
+
|
|
377
|
+
```
|
|
378
|
+
Hash mismatch for 1.0.0 migrationSQL:
|
|
379
|
+
Expected: abc123...
|
|
380
|
+
Actual: def456...
|
|
381
|
+
SQL has changed:
|
|
382
|
+
- Original: CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT);
|
|
383
|
+
+ Current: CREATE TABLE items (id INTEGER PRIMARY KEY, email TEXT);
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
### How It Works
|
|
387
|
+
|
|
388
|
+
1. **Version Tracking**: Each release has a semantic version (e.g., "1.0.0")
|
|
389
|
+
2. **Automatic Migration**: When opening a database, new releases are applied in order
|
|
390
|
+
3. **Hash Verification**: Migration SQL is hashed to prevent tampering
|
|
391
|
+
4. **Two-Tier Validation**: Distinguishes whitespace-only changes from actual SQL changes
|
|
392
|
+
5. **OPFS Storage**: Each version is stored as a separate file (`1.0.0.sqlite3`, `1.1.0.sqlite3`)
|
|
393
|
+
|
|
394
|
+
### Best Practices
|
|
395
|
+
|
|
396
|
+
- **Use Semantic Versioning**: Follow `MAJOR.MINOR.PATCH` format
|
|
397
|
+
- **Idempotent Migrations**: Each migration should handle re-runs safely
|
|
398
|
+
- **Test Migrations**: Always test migrations on a clean database
|
|
399
|
+
- **Incremental Changes**: Keep migrations focused on single schema changes
|
|
400
|
+
|
|
401
|
+
## Structured Logging
|
|
290
402
|
|
|
291
403
|
Subscribe to structured log events for monitoring, debugging, and analytics. The `onLog()` API allows you to capture SQL execution details, errors, and application events.
|
|
292
404
|
|
|
@@ -330,97 +442,6 @@ const cancel2 = db.onLog((log) => {
|
|
|
330
442
|
});
|
|
331
443
|
```
|
|
332
444
|
|
|
333
|
-
---
|
|
334
|
-
|
|
335
|
-
## Global Database Access (v2.0.0)
|
|
336
|
-
|
|
337
|
-
Access opened databases from anywhere in your application without imports. The `window.__web_sqlite` global namespace provides direct references to all opened database instances.
|
|
338
|
-
|
|
339
|
-
```typescript
|
|
340
|
-
// Open database in module A
|
|
341
|
-
const db = await openDB("app");
|
|
342
|
-
|
|
343
|
-
// In module B (no import needed):
|
|
344
|
-
const db = window.__web_sqlite.databases["app.sqlite3"];
|
|
345
|
-
const users = await db.query("SELECT * FROM users");
|
|
346
|
-
|
|
347
|
-
// List all opened databases
|
|
348
|
-
console.log(Object.keys(window.__web_sqlite.databases));
|
|
349
|
-
// Output: ["app.sqlite3", "users.sqlite3"]
|
|
350
|
-
```
|
|
351
|
-
|
|
352
|
-
**Use Cases**:
|
|
353
|
-
|
|
354
|
-
- **DevTools Integration**: Access databases from browser console for debugging
|
|
355
|
-
- **Cross-Module Communication**: Share database state without prop drilling
|
|
356
|
-
- **Debugging**: Inspect and query databases directly from DevTools console
|
|
357
|
-
|
|
358
|
-
**Browser Console Example**:
|
|
359
|
-
|
|
360
|
-
```javascript
|
|
361
|
-
// From browser DevTools console:
|
|
362
|
-
window.__web_sqlite.databases["app.sqlite3"]
|
|
363
|
-
.query("SELECT * FROM users")
|
|
364
|
-
.then((users) => console.table(users));
|
|
365
|
-
```
|
|
366
|
-
|
|
367
|
-
---
|
|
368
|
-
|
|
369
|
-
## Database Events (v2.0.0)
|
|
370
|
-
|
|
371
|
-
Subscribe to database open/close events for UI synchronization and monitoring. The `onDatabaseChange()` API notifies you when databases are opened or closed.
|
|
372
|
-
|
|
373
|
-
```typescript
|
|
374
|
-
// Subscribe to database changes
|
|
375
|
-
const unsubscribe = window.__web_sqlite.onDatabaseChange((event) => {
|
|
376
|
-
if (event.action === "opened") {
|
|
377
|
-
console.log(`Database opened: ${event.dbName}`);
|
|
378
|
-
updateDatabaseList(event.databases);
|
|
379
|
-
} else if (event.action === "closed") {
|
|
380
|
-
console.log(`Database closed: ${event.dbName}`);
|
|
381
|
-
updateDatabaseList(event.databases);
|
|
382
|
-
}
|
|
383
|
-
console.log("Current databases:", event.databases);
|
|
384
|
-
});
|
|
385
|
-
|
|
386
|
-
// Open a database
|
|
387
|
-
await openDB("app");
|
|
388
|
-
// Output: Database opened: app.sqlite3
|
|
389
|
-
// Output: Current databases: ["app.sqlite3"]
|
|
390
|
-
|
|
391
|
-
// Open another database
|
|
392
|
-
await openDB("users");
|
|
393
|
-
// Output: Database opened: users.sqlite3
|
|
394
|
-
// Output: Current databases: ["app.sqlite3", "users.sqlite3"]
|
|
395
|
-
|
|
396
|
-
// Close first database
|
|
397
|
-
await window.__web_sqlite.databases["app.sqlite3"].close();
|
|
398
|
-
// Output: Database closed: app.sqlite3
|
|
399
|
-
// Output: Current databases: ["users.sqlite3"]
|
|
400
|
-
|
|
401
|
-
// Unsubscribe when done
|
|
402
|
-
// unsubscribe();
|
|
403
|
-
```
|
|
404
|
-
|
|
405
|
-
**Event Structure**:
|
|
406
|
-
|
|
407
|
-
```typescript
|
|
408
|
-
interface DatabaseChangeEvent {
|
|
409
|
-
action: "opened" | "closed"; // What happened
|
|
410
|
-
dbName: string; // Which database (normalized name)
|
|
411
|
-
databases: string[]; // All currently opened database names
|
|
412
|
-
}
|
|
413
|
-
```
|
|
414
|
-
|
|
415
|
-
**Use Cases**:
|
|
416
|
-
|
|
417
|
-
- **DevTools Panels**: Show active databases in browser DevTools
|
|
418
|
-
- **UI Updates**: Refresh database list when databases open/close
|
|
419
|
-
- **Monitoring**: Track database lifecycle for debugging
|
|
420
|
-
- **Multi-Window Sync**: Coordinate database access across browser windows
|
|
421
|
-
|
|
422
|
-
---
|
|
423
|
-
|
|
424
445
|
## Star History
|
|
425
446
|
|
|
426
447
|
<p align="left">
|
package/dist/index.d.ts
CHANGED
|
@@ -3,45 +3,96 @@ declare interface DBInterface {
|
|
|
3
3
|
/**
|
|
4
4
|
* Execute a SQL script (one or more statements) without returning rows.
|
|
5
5
|
* Intended for migrations, schema setup, or bulk SQL execution.
|
|
6
|
+
*
|
|
6
7
|
* @param sql - SQL string to execute.
|
|
7
8
|
* @param params - Optional bind parameters for the statement.
|
|
9
|
+
* @returns Result metadata (changes, lastInsertRowid).
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* await db.exec("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)");
|
|
14
|
+
* await db.exec("INSERT INTO users (name) VALUES (?)", ["Alice"]);
|
|
15
|
+
* ```
|
|
8
16
|
*/
|
|
9
17
|
exec(sql: string, params?: SQLParams): Promise<ExecResult>;
|
|
10
18
|
/**
|
|
11
19
|
* Execute a query and return all result rows as an array of objects.
|
|
20
|
+
*
|
|
12
21
|
* @param sql - SELECT SQL to execute.
|
|
13
22
|
* @param params - Optional bind parameters for the query.
|
|
23
|
+
* @returns Array of result rows.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```ts
|
|
27
|
+
* const users = await db.query<{ id: number; name: string }>(
|
|
28
|
+
* "SELECT id, name FROM users WHERE id = ?",
|
|
29
|
+
* [1]
|
|
30
|
+
* );
|
|
31
|
+
* ```
|
|
14
32
|
*/
|
|
15
33
|
query<T = unknown>(sql: string, params?: SQLParams): Promise<T[]>;
|
|
16
34
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* @param fn -
|
|
35
|
+
* Execute a transaction with automatic rollback on error.
|
|
36
|
+
*
|
|
37
|
+
* @param fn - Transaction callback receiving transaction interface.
|
|
38
|
+
* @returns Result of the transaction callback.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```ts
|
|
42
|
+
* await db.transaction(async (tx) => {
|
|
43
|
+
* await tx.exec("INSERT INTO users (name) VALUES (?)", ["Bob"]);
|
|
44
|
+
* await tx.exec("INSERT INTO posts (title) VALUES (?)", ["Hello"]);
|
|
45
|
+
* });
|
|
46
|
+
* ```
|
|
20
47
|
*/
|
|
21
48
|
transaction<T>(fn: transactionCallback<T>): Promise<T>;
|
|
22
|
-
/**
|
|
49
|
+
/**
|
|
50
|
+
* Close the database and release worker resources.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```ts
|
|
54
|
+
* await db.close();
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
23
57
|
close(): Promise<void>;
|
|
24
58
|
/**
|
|
25
|
-
*
|
|
26
|
-
* Logs include SQL execution, timing, errors, and application events
|
|
59
|
+
* Register a callback for database logs (worker SQL execution logs).
|
|
27
60
|
*
|
|
28
|
-
* @param callback -
|
|
29
|
-
* @returns
|
|
61
|
+
* @param callback - Function to receive log entries.
|
|
62
|
+
* @returns Unregister function.
|
|
30
63
|
*
|
|
31
64
|
* @example
|
|
32
|
-
*
|
|
33
|
-
*
|
|
65
|
+
* ```ts
|
|
66
|
+
* const unregister = db.onLog((log) => {
|
|
67
|
+
* console.log(`[${log.level}]`, log.data);
|
|
34
68
|
* });
|
|
35
|
-
* // Later:
|
|
69
|
+
* // Later: unregister();
|
|
70
|
+
* ```
|
|
36
71
|
*/
|
|
37
72
|
onLog(callback: (log: LogEntry) => void): () => void;
|
|
38
|
-
/**
|
|
73
|
+
/**
|
|
74
|
+
* Dev tooling for creating and managing dev versions.
|
|
75
|
+
*/
|
|
39
76
|
devTool: DevTool;
|
|
40
77
|
}
|
|
41
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Dev tooling interface for creating and rolling back dev versions.
|
|
81
|
+
*/
|
|
42
82
|
declare type DevTool = {
|
|
43
83
|
/**
|
|
44
|
-
* Create a new dev version
|
|
84
|
+
* Create a new dev version with migration and seed SQL.
|
|
85
|
+
*
|
|
86
|
+
* @param input - Release config with version, migration SQL, and optional seed SQL.
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```ts
|
|
90
|
+
* await db.devTool.release({
|
|
91
|
+
* version: "1.0.1",
|
|
92
|
+
* migrationSQL: "ALTER TABLE users ADD COLUMN email TEXT",
|
|
93
|
+
* seedSQL: "UPDATE users SET email = 'test@example.com' WHERE email IS NULL",
|
|
94
|
+
* });
|
|
95
|
+
* ```
|
|
45
96
|
*/
|
|
46
97
|
release(input: ReleaseConfig): Promise<void>;
|
|
47
98
|
/**
|
|
@@ -118,6 +169,25 @@ declare type SQLParams = SqlValue[] | Record<string, SqlValue>;
|
|
|
118
169
|
*/
|
|
119
170
|
declare type SqlValue = null | number | string | boolean | bigint | Uint8Array | ArrayBuffer;
|
|
120
171
|
|
|
121
|
-
|
|
172
|
+
/**
|
|
173
|
+
* Transaction interface passed to transaction callbacks.
|
|
174
|
+
* All operations execute within the same transaction.
|
|
175
|
+
*/
|
|
176
|
+
declare interface Transaction {
|
|
177
|
+
/**
|
|
178
|
+
* Execute a SQL statement within the transaction.
|
|
179
|
+
*/
|
|
180
|
+
exec(sql: string, params?: SQLParams): Promise<ExecResult>;
|
|
181
|
+
/**
|
|
182
|
+
* Execute a query within the transaction.
|
|
183
|
+
*/
|
|
184
|
+
query<T = unknown>(sql: string, params?: SQLParams): Promise<T[]>;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Transaction callback interface.
|
|
189
|
+
* Provides exec and query methods scoped to the transaction.
|
|
190
|
+
*/
|
|
191
|
+
declare type transactionCallback<T> = (tx: Transaction) => Promise<T>;
|
|
122
192
|
|
|
123
193
|
export { }
|