Notable changes:
- Respect progress callback function option.
- Set default backup rate to 100 to follow Node's implementation.
- Various validation and error handling.
Note that the op implementation in this PR is still sync.
Given this code:
```js
import { backup, DatabaseSync } from "node:sqlite";
const populate = (database, rows) => {
database.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT);");
let values = "";
for (let i = 0; i < rows; i++) {
values += `(${i}, 'Name ${i}'),`;
}
values = values.slice(0, -1);
database.exec(`INSERT INTO test (id, name) VALUES ${values}`);
};
const backupPath = "backup.sqlite";
const database = new DatabaseSync(":memory:");
populate(database, 1000);
const t0 = performance.now();
await backup(database, backupPath, { rate: 1 });
const t1 = performance.now();
database.close();
console.log(`Backup completed in ${(t1 - t0).toFixed(2)} ms`);
```
Results:
```bash
# Node.js v25.2.1
➜ node ./backup-benchmark.js
Backup completed in 0.71 ms
# This PR (debug build mode)
➜ ddeno -A ./backup-benchmark.js
Backup completed in 0.71 ms
# Deno v2.6.0
➜ deno -A ./backup-benchmark.js
Backup completed in 1272.16 ms
```
The current implementation is slow because it sleeps 250ms after each
`sqlite3_backup_step` call.