You're Invited:Meet the Socket Team at BlackHat and DEF CON in Las Vegas, Aug 4-6.RSVP
Socket
Book a DemoInstallSign in
Socket

cojson-storage-sqlite

Package Overview
Dependencies
Maintainers
1
Versions
186
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

cojson-storage-sqlite - npm Package Compare versions

Comparing version

to
0.15.9

8

CHANGELOG.md
# cojson-storage-sqlite
## 0.15.9
### Patch Changes
- Updated dependencies [27b4837]
- Updated dependencies [2776263]
- cojson@0.15.9
## 0.15.8

@@ -4,0 +12,0 @@

12

dist/index.d.ts

@@ -1,2 +0,12 @@

export { SQLiteNode, SQLiteNode as SQLiteStorage } from "./sqliteNode.js";
import type { SQLiteDatabaseDriver } from "cojson";
export declare class BetterSqliteDriver implements SQLiteDatabaseDriver {
private readonly db;
constructor(filename: string);
run(sql: string, params: unknown[]): void;
query<T>(sql: string, params: unknown[]): T[];
get<T>(sql: string, params: unknown[]): T | undefined;
transaction(callback: () => unknown): unknown;
closeDb(): void;
}
export declare function getBetterSqliteStorage(filename: string): import("cojson").StorageApiSync;
//# sourceMappingURL=index.d.ts.map

@@ -1,2 +0,29 @@

export { SQLiteNode, SQLiteNode as SQLiteStorage } from "./sqliteNode.js";
import Database from "better-sqlite3";
import { getSqliteStorage } from "cojson";
export class BetterSqliteDriver {
constructor(filename) {
const db = new Database(filename);
this.db = db;
db.pragma("journal_mode = WAL");
}
run(sql, params) {
this.db.prepare(sql).run(params);
}
query(sql, params) {
return this.db.prepare(sql).all(params);
}
get(sql, params) {
return this.db.prepare(sql).get(params);
}
transaction(callback) {
return this.db.transaction(callback)();
}
closeDb() {
this.db.close();
}
}
export function getBetterSqliteStorage(filename) {
const db = new BetterSqliteDriver(filename);
return getSqliteStorage(db);
}
//# sourceMappingURL=index.js.map

171

dist/tests/storage.sqlite.test.js

@@ -5,12 +5,10 @@ import { randomUUID } from "node:crypto";

import { join } from "node:path";
import { LocalNode, cojsonInternals } from "cojson";
import { SQLiteNodeBase, StorageManagerSync } from "cojson-storage";
import { LocalNode, StorageApiSync, cojsonInternals } from "cojson";
import { WasmCrypto } from "cojson/crypto/WasmCrypto";
import { expect, onTestFinished, test, vi } from "vitest";
import { BetterSqliteDriver } from "../betterSqliteDriver.js";
import { SQLiteNode } from "../index.js";
import { getBetterSqliteStorage } from "../index.js";
import { toSimplifiedMessages } from "./messagesTestUtils.js";
import { trackMessages, waitFor } from "./testUtils.js";
const Crypto = await WasmCrypto.create();
async function createSQLiteStorage(defaultDbPath) {
function createSQLiteStorage(defaultDbPath) {
const dbPath = defaultDbPath ?? join(tmpdir(), `test-${randomUUID()}.db`);

@@ -23,21 +21,12 @@ if (!defaultDbPath) {

return {
peer: await SQLiteNode.asPeer({
filename: dbPath,
}),
storage: getBetterSqliteStorage(dbPath),
dbPath,
};
}
test("Should be able to initialize and load from empty DB", async () => {
const agentSecret = Crypto.newRandomAgentSecret();
const node = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
node.syncManager.addPeer((await createSQLiteStorage()).peer);
await new Promise((resolve) => setTimeout(resolve, 200));
expect(node.syncManager.peers.storage).toBeDefined();
});
test("should sync and load data from storage", async () => {
const agentSecret = Crypto.newRandomAgentSecret();
const node1 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
const node1Sync = trackMessages(node1);
const { peer, dbPath } = await createSQLiteStorage();
node1.syncManager.addPeer(peer);
const node1Sync = trackMessages();
const { storage, dbPath } = createSQLiteStorage();
node1.setStorage(storage);
const group = node1.createGroup();

@@ -53,5 +42,3 @@ const map = group.createMap();

"client -> CONTENT Group header: true new: After: 0 New: 3",
"storage -> KNOWN Group sessions: header/3",
"client -> CONTENT Map header: true new: After: 0 New: 1",
"storage -> KNOWN Map sessions: header/1",
]

@@ -61,5 +48,4 @@ `);

const node2 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
const node2Sync = trackMessages(node2);
const { peer: peer2 } = await createSQLiteStorage(dbPath);
node2.syncManager.addPeer(peer2);
const node2Sync = trackMessages();
node2.setStorage(createSQLiteStorage(dbPath).storage);
const map2 = await node2.load(map.id);

@@ -77,5 +63,3 @@ if (map2 === "unavailable") {

"storage -> CONTENT Group header: true new: After: 0 New: 3",
"client -> KNOWN Group sessions: header/3",
"storage -> CONTENT Map header: true new: After: 0 New: 1",
"client -> KNOWN Map sessions: header/1",
]

@@ -88,5 +72,5 @@ `);

const node1 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
const node1Sync = trackMessages(node1);
const { peer, dbPath } = await createSQLiteStorage();
node1.syncManager.addPeer(peer);
const node1Sync = trackMessages();
const { storage, dbPath } = createSQLiteStorage();
node1.setStorage(storage);
const group = node1.createGroup();

@@ -101,5 +85,3 @@ const map = group.createMap();

"client -> CONTENT Group header: true new: After: 0 New: 3",
"storage -> KNOWN Group sessions: header/3",
"client -> CONTENT Map header: true new: ",
"storage -> KNOWN Map sessions: header/0",
]

@@ -109,5 +91,4 @@ `);

const node2 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
const node2Sync = trackMessages(node2);
const { peer: peer2 } = await createSQLiteStorage(dbPath);
node2.syncManager.addPeer(peer2);
const node2Sync = trackMessages();
node2.setStorage(createSQLiteStorage(dbPath).storage);
const map2 = await node2.load(map.id);

@@ -124,5 +105,3 @@ if (map2 === "unavailable") {

"storage -> CONTENT Group header: true new: After: 0 New: 3",
"client -> KNOWN Group sessions: header/3",
"storage -> CONTENT Map header: true new: ",
"client -> KNOWN Map sessions: header/0",
]

@@ -135,5 +114,5 @@ `);

