browser-sqlite 1.0.0-rc.3 → 1.0.0-rc.5
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/NOTICE +56 -0
- package/README.md +112 -104
- package/dist/LICENSE +21 -0
- package/dist/NOTICE +56 -0
- package/dist/abandon.d.ts +77 -0
- package/dist/api.d.ts +426 -0
- package/dist/bulk.d.ts +57 -0
- package/dist/capabilities.d.ts +23 -0
- package/dist/client.d.ts +221 -0
- package/dist/credits.d.ts +31 -0
- package/dist/{esm/src/debug.d.ts → debug.d.ts} +21 -10
- package/dist/delete.d.ts +48 -0
- package/dist/epochs.d.ts +85 -0
- package/dist/errors.d.ts +76 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/inspect.d.ts +96 -0
- package/dist/locks.d.ts +172 -0
- package/dist/logger.d.ts +24 -0
- package/dist/pool.d.ts +191 -0
- package/dist/queries.d.ts +65 -0
- package/dist/scheduler.d.ts +145 -0
- package/dist/sqlite-codes.d.ts +154 -0
- package/dist/supervisor.d.ts +17 -0
- package/dist/transaction.d.ts +61 -0
- package/dist/types.d.ts +642 -0
- package/dist/utils.d.ts +156 -0
- package/dist/worker/cloneable.d.ts +25 -0
- package/dist/worker/probes.d.ts +26 -0
- package/dist/worker/sqlite-code.d.ts +9 -0
- package/dist/worker/statement-cache.d.ts +36 -0
- package/dist/worker/wa-sqlite-async.wasm +0 -0
- package/dist/worker/wa-sqlite-jspi.wasm +0 -0
- package/dist/worker/wa-sqlite.wasm +0 -0
- package/dist/worker/worker.js +11 -0
- package/dist/worker/worker.js.map +1 -0
- package/package.json +46 -22
- package/dist/esm/index.js +0 -424
- package/dist/esm/rslib.config.d.ts +0 -2
- package/dist/esm/rstest.config.d.ts +0 -2
- package/dist/esm/src/client.d.ts +0 -332
- package/dist/esm/src/index.d.ts +0 -1
- package/dist/esm/src/orchestrator.d.ts +0 -87
- package/dist/esm/src/types.d.ts +0 -83
- package/dist/esm/src/utils.d.ts +0 -6
- /package/dist/{esm/src → worker}/worker.d.ts +0 -0
package/NOTICE
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
THIRD-PARTY NOTICES
|
|
2
|
+
===================
|
|
3
|
+
|
|
4
|
+
browser-sqlite is distributed under the MIT License; see LICENSE.
|
|
5
|
+
|
|
6
|
+
Its published worker artifact (dist/worker/worker.js) has third-party code
|
|
7
|
+
bundled into it, and ships compiled WebAssembly built from third-party
|
|
8
|
+
sources (dist/worker/wa-sqlite.wasm, wa-sqlite-async.wasm, wa-sqlite-jspi.wasm).
|
|
9
|
+
The notices below travel with those files and must be preserved in any
|
|
10
|
+
redistribution.
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
-------------------------------------------------------------------------------
|
|
14
|
+
wa-sqlite — https://github.com/rhashimoto/wa-sqlite
|
|
15
|
+
-------------------------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
The JavaScript glue and the VFS implementations bundled into
|
|
18
|
+
dist/worker/worker.js, and the .wasm binaries beside it, are produced by
|
|
19
|
+
wa-sqlite.
|
|
20
|
+
|
|
21
|
+
MIT License
|
|
22
|
+
|
|
23
|
+
Copyright (c) 2023 Roy T. Hashimoto
|
|
24
|
+
|
|
25
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
26
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
27
|
+
in the Software without restriction, including without limitation the rights
|
|
28
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
29
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
30
|
+
furnished to do so, subject to the following conditions:
|
|
31
|
+
|
|
32
|
+
The above copyright notice and this permission notice shall be included in all
|
|
33
|
+
copies or substantial portions of the Software.
|
|
34
|
+
|
|
35
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
36
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
37
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
38
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
39
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
40
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
41
|
+
SOFTWARE.
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
-------------------------------------------------------------------------------
|
|
45
|
+
SQLite — https://sqlite.org
|
|
46
|
+
-------------------------------------------------------------------------------
|
|
47
|
+
|
|
48
|
+
The .wasm binaries are builds of SQLite. SQLite is in the public domain and
|
|
49
|
+
requires no attribution; the customary blessing is reproduced here.
|
|
50
|
+
|
|
51
|
+
The author disclaims copyright to this source code. In place of
|
|
52
|
+
a legal notice, here is a blessing:
|
|
53
|
+
|
|
54
|
+
May you do good and not evil.
|
|
55
|
+
May you find forgiveness for yourself and forgive others.
|
|
56
|
+
May you share freely, never taking more than you give.
|
package/README.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
A persistent SQLite database that lives in your browser — yes, for real. Powered by [wa-sqlite](https://github.com/rhashimoto/wa-sqlite) (WebAssembly), built for (read) concurrency.
|
|
4
4
|
|
|
5
|
+
A client stores its data through a wa-sqlite VFS, which decides where that data lives.
|
|
6
|
+
**[Read the VFS page](VFS.md)** to compare them, then
|
|
7
|
+
**[run the benchmarks in your own browser](https://lalexdotcom.github.io/browser-sqlite/)**.
|
|
8
|
+
|
|
5
9
|
## Install
|
|
6
10
|
|
|
7
11
|
```bash
|
|
@@ -10,152 +14,156 @@ npm install browser-sqlite
|
|
|
10
14
|
pnpm add browser-sqlite
|
|
11
15
|
```
|
|
12
16
|
|
|
13
|
-
Requires a bundler that supports Web Workers with dynamic imports
|
|
17
|
+
Requires a bundler that supports Web Workers with dynamic imports — or no bundler at all.
|
|
18
|
+
|
|
19
|
+
<details>
|
|
20
|
+
<summary><b>Bundler Configuration</b></summary>
|
|
14
21
|
|
|
15
|
-
|
|
22
|
+
Works with no configuration under **rsbuild 1+**, **rspack 1+**, **Parcel 2+**, **Vite 8+**, **webpack 5.101+** — and with no bundler at all.
|
|
16
23
|
|
|
17
|
-
|
|
24
|
+
Works under **Vite 6.1 to 7** with the following config, which only the dev server needs:
|
|
18
25
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
| `IDBBatchAtomicVFS` | IndexedDB | None | Fallback when OPFS is unavailable (older browsers, some mobile environments). |
|
|
26
|
+
```typescript
|
|
27
|
+
// vite.config.ts
|
|
28
|
+
export default defineConfig({
|
|
29
|
+
optimizeDeps: { exclude: ['browser-sqlite'] },
|
|
30
|
+
});
|
|
31
|
+
```
|
|
26
32
|
|
|
27
|
-
|
|
33
|
+
Another bundler will likely work — the worker and its `.wasm` are reached through plain, statically analysable URLs — but may need configuration of its own.
|
|
28
34
|
|
|
29
|
-
|
|
35
|
+
The `.wasm` are read from beside `worker.js`. If a build separates them, or you move them by hand, point at them with [`wasmUrl`](API.md#options).
|
|
36
|
+
</details>
|
|
37
|
+
|
|
38
|
+
## Browser support
|
|
39
|
+
|
|
40
|
+
| Chrome | Firefox | Safari |
|
|
41
|
+
|---|---|---|
|
|
42
|
+
| 92+ | 95+ | 15.4+ |
|
|
43
|
+
|
|
44
|
+
Cross-origin isolation is worth adding where you control your headers: it is what lets an
|
|
45
|
+
aborted call stop a running statement when using a VFS with `sync` build. See
|
|
46
|
+
[Aborting a call](#aborting-a-call).
|
|
30
47
|
|
|
31
48
|
## Usage
|
|
32
49
|
|
|
33
|
-
|
|
50
|
+
Read the [detailed API documentation](API.md) for the full description.
|
|
34
51
|
|
|
35
52
|
```typescript
|
|
36
53
|
import { createSQLiteClient } from 'browser-sqlite';
|
|
37
54
|
|
|
38
|
-
const db = createSQLiteClient('myapp.sqlite', {
|
|
39
|
-
poolSize: 2, // number of worker threads (default: 2)
|
|
40
|
-
vfs: 'OPFSPermutedVFS', // VFS selection (default: 'OPFSPermutedVFS')
|
|
41
|
-
pragmas: { // SQLite PRAGMAs applied on open
|
|
42
|
-
journal_mode: 'WAL',
|
|
43
|
-
synchronous: 'NORMAL',
|
|
44
|
-
},
|
|
45
|
-
});
|
|
46
|
-
```
|
|
55
|
+
const db = createSQLiteClient('myapp.sqlite', { vfs: 'OPFSAdaptiveVFS' });
|
|
47
56
|
|
|
48
|
-
|
|
57
|
+
await db.write('CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)');
|
|
58
|
+
await db.write('INSERT INTO users (name) VALUES (?)', ['Alice']);
|
|
49
59
|
|
|
50
|
-
|
|
60
|
+
const users = await db.read<{ id: number; name: string }>('SELECT id, name FROM users');
|
|
51
61
|
|
|
52
|
-
|
|
53
|
-
|
|
62
|
+
for await (const row of db.stream<{ id: number; name: string }>('SELECT * FROM users')) {
|
|
63
|
+
process(row);
|
|
64
|
+
}
|
|
54
65
|
|
|
55
|
-
|
|
56
|
-
'SELECT id, name FROM users WHERE active = ?',
|
|
57
|
-
[1],
|
|
58
|
-
);
|
|
59
|
-
// users: User[]
|
|
66
|
+
await db.close();
|
|
60
67
|
```
|
|
61
68
|
|
|
62
|
-
|
|
69
|
+
[*client*.id](API.md#clientid) · [*client*.name](API.md#clientname) · [*client*.file](API.md#clientfile) · [*client*.vfs](API.md#clientvfs) · [*client*.build](API.md#clientbuild) · [*client*.poolSize](API.md#clientpoolsize)
|
|
63
70
|
|
|
64
|
-
|
|
71
|
+
[createSQLiteClient()](API.md#createsqliteclient) · [*client*.read()](API.md#clientread) · [*client*.write()](API.md#clientwrite) · [*client*.stream()](API.md#clientstream) · [*client*.chunk()](API.md#clientchunk) · [*client*.first()](API.md#clientfirst) · [*client*.transaction()](API.md#clienttransaction) · [*client*.bulkWrite()](API.md#clientbulkwrite) · [*client*.output()](API.md#clientoutput) · [*client*.inspect()](API.md#clientinspect) · [*client*.close()](API.md#clientclose) · [deleteDatabase()](API.md#deletedatabase) · [inspectDatabase()](API.md#inspectdatabase)
|
|
65
72
|
|
|
66
|
-
|
|
67
|
-
const { affected } = await db.write(
|
|
68
|
-
'INSERT INTO users (name, email) VALUES (?, ?)',
|
|
69
|
-
['Alice', 'alice@example.com'],
|
|
70
|
-
);
|
|
71
|
-
// affected: number of rows inserted
|
|
72
|
-
```
|
|
73
|
+
## Storage
|
|
73
74
|
|
|
74
|
-
|
|
75
|
+
The VFS decides *where* your database is written.
|
|
76
|
+
[See every available VFS on the dedicated page](VFS.md), with their pros, their cons, their
|
|
77
|
+
limitations and their browser compatibility.
|
|
75
78
|
|
|
76
|
-
|
|
79
|
+
`OPFSWriteAheadVFS` and `OPFSAdaptiveVFS` are the recommended options.
|
|
77
80
|
|
|
78
|
-
|
|
79
|
-
// Worker is held for the full generator lifetime — always exhaust or break.
|
|
80
|
-
for await (const chunk of db.stream<User>(
|
|
81
|
-
'SELECT * FROM large_table',
|
|
82
|
-
[],
|
|
83
|
-
{ chunkSize: 100 },
|
|
84
|
-
)) {
|
|
85
|
-
processChunk(chunk); // chunk is User[]
|
|
86
|
-
}
|
|
87
|
-
```
|
|
81
|
+
[`OPFSWriteAheadVFS`](VFS.md#opfswriteaheadvfs) · [`OPFSAdaptiveVFS`](VFS.md#opfsadaptivevfs) · [`OPFSCoopSyncVFS`](VFS.md#opfscoopsyncvfs) · [`AccessHandlePoolVFS`](VFS.md#accesshandlepoolvfs) · [`IDBBatchAtomicVFS`](VFS.md#idbbatchatomicvfs) · [`IDBMirrorVFS`](VFS.md#idbmirrorvfs) · [`OPFSAnyContextVFS`](VFS.md#opfsanycontextvfs) · [`MemoryVFS`](VFS.md#memoryvfs) · [`MemoryAsyncVFS`](VFS.md#memoryasyncvfs)
|
|
88
82
|
|
|
89
|
-
|
|
83
|
+
## Guarantees
|
|
90
84
|
|
|
91
|
-
###
|
|
85
|
+
### Reads run concurrently
|
|
92
86
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
'SELECT * FROM users WHERE id = ?',
|
|
96
|
-
[42],
|
|
97
|
-
);
|
|
98
|
-
// user: User | undefined
|
|
99
|
-
```
|
|
87
|
+
Every read is dispatched to whichever worker in the pool is free, so several run at once.
|
|
88
|
+
Writes take a dedicated writer worker instead, one at a time.
|
|
100
89
|
|
|
101
|
-
|
|
90
|
+
### Read-your-own-writes
|
|
102
91
|
|
|
103
|
-
|
|
92
|
+
It holds within a tab and across tabs. Once a write has resolved, any read issued afterwards
|
|
93
|
+
observes it — from that client, from any other client in the same tab, and from any other tab
|
|
94
|
+
on the same database, whatever the pool size. A worker that has not yet observed the latest
|
|
95
|
+
commit runs one discarded statement that opens a real read transaction before it serves the
|
|
96
|
+
query; that costs one extra worker round-trip on each worker's first statement after a write,
|
|
97
|
+
and nothing under read-only load. `poolSize: 1` and reading inside the same `transaction()`
|
|
98
|
+
remain valid, they are no longer required.
|
|
104
99
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
- `db.output(table, schema, options)` — drops, recreates, and populates a table from a schema definition
|
|
108
|
-
- `db.transaction(callback, options)` — wraps operations in a SQLite transaction with auto-commit and rollback
|
|
100
|
+
The one exception is [`IDBMirrorVFS`](VFS.md#idbmirrorvfs), which does not hold it across
|
|
101
|
+
tabs.
|
|
109
102
|
|
|
110
|
-
###
|
|
103
|
+
### Writes are serialized
|
|
111
104
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
105
|
+
A write, a write transaction, and each batch of a `bulkWrite` take one lock per database
|
|
106
|
+
across the whole origin, so a second writer **waits** rather than failing — between clients
|
|
107
|
+
and between tabs alike. The wait is unbounded and first-come-first-served: pass a `signal` if
|
|
108
|
+
you would rather fail than wait. A write transaction holds that lock for the whole of its
|
|
109
|
+
callback, so a callback that never returns blocks every other writer in the origin, not only
|
|
110
|
+
its own client. **A `bulkWrite` takes the lock per batch and commits per batch**, so another
|
|
111
|
+
client's write can land between two of its batches — use `tx.bulkWrite` where you need all or
|
|
112
|
+
nothing.
|
|
115
113
|
|
|
116
|
-
|
|
114
|
+
## Known Limitations
|
|
117
115
|
|
|
118
|
-
|
|
116
|
+
Some VFS have limitations of their own — see [the detailed VFS page](VFS.md#vfs-reference).
|
|
117
|
+
What follows holds on all of them.
|
|
119
118
|
|
|
120
|
-
|
|
119
|
+
### Aborting a call
|
|
121
120
|
|
|
122
|
-
|
|
121
|
+
An abort does not always stop the work, and your hosting decides. On the `sync` build, a
|
|
122
|
+
`signal` or a `timeout` rejects your promise straight away, but the statement runs to its
|
|
123
|
+
end on its worker, which stays unavailable until it does.
|
|
123
124
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
125
|
+
Two ways out — serving the page cross-origin isolated, or `build: 'async'` — and what each
|
|
126
|
+
one costs are under [Interrupting a call](API.md#interrupting-a-call).
|
|
127
|
+
|
|
128
|
+
### Deleting a database
|
|
128
129
|
|
|
129
|
-
|
|
130
|
+
A database that any client still holds cannot be deleted, in this tab or another, on every
|
|
131
|
+
VFS. More on the dedicated [`deleteDatabase`](API.md#deletedatabase) API entry.
|
|
130
132
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
133
|
+
## Development
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
pnpm install
|
|
137
|
+
pnpm build # rslib → dist/
|
|
138
|
+
pnpm test # unit (Node) + browser (Playwright/Chromium)
|
|
139
|
+
pnpm check # biome, with --write
|
|
135
140
|
```
|
|
136
141
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
next();
|
|
143
|
-
});
|
|
142
|
+
Two suites run on demand rather than on every change:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
pnpm test:conformance # every declared (vfs, build) pair through six invariants
|
|
146
|
+
pnpm test:consumer # packs the tarball and drives four bundler modes
|
|
144
147
|
```
|
|
145
148
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
149
|
+
### The benchmark page
|
|
150
|
+
|
|
151
|
+
`scripts/bench/html/index.html` is the page published above. It is one self-contained file
|
|
152
|
+
served beside a verbatim copy of `dist/`, so it exercises the library exactly as
|
|
153
|
+
a consumer would with no bundler at all.
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
pnpm bench:dev # build, serve on http://127.0.0.1:8099, rebuild on change
|
|
157
|
+
pnpm bench:serve # same without the watch
|
|
158
|
+
pnpm bench:build # assemble _site/ only
|
|
155
159
|
```
|
|
156
160
|
|
|
157
|
-
|
|
161
|
+
`http://127.0.0.1` is a secure context, so OPFS works with no certificate — no
|
|
162
|
+
TLS setup is needed to develop against it. A phone on the LAN is a different
|
|
163
|
+
matter: it is not a secure context, so OPFS is unavailable there and a tunnel
|
|
164
|
+
(or the published page) is the way to test a real device.
|
|
158
165
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
166
|
+
`node scripts/bench/check.mjs [chromium|firefox] [--all]` drives the page under
|
|
167
|
+
Playwright and asserts that it still works — it is run by hand and deliberately
|
|
168
|
+
not wired into CI. It checks the *page*, never that a VFS passes: a red cell can
|
|
169
|
+
be a correct report about the engine you are on.
|
package/dist/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 lalexdotcom
|
|
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/dist/NOTICE
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
THIRD-PARTY NOTICES
|
|
2
|
+
===================
|
|
3
|
+
|
|
4
|
+
browser-sqlite is distributed under the MIT License; see LICENSE.
|
|
5
|
+
|
|
6
|
+
Its published worker artifact (dist/worker/worker.js) has third-party code
|
|
7
|
+
bundled into it, and ships compiled WebAssembly built from third-party
|
|
8
|
+
sources (dist/worker/wa-sqlite.wasm, wa-sqlite-async.wasm, wa-sqlite-jspi.wasm).
|
|
9
|
+
The notices below travel with those files and must be preserved in any
|
|
10
|
+
redistribution.
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
-------------------------------------------------------------------------------
|
|
14
|
+
wa-sqlite — https://github.com/rhashimoto/wa-sqlite
|
|
15
|
+
-------------------------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
The JavaScript glue and the VFS implementations bundled into
|
|
18
|
+
dist/worker/worker.js, and the .wasm binaries beside it, are produced by
|
|
19
|
+
wa-sqlite.
|
|
20
|
+
|
|
21
|
+
MIT License
|
|
22
|
+
|
|
23
|
+
Copyright (c) 2023 Roy T. Hashimoto
|
|
24
|
+
|
|
25
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
26
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
27
|
+
in the Software without restriction, including without limitation the rights
|
|
28
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
29
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
30
|
+
furnished to do so, subject to the following conditions:
|
|
31
|
+
|
|
32
|
+
The above copyright notice and this permission notice shall be included in all
|
|
33
|
+
copies or substantial portions of the Software.
|
|
34
|
+
|
|
35
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
36
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
37
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
38
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
39
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
40
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
41
|
+
SOFTWARE.
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
-------------------------------------------------------------------------------
|
|
45
|
+
SQLite — https://sqlite.org
|
|
46
|
+
-------------------------------------------------------------------------------
|
|
47
|
+
|
|
48
|
+
The .wasm binaries are builds of SQLite. SQLite is in the public domain and
|
|
49
|
+
requires no attribution; the customary blessing is reproduced here.
|
|
50
|
+
|
|
51
|
+
The author disclaims copyright to this source code. In place of
|
|
52
|
+
a legal notice, here is a blessing:
|
|
53
|
+
|
|
54
|
+
May you do good and not evil.
|
|
55
|
+
May you find forgiveness for yourself and forgive others.
|
|
56
|
+
May you share freely, never taking more than you give.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { PoolWorker } from './pool';
|
|
2
|
+
/**
|
|
3
|
+
* Whether this cleanup has already run.
|
|
4
|
+
*
|
|
5
|
+
* A plain object rather than a boolean because the held value must observe a
|
|
6
|
+
* change the generator makes after registration. Three routes reach the
|
|
7
|
+
* cleanup — the registry, the abort listener and the generator's own `finally`
|
|
8
|
+
* — and whichever arrives first closes the door on the other two.
|
|
9
|
+
*
|
|
10
|
+
* What it deliberately does NOT record is whether the query ever started. That
|
|
11
|
+
* answers "did this generator run", where the only question that matters is
|
|
12
|
+
* "is the worker still serving this query" — and the worker is the one that
|
|
13
|
+
* knows, which is why `interrupt()` is asked rather than told.
|
|
14
|
+
*/
|
|
15
|
+
export type AbandonState = {
|
|
16
|
+
done: boolean;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* What the cleanup needs, and all it may hold.
|
|
20
|
+
*
|
|
21
|
+
* **It must never refer to the registered generator.** A `FinalizationRegistry`
|
|
22
|
+
* held value that reaches its own target keeps the target alive and the
|
|
23
|
+
* callback then never fires. Every field here points downward or sideways: the
|
|
24
|
+
* worker and the transport iterator are reachable from the pool anyway, `state`
|
|
25
|
+
* is a plain flag, `detach` closes over the caller's signal and its listener,
|
|
26
|
+
* and `release` is the owning layer's teardown.
|
|
27
|
+
*/
|
|
28
|
+
export type Abandoned = {
|
|
29
|
+
worker: Pick<PoolWorker, 'interrupt'>;
|
|
30
|
+
iterator: {
|
|
31
|
+
return: (value?: undefined) => Promise<unknown>;
|
|
32
|
+
};
|
|
33
|
+
state: AbandonState;
|
|
34
|
+
/**
|
|
35
|
+
* Removes the abort listener that carries this very cleanup. Without it a
|
|
36
|
+
* listener stays armed on a signal the CALLER owns, long after the query it
|
|
37
|
+
* belonged to has ended — and fires against whatever the worker is doing
|
|
38
|
+
* then.
|
|
39
|
+
*/
|
|
40
|
+
detach: () => void;
|
|
41
|
+
release?: (() => void) | undefined;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* What the `finally` of `queries.chunk` would have done, for a generator that
|
|
45
|
+
* will never run it.
|
|
46
|
+
*
|
|
47
|
+
* The order is that `finally`'s and for its reason: `interrupt()` first, so the
|
|
48
|
+
* queued `return()` is not parked behind a `next()` that will not settle.
|
|
49
|
+
*
|
|
50
|
+
* **Nothing here may assume the worker is still ours.** This runs at a moment
|
|
51
|
+
* nobody chose — a collection, or the caller tidying up its own controller —
|
|
52
|
+
* and by then the worker may be serving a query that has nothing to do with
|
|
53
|
+
* this one. So the transport is named in both calls: `interrupt(iterator)` is a
|
|
54
|
+
* no-op unless the worker is still serving it, and `iterator.return()` resumes
|
|
55
|
+
* a transport whose own `finally` makes the same check. `return()` on a
|
|
56
|
+
* generator whose body never ran is a no-op besides, the body having never
|
|
57
|
+
* entered its `try`.
|
|
58
|
+
*
|
|
59
|
+
* `release` is the exception and runs unconditionally: it is the owning layer's
|
|
60
|
+
* resource — a lease, a timer, a merge teardown — and it is owed whatever the
|
|
61
|
+
* worker has since moved on to.
|
|
62
|
+
*/
|
|
63
|
+
export declare const reclaim: ({ worker, iterator, state, detach, release, }: Abandoned) => void;
|
|
64
|
+
export type AbandonRegistry = {
|
|
65
|
+
/** Watch `target`; `held` is what the cleanup receives, `token` unregisters. */
|
|
66
|
+
watch: (target: object, held: Abandoned, token: object) => void;
|
|
67
|
+
/** The generator ended by an ordinary route — there is nothing to reclaim. */
|
|
68
|
+
forget: (token: object) => void;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* `run` is injected so that tests drive the cleanup without a collection.
|
|
72
|
+
* Nothing else here is observable: a `FinalizationRegistry` fires when the
|
|
73
|
+
* engine decides, which is not a schedule a test can assert against.
|
|
74
|
+
*/
|
|
75
|
+
export declare const createAbandonRegistry: (run?: (held: Abandoned) => void) => AbandonRegistry;
|
|
76
|
+
/** The one this library uses. */
|
|
77
|
+
export declare const abandonRegistry: AbandonRegistry;
|