@birchill/nice-sqlite-wasm 0.1.0 → 0.1.2

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
@@ -15,6 +15,9 @@ It's "nice" because:
15
15
  In general, it should be nicer for apps using bundlers that only need the
16
16
  "opfs-sahpool" VFS.
17
17
 
18
+ As an extra bonus, the whole build (including building the WASM module) is done
19
+ in CI and published to npm with provenance data so you get full traceability.
20
+
18
21
  > [!NOTE]
19
22
  > The JS/WASM part of SQLite is under heavy development and is expected to
20
23
  > change a lot in future (e.g. using WASI instead of Emscripten). As a result
@@ -25,7 +28,116 @@ For the official SQLite WASM package see
25
28
 
26
29
  ## Usage
27
30
 
28
- TODO
31
+ Install:
32
+
33
+ ```
34
+ npm install @birchill/nice-sqlite-wasm
35
+ ```
36
+
37
+ You _could_ probably just do an `import sqlite3InitModule from
38
+ '@birchill/nice-sqlite-wasm'` and be done with it but the whole point of this
39
+ module is to allow you to set it up for better caching and pre-loading.
40
+ How you do that will depend on your bundler.
41
+
42
+ Following is an example for [rspack](https://rspack.rs).
43
+
44
+ ### rspack
45
+
46
+ First, we set up a way to generated the name of the WASM module so we can pass
47
+ it to `sqlite3InitModule`.
48
+
49
+ In your `rspack.config.js`:
50
+
51
+ ```js
52
+ export default defineConfig((env) => {
53
+ // ...
54
+ module: {
55
+ rules: [
56
+ { resourceQuery: /url$/, type: 'asset/resource' },
57
+ ],
58
+ },
59
+ });
60
+ ```
61
+
62
+ Second, we set up rspack to produce the desired output filename for the asset,
63
+ otherwise you'll get something like `[hash].wasm` which isn't very helpful.
64
+
65
+ Furthermore, we want to drop the query string we enabled above.
66
+
67
+ ```js
68
+ export default defineConfig((env) => {
69
+ // ...
70
+ output: {
71
+ assetModuleFilename: (fileInfo) => {
72
+ // Generate a cacheable but readable filename for WASM files
73
+ if (
74
+ fileInfo.filename.endsWith('.wasm') ||
75
+ fileInfo.filename.endsWith('.wasm?url')
76
+ ) {
77
+ return '[name].[hash].wasm';
78
+ }
79
+ return '[hash][ext][query]';
80
+ },
81
+ },
82
+ });
83
+ ```
84
+
85
+ Then in your worker code:
86
+
87
+ ```js
88
+ import wasmUrl from '@birchill/nice-sqlite-wasm/sqlite3.wasm?url';
89
+ import sqlite3InitModule from '@birchill/nice-sqlite-wasm';
90
+ ```
91
+
92
+ Then when you initialize SQLite:
93
+
94
+ ```js
95
+ const sqlite = await sqlite3InitModule({
96
+ // Override SQLite's locateFile implementation which wants to resolve
97
+ // the SQLite WASM binary relative to the source directory instead of
98
+ // the asset name assigned by rspack.
99
+ locateFile: (file) => {
100
+ if (file === 'sqlite3.wasm') {
101
+ // Since we strip the query string in our `assetModuleFilename`
102
+ // option in rspack.config.js we don't need to worry about dropping
103
+ // it here.
104
+ //
105
+ // If we were to stop doing that, however, we'd need to do
106
+ // something like:
107
+ //
108
+ // return new URL(wasmUrl, self.location.href).pathname;
109
+ //
110
+ // instead.
111
+ return fetch(wasmUrl, {
112
+ credentials: 'same-origin',
113
+ // If you want to make the fetch abortable...
114
+ signal: abortController.signal,
115
+ });
116
+ } else {
117
+ throw new Error(`Unknown file: ${file}`);
118
+ }
119
+ },
120
+ });
121
+ ```
122
+
123
+ You can also just return `wasmUrl` from `locateFile` if don't need to control
124
+ the fetch yourself.
125
+
126
+ ### vite
127
+
128
+ I'm not sure how to configure vite, but if you're only using it for testing
129
+ (i.e. using [vitest](https://vitest.dev/)) then you can just disable
130
+ optimization there as [explained in the official WASM
131
+ module docs](https://github.com/sqlite/sqlite-wasm/#usage-with-vite):
132
+
133
+ ```js
134
+ // vitest.config.js
135
+ import { defineConfig } from 'vite';
136
+
137
+ export default defineConfig({
138
+ optimizeDeps: { exclude: ['@birchill/nice-sqlite-wasm'] },
139
+ });
140
+ ```
29
141
 
30
142
  ## Developing
31
143
 
@@ -0,0 +1 @@
1
+ a5333afb9ad1aa473f8963b92caeaa955f47dc74
package/dist/sqlite3.js CHANGED
@@ -26,11 +26,11 @@
26
26
  /*
27
27
  ** This code was built from sqlite3 version...
28
28
  **
29
- ** SQLITE_VERSION "3.51.1"
30
- ** SQLITE_VERSION_NUMBER 3051001
31
- ** SQLITE_SOURCE_ID "2025-11-28 17:28:25 281fc0e9afc38674b9b0991943b9e9d1e64c6cbdb133d35f6f5c87ff6af3alt1"
29
+ ** SQLITE_VERSION "3.51.3"
30
+ ** SQLITE_VERSION_NUMBER 3051003
31
+ ** SQLITE_SOURCE_ID "2026-03-13 10:38:09 737ae4a34738ffa0c3ff7f9bb18df914dd1cad163f28fd6b6e114a344fe6alt1"
32
32
  **
33
- ** Emscripten SDK: 4.0.23
33
+ ** Emscripten SDK: 5.0.3
34
34
  **
35
35
  */
36
36
 
@@ -845,9 +845,10 @@ async function sqlite3InitModule(moduleArg = {}) {
845
845
  } else if (FS.isFile(node.mode)) {
846
846
  node.node_ops = MEMFS.ops_table.file.node;
847
847
  node.stream_ops = MEMFS.ops_table.file.stream;
848
+
848
849
  node.usedBytes = 0;
849
850
 
850
- node.contents = null;
851
+ node.contents = MEMFS.emptyFileContents ??= new Uint8Array(0);
851
852
  } else if (FS.isLink(node.mode)) {
852
853
  node.node_ops = MEMFS.ops_table.link.node;
853
854
  node.stream_ops = MEMFS.ops_table.link.stream;
@@ -864,13 +865,10 @@ async function sqlite3InitModule(moduleArg = {}) {
864
865
  return node;
865
866
  },
866
867
  getFileDataAsTypedArray(node) {
867
- if (!node.contents) return new Uint8Array(0);
868
- if (node.contents.subarray)
869
- return node.contents.subarray(0, node.usedBytes);
870
- return new Uint8Array(node.contents);
868
+ return node.contents.subarray(0, node.usedBytes);
871
869
  },
872
870
  expandFileStorage(node, newCapacity) {
873
- var prevCapacity = node.contents ? node.contents.length : 0;
871
+ var prevCapacity = node.contents.length;
874
872
  if (prevCapacity >= newCapacity) return;
875
873
 
876
874
  var CAPACITY_DOUBLING_MAX = 1024 * 1024;
@@ -880,27 +878,19 @@ async function sqlite3InitModule(moduleArg = {}) {
880
878
  (prevCapacity < CAPACITY_DOUBLING_MAX ? 2.0 : 1.125)) >>>
881
879
  0
882
880
  );
883
- if (prevCapacity != 0) newCapacity = Math.max(newCapacity, 256);
884
- var oldContents = node.contents;
881
+ if (prevCapacity) newCapacity = Math.max(newCapacity, 256);
882
+ var oldContents = MEMFS.getFileDataAsTypedArray(node);
885
883
  node.contents = new Uint8Array(newCapacity);
886
- if (node.usedBytes > 0)
887
- node.contents.set(oldContents.subarray(0, node.usedBytes), 0);
884
+ node.contents.set(oldContents);
888
885
  },
889
886
  resizeFileStorage(node, newSize) {
890
887
  if (node.usedBytes == newSize) return;
891
- if (newSize == 0) {
892
- node.contents = null;
893
- node.usedBytes = 0;
894
- } else {
895
- var oldContents = node.contents;
896
- node.contents = new Uint8Array(newSize);
897
- if (oldContents) {
898
- node.contents.set(
899
- oldContents.subarray(0, Math.min(newSize, node.usedBytes))
900
- );
901
- }
902
- node.usedBytes = newSize;
903
- }
888
+ var oldContents = node.contents;
889
+ node.contents = new Uint8Array(newSize);
890
+ node.contents.set(
891
+ oldContents.subarray(0, Math.min(newSize, node.usedBytes))
892
+ );
893
+ node.usedBytes = newSize;
904
894
  },
905
895
  node_ops: {
906
896
  getattr(node) {
@@ -1006,12 +996,7 @@ async function sqlite3InitModule(moduleArg = {}) {
1006
996
  var contents = stream.node.contents;
1007
997
  if (position >= stream.node.usedBytes) return 0;
1008
998
  var size = Math.min(stream.node.usedBytes - position, length);
1009
- if (size > 8 && contents.subarray) {
1010
- buffer.set(contents.subarray(position, position + size), offset);
1011
- } else {
1012
- for (var i = 0; i < size; i++)
1013
- buffer[offset + i] = contents[position + i];
1014
- }
999
+ buffer.set(contents.subarray(position, position + size), offset);
1015
1000
  return size;
1016
1001
  },
1017
1002
  write(stream, buffer, offset, length, position, canOwn) {
@@ -1023,33 +1008,18 @@ async function sqlite3InitModule(moduleArg = {}) {
1023
1008
  var node = stream.node;
1024
1009
  node.mtime = node.ctime = Date.now();
1025
1010
 
1026
- if (buffer.subarray && (!node.contents || node.contents.subarray)) {
1027
- if (canOwn) {
1028
- node.contents = buffer.subarray(offset, offset + length);
1029
- node.usedBytes = length;
1030
- return length;
1031
- } else if (node.usedBytes === 0 && position === 0) {
1032
- node.contents = buffer.slice(offset, offset + length);
1033
- node.usedBytes = length;
1034
- return length;
1035
- } else if (position + length <= node.usedBytes) {
1036
- node.contents.set(
1037
- buffer.subarray(offset, offset + length),
1038
- position
1039
- );
1040
- return length;
1041
- }
1042
- }
1011
+ if (canOwn) {
1012
+ node.contents = buffer.subarray(offset, offset + length);
1013
+ node.usedBytes = length;
1014
+ } else if (node.usedBytes === 0 && position === 0) {
1015
+ node.contents = buffer.slice(offset, offset + length);
1016
+ node.usedBytes = length;
1017
+ } else {
1018
+ MEMFS.expandFileStorage(node, position + length);
1043
1019
 
1044
- MEMFS.expandFileStorage(node, position + length);
1045
- if (node.contents.subarray && buffer.subarray) {
1046
1020
  node.contents.set(buffer.subarray(offset, offset + length), position);
1047
- } else {
1048
- for (var i = 0; i < length; i++) {
1049
- node.contents[position + i] = buffer[offset + i];
1050
- }
1021
+ node.usedBytes = Math.max(node.usedBytes, position + length);
1051
1022
  }
1052
- node.usedBytes = Math.max(node.usedBytes, position + length);
1053
1023
  return length;
1054
1024
  },
1055
1025
  llseek(stream, offset, whence) {
@@ -1074,7 +1044,7 @@ async function sqlite3InitModule(moduleArg = {}) {
1074
1044
  var allocated;
1075
1045
  var contents = stream.node.contents;
1076
1046
 
1077
- if (!(flags & 2) && contents && contents.buffer === HEAP8.buffer) {
1047
+ if (!(flags & 2) && contents.buffer === HEAP8.buffer) {
1078
1048
  allocated = false;
1079
1049
  ptr = contents.byteOffset;
1080
1050
  } else {
@@ -1109,6 +1079,7 @@ async function sqlite3InitModule(moduleArg = {}) {
1109
1079
  };
1110
1080
 
1111
1081
  var FS_modeStringToFlags = (str) => {
1082
+ if (typeof str != 'string') return str;
1112
1083
  var flagModes = {
1113
1084
  r: 0,
1114
1085
  'r+': 2,
@@ -1124,6 +1095,16 @@ async function sqlite3InitModule(moduleArg = {}) {
1124
1095
  return flags;
1125
1096
  };
1126
1097
 
1098
+ var FS_fileDataToTypedArray = (data) => {
1099
+ if (typeof data == 'string') {
1100
+ data = intArrayFromString(data, true);
1101
+ }
1102
+ if (!data.subarray) {
1103
+ data = new Uint8Array(data);
1104
+ }
1105
+ return data;
1106
+ };
1107
+
1127
1108
  var FS_getMode = (canRead, canWrite) => {
1128
1109
  var mode = 0;
1129
1110
  if (canRead) mode |= 292 | 73;
@@ -1242,7 +1223,6 @@ async function sqlite3InitModule(moduleArg = {}) {
1242
1223
  ignorePermissions: true,
1243
1224
  filesystems: null,
1244
1225
  syncFSRequests: 0,
1245
- readFiles: {},
1246
1226
  ErrnoError: class {
1247
1227
  name = 'ErrnoError';
1248
1228
 
@@ -1494,9 +1474,11 @@ async function sqlite3InitModule(moduleArg = {}) {
1494
1474
 
1495
1475
  if (perms.includes('r') && !(node.mode & 292)) {
1496
1476
  return 2;
1497
- } else if (perms.includes('w') && !(node.mode & 146)) {
1477
+ }
1478
+ if (perms.includes('w') && !(node.mode & 146)) {
1498
1479
  return 2;
1499
- } else if (perms.includes('x') && !(node.mode & 73)) {
1480
+ }
1481
+ if (perms.includes('x') && !(node.mode & 73)) {
1500
1482
  return 2;
1501
1483
  }
1502
1484
  return 0;
@@ -1536,10 +1518,8 @@ async function sqlite3InitModule(moduleArg = {}) {
1536
1518
  if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {
1537
1519
  return 10;
1538
1520
  }
1539
- } else {
1540
- if (FS.isDir(node.mode)) {
1541
- return 31;
1542
- }
1521
+ } else if (FS.isDir(node.mode)) {
1522
+ return 31;
1543
1523
  }
1544
1524
  return 0;
1545
1525
  },
@@ -1549,12 +1529,14 @@ async function sqlite3InitModule(moduleArg = {}) {
1549
1529
  }
1550
1530
  if (FS.isLink(node.mode)) {
1551
1531
  return 32;
1552
- } else if (FS.isDir(node.mode)) {
1553
- if (FS.flagsToPermissionString(flags) !== 'r' || flags & (512 | 64)) {
1532
+ }
1533
+ var mode = FS.flagsToPermissionString(flags);
1534
+ if (FS.isDir(node.mode)) {
1535
+ if (mode !== 'r' || flags & (512 | 64)) {
1554
1536
  return 31;
1555
1537
  }
1556
1538
  }
1557
- return FS.nodePermissions(node, FS.flagsToPermissionString(flags));
1539
+ return FS.nodePermissions(node, mode);
1558
1540
  },
1559
1541
  checkOpExists(op, err) {
1560
1542
  if (!op) {
@@ -2087,7 +2069,7 @@ async function sqlite3InitModule(moduleArg = {}) {
2087
2069
  if (path === '') {
2088
2070
  throw new FS.ErrnoError(44);
2089
2071
  }
2090
- flags = typeof flags == 'string' ? FS_modeStringToFlags(flags) : flags;
2072
+ flags = FS_modeStringToFlags(flags);
2091
2073
  if (flags & 64) {
2092
2074
  mode = (mode & 4095) | 32768;
2093
2075
  } else {
@@ -2164,11 +2146,6 @@ async function sqlite3InitModule(moduleArg = {}) {
2164
2146
  if (created) {
2165
2147
  FS.chmod(node, mode & 0o777);
2166
2148
  }
2167
- if (Module['logReadFiles'] && !(flags & 1)) {
2168
- if (!(path in FS.readFiles)) {
2169
- FS.readFiles[path] = 1;
2170
- }
2171
- }
2172
2149
  return stream;
2173
2150
  },
2174
2151
  close(stream) {
@@ -2323,14 +2300,8 @@ async function sqlite3InitModule(moduleArg = {}) {
2323
2300
  writeFile(path, data, opts = {}) {
2324
2301
  opts.flags = opts.flags || 577;
2325
2302
  var stream = FS.open(path, opts.flags, opts.mode);
2326
- if (typeof data == 'string') {
2327
- data = new Uint8Array(intArrayFromString(data, true));
2328
- }
2329
- if (ArrayBuffer.isView(data)) {
2330
- FS.write(stream, data, 0, data.byteLength, undefined, opts.canOwn);
2331
- } else {
2332
- abort('Unsupported data type');
2333
- }
2303
+ data = FS_fileDataToTypedArray(data);
2304
+ FS.write(stream, data, 0, data.byteLength, undefined, opts.canOwn);
2334
2305
  FS.close(stream);
2335
2306
  },
2336
2307
  cwd: () => FS.currentPath,
@@ -2541,12 +2512,7 @@ async function sqlite3InitModule(moduleArg = {}) {
2541
2512
  var mode = FS_getMode(canRead, canWrite);
2542
2513
  var node = FS.create(path, mode);
2543
2514
  if (data) {
2544
- if (typeof data == 'string') {
2545
- var arr = new Array(data.length);
2546
- for (var i = 0, len = data.length; i < len; ++i)
2547
- arr[i] = data.charCodeAt(i);
2548
- data = arr;
2549
- }
2515
+ data = FS_fileDataToTypedArray(data);
2550
2516
 
2551
2517
  FS.chmod(node, mode | 146);
2552
2518
  var stream = FS.open(node, 577);
@@ -9719,17 +9685,17 @@ async function sqlite3InitModule(moduleArg = {}) {
9719
9685
  });
9720
9686
  globalThis.sqlite3ApiBootstrap.initializers.push(function (sqlite3) {
9721
9687
  sqlite3.version = {
9722
- libVersion: '3.51.1',
9723
- libVersionNumber: 3051001,
9688
+ libVersion: '3.51.3',
9689
+ libVersionNumber: 3051003,
9724
9690
  sourceId:
9725
- '2025-11-28 17:28:25 281fc0e9afc38674b9b0991943b9e9d1e64c6cbdb133d35f6f5c87ff6af3alt1',
9726
- downloadVersion: 3510100,
9691
+ '2026-03-13 10:38:09 737ae4a34738ffa0c3ff7f9bb18df914dd1cad163f28fd6b6e114a344fe6alt1',
9692
+ downloadVersion: 3510300,
9727
9693
  scm: {
9728
9694
  'sha3-256':
9729
- '281fc0e9afc38674b9b0991943b9e9d1e64c6cbdb133d35f6f5c87ff6af3alt1',
9695
+ '737ae4a34738ffa0c3ff7f9bb18df914dd1cad163f28fd6b6e114a344fe6alt1',
9730
9696
  branch: 'branch-3.51',
9731
- tags: 'release version-3.51.1',
9732
- datetime: '2025-11-28T17:28:25.933Z',
9697
+ tags: 'release version-3.51.3',
9698
+ datetime: '2026-03-13T10:38:09.694Z',
9733
9699
  },
9734
9700
  };
9735
9701
  });
@@ -10264,11 +10230,11 @@ async function sqlite3InitModule(moduleArg = {}) {
10264
10230
  stmt = null;
10265
10231
  }
10266
10232
  } finally {
10267
- wasm.scopedAllocPop(stack);
10268
10233
  if (stmt) {
10269
10234
  __execLock.delete(stmt);
10270
10235
  stmt.finalize();
10271
10236
  }
10237
+ wasm.scopedAllocPop(stack);
10272
10238
  }
10273
10239
  return arg.returnVal();
10274
10240
  },
package/dist/sqlite3.wasm CHANGED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@birchill/nice-sqlite-wasm",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",
@@ -23,5 +23,5 @@
23
23
  "publishConfig": {
24
24
  "provenance": true
25
25
  },
26
- "publishedAt": "2026-01-14T05:14:37.216Z"
26
+ "publishedAt": "2026-03-20T02:25:21.222Z"
27
27
  }