const node1 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
const node1Sync = trackMessages(node1);
const { peer, dbPath } = await createSQLiteStorage();
node1.syncManager.addPeer(peer);
const node1Sync = trackMessages();
const { storage, dbPath } = createSQLiteStorage();
node1.setStorage(storage);
const group = node1.createGroup();

@@ -151,8 +130,5 @@ const parentGroup = node1.createGroup();

[
"client -> CONTENT Group header: true new: After: 0 New: 5",
"client -> CONTENT ParentGroup header: true new: After: 0 New: 4",
"storage -> KNOWN ParentGroup sessions: header/4",
"client -> CONTENT Group header: true new: After: 0 New: 5",
"storage -> KNOWN Group sessions: header/5",
"client -> CONTENT Map header: true new: After: 0 New: 1",
"storage -> KNOWN Map sessions: header/1",
]

@@ -162,5 +138,4 @@ `);

const node2 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
const node2Sync = trackMessages(node2);
const { peer: peer2 } = await createSQLiteStorage(dbPath);
node2.syncManager.addPeer(peer2);
const node2Sync = trackMessages();
node2.setStorage(createSQLiteStorage(dbPath).storage);
await node2.load(map.id);

@@ -178,7 +153,4 @@ expect(node2.expectCoValueLoaded(map.id)).toBeTruthy();

"storage -> CONTENT ParentGroup header: true new: After: 0 New: 4",
"client -> KNOWN ParentGroup sessions: header/4",
"storage -> CONTENT Group header: true new: After: 0 New: 5",
"client -> KNOWN Group sessions: header/5",
"storage -> CONTENT Map header: true new: After: 0 New: 1",
"client -> KNOWN Map sessions: header/1",
]

@@ -190,5 +162,5 @@ `);

const node1 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
const node1Sync = trackMessages(node1);
const { peer, dbPath } = await createSQLiteStorage();
node1.syncManager.addPeer(peer);
const node1Sync = trackMessages();
const { storage, dbPath } = createSQLiteStorage();
node1.setStorage(storage);
const group = node1.createGroup();

@@ -204,5 +176,4 @@ const parentGroup = node1.createGroup();

const node2 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
const node2Sync = trackMessages(node2);
const { peer: peer2 } = await createSQLiteStorage(dbPath);
node2.syncManager.addPeer(peer2);
const node2Sync = trackMessages();
node2.setStorage(createSQLiteStorage(dbPath).storage);
await node2.load(map.id);

