web-sqlite-js 0.0.1 → 0.0.2-beta
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/LICENSE +21 -0
- package/README.md +250 -0
- package/dist/index.js +1 -2
- package/package.json +20 -8
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 wuchuheng
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
# web-sqlite-js
|
|
2
|
+
|
|
3
|
+
Enables direct use of SQLite in the web browser with reliable local data persistence via OPFS (Origin Private File System).
|
|
4
|
+
|
|
5
|
+
It runs SQLite in a Web Worker to avoid blocking the main thread and handles all synchronization automatically, providing a simple, Promise-based API.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Persistent Storage**: Uses OPFS for high-performance, persistent file storage.
|
|
10
|
+
- **Non-Blocking**: Runs in a Web Worker, keeping your UI responsive.
|
|
11
|
+
- **Concurrency Safe**: Built-in mutex ensures safe, sequential execution of commands.
|
|
12
|
+
- **Type-Safe**: Written in TypeScript with full type definitions.
|
|
13
|
+
- **Transactions**: Supports atomic transactions with automatic rollback on error.
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install web-sqlite-js
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## ⚠️ Critical Configuration: COOP & COEP
|
|
22
|
+
|
|
23
|
+
To use `SharedArrayBuffer` (required by the SQLite WASM build), your server **must** serve the application with the following HTTP headers:
|
|
24
|
+
|
|
25
|
+
```http
|
|
26
|
+
Cross-Origin-Opener-Policy: same-origin
|
|
27
|
+
Cross-Origin-Embedder-Policy: require-corp
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
If these headers are missing, the database **will not start**.
|
|
31
|
+
|
|
32
|
+
### Configuration Guides
|
|
33
|
+
|
|
34
|
+
<details>
|
|
35
|
+
<summary><strong>Vite</strong></summary>
|
|
36
|
+
|
|
37
|
+
Update your `vite.config.ts`:
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
import { defineConfig } from "vite";
|
|
41
|
+
|
|
42
|
+
export default defineConfig({
|
|
43
|
+
server: {
|
|
44
|
+
headers: {
|
|
45
|
+
"Cross-Origin-Opener-Policy": "same-origin",
|
|
46
|
+
"Cross-Origin-Embedder-Policy": "require-corp",
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
preview: {
|
|
50
|
+
headers: {
|
|
51
|
+
"Cross-Origin-Opener-Policy": "same-origin",
|
|
52
|
+
"Cross-Origin-Embedder-Policy": "require-corp",
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
</details>
|
|
59
|
+
|
|
60
|
+
<details>
|
|
61
|
+
<summary><strong>Next.js</strong></summary>
|
|
62
|
+
|
|
63
|
+
Update your `next.config.js`:
|
|
64
|
+
|
|
65
|
+
```javascript
|
|
66
|
+
/** @type {import('next').NextConfig} */
|
|
67
|
+
const nextConfig = {
|
|
68
|
+
async headers() {
|
|
69
|
+
return [
|
|
70
|
+
{
|
|
71
|
+
source: "/(.*)",
|
|
72
|
+
headers: [
|
|
73
|
+
{
|
|
74
|
+
key: "Cross-Origin-Opener-Policy",
|
|
75
|
+
value: "same-origin",
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
key: "Cross-Origin-Embedder-Policy",
|
|
79
|
+
value: "require-corp",
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
},
|
|
83
|
+
];
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
module.exports = nextConfig;
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
</details>
|
|
91
|
+
|
|
92
|
+
<details>
|
|
93
|
+
<summary><strong>Webpack (Dev Server)</strong></summary>
|
|
94
|
+
|
|
95
|
+
Update your `webpack.config.js`:
|
|
96
|
+
|
|
97
|
+
```javascript
|
|
98
|
+
module.exports = {
|
|
99
|
+
// ...
|
|
100
|
+
devServer: {
|
|
101
|
+
headers: {
|
|
102
|
+
"Cross-Origin-Opener-Policy": "same-origin",
|
|
103
|
+
"Cross-Origin-Embedder-Policy": "require-corp",
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
</details>
|
|
110
|
+
|
|
111
|
+
<details>
|
|
112
|
+
<summary><strong>Nginx</strong></summary>
|
|
113
|
+
|
|
114
|
+
Add the headers to your server block:
|
|
115
|
+
|
|
116
|
+
```nginx
|
|
117
|
+
server {
|
|
118
|
+
# ...
|
|
119
|
+
add_header Cross-Origin-Opener-Policy "same-origin";
|
|
120
|
+
add_header Cross-Origin-Embedder-Policy "require-corp";
|
|
121
|
+
# ...
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
</details>
|
|
126
|
+
|
|
127
|
+
<details>
|
|
128
|
+
<summary><strong>Express.js</strong></summary>
|
|
129
|
+
|
|
130
|
+
Use a middleware:
|
|
131
|
+
|
|
132
|
+
```javascript
|
|
133
|
+
const express = require("express");
|
|
134
|
+
const app = express();
|
|
135
|
+
|
|
136
|
+
app.use((req, res, next) => {
|
|
137
|
+
res.setHeader("Cross-Origin-Opener-Policy", "same-origin");
|
|
138
|
+
res.setHeader("Cross-Origin-Embedder-Policy", "require-corp");
|
|
139
|
+
next();
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// ...
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
</details>
|
|
146
|
+
|
|
147
|
+
<details>
|
|
148
|
+
<summary><strong>React / Vue (Create React App / Vue CLI)</strong></summary>
|
|
149
|
+
|
|
150
|
+
Most modern React/Vue setups use **Vite**. Please refer to the **Vite** section above.
|
|
151
|
+
|
|
152
|
+
If you are using an older webpack-based setup (like CRA `react-scripts`), you technically need to configure the underlying `webpack-dev-server`, but CRA doesn't expose this easily without ejecting or using tools like `craco` or `react-app-rewired` to modify the dev server configuration as shown in the **Webpack** section.
|
|
153
|
+
|
|
154
|
+
</details>
|
|
155
|
+
|
|
156
|
+
## Usage
|
|
157
|
+
|
|
158
|
+
### Basic Query
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
import openDB from "web-sqlite-js";
|
|
162
|
+
|
|
163
|
+
// 1. Open the database (creates 'my-database.sqlite3' in OPFS)
|
|
164
|
+
const db = await openDB("my-database");
|
|
165
|
+
|
|
166
|
+
// 2. Initialize schema
|
|
167
|
+
await db.exec(`
|
|
168
|
+
CREATE TABLE IF NOT EXISTS users (
|
|
169
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
170
|
+
name TEXT,
|
|
171
|
+
email TEXT
|
|
172
|
+
);
|
|
173
|
+
`);
|
|
174
|
+
|
|
175
|
+
// 3. Insert data (Parameterized)
|
|
176
|
+
await db.exec("INSERT INTO users (name, email) VALUES (?, ?)", [
|
|
177
|
+
"Alice",
|
|
178
|
+
"alice@example.com",
|
|
179
|
+
]);
|
|
180
|
+
await db.exec("INSERT INTO users (name, email) VALUES ($name, $email)", {
|
|
181
|
+
$name: "Bob",
|
|
182
|
+
$email: "bob@example.com",
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
// 4. Query data
|
|
186
|
+
interface User {
|
|
187
|
+
id: number;
|
|
188
|
+
name: string;
|
|
189
|
+
email: string;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const users = await db.query<User>("SELECT * FROM users");
|
|
193
|
+
console.log(users);
|
|
194
|
+
// Output: [{ id: 1, name: 'Alice', ... }, { id: 2, name: 'Bob', ... }]
|
|
195
|
+
|
|
196
|
+
// 5. Close when done
|
|
197
|
+
await db.close();
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Transactions
|
|
201
|
+
|
|
202
|
+
Transactions are atomic. If any command inside the callback fails, the entire transaction is rolled back.
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
await db.transaction(async (tx) => {
|
|
206
|
+
await tx.exec("INSERT INTO users (name) VALUES (?)", ["Charlie"]);
|
|
207
|
+
|
|
208
|
+
// You can perform multiple operations safely
|
|
209
|
+
await tx.exec("INSERT INTO logs (action) VALUES (?)", ["User Created"]);
|
|
210
|
+
|
|
211
|
+
// If you throw an error here, both INSERTs will be rolled back!
|
|
212
|
+
// throw new Error('Something went wrong');
|
|
213
|
+
});
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Multiple Connections
|
|
217
|
+
|
|
218
|
+
You can open multiple connections to the same file. They will automatically synchronize access.
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
const db1 = await openDB("shared-db");
|
|
222
|
+
const db2 = await openDB("shared-db");
|
|
223
|
+
|
|
224
|
+
await db1.exec("INSERT INTO items (name) VALUES (?)", ["Item 1"]);
|
|
225
|
+
|
|
226
|
+
// db2 sees the change immediately after db1 finishes
|
|
227
|
+
const items = await db2.query("SELECT * FROM items");
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## API
|
|
231
|
+
|
|
232
|
+
### `openDB(filename: string, options?: { debug?: boolean })`
|
|
233
|
+
|
|
234
|
+
Opens a database connection. Returns a `DBInterface`.
|
|
235
|
+
|
|
236
|
+
### `db.exec(sql: string, params?: any[] | Record<string, any>)`
|
|
237
|
+
|
|
238
|
+
Executes a SQL statement (INSERT, UPDATE, DELETE, CREATE). Returns `{ changes, lastInsertRowid }`.
|
|
239
|
+
|
|
240
|
+
### `db.query<T>(sql: string, params?: any[] | Record<string, any>)`
|
|
241
|
+
|
|
242
|
+
Executes a SELECT statement. Returns an array of rows `T[]`.
|
|
243
|
+
|
|
244
|
+
### `db.transaction<T>(callback: (tx: DBInterface) => Promise<T>)`
|
|
245
|
+
|
|
246
|
+
Runs the callback inside a transaction (`BEGIN` ... `COMMIT`/`ROLLBACK`). The `tx` object provided to the callback has the same `exec` and `query` methods.
|
|
247
|
+
|
|
248
|
+
### `db.close()`
|
|
249
|
+
|
|
250
|
+
Closes the connection and terminates the worker.
|
package/dist/index.js
CHANGED
|
@@ -12743,7 +12743,6 @@ if(!globalThis.SharedArrayBuffer){
|
|
|
12743
12743
|
return sIM;
|
|
12744
12744
|
})();
|
|
12745
12745
|
sqlite3InitModule = toExportForESM;
|
|
12746
|
-
var sqlite3InitModule$1 = sqlite3InitModule;
|
|
12747
12746
|
var SqliteEvent = /* @__PURE__ */ ((SqliteEvent2) => {
|
|
12748
12747
|
SqliteEvent2["OPEN"] = "open";
|
|
12749
12748
|
SqliteEvent2["CLOSE"] = "close";
|
|
@@ -12865,7 +12864,7 @@ if(!globalThis.SharedArrayBuffer){
|
|
|
12865
12864
|
if (typeof payload.filename !== "string") {
|
|
12866
12865
|
throw new Error("Invalid payload for OPEN event: expected filename string");
|
|
12867
12866
|
}
|
|
12868
|
-
sqlite3 = await sqlite3InitModule
|
|
12867
|
+
sqlite3 = await sqlite3InitModule();
|
|
12869
12868
|
console.debug(\`Initialized sqlite3 module in worker.\`);
|
|
12870
12869
|
let { filename } = payload;
|
|
12871
12870
|
if (!filename.endsWith(".sqlite3")) {
|
package/package.json
CHANGED
|
@@ -1,10 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "web-sqlite-js",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "",
|
|
3
|
+
"version": "0.0.2-beta",
|
|
4
|
+
"description": "Enables direct use of SQLite in the web browser with reliable local data persistence via OPFS.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
8
|
+
"author": "wuchuheng <root@wuchuheng.com>",
|
|
9
|
+
"keywords": [
|
|
10
|
+
"sqlite",
|
|
11
|
+
"wasm",
|
|
12
|
+
"opfs",
|
|
13
|
+
"web-worker",
|
|
14
|
+
"database",
|
|
15
|
+
"typescript",
|
|
16
|
+
"web-sqlite"
|
|
17
|
+
],
|
|
18
|
+
"sideEffects": false,
|
|
8
19
|
"exports": {
|
|
9
20
|
".": {
|
|
10
21
|
"types": "./dist/index.d.ts",
|
|
@@ -27,7 +38,9 @@
|
|
|
27
38
|
"package:publish": "npm run test && npm run build && npm publish --access public"
|
|
28
39
|
},
|
|
29
40
|
"files": [
|
|
30
|
-
"dist"
|
|
41
|
+
"dist",
|
|
42
|
+
"LICENSE",
|
|
43
|
+
"README.md"
|
|
31
44
|
],
|
|
32
45
|
"devDependencies": {
|
|
33
46
|
"@eslint/css": "^0.14.1",
|
|
@@ -53,12 +66,11 @@
|
|
|
53
66
|
},
|
|
54
67
|
"repository": {
|
|
55
68
|
"type": "git",
|
|
56
|
-
"url": "git+https://github.com/wuchuheng/web-sqlite-
|
|
69
|
+
"url": "git+https://github.com/wuchuheng/web-sqlite-js.git"
|
|
57
70
|
},
|
|
58
|
-
"
|
|
59
|
-
"license": "ISC",
|
|
71
|
+
"license": "MIT",
|
|
60
72
|
"bugs": {
|
|
61
|
-
"url": "https://github.com/wuchuheng/web-sqlite-
|
|
73
|
+
"url": "https://github.com/wuchuheng/web-sqlite-js/issues"
|
|
62
74
|
},
|
|
63
|
-
"homepage": "https://github.com/wuchuheng/web-sqlite-
|
|
75
|
+
"homepage": "https://github.com/wuchuheng/web-sqlite-js#readme"
|
|
64
76
|
}
|