@tursodatabase/sync 0.1.5 → 0.2.0-pre.3
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 +83 -18
- package/dist/promise.d.ts +30 -0
- package/dist/promise.d.ts.map +1 -0
- package/dist/promise.js +102 -0
- package/dist/promise.test.d.ts +2 -0
- package/dist/promise.test.d.ts.map +1 -0
- package/dist/promise.test.js +259 -0
- package/index.js +164 -50
- package/package.json +37 -48
- package/browser.js +0 -1
- package/dist/sync_engine.d.ts +0 -24
- package/dist/sync_engine.js +0 -152
package/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<h1 align="center">Turso
|
|
2
|
+
<h1 align="center">Turso Database for JavaScript in Node</h1>
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
5
|
<p align="center">
|
|
6
|
-
<a title="JavaScript" target="_blank" href="https://www.npmjs.com/package/@tursodatabase/
|
|
6
|
+
<a title="JavaScript" target="_blank" href="https://www.npmjs.com/package/@tursodatabase/database"><img alt="npm" src="https://img.shields.io/npm/v/@tursodatabase/database"></a>
|
|
7
7
|
<a title="MIT" target="_blank" href="https://github.com/tursodatabase/turso/blob/main/LICENSE.md"><img src="http://img.shields.io/badge/license-MIT-orange.svg?style=flat-square"></a>
|
|
8
8
|
</p>
|
|
9
9
|
<p align="center">
|
|
@@ -14,40 +14,105 @@
|
|
|
14
14
|
|
|
15
15
|
## About
|
|
16
16
|
|
|
17
|
-
This package is
|
|
17
|
+
This package is the Turso embedded database library for JavaScript in Node.
|
|
18
18
|
|
|
19
19
|
> **⚠️ Warning:** This software is ALPHA, only use for development, testing, and experimentation. We are working to make it production ready, but do not use it for critical data right now.
|
|
20
20
|
|
|
21
|
+
## Features
|
|
22
|
+
|
|
23
|
+
- **SQLite compatible:** SQLite query language and file format support ([status](https://github.com/tursodatabase/turso/blob/main/COMPAT.md)).
|
|
24
|
+
- **In-process**: No network overhead, runs directly in your Node.js process
|
|
25
|
+
- **TypeScript support**: Full TypeScript definitions included
|
|
26
|
+
- **Cross-platform**: Supports Linux (x86 and arm64), macOS, Windows (browser is supported in the separate package `@tursodatabase/database-browser` package)
|
|
27
|
+
|
|
21
28
|
## Installation
|
|
22
29
|
|
|
23
30
|
```bash
|
|
24
|
-
npm install @tursodatabase/
|
|
31
|
+
npm install @tursodatabase/database
|
|
25
32
|
```
|
|
26
33
|
|
|
27
34
|
## Getting Started
|
|
28
35
|
|
|
29
|
-
|
|
36
|
+
### In-Memory Database
|
|
37
|
+
|
|
38
|
+
```javascript
|
|
39
|
+
import { connect } from '@tursodatabase/database';
|
|
40
|
+
|
|
41
|
+
// Create an in-memory database
|
|
42
|
+
const db = await connect(':memory:');
|
|
43
|
+
|
|
44
|
+
// Create a table
|
|
45
|
+
await db.exec('CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)');
|
|
46
|
+
|
|
47
|
+
// Insert data
|
|
48
|
+
const insert = db.prepare('INSERT INTO users (name, email) VALUES (?, ?)');
|
|
49
|
+
await insert.run('Alice', 'alice@example.com');
|
|
50
|
+
await insert.run('Bob', 'bob@example.com');
|
|
51
|
+
|
|
52
|
+
// Query data
|
|
53
|
+
const users = await db.prepare('SELECT * FROM users').all();
|
|
54
|
+
console.log(users);
|
|
55
|
+
// Output: [
|
|
56
|
+
// { id: 1, name: 'Alice', email: 'alice@example.com' },
|
|
57
|
+
// { id: 2, name: 'Bob', email: 'bob@example.com' }
|
|
58
|
+
// ]
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### File-Based Database
|
|
62
|
+
|
|
63
|
+
```javascript
|
|
64
|
+
import { connect } from '@tursodatabase/database';
|
|
30
65
|
|
|
31
|
-
|
|
32
|
-
|
|
66
|
+
// Create or open a database file
|
|
67
|
+
const db = await connect('my-database.db');
|
|
33
68
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
69
|
+
// Create a table
|
|
70
|
+
await db.exec(`
|
|
71
|
+
CREATE TABLE IF NOT EXISTS posts (
|
|
72
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
73
|
+
title TEXT NOT NULL,
|
|
74
|
+
content TEXT,
|
|
75
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
76
|
+
)
|
|
77
|
+
`);
|
|
78
|
+
|
|
79
|
+
// Insert a post
|
|
80
|
+
const insertPost = db.prepare('INSERT INTO posts (title, content) VALUES (?, ?)');
|
|
81
|
+
const result = await insertPost.run('Hello World', 'This is my first blog post!');
|
|
82
|
+
|
|
83
|
+
console.log(`Inserted post with ID: ${result.lastInsertRowid}`);
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Transactions
|
|
87
|
+
|
|
88
|
+
```javascript
|
|
89
|
+
import { connect } from '@tursodatabase/database';
|
|
90
|
+
|
|
91
|
+
const db = await connect('transactions.db');
|
|
92
|
+
|
|
93
|
+
// Using transactions for atomic operations
|
|
94
|
+
const transaction = db.transaction(async (users) => {
|
|
95
|
+
const insert = db.prepare('INSERT INTO users (name, email) VALUES (?, ?)');
|
|
96
|
+
for (const user of users) {
|
|
97
|
+
await insert.run(user.name, user.email);
|
|
98
|
+
}
|
|
39
99
|
});
|
|
40
100
|
|
|
41
|
-
//
|
|
42
|
-
await
|
|
43
|
-
|
|
44
|
-
|
|
101
|
+
// Execute transaction
|
|
102
|
+
await transaction([
|
|
103
|
+
{ name: 'Alice', email: 'alice@example.com' },
|
|
104
|
+
{ name: 'Bob', email: 'bob@example.com' }
|
|
105
|
+
]);
|
|
45
106
|
```
|
|
46
107
|
|
|
108
|
+
## API Reference
|
|
109
|
+
|
|
110
|
+
For complete API documentation, see [JavaScript API Reference](../../../../docs/javascript-api-reference.md).
|
|
111
|
+
|
|
47
112
|
## Related Packages
|
|
48
113
|
|
|
49
|
-
* The [@tursodatabase/database](https://www.npmjs.com/package/@tursodatabase/database) package provides the Turso in-memory database, compatible with SQLite.
|
|
50
114
|
* The [@tursodatabase/serverless](https://www.npmjs.com/package/@tursodatabase/serverless) package provides a serverless driver with the same API.
|
|
115
|
+
* The [@tursodatabase/sync](https://www.npmjs.com/package/@tursodatabase/sync) package provides bidirectional sync between a local Turso database and Turso Cloud.
|
|
51
116
|
|
|
52
117
|
## License
|
|
53
118
|
|
|
@@ -57,4 +122,4 @@ This project is licensed under the [MIT license](../../LICENSE.md).
|
|
|
57
122
|
|
|
58
123
|
- [GitHub Issues](https://github.com/tursodatabase/turso/issues)
|
|
59
124
|
- [Documentation](https://docs.turso.tech)
|
|
60
|
-
- [Discord Community](https://tur.so/discord)
|
|
125
|
+
- [Discord Community](https://tur.so/discord)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { DatabasePromise, DatabaseOpts, NativeDatabase } from "@tursodatabase/database-common";
|
|
2
|
+
import { ProtocolIo, SyncOpts, RunOpts, DatabaseRowMutation, DatabaseRowStatement, DatabaseRowTransformResult } from "@tursodatabase/sync-common";
|
|
3
|
+
declare class Database extends DatabasePromise {
|
|
4
|
+
runOpts: RunOpts;
|
|
5
|
+
engine: any;
|
|
6
|
+
io: ProtocolIo;
|
|
7
|
+
constructor(db: NativeDatabase, io: ProtocolIo, runOpts: RunOpts, engine: any, opts?: DatabaseOpts);
|
|
8
|
+
sync(): Promise<void>;
|
|
9
|
+
pull(): Promise<void>;
|
|
10
|
+
push(): Promise<void>;
|
|
11
|
+
checkpoint(): Promise<void>;
|
|
12
|
+
stats(): Promise<{
|
|
13
|
+
operations: number;
|
|
14
|
+
mainWal: number;
|
|
15
|
+
revertWal: number;
|
|
16
|
+
lastPullUnixTime: number;
|
|
17
|
+
lastPushUnixTime: number | null;
|
|
18
|
+
}>;
|
|
19
|
+
close(): Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Creates a new database connection asynchronously.
|
|
23
|
+
*
|
|
24
|
+
* @param {string} path - Path to the database file.
|
|
25
|
+
* @param {Object} opts - Options for database behavior.
|
|
26
|
+
* @returns {Promise<Database>} - A promise that resolves to a Database instance.
|
|
27
|
+
*/
|
|
28
|
+
declare function connect(opts: SyncOpts): Promise<Database>;
|
|
29
|
+
export { connect, Database, DatabaseRowMutation, DatabaseRowStatement, DatabaseRowTransformResult };
|
|
30
|
+
//# sourceMappingURL=promise.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"promise.d.ts","sourceRoot":"","sources":["../promise.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AAC9F,OAAO,EAAE,UAAU,EAAO,QAAQ,EAAE,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AAwCvJ,cAAM,QAAS,SAAQ,eAAe;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,GAAG,CAAC;IACZ,EAAE,EAAE,UAAU,CAAC;gBACH,EAAE,EAAE,cAAc,EAAE,EAAE,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,GAAE,YAAiB;IAMhG,IAAI;IAGJ,IAAI;IAGJ,IAAI;IAGJ,UAAU;IAGV,KAAK,IAAI,OAAO,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAG9H,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAGxC;AAED;;;;;;GAMG;AACH,iBAAe,OAAO,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAuBxD;AAED,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,0BAA0B,EAAE,CAAA"}
|
package/dist/promise.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { DatabasePromise } from "@tursodatabase/database-common";
|
|
2
|
+
import { run } from "@tursodatabase/sync-common";
|
|
3
|
+
import { SyncEngine } from "#index";
|
|
4
|
+
import { promises } from "node:fs";
|
|
5
|
+
let NodeIO = {
|
|
6
|
+
async read(path) {
|
|
7
|
+
try {
|
|
8
|
+
return await promises.readFile(path);
|
|
9
|
+
}
|
|
10
|
+
catch (error) {
|
|
11
|
+
if (error.code === 'ENOENT') {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
throw error;
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
async write(path, data) {
|
|
18
|
+
const unix = Math.floor(Date.now() / 1000);
|
|
19
|
+
const nonce = Math.floor(Math.random() * 1000000000);
|
|
20
|
+
const tmp = `${path}.tmp.${unix}.${nonce}`;
|
|
21
|
+
await promises.writeFile(tmp, new Uint8Array(data));
|
|
22
|
+
try {
|
|
23
|
+
await promises.rename(tmp, path);
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
await promises.unlink(tmp);
|
|
27
|
+
throw err;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
function memoryIO() {
|
|
32
|
+
let values = new Map();
|
|
33
|
+
return {
|
|
34
|
+
async read(path) {
|
|
35
|
+
return values.get(path);
|
|
36
|
+
},
|
|
37
|
+
async write(path, data) {
|
|
38
|
+
values.set(path, data);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
;
|
|
43
|
+
class Database extends DatabasePromise {
|
|
44
|
+
runOpts;
|
|
45
|
+
engine;
|
|
46
|
+
io;
|
|
47
|
+
constructor(db, io, runOpts, engine, opts = {}) {
|
|
48
|
+
super(db, opts);
|
|
49
|
+
this.runOpts = runOpts;
|
|
50
|
+
this.engine = engine;
|
|
51
|
+
this.io = io;
|
|
52
|
+
}
|
|
53
|
+
async sync() {
|
|
54
|
+
await run(this.runOpts, this.io, this.engine, this.engine.sync());
|
|
55
|
+
}
|
|
56
|
+
async pull() {
|
|
57
|
+
await run(this.runOpts, this.io, this.engine, this.engine.pull());
|
|
58
|
+
}
|
|
59
|
+
async push() {
|
|
60
|
+
await run(this.runOpts, this.io, this.engine, this.engine.push());
|
|
61
|
+
}
|
|
62
|
+
async checkpoint() {
|
|
63
|
+
await run(this.runOpts, this.io, this.engine, this.engine.checkpoint());
|
|
64
|
+
}
|
|
65
|
+
async stats() {
|
|
66
|
+
return (await run(this.runOpts, this.io, this.engine, this.engine.stats()));
|
|
67
|
+
}
|
|
68
|
+
async close() {
|
|
69
|
+
this.engine.close();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Creates a new database connection asynchronously.
|
|
74
|
+
*
|
|
75
|
+
* @param {string} path - Path to the database file.
|
|
76
|
+
* @param {Object} opts - Options for database behavior.
|
|
77
|
+
* @returns {Promise<Database>} - A promise that resolves to a Database instance.
|
|
78
|
+
*/
|
|
79
|
+
async function connect(opts) {
|
|
80
|
+
const engine = new SyncEngine({
|
|
81
|
+
path: opts.path,
|
|
82
|
+
clientName: opts.clientName,
|
|
83
|
+
tablesIgnore: opts.tablesIgnore,
|
|
84
|
+
useTransform: opts.transform != null,
|
|
85
|
+
tracing: opts.tracing,
|
|
86
|
+
protocolVersion: 1
|
|
87
|
+
});
|
|
88
|
+
const runOpts = {
|
|
89
|
+
url: opts.url,
|
|
90
|
+
headers: {
|
|
91
|
+
...(opts.authToken != null && { "Authorization": `Bearer ${opts.authToken}` }),
|
|
92
|
+
...(opts.encryptionKey != null && { "x-turso-encryption-key": opts.encryptionKey })
|
|
93
|
+
},
|
|
94
|
+
preemptionMs: 1,
|
|
95
|
+
transform: opts.transform,
|
|
96
|
+
};
|
|
97
|
+
let io = opts.path == ':memory:' ? memoryIO() : NodeIO;
|
|
98
|
+
await run(runOpts, io, engine, engine.init());
|
|
99
|
+
const nativeDb = engine.open();
|
|
100
|
+
return new Database(nativeDb, io, runOpts, engine, {});
|
|
101
|
+
}
|
|
102
|
+
export { connect, Database };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"promise.test.d.ts","sourceRoot":"","sources":["../promise.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import { unlinkSync } from "node:fs";
|
|
2
|
+
import { expect, test } from 'vitest';
|
|
3
|
+
import { connect } from './promise.js';
|
|
4
|
+
const localeCompare = (a, b) => a.x.localeCompare(b.x);
|
|
5
|
+
test('select-after-push', async () => {
|
|
6
|
+
{
|
|
7
|
+
const db = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL });
|
|
8
|
+
await db.exec("CREATE TABLE IF NOT EXISTS t(x)");
|
|
9
|
+
await db.exec("DELETE FROM t");
|
|
10
|
+
await db.push();
|
|
11
|
+
await db.close();
|
|
12
|
+
}
|
|
13
|
+
{
|
|
14
|
+
const db = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL });
|
|
15
|
+
await db.exec("INSERT INTO t VALUES (1), (2), (3)");
|
|
16
|
+
await db.push();
|
|
17
|
+
}
|
|
18
|
+
{
|
|
19
|
+
const db = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL });
|
|
20
|
+
const rows = await db.prepare('SELECT * FROM t').all();
|
|
21
|
+
expect(rows).toEqual([{ x: 1 }, { x: 2 }, { x: 3 }]);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
test('select-without-push', async () => {
|
|
25
|
+
{
|
|
26
|
+
const db = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL });
|
|
27
|
+
await db.exec("CREATE TABLE IF NOT EXISTS t(x)");
|
|
28
|
+
await db.exec("DELETE FROM t");
|
|
29
|
+
await db.push();
|
|
30
|
+
await db.close();
|
|
31
|
+
}
|
|
32
|
+
{
|
|
33
|
+
const db = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL });
|
|
34
|
+
await db.exec("INSERT INTO t VALUES (1), (2), (3)");
|
|
35
|
+
}
|
|
36
|
+
{
|
|
37
|
+
const db = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL });
|
|
38
|
+
const rows = await db.prepare('SELECT * FROM t').all();
|
|
39
|
+
expect(rows).toEqual([]);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
test('merge-non-overlapping-keys', async () => {
|
|
43
|
+
{
|
|
44
|
+
const db = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL });
|
|
45
|
+
await db.exec("CREATE TABLE IF NOT EXISTS q(x TEXT PRIMARY KEY, y)");
|
|
46
|
+
await db.exec("DELETE FROM q");
|
|
47
|
+
await db.push();
|
|
48
|
+
await db.close();
|
|
49
|
+
}
|
|
50
|
+
const db1 = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL });
|
|
51
|
+
await db1.exec("INSERT INTO q VALUES ('k1', 'value1'), ('k2', 'value2')");
|
|
52
|
+
const db2 = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL });
|
|
53
|
+
await db2.exec("INSERT INTO q VALUES ('k3', 'value3'), ('k4', 'value4'), ('k5', 'value5')");
|
|
54
|
+
await Promise.all([db1.push(), db2.push()]);
|
|
55
|
+
await Promise.all([db1.pull(), db2.pull()]);
|
|
56
|
+
const rows1 = await db1.prepare('SELECT * FROM q').all();
|
|
57
|
+
const rows2 = await db1.prepare('SELECT * FROM q').all();
|
|
58
|
+
const expected = [{ x: 'k1', y: 'value1' }, { x: 'k2', y: 'value2' }, { x: 'k3', y: 'value3' }, { x: 'k4', y: 'value4' }, { x: 'k5', y: 'value5' }];
|
|
59
|
+
expect(rows1.sort(localeCompare)).toEqual(expected.sort(localeCompare));
|
|
60
|
+
expect(rows2.sort(localeCompare)).toEqual(expected.sort(localeCompare));
|
|
61
|
+
});
|
|
62
|
+
test('last-push-wins', async () => {
|
|
63
|
+
{
|
|
64
|
+
const db = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL });
|
|
65
|
+
await db.exec("CREATE TABLE IF NOT EXISTS q(x TEXT PRIMARY KEY, y)");
|
|
66
|
+
await db.exec("DELETE FROM q");
|
|
67
|
+
await db.push();
|
|
68
|
+
await db.close();
|
|
69
|
+
}
|
|
70
|
+
const db1 = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL });
|
|
71
|
+
await db1.exec("INSERT INTO q VALUES ('k1', 'value1'), ('k2', 'value2'), ('k4', 'value4')");
|
|
72
|
+
const db2 = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL });
|
|
73
|
+
await db2.exec("INSERT INTO q VALUES ('k1', 'value3'), ('k2', 'value4'), ('k3', 'value5')");
|
|
74
|
+
await db2.push();
|
|
75
|
+
await db1.push();
|
|
76
|
+
await Promise.all([db1.pull(), db2.pull()]);
|
|
77
|
+
const rows1 = await db1.prepare('SELECT * FROM q').all();
|
|
78
|
+
const rows2 = await db1.prepare('SELECT * FROM q').all();
|
|
79
|
+
const expected = [{ x: 'k1', y: 'value1' }, { x: 'k2', y: 'value2' }, { x: 'k3', y: 'value5' }, { x: 'k4', y: 'value4' }];
|
|
80
|
+
expect(rows1.sort(localeCompare)).toEqual(expected.sort(localeCompare));
|
|
81
|
+
expect(rows2.sort(localeCompare)).toEqual(expected.sort(localeCompare));
|
|
82
|
+
});
|
|
83
|
+
test('last-push-wins-with-delete', async () => {
|
|
84
|
+
{
|
|
85
|
+
const db = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL });
|
|
86
|
+
await db.exec("CREATE TABLE IF NOT EXISTS q(x TEXT PRIMARY KEY, y)");
|
|
87
|
+
await db.exec("DELETE FROM q");
|
|
88
|
+
await db.push();
|
|
89
|
+
await db.close();
|
|
90
|
+
}
|
|
91
|
+
const db1 = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL });
|
|
92
|
+
await db1.exec("INSERT INTO q VALUES ('k1', 'value1'), ('k2', 'value2'), ('k4', 'value4')");
|
|
93
|
+
await db1.exec("DELETE FROM q");
|
|
94
|
+
const db2 = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL });
|
|
95
|
+
await db2.exec("INSERT INTO q VALUES ('k1', 'value3'), ('k2', 'value4'), ('k3', 'value5')");
|
|
96
|
+
await db2.push();
|
|
97
|
+
await db1.push();
|
|
98
|
+
await Promise.all([db1.pull(), db2.pull()]);
|
|
99
|
+
const rows1 = await db1.prepare('SELECT * FROM q').all();
|
|
100
|
+
const rows2 = await db1.prepare('SELECT * FROM q').all();
|
|
101
|
+
const expected = [{ x: 'k3', y: 'value5' }];
|
|
102
|
+
expect(rows1).toEqual(expected);
|
|
103
|
+
expect(rows2).toEqual(expected);
|
|
104
|
+
});
|
|
105
|
+
test('constraint-conflict', async () => {
|
|
106
|
+
{
|
|
107
|
+
const db = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL });
|
|
108
|
+
await db.exec("CREATE TABLE IF NOT EXISTS u(x TEXT PRIMARY KEY, y UNIQUE)");
|
|
109
|
+
await db.exec("DELETE FROM u");
|
|
110
|
+
await db.push();
|
|
111
|
+
await db.close();
|
|
112
|
+
}
|
|
113
|
+
const db1 = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL });
|
|
114
|
+
await db1.exec("INSERT INTO u VALUES ('k1', 'value1')");
|
|
115
|
+
const db2 = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL });
|
|
116
|
+
await db2.exec("INSERT INTO u VALUES ('k2', 'value1')");
|
|
117
|
+
await db1.push();
|
|
118
|
+
await expect(async () => await db2.push()).rejects.toThrow('SQLite error: UNIQUE constraint failed: u.y');
|
|
119
|
+
});
|
|
120
|
+
test('checkpoint', async () => {
|
|
121
|
+
{
|
|
122
|
+
const db = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL });
|
|
123
|
+
await db.exec("CREATE TABLE IF NOT EXISTS q(x TEXT PRIMARY KEY, y)");
|
|
124
|
+
await db.exec("DELETE FROM q");
|
|
125
|
+
await db.push();
|
|
126
|
+
await db.close();
|
|
127
|
+
}
|
|
128
|
+
const db1 = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL });
|
|
129
|
+
for (let i = 0; i < 1000; i++) {
|
|
130
|
+
await db1.exec(`INSERT INTO q VALUES ('k${i}', 'v${i}')`);
|
|
131
|
+
}
|
|
132
|
+
expect((await db1.stats()).mainWal).toBeGreaterThan(4096 * 1000);
|
|
133
|
+
await db1.checkpoint();
|
|
134
|
+
expect((await db1.stats()).mainWal).toBe(0);
|
|
135
|
+
let revertWal = (await db1.stats()).revertWal;
|
|
136
|
+
expect(revertWal).toBeLessThan(4096 * 1000 / 100);
|
|
137
|
+
for (let i = 0; i < 1000; i++) {
|
|
138
|
+
await db1.exec(`UPDATE q SET y = 'u${i}' WHERE x = 'k${i}'`);
|
|
139
|
+
}
|
|
140
|
+
await db1.checkpoint();
|
|
141
|
+
expect((await db1.stats()).revertWal).toBe(revertWal);
|
|
142
|
+
});
|
|
143
|
+
test('persistence', async () => {
|
|
144
|
+
{
|
|
145
|
+
const db = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL });
|
|
146
|
+
await db.exec("CREATE TABLE IF NOT EXISTS q(x TEXT PRIMARY KEY, y)");
|
|
147
|
+
await db.exec("DELETE FROM q");
|
|
148
|
+
await db.push();
|
|
149
|
+
await db.close();
|
|
150
|
+
}
|
|
151
|
+
const path = `test-${(Math.random() * 10000) | 0}.db`;
|
|
152
|
+
try {
|
|
153
|
+
{
|
|
154
|
+
const db1 = await connect({ path: path, url: process.env.VITE_TURSO_DB_URL });
|
|
155
|
+
await db1.exec(`INSERT INTO q VALUES ('k1', 'v1')`);
|
|
156
|
+
await db1.exec(`INSERT INTO q VALUES ('k2', 'v2')`);
|
|
157
|
+
await db1.close();
|
|
158
|
+
}
|
|
159
|
+
{
|
|
160
|
+
const db2 = await connect({ path: path, url: process.env.VITE_TURSO_DB_URL });
|
|
161
|
+
await db2.exec(`INSERT INTO q VALUES ('k3', 'v3')`);
|
|
162
|
+
await db2.exec(`INSERT INTO q VALUES ('k4', 'v4')`);
|
|
163
|
+
const rows = await db2.prepare('SELECT * FROM q').all();
|
|
164
|
+
const expected = [{ x: 'k1', y: 'v1' }, { x: 'k2', y: 'v2' }, { x: 'k3', y: 'v3' }, { x: 'k4', y: 'v4' }];
|
|
165
|
+
expect(rows).toEqual(expected);
|
|
166
|
+
await db2.close();
|
|
167
|
+
}
|
|
168
|
+
{
|
|
169
|
+
const db3 = await connect({ path: path, url: process.env.VITE_TURSO_DB_URL });
|
|
170
|
+
await db3.push();
|
|
171
|
+
await db3.close();
|
|
172
|
+
}
|
|
173
|
+
{
|
|
174
|
+
const db4 = await connect({ path: path, url: process.env.VITE_TURSO_DB_URL });
|
|
175
|
+
const rows = await db4.prepare('SELECT * FROM q').all();
|
|
176
|
+
const expected = [{ x: 'k1', y: 'v1' }, { x: 'k2', y: 'v2' }, { x: 'k3', y: 'v3' }, { x: 'k4', y: 'v4' }];
|
|
177
|
+
expect(rows).toEqual(expected);
|
|
178
|
+
await db4.close();
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
finally {
|
|
182
|
+
unlinkSync(path);
|
|
183
|
+
unlinkSync(`${path}-wal`);
|
|
184
|
+
unlinkSync(`${path}-info`);
|
|
185
|
+
unlinkSync(`${path}-changes`);
|
|
186
|
+
try {
|
|
187
|
+
unlinkSync(`${path}-revert`);
|
|
188
|
+
}
|
|
189
|
+
catch (e) { }
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
test('transform', async () => {
|
|
193
|
+
{
|
|
194
|
+
const db = await connect({
|
|
195
|
+
path: ':memory:',
|
|
196
|
+
url: process.env.VITE_TURSO_DB_URL,
|
|
197
|
+
});
|
|
198
|
+
await db.exec("CREATE TABLE IF NOT EXISTS counter(key TEXT PRIMARY KEY, value INTEGER)");
|
|
199
|
+
await db.exec("DELETE FROM counter");
|
|
200
|
+
await db.exec("INSERT INTO counter VALUES ('1', 0)");
|
|
201
|
+
await db.push();
|
|
202
|
+
await db.close();
|
|
203
|
+
}
|
|
204
|
+
const transform = (m) => ({
|
|
205
|
+
operation: 'rewrite',
|
|
206
|
+
stmt: {
|
|
207
|
+
sql: `UPDATE counter SET value = value + ? WHERE key = ?`,
|
|
208
|
+
values: [m.after.value - m.before.value, m.after.key]
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
const db1 = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL, transform: transform });
|
|
212
|
+
const db2 = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL, transform: transform });
|
|
213
|
+
await db1.exec("UPDATE counter SET value = value + 1 WHERE key = '1'");
|
|
214
|
+
await db2.exec("UPDATE counter SET value = value + 1 WHERE key = '1'");
|
|
215
|
+
await Promise.all([db1.push(), db2.push()]);
|
|
216
|
+
await Promise.all([db1.pull(), db2.pull()]);
|
|
217
|
+
const rows1 = await db1.prepare('SELECT * FROM counter').all();
|
|
218
|
+
const rows2 = await db2.prepare('SELECT * FROM counter').all();
|
|
219
|
+
expect(rows1).toEqual([{ key: '1', value: 2 }]);
|
|
220
|
+
expect(rows2).toEqual([{ key: '1', value: 2 }]);
|
|
221
|
+
});
|
|
222
|
+
test('transform-many', async () => {
|
|
223
|
+
{
|
|
224
|
+
const db = await connect({
|
|
225
|
+
path: ':memory:',
|
|
226
|
+
url: process.env.VITE_TURSO_DB_URL,
|
|
227
|
+
});
|
|
228
|
+
await db.exec("CREATE TABLE IF NOT EXISTS counter(key TEXT PRIMARY KEY, value INTEGER)");
|
|
229
|
+
await db.exec("DELETE FROM counter");
|
|
230
|
+
await db.exec("INSERT INTO counter VALUES ('1', 0)");
|
|
231
|
+
await db.push();
|
|
232
|
+
await db.close();
|
|
233
|
+
}
|
|
234
|
+
const transform = (m) => ({
|
|
235
|
+
operation: 'rewrite',
|
|
236
|
+
stmt: {
|
|
237
|
+
sql: `UPDATE counter SET value = value + ? WHERE key = ?`,
|
|
238
|
+
values: [m.after.value - m.before.value, m.after.key]
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
const db1 = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL, transform: transform });
|
|
242
|
+
const db2 = await connect({ path: ':memory:', url: process.env.VITE_TURSO_DB_URL, transform: transform });
|
|
243
|
+
for (let i = 0; i < 1002; i++) {
|
|
244
|
+
await db1.exec("UPDATE counter SET value = value + 1 WHERE key = '1'");
|
|
245
|
+
}
|
|
246
|
+
for (let i = 0; i < 1001; i++) {
|
|
247
|
+
await db2.exec("UPDATE counter SET value = value + 1 WHERE key = '1'");
|
|
248
|
+
}
|
|
249
|
+
let start = performance.now();
|
|
250
|
+
await Promise.all([db1.push(), db2.push()]);
|
|
251
|
+
console.info('push', performance.now() - start);
|
|
252
|
+
start = performance.now();
|
|
253
|
+
await Promise.all([db1.pull(), db2.pull()]);
|
|
254
|
+
console.info('pull', performance.now() - start);
|
|
255
|
+
const rows1 = await db1.prepare('SELECT * FROM counter').all();
|
|
256
|
+
const rows2 = await db2.prepare('SELECT * FROM counter').all();
|
|
257
|
+
expect(rows1).toEqual([{ key: '1', value: 1001 + 1002 }]);
|
|
258
|
+
expect(rows2).toEqual([{ key: '1', value: 1001 + 1002 }]);
|
|
259
|
+
});
|
package/index.js
CHANGED
|
@@ -74,23 +74,33 @@ function requireNative() {
|
|
|
74
74
|
} else if (process.platform === 'android') {
|
|
75
75
|
if (process.arch === 'arm64') {
|
|
76
76
|
try {
|
|
77
|
-
return require('./
|
|
77
|
+
return require('./sync.android-arm64.node')
|
|
78
78
|
} catch (e) {
|
|
79
79
|
loadErrors.push(e)
|
|
80
80
|
}
|
|
81
81
|
try {
|
|
82
|
-
|
|
82
|
+
const binding = require('@tursodatabase/sync-android-arm64')
|
|
83
|
+
const bindingPackageVersion = require('@tursodatabase/sync-android-arm64/package.json').version
|
|
84
|
+
if (bindingPackageVersion !== '0.2.0-pre.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
85
|
+
throw new Error(`Native binding package version mismatch, expected 0.2.0-pre.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
86
|
+
}
|
|
87
|
+
return binding
|
|
83
88
|
} catch (e) {
|
|
84
89
|
loadErrors.push(e)
|
|
85
90
|
}
|
|
86
91
|
} else if (process.arch === 'arm') {
|
|
87
92
|
try {
|
|
88
|
-
return require('./
|
|
93
|
+
return require('./sync.android-arm-eabi.node')
|
|
89
94
|
} catch (e) {
|
|
90
95
|
loadErrors.push(e)
|
|
91
96
|
}
|
|
92
97
|
try {
|
|
93
|
-
|
|
98
|
+
const binding = require('@tursodatabase/sync-android-arm-eabi')
|
|
99
|
+
const bindingPackageVersion = require('@tursodatabase/sync-android-arm-eabi/package.json').version
|
|
100
|
+
if (bindingPackageVersion !== '0.2.0-pre.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
101
|
+
throw new Error(`Native binding package version mismatch, expected 0.2.0-pre.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
102
|
+
}
|
|
103
|
+
return binding
|
|
94
104
|
} catch (e) {
|
|
95
105
|
loadErrors.push(e)
|
|
96
106
|
}
|
|
@@ -100,34 +110,49 @@ function requireNative() {
|
|
|
100
110
|
} else if (process.platform === 'win32') {
|
|
101
111
|
if (process.arch === 'x64') {
|
|
102
112
|
try {
|
|
103
|
-
return require('./
|
|
113
|
+
return require('./sync.win32-x64-msvc.node')
|
|
104
114
|
} catch (e) {
|
|
105
115
|
loadErrors.push(e)
|
|
106
116
|
}
|
|
107
117
|
try {
|
|
108
|
-
|
|
118
|
+
const binding = require('@tursodatabase/sync-win32-x64-msvc')
|
|
119
|
+
const bindingPackageVersion = require('@tursodatabase/sync-win32-x64-msvc/package.json').version
|
|
120
|
+
if (bindingPackageVersion !== '0.2.0-pre.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
121
|
+
throw new Error(`Native binding package version mismatch, expected 0.2.0-pre.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
122
|
+
}
|
|
123
|
+
return binding
|
|
109
124
|
} catch (e) {
|
|
110
125
|
loadErrors.push(e)
|
|
111
126
|
}
|
|
112
127
|
} else if (process.arch === 'ia32') {
|
|
113
128
|
try {
|
|
114
|
-
return require('./
|
|
129
|
+
return require('./sync.win32-ia32-msvc.node')
|
|
115
130
|
} catch (e) {
|
|
116
131
|
loadErrors.push(e)
|
|
117
132
|
}
|
|
118
133
|
try {
|
|
119
|
-
|
|
134
|
+
const binding = require('@tursodatabase/sync-win32-ia32-msvc')
|
|
135
|
+
const bindingPackageVersion = require('@tursodatabase/sync-win32-ia32-msvc/package.json').version
|
|
136
|
+
if (bindingPackageVersion !== '0.2.0-pre.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
137
|
+
throw new Error(`Native binding package version mismatch, expected 0.2.0-pre.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
138
|
+
}
|
|
139
|
+
return binding
|
|
120
140
|
} catch (e) {
|
|
121
141
|
loadErrors.push(e)
|
|
122
142
|
}
|
|
123
143
|
} else if (process.arch === 'arm64') {
|
|
124
144
|
try {
|
|
125
|
-
return require('./
|
|
145
|
+
return require('./sync.win32-arm64-msvc.node')
|
|
126
146
|
} catch (e) {
|
|
127
147
|
loadErrors.push(e)
|
|
128
148
|
}
|
|
129
149
|
try {
|
|
130
|
-
|
|
150
|
+
const binding = require('@tursodatabase/sync-win32-arm64-msvc')
|
|
151
|
+
const bindingPackageVersion = require('@tursodatabase/sync-win32-arm64-msvc/package.json').version
|
|
152
|
+
if (bindingPackageVersion !== '0.2.0-pre.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
153
|
+
throw new Error(`Native binding package version mismatch, expected 0.2.0-pre.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
154
|
+
}
|
|
155
|
+
return binding
|
|
131
156
|
} catch (e) {
|
|
132
157
|
loadErrors.push(e)
|
|
133
158
|
}
|
|
@@ -136,34 +161,49 @@ function requireNative() {
|
|
|
136
161
|
}
|
|
137
162
|
} else if (process.platform === 'darwin') {
|
|
138
163
|
try {
|
|
139
|
-
return require('./
|
|
164
|
+
return require('./sync.darwin-universal.node')
|
|
140
165
|
} catch (e) {
|
|
141
166
|
loadErrors.push(e)
|
|
142
167
|
}
|
|
143
168
|
try {
|
|
144
|
-
|
|
169
|
+
const binding = require('@tursodatabase/sync-darwin-universal')
|
|
170
|
+
const bindingPackageVersion = require('@tursodatabase/sync-darwin-universal/package.json').version
|
|
171
|
+
if (bindingPackageVersion !== '0.2.0-pre.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
172
|
+
throw new Error(`Native binding package version mismatch, expected 0.2.0-pre.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
173
|
+
}
|
|
174
|
+
return binding
|
|
145
175
|
} catch (e) {
|
|
146
176
|
loadErrors.push(e)
|
|
147
177
|
}
|
|
148
178
|
if (process.arch === 'x64') {
|
|
149
179
|
try {
|
|
150
|
-
return require('./
|
|
180
|
+
return require('./sync.darwin-x64.node')
|
|
151
181
|
} catch (e) {
|
|
152
182
|
loadErrors.push(e)
|
|
153
183
|
}
|
|
154
184
|
try {
|
|
155
|
-
|
|
185
|
+
const binding = require('@tursodatabase/sync-darwin-x64')
|
|
186
|
+
const bindingPackageVersion = require('@tursodatabase/sync-darwin-x64/package.json').version
|
|
187
|
+
if (bindingPackageVersion !== '0.2.0-pre.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
188
|
+
throw new Error(`Native binding package version mismatch, expected 0.2.0-pre.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
189
|
+
}
|
|
190
|
+
return binding
|
|
156
191
|
} catch (e) {
|
|
157
192
|
loadErrors.push(e)
|
|
158
193
|
}
|
|
159
194
|
} else if (process.arch === 'arm64') {
|
|
160
195
|
try {
|
|
161
|
-
return require('./
|
|
196
|
+
return require('./sync.darwin-arm64.node')
|
|
162
197
|
} catch (e) {
|
|
163
198
|
loadErrors.push(e)
|
|
164
199
|
}
|
|
165
200
|
try {
|
|
166
|
-
|
|
201
|
+
const binding = require('@tursodatabase/sync-darwin-arm64')
|
|
202
|
+
const bindingPackageVersion = require('@tursodatabase/sync-darwin-arm64/package.json').version
|
|
203
|
+
if (bindingPackageVersion !== '0.2.0-pre.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
204
|
+
throw new Error(`Native binding package version mismatch, expected 0.2.0-pre.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
205
|
+
}
|
|
206
|
+
return binding
|
|
167
207
|
} catch (e) {
|
|
168
208
|
loadErrors.push(e)
|
|
169
209
|
}
|
|
@@ -173,23 +213,33 @@ function requireNative() {
|
|
|
173
213
|
} else if (process.platform === 'freebsd') {
|
|
174
214
|
if (process.arch === 'x64') {
|
|
175
215
|
try {
|
|
176
|
-
return require('./
|
|
216
|
+
return require('./sync.freebsd-x64.node')
|
|
177
217
|
} catch (e) {
|
|
178
218
|
loadErrors.push(e)
|
|
179
219
|
}
|
|
180
220
|
try {
|
|
181
|
-
|
|
221
|
+
const binding = require('@tursodatabase/sync-freebsd-x64')
|
|
222
|
+
const bindingPackageVersion = require('@tursodatabase/sync-freebsd-x64/package.json').version
|
|
223
|
+
if (bindingPackageVersion !== '0.2.0-pre.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
224
|
+
throw new Error(`Native binding package version mismatch, expected 0.2.0-pre.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
225
|
+
}
|
|
226
|
+
return binding
|
|
182
227
|
} catch (e) {
|
|
183
228
|
loadErrors.push(e)
|
|
184
229
|
}
|
|
185
230
|
} else if (process.arch === 'arm64') {
|
|
186
231
|
try {
|
|
187
|
-
return require('./
|
|
232
|
+
return require('./sync.freebsd-arm64.node')
|
|
188
233
|
} catch (e) {
|
|
189
234
|
loadErrors.push(e)
|
|
190
235
|
}
|
|
191
236
|
try {
|
|
192
|
-
|
|
237
|
+
const binding = require('@tursodatabase/sync-freebsd-arm64')
|
|
238
|
+
const bindingPackageVersion = require('@tursodatabase/sync-freebsd-arm64/package.json').version
|
|
239
|
+
if (bindingPackageVersion !== '0.2.0-pre.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
240
|
+
throw new Error(`Native binding package version mismatch, expected 0.2.0-pre.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
241
|
+
}
|
|
242
|
+
return binding
|
|
193
243
|
} catch (e) {
|
|
194
244
|
loadErrors.push(e)
|
|
195
245
|
}
|
|
@@ -200,23 +250,33 @@ function requireNative() {
|
|
|
200
250
|
if (process.arch === 'x64') {
|
|
201
251
|
if (isMusl()) {
|
|
202
252
|
try {
|
|
203
|
-
return require('./
|
|
253
|
+
return require('./sync.linux-x64-musl.node')
|
|
204
254
|
} catch (e) {
|
|
205
255
|
loadErrors.push(e)
|
|
206
256
|
}
|
|
207
257
|
try {
|
|
208
|
-
|
|
258
|
+
const binding = require('@tursodatabase/sync-linux-x64-musl')
|
|
259
|
+
const bindingPackageVersion = require('@tursodatabase/sync-linux-x64-musl/package.json').version
|
|
260
|
+
if (bindingPackageVersion !== '0.2.0-pre.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
261
|
+
throw new Error(`Native binding package version mismatch, expected 0.2.0-pre.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
262
|
+
}
|
|
263
|
+
return binding
|
|
209
264
|
} catch (e) {
|
|
210
265
|
loadErrors.push(e)
|
|
211
266
|
}
|
|
212
267
|
} else {
|
|
213
268
|
try {
|
|
214
|
-
return require('./
|
|
269
|
+
return require('./sync.linux-x64-gnu.node')
|
|
215
270
|
} catch (e) {
|
|
216
271
|
loadErrors.push(e)
|
|
217
272
|
}
|
|
218
273
|
try {
|
|
219
|
-
|
|
274
|
+
const binding = require('@tursodatabase/sync-linux-x64-gnu')
|
|
275
|
+
const bindingPackageVersion = require('@tursodatabase/sync-linux-x64-gnu/package.json').version
|
|
276
|
+
if (bindingPackageVersion !== '0.2.0-pre.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
277
|
+
throw new Error(`Native binding package version mismatch, expected 0.2.0-pre.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
278
|
+
}
|
|
279
|
+
return binding
|
|
220
280
|
} catch (e) {
|
|
221
281
|
loadErrors.push(e)
|
|
222
282
|
}
|
|
@@ -224,23 +284,33 @@ function requireNative() {
|
|
|
224
284
|
} else if (process.arch === 'arm64') {
|
|
225
285
|
if (isMusl()) {
|
|
226
286
|
try {
|
|
227
|
-
return require('./
|
|
287
|
+
return require('./sync.linux-arm64-musl.node')
|
|
228
288
|
} catch (e) {
|
|
229
289
|
loadErrors.push(e)
|
|
230
290
|
}
|
|
231
291
|
try {
|
|
232
|
-
|
|
292
|
+
const binding = require('@tursodatabase/sync-linux-arm64-musl')
|
|
293
|
+
const bindingPackageVersion = require('@tursodatabase/sync-linux-arm64-musl/package.json').version
|
|
294
|
+
if (bindingPackageVersion !== '0.2.0-pre.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
295
|
+
throw new Error(`Native binding package version mismatch, expected 0.2.0-pre.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
296
|
+
}
|
|
297
|
+
return binding
|
|
233
298
|
} catch (e) {
|
|
234
299
|
loadErrors.push(e)
|
|
235
300
|
}
|
|
236
301
|
} else {
|
|
237
302
|
try {
|
|
238
|
-
return require('./
|
|
303
|
+
return require('./sync.linux-arm64-gnu.node')
|
|
239
304
|
} catch (e) {
|
|
240
305
|
loadErrors.push(e)
|
|
241
306
|
}
|
|
242
307
|
try {
|
|
243
|
-
|
|
308
|
+
const binding = require('@tursodatabase/sync-linux-arm64-gnu')
|
|
309
|
+
const bindingPackageVersion = require('@tursodatabase/sync-linux-arm64-gnu/package.json').version
|
|
310
|
+
if (bindingPackageVersion !== '0.2.0-pre.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
311
|
+
throw new Error(`Native binding package version mismatch, expected 0.2.0-pre.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
312
|
+
}
|
|
313
|
+
return binding
|
|
244
314
|
} catch (e) {
|
|
245
315
|
loadErrors.push(e)
|
|
246
316
|
}
|
|
@@ -248,23 +318,33 @@ function requireNative() {
|
|
|
248
318
|
} else if (process.arch === 'arm') {
|
|
249
319
|
if (isMusl()) {
|
|
250
320
|
try {
|
|
251
|
-
return require('./
|
|
321
|
+
return require('./sync.linux-arm-musleabihf.node')
|
|
252
322
|
} catch (e) {
|
|
253
323
|
loadErrors.push(e)
|
|
254
324
|
}
|
|
255
325
|
try {
|
|
256
|
-
|
|
326
|
+
const binding = require('@tursodatabase/sync-linux-arm-musleabihf')
|
|
327
|
+
const bindingPackageVersion = require('@tursodatabase/sync-linux-arm-musleabihf/package.json').version
|
|
328
|
+
if (bindingPackageVersion !== '0.2.0-pre.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
329
|
+
throw new Error(`Native binding package version mismatch, expected 0.2.0-pre.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
330
|
+
}
|
|
331
|
+
return binding
|
|
257
332
|
} catch (e) {
|
|
258
333
|
loadErrors.push(e)
|
|
259
334
|
}
|
|
260
335
|
} else {
|
|
261
336
|
try {
|
|
262
|
-
return require('./
|
|
337
|
+
return require('./sync.linux-arm-gnueabihf.node')
|
|
263
338
|
} catch (e) {
|
|
264
339
|
loadErrors.push(e)
|
|
265
340
|
}
|
|
266
341
|
try {
|
|
267
|
-
|
|
342
|
+
const binding = require('@tursodatabase/sync-linux-arm-gnueabihf')
|
|
343
|
+
const bindingPackageVersion = require('@tursodatabase/sync-linux-arm-gnueabihf/package.json').version
|
|
344
|
+
if (bindingPackageVersion !== '0.2.0-pre.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
345
|
+
throw new Error(`Native binding package version mismatch, expected 0.2.0-pre.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
346
|
+
}
|
|
347
|
+
return binding
|
|
268
348
|
} catch (e) {
|
|
269
349
|
loadErrors.push(e)
|
|
270
350
|
}
|
|
@@ -272,46 +352,66 @@ function requireNative() {
|
|
|
272
352
|
} else if (process.arch === 'riscv64') {
|
|
273
353
|
if (isMusl()) {
|
|
274
354
|
try {
|
|
275
|
-
return require('./
|
|
355
|
+
return require('./sync.linux-riscv64-musl.node')
|
|
276
356
|
} catch (e) {
|
|
277
357
|
loadErrors.push(e)
|
|
278
358
|
}
|
|
279
359
|
try {
|
|
280
|
-
|
|
360
|
+
const binding = require('@tursodatabase/sync-linux-riscv64-musl')
|
|
361
|
+
const bindingPackageVersion = require('@tursodatabase/sync-linux-riscv64-musl/package.json').version
|
|
362
|
+
if (bindingPackageVersion !== '0.2.0-pre.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
363
|
+
throw new Error(`Native binding package version mismatch, expected 0.2.0-pre.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
364
|
+
}
|
|
365
|
+
return binding
|
|
281
366
|
} catch (e) {
|
|
282
367
|
loadErrors.push(e)
|
|
283
368
|
}
|
|
284
369
|
} else {
|
|
285
370
|
try {
|
|
286
|
-
return require('./
|
|
371
|
+
return require('./sync.linux-riscv64-gnu.node')
|
|
287
372
|
} catch (e) {
|
|
288
373
|
loadErrors.push(e)
|
|
289
374
|
}
|
|
290
375
|
try {
|
|
291
|
-
|
|
376
|
+
const binding = require('@tursodatabase/sync-linux-riscv64-gnu')
|
|
377
|
+
const bindingPackageVersion = require('@tursodatabase/sync-linux-riscv64-gnu/package.json').version
|
|
378
|
+
if (bindingPackageVersion !== '0.2.0-pre.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
379
|
+
throw new Error(`Native binding package version mismatch, expected 0.2.0-pre.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
380
|
+
}
|
|
381
|
+
return binding
|
|
292
382
|
} catch (e) {
|
|
293
383
|
loadErrors.push(e)
|
|
294
384
|
}
|
|
295
385
|
}
|
|
296
386
|
} else if (process.arch === 'ppc64') {
|
|
297
387
|
try {
|
|
298
|
-
return require('./
|
|
388
|
+
return require('./sync.linux-ppc64-gnu.node')
|
|
299
389
|
} catch (e) {
|
|
300
390
|
loadErrors.push(e)
|
|
301
391
|
}
|
|
302
392
|
try {
|
|
303
|
-
|
|
393
|
+
const binding = require('@tursodatabase/sync-linux-ppc64-gnu')
|
|
394
|
+
const bindingPackageVersion = require('@tursodatabase/sync-linux-ppc64-gnu/package.json').version
|
|
395
|
+
if (bindingPackageVersion !== '0.2.0-pre.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
396
|
+
throw new Error(`Native binding package version mismatch, expected 0.2.0-pre.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
397
|
+
}
|
|
398
|
+
return binding
|
|
304
399
|
} catch (e) {
|
|
305
400
|
loadErrors.push(e)
|
|
306
401
|
}
|
|
307
402
|
} else if (process.arch === 's390x') {
|
|
308
403
|
try {
|
|
309
|
-
return require('./
|
|
404
|
+
return require('./sync.linux-s390x-gnu.node')
|
|
310
405
|
} catch (e) {
|
|
311
406
|
loadErrors.push(e)
|
|
312
407
|
}
|
|
313
408
|
try {
|
|
314
|
-
|
|
409
|
+
const binding = require('@tursodatabase/sync-linux-s390x-gnu')
|
|
410
|
+
const bindingPackageVersion = require('@tursodatabase/sync-linux-s390x-gnu/package.json').version
|
|
411
|
+
if (bindingPackageVersion !== '0.2.0-pre.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
412
|
+
throw new Error(`Native binding package version mismatch, expected 0.2.0-pre.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
413
|
+
}
|
|
414
|
+
return binding
|
|
315
415
|
} catch (e) {
|
|
316
416
|
loadErrors.push(e)
|
|
317
417
|
}
|
|
@@ -321,34 +421,49 @@ function requireNative() {
|
|
|
321
421
|
} else if (process.platform === 'openharmony') {
|
|
322
422
|
if (process.arch === 'arm64') {
|
|
323
423
|
try {
|
|
324
|
-
return require('./
|
|
424
|
+
return require('./sync.openharmony-arm64.node')
|
|
325
425
|
} catch (e) {
|
|
326
426
|
loadErrors.push(e)
|
|
327
427
|
}
|
|
328
428
|
try {
|
|
329
|
-
|
|
429
|
+
const binding = require('@tursodatabase/sync-openharmony-arm64')
|
|
430
|
+
const bindingPackageVersion = require('@tursodatabase/sync-openharmony-arm64/package.json').version
|
|
431
|
+
if (bindingPackageVersion !== '0.2.0-pre.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
432
|
+
throw new Error(`Native binding package version mismatch, expected 0.2.0-pre.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
433
|
+
}
|
|
434
|
+
return binding
|
|
330
435
|
} catch (e) {
|
|
331
436
|
loadErrors.push(e)
|
|
332
437
|
}
|
|
333
438
|
} else if (process.arch === 'x64') {
|
|
334
439
|
try {
|
|
335
|
-
return require('./
|
|
440
|
+
return require('./sync.openharmony-x64.node')
|
|
336
441
|
} catch (e) {
|
|
337
442
|
loadErrors.push(e)
|
|
338
443
|
}
|
|
339
444
|
try {
|
|
340
|
-
|
|
445
|
+
const binding = require('@tursodatabase/sync-openharmony-x64')
|
|
446
|
+
const bindingPackageVersion = require('@tursodatabase/sync-openharmony-x64/package.json').version
|
|
447
|
+
if (bindingPackageVersion !== '0.2.0-pre.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
448
|
+
throw new Error(`Native binding package version mismatch, expected 0.2.0-pre.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
449
|
+
}
|
|
450
|
+
return binding
|
|
341
451
|
} catch (e) {
|
|
342
452
|
loadErrors.push(e)
|
|
343
453
|
}
|
|
344
454
|
} else if (process.arch === 'arm') {
|
|
345
455
|
try {
|
|
346
|
-
return require('./
|
|
456
|
+
return require('./sync.openharmony-arm.node')
|
|
347
457
|
} catch (e) {
|
|
348
458
|
loadErrors.push(e)
|
|
349
459
|
}
|
|
350
460
|
try {
|
|
351
|
-
|
|
461
|
+
const binding = require('@tursodatabase/sync-openharmony-arm')
|
|
462
|
+
const bindingPackageVersion = require('@tursodatabase/sync-openharmony-arm/package.json').version
|
|
463
|
+
if (bindingPackageVersion !== '0.2.0-pre.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
464
|
+
throw new Error(`Native binding package version mismatch, expected 0.2.0-pre.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
465
|
+
}
|
|
466
|
+
return binding
|
|
352
467
|
} catch (e) {
|
|
353
468
|
loadErrors.push(e)
|
|
354
469
|
}
|
|
@@ -364,7 +479,7 @@ nativeBinding = requireNative()
|
|
|
364
479
|
|
|
365
480
|
if (!nativeBinding || process.env.NAPI_RS_FORCE_WASI) {
|
|
366
481
|
try {
|
|
367
|
-
nativeBinding = require('./
|
|
482
|
+
nativeBinding = require('./sync.wasi.cjs')
|
|
368
483
|
} catch (err) {
|
|
369
484
|
if (process.env.NAPI_RS_FORCE_WASI) {
|
|
370
485
|
loadErrors.push(err)
|
|
@@ -393,14 +508,13 @@ if (!nativeBinding) {
|
|
|
393
508
|
throw new Error(`Failed to load native binding`)
|
|
394
509
|
}
|
|
395
510
|
|
|
396
|
-
const { Database, Statement, GeneratorHolder, JsDataCompletion,
|
|
511
|
+
const { Database, Statement, GeneratorHolder, JsDataCompletion, JsProtocolIo, JsProtocolRequestBytes, SyncEngine, DatabaseChangeTypeJs, SyncEngineProtocolVersion } = nativeBinding
|
|
397
512
|
export { Database }
|
|
398
513
|
export { Statement }
|
|
399
514
|
export { GeneratorHolder }
|
|
400
515
|
export { JsDataCompletion }
|
|
401
|
-
export { JsDataPollResult }
|
|
402
516
|
export { JsProtocolIo }
|
|
403
|
-
export {
|
|
517
|
+
export { JsProtocolRequestBytes }
|
|
404
518
|
export { SyncEngine }
|
|
405
519
|
export { DatabaseChangeTypeJs }
|
|
406
520
|
export { SyncEngineProtocolVersion }
|
package/package.json
CHANGED
|
@@ -1,70 +1,59 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tursodatabase/sync",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0-pre.3",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/tursodatabase/turso"
|
|
7
7
|
},
|
|
8
|
-
"
|
|
9
|
-
"module": "./dist/
|
|
10
|
-
"main": "./dist/
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"module": "./dist/promise.js",
|
|
10
|
+
"main": "./dist/promise.js",
|
|
11
11
|
"type": "module",
|
|
12
|
-
"exports":
|
|
12
|
+
"exports": {
|
|
13
|
+
".": "./dist/promise.js",
|
|
14
|
+
"./compat": "./dist/compat.js"
|
|
15
|
+
},
|
|
13
16
|
"files": [
|
|
14
|
-
"browser.js",
|
|
15
17
|
"index.js",
|
|
16
|
-
"dist/**"
|
|
18
|
+
"dist/**",
|
|
19
|
+
"README.md"
|
|
17
20
|
],
|
|
18
|
-
"
|
|
21
|
+
"packageManager": "yarn@4.9.2",
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@napi-rs/cli": "^3.1.5",
|
|
24
|
+
"@types/node": "^24.3.1",
|
|
25
|
+
"typescript": "^5.9.2",
|
|
26
|
+
"vitest": "^3.2.4"
|
|
27
|
+
},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"napi-build": "napi build --platform --release --esm --manifest-path ../../Cargo.toml --output-dir .",
|
|
30
|
+
"napi-dirs": "napi create-npm-dirs",
|
|
31
|
+
"napi-artifacts": "napi artifacts --output-dir .",
|
|
32
|
+
"tsc-build": "npm exec tsc",
|
|
33
|
+
"build": "npm run napi-build && npm run tsc-build",
|
|
34
|
+
"test": "VITE_TURSO_DB_URL=http://b--a--a.localhost:10000 vitest --run",
|
|
35
|
+
"prepublishOnly": "npm run napi-dirs && npm run napi-artifacts && napi prepublish -t npm"
|
|
36
|
+
},
|
|
19
37
|
"napi": {
|
|
20
|
-
"binaryName": "
|
|
38
|
+
"binaryName": "sync",
|
|
21
39
|
"targets": [
|
|
22
40
|
"x86_64-unknown-linux-gnu",
|
|
23
41
|
"x86_64-pc-windows-msvc",
|
|
24
|
-
"
|
|
25
|
-
"aarch64-unknown-linux-gnu"
|
|
26
|
-
"wasm32-wasip1-threads"
|
|
42
|
+
"aarch64-apple-darwin",
|
|
43
|
+
"aarch64-unknown-linux-gnu"
|
|
27
44
|
]
|
|
28
45
|
},
|
|
29
|
-
"
|
|
30
|
-
|
|
31
|
-
"@
|
|
32
|
-
"@napi-rs/wasm-runtime": "^1.0.1",
|
|
33
|
-
"@types/node": "^24.2.0",
|
|
34
|
-
"ava": "^6.0.1",
|
|
35
|
-
"typescript": "^5.9.2"
|
|
36
|
-
},
|
|
37
|
-
"ava": {
|
|
38
|
-
"timeout": "3m"
|
|
39
|
-
},
|
|
40
|
-
"engines": {
|
|
41
|
-
"node": ">= 10"
|
|
42
|
-
},
|
|
43
|
-
"scripts": {
|
|
44
|
-
"artifacts": "napi artifacts",
|
|
45
|
-
"build": "npm exec tsc && napi build --platform --release --esm",
|
|
46
|
-
"build:debug": "npm exec tsc && napi build --platform",
|
|
47
|
-
"prepublishOnly": "npm exec tsc && napi prepublish -t npm",
|
|
48
|
-
"test": "true",
|
|
49
|
-
"universal": "napi universalize",
|
|
50
|
-
"version": "napi version"
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@tursodatabase/database-common": "^0.2.0-pre.3",
|
|
48
|
+
"@tursodatabase/sync-common": "^0.2.0-pre.3"
|
|
51
49
|
},
|
|
52
|
-
"packageManager": "yarn@4.9.2",
|
|
53
50
|
"imports": {
|
|
54
|
-
"#
|
|
55
|
-
"types": "./index.d.ts",
|
|
56
|
-
"browser": "./browser.js",
|
|
57
|
-
"node": "./index.js"
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
"dependencies": {
|
|
61
|
-
"@tursodatabase/database": "~0.1.4-pre.5"
|
|
51
|
+
"#index": "./index.js"
|
|
62
52
|
},
|
|
63
53
|
"optionalDependencies": {
|
|
64
|
-
"@tursodatabase/sync-linux-x64-gnu": "0.
|
|
65
|
-
"@tursodatabase/sync-win32-x64-msvc": "0.
|
|
66
|
-
"@tursodatabase/sync-darwin-
|
|
67
|
-
"@tursodatabase/sync-linux-arm64-gnu": "0.
|
|
68
|
-
"@tursodatabase/sync-wasm32-wasi": "0.1.5"
|
|
54
|
+
"@tursodatabase/sync-linux-x64-gnu": "0.2.0-pre.3",
|
|
55
|
+
"@tursodatabase/sync-win32-x64-msvc": "0.2.0-pre.3",
|
|
56
|
+
"@tursodatabase/sync-darwin-arm64": "0.2.0-pre.3",
|
|
57
|
+
"@tursodatabase/sync-linux-arm64-gnu": "0.2.0-pre.3"
|
|
69
58
|
}
|
|
70
59
|
}
|
package/browser.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from '@tursodatabase/sync-wasm32-wasi'
|
package/dist/sync_engine.d.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { DatabaseRowMutationJs, DatabaseRowStatementJs } from '#entry-point';
|
|
2
|
-
import { Database } from '@tursodatabase/database';
|
|
3
|
-
interface ConnectOpts {
|
|
4
|
-
path: string;
|
|
5
|
-
clientName?: string;
|
|
6
|
-
url: string;
|
|
7
|
-
authToken?: string;
|
|
8
|
-
encryptionKey?: string;
|
|
9
|
-
tablesIgnore?: string[];
|
|
10
|
-
transform?: (arg: DatabaseRowMutationJs) => DatabaseRowStatementJs | null;
|
|
11
|
-
enableTracing?: string;
|
|
12
|
-
}
|
|
13
|
-
interface Sync {
|
|
14
|
-
sync(): Promise<void>;
|
|
15
|
-
push(): Promise<void>;
|
|
16
|
-
pull(): Promise<void>;
|
|
17
|
-
checkpoint(): Promise<void>;
|
|
18
|
-
stats(): Promise<{
|
|
19
|
-
operations: number;
|
|
20
|
-
wal: number;
|
|
21
|
-
}>;
|
|
22
|
-
}
|
|
23
|
-
export declare function connect(opts: ConnectOpts): Database & Sync;
|
|
24
|
-
export { Database, Sync };
|
package/dist/sync_engine.js
DELETED
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
import { SyncEngine } from '#entry-point';
|
|
3
|
-
import { Database } from '@tursodatabase/database';
|
|
4
|
-
const GENERATOR_RESUME_IO = 0;
|
|
5
|
-
const GENERATOR_RESUME_DONE = 1;
|
|
6
|
-
function trackPromise(p) {
|
|
7
|
-
let status = { promise: null, finished: false };
|
|
8
|
-
status.promise = p.finally(() => status.finished = true);
|
|
9
|
-
return status;
|
|
10
|
-
}
|
|
11
|
-
function timeoutMs(ms) {
|
|
12
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
13
|
-
}
|
|
14
|
-
async function read(opts, path) {
|
|
15
|
-
if (opts.isMemory) {
|
|
16
|
-
return opts.value;
|
|
17
|
-
}
|
|
18
|
-
if (typeof window === 'undefined') {
|
|
19
|
-
const { promises } = await import('node:fs');
|
|
20
|
-
try {
|
|
21
|
-
return await promises.readFile(path);
|
|
22
|
-
}
|
|
23
|
-
catch (error) {
|
|
24
|
-
if (error.code === 'ENOENT') {
|
|
25
|
-
return null;
|
|
26
|
-
}
|
|
27
|
-
throw error;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
else {
|
|
31
|
-
const data = localStorage.getItem(path);
|
|
32
|
-
if (data != null) {
|
|
33
|
-
return new TextEncoder().encode(data);
|
|
34
|
-
}
|
|
35
|
-
else {
|
|
36
|
-
return null;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
async function write(opts, path, content) {
|
|
41
|
-
if (opts.isMemory) {
|
|
42
|
-
opts.value = content;
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
const data = new Uint8Array(content);
|
|
46
|
-
if (typeof window === 'undefined') {
|
|
47
|
-
const { promises } = await import('node:fs');
|
|
48
|
-
const unix = Math.floor(Date.now() / 1000);
|
|
49
|
-
const nonce = Math.floor(Math.random() * 1000000000);
|
|
50
|
-
const tmp = `${path}.tmp.${unix}.${nonce}`;
|
|
51
|
-
await promises.writeFile(tmp, data);
|
|
52
|
-
await promises.rename(tmp, path);
|
|
53
|
-
}
|
|
54
|
-
else {
|
|
55
|
-
localStorage.setItem(path, new TextDecoder().decode(data));
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
async function process(opts, request) {
|
|
59
|
-
const requestType = request.request();
|
|
60
|
-
const completion = request.completion();
|
|
61
|
-
if (requestType.type == 'Http') {
|
|
62
|
-
try {
|
|
63
|
-
let headers = opts.headers;
|
|
64
|
-
if (requestType.headers != null && requestType.headers.length > 0) {
|
|
65
|
-
headers = { ...opts.headers };
|
|
66
|
-
for (let header of requestType.headers) {
|
|
67
|
-
headers[header[0]] = header[1];
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
const response = await fetch(`${opts.url}${requestType.path}`, {
|
|
71
|
-
method: requestType.method,
|
|
72
|
-
headers: headers,
|
|
73
|
-
body: requestType.body != null ? new Uint8Array(requestType.body) : null,
|
|
74
|
-
});
|
|
75
|
-
completion.status(response.status);
|
|
76
|
-
const reader = response.body.getReader();
|
|
77
|
-
while (true) {
|
|
78
|
-
const { done, value } = await reader.read();
|
|
79
|
-
if (done) {
|
|
80
|
-
completion.done();
|
|
81
|
-
break;
|
|
82
|
-
}
|
|
83
|
-
completion.push(value);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
catch (error) {
|
|
87
|
-
completion.poison(`fetch error: ${error}`);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
else if (requestType.type == 'FullRead') {
|
|
91
|
-
try {
|
|
92
|
-
const metadata = await read(opts.metadata, requestType.path);
|
|
93
|
-
if (metadata != null) {
|
|
94
|
-
completion.push(metadata);
|
|
95
|
-
}
|
|
96
|
-
completion.done();
|
|
97
|
-
}
|
|
98
|
-
catch (error) {
|
|
99
|
-
completion.poison(`metadata read error: ${error}`);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
else if (requestType.type == 'FullWrite') {
|
|
103
|
-
try {
|
|
104
|
-
await write(opts.metadata, requestType.path, requestType.content);
|
|
105
|
-
completion.done();
|
|
106
|
-
}
|
|
107
|
-
catch (error) {
|
|
108
|
-
completion.poison(`metadata write error: ${error}`);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
async function run(opts, engine, generator) {
|
|
113
|
-
let tasks = [];
|
|
114
|
-
while (generator.resume(null) !== GENERATOR_RESUME_DONE) {
|
|
115
|
-
for (let request = engine.protocolIo(); request != null; request = engine.protocolIo()) {
|
|
116
|
-
tasks.push(trackPromise(process(opts, request)));
|
|
117
|
-
}
|
|
118
|
-
const tasksRace = tasks.length == 0 ? Promise.resolve() : Promise.race([timeoutMs(opts.preemptionMs), ...tasks.map(t => t.promise)]);
|
|
119
|
-
await Promise.all([engine.ioLoopAsync(), tasksRace]);
|
|
120
|
-
tasks = tasks.filter(t => !t.finished);
|
|
121
|
-
}
|
|
122
|
-
return generator.take();
|
|
123
|
-
}
|
|
124
|
-
export async function connect(opts) {
|
|
125
|
-
const engine = new SyncEngine({
|
|
126
|
-
path: opts.path,
|
|
127
|
-
clientName: opts.clientName,
|
|
128
|
-
tablesIgnore: opts.tablesIgnore,
|
|
129
|
-
transform: opts.transform,
|
|
130
|
-
enableTracing: opts.enableTracing
|
|
131
|
-
});
|
|
132
|
-
const httpOpts = {
|
|
133
|
-
url: opts.url,
|
|
134
|
-
headers: {
|
|
135
|
-
...(opts.authToken != null && { "Authorization": `Bearer ${opts.authToken}` }),
|
|
136
|
-
...(opts.encryptionKey != null && { "x-turso-encryption-key": opts.encryptionKey })
|
|
137
|
-
},
|
|
138
|
-
metadata: opts.path == ':memory:' ? { isMemory: true, value: null } : { isMemory: false },
|
|
139
|
-
preemptionMs: 1,
|
|
140
|
-
};
|
|
141
|
-
await run(httpOpts, engine, engine.init());
|
|
142
|
-
const nativeDb = engine.open();
|
|
143
|
-
const db = Database.create();
|
|
144
|
-
db.initialize(nativeDb, opts.path, false);
|
|
145
|
-
db.sync = async function () { await run(httpOpts, engine, engine.sync()); };
|
|
146
|
-
db.pull = async function () { await run(httpOpts, engine, engine.pull()); };
|
|
147
|
-
db.push = async function () { await run(httpOpts, engine, engine.push()); };
|
|
148
|
-
db.checkpoint = async function () { await run(httpOpts, engine, engine.checkpoint()); };
|
|
149
|
-
db.stats = async function () { return (await run(httpOpts, engine, engine.stats())); };
|
|
150
|
-
return db;
|
|
151
|
-
}
|
|
152
|
-
export { Database };
|