@@ -223,10 +194,6 @@ await node2.load(mapFromParent.id);

"storage -> CONTENT ParentGroup header: true new: After: 0 New: 4",
"client -> KNOWN ParentGroup sessions: header/4",
"storage -> CONTENT Group header: true new: After: 0 New: 5",
"client -> KNOWN Group sessions: header/5",
"storage -> CONTENT Map header: true new: After: 0 New: 1",
"client -> KNOWN Map sessions: header/1",
"client -> LOAD MapFromParent sessions: empty",
"storage -> CONTENT MapFromParent header: true new: After: 0 New: 1",
"client -> KNOWN MapFromParent sessions: header/1",
]

@@ -238,5 +205,5 @@ `);

const node1 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
const node1Sync = trackMessages(node1);
const { peer, dbPath } = await createSQLiteStorage();
node1.syncManager.addPeer(peer);
const node1Sync = trackMessages();
const { storage, dbPath } = createSQLiteStorage();
node1.setStorage(storage);
const group = node1.createGroup();

@@ -247,4 +214,4 @@ const map = group.createMap();

const mock = vi
.spyOn(StorageManagerSync.prototype, "handleSyncMessage")
.mockImplementation(() => Promise.resolve());
.spyOn(StorageApiSync.prototype, "store")
.mockImplementation(() => false);
map.set("1", 1);

@@ -262,9 +229,4 @@ map.set("2", 2);

"client -> CONTENT Group header: true new: After: 0 New: 3",
"storage -> KNOWN Group sessions: header/3",
"client -> CONTENT Map header: true new: After: 0 New: 1",
"storage -> KNOWN Map sessions: header/1",
"client -> CONTENT Map header: false new: After: 3 New: 1",
"storage -> KNOWN CORRECTION Map sessions: header/1",
"client -> CONTENT Map header: false new: After: 1 New: 3",
"storage -> KNOWN Map sessions: header/4",
]

@@ -274,5 +236,4 @@ `);

const node2 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
const node2Sync = trackMessages(node2);
const { peer: peer2 } = await createSQLiteStorage(dbPath);
node2.syncManager.addPeer(peer2);
const node2Sync = trackMessages();
node2.setStorage(createSQLiteStorage(dbPath).storage);
const map2 = await node2.load(map.id);

@@ -295,5 +256,3 @@ if (map2 === "unavailable") {

"storage -> CONTENT Group header: true new: After: 0 New: 3",
"client -> KNOWN Group sessions: header/3",
"storage -> CONTENT Map header: true new: After: 0 New: 4",
"client -> KNOWN Map sessions: header/4",
]

@@ -315,14 +274,14 @@ `);

serverNode.syncManager.addPeer(clientPeer);
const handleSyncMessage = StorageManagerSync.prototype.handleSyncMessage;
const store = StorageApiSync.prototype.store;
const mock = vi
.spyOn(StorageManagerSync.prototype, "handleSyncMessage")
.mockImplementation(function (msg) {
if (msg.action === "content" &&
[group.core.id, account.core.id].includes(msg.id)) {
return Promise.resolve();
.spyOn(StorageApiSync.prototype, "store")
.mockImplementation(function (data, correctionCallback) {
if (data[0]?.id &&
[group.core.id, account.core.id].includes(data[0].id)) {
return false;
}
return handleSyncMessage.call(this, msg);
return store.call(this, data, correctionCallback);
});
const { peer, dbPath } = await createSQLiteStorage();
node1.syncManager.addPeer(peer);
const { storage, dbPath } = createSQLiteStorage();
node1.setStorage(storage);
const group = node1.createGroup();

@@ -341,4 +300,3 @@ group.addMember("everyone", "writer");

serverNode.syncManager.addPeer(clientPeer2);
const { peer: peer2 } = await createSQLiteStorage(dbPath);
node2.syncManager.addPeer(peer2);
node2.setStorage(createSQLiteStorage(dbPath).storage);
const map2 = await node2.load(map.id);

@@ -355,4 +313,4 @@ if (map2 === "unavailable") {

const node1 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
const { peer, dbPath } = await createSQLiteStorage();
node1.syncManager.addPeer(peer);
const { storage, dbPath } = createSQLiteStorage();
node1.setStorage(storage);
const group = node1.createGroup();

@@ -364,3 +322,3 @@ const map = group.createMap();

const node2 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
node2.syncManager.addPeer((await createSQLiteStorage(dbPath)).peer);
node2.setStorage(createSQLiteStorage(dbPath).storage);
const map2 = await node2.load(map.id);

@@ -375,4 +333,4 @@ if (map2 === "unavailable") {

const node3 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
const node3Sync = trackMessages(node3);
node3.syncManager.addPeer((await createSQLiteStorage(dbPath)).peer);
const node3Sync = trackMessages();
node3.setStorage(createSQLiteStorage(dbPath).storage);
const map3 = await node3.load(map.id);

@@ -390,5 +348,3 @@ if (map3 === "unavailable") {

"storage -> CONTENT Group header: true new: After: 0 New: 3",
"client -> KNOWN Group sessions: header/3",
"storage -> CONTENT Map header: true new: After: 0 New: 1 | After: 0 New: 1",
"client -> KNOWN Map sessions: header/2",
]

@@ -401,4 +357,4 @@ `);

