rqlite-js 2.6.0 → 3.0.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 +207 -29
- package/dist/index.cjs +904 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +329 -0
- package/dist/index.d.ts +329 -0
- package/dist/index.js +865 -0
- package/dist/index.js.map +1 -0
- package/docs/MIGRATION-v2-to-v3.md +71 -0
- package/package.json +56 -35
- package/src/api/backup/index.ts +69 -0
- package/src/api/backup-formats.ts +8 -0
- package/src/api/client/index.ts +97 -0
- package/src/api/consistency-levels.ts +10 -0
- package/src/api/data/index.ts +87 -0
- package/src/api/paths.ts +13 -0
- package/src/api/query-params.ts +15 -0
- package/src/api/results/data-result-error.ts +41 -0
- package/src/api/results/data-result.ts +91 -0
- package/src/api/results/data-results.ts +91 -0
- package/src/api/results/index.ts +7 -0
- package/src/api/results/result-fields.ts +14 -0
- package/src/api/status/index.ts +53 -0
- package/src/http-request/auth-keys.ts +14 -0
- package/src/http-request/content-types.ts +4 -0
- package/src/http-request/errors.ts +17 -0
- package/src/http-request/http-headers.ts +19 -0
- package/src/http-request/http-methods.ts +12 -0
- package/src/http-request/index.ts +676 -0
- package/src/http-request/retryable.ts +41 -0
- package/src/index.ts +38 -0
- package/lib/api/backup/index.js +0 -72
- package/lib/api/backup/index.js.map +0 -1
- package/lib/api/backup/test.unit.js +0 -45
- package/lib/api/backup/test.unit.js.map +0 -1
- package/lib/api/backup-formats.js +0 -16
- package/lib/api/backup-formats.js.map +0 -1
- package/lib/api/client/index.js +0 -105
- package/lib/api/client/index.js.map +0 -1
- package/lib/api/client/test.unit.js +0 -53
- package/lib/api/client/test.unit.js.map +0 -1
- package/lib/api/consistency-levels.js +0 -30
- package/lib/api/consistency-levels.js.map +0 -1
- package/lib/api/data/index.js +0 -108
- package/lib/api/data/index.js.map +0 -1
- package/lib/api/data/test.unit.js +0 -98
- package/lib/api/data/test.unit.js.map +0 -1
- package/lib/api/paths.js +0 -33
- package/lib/api/paths.js.map +0 -1
- package/lib/api/query-params.js +0 -43
- package/lib/api/query-params.js.map +0 -1
- package/lib/api/results/data-result-error.js +0 -62
- package/lib/api/results/data-result-error.js.map +0 -1
- package/lib/api/results/data-result.js +0 -141
- package/lib/api/results/data-result.js.map +0 -1
- package/lib/api/results/data-results.js +0 -142
- package/lib/api/results/data-results.js.map +0 -1
- package/lib/api/results/index.js +0 -8
- package/lib/api/results/index.js.map +0 -1
- package/lib/api/results/result-fields.js +0 -47
- package/lib/api/results/result-fields.js.map +0 -1
- package/lib/api/results/test.unit.js +0 -238
- package/lib/api/results/test.unit.js.map +0 -1
- package/lib/api/status/index.js +0 -67
- package/lib/api/status/index.js.map +0 -1
- package/lib/api/status/test.unit.js +0 -57
- package/lib/api/status/test.unit.js.map +0 -1
- package/lib/http-request/auth-keys.js +0 -15
- package/lib/http-request/auth-keys.js.map +0 -1
- package/lib/http-request/content-types.js +0 -5
- package/lib/http-request/content-types.js.map +0 -1
- package/lib/http-request/errors.js +0 -17
- package/lib/http-request/errors.js.map +0 -1
- package/lib/http-request/http-headers.js +0 -20
- package/lib/http-request/http-headers.js.map +0 -1
- package/lib/http-request/http-methods.js +0 -40
- package/lib/http-request/http-methods.js.map +0 -1
- package/lib/http-request/index.js +0 -764
- package/lib/http-request/index.js.map +0 -1
- package/lib/http-request/retryable.js +0 -42
- package/lib/http-request/retryable.js.map +0 -1
- package/lib/http-request/test.unit.js +0 -560
- package/lib/http-request/test.unit.js.map +0 -1
- package/lib/index.js +0 -39
- package/lib/index.js.map +0 -1
- package/lib/test/api-data-execute-nock.js +0 -142
- package/lib/test/api-data-execute-nock.js.map +0 -1
- package/lib/test/api-data-query-nock.js +0 -210
- package/lib/test/api-data-query-nock.js.map +0 -1
- package/lib/test/backups/backup-nock.js +0 -29
- package/lib/test/backups/backup-nock.js.map +0 -1
- package/lib/test/backups/restore-nock.js +0 -30
- package/lib/test/backups/restore-nock.js.map +0 -1
- package/lib/test/env.js +0 -15
- package/lib/test/env.js.map +0 -1
- package/lib/test/unit/index.unit.js +0 -27
- package/lib/test/unit/index.unit.js.map +0 -1
- package/lib/test.integration.js +0 -238
- package/lib/test.integration.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,22 +1,31 @@
|
|
|
1
1
|
# rqlite-js · [](https://www.npmjs.com/package/rqlite-js) · [](https://github.com/rqlite/rqlite-js/actions/workflows/ci.yml)
|
|
2
2
|
|
|
3
|
-
A promise-based client
|
|
3
|
+
A promise-based TypeScript/JavaScript client for [rqlite](https://rqlite.io) — the lightweight, distributed database built on SQLite. It speaks the HTTP API (`/db/query`, `/db/execute`, `/db/backup`, `/status`) and returns structured results you can use in Node or the browser.
|
|
4
4
|
|
|
5
|
-
**
|
|
5
|
+
**This package does not generate SQL.** Pass SQL strings (or rqlite parameterized statement arrays). Build those strings however you like — by hand, or with any SQL builder you choose.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
**Prefer parameterized statements for anything that includes user or external input.** Interpolating values into SQL strings (`WHERE name = "${name}"`) risks SQL injection. Use rqlite’s bound-parameter form (`[["SELECT … WHERE name = ?", name]]`) or equivalent bindings from your own SQL tooling. Treat string-concatenated SQL as unsafe unless the values are strictly trusted constants you control.
|
|
8
|
+
|
|
9
|
+
**Requirements:** Node.js `>= 20.19`. **Zero runtime dependencies** (native `fetch`). Types ship in-box. CI tests Node 20–24; Docker integrations use Node 24 against **rqlite 10.x** (`rqlite/rqlite:10.6.6`).
|
|
10
|
+
|
|
11
|
+
Upgrading from v2? See [docs/MIGRATION-v2-to-v3.md](docs/MIGRATION-v2-to-v3.md).
|
|
12
|
+
|
|
13
|
+
Official rqlite docs:
|
|
8
14
|
|
|
9
15
|
- [Accessing rqlite (HTTP API)](https://rqlite.io/docs/api/api/)
|
|
10
16
|
- [Read consistency](https://rqlite.io/docs/api/read-consistency/)
|
|
17
|
+
- [Bulk writes](https://rqlite.io/docs/api/bulk-api/)
|
|
11
18
|
- [Backup and restore](https://rqlite.io/docs/guides/backup/)
|
|
12
19
|
- [Monitoring / status](https://rqlite.io/docs/guides/monitoring-rqlite/)
|
|
13
20
|
|
|
14
21
|
## Features
|
|
15
22
|
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
23
|
+
- Dual **ESM + CJS** builds with TypeScript declarations (import from `rqlite-js` only — no deep paths)
|
|
24
|
+
- Native `fetch` HTTP (optional undici `Dispatcher` for keepalive)
|
|
25
|
+
- Follow 301/302 redirects to the leader; round-robin hosts for non-leader reads
|
|
26
|
+
- Single or bulk `query` / `execute`, parameterized statements, consistency levels, transactions
|
|
27
|
+
- `DataResults` helpers (`get`, `toObject`, `toArray`, `hasError`, `getFirstError` / `error_v2`)
|
|
28
|
+
- Backup / restore streams and `/status` clients
|
|
20
29
|
|
|
21
30
|
## Install
|
|
22
31
|
|
|
@@ -24,6 +33,16 @@ See the official docs:
|
|
|
24
33
|
npm install rqlite-js
|
|
25
34
|
```
|
|
26
35
|
|
|
36
|
+
```javascript
|
|
37
|
+
// ESM
|
|
38
|
+
import { DataApiClient } from 'rqlite-js'
|
|
39
|
+
|
|
40
|
+
// CommonJS
|
|
41
|
+
const { DataApiClient } = require('rqlite-js')
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Consumers get **no transitive runtime packages**. Build tooling stays in this repo’s `devDependencies` only.
|
|
45
|
+
|
|
27
46
|
## Quick start
|
|
28
47
|
|
|
29
48
|
```javascript
|
|
@@ -31,7 +50,9 @@ import { DataApiClient } from 'rqlite-js'
|
|
|
31
50
|
|
|
32
51
|
const dataApiClient = new DataApiClient('http://localhost:4001')
|
|
33
52
|
|
|
34
|
-
await dataApiClient.execute(
|
|
53
|
+
await dataApiClient.execute(
|
|
54
|
+
'CREATE TABLE IF NOT EXISTS foo (id INTEGER NOT NULL PRIMARY KEY, name TEXT)',
|
|
55
|
+
)
|
|
35
56
|
const insert = await dataApiClient.execute('INSERT INTO foo(name) VALUES("fiona")')
|
|
36
57
|
if (insert.hasError()) {
|
|
37
58
|
throw insert.getFirstError()
|
|
@@ -41,14 +62,107 @@ const select = await dataApiClient.query(`SELECT id, name FROM foo WHERE id=${id
|
|
|
41
62
|
console.log(select.get(0).toObject()) // { id: 1, name: 'fiona' }
|
|
42
63
|
```
|
|
43
64
|
|
|
65
|
+
## Optional: building SQL with Knex (not included)
|
|
66
|
+
|
|
67
|
+
**Knex is not part of `rqlite-js`.** It is an optional third-party dependency you may install separately if you want a query builder. This repo does not depend on or bundle Knex. The examples below are for illustration only.
|
|
68
|
+
|
|
69
|
+
`rqlite-js` only accepts SQL (or rqlite’s parameterized JSON form). If you use [Knex](https://knexjs.org/), generate SQL with it, then pass that into this client. You do **not** need a Knex connection pool to rqlite — configure the SQLite dialect for SQL generation only.
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npm install knex # optional — only if you want Knex in your app
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
```javascript
|
|
76
|
+
import knex from 'knex' // your app's dependency, not rqlite-js
|
|
77
|
+
import { DataApiClient } from 'rqlite-js'
|
|
78
|
+
|
|
79
|
+
const dataApiClient = new DataApiClient('http://localhost:4001')
|
|
80
|
+
|
|
81
|
+
// Dialect only — no DB connection. SQLite placeholders (?) match rqlite.
|
|
82
|
+
const qb = knex({ client: 'sqlite3' })
|
|
83
|
+
|
|
84
|
+
async function execBuilder (builder) {
|
|
85
|
+
const { sql, bindings } = builder.toSQL()
|
|
86
|
+
// Safer than toQuery(): keep values as bound parameters
|
|
87
|
+
return dataApiClient.execute([[sql, ...bindings]])
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async function queryBuilder (builder, options) {
|
|
91
|
+
const { sql, bindings } = builder.toSQL()
|
|
92
|
+
return dataApiClient.query([[sql, ...bindings]], options)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
await execBuilder(
|
|
96
|
+
qb.schema.createTableIfNotExists('foo', (table) => {
|
|
97
|
+
table.increments('id').primary()
|
|
98
|
+
table.text('name')
|
|
99
|
+
}),
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
await execBuilder(qb('foo').insert({ name: 'fiona' }))
|
|
103
|
+
|
|
104
|
+
const rows = await queryBuilder(
|
|
105
|
+
qb('foo').select('id', 'name').where('name', 'fiona').limit(10),
|
|
106
|
+
)
|
|
107
|
+
console.log(rows.toArray()) // [{ id: 1, name: 'fiona' }]
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Bulk inserts from Knex builders (same idea — Knex stays in your app):
|
|
111
|
+
|
|
112
|
+
```javascript
|
|
113
|
+
const statements = ['fiona', 'justin'].map((name) => {
|
|
114
|
+
const { sql, bindings } = qb('foo').insert({ name }).toSQL()
|
|
115
|
+
return [sql, ...bindings]
|
|
116
|
+
})
|
|
117
|
+
await dataApiClient.execute(statements, { transaction: true })
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Fully interpolated SQL via Knex `toQuery()` works with plain string `execute` / `query`, but **prefer `toSQL()` + bindings** whenever values are not compile-time constants:
|
|
121
|
+
|
|
122
|
+
```javascript
|
|
123
|
+
// OK only when every value is trusted (e.g. fixed id in your own code)
|
|
124
|
+
const sql = qb('foo').where('id', 1).select('*').toQuery()
|
|
125
|
+
await dataApiClient.query(sql)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
|
|
44
129
|
## DataApiClient
|
|
45
130
|
|
|
46
|
-
Access the [data API](https://rqlite.io/docs/api/api/)
|
|
131
|
+
Access the [data API](https://rqlite.io/docs/api/api/). By default methods return a `DataResults` instance. Pass `{ raw: true }` to get `{ status, body }` instead.
|
|
47
132
|
|
|
48
133
|
### Methods
|
|
49
134
|
|
|
50
|
-
- `query(sql, options)` — read via HTTP GET (or POST when `sql` is an array)
|
|
51
|
-
- `execute(sql, options)` — write via HTTP POST (`sql` may be a string or
|
|
135
|
+
- `query(sql, options)` — read via HTTP GET (or POST when `sql` is an array / parameterized batch)
|
|
136
|
+
- `execute(sql, options)` — write via HTTP POST (`sql` may be a string, string array, or parameterized nested arrays)
|
|
137
|
+
|
|
138
|
+
### Parameterized statements (recommended for safety)
|
|
139
|
+
|
|
140
|
+
rqlite accepts bound parameters as nested JSON arrays. The client forwards them as-is. **This is the safest way to pass dynamic values** — the server binds parameters separately from the SQL text, so user input cannot change the statement structure.
|
|
141
|
+
|
|
142
|
+
```javascript
|
|
143
|
+
// Safe: values are parameters, not concatenated into the SQL string
|
|
144
|
+
const name = req.body.name // untrusted input
|
|
145
|
+
await dataApiClient.execute([
|
|
146
|
+
['INSERT INTO foo(name, age) VALUES(?, ?)', name, 36],
|
|
147
|
+
])
|
|
148
|
+
|
|
149
|
+
const results = await dataApiClient.query([
|
|
150
|
+
['SELECT name, age FROM foo WHERE name = ?', name],
|
|
151
|
+
])
|
|
152
|
+
console.log(results.get(0).toObject())
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
```javascript
|
|
156
|
+
// Unsafe: do not build SQL by string interpolation with untrusted data
|
|
157
|
+
// await dataApiClient.query(`SELECT * FROM foo WHERE name = "${name}"`)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**Security tips for npm consumers:**
|
|
161
|
+
|
|
162
|
+
- Use parameterized statements (or your SQL builder’s bound parameters, e.g. Knex `toSQL()` if you use it) for all request/query-string/body values.
|
|
163
|
+
- Never concatenate untrusted input into SQL identifiers either (table/column names). Keep those as fixed allow-lists in your app code.
|
|
164
|
+
- `{ transaction: true }` / `{ atomic: true }` help with atomicity, not injection — they do not replace parameterization.
|
|
165
|
+
- Review any helper that calls `.toQuery()` or similar “print full SQL” APIs; those embed values into the string and are only appropriate for trusted constants.
|
|
52
166
|
|
|
53
167
|
### Create table
|
|
54
168
|
|
|
@@ -65,7 +179,6 @@ if (dataResults.hasError()) {
|
|
|
65
179
|
console.log(dataResults.toArray())
|
|
66
180
|
}
|
|
67
181
|
|
|
68
|
-
// Raw HTTP response shape from this client:
|
|
69
182
|
const { status, body } = await dataApiClient.execute(
|
|
70
183
|
'CREATE TABLE IF NOT EXISTS bar (id INTEGER NOT NULL PRIMARY KEY)',
|
|
71
184
|
{ raw: true },
|
|
@@ -94,9 +207,9 @@ dataResults = await dataApiClient.execute('UPDATE foo SET name="justin" WHERE na
|
|
|
94
207
|
console.log(dataResults.get(0).getRowsAffected()) // 1
|
|
95
208
|
```
|
|
96
209
|
|
|
97
|
-
###
|
|
210
|
+
### Bulk statements and transactions
|
|
98
211
|
|
|
99
|
-
Use `{ atomic: true }`
|
|
212
|
+
Send multiple statements in one HTTP request as a JSON array. Use `{ atomic: true }` (rqlite v5+) or `{ transaction: true }` to wrap them in a SQLite transaction (failed batches roll back when `transaction` is set).
|
|
100
213
|
|
|
101
214
|
```javascript
|
|
102
215
|
import { DataApiClient } from 'rqlite-js'
|
|
@@ -106,7 +219,7 @@ const sql = [
|
|
|
106
219
|
'INSERT INTO foo(name) VALUES("fiona")',
|
|
107
220
|
'INSERT INTO foo(name) VALUES("justin")',
|
|
108
221
|
]
|
|
109
|
-
const dataResults = await dataApiClient.execute(sql, {
|
|
222
|
+
const dataResults = await dataApiClient.execute(sql, { transaction: true })
|
|
110
223
|
if (dataResults.hasError()) {
|
|
111
224
|
throw dataResults.getFirstError()
|
|
112
225
|
}
|
|
@@ -114,10 +227,58 @@ console.log(dataResults.get(0).getLastInsertId())
|
|
|
114
227
|
console.log(dataResults.get(1).getLastInsertId())
|
|
115
228
|
```
|
|
116
229
|
|
|
230
|
+
Bulk **reads** use the same array form (HTTP POST):
|
|
231
|
+
|
|
232
|
+
```javascript
|
|
233
|
+
const dataResults = await dataApiClient.query([
|
|
234
|
+
'SELECT name FROM foo WHERE id = 1',
|
|
235
|
+
'SELECT COUNT(*) AS total FROM foo',
|
|
236
|
+
])
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Paging large reads
|
|
240
|
+
|
|
241
|
+
rqlite has no separate cursor API — page in SQL with `LIMIT` / `OFFSET` (or the equivalent helpers in whatever SQL builder you use):
|
|
242
|
+
|
|
243
|
+
```javascript
|
|
244
|
+
const pageSize = 50
|
|
245
|
+
for (let offset = 0; ; offset += pageSize) {
|
|
246
|
+
const page = await dataApiClient.query(
|
|
247
|
+
`SELECT id, name FROM foo ORDER BY id LIMIT ${pageSize} OFFSET ${offset}`,
|
|
248
|
+
)
|
|
249
|
+
const rows = page.toArray()
|
|
250
|
+
if (rows.length === 0) break
|
|
251
|
+
console.log(rows)
|
|
252
|
+
if (rows.length < pageSize) break
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Results shape notes
|
|
257
|
+
|
|
258
|
+
- One SELECT with **N value rows** → N `DataResult` entries (`toArray()` / `get(i)`).
|
|
259
|
+
- A SELECT with **no matching rows** often omits `values`; this client then yields a single empty `DataResult` (`toObject()` → `{}`). Check `toArray()` / column getters rather than assuming `getResults().length === 0`.
|
|
260
|
+
- Aggregates like `COUNT(*)` still return one row object.
|
|
261
|
+
|
|
262
|
+
Map rows into plain objects or your own types with `toObject()` / `toArray()` — Knex has no model layer, and this client does not integrate with ORMs:
|
|
263
|
+
|
|
264
|
+
```javascript
|
|
265
|
+
const dataResults = await dataApiClient.query('SELECT id, name FROM foo')
|
|
266
|
+
const rows = dataResults.toArray() // [{ id: 1, name: 'fiona' }, ...]
|
|
267
|
+
|
|
268
|
+
// Optional: map into your app's types
|
|
269
|
+
const users = rows.map((row) => ({ id: row.id, displayName: row.name }))
|
|
270
|
+
```
|
|
271
|
+
|
|
117
272
|
### Consistency
|
|
118
273
|
|
|
119
274
|
```javascript
|
|
120
|
-
import {
|
|
275
|
+
import {
|
|
276
|
+
DataApiClient,
|
|
277
|
+
CONSISTENCY_LEVEL_NONE,
|
|
278
|
+
CONSISTENCY_LEVEL_WEAK,
|
|
279
|
+
CONSISTENCY_LEVEL_STRONG,
|
|
280
|
+
CONSISTENCY_LEVEL_LINEARIZABLE,
|
|
281
|
+
} from 'rqlite-js'
|
|
121
282
|
|
|
122
283
|
const dataApiClient = new DataApiClient('http://localhost:4001')
|
|
123
284
|
const dataResults = await dataApiClient.query(
|
|
@@ -126,11 +287,13 @@ const dataResults = await dataApiClient.query(
|
|
|
126
287
|
)
|
|
127
288
|
```
|
|
128
289
|
|
|
129
|
-
See [read consistency](https://rqlite.io/docs/api/read-consistency/)
|
|
290
|
+
Levels: `none`, `weak` (default), `strong`, `linearizable`. See [read consistency](https://rqlite.io/docs/api/read-consistency/). On a single node, all levels succeed; choose based on your cluster topology.
|
|
291
|
+
|
|
292
|
+
Optional flags: `{ timings: true }` (response timing fields), `{ pretty: true }` (pretty-printed JSON from the server).
|
|
130
293
|
|
|
131
294
|
### Errors (`error` and `error_v2`)
|
|
132
295
|
|
|
133
|
-
Failed statements
|
|
296
|
+
Failed statements use the legacy `error` string. On rqlite v10+, structured `error_v2` is also exposed:
|
|
134
297
|
|
|
135
298
|
```javascript
|
|
136
299
|
const dataResults = await dataApiClient.execute('INSERT INTO nonsense')
|
|
@@ -158,16 +321,17 @@ const dataApiClient = new DataApiClient('http://localhost:4001', {
|
|
|
158
321
|
### Client options (hosts, agents, retries)
|
|
159
322
|
|
|
160
323
|
```javascript
|
|
161
|
-
import
|
|
162
|
-
import https from 'https'
|
|
324
|
+
import { Agent } from 'undici'
|
|
163
325
|
import { DataApiClient } from 'rqlite-js'
|
|
164
326
|
|
|
327
|
+
const dispatcher = new Agent({ keepAliveTimeout: 10_000 })
|
|
328
|
+
|
|
165
329
|
const dataApiClient = new DataApiClient(
|
|
166
330
|
['http://localhost:4001', 'http://localhost:4002', 'http://localhost:4003'],
|
|
167
331
|
{
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
332
|
+
// undici Dispatcher (has .dispatch) — used by native fetch for keepalive pools
|
|
333
|
+
httpAgent: dispatcher,
|
|
334
|
+
httpsAgent: dispatcher,
|
|
171
335
|
retryableStatusCodes: new Set([408, 429, 500, 502, 503, 504]),
|
|
172
336
|
retryableErrorCodes: new Set(['ECONNRESET', 'ETIMEDOUT']),
|
|
173
337
|
retryableHttpMethods: new Set(['GET', 'POST']),
|
|
@@ -176,7 +340,7 @@ const dataApiClient = new DataApiClient(
|
|
|
176
340
|
)
|
|
177
341
|
```
|
|
178
342
|
|
|
179
|
-
Hosts may also be a comma-separated string: `'http://localhost:4001,http://localhost:4002'`.
|
|
343
|
+
Hosts may also be a comma-separated string: `'http://localhost:4001,http://localhost:4002'`. Classic `http.Agent` / `https.Agent` option names remain for API compatibility; pass an undici `Dispatcher` when you need fetch keepalive.
|
|
180
344
|
|
|
181
345
|
## StatusApiClient
|
|
182
346
|
|
|
@@ -187,7 +351,6 @@ const statusApiClient = new StatusApiClient('http://localhost:4001')
|
|
|
187
351
|
const { status, body } = await statusApiClient.status()
|
|
188
352
|
console.log(status, body.store?.ready)
|
|
189
353
|
|
|
190
|
-
// One status call per configured host:
|
|
191
354
|
const all = await statusApiClient.statusAllHosts()
|
|
192
355
|
all.forEach(({ host, response }) => {
|
|
193
356
|
console.log(host, response.body?.store?.ready)
|
|
@@ -198,34 +361,49 @@ See [Monitoring rqlite](https://rqlite.io/docs/guides/monitoring-rqlite/).
|
|
|
198
361
|
|
|
199
362
|
## BackupApiClient
|
|
200
363
|
|
|
364
|
+
Backup/load return Node `Readable` streams.
|
|
365
|
+
|
|
201
366
|
```javascript
|
|
202
367
|
import { BackupApiClient, BACKUP_DATA_FORMAT_SQL } from 'rqlite-js'
|
|
368
|
+
import { pipeline } from 'node:stream/promises'
|
|
369
|
+
import { createWriteStream } from 'node:fs'
|
|
203
370
|
|
|
204
371
|
const backupApiClient = new BackupApiClient('http://localhost:4001')
|
|
205
372
|
|
|
206
|
-
// Binary SQLite
|
|
373
|
+
// Binary SQLite dump (default):
|
|
207
374
|
const backupStream = await backupApiClient.backup()
|
|
375
|
+
await pipeline(backupStream, createWriteStream('backup.sqlite'))
|
|
208
376
|
|
|
209
377
|
// SQL text backup:
|
|
210
378
|
const sqlStream = await backupApiClient.backup(BACKUP_DATA_FORMAT_SQL)
|
|
211
379
|
|
|
212
380
|
// Restore from SQL buffer/string:
|
|
213
381
|
await backupApiClient.load(
|
|
214
|
-
Buffer.from('CREATE TABLE foo (id INTEGER PRIMARY KEY);'),
|
|
382
|
+
Buffer.from('CREATE TABLE foo (id INTEGER PRIMARY KEY); INSERT INTO foo DEFAULT VALUES;'),
|
|
215
383
|
BACKUP_DATA_FORMAT_SQL,
|
|
216
384
|
)
|
|
217
385
|
```
|
|
218
386
|
|
|
219
387
|
See [Backup and restore](https://rqlite.io/docs/guides/backup/).
|
|
220
388
|
|
|
389
|
+
## Package surface (npm)
|
|
390
|
+
|
|
391
|
+
| Item | Detail |
|
|
392
|
+
|------|--------|
|
|
393
|
+
| Import | `rqlite-js` only (ESM + CJS) |
|
|
394
|
+
| Types | Bundled `.d.ts` / `.d.cts` — no `@types/rqlite-js` |
|
|
395
|
+
| Runtime deps | None |
|
|
396
|
+
| Engines | `node >= 20.19` |
|
|
397
|
+
| Published | `dist/` (runtime) + `src/` (TypeScript sources for debugging) |
|
|
398
|
+
|
|
221
399
|
## Releases
|
|
222
400
|
|
|
223
|
-
Versions and `CHANGELOG.md` are managed with [release-please](https://github.com/googleapis/release-please). Merging the release PR creates a GitHub Release; the
|
|
401
|
+
Versions and `CHANGELOG.md` are managed with [release-please](https://github.com/googleapis/release-please). Merging the release PR creates a GitHub Release; the workflow re-runs the full suite (including Docker integrations) and runs [`npm stage publish`](https://docs.npmjs.com/staged-publishing/) via [trusted publishing](https://docs.npmjs.com/trusted-publishers/) (OIDC). A maintainer must approve the staged version with 2FA on npmjs.com (or `npm stage approve <id>`) before it goes live.
|
|
224
402
|
|
|
225
403
|
**Local quality gate (required before commit/push/publish):**
|
|
226
404
|
|
|
227
405
|
```bash
|
|
228
|
-
npm run verify # lint, type-check, unit, build,
|
|
406
|
+
npm run verify # lint, type-check, unit, build, pack checks
|
|
229
407
|
npm run verify:integrations # Docker + rqlite 10.6.6 integrations
|
|
230
408
|
```
|
|
231
409
|
|