web-sqlite-js 2.2.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 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.0.0-new%20features-blue" alt="v2.0.0" />
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" />
@@ -49,6 +49,8 @@ Designed to be truly effortless, it allows you to get a high-performance relatio
49
49
  - **Type-Safe**: Written in TypeScript with full type definitions.
50
50
  - **Transactions**: Supports atomic transactions with automatic rollback on error.
51
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.
52
54
  - **Structured Logging**: Subscribe to SQL execution logs via `onLog()`.
53
55
 
54
56
  ## Quick start
@@ -73,7 +75,7 @@ For quick demos or plain HTML pages you can load the prebuilt module directly:
73
75
 
74
76
  ```html
75
77
  <script type="module">
76
- import openDB from "https://cdn.jsdelivr.net/npm/web-sqlite-js@1.0.9/dist/index.js";
78
+ import openDB from "https://cdn.jsdelivr.net/npm/web-sqlite-js@2.2.0/dist/index.js";
77
79
  // ...
78
80
  </script>
79
81
  ```
@@ -322,12 +324,72 @@ console.log(users);
322
324
  // Output: [{ id: 1, name: 'Alice', email: 'alice@example.com', created_at: '...' }, ...]
323
325
  ```
324
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
+
325
386
  ### How It Works
326
387
 
327
388
  1. **Version Tracking**: Each release has a semantic version (e.g., "1.0.0")
328
389
  2. **Automatic Migration**: When opening a database, new releases are applied in order
329
390
  3. **Hash Verification**: Migration SQL is hashed to prevent tampering
330
- 4. **OPFS Storage**: Each version is stored as a separate file (`1.0.0.sqlite3`, `1.1.0.sqlite3`)
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`)
331
393
 
332
394
  ### Best Practices
333
395
 
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
- * Run a callback inside a transaction. The implementation should BEGIN before calling `fn`
18
- * and COMMIT on success or ROLLBACK on error.
19
- * @param fn - Callback that receives a DBInterface and performs transactional work.
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
- /** Close the database and release resources. */
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
- * Subscribe to log events
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 - Called for each log entry
29
- * @returns Unsubscribe function
61
+ * @param callback - Function to receive log entries.
62
+ * @returns Unregister function.
30
63
  *
31
64
  * @example
32
- * const unsubscribe = db.onLog((log) => {
33
- * console.log(`[${log.level}]`, log.data);
65
+ * ```ts
66
+ * const unregister = db.onLog((log) => {
67
+ * console.log(`[${log.level}]`, log.data);
34
68
  * });
35
- * // Later: unsubscribe();
69
+ * // Later: unregister();
70
+ * ```
36
71
  */
37
72
  onLog(callback: (log: LogEntry) => void): () => void;
38
- /** Dev tooling APIs for release testing. */
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 using migration and seed SQL.
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
- declare type transactionCallback<T> = (db: Pick<DBInterface, "exec" | "query">) => Promise<T>;
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 { }