const node1 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
const { peer, dbPath } = await createSQLiteStorage();
node1.syncManager.addPeer(peer);
const { storage, dbPath } = createSQLiteStorage();
node1.setStorage(storage);
const group = node1.createGroup();

@@ -417,5 +373,4 @@ const largeMap = group.createMap();

const node2 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
const node2Sync = trackMessages(node2);
const { peer: peer2 } = await createSQLiteStorage(dbPath);
node2.syncManager.addPeer(peer2);
const node2Sync = trackMessages();
node2.setStorage(createSQLiteStorage(dbPath).storage);
const largeMapOnNode2 = await node2.load(largeMap.id);

@@ -435,33 +390,9 @@ if (largeMapOnNode2 === "unavailable") {

"client -> LOAD Map sessions: empty",
"storage -> KNOWN Map sessions: header/200",
"storage -> CONTENT Group header: true new: After: 0 New: 3",
"client -> KNOWN Group sessions: header/3",
"storage -> CONTENT Map header: true new: After: 0 New: 97",
"client -> KNOWN Map sessions: header/97",
"storage -> CONTENT Map header: true new: After: 97 New: 97",
"client -> KNOWN Map sessions: header/194",
"storage -> CONTENT Map header: true new: After: 194 New: 6",
"client -> KNOWN Map sessions: header/200",
]
`);
});
test("should close the db when the node is closed", async () => {
const agentSecret = Crypto.newRandomAgentSecret();
const node1 = new LocalNode(agentSecret, Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)), Crypto);
const dbPath = join(tmpdir(), `test-${randomUUID()}.db`);
const db = new BetterSqliteDriver(dbPath);
const peer = SQLiteNodeBase.create({
db,
localNodeName: "test",
maxBlockingTime: 500,
});
const spy = vi.spyOn(db, "closeDb");
node1.syncManager.addPeer(peer);
await new Promise((resolve) => setTimeout(resolve, 10));
expect(spy).not.toHaveBeenCalled();
node1.gracefulShutdown();
await new Promise((resolve) => setTimeout(resolve, 10));
expect(spy).toHaveBeenCalled();
unlinkSync(dbPath);
});
//# sourceMappingURL=storage.sqlite.test.js.map

@@ -1,3 +0,3 @@

import type { LocalNode, SyncMessage } from "cojson";
export declare function trackMessages(node: LocalNode): {
import type { SyncMessage } from "cojson";
export declare function trackMessages(): {
messages: {

@@ -4,0 +4,0 @@ from: "client" | "server" | "storage";

@@ -1,24 +0,48 @@

import { StorageManagerSync } from "cojson-storage";
import { StorageApiSync } from "cojson";
import { onTestFinished } from "vitest";
export function trackMessages(node) {
export function trackMessages() {
const messages = [];
const originalHandleSyncMessage = StorageManagerSync.prototype.handleSyncMessage;
const originalNodeSyncMessage = node.syncManager.handleSyncMessage;
StorageManagerSync.prototype.handleSyncMessage = async function (msg) {
const originalLoad = StorageApiSync.prototype.load;
const originalStore = StorageApiSync.prototype.store;
StorageApiSync.prototype.load = async function (id, callback, done) {
messages.push({
from: "client",
msg,
msg: {
action: "load",
id: id,
header: false,
sessions: {},
},
});
return originalHandleSyncMessage.call(this, msg);
return originalLoad.call(this, id, (msg) => {
messages.push({
from: "storage",
msg,
});
callback(msg);
}, done);
};
node.syncManager.handleSyncMessage = async function (msg, peer) {
messages.push({
from: "storage",
msg,
StorageApiSync.prototype.store = function (data, correctionCallback) {
for (const msg of data) {
messages.push({
from: "client",
msg,
});
}
return originalStore.call(this, data, (msg) => {
messages.push({
from: "storage",
msg: {
action: "known",
isCorrection: true,
...msg,
},
});
correctionCallback(msg);
});
return originalNodeSyncMessage.call(this, msg, peer);
};
const restore = () => {
StorageManagerSync.prototype.handleSyncMessage = originalHandleSyncMessage;
node.syncManager.handleSyncMessage = originalNodeSyncMessage;
StorageApiSync.prototype.load = originalLoad;
StorageApiSync.prototype.store = originalStore;
messages.length = 0;
};

@@ -25,0 +49,0 @@ onTestFinished(() => {

{
"name": "cojson-storage-sqlite",
"type": "module",
"version": "0.15.8",
"version": "0.15.9",
"main": "dist/index.js",

@@ -10,4 +10,3 @@ "types": "dist/index.d.ts",

"better-sqlite3": "^11.7.0",
"cojson": "0.15.8",
"cojson-storage": "0.15.8"
"cojson": "0.15.9"
},

@@ -14,0 +13,0 @@ "devDependencies": {

@@ -1,1 +0,39 @@

export { SQLiteNode, SQLiteNode as SQLiteStorage } from "./sqliteNode.js";
import Database, { type Database as DatabaseT } from "better-sqlite3";
import type { SQLiteDatabaseDriver } from "cojson";
import { getSqliteStorage } from "cojson";
export class BetterSqliteDriver implements SQLiteDatabaseDriver {
private readonly db: DatabaseT;
constructor(filename: string) {
const db = new Database(filename);
this.db = db;
db.pragma("journal_mode = WAL");
}
run(sql: string, params: unknown[]) {
this.db.prepare(sql).run(params);
}
query<T>(sql: string, params: unknown[]): T[] {
return this.db.prepare(sql).all(params) as T[];
}
get<T>(sql: string, params: unknown[]): T | undefined {
return this.db.prepare(sql).get(params) as T | undefined;
}
transaction(callback: () => unknown) {
return this.db.transaction(callback)();
}
closeDb() {
this.db.close();
}
}
export function getBetterSqliteStorage(filename: string) {
const db = new BetterSqliteDriver(filename);
return getSqliteStorage(db);
}

@@ -5,8 +5,6 @@ import { randomUUID } from "node:crypto";

import { join } from "node:path";
import { LocalNode, cojsonInternals } from "cojson";
import { SQLiteNodeBase, StorageManagerSync } from "cojson-storage";
import { LocalNode, StorageApiSync, cojsonInternals } from "cojson";
import { WasmCrypto } from "cojson/crypto/WasmCrypto";
import { expect, onTestFinished, test, vi } from "vitest";
import { BetterSqliteDriver } from "../betterSqliteDriver.js";
import { SQLiteNode } from "../index.js";
import { getBetterSqliteStorage } from "../index.js";
import { toSimplifiedMessages } from "./messagesTestUtils.js";

@@ -17,3 +15,3 @@ import { trackMessages, waitFor } from "./testUtils.js";

async function createSQLiteStorage(defaultDbPath?: string) {
function createSQLiteStorage(defaultDbPath?: string) {
const dbPath = defaultDbPath ?? join(tmpdir(), `test-${randomUUID()}.db`);

@@ -28,5 +26,3 @@

return {
peer: await SQLiteNode.asPeer({
filename: dbPath,
}),
storage: getBetterSqliteStorage(dbPath),
dbPath,

@@ -36,18 +32,2 @@ };

test("Should be able to initialize and load from empty DB", async () => {
const agentSecret = Crypto.newRandomAgentSecret();
const node = new LocalNode(
agentSecret,
Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)),
Crypto,
);
node.syncManager.addPeer((await createSQLiteStorage()).peer);
await new Promise((resolve) => setTimeout(resolve, 200));
expect(node.syncManager.peers.storage).toBeDefined();
});
test("should sync and load data from storage", async () => {

@@ -62,7 +42,7 @@ const agentSecret = Crypto.newRandomAgentSecret();

const node1Sync = trackMessages(node1);
const node1Sync = trackMessages();
const { peer, dbPath } = await createSQLiteStorage();
const { storage, dbPath } = createSQLiteStorage();
node1.syncManager.addPeer(peer);
node1.setStorage(storage);

@@ -88,5 +68,3 @@ const group = node1.createGroup();

"client -> CONTENT Group header: true new: After: 0 New: 3",
"storage -> KNOWN Group sessions: header/3",
"client -> CONTENT Map header: true new: After: 0 New: 1",
"storage -> KNOWN Map sessions: header/1",
]

@@ -103,8 +81,6 @@ `);

