Fix: Corregir UModal en MessageContact usando v-model:open
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m7s
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m7s
El modal de contacto usaba v-model en lugar de v-model:open según la documentación de Nuxt UI 4. También se actualizó la estructura para usar los slots correctos del UModal (#header, #body, #footer).
This commit is contained in:
@@ -60,8 +60,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Contact details modal -->
|
<!-- Contact details modal -->
|
||||||
<UModal v-model="showDetails">
|
<UModal v-model:open="showDetails" :title="contact.displayName" description="Contacto compartido">
|
||||||
<UCard>
|
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
<div class="w-12 h-12 rounded-full bg-[var(--wa-green-light)] flex items-center justify-center">
|
<div class="w-12 h-12 rounded-full bg-[var(--wa-green-light)] flex items-center justify-center">
|
||||||
@@ -74,6 +73,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template #body>
|
||||||
<div class="space-y-3">
|
<div class="space-y-3">
|
||||||
<div v-for="(phone, i) in contact.phones" :key="i" class="flex items-center gap-3">
|
<div v-for="(phone, i) in contact.phones" :key="i" class="flex items-center gap-3">
|
||||||
<UIcon name="i-lucide-phone" class="w-5 h-5 text-[var(--wa-text-muted)]" />
|
<UIcon name="i-lucide-phone" class="w-5 h-5 text-[var(--wa-text-muted)]" />
|
||||||
@@ -89,9 +89,9 @@
|
|||||||
No hay números de teléfono disponibles
|
No hay números de teléfono disponibles
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="flex justify-end gap-2">
|
|
||||||
<UButton variant="ghost" @click="showDetails = false">
|
<UButton variant="ghost" @click="showDetails = false">
|
||||||
Cerrar
|
Cerrar
|
||||||
</UButton>
|
</UButton>
|
||||||
@@ -99,9 +99,7 @@
|
|||||||
<UIcon name="i-lucide-copy" class="w-4 h-4 mr-1" />
|
<UIcon name="i-lucide-copy" class="w-4 h-4 mr-1" />
|
||||||
Copiar número
|
Copiar número
|
||||||
</UButton>
|
</UButton>
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
</UCard>
|
|
||||||
</UModal>
|
</UModal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
1117
docs/baileys-media-messaging.md
Normal file
1117
docs/baileys-media-messaging.md
Normal file
File diff suppressed because it is too large
Load Diff
400
docs/scrape-media-docs.mjs
Normal file
400
docs/scrape-media-docs.mjs
Normal file
@@ -0,0 +1,400 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Script para scrapear documentación de Baileys relacionada con Media Messaging
|
||||||
|
* Genera: baileys-media-messaging.md
|
||||||
|
*/
|
||||||
|
|
||||||
|
const BASE_URL = 'https://baileys.wiki/docs/api';
|
||||||
|
|
||||||
|
// Elementos a scrapear para media messaging
|
||||||
|
const ELEMENTS = {
|
||||||
|
typeAliases: [
|
||||||
|
'AnyMediaMessageContent',
|
||||||
|
'AnyMessageContent',
|
||||||
|
'AnyRegularMessageContent',
|
||||||
|
'WAContactMessage',
|
||||||
|
'WAContactsArrayMessage',
|
||||||
|
'WALocationMessage',
|
||||||
|
'WAGenericMediaMessage',
|
||||||
|
'PollMessageOptions',
|
||||||
|
'EventMessageOptions',
|
||||||
|
'MediaType',
|
||||||
|
'MediaGenerationOptions',
|
||||||
|
'MiscMessageGenerationOptions',
|
||||||
|
'MessageGenerationOptions',
|
||||||
|
'MessageContentGenerationOptions',
|
||||||
|
'WAMediaUpload',
|
||||||
|
'DownloadableMessage',
|
||||||
|
'WAContextInfo',
|
||||||
|
'MessageWithContextInfo',
|
||||||
|
],
|
||||||
|
functions: [
|
||||||
|
'prepareWAMessageMedia',
|
||||||
|
'generateWAMessage',
|
||||||
|
'generateWAMessageContent',
|
||||||
|
'generateWAMessageFromContent',
|
||||||
|
'getContentType',
|
||||||
|
'extensionForMediaMessage',
|
||||||
|
'downloadMediaMessage',
|
||||||
|
'downloadContentFromMessage',
|
||||||
|
'encryptedStream',
|
||||||
|
'getMediaKeys',
|
||||||
|
],
|
||||||
|
variables: [
|
||||||
|
'MEDIA_KEYS',
|
||||||
|
'MEDIA_PATH_MAP',
|
||||||
|
'MEDIA_HKDF_KEY_MAPPING',
|
||||||
|
],
|
||||||
|
interfaces: [
|
||||||
|
'WAUrlInfo',
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
// Función para hacer fetch con retry
|
||||||
|
async function fetchWithRetry(url, retries = 3) {
|
||||||
|
for (let i = 0; i < retries; i++) {
|
||||||
|
try {
|
||||||
|
const response = await fetch(url);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP ${response.status}`);
|
||||||
|
}
|
||||||
|
return await response.text();
|
||||||
|
} catch (error) {
|
||||||
|
console.error(` Intento ${i + 1}/${retries} fallido: ${error.message}`);
|
||||||
|
if (i === retries - 1) throw error;
|
||||||
|
await new Promise(r => setTimeout(r, 1000 * (i + 1)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Función para extraer contenido principal de una página
|
||||||
|
function extractContent(html, elementName) {
|
||||||
|
// Remover scripts, styles, nav, footer
|
||||||
|
let content = html
|
||||||
|
.replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '')
|
||||||
|
.replace(/<style[^>]*>[\s\S]*?<\/style>/gi, '')
|
||||||
|
.replace(/<nav[^>]*>[\s\S]*?<\/nav>/gi, '')
|
||||||
|
.replace(/<footer[^>]*>[\s\S]*?<\/footer>/gi, '')
|
||||||
|
.replace(/<header[^>]*>[\s\S]*?<\/header>/gi, '');
|
||||||
|
|
||||||
|
// Buscar el contenido principal (article o main)
|
||||||
|
const articleMatch = content.match(/<article[^>]*>([\s\S]*?)<\/article>/i);
|
||||||
|
const mainMatch = content.match(/<main[^>]*>([\s\S]*?)<\/main>/i);
|
||||||
|
|
||||||
|
content = articleMatch ? articleMatch[1] : (mainMatch ? mainMatch[1] : content);
|
||||||
|
|
||||||
|
// Convertir HTML a texto/markdown básico
|
||||||
|
content = content
|
||||||
|
// Headers
|
||||||
|
.replace(/<h1[^>]*>([\s\S]*?)<\/h1>/gi, '\n# $1\n')
|
||||||
|
.replace(/<h2[^>]*>([\s\S]*?)<\/h2>/gi, '\n## $1\n')
|
||||||
|
.replace(/<h3[^>]*>([\s\S]*?)<\/h3>/gi, '\n### $1\n')
|
||||||
|
.replace(/<h4[^>]*>([\s\S]*?)<\/h4>/gi, '\n#### $1\n')
|
||||||
|
// Code blocks
|
||||||
|
.replace(/<pre[^>]*><code[^>]*>([\s\S]*?)<\/code><\/pre>/gi, '\n```typescript\n$1\n```\n')
|
||||||
|
.replace(/<code[^>]*>([\s\S]*?)<\/code>/gi, '`$1`')
|
||||||
|
// Lists
|
||||||
|
.replace(/<li[^>]*>([\s\S]*?)<\/li>/gi, '- $1\n')
|
||||||
|
.replace(/<ul[^>]*>/gi, '\n')
|
||||||
|
.replace(/<\/ul>/gi, '\n')
|
||||||
|
.replace(/<ol[^>]*>/gi, '\n')
|
||||||
|
.replace(/<\/ol>/gi, '\n')
|
||||||
|
// Paragraphs
|
||||||
|
.replace(/<p[^>]*>([\s\S]*?)<\/p>/gi, '\n$1\n')
|
||||||
|
// Bold/Italic
|
||||||
|
.replace(/<strong[^>]*>([\s\S]*?)<\/strong>/gi, '**$1**')
|
||||||
|
.replace(/<b[^>]*>([\s\S]*?)<\/b>/gi, '**$1**')
|
||||||
|
.replace(/<em[^>]*>([\s\S]*?)<\/em>/gi, '*$1*')
|
||||||
|
.replace(/<i[^>]*>([\s\S]*?)<\/i>/gi, '*$1*')
|
||||||
|
// Links
|
||||||
|
.replace(/<a[^>]*href="([^"]*)"[^>]*>([\s\S]*?)<\/a>/gi, '[$2]($1)')
|
||||||
|
// Divs y spans
|
||||||
|
.replace(/<div[^>]*>/gi, '\n')
|
||||||
|
.replace(/<\/div>/gi, '\n')
|
||||||
|
.replace(/<span[^>]*>/gi, '')
|
||||||
|
.replace(/<\/span>/gi, '')
|
||||||
|
// Breaks
|
||||||
|
.replace(/<br\s*\/?>/gi, '\n')
|
||||||
|
// Remover otros tags HTML
|
||||||
|
.replace(/<[^>]+>/g, '')
|
||||||
|
// Decodificar entidades HTML
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>')
|
||||||
|
.replace(/&/g, '&')
|
||||||
|
.replace(/"/g, '"')
|
||||||
|
.replace(/'/g, "'")
|
||||||
|
.replace(/'/g, "'")
|
||||||
|
.replace(/ /g, ' ')
|
||||||
|
// Limpiar espacios múltiples
|
||||||
|
.replace(/\n{3,}/g, '\n\n')
|
||||||
|
.replace(/[ \t]+/g, ' ')
|
||||||
|
.trim();
|
||||||
|
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Función para construir URL según el tipo
|
||||||
|
function buildUrl(type, name) {
|
||||||
|
const urlMap = {
|
||||||
|
typeAliases: `${BASE_URL}/type-aliases/${name}`,
|
||||||
|
functions: `${BASE_URL}/functions/${name}`,
|
||||||
|
variables: `${BASE_URL}/variables/${name}`,
|
||||||
|
interfaces: `${BASE_URL}/interfaces/${name}`,
|
||||||
|
};
|
||||||
|
return urlMap[type];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Función principal
|
||||||
|
async function main() {
|
||||||
|
console.log('🚀 Iniciando scraping de documentación de Baileys para Media Messaging...\n');
|
||||||
|
|
||||||
|
const results = {
|
||||||
|
typeAliases: [],
|
||||||
|
functions: [],
|
||||||
|
variables: [],
|
||||||
|
interfaces: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
// Scrapear cada categoría
|
||||||
|
for (const [category, elements] of Object.entries(ELEMENTS)) {
|
||||||
|
console.log(`\n📁 Scrapeando ${category}...`);
|
||||||
|
|
||||||
|
for (const element of elements) {
|
||||||
|
const url = buildUrl(category, element);
|
||||||
|
console.log(` 📄 ${element}...`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const html = await fetchWithRetry(url);
|
||||||
|
const content = extractContent(html, element);
|
||||||
|
|
||||||
|
results[category].push({
|
||||||
|
name: element,
|
||||||
|
url: url,
|
||||||
|
content: content,
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(` ✅ ${element} - OK`);
|
||||||
|
|
||||||
|
// Pequeña pausa para no saturar el servidor
|
||||||
|
await new Promise(r => setTimeout(r, 500));
|
||||||
|
} catch (error) {
|
||||||
|
console.log(` ❌ ${element} - Error: ${error.message}`);
|
||||||
|
results[category].push({
|
||||||
|
name: element,
|
||||||
|
url: url,
|
||||||
|
content: `Error al obtener documentación: ${error.message}`,
|
||||||
|
error: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generar markdown
|
||||||
|
console.log('\n📝 Generando markdown...');
|
||||||
|
|
||||||
|
let markdown = `# Baileys Media Messaging API Documentation
|
||||||
|
|
||||||
|
> Documentación auto-generada para el desarrollo de mensajes multimedia en WhatsApp Nucleo
|
||||||
|
> Fuente: https://baileys.wiki
|
||||||
|
> Generado: ${new Date().toISOString()}
|
||||||
|
|
||||||
|
Esta documentación contiene la API de Baileys relevante para enviar diferentes tipos de mensajes multimedia:
|
||||||
|
- Imágenes y Videos
|
||||||
|
- Documentos
|
||||||
|
- Audio y Notas de Voz
|
||||||
|
- Contactos
|
||||||
|
- Ubicación
|
||||||
|
- Encuestas (Polls)
|
||||||
|
- Eventos
|
||||||
|
|
||||||
|
## Tabla de Contenidos
|
||||||
|
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Generar tabla de contenidos
|
||||||
|
const categoryNames = {
|
||||||
|
interfaces: 'Interfaces',
|
||||||
|
typeAliases: 'Type Aliases',
|
||||||
|
functions: 'Funciones',
|
||||||
|
variables: 'Variables',
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const [category, items] of Object.entries(results)) {
|
||||||
|
if (items.length > 0) {
|
||||||
|
markdown += `### ${categoryNames[category]}\n`;
|
||||||
|
for (const item of items) {
|
||||||
|
const anchor = `${category.slice(0, -1)}-${item.name.toLowerCase()}`;
|
||||||
|
markdown += `- [${item.name}](#${anchor})\n`;
|
||||||
|
}
|
||||||
|
markdown += '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Agregar contenido de cada categoría
|
||||||
|
for (const [category, items] of Object.entries(results)) {
|
||||||
|
if (items.length > 0) {
|
||||||
|
markdown += `\n---\n\n# ${categoryNames[category]}\n\n`;
|
||||||
|
|
||||||
|
for (const item of items) {
|
||||||
|
const typeLabel = category.slice(0, -1).replace(/([A-Z])/g, ' $1').trim();
|
||||||
|
markdown += `---\n\n## ${typeLabel}: ${item.name}\n\n`;
|
||||||
|
markdown += `**Fuente:** ${item.url}\n\n`;
|
||||||
|
|
||||||
|
if (item.error) {
|
||||||
|
markdown += `> ⚠️ ${item.content}\n\n`;
|
||||||
|
} else {
|
||||||
|
markdown += `${item.content}\n\n`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Agregar sección de ejemplos de uso
|
||||||
|
markdown += `
|
||||||
|
---
|
||||||
|
|
||||||
|
# Ejemplos de Uso Comunes
|
||||||
|
|
||||||
|
## Enviar Imagen
|
||||||
|
|
||||||
|
\`\`\`typescript
|
||||||
|
import { prepareWAMessageMedia, generateWAMessageFromContent } from '@whiskeysockets/baileys'
|
||||||
|
|
||||||
|
// Opción 1: Usando sendMessage directamente
|
||||||
|
await sock.sendMessage(jid, {
|
||||||
|
image: { url: './image.jpg' }, // o Buffer
|
||||||
|
caption: 'Descripción de la imagen',
|
||||||
|
mimetype: 'image/jpeg'
|
||||||
|
})
|
||||||
|
|
||||||
|
// Opción 2: Con prepareWAMessageMedia
|
||||||
|
const media = await prepareWAMessageMedia(
|
||||||
|
{ image: { url: './image.jpg' } },
|
||||||
|
{ upload: sock.waUploadToServer }
|
||||||
|
)
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
## Enviar Video
|
||||||
|
|
||||||
|
\`\`\`typescript
|
||||||
|
await sock.sendMessage(jid, {
|
||||||
|
video: { url: './video.mp4' },
|
||||||
|
caption: 'Mi video',
|
||||||
|
mimetype: 'video/mp4',
|
||||||
|
gifPlayback: false // true para GIFs
|
||||||
|
})
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
## Enviar Documento
|
||||||
|
|
||||||
|
\`\`\`typescript
|
||||||
|
await sock.sendMessage(jid, {
|
||||||
|
document: { url: './document.pdf' },
|
||||||
|
mimetype: 'application/pdf',
|
||||||
|
fileName: 'documento.pdf',
|
||||||
|
caption: 'Documento importante'
|
||||||
|
})
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
## Enviar Audio
|
||||||
|
|
||||||
|
\`\`\`typescript
|
||||||
|
// Audio normal
|
||||||
|
await sock.sendMessage(jid, {
|
||||||
|
audio: { url: './audio.mp3' },
|
||||||
|
mimetype: 'audio/mp4'
|
||||||
|
})
|
||||||
|
|
||||||
|
// Nota de voz (PTT)
|
||||||
|
await sock.sendMessage(jid, {
|
||||||
|
audio: { url: './voice.ogg' },
|
||||||
|
mimetype: 'audio/ogg; codecs=opus',
|
||||||
|
ptt: true // Push To Talk = nota de voz
|
||||||
|
})
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
## Enviar Contacto
|
||||||
|
|
||||||
|
\`\`\`typescript
|
||||||
|
// Un contacto
|
||||||
|
await sock.sendMessage(jid, {
|
||||||
|
contacts: {
|
||||||
|
displayName: 'Juan Pérez',
|
||||||
|
contacts: [{
|
||||||
|
vcard: \`BEGIN:VCARD
|
||||||
|
VERSION:3.0
|
||||||
|
FN:Juan Pérez
|
||||||
|
TEL;type=CELL;waid=1234567890:+1234567890
|
||||||
|
END:VCARD\`
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Múltiples contactos
|
||||||
|
await sock.sendMessage(jid, {
|
||||||
|
contacts: {
|
||||||
|
displayName: 'Mis Contactos',
|
||||||
|
contacts: [
|
||||||
|
{ vcard: '...' },
|
||||||
|
{ vcard: '...' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
## Enviar Ubicación
|
||||||
|
|
||||||
|
\`\`\`typescript
|
||||||
|
await sock.sendMessage(jid, {
|
||||||
|
location: {
|
||||||
|
degreesLatitude: 24.121231,
|
||||||
|
degreesLongitude: 55.1121221
|
||||||
|
}
|
||||||
|
})
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
## Enviar Encuesta (Poll)
|
||||||
|
|
||||||
|
\`\`\`typescript
|
||||||
|
await sock.sendMessage(jid, {
|
||||||
|
poll: {
|
||||||
|
name: '¿Cuál es tu color favorito?',
|
||||||
|
values: ['Rojo', 'Azul', 'Verde', 'Amarillo'],
|
||||||
|
selectableCount: 1 // Cantidad de opciones seleccionables
|
||||||
|
}
|
||||||
|
})
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
## Enviar con Quoted (Respuesta)
|
||||||
|
|
||||||
|
\`\`\`typescript
|
||||||
|
// El 'quoted' debe ser el mensaje original completo
|
||||||
|
await sock.sendMessage(jid,
|
||||||
|
{ text: 'Esta es una respuesta' },
|
||||||
|
{ quoted: originalMessage }
|
||||||
|
)
|
||||||
|
|
||||||
|
// También funciona con media
|
||||||
|
await sock.sendMessage(jid,
|
||||||
|
{ image: { url: './image.jpg' }, caption: 'Respuesta con imagen' },
|
||||||
|
{ quoted: originalMessage }
|
||||||
|
)
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Guardar archivo
|
||||||
|
const fs = await import('fs');
|
||||||
|
const outputPath = './docs/baileys-media-messaging.md';
|
||||||
|
fs.writeFileSync(outputPath, markdown);
|
||||||
|
|
||||||
|
console.log(`\n✅ Documentación generada exitosamente en: ${outputPath}`);
|
||||||
|
console.log(` Total elementos: ${Object.values(results).flat().length}`);
|
||||||
|
console.log(` - Type Aliases: ${results.typeAliases.length}`);
|
||||||
|
console.log(` - Functions: ${results.functions.length}`);
|
||||||
|
console.log(` - Variables: ${results.variables.length}`);
|
||||||
|
console.log(` - Interfaces: ${results.interfaces.length}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch(console.error);
|
||||||
Reference in New Issue
Block a user