@vex-chat/libvex 1.0.1 → 1.0.2
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/dist/Client.d.ts +12 -8
- package/dist/Client.js +131 -74
- package/dist/Client.js.map +1 -1
- package/dist/IStorage.d.ts +1 -1
- package/dist/IStorage.js +1 -1
- package/dist/IStorage.js.map +1 -1
- package/dist/__tests__/harness/memory-storage.d.ts +45 -0
- package/dist/__tests__/harness/memory-storage.js +181 -0
- package/dist/__tests__/harness/memory-storage.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/keystore/memory.d.ts +11 -0
- package/dist/keystore/memory.js +18 -0
- package/dist/keystore/memory.js.map +1 -0
- package/dist/keystore/node.d.ts +10 -0
- package/dist/keystore/node.js +64 -0
- package/dist/keystore/node.js.map +1 -0
- package/dist/keystore/types.d.ts +4 -0
- package/dist/keystore/types.js +2 -0
- package/dist/keystore/types.js.map +1 -0
- package/dist/preset/expo.d.ts +2 -0
- package/dist/preset/expo.js +37 -0
- package/dist/preset/expo.js.map +1 -0
- package/dist/preset/node.d.ts +12 -0
- package/dist/preset/node.js +16 -0
- package/dist/preset/node.js.map +1 -0
- package/dist/preset/tauri.d.ts +2 -0
- package/dist/preset/tauri.js +35 -0
- package/dist/preset/tauri.js.map +1 -0
- package/dist/preset/test.d.ts +10 -0
- package/dist/preset/test.js +28 -0
- package/dist/preset/test.js.map +1 -0
- package/dist/preset/types.d.ts +13 -0
- package/dist/preset/types.js +2 -0
- package/dist/preset/types.js.map +1 -0
- package/dist/storage/expo.d.ts +3 -0
- package/dist/storage/expo.js +18 -0
- package/dist/storage/expo.js.map +1 -0
- package/dist/storage/node.d.ts +3 -0
- package/dist/storage/node.js +24 -0
- package/dist/storage/node.js.map +1 -0
- package/dist/storage/schema.d.ts +79 -0
- package/dist/storage/schema.js +2 -0
- package/dist/storage/schema.js.map +1 -0
- package/dist/{Storage.d.ts → storage/sqlite.d.ts} +19 -21
- package/dist/storage/sqlite.js +487 -0
- package/dist/storage/sqlite.js.map +1 -0
- package/dist/storage/tauri.d.ts +3 -0
- package/dist/storage/tauri.js +21 -0
- package/dist/storage/tauri.js.map +1 -0
- package/dist/transport/browser.d.ts +17 -0
- package/dist/transport/browser.js +56 -0
- package/dist/transport/browser.js.map +1 -0
- package/dist/transport/types.d.ts +20 -0
- package/dist/transport/types.js +2 -0
- package/dist/transport/types.js.map +1 -0
- package/package.json +102 -14
- package/dist/Storage.js +0 -444
- package/dist/Storage.js.map +0 -1
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File-backed KeyStore for Node.js (CLI tools, bots, integration tests).
|
|
3
|
+
*
|
|
4
|
+
* Stores credentials as encrypted files on disk using XUtils.encryptKeyData.
|
|
5
|
+
* Node-only — imports node:fs.
|
|
6
|
+
*/
|
|
7
|
+
import { XUtils } from "@vex-chat/crypto";
|
|
8
|
+
import * as fs from "node:fs";
|
|
9
|
+
import * as path from "node:path";
|
|
10
|
+
export class NodeKeyStore {
|
|
11
|
+
dir;
|
|
12
|
+
constructor(dir = ".") {
|
|
13
|
+
this.dir = dir;
|
|
14
|
+
}
|
|
15
|
+
filePath(username) {
|
|
16
|
+
return path.join(this.dir, `${username}.vex`);
|
|
17
|
+
}
|
|
18
|
+
async load(username) {
|
|
19
|
+
if (username) {
|
|
20
|
+
return this.readFile(this.filePath(username));
|
|
21
|
+
}
|
|
22
|
+
// Find most recent .vex file in the directory
|
|
23
|
+
try {
|
|
24
|
+
const files = fs
|
|
25
|
+
.readdirSync(this.dir)
|
|
26
|
+
.filter((f) => f.endsWith(".vex"))
|
|
27
|
+
.map((f) => ({
|
|
28
|
+
name: f,
|
|
29
|
+
mtime: fs.statSync(path.join(this.dir, f)).mtimeMs,
|
|
30
|
+
}))
|
|
31
|
+
.sort((a, b) => b.mtime - a.mtime);
|
|
32
|
+
if (files.length === 0)
|
|
33
|
+
return null;
|
|
34
|
+
return this.readFile(path.join(this.dir, files[0].name));
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async save(creds) {
|
|
41
|
+
const data = JSON.stringify(creds);
|
|
42
|
+
const encrypted = XUtils.encryptKeyData("", data);
|
|
43
|
+
fs.writeFileSync(this.filePath(creds.username), encrypted);
|
|
44
|
+
}
|
|
45
|
+
async clear(username) {
|
|
46
|
+
try {
|
|
47
|
+
fs.unlinkSync(this.filePath(username));
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
// File may not exist
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
readFile(filePath) {
|
|
54
|
+
try {
|
|
55
|
+
const data = fs.readFileSync(filePath);
|
|
56
|
+
const decrypted = XUtils.decryptKeyData(new Uint8Array(data), "");
|
|
57
|
+
return JSON.parse(decrypted);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node.js","sourceRoot":"","sources":["../../src/keystore/node.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAGlC,MAAM,OAAO,YAAY;IACb,GAAG,CAAS;IAEpB,YAAY,MAAc,GAAG;QACzB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACnB,CAAC;IAEO,QAAQ,CAAC,QAAgB;QAC7B,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,MAAM,CAAC,CAAC;IAClD,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,QAAiB;QACxB,IAAI,QAAQ,EAAE,CAAC;YACX,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;QAClD,CAAC;QACD,8CAA8C;QAC9C,IAAI,CAAC;YACD,MAAM,KAAK,GAAG,EAAE;iBACX,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC;iBACrB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;iBACjC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACT,IAAI,EAAE,CAAC;gBACP,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO;aACrD,CAAC,CAAC;iBACF,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;YACvC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,IAAI,CAAC;YACpC,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAE,CAAC,IAAI,CAAC,CAAC,CAAC;QAC9D,CAAC;QAAC,MAAM,CAAC;YACL,OAAO,IAAI,CAAC;QAChB,CAAC;IACL,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,KAAwB;QAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACnC,MAAM,SAAS,GAAG,MAAM,CAAC,cAAc,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QAClD,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC,CAAC;IAC/D,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,QAAgB;QACxB,IAAI,CAAC;YACD,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC3C,CAAC;QAAC,MAAM,CAAC;YACL,qBAAqB;QACzB,CAAC;IACL,CAAC;IAEO,QAAQ,CAAC,QAAgB;QAC7B,IAAI,CAAC;YACD,MAAM,IAAI,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;YACvC,MAAM,SAAS,GAAG,MAAM,CAAC,cAAc,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;YAClE,OAAO,IAAI,CAAC,KAAK,CAAC,SAAS,CAAsB,CAAC;QACtD,CAAC;QAAC,MAAM,CAAC;YACL,OAAO,IAAI,CAAC;QAChB,CAAC;IACL,CAAC;CACJ"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/keystore/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Platform preset for Expo / React Native apps.
|
|
3
|
+
*
|
|
4
|
+
* - WebSocket: browser-native (React Native's global WebSocket)
|
|
5
|
+
* - Storage: Kysely + kysely-expo + expo-sqlite
|
|
6
|
+
* - Logger: console
|
|
7
|
+
*
|
|
8
|
+
* expo-sqlite and kysely-expo are optional peerDependencies.
|
|
9
|
+
*/
|
|
10
|
+
import { BrowserWebSocket } from "../transport/browser.js";
|
|
11
|
+
const logger = {
|
|
12
|
+
info(m) {
|
|
13
|
+
console.log(`[vex] ${m}`);
|
|
14
|
+
},
|
|
15
|
+
warn(m) {
|
|
16
|
+
console.warn(`[vex] ${m}`);
|
|
17
|
+
},
|
|
18
|
+
error(m) {
|
|
19
|
+
console.error(`[vex] ${m}`);
|
|
20
|
+
},
|
|
21
|
+
debug(m) {
|
|
22
|
+
console.debug(`[vex] ${m}`);
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
export function expoPreset() {
|
|
26
|
+
return {
|
|
27
|
+
adapters: {
|
|
28
|
+
logger,
|
|
29
|
+
WebSocket: BrowserWebSocket,
|
|
30
|
+
},
|
|
31
|
+
async createStorage(dbName, privateKey, _logger) {
|
|
32
|
+
const { createExpoStorage } = await import("../storage/expo.js");
|
|
33
|
+
return createExpoStorage(dbName, privateKey, _logger ?? logger);
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=expo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"expo.js","sourceRoot":"","sources":["../../src/preset/expo.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAI3D,MAAM,MAAM,GAAY;IACpB,IAAI,CAAC,CAAS;QACV,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC;IACD,IAAI,CAAC,CAAS;QACV,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IAC/B,CAAC;IACD,KAAK,CAAC,CAAS;QACX,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IAChC,CAAC;IACD,KAAK,CAAC,CAAS;QACX,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IAChC,CAAC;CACJ,CAAC;AAEF,MAAM,UAAU,UAAU;IACtB,OAAO;QACH,QAAQ,EAAE;YACN,MAAM;YACN,SAAS,EAAE,gBAAuB;SACrC;QACD,KAAK,CAAC,aAAa,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO;YAC3C,MAAM,EAAE,iBAAiB,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;YACjE,OAAO,iBAAiB,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,IAAI,MAAM,CAAC,CAAC;QACpE,CAAC;KACJ,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Platform preset for Node.js (CLI tools, bots, tests).
|
|
3
|
+
*
|
|
4
|
+
* - WebSocket: ws (loaded dynamically)
|
|
5
|
+
* - Storage: Kysely + better-sqlite3
|
|
6
|
+
* - Logger: winston (loaded dynamically)
|
|
7
|
+
*
|
|
8
|
+
* Async because ws and winston are lazy-loaded to keep them out of
|
|
9
|
+
* browser bundles that import from the main entrypoint.
|
|
10
|
+
*/
|
|
11
|
+
import type { PlatformPreset } from "./types.js";
|
|
12
|
+
export declare function nodePreset(logLevel?: string): Promise<PlatformPreset>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export async function nodePreset(logLevel) {
|
|
2
|
+
const { default: WebSocket } = await import("ws");
|
|
3
|
+
const { createLogger } = await import("../utils/createLogger.js");
|
|
4
|
+
const logger = createLogger("libvex", logLevel);
|
|
5
|
+
return {
|
|
6
|
+
adapters: {
|
|
7
|
+
logger,
|
|
8
|
+
WebSocket: WebSocket,
|
|
9
|
+
},
|
|
10
|
+
async createStorage(dbName, privateKey, _logger) {
|
|
11
|
+
const { createNodeStorage } = await import("../storage/node.js");
|
|
12
|
+
return createNodeStorage(dbName, privateKey, _logger ?? logger);
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node.js","sourceRoot":"","sources":["../../src/preset/node.ts"],"names":[],"mappings":"AAaA,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,QAAiB;IAC9C,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;IAClD,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,0BAA0B,CAAC,CAAC;IAClE,MAAM,MAAM,GAAY,YAAY,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAEzD,OAAO;QACH,QAAQ,EAAE;YACN,MAAM;YACN,SAAS,EAAE,SAAgB;SAC9B;QACD,KAAK,CAAC,aAAa,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO;YAC3C,MAAM,EAAE,iBAAiB,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;YACjE,OAAO,iBAAiB,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,IAAI,MAAM,CAAC,CAAC;QACpE,CAAC;KACJ,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Platform preset for Tauri (desktop) apps.
|
|
3
|
+
*
|
|
4
|
+
* - WebSocket: browser-native (Tauri webview)
|
|
5
|
+
* - Storage: Kysely + kysely-dialect-tauri + @tauri-apps/plugin-sql
|
|
6
|
+
* - Logger: console
|
|
7
|
+
*/
|
|
8
|
+
import { BrowserWebSocket } from "../transport/browser.js";
|
|
9
|
+
const logger = {
|
|
10
|
+
info(m) {
|
|
11
|
+
console.log(`[vex] ${m}`);
|
|
12
|
+
},
|
|
13
|
+
warn(m) {
|
|
14
|
+
console.warn(`[vex] ${m}`);
|
|
15
|
+
},
|
|
16
|
+
error(m) {
|
|
17
|
+
console.error(`[vex] ${m}`);
|
|
18
|
+
},
|
|
19
|
+
debug(m) {
|
|
20
|
+
console.debug(`[vex] ${m}`);
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
export function tauriPreset() {
|
|
24
|
+
return {
|
|
25
|
+
adapters: {
|
|
26
|
+
logger,
|
|
27
|
+
WebSocket: BrowserWebSocket,
|
|
28
|
+
},
|
|
29
|
+
async createStorage(dbName, privateKey, _logger) {
|
|
30
|
+
const { createTauriStorage } = await import("../storage/tauri.js");
|
|
31
|
+
return createTauriStorage(dbName, privateKey, _logger ?? logger);
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=tauri.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tauri.js","sourceRoot":"","sources":["../../src/preset/tauri.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAI3D,MAAM,MAAM,GAAY;IACpB,IAAI,CAAC,CAAS;QACV,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC;IACD,IAAI,CAAC,CAAS;QACV,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IAC/B,CAAC;IACD,KAAK,CAAC,CAAS;QACX,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IAChC,CAAC;IACD,KAAK,CAAC,CAAS;QACX,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IAChC,CAAC;CACJ,CAAC;AAEF,MAAM,UAAU,WAAW;IACvB,OAAO;QACH,QAAQ,EAAE;YACN,MAAM;YACN,SAAS,EAAE,gBAAuB;SACrC;QACD,KAAK,CAAC,aAAa,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO;YAC3C,MAAM,EAAE,kBAAkB,EAAE,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAC;YACnE,OAAO,kBAAkB,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,IAAI,MAAM,CAAC,CAAC;QACrE,CAAC;KACJ,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Platform preset for tests — no I/O, no platform dependencies.
|
|
3
|
+
*
|
|
4
|
+
* - WebSocket: must be injected by the test (platform-specific)
|
|
5
|
+
* - Storage: in-memory (no persistence)
|
|
6
|
+
* - Logger: console
|
|
7
|
+
*/
|
|
8
|
+
import type { PlatformPreset } from "./types.js";
|
|
9
|
+
import type { IWebSocketCtor } from "../transport/types.js";
|
|
10
|
+
export declare function testPreset(WebSocket: IWebSocketCtor): PlatformPreset;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const logger = {
|
|
2
|
+
info(m) {
|
|
3
|
+
console.log(`[test] ${m}`);
|
|
4
|
+
},
|
|
5
|
+
warn(m) {
|
|
6
|
+
console.warn(`[test] ${m}`);
|
|
7
|
+
},
|
|
8
|
+
error(m) {
|
|
9
|
+
console.error(`[test] ${m}`);
|
|
10
|
+
},
|
|
11
|
+
debug() { },
|
|
12
|
+
};
|
|
13
|
+
export function testPreset(WebSocket) {
|
|
14
|
+
return {
|
|
15
|
+
adapters: {
|
|
16
|
+
logger,
|
|
17
|
+
WebSocket,
|
|
18
|
+
},
|
|
19
|
+
async createStorage(dbName, privateKey, _logger) {
|
|
20
|
+
// Lazy import to avoid pulling eventemitter3 into the type graph
|
|
21
|
+
const { MemoryStorage } = await import("../__tests__/harness/memory-storage.js");
|
|
22
|
+
const storage = new MemoryStorage(privateKey);
|
|
23
|
+
await storage.init();
|
|
24
|
+
return storage;
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test.js","sourceRoot":"","sources":["../../src/preset/test.ts"],"names":[],"mappings":"AAWA,MAAM,MAAM,GAAY;IACpB,IAAI,CAAC,CAAS;QACV,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IAC/B,CAAC;IACD,IAAI,CAAC,CAAS;QACV,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IAChC,CAAC;IACD,KAAK,CAAC,CAAS;QACX,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IACjC,CAAC;IACD,KAAK,KAAI,CAAC;CACb,CAAC;AAEF,MAAM,UAAU,UAAU,CAAC,SAAyB;IAChD,OAAO;QACH,QAAQ,EAAE;YACN,MAAM;YACN,SAAS;SACZ;QACD,KAAK,CAAC,aAAa,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO;YAC3C,iEAAiE;YACjE,MAAM,EAAE,aAAa,EAAE,GACnB,MAAM,MAAM,CAAC,wCAAwC,CAAC,CAAC;YAC3D,MAAM,OAAO,GAAG,IAAI,aAAa,CAAC,UAAU,CAAC,CAAC;YAC9C,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC;YACrB,OAAO,OAAO,CAAC;QACnB,CAAC;KACJ,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { IClientAdapters, ILogger } from "../transport/types.js";
|
|
2
|
+
import type { IStorage } from "../IStorage.js";
|
|
3
|
+
/**
|
|
4
|
+
* Bundles platform-specific adapters + storage factory.
|
|
5
|
+
*
|
|
6
|
+
* Each platform (Tauri, Expo, Node CLI) provides a preset factory
|
|
7
|
+
* that returns one of these. The store's bootstrap functions accept it
|
|
8
|
+
* so app code stays a one-liner.
|
|
9
|
+
*/
|
|
10
|
+
export interface PlatformPreset {
|
|
11
|
+
adapters: IClientAdapters;
|
|
12
|
+
createStorage(dbName: string, privateKey: string, logger: ILogger): Promise<IStorage>;
|
|
13
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/preset/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Expo (React Native) storage factory — creates SqliteStorage with kysely-expo.
|
|
3
|
+
*
|
|
4
|
+
* expo-sqlite and kysely-expo are peerDependencies —
|
|
5
|
+
* only available in Expo apps.
|
|
6
|
+
*/
|
|
7
|
+
import { Kysely } from "kysely";
|
|
8
|
+
import { SqliteStorage } from "./sqlite.js";
|
|
9
|
+
export async function createExpoStorage(dbName, SK, logger) {
|
|
10
|
+
const { ExpoDialect } = await import("kysely-expo");
|
|
11
|
+
const db = new Kysely({
|
|
12
|
+
dialect: new ExpoDialect({ database: dbName }),
|
|
13
|
+
});
|
|
14
|
+
const storage = new SqliteStorage(db, SK, logger);
|
|
15
|
+
await storage.init();
|
|
16
|
+
return storage;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=expo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"expo.js","sourceRoot":"","sources":["../../src/storage/expo.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAI5C,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACnC,MAAc,EACd,EAAU,EACV,MAAe;IAEf,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;IACpD,MAAM,EAAE,GAAG,IAAI,MAAM,CAAiB;QAClC,OAAO,EAAE,IAAI,WAAW,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAQ;KACxD,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,IAAI,aAAa,CAAC,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;IAClD,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC;IACrB,OAAO,OAAO,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node.js storage factory — creates SqliteStorage with better-sqlite3 dialect.
|
|
3
|
+
* Node-only — imports better-sqlite3 which is a native addon.
|
|
4
|
+
*/
|
|
5
|
+
import { Kysely, SqliteDialect } from "kysely";
|
|
6
|
+
import BetterSqlite3 from "better-sqlite3";
|
|
7
|
+
import { SqliteStorage } from "./sqlite.js";
|
|
8
|
+
export function createNodeStorage(dbPath, SK, logger) {
|
|
9
|
+
const db = new Kysely({
|
|
10
|
+
dialect: new SqliteDialect({
|
|
11
|
+
database: new BetterSqlite3(dbPath),
|
|
12
|
+
}),
|
|
13
|
+
});
|
|
14
|
+
const log = logger ?? {
|
|
15
|
+
info() { },
|
|
16
|
+
warn() { },
|
|
17
|
+
error() { },
|
|
18
|
+
debug() { },
|
|
19
|
+
};
|
|
20
|
+
const storage = new SqliteStorage(db, SK, log);
|
|
21
|
+
storage.init();
|
|
22
|
+
return storage;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node.js","sourceRoot":"","sources":["../../src/storage/node.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAC/C,OAAO,aAAa,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAI5C,MAAM,UAAU,iBAAiB,CAC7B,MAAc,EACd,EAAU,EACV,MAAgB;IAEhB,MAAM,EAAE,GAAG,IAAI,MAAM,CAAiB;QAClC,OAAO,EAAE,IAAI,aAAa,CAAC;YACvB,QAAQ,EAAE,IAAI,aAAa,CAAC,MAAM,CAAC;SACtC,CAAC;KACL,CAAC,CAAC;IACH,MAAM,GAAG,GAAY,MAAM,IAAI;QAC3B,IAAI,KAAI,CAAC;QACT,IAAI,KAAI,CAAC;QACT,KAAK,KAAI,CAAC;QACV,KAAK,KAAI,CAAC;KACb,CAAC;IACF,MAAM,OAAO,GAAG,IAAI,aAAa,CAAC,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC;IAC/C,OAAO,CAAC,IAAI,EAAE,CAAC;IACf,OAAO,OAAO,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kysely typed table interfaces for the client-side SQLite database.
|
|
3
|
+
*
|
|
4
|
+
* These mirror the schema previously created by knex / raw SQL in the
|
|
5
|
+
* three platform-specific storage implementations (Node, Tauri, Expo).
|
|
6
|
+
*/
|
|
7
|
+
import type { Generated, Insertable, Selectable, Updateable } from "kysely";
|
|
8
|
+
interface MessagesTable {
|
|
9
|
+
nonce: string;
|
|
10
|
+
sender: string;
|
|
11
|
+
recipient: string;
|
|
12
|
+
group: string | null;
|
|
13
|
+
mailID: string;
|
|
14
|
+
message: string;
|
|
15
|
+
direction: string;
|
|
16
|
+
timestamp: string;
|
|
17
|
+
decrypted: number;
|
|
18
|
+
forward: number;
|
|
19
|
+
authorID: string;
|
|
20
|
+
readerID: string;
|
|
21
|
+
}
|
|
22
|
+
interface DevicesTable {
|
|
23
|
+
deviceID: string;
|
|
24
|
+
owner: string;
|
|
25
|
+
signKey: string;
|
|
26
|
+
name: string;
|
|
27
|
+
lastLogin: string;
|
|
28
|
+
deleted: number;
|
|
29
|
+
}
|
|
30
|
+
interface SessionsTable {
|
|
31
|
+
sessionID: string;
|
|
32
|
+
userID: string;
|
|
33
|
+
deviceID: string;
|
|
34
|
+
SK: string;
|
|
35
|
+
publicKey: string;
|
|
36
|
+
fingerprint: string;
|
|
37
|
+
mode: string;
|
|
38
|
+
lastUsed: string;
|
|
39
|
+
verified: number;
|
|
40
|
+
}
|
|
41
|
+
interface PreKeysTable {
|
|
42
|
+
index: Generated<number>;
|
|
43
|
+
keyID: string;
|
|
44
|
+
userID: string;
|
|
45
|
+
deviceID: string;
|
|
46
|
+
privateKey: string;
|
|
47
|
+
publicKey: string;
|
|
48
|
+
signature: string;
|
|
49
|
+
}
|
|
50
|
+
interface OneTimeKeysTable {
|
|
51
|
+
index: Generated<number>;
|
|
52
|
+
keyID: string;
|
|
53
|
+
userID: string;
|
|
54
|
+
deviceID: string;
|
|
55
|
+
privateKey: string;
|
|
56
|
+
publicKey: string;
|
|
57
|
+
signature: string;
|
|
58
|
+
}
|
|
59
|
+
export interface ClientDatabase {
|
|
60
|
+
messages: MessagesTable;
|
|
61
|
+
devices: DevicesTable;
|
|
62
|
+
sessions: SessionsTable;
|
|
63
|
+
preKeys: PreKeysTable;
|
|
64
|
+
oneTimeKeys: OneTimeKeysTable;
|
|
65
|
+
}
|
|
66
|
+
export type MessageRow = Selectable<MessagesTable>;
|
|
67
|
+
export type NewMessage = Insertable<MessagesTable>;
|
|
68
|
+
export type MessageUpdate = Updateable<MessagesTable>;
|
|
69
|
+
export type DeviceRow = Selectable<DevicesTable>;
|
|
70
|
+
export type NewDevice = Insertable<DevicesTable>;
|
|
71
|
+
export type DeviceUpdate = Updateable<DevicesTable>;
|
|
72
|
+
export type SessionRow = Selectable<SessionsTable>;
|
|
73
|
+
export type NewSession = Insertable<SessionsTable>;
|
|
74
|
+
export type SessionUpdate = Updateable<SessionsTable>;
|
|
75
|
+
export type PreKeyRow = Selectable<PreKeysTable>;
|
|
76
|
+
export type NewPreKey = Insertable<PreKeysTable>;
|
|
77
|
+
export type OneTimeKeyRow = Selectable<OneTimeKeysTable>;
|
|
78
|
+
export type NewOneTimeKey = Insertable<OneTimeKeysTable>;
|
|
79
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/storage/schema.ts"],"names":[],"mappings":""}
|
|
@@ -1,41 +1,39 @@
|
|
|
1
1
|
import type { IDevice, IPreKeysCrypto, IPreKeysSQL, ISessionCrypto, ISessionSQL } from "@vex-chat/types";
|
|
2
|
-
import { EventEmitter } from "
|
|
3
|
-
import type {
|
|
4
|
-
import type {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
*/
|
|
10
|
-
export declare class Storage extends EventEmitter implements IStorage {
|
|
2
|
+
import { EventEmitter } from "eventemitter3";
|
|
3
|
+
import type { Kysely } from "kysely";
|
|
4
|
+
import type { IMessage } from "../index.js";
|
|
5
|
+
import type { IStorage } from "../IStorage.js";
|
|
6
|
+
import type { ILogger } from "../transport/types.js";
|
|
7
|
+
import type { ClientDatabase } from "./schema.js";
|
|
8
|
+
export declare class SqliteStorage extends EventEmitter implements IStorage {
|
|
11
9
|
ready: boolean;
|
|
12
10
|
private closing;
|
|
13
|
-
private dbPath;
|
|
14
11
|
private db;
|
|
15
12
|
private log;
|
|
16
13
|
private idKeys;
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
constructor(db: Kysely<ClientDatabase>, SK: string, logger: ILogger);
|
|
15
|
+
init(): Promise<void>;
|
|
19
16
|
close(): Promise<void>;
|
|
20
17
|
saveMessage(message: IMessage): Promise<void>;
|
|
21
18
|
deleteMessage(mailID: string): Promise<void>;
|
|
22
|
-
markSessionVerified(sessionID: string, status?: boolean): Promise<void>;
|
|
23
19
|
getMessageHistory(userID: string): Promise<IMessage[]>;
|
|
24
20
|
getGroupHistory(channelID: string): Promise<IMessage[]>;
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
deleteHistory(channelOrUserID: string, _olderThan?: string): Promise<void>;
|
|
22
|
+
purgeHistory(): Promise<void>;
|
|
23
|
+
markSessionVerified(sessionID: string): Promise<void>;
|
|
27
24
|
markSessionUsed(sessionID: string): Promise<void>;
|
|
25
|
+
getSessionByPublicKey(publicKey: Uint8Array): Promise<ISessionCrypto | null>;
|
|
28
26
|
getAllSessions(): Promise<ISessionSQL[]>;
|
|
29
27
|
getSessionByDeviceID(deviceID: string): Promise<ISessionCrypto | null>;
|
|
28
|
+
saveSession(session: ISessionSQL): Promise<void>;
|
|
29
|
+
savePreKeys(preKeys: IPreKeysCrypto[], oneTime: boolean): Promise<IPreKeysSQL[]>;
|
|
30
30
|
getPreKeys(): Promise<IPreKeysCrypto | null>;
|
|
31
31
|
getOneTimeKey(index: number): Promise<IPreKeysCrypto | null>;
|
|
32
32
|
deleteOneTimeKey(index: number): Promise<void>;
|
|
33
|
-
|
|
34
|
-
getDevice(deviceID: string): Promise<any>;
|
|
35
|
-
purgeHistory(): Promise<void>;
|
|
36
|
-
purgeKeyData(): Promise<void>;
|
|
37
|
-
deleteHistory(channelOrUserID: string, olderThan?: string): Promise<void>;
|
|
33
|
+
getDevice(deviceID: string): Promise<IDevice | null>;
|
|
38
34
|
saveDevice(device: IDevice): Promise<void>;
|
|
39
|
-
|
|
35
|
+
purgeKeyData(): Promise<void>;
|
|
36
|
+
private decryptMessages;
|
|
37
|
+
private sqlToCrypto;
|
|
40
38
|
private untilReady;
|
|
41
39
|
}
|