const node2Sync = trackMessages(node2);
const node2Sync = trackMessages();
const { peer: peer2 } = await createSQLiteStorage(dbPath);
node2.setStorage(createSQLiteStorage(dbPath).storage);
node2.syncManager.addPeer(peer2);
const map2 = await node2.load(map.id);

@@ -129,5 +105,3 @@ if (map2 === "unavailable") {

"storage -> CONTENT Group header: true new: After: 0 New: 3",
"client -> KNOWN Group sessions: header/3",
"storage -> CONTENT Map header: true new: After: 0 New: 1",
"client -> KNOWN Map sessions: header/1",
]

@@ -148,7 +122,7 @@ `);

const node1Sync = trackMessages(node1);
const node1Sync = trackMessages();
const { peer, dbPath } = await createSQLiteStorage();
const { storage, dbPath } = createSQLiteStorage();
node1.syncManager.addPeer(peer);
node1.setStorage(storage);

@@ -172,5 +146,3 @@ const group = node1.createGroup();

"client -> CONTENT Group header: true new: After: 0 New: 3",
"storage -> KNOWN Group sessions: header/3",
"client -> CONTENT Map header: true new: ",
"storage -> KNOWN Map sessions: header/0",
]

@@ -187,8 +159,6 @@ `);

const node2Sync = trackMessages(node2);
const node2Sync = trackMessages();
const { peer: peer2 } = await createSQLiteStorage(dbPath);
node2.setStorage(createSQLiteStorage(dbPath).storage);
node2.syncManager.addPeer(peer2);
const map2 = await node2.load(map.id);

