feat: WhatsApp Nucleo con Nuxt 4 + Baileys v7
Some checks failed
Build and Deploy / build-and-deploy (push) Failing after 6m46s
Some checks failed
Build and Deploy / build-and-deploy (push) Failing after 6m46s
Reemplazo completo de Evolution API por implementación directa con Baileys. Características: - Dashboard completo con Nuxt UI v4 - Soporte para múltiples instancias de WhatsApp - Conexión via QR code o pairing code - Persistencia de mensajes en PostgreSQL - API REST para integraciones externas - Webhooks con firma HMAC - SSE para actualizaciones en tiempo real - Autenticación con Authentik
This commit is contained in:
131
server/services/baileys/auth-state.ts
Normal file
131
server/services/baileys/auth-state.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* PostgreSQL-based auth state for Baileys
|
||||
* Stores credentials and keys in the database instead of files
|
||||
*/
|
||||
import type { AuthenticationCreds, SignalDataTypeMap } from '@whiskeysockets/baileys'
|
||||
import { initAuthCreds, BufferJSON, proto } from '@whiskeysockets/baileys'
|
||||
import { query } from '../../utils/database'
|
||||
|
||||
export interface PostgresAuthState {
|
||||
state: {
|
||||
creds: AuthenticationCreds
|
||||
keys: {
|
||||
get: <T extends keyof SignalDataTypeMap>(type: T, ids: string[]) => Promise<{ [id: string]: SignalDataTypeMap[T] }>
|
||||
set: (data: { [type: string]: { [id: string]: SignalDataTypeMap[keyof SignalDataTypeMap] | null } }) => Promise<void>
|
||||
}
|
||||
}
|
||||
saveCreds: () => Promise<void>
|
||||
}
|
||||
|
||||
export async function usePostgresAuthState(instanceId: string): Promise<PostgresAuthState> {
|
||||
// Load or create credentials
|
||||
const loadCreds = async (): Promise<AuthenticationCreds> => {
|
||||
const result = await query<{ key_data: any }>(
|
||||
'SELECT key_data FROM auth_keys WHERE instance_id = $1 AND key_type = $2 AND key_id = $3',
|
||||
[instanceId, 'creds', 'default']
|
||||
)
|
||||
|
||||
if (result.rows.length > 0 && result.rows[0].key_data) {
|
||||
return JSON.parse(JSON.stringify(result.rows[0].key_data), BufferJSON.reviver)
|
||||
}
|
||||
|
||||
return initAuthCreds()
|
||||
}
|
||||
|
||||
// Save credentials
|
||||
const saveCreds = async (creds: AuthenticationCreds): Promise<void> => {
|
||||
const data = JSON.parse(JSON.stringify(creds, BufferJSON.replacer))
|
||||
await query(
|
||||
`INSERT INTO auth_keys (instance_id, key_type, key_id, key_data)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
ON CONFLICT (instance_id, key_type, key_id)
|
||||
DO UPDATE SET key_data = $4, updated_at = NOW()`,
|
||||
[instanceId, 'creds', 'default', data]
|
||||
)
|
||||
}
|
||||
|
||||
// Load keys by type and ids
|
||||
const loadKeys = async <T extends keyof SignalDataTypeMap>(
|
||||
type: T,
|
||||
ids: string[]
|
||||
): Promise<{ [id: string]: SignalDataTypeMap[T] }> => {
|
||||
const result: { [id: string]: SignalDataTypeMap[T] } = {}
|
||||
|
||||
if (ids.length === 0) return result
|
||||
|
||||
const placeholders = ids.map((_, i) => `$${i + 3}`).join(', ')
|
||||
const queryResult = await query<{ key_id: string; key_data: any }>(
|
||||
`SELECT key_id, key_data FROM auth_keys
|
||||
WHERE instance_id = $1 AND key_type = $2 AND key_id IN (${placeholders})`,
|
||||
[instanceId, type, ...ids]
|
||||
)
|
||||
|
||||
for (const row of queryResult.rows) {
|
||||
let value = JSON.parse(JSON.stringify(row.key_data), BufferJSON.reviver)
|
||||
|
||||
// Handle special types
|
||||
if (type === 'app-state-sync-key' && value) {
|
||||
value = proto.Message.AppStateSyncKeyData.fromObject(value)
|
||||
}
|
||||
|
||||
result[row.key_id] = value
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Save keys
|
||||
const saveKeys = async (
|
||||
data: { [type: string]: { [id: string]: SignalDataTypeMap[keyof SignalDataTypeMap] | null } }
|
||||
): Promise<void> => {
|
||||
for (const type in data) {
|
||||
for (const id in data[type]) {
|
||||
const value = data[type][id]
|
||||
|
||||
if (value === null) {
|
||||
// Delete key
|
||||
await query(
|
||||
'DELETE FROM auth_keys WHERE instance_id = $1 AND key_type = $2 AND key_id = $3',
|
||||
[instanceId, type, id]
|
||||
)
|
||||
} else {
|
||||
// Upsert key
|
||||
const serialized = JSON.parse(JSON.stringify(value, BufferJSON.replacer))
|
||||
await query(
|
||||
`INSERT INTO auth_keys (instance_id, key_type, key_id, key_data)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
ON CONFLICT (instance_id, key_type, key_id)
|
||||
DO UPDATE SET key_data = $4, updated_at = NOW()`,
|
||||
[instanceId, type, id, serialized]
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load initial credentials
|
||||
const creds = await loadCreds()
|
||||
|
||||
return {
|
||||
state: {
|
||||
creds,
|
||||
keys: {
|
||||
get: loadKeys,
|
||||
set: saveKeys
|
||||
}
|
||||
},
|
||||
saveCreds: async () => {
|
||||
await saveCreds(creds)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all auth data for an instance
|
||||
*/
|
||||
export async function clearAuthState(instanceId: string): Promise<void> {
|
||||
await query(
|
||||
'DELETE FROM auth_keys WHERE instance_id = $1',
|
||||
[instanceId]
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user