zaileys 0.29.7-beta → 0.29.9-beta
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 +0 -342
- package/bun.lock +1027 -0
- package/dist/classes/Client.d.ts +17 -0
- package/dist/classes/Event.d.ts +12 -0
- package/dist/classes/Parser.d.ts +3 -0
- package/dist/database/handler.d.ts +12 -0
- package/dist/database/schema.d.ts +63 -0
- package/dist/helpers/adapter.d.ts +57 -0
- package/dist/helpers/error.d.ts +8 -0
- package/dist/index.d.ts +2 -235
- package/dist/types/adapter/general.d.ts +156 -0
- package/dist/types/classes/client.d.ts +152 -0
- package/dist/types/classes/event.d.ts +65 -0
- package/dist/zaileys.cjs.js +1 -0
- package/dist/zaileys.esm.js +1 -0
- package/package.json +42 -29
- package/rollup.config.js +38 -0
- package/src/classes/Client.ts +73 -0
- package/src/classes/Event.ts +59 -0
- package/src/classes/Parser.ts +3 -0
- package/src/database/handler.ts +272 -0
- package/src/database/schema.ts +37 -0
- package/src/helpers/adapter.ts +125 -0
- package/src/helpers/error.ts +13 -0
- package/src/index.ts +2 -0
- package/src/types/adapter/general.ts +178 -0
- package/src/types/classes/client.ts +53 -0
- package/src/types/classes/event.ts +29 -0
- package/src/types/libsignal.d.ts +4 -0
- package/test/example.ts +37 -0
- package/tsconfig.json +16 -0
- package/LICENSE +0 -21
- package/dist/index.d.mts +0 -235
- package/dist/index.js +0 -1
- package/dist/index.mjs +0 -1
package/package.json
CHANGED
|
@@ -1,7 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zaileys",
|
|
3
|
-
"version": "0.29.
|
|
3
|
+
"version": "0.29.9-beta",
|
|
4
4
|
"description": "Zaileys - Simplify Typescript/Javascript WhatsApp NodeJS API",
|
|
5
|
+
"main": "dist/zaileys.cjs.js",
|
|
6
|
+
"module": "dist/zaileys.esm.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/zaileys.esm.js",
|
|
11
|
+
"require": "./dist/zaileys.cjs.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "rollup --bundleConfigAsCjs -c",
|
|
16
|
+
"watch": "rollup --bundleConfigAsCjs -c -w",
|
|
17
|
+
"dev": "concurrently \"npm:dev:test\"",
|
|
18
|
+
"dev:test": "npx tsx watch test/example.ts",
|
|
19
|
+
"clean": "rimraf dist"
|
|
20
|
+
},
|
|
5
21
|
"keywords": [
|
|
6
22
|
"zaileys",
|
|
7
23
|
"whatsapp",
|
|
@@ -29,39 +45,36 @@
|
|
|
29
45
|
"email": "zaadevofc@gmail.com",
|
|
30
46
|
"url": "https://github.com/zeative"
|
|
31
47
|
},
|
|
32
|
-
"license": "MIT",
|
|
33
|
-
"main": "dist/index.js",
|
|
34
|
-
"module": "dist/index.mjs",
|
|
35
|
-
"types": "dist/index.d.ts",
|
|
36
48
|
"engines": {
|
|
37
49
|
"node": ">=18"
|
|
38
50
|
},
|
|
39
|
-
"
|
|
40
|
-
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
51
|
+
"license": "MIT",
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@rollup/plugin-commonjs": "^24.0.0",
|
|
54
|
+
"@rollup/plugin-json": "^6.1.0",
|
|
55
|
+
"@rollup/plugin-node-resolve": "^15.0.0",
|
|
56
|
+
"@rollup/plugin-typescript": "^12.0.0",
|
|
57
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
58
|
+
"@types/pg": "^8.15.1",
|
|
59
|
+
"concurrently": "^8.0.0",
|
|
60
|
+
"rimraf": "^5.0.0",
|
|
61
|
+
"rollup": "^3.0.0",
|
|
62
|
+
"rollup-plugin-dts": "^5.0.0",
|
|
63
|
+
"rollup-plugin-esbuild": "^6.2.1",
|
|
64
|
+
"rollup-plugin-strip": "^1.2.2",
|
|
65
|
+
"rollup-plugin-terser": "^7.0.0",
|
|
66
|
+
"tsx": "^4.19.4",
|
|
67
|
+
"typescript": "^5.0.0",
|
|
68
|
+
"zod": "^3.24.4"
|
|
45
69
|
},
|
|
46
70
|
"dependencies": {
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"jimp": "0.22.12",
|
|
71
|
+
"baileys": "^6.7.16",
|
|
72
|
+
"better-sqlite3": "^11.10.0",
|
|
73
|
+
"kysely": "^0.28.2",
|
|
74
|
+
"libsignal": "^2.0.1",
|
|
75
|
+
"mysql2": "^3.14.1",
|
|
53
76
|
"node-cache": "^5.1.2",
|
|
54
|
-
"
|
|
55
|
-
"pino": "^9.6.0"
|
|
56
|
-
"qrcode-terminal": "^0.12.0"
|
|
57
|
-
},
|
|
58
|
-
"devDependencies": {
|
|
59
|
-
"@types/node": "^16.0.0",
|
|
60
|
-
"ts-node": "^10.8.1",
|
|
61
|
-
"ts-node-dev": "^2.0.0",
|
|
62
|
-
"tsup": "^8.3.6",
|
|
63
|
-
"typedoc": "^0.24.7",
|
|
64
|
-
"typedoc-material-theme": "^1.3.0",
|
|
65
|
-
"typescript": "^4.6.4"
|
|
77
|
+
"pg": "^8.15.6",
|
|
78
|
+
"pino": "^9.6.0"
|
|
66
79
|
}
|
|
67
80
|
}
|
package/rollup.config.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import commonjs from '@rollup/plugin-commonjs';
|
|
2
|
+
import { nodeResolve } from '@rollup/plugin-node-resolve';
|
|
3
|
+
import typescript from '@rollup/plugin-typescript';
|
|
4
|
+
import { dts } from 'rollup-plugin-dts';
|
|
5
|
+
import { minify } from 'rollup-plugin-esbuild';
|
|
6
|
+
import strip from 'rollup-plugin-strip';
|
|
7
|
+
import { terser } from 'rollup-plugin-terser';
|
|
8
|
+
|
|
9
|
+
/** @type {import('rollup').RollupOptions[]} */
|
|
10
|
+
export default [
|
|
11
|
+
{
|
|
12
|
+
input: 'src/index.ts',
|
|
13
|
+
external: Object.keys(require('./package.json').dependencies || {}),
|
|
14
|
+
treeshake: {
|
|
15
|
+
moduleSideEffects: false,
|
|
16
|
+
propertyReadSideEffects: false
|
|
17
|
+
},
|
|
18
|
+
output: [
|
|
19
|
+
{ file: 'dist/zaileys.cjs.js', format: 'cjs', sourcemap: false },
|
|
20
|
+
{ file: 'dist/zaileys.esm.js', format: 'esm', sourcemap: false }
|
|
21
|
+
],
|
|
22
|
+
plugins: [
|
|
23
|
+
nodeResolve({
|
|
24
|
+
extensions: ['.js', '.ts']
|
|
25
|
+
}), ,
|
|
26
|
+
commonjs(),
|
|
27
|
+
minify(),
|
|
28
|
+
typescript(),
|
|
29
|
+
strip({ functions: ['assert.*'] }),
|
|
30
|
+
terser({ format: { comments: false } })
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
input: 'src/index.ts',
|
|
35
|
+
output: { file: 'dist/index.d.ts', format: 'es' },
|
|
36
|
+
plugins: [dts(), typescript()]
|
|
37
|
+
}
|
|
38
|
+
];
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import makeWASocket, { Browsers, makeCacheableSignalKeyStore } from "baileys";
|
|
2
|
+
import { Kysely, sql } from "kysely";
|
|
3
|
+
import NodeCache from "node-cache";
|
|
4
|
+
import pino from "pino";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { AuthAdapterHandler, ConnectDB, StoreAdapterHandler } from "../database/handler";
|
|
7
|
+
import { DB } from "../database/schema";
|
|
8
|
+
import { ClientClassesType } from "../types/classes/client";
|
|
9
|
+
import { EventCallbackType, EventEnumType } from "../types/classes/event";
|
|
10
|
+
import Event from "./Event";
|
|
11
|
+
|
|
12
|
+
class Client {
|
|
13
|
+
options: z.infer<typeof ClientClassesType> | undefined;
|
|
14
|
+
private chatId = "zaileys-chats";
|
|
15
|
+
|
|
16
|
+
private logger = pino({ level: "silent", enabled: false });
|
|
17
|
+
private event: Event;
|
|
18
|
+
private db: Kysely<DB> | undefined;
|
|
19
|
+
private socket: ReturnType<typeof makeWASocket> | undefined;
|
|
20
|
+
private groupCache = new NodeCache({ stdTTL: 5 * 60, useClones: false });
|
|
21
|
+
|
|
22
|
+
constructor(private props: z.input<typeof ClientClassesType>) {
|
|
23
|
+
this.initialize();
|
|
24
|
+
this.event = new Event(this);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async initialize() {
|
|
28
|
+
this.options = await ClientClassesType.parseAsync(this.props);
|
|
29
|
+
this.db = ConnectDB(this.options!.database.type, this.options!.database.connection.url);
|
|
30
|
+
|
|
31
|
+
const { state, saveCreds, removeCreds } = await AuthAdapterHandler(this.db, this.chatId);
|
|
32
|
+
const store = await StoreAdapterHandler(this.db, this.chatId);
|
|
33
|
+
|
|
34
|
+
this.socket = makeWASocket({
|
|
35
|
+
logger: this.logger,
|
|
36
|
+
markOnlineOnConnect: this.options.autoOnline,
|
|
37
|
+
syncFullHistory: false,
|
|
38
|
+
defaultQueryTimeoutMs: undefined,
|
|
39
|
+
msgRetryCounterCache: new NodeCache(),
|
|
40
|
+
cachedGroupMetadata: async (jid) => this.groupCache.get(jid),
|
|
41
|
+
printQRInTerminal: this.options.authType == "qr",
|
|
42
|
+
browser: Browsers.ubuntu(this.options.authType == "qr" ? "Zaileys Library" : "Firefox"),
|
|
43
|
+
auth: {
|
|
44
|
+
creds: state.creds,
|
|
45
|
+
keys: makeCacheableSignalKeyStore(state.keys, this.logger),
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
if (this.options.authType == "pairing" && this.options.phoneNumber && !this.socket?.authState.creds.registered) {
|
|
50
|
+
setTimeout(async () => {
|
|
51
|
+
try {
|
|
52
|
+
if (this.options?.authType == "pairing") {
|
|
53
|
+
const code = await this.socket?.requestPairingCode(this.options.phoneNumber.toString());
|
|
54
|
+
console.log("🚀 ~ Client.ts:53 ~ Client ~ setTimeout ~ code:", code);
|
|
55
|
+
}
|
|
56
|
+
} catch {
|
|
57
|
+
console.log("Connection failed");
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
}, 5000);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
this.socket?.ev.on("creds.update", saveCreds);
|
|
64
|
+
store.bind(this.socket?.ev);
|
|
65
|
+
this.event.setup(this.socket);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
on<T extends EventEnumType>(event: T, handler: EventCallbackType[T]) {
|
|
69
|
+
this.event.on(event, handler);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export default Client;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { DisconnectReason, WASocket } from "baileys";
|
|
3
|
+
import { EventCallbackType, EventEnumType } from "../types/classes/event";
|
|
4
|
+
import Client from "./Client";
|
|
5
|
+
|
|
6
|
+
class Event {
|
|
7
|
+
private events: Map<EventEnumType, Function[]> = new Map();
|
|
8
|
+
|
|
9
|
+
constructor(private client: Client) {}
|
|
10
|
+
|
|
11
|
+
setup(sock: WASocket) {
|
|
12
|
+
sock.ev.on("connection.update", async (update) => {
|
|
13
|
+
const { connection, lastDisconnect, qr } = update;
|
|
14
|
+
this.emit("connection", { status: connection || "connecting" });
|
|
15
|
+
|
|
16
|
+
if (this.client.options?.authType == "qr" && qr) {
|
|
17
|
+
console.log("Scan qrcode with your whatsapp: ");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (connection === "close") {
|
|
21
|
+
const code = (lastDisconnect?.error as any)?.output?.statusCode;
|
|
22
|
+
const isReconnect = code !== DisconnectReason.loggedOut;
|
|
23
|
+
console.log(lastDisconnect?.error?.message);
|
|
24
|
+
|
|
25
|
+
if (code == 401 || code == 405 || code == 500) {
|
|
26
|
+
// await this.client.logout();
|
|
27
|
+
// await this.client.initialize();
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (isReconnect) await this.client.initialize();
|
|
32
|
+
} else if (connection === "open") {
|
|
33
|
+
this.emit("connection", { status: "open" });
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
sock.ev.on("messages.upsert", ({ messages }) => {
|
|
38
|
+
this.emit("messages", messages as never);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
sock.ev.on("call", (call) => {
|
|
42
|
+
this.emit("call", call as never);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
on<T extends EventEnumType>(event: T, handler: EventCallbackType[T]) {
|
|
47
|
+
if (!this.events.has(event)) {
|
|
48
|
+
this.events.set(event, []);
|
|
49
|
+
}
|
|
50
|
+
this.events.get(event)!.push(handler);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private emit<T extends EventEnumType>(event: T, data: Parameters<EventCallbackType[T]>[0]) {
|
|
54
|
+
const handlers = this.events.get(event) || [];
|
|
55
|
+
handlers.forEach((handler) => handler(data));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export default Event;
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import Database from "better-sqlite3";
|
|
2
|
+
import { existsSync, mkdirSync, writeFileSync } from "fs";
|
|
3
|
+
import { Kysely, MysqlDialect, PostgresDialect, SqliteDialect } from "kysely";
|
|
4
|
+
import mysql from "mysql2";
|
|
5
|
+
import path from "path";
|
|
6
|
+
import { Pool } from "pg";
|
|
7
|
+
import { URL } from "url";
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
import { BufferJSON, fromObject, initAuthCreds } from "../helpers/adapter";
|
|
10
|
+
import { AuthAdapterHandlerType, AuthenticationCreds, SignalDataTypeMap } from "../types/adapter/general";
|
|
11
|
+
import { AdapterDatabaseType, ClientClassesType } from "../types/classes/client";
|
|
12
|
+
import type { DB } from "./schema";
|
|
13
|
+
import { BaileysEventEmitter } from "baileys";
|
|
14
|
+
|
|
15
|
+
export const ConnectDB = (type: z.infer<typeof AdapterDatabaseType>["type"], url: string): Kysely<DB> => {
|
|
16
|
+
if (type === "sqlite") {
|
|
17
|
+
const filepath = url || "./db/zaileys.db";
|
|
18
|
+
const resolvedPath = path.resolve(filepath);
|
|
19
|
+
|
|
20
|
+
mkdirSync(path.dirname(resolvedPath), { recursive: true });
|
|
21
|
+
writeFileSync(resolvedPath, "", { flag: "a" });
|
|
22
|
+
|
|
23
|
+
return new Kysely<DB>({
|
|
24
|
+
dialect: new SqliteDialect({
|
|
25
|
+
database: new Database(resolvedPath),
|
|
26
|
+
}),
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const conn = new URL(url);
|
|
31
|
+
const protocol = conn.protocol.replace(":", "");
|
|
32
|
+
|
|
33
|
+
if (type === "mysql") {
|
|
34
|
+
return new Kysely<DB>({
|
|
35
|
+
dialect: new MysqlDialect({
|
|
36
|
+
pool: mysql.createPool({
|
|
37
|
+
host: conn.hostname,
|
|
38
|
+
user: conn.username,
|
|
39
|
+
password: conn.password,
|
|
40
|
+
database: conn.pathname.replace("/", ""),
|
|
41
|
+
port: parseInt(conn.port || "3306", 10),
|
|
42
|
+
}),
|
|
43
|
+
}),
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (type === "postgresql") {
|
|
48
|
+
return new Kysely<DB>({
|
|
49
|
+
dialect: new PostgresDialect({
|
|
50
|
+
pool: new Pool({
|
|
51
|
+
host: conn.hostname,
|
|
52
|
+
user: conn.username,
|
|
53
|
+
password: conn.password,
|
|
54
|
+
database: conn.pathname.replace("/", ""),
|
|
55
|
+
port: parseInt(conn.port || "5432", 10),
|
|
56
|
+
}),
|
|
57
|
+
}),
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
throw new Error(`Unsupported database protocol: ${protocol}`);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export const MigrateDB = async (db: Kysely<DB>) => {
|
|
65
|
+
await db.schema
|
|
66
|
+
.createTable("auth")
|
|
67
|
+
.ifNotExists()
|
|
68
|
+
.addColumn("session", "varchar(50)", (col) => col.notNull())
|
|
69
|
+
.addColumn("id", "varchar(80)", (col) => col.notNull())
|
|
70
|
+
.addColumn("value", "text", (col) => col.defaultTo(null))
|
|
71
|
+
.addUniqueConstraint("auth_session_id_unique", ["session", "id"])
|
|
72
|
+
.execute();
|
|
73
|
+
|
|
74
|
+
await db.schema
|
|
75
|
+
.createTable("chats")
|
|
76
|
+
.ifNotExists()
|
|
77
|
+
.addColumn("session", "varchar(50)", (col) => col.notNull())
|
|
78
|
+
.addColumn("id", "varchar(80)", (col) => col.notNull())
|
|
79
|
+
.addColumn("value", "text", (col) => col.defaultTo(null))
|
|
80
|
+
.addUniqueConstraint("chats_session_id_unique", ["session", "id"])
|
|
81
|
+
.execute();
|
|
82
|
+
|
|
83
|
+
await db.schema
|
|
84
|
+
.createTable("contacts")
|
|
85
|
+
.ifNotExists()
|
|
86
|
+
.addColumn("session", "varchar(50)", (col) => col.notNull())
|
|
87
|
+
.addColumn("id", "varchar(80)", (col) => col.notNull())
|
|
88
|
+
.addColumn("value", "text", (col) => col.defaultTo(null))
|
|
89
|
+
.addUniqueConstraint("contacts_session_id_unique", ["session", "id"])
|
|
90
|
+
.execute();
|
|
91
|
+
|
|
92
|
+
await db.schema
|
|
93
|
+
.createTable("messages")
|
|
94
|
+
.ifNotExists()
|
|
95
|
+
.addColumn("session", "varchar(50)", (col) => col.notNull())
|
|
96
|
+
.addColumn("id", "varchar(80)", (col) => col.notNull())
|
|
97
|
+
.addColumn("value", "text", (col) => col.defaultTo(null))
|
|
98
|
+
.addUniqueConstraint("messages_session_id_unique", ["session", "id"])
|
|
99
|
+
.execute();
|
|
100
|
+
|
|
101
|
+
await db.schema.createIndex("auth_session_idx").ifNotExists().on("auth").column("session").execute();
|
|
102
|
+
await db.schema.createIndex("auth_id_idx").ifNotExists().on("auth").column("id").execute();
|
|
103
|
+
await db.schema.createIndex("chats_session_idx").ifNotExists().on("chats").column("session").execute();
|
|
104
|
+
await db.schema.createIndex("chats_id_idx").ifNotExists().on("chats").column("id").execute();
|
|
105
|
+
await db.schema.createIndex("contacts_session_idx").ifNotExists().on("contacts").column("session").execute();
|
|
106
|
+
await db.schema.createIndex("contacts_id_idx").ifNotExists().on("contacts").column("id").execute();
|
|
107
|
+
await db.schema.createIndex("messages_session_idx").ifNotExists().on("messages").column("session").execute();
|
|
108
|
+
await db.schema.createIndex("messages_id_idx").ifNotExists().on("messages").column("id").execute();
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
export const AuthAdapterHandler = async (db: Kysely<DB>, session: string): AuthAdapterHandlerType => {
|
|
112
|
+
const TABLE_NAME = "auth";
|
|
113
|
+
const RETRY_DELAY = 200;
|
|
114
|
+
const MAX_RETRIES = 10;
|
|
115
|
+
|
|
116
|
+
await MigrateDB(db);
|
|
117
|
+
|
|
118
|
+
const retry = async <T>(fn: () => Promise<T>): Promise<T> => {
|
|
119
|
+
for (let x = 0; x < MAX_RETRIES; x++) {
|
|
120
|
+
try {
|
|
121
|
+
return await fn();
|
|
122
|
+
} catch (e) {
|
|
123
|
+
await new Promise((r) => setTimeout(r, RETRY_DELAY));
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
throw new Error("Max retries reached");
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const readData = async (id: string) => {
|
|
130
|
+
const row = await retry(() => db.selectFrom(TABLE_NAME).select(["value"]).where("id", "=", id).where("session", "=", session).executeTakeFirst());
|
|
131
|
+
|
|
132
|
+
if (!row?.value) return null;
|
|
133
|
+
|
|
134
|
+
const credsStr = typeof row.value === "object" ? JSON.stringify(row.value) : row.value;
|
|
135
|
+
return JSON.parse(credsStr, BufferJSON.reviver);
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const writeData = async (id: string, value: object) => {
|
|
139
|
+
const valueFixed = JSON.stringify(value, BufferJSON.replacer);
|
|
140
|
+
|
|
141
|
+
await retry(() =>
|
|
142
|
+
db
|
|
143
|
+
.insertInto(TABLE_NAME)
|
|
144
|
+
.values({
|
|
145
|
+
session: session,
|
|
146
|
+
id,
|
|
147
|
+
value: valueFixed,
|
|
148
|
+
})
|
|
149
|
+
.onConflict((oc) => oc.columns(["session", "id"]).doUpdateSet({ value: valueFixed }))
|
|
150
|
+
.execute()
|
|
151
|
+
);
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
const removeData = async (id: string) => {
|
|
155
|
+
await retry(() => db.deleteFrom(TABLE_NAME).where("id", "=", id).where("session", "=", session).execute());
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const clearAll = async () => {
|
|
159
|
+
await retry(() => db.deleteFrom(TABLE_NAME).where("session", "=", session).where("id", "!=", "creds").execute());
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
const removeAll = async () => {
|
|
163
|
+
await retry(() => db.deleteFrom(TABLE_NAME).where("session", "=", session).execute());
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const creds: AuthenticationCreds = (await readData("creds")) || initAuthCreds();
|
|
167
|
+
|
|
168
|
+
return {
|
|
169
|
+
state: {
|
|
170
|
+
creds: creds,
|
|
171
|
+
keys: {
|
|
172
|
+
get: async (type, ids) => {
|
|
173
|
+
const data: { [id: string]: SignalDataTypeMap[typeof type] } = {};
|
|
174
|
+
for (const id of ids) {
|
|
175
|
+
let value = await readData(`${type}-${id}`);
|
|
176
|
+
if (type === "app-state-sync-key" && value) {
|
|
177
|
+
value = fromObject(value);
|
|
178
|
+
}
|
|
179
|
+
data[id] = value;
|
|
180
|
+
}
|
|
181
|
+
return data;
|
|
182
|
+
},
|
|
183
|
+
set: async (data) => {
|
|
184
|
+
for (const category in data) {
|
|
185
|
+
for (const id in data[category as never] as any) {
|
|
186
|
+
const value = data[category as never][id];
|
|
187
|
+
const name = `${category}-${id}`;
|
|
188
|
+
if (value) {
|
|
189
|
+
await writeData(name, value);
|
|
190
|
+
} else {
|
|
191
|
+
await removeData(name);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
saveCreds: async () => {
|
|
199
|
+
await writeData("creds", creds);
|
|
200
|
+
},
|
|
201
|
+
clear: async () => {
|
|
202
|
+
await clearAll();
|
|
203
|
+
},
|
|
204
|
+
removeCreds: async () => {
|
|
205
|
+
await removeAll();
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
export const StoreAdapterHandler = async (db: Kysely<DB>, session: string) => {
|
|
211
|
+
return {
|
|
212
|
+
bind: (event: BaileysEventEmitter) => {
|
|
213
|
+
event.on("messaging-history.set", async (update) => {
|
|
214
|
+
const { chats, contacts, messages } = update;
|
|
215
|
+
|
|
216
|
+
for (const chat of chats) {
|
|
217
|
+
await db
|
|
218
|
+
.insertInto("chats")
|
|
219
|
+
.values({ session, id: chat.id!, value: JSON.stringify(chat) })
|
|
220
|
+
.onConflict((oc) => oc.columns(["session", "id"]).doUpdateSet({ value: JSON.stringify(chat) }))
|
|
221
|
+
.execute();
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
for (const contact of contacts) {
|
|
225
|
+
await db
|
|
226
|
+
.insertInto("contacts")
|
|
227
|
+
.values({ session, id: contact.id!, value: JSON.stringify(contact) })
|
|
228
|
+
.onConflict((oc) => oc.columns(["session", "id"]).doUpdateSet({ value: JSON.stringify(contact) }))
|
|
229
|
+
.execute();
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
for (const message of messages) {
|
|
233
|
+
await db
|
|
234
|
+
.insertInto("messages")
|
|
235
|
+
.values({ session, id: message.key.id!, value: JSON.stringify(message) })
|
|
236
|
+
.onConflict((oc) => oc.columns(["session", "id"]).doUpdateSet({ value: JSON.stringify(message) }))
|
|
237
|
+
.execute();
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
event.on("messages.upsert", async ({ messages }) => {
|
|
242
|
+
for (const message of messages) {
|
|
243
|
+
await db
|
|
244
|
+
.insertInto("messages")
|
|
245
|
+
.values({ session, id: message.key.id!, value: JSON.stringify(message) })
|
|
246
|
+
.onConflict((oc) => oc.columns(["session", "id"]).doUpdateSet({ value: JSON.stringify(message) }))
|
|
247
|
+
.execute();
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
event.on("chats.upsert", async (chats) => {
|
|
252
|
+
for (const chat of chats) {
|
|
253
|
+
await db
|
|
254
|
+
.insertInto("chats")
|
|
255
|
+
.values({ session, id: chat.id!, value: JSON.stringify(chat) })
|
|
256
|
+
.onConflict((oc) => oc.columns(["session", "id"]).doUpdateSet({ value: JSON.stringify(chat) }))
|
|
257
|
+
.execute();
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
event.on("contacts.upsert", async (contacts) => {
|
|
262
|
+
for (const contact of contacts) {
|
|
263
|
+
await db
|
|
264
|
+
.insertInto("contacts")
|
|
265
|
+
.values({ session, id: contact.id!, value: JSON.stringify(contact) })
|
|
266
|
+
.onConflict((oc) => oc.columns(["session", "id"]).doUpdateSet({ value: JSON.stringify(contact) }))
|
|
267
|
+
.execute();
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
},
|
|
271
|
+
};
|
|
272
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
export const AuthSchema = z.object({
|
|
4
|
+
session: z.string(),
|
|
5
|
+
id: z.string(),
|
|
6
|
+
value: z.string().nullable(),
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
export const ChatSchema = z.object({
|
|
10
|
+
session: z.string(),
|
|
11
|
+
id: z.string(),
|
|
12
|
+
value: z.string().nullable(),
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export const ContactSchema = z.object({
|
|
16
|
+
session: z.string(),
|
|
17
|
+
id: z.string(),
|
|
18
|
+
value: z.string().nullable(),
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
export const MessageSchema = z.object({
|
|
22
|
+
session: z.string(),
|
|
23
|
+
id: z.string(),
|
|
24
|
+
value: z.string().nullable(),
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
export type AuthTable = z.infer<typeof AuthSchema>;
|
|
28
|
+
export type ChatTable = z.infer<typeof ChatSchema>;
|
|
29
|
+
export type ContactTable = z.infer<typeof ContactSchema>;
|
|
30
|
+
export type MessageTable = z.infer<typeof MessageSchema>;
|
|
31
|
+
|
|
32
|
+
export type DB = {
|
|
33
|
+
auth: AuthTable;
|
|
34
|
+
chats: ChatTable;
|
|
35
|
+
contacts: ContactTable;
|
|
36
|
+
messages: MessageTable;
|
|
37
|
+
};
|