@@ -211,5 +181,3 @@ if (map2 === "unavailable") {

"storage -> CONTENT Group header: true new: After: 0 New: 3",
"client -> KNOWN Group sessions: header/3",
"storage -> CONTENT Map header: true new: ",
"client -> KNOWN Map sessions: header/0",
]

@@ -230,7 +198,7 @@ `);

const node1Sync = trackMessages(node1);
const node1Sync = trackMessages();
const { peer, dbPath } = await createSQLiteStorage();
const { storage, dbPath } = createSQLiteStorage();
node1.syncManager.addPeer(peer);
node1.setStorage(storage);

@@ -259,8 +227,5 @@ const group = node1.createGroup();

[
"client -> CONTENT Group header: true new: After: 0 New: 5",
"client -> CONTENT ParentGroup header: true new: After: 0 New: 4",
"storage -> KNOWN ParentGroup sessions: header/4",
"client -> CONTENT Group header: true new: After: 0 New: 5",
"storage -> KNOWN Group sessions: header/5",
"client -> CONTENT Map header: true new: After: 0 New: 1",
"storage -> KNOWN Map sessions: header/1",
]

@@ -277,8 +242,6 @@ `);

const node2Sync = trackMessages(node2);
const node2Sync = trackMessages();
const { peer: peer2 } = await createSQLiteStorage(dbPath);
node2.setStorage(createSQLiteStorage(dbPath).storage);
node2.syncManager.addPeer(peer2);
await node2.load(map.id);

@@ -303,7 +266,4 @@

"storage -> CONTENT ParentGroup header: true new: After: 0 New: 4",
"client -> KNOWN ParentGroup sessions: header/4",
"storage -> CONTENT Group header: true new: After: 0 New: 5",
"client -> KNOWN Group sessions: header/5",
"storage -> CONTENT Map header: true new: After: 0 New: 1",
"client -> KNOWN Map sessions: header/1",
]

@@ -322,7 +282,7 @@ `);

const node1Sync = trackMessages(node1);
const node1Sync = trackMessages();
const { peer, dbPath } = await createSQLiteStorage();
const { storage, dbPath } = createSQLiteStorage();
node1.syncManager.addPeer(peer);
node1.setStorage(storage);

@@ -350,8 +310,6 @@ const group = node1.createGroup();

const node2Sync = trackMessages(node2);
const node2Sync = trackMessages();
const { peer: peer2 } = await createSQLiteStorage(dbPath);
node2.setStorage(createSQLiteStorage(dbPath).storage);
node2.syncManager.addPeer(peer2);
await node2.load(map.id);

@@ -379,10 +337,6 @@ await node2.load(mapFromParent.id);

"storage -> CONTENT ParentGroup header: true new: After: 0 New: 4",
"client -> KNOWN ParentGroup sessions: header/4",
"storage -> CONTENT Group header: true new: After: 0 New: 5",
"client -> KNOWN Group sessions: header/5",
"storage -> CONTENT Map header: true new: After: 0 New: 1",
"client -> KNOWN Map sessions: header/1",
"client -> LOAD MapFromParent sessions: empty",
"storage -> CONTENT MapFromParent header: true new: After: 0 New: 1",
"client -> KNOWN MapFromParent sessions: header/1",
]

@@ -401,7 +355,7 @@ `);

const node1Sync = trackMessages(node1);
const node1Sync = trackMessages();
const { peer, dbPath } = await createSQLiteStorage();
const { storage, dbPath } = createSQLiteStorage();
node1.syncManager.addPeer(peer);
node1.setStorage(storage);

@@ -417,4 +371,4 @@ const group = node1.createGroup();

const mock = vi
.spyOn(StorageManagerSync.prototype, "handleSyncMessage")
.mockImplementation(() => Promise.resolve());
.spyOn(StorageApiSync.prototype, "store")
.mockImplementation(() => false);

@@ -443,9 +397,4 @@ map.set("1", 1);

"client -> CONTENT Group header: true new: After: 0 New: 3",
"storage -> KNOWN Group sessions: header/3",
"client -> CONTENT Map header: true new: After: 0 New: 1",
"storage -> KNOWN Map sessions: header/1",
"client -> CONTENT Map header: false new: After: 3 New: 1",
"storage -> KNOWN CORRECTION Map sessions: header/1",
"client -> CONTENT Map header: false new: After: 1 New: 3",
"storage -> KNOWN Map sessions: header/4",
]

@@ -462,8 +411,6 @@ `);

const node2Sync = trackMessages(node2);
const node2Sync = trackMessages();
const { peer: peer2 } = await createSQLiteStorage(dbPath);
node2.setStorage(createSQLiteStorage(dbPath).storage);
node2.syncManager.addPeer(peer2);
const map2 = await node2.load(map.id);

@@ -494,5 +441,3 @@

"storage -> CONTENT Group header: true new: After: 0 New: 3",
"client -> KNOWN Group sessions: header/3",
"storage -> CONTENT Map header: true new: After: 0 New: 4",
"client -> KNOWN Map sessions: header/4",
]

@@ -528,20 +473,24 @@ `);

const handleSyncMessage = StorageManagerSync.prototype.handleSyncMessage;
const store = StorageApiSync.prototype.store;
const mock = vi
.spyOn(StorageManagerSync.prototype, "handleSyncMessage")
.mockImplementation(function (this: StorageManagerSync, msg) {
.spyOn(StorageApiSync.prototype, "store")
.mockImplementation(function (
this: StorageApiSync,
data,
correctionCallback,
) {
if (
msg.action === "content" &&
[group.core.id, account.core.id].includes(msg.id)
data[0]?.id &&
[group.core.id, account.core.id as string].includes(data[0].id)
) {
return Promise.resolve();
return false;
}
return handleSyncMessage.call(this, msg);
return store.call(this, data, correctionCallback);
});
const { peer, dbPath } = await createSQLiteStorage();
const { storage, dbPath } = createSQLiteStorage();
node1.syncManager.addPeer(peer);
node1.setStorage(storage);

@@ -577,6 +526,4 @@ const group = node1.createGroup();

const { peer: peer2 } = await createSQLiteStorage(dbPath);
node2.setStorage(createSQLiteStorage(dbPath).storage);
node2.syncManager.addPeer(peer2);
const map2 = await node2.load(map.id);

@@ -602,5 +549,5 @@

const { peer, dbPath } = await createSQLiteStorage();
const { storage, dbPath } = createSQLiteStorage();
node1.syncManager.addPeer(peer);
node1.setStorage(storage);

@@ -623,3 +570,3 @@ const group = node1.createGroup();

node2.syncManager.addPeer((await createSQLiteStorage(dbPath)).peer);
node2.setStorage(createSQLiteStorage(dbPath).storage);

@@ -645,5 +592,5 @@ const map2 = await node2.load(map.id);

const node3Sync = trackMessages(node3);
const node3Sync = trackMessages();
node3.syncManager.addPeer((await createSQLiteStorage(dbPath)).peer);
node3.setStorage(createSQLiteStorage(dbPath).storage);

@@ -669,5 +616,3 @@ const map3 = await node3.load(map.id);

"storage -> CONTENT Group header: true new: After: 0 New: 3",
"client -> KNOWN Group sessions: header/3",
"storage -> CONTENT Map header: true new: After: 0 New: 1 | After: 0 New: 1",
"client -> KNOWN Map sessions: header/2",
]

@@ -688,5 +633,5 @@ `);

const { peer, dbPath } = await createSQLiteStorage();
const { storage, dbPath } = createSQLiteStorage();
node1.syncManager.addPeer(peer);
node1.setStorage(storage);

@@ -717,8 +662,6 @@ const group = node1.createGroup();

const node2Sync = trackMessages(node2);
const node2Sync = trackMessages();
const { peer: peer2 } = await createSQLiteStorage(dbPath);
node2.setStorage(createSQLiteStorage(dbPath).storage);
node2.syncManager.addPeer(peer2);
const largeMapOnNode2 = await node2.load(largeMap.id);

@@ -749,49 +692,8 @@

"client -> LOAD Map sessions: empty",
"storage -> KNOWN Map sessions: header/200",
"storage -> CONTENT Group header: true new: After: 0 New: 3",
"client -> KNOWN Group sessions: header/3",
"storage -> CONTENT Map header: true new: After: 0 New: 97",
"client -> KNOWN Map sessions: header/97",
"storage -> CONTENT Map header: true new: After: 97 New: 97",
"client -> KNOWN Map sessions: header/194",
"storage -> CONTENT Map header: true new: After: 194 New: 6",
"client -> KNOWN Map sessions: header/200",
]
`);
});
test("should close the db when the node is closed", async () => {
const agentSecret = Crypto.newRandomAgentSecret();
const node1 = new LocalNode(
agentSecret,
Crypto.newRandomSessionID(Crypto.getAgentID(agentSecret)),
Crypto,
);
const dbPath = join(tmpdir(), `test-${randomUUID()}.db`);
const db = new BetterSqliteDriver(dbPath);
const peer = SQLiteNodeBase.create({
db,
localNodeName: "test",
maxBlockingTime: 500,
});
const spy = vi.spyOn(db, "closeDb");
node1.syncManager.addPeer(peer);
await new Promise((resolve) => setTimeout(resolve, 10));
expect(spy).not.toHaveBeenCalled();
node1.gracefulShutdown();
await new Promise((resolve) => setTimeout(resolve, 10));
expect(spy).toHaveBeenCalled();
unlinkSync(dbPath);
});

@@ -1,6 +0,6 @@

import type { LocalNode, SyncMessage } from "cojson";
import { StorageManagerSync } from "cojson-storage";
import type { LocalNode, RawCoID, SyncMessage } from "cojson";
import { StorageApiSync } from "cojson";
import { onTestFinished } from "vitest";
export function trackMessages(node: LocalNode) {
export function trackMessages() {
const messages: {

@@ -11,25 +11,53 @@ from: "client" | "server" | "storage";

const originalHandleSyncMessage =
StorageManagerSync.prototype.handleSyncMessage;
const originalNodeSyncMessage = node.syncManager.handleSyncMessage;
const originalLoad = StorageApiSync.prototype.load;
const originalStore = StorageApiSync.prototype.store;
StorageManagerSync.prototype.handleSyncMessage = async function (msg) {
StorageApiSync.prototype.load = async function (id, callback, done) {
messages.push({
from: "client",
msg,
msg: {
action: "load",
id: id as RawCoID,
header: false,
sessions: {},
},
});
return originalHandleSyncMessage.call(this, msg);
return originalLoad.call(
this,
id,
(msg) => {
messages.push({
from: "storage",
msg,
});
callback(msg);
},
done,
);
};
node.syncManager.handleSyncMessage = async function (msg, peer) {
messages.push({
from: "storage",
msg,
StorageApiSync.prototype.store = function (data, correctionCallback) {
for (const msg of data) {
messages.push({
from: "client",
msg,
});
}
return originalStore.call(this, data, (msg) => {
messages.push({
from: "storage",
msg: {
action: "known",
isCorrection: true,
...msg,
},
});
correctionCallback(msg);
});
return originalNodeSyncMessage.call(this, msg, peer);
};
const restore = () => {
StorageManagerSync.prototype.handleSyncMessage = originalHandleSyncMessage;
node.syncManager.handleSyncMessage = originalNodeSyncMessage;
StorageApiSync.prototype.load = originalLoad;
StorageApiSync.prototype.store = originalStore;
messages.length = 0;
};

@@ -36,0 +64,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet