Docs: Script para scrapear documentacion de Baileys API
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m3s
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m3s
- Script en scripts/scrape-baileys-docs.ts - Genera docs/baileys-api-reference.md con 6433 lineas - 79 secciones: interfaces, types, functions, variables, enums - Referencia completa para desarrollo de mensajes
This commit is contained in:
94
app/components/debug/BlocklistSection.vue
Normal file
94
app/components/debug/BlocklistSection.vue
Normal file
@@ -0,0 +1,94 @@
|
||||
<template>
|
||||
<div class="space-y-6 p-4">
|
||||
<!-- Fetch Blocklist -->
|
||||
<div class="space-y-4">
|
||||
<h3 class="text-lg font-medium text-[var(--wa-text)]">Obtener Lista de Bloqueados</h3>
|
||||
<UButton
|
||||
:loading="loadingFetch"
|
||||
:disabled="!instanceId"
|
||||
@click="fetchBlocklist"
|
||||
>
|
||||
Obtener Blocklist
|
||||
</UButton>
|
||||
</div>
|
||||
|
||||
<hr class="border-[var(--wa-border)]" />
|
||||
|
||||
<!-- Block/Unblock -->
|
||||
<div class="space-y-4">
|
||||
<h3 class="text-lg font-medium text-[var(--wa-text)]">Bloquear / Desbloquear</h3>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<UInput
|
||||
v-model="jid"
|
||||
placeholder="JID (ej: 5491155551234@s.whatsapp.net)"
|
||||
class="col-span-2"
|
||||
/>
|
||||
<USelectMenu
|
||||
v-model="action"
|
||||
:items="actionOptions"
|
||||
placeholder="Accion"
|
||||
/>
|
||||
</div>
|
||||
<UButton
|
||||
:loading="loadingUpdate"
|
||||
:disabled="!instanceId || !jid || !action"
|
||||
@click="updateBlockStatus"
|
||||
>
|
||||
Ejecutar
|
||||
</UButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{
|
||||
instanceId: string | null
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'response', data: any): void
|
||||
}>()
|
||||
|
||||
const jid = ref('')
|
||||
const action = ref<{ label: string; value: string } | null>(null)
|
||||
const loadingFetch = ref(false)
|
||||
const loadingUpdate = ref(false)
|
||||
|
||||
const actionOptions = [
|
||||
{ label: 'Bloquear', value: 'block' },
|
||||
{ label: 'Desbloquear', value: 'unblock' },
|
||||
]
|
||||
|
||||
const fetchBlocklist = async () => {
|
||||
loadingFetch.value = true
|
||||
try {
|
||||
const result = await $fetch(`/api/debug/blocklist?instanceId=${props.instanceId}`)
|
||||
emit('response', result)
|
||||
} catch (error: any) {
|
||||
emit('response', { success: false, error: error.data?.message || error.message })
|
||||
} finally {
|
||||
loadingFetch.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const updateBlockStatus = async () => {
|
||||
if (!action.value) return
|
||||
|
||||
loadingUpdate.value = true
|
||||
try {
|
||||
const result = await $fetch('/api/debug/blocklist/update', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
instanceId: props.instanceId,
|
||||
jid: jid.value,
|
||||
action: action.value.value
|
||||
}
|
||||
})
|
||||
emit('response', result)
|
||||
} catch (error: any) {
|
||||
emit('response', { success: false, error: error.data?.message || error.message })
|
||||
} finally {
|
||||
loadingUpdate.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
131
app/components/debug/ChatSection.vue
Normal file
131
app/components/debug/ChatSection.vue
Normal file
@@ -0,0 +1,131 @@
|
||||
<template>
|
||||
<div class="space-y-6 p-4">
|
||||
<!-- Chat Modify -->
|
||||
<div class="space-y-4">
|
||||
<h3 class="text-lg font-medium text-[var(--wa-text)]">Modificar Chat</h3>
|
||||
<p class="text-sm text-[var(--wa-text-muted)]">
|
||||
Modifica el estado de un chat (archivar, silenciar, marcar como leido, fijar).
|
||||
</p>
|
||||
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<UInput
|
||||
v-model="jid"
|
||||
placeholder="JID del chat"
|
||||
class="col-span-2"
|
||||
/>
|
||||
<USelectMenu
|
||||
v-model="modificationType"
|
||||
:items="modificationTypes"
|
||||
placeholder="Tipo de modificacion"
|
||||
/>
|
||||
<template v-if="modificationType?.value === 'mute'">
|
||||
<UInput
|
||||
v-model.number="muteTimestamp"
|
||||
type="number"
|
||||
placeholder="Timestamp de expiracion (0 = unmute)"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<USelectMenu
|
||||
v-model="boolValue"
|
||||
:items="boolOptions"
|
||||
placeholder="Valor"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div v-if="requiresLastMessages" class="space-y-2">
|
||||
<p class="text-sm text-[var(--wa-text-muted)]">Last Messages (JSON array, requerido para archive/markRead):</p>
|
||||
<UTextarea
|
||||
v-model="lastMessagesJson"
|
||||
placeholder='[{"key": {"remoteJid": "...", "id": "..."}, "messageTimestamp": 123456}]'
|
||||
:rows="3"
|
||||
class="font-mono text-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<UButton
|
||||
:loading="loading"
|
||||
:disabled="!instanceId || !jid || !modificationType"
|
||||
@click="modifyChat"
|
||||
>
|
||||
Modificar Chat
|
||||
</UButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{
|
||||
instanceId: string | null
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'response', data: any): void
|
||||
}>()
|
||||
|
||||
const jid = ref('')
|
||||
const modificationType = ref<{ label: string; value: string } | null>(null)
|
||||
const boolValue = ref<{ label: string; value: boolean } | null>(null)
|
||||
const muteTimestamp = ref<number>(0)
|
||||
const lastMessagesJson = ref('')
|
||||
const loading = ref(false)
|
||||
|
||||
const modificationTypes = [
|
||||
{ label: 'Archivar', value: 'archive' },
|
||||
{ label: 'Silenciar', value: 'mute' },
|
||||
{ label: 'Marcar Leido', value: 'markRead' },
|
||||
{ label: 'Fijar', value: 'pin' },
|
||||
]
|
||||
|
||||
const boolOptions = [
|
||||
{ label: 'Activar (true)', value: true },
|
||||
{ label: 'Desactivar (false)', value: false },
|
||||
]
|
||||
|
||||
const requiresLastMessages = computed(() =>
|
||||
modificationType.value?.value === 'archive' || modificationType.value?.value === 'markRead'
|
||||
)
|
||||
|
||||
const modifyChat = async () => {
|
||||
if (!modificationType.value) return
|
||||
|
||||
loading.value = true
|
||||
try {
|
||||
let value: boolean | number | null
|
||||
let lastMessages: any[] = []
|
||||
|
||||
if (modificationType.value.value === 'mute') {
|
||||
value = muteTimestamp.value || null
|
||||
} else {
|
||||
value = boolValue.value?.value ?? false
|
||||
}
|
||||
|
||||
if (requiresLastMessages.value && lastMessagesJson.value.trim()) {
|
||||
try {
|
||||
lastMessages = JSON.parse(lastMessagesJson.value)
|
||||
} catch {
|
||||
emit('response', { success: false, error: 'Invalid JSON for lastMessages' })
|
||||
loading.value = false
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const result = await $fetch('/api/debug/chat/modify', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
instanceId: props.instanceId,
|
||||
jid: jid.value,
|
||||
type: modificationType.value.value,
|
||||
value,
|
||||
lastMessages
|
||||
}
|
||||
})
|
||||
emit('response', result)
|
||||
} catch (error: any) {
|
||||
emit('response', { success: false, error: error.data?.message || error.message })
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
291
app/components/debug/GroupsSection.vue
Normal file
291
app/components/debug/GroupsSection.vue
Normal file
@@ -0,0 +1,291 @@
|
||||
<template>
|
||||
<div class="space-y-6 p-4">
|
||||
<!-- Get Metadata -->
|
||||
<div class="space-y-4">
|
||||
<h3 class="text-lg font-medium text-[var(--wa-text)]">Obtener Metadata del Grupo</h3>
|
||||
<div class="flex gap-4">
|
||||
<UInput
|
||||
v-model="metadataJid"
|
||||
placeholder="Group JID (ej: 123456789@g.us)"
|
||||
class="flex-1"
|
||||
/>
|
||||
<UButton
|
||||
:loading="loadingMetadata"
|
||||
:disabled="!instanceId || !metadataJid"
|
||||
@click="getMetadata"
|
||||
>
|
||||
Obtener
|
||||
</UButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="border-[var(--wa-border)]" />
|
||||
|
||||
<!-- Get Invite Code -->
|
||||
<div class="space-y-4">
|
||||
<h3 class="text-lg font-medium text-[var(--wa-text)]">Obtener Codigo de Invitacion</h3>
|
||||
<div class="flex gap-4">
|
||||
<UInput
|
||||
v-model="inviteJid"
|
||||
placeholder="Group JID"
|
||||
class="flex-1"
|
||||
/>
|
||||
<UButton
|
||||
:loading="loadingInvite"
|
||||
:disabled="!instanceId || !inviteJid"
|
||||
@click="getInviteCode"
|
||||
>
|
||||
Obtener
|
||||
</UButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="border-[var(--wa-border)]" />
|
||||
|
||||
<!-- Create Group -->
|
||||
<div class="space-y-4">
|
||||
<h3 class="text-lg font-medium text-[var(--wa-text)]">Crear Grupo</h3>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<UInput
|
||||
v-model="groupName"
|
||||
placeholder="Nombre del grupo"
|
||||
/>
|
||||
<UInput
|
||||
v-model="groupParticipants"
|
||||
placeholder="Participantes (separados por coma)"
|
||||
/>
|
||||
</div>
|
||||
<UButton
|
||||
:loading="loadingCreate"
|
||||
:disabled="!instanceId || !groupName || !groupParticipants"
|
||||
@click="createGroup"
|
||||
>
|
||||
Crear Grupo
|
||||
</UButton>
|
||||
</div>
|
||||
|
||||
<hr class="border-[var(--wa-border)]" />
|
||||
|
||||
<!-- Update Participants -->
|
||||
<div class="space-y-4">
|
||||
<h3 class="text-lg font-medium text-[var(--wa-text)]">Gestionar Participantes</h3>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<UInput
|
||||
v-model="participantsJid"
|
||||
placeholder="Group JID"
|
||||
/>
|
||||
<UInput
|
||||
v-model="participantsList"
|
||||
placeholder="Participantes (separados por coma)"
|
||||
/>
|
||||
<USelectMenu
|
||||
v-model="participantAction"
|
||||
:items="participantActions"
|
||||
placeholder="Accion"
|
||||
class="col-span-2"
|
||||
/>
|
||||
</div>
|
||||
<UButton
|
||||
:loading="loadingParticipants"
|
||||
:disabled="!instanceId || !participantsJid || !participantsList || !participantAction"
|
||||
@click="updateParticipants"
|
||||
>
|
||||
Ejecutar
|
||||
</UButton>
|
||||
</div>
|
||||
|
||||
<hr class="border-[var(--wa-border)]" />
|
||||
|
||||
<!-- Update Subject -->
|
||||
<div class="space-y-4">
|
||||
<h3 class="text-lg font-medium text-[var(--wa-text)]">Cambiar Nombre del Grupo</h3>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<UInput
|
||||
v-model="subjectJid"
|
||||
placeholder="Group JID"
|
||||
/>
|
||||
<UInput
|
||||
v-model="newSubject"
|
||||
placeholder="Nuevo nombre"
|
||||
/>
|
||||
</div>
|
||||
<UButton
|
||||
:loading="loadingSubject"
|
||||
:disabled="!instanceId || !subjectJid || !newSubject"
|
||||
@click="updateSubject"
|
||||
>
|
||||
Actualizar Nombre
|
||||
</UButton>
|
||||
</div>
|
||||
|
||||
<hr class="border-[var(--wa-border)]" />
|
||||
|
||||
<!-- Update Description -->
|
||||
<div class="space-y-4">
|
||||
<h3 class="text-lg font-medium text-[var(--wa-text)]">Cambiar Descripcion del Grupo</h3>
|
||||
<div class="grid grid-cols-1 gap-4">
|
||||
<UInput
|
||||
v-model="descriptionJid"
|
||||
placeholder="Group JID"
|
||||
/>
|
||||
<UTextarea
|
||||
v-model="newDescription"
|
||||
placeholder="Nueva descripcion"
|
||||
:rows="3"
|
||||
/>
|
||||
</div>
|
||||
<UButton
|
||||
:loading="loadingDescription"
|
||||
:disabled="!instanceId || !descriptionJid"
|
||||
@click="updateDescription"
|
||||
>
|
||||
Actualizar Descripcion
|
||||
</UButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{
|
||||
instanceId: string | null
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'response', data: any): void
|
||||
}>()
|
||||
|
||||
// Metadata
|
||||
const metadataJid = ref('')
|
||||
const loadingMetadata = ref(false)
|
||||
|
||||
// Invite
|
||||
const inviteJid = ref('')
|
||||
const loadingInvite = ref(false)
|
||||
|
||||
// Create
|
||||
const groupName = ref('')
|
||||
const groupParticipants = ref('')
|
||||
const loadingCreate = ref(false)
|
||||
|
||||
// Participants
|
||||
const participantsJid = ref('')
|
||||
const participantsList = ref('')
|
||||
const participantAction = ref<{ label: string; value: string } | null>(null)
|
||||
const loadingParticipants = ref(false)
|
||||
|
||||
// Subject
|
||||
const subjectJid = ref('')
|
||||
const newSubject = ref('')
|
||||
const loadingSubject = ref(false)
|
||||
|
||||
// Description
|
||||
const descriptionJid = ref('')
|
||||
const newDescription = ref('')
|
||||
const loadingDescription = ref(false)
|
||||
|
||||
const participantActions = [
|
||||
{ label: 'Agregar', value: 'add' },
|
||||
{ label: 'Remover', value: 'remove' },
|
||||
{ label: 'Promover a Admin', value: 'promote' },
|
||||
{ label: 'Degradar a Miembro', value: 'demote' },
|
||||
]
|
||||
|
||||
const getMetadata = async () => {
|
||||
loadingMetadata.value = true
|
||||
try {
|
||||
const result = await $fetch('/api/debug/groups/metadata', {
|
||||
method: 'POST',
|
||||
body: { instanceId: props.instanceId, jid: metadataJid.value }
|
||||
})
|
||||
emit('response', result)
|
||||
} catch (error: any) {
|
||||
emit('response', { success: false, error: error.data?.message || error.message })
|
||||
} finally {
|
||||
loadingMetadata.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const getInviteCode = async () => {
|
||||
loadingInvite.value = true
|
||||
try {
|
||||
const result = await $fetch('/api/debug/groups/invite-code', {
|
||||
method: 'POST',
|
||||
body: { instanceId: props.instanceId, jid: inviteJid.value }
|
||||
})
|
||||
emit('response', result)
|
||||
} catch (error: any) {
|
||||
emit('response', { success: false, error: error.data?.message || error.message })
|
||||
} finally {
|
||||
loadingInvite.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const createGroup = async () => {
|
||||
loadingCreate.value = true
|
||||
try {
|
||||
const participants = groupParticipants.value.split(',').map(p => p.trim()).filter(Boolean)
|
||||
const result = await $fetch('/api/debug/groups/create', {
|
||||
method: 'POST',
|
||||
body: { instanceId: props.instanceId, name: groupName.value, participants }
|
||||
})
|
||||
emit('response', result)
|
||||
} catch (error: any) {
|
||||
emit('response', { success: false, error: error.data?.message || error.message })
|
||||
} finally {
|
||||
loadingCreate.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const updateParticipants = async () => {
|
||||
if (!participantAction.value) return
|
||||
|
||||
loadingParticipants.value = true
|
||||
try {
|
||||
const participants = participantsList.value.split(',').map(p => p.trim()).filter(Boolean)
|
||||
const result = await $fetch('/api/debug/groups/participants', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
instanceId: props.instanceId,
|
||||
jid: participantsJid.value,
|
||||
participants,
|
||||
action: participantAction.value.value
|
||||
}
|
||||
})
|
||||
emit('response', result)
|
||||
} catch (error: any) {
|
||||
emit('response', { success: false, error: error.data?.message || error.message })
|
||||
} finally {
|
||||
loadingParticipants.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const updateSubject = async () => {
|
||||
loadingSubject.value = true
|
||||
try {
|
||||
const result = await $fetch('/api/debug/groups/subject', {
|
||||
method: 'POST',
|
||||
body: { instanceId: props.instanceId, jid: subjectJid.value, subject: newSubject.value }
|
||||
})
|
||||
emit('response', result)
|
||||
} catch (error: any) {
|
||||
emit('response', { success: false, error: error.data?.message || error.message })
|
||||
} finally {
|
||||
loadingSubject.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const updateDescription = async () => {
|
||||
loadingDescription.value = true
|
||||
try {
|
||||
const result = await $fetch('/api/debug/groups/description', {
|
||||
method: 'POST',
|
||||
body: { instanceId: props.instanceId, jid: descriptionJid.value, description: newDescription.value }
|
||||
})
|
||||
emit('response', result)
|
||||
} catch (error: any) {
|
||||
emit('response', { success: false, error: error.data?.message || error.message })
|
||||
} finally {
|
||||
loadingDescription.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
87
app/components/debug/HistorySection.vue
Normal file
87
app/components/debug/HistorySection.vue
Normal file
@@ -0,0 +1,87 @@
|
||||
<template>
|
||||
<div class="space-y-6 p-4">
|
||||
<!-- Fetch Message History -->
|
||||
<div class="space-y-4">
|
||||
<h3 class="text-lg font-medium text-[var(--wa-text)]">Solicitar Historial de Mensajes</h3>
|
||||
<p class="text-sm text-[var(--wa-text-muted)]">
|
||||
Solicita mensajes adicionales del historial. Los resultados llegaran via el evento messaging-history.set.
|
||||
</p>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<UInput
|
||||
v-model.number="count"
|
||||
type="number"
|
||||
placeholder="Cantidad de mensajes"
|
||||
:min="1"
|
||||
:max="1000"
|
||||
/>
|
||||
<UInput
|
||||
v-model.number="oldestMsgTimestamp"
|
||||
type="number"
|
||||
placeholder="Timestamp mas antiguo (opcional)"
|
||||
/>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<p class="text-sm text-[var(--wa-text-muted)]">Oldest Message Key (opcional, JSON):</p>
|
||||
<UTextarea
|
||||
v-model="oldestMsgKeyJson"
|
||||
placeholder='{"remoteJid": "...", "id": "...", "fromMe": false}'
|
||||
:rows="3"
|
||||
class="font-mono text-sm"
|
||||
/>
|
||||
</div>
|
||||
<UButton
|
||||
:loading="loading"
|
||||
:disabled="!instanceId || !count"
|
||||
@click="fetchHistory"
|
||||
>
|
||||
Solicitar Historial
|
||||
</UButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{
|
||||
instanceId: string | null
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'response', data: any): void
|
||||
}>()
|
||||
|
||||
const count = ref<number>(50)
|
||||
const oldestMsgTimestamp = ref<number | null>(null)
|
||||
const oldestMsgKeyJson = ref('')
|
||||
const loading = ref(false)
|
||||
|
||||
const fetchHistory = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
let oldestMsgKey = undefined
|
||||
if (oldestMsgKeyJson.value.trim()) {
|
||||
try {
|
||||
oldestMsgKey = JSON.parse(oldestMsgKeyJson.value)
|
||||
} catch {
|
||||
emit('response', { success: false, error: 'Invalid JSON for oldestMsgKey' })
|
||||
loading.value = false
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const result = await $fetch('/api/debug/history/fetch', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
instanceId: props.instanceId,
|
||||
count: count.value,
|
||||
oldestMsgKey,
|
||||
oldestMsgTimestamp: oldestMsgTimestamp.value || undefined
|
||||
}
|
||||
})
|
||||
emit('response', result)
|
||||
} catch (error: any) {
|
||||
emit('response', { success: false, error: error.data?.message || error.message })
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
95
app/components/debug/MediaSection.vue
Normal file
95
app/components/debug/MediaSection.vue
Normal file
@@ -0,0 +1,95 @@
|
||||
<template>
|
||||
<div class="space-y-6 p-4">
|
||||
<!-- Update Media Message -->
|
||||
<div class="space-y-4">
|
||||
<h3 class="text-lg font-medium text-[var(--wa-text)]">Actualizar Mensaje de Media</h3>
|
||||
<p class="text-sm text-[var(--wa-text-muted)]">
|
||||
Actualiza un mensaje de media expirado. Proporciona el objeto proto.IWebMessageInfo completo.
|
||||
</p>
|
||||
|
||||
<div class="space-y-2">
|
||||
<p class="text-sm text-[var(--wa-text-muted)]">Mensaje (JSON proto.IWebMessageInfo):</p>
|
||||
<UTextarea
|
||||
v-model="messageJson"
|
||||
placeholder='{
|
||||
"key": {
|
||||
"remoteJid": "...",
|
||||
"fromMe": false,
|
||||
"id": "..."
|
||||
},
|
||||
"message": {
|
||||
"imageMessage": {
|
||||
"url": "...",
|
||||
"mimetype": "image/jpeg",
|
||||
...
|
||||
}
|
||||
},
|
||||
"messageTimestamp": 123456789
|
||||
}'
|
||||
:rows="12"
|
||||
class="font-mono text-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<UButton
|
||||
:loading="loading"
|
||||
:disabled="!instanceId || !messageJson"
|
||||
@click="updateMedia"
|
||||
>
|
||||
Actualizar Media
|
||||
</UButton>
|
||||
</div>
|
||||
|
||||
<hr class="border-[var(--wa-border)]" />
|
||||
|
||||
<!-- Help -->
|
||||
<div class="space-y-2">
|
||||
<h4 class="text-md font-medium text-[var(--wa-text)]">Ayuda</h4>
|
||||
<p class="text-sm text-[var(--wa-text-muted)]">
|
||||
Esta funcion se usa para recargar media de mensajes cuyo contenido ha expirado.
|
||||
Necesitas proporcionar el mensaje original completo (puedes obtenerlo de la base de datos
|
||||
en la columna raw_message de la tabla messages).
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{
|
||||
instanceId: string | null
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'response', data: any): void
|
||||
}>()
|
||||
|
||||
const messageJson = ref('')
|
||||
const loading = ref(false)
|
||||
|
||||
const updateMedia = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
let message: any
|
||||
try {
|
||||
message = JSON.parse(messageJson.value)
|
||||
} catch {
|
||||
emit('response', { success: false, error: 'Invalid JSON for message' })
|
||||
loading.value = false
|
||||
return
|
||||
}
|
||||
|
||||
const result = await $fetch('/api/debug/media/update', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
instanceId: props.instanceId,
|
||||
message
|
||||
}
|
||||
})
|
||||
emit('response', result)
|
||||
} catch (error: any) {
|
||||
emit('response', { success: false, error: error.data?.message || error.message })
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
124
app/components/debug/PrivacySection.vue
Normal file
124
app/components/debug/PrivacySection.vue
Normal file
@@ -0,0 +1,124 @@
|
||||
<template>
|
||||
<div class="space-y-6 p-4">
|
||||
<!-- Fetch Privacy Settings -->
|
||||
<div class="space-y-4">
|
||||
<h3 class="text-lg font-medium text-[var(--wa-text)]">Obtener Configuracion de Privacidad</h3>
|
||||
<UButton
|
||||
:loading="loadingFetch"
|
||||
:disabled="!instanceId"
|
||||
@click="fetchPrivacy"
|
||||
>
|
||||
Obtener Configuracion
|
||||
</UButton>
|
||||
</div>
|
||||
|
||||
<hr class="border-[var(--wa-border)]" />
|
||||
|
||||
<!-- Update Privacy Setting -->
|
||||
<div class="space-y-4">
|
||||
<h3 class="text-lg font-medium text-[var(--wa-text)]">Actualizar Configuracion</h3>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<USelectMenu
|
||||
v-model="setting"
|
||||
:items="settingOptions"
|
||||
placeholder="Configuracion"
|
||||
/>
|
||||
<USelectMenu
|
||||
v-model="value"
|
||||
:items="valueOptions"
|
||||
placeholder="Valor"
|
||||
/>
|
||||
</div>
|
||||
<UButton
|
||||
:loading="loadingUpdate"
|
||||
:disabled="!instanceId || !setting || !value"
|
||||
@click="updatePrivacy"
|
||||
>
|
||||
Actualizar
|
||||
</UButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{
|
||||
instanceId: string | null
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'response', data: any): void
|
||||
}>()
|
||||
|
||||
const setting = ref<{ label: string; value: string } | null>(null)
|
||||
const value = ref<{ label: string; value: string } | null>(null)
|
||||
const loadingFetch = ref(false)
|
||||
const loadingUpdate = ref(false)
|
||||
|
||||
const settingOptions = [
|
||||
{ label: 'Last Seen', value: 'lastSeen' },
|
||||
{ label: 'Online', value: 'online' },
|
||||
{ label: 'Profile Picture', value: 'profilePicture' },
|
||||
{ label: 'Status', value: 'status' },
|
||||
{ label: 'Groups Add', value: 'groupsAdd' },
|
||||
{ label: 'Read Receipts', value: 'readReceipts' },
|
||||
]
|
||||
|
||||
const valueOptions = computed(() => {
|
||||
if (setting.value?.value === 'online') {
|
||||
return [
|
||||
{ label: 'all', value: 'all' },
|
||||
{ label: 'match_last_seen', value: 'match_last_seen' },
|
||||
]
|
||||
}
|
||||
if (setting.value?.value === 'readReceipts') {
|
||||
return [
|
||||
{ label: 'all', value: 'all' },
|
||||
{ label: 'none', value: 'none' },
|
||||
]
|
||||
}
|
||||
return [
|
||||
{ label: 'all', value: 'all' },
|
||||
{ label: 'contacts', value: 'contacts' },
|
||||
{ label: 'contact_blacklist', value: 'contact_blacklist' },
|
||||
{ label: 'none', value: 'none' },
|
||||
]
|
||||
})
|
||||
|
||||
// Reset value when setting changes
|
||||
watch(setting, () => {
|
||||
value.value = null
|
||||
})
|
||||
|
||||
const fetchPrivacy = async () => {
|
||||
loadingFetch.value = true
|
||||
try {
|
||||
const result = await $fetch(`/api/debug/privacy?instanceId=${props.instanceId}`)
|
||||
emit('response', result)
|
||||
} catch (error: any) {
|
||||
emit('response', { success: false, error: error.data?.message || error.message })
|
||||
} finally {
|
||||
loadingFetch.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const updatePrivacy = async () => {
|
||||
if (!setting.value || !value.value) return
|
||||
|
||||
loadingUpdate.value = true
|
||||
try {
|
||||
const result = await $fetch('/api/debug/privacy/update', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
instanceId: props.instanceId,
|
||||
setting: setting.value.value,
|
||||
value: value.value.value
|
||||
}
|
||||
})
|
||||
emit('response', result)
|
||||
} catch (error: any) {
|
||||
emit('response', { success: false, error: error.data?.message || error.message })
|
||||
} finally {
|
||||
loadingUpdate.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -85,6 +85,7 @@ const menuItems = [
|
||||
{ to: '/', label: 'Instancias', icon: 'i-lucide-smartphone' },
|
||||
{ to: '/messages', label: 'Mensajes', icon: 'i-lucide-message-square' },
|
||||
{ to: '/webhooks', label: 'Webhooks', icon: 'i-lucide-webhook' },
|
||||
{ to: '/debug', label: 'Debug', icon: 'i-lucide-bug' },
|
||||
]
|
||||
|
||||
// Close sidebar on route change (mobile)
|
||||
|
||||
141
app/pages/debug/index.vue
Normal file
141
app/pages/debug/index.vue
Normal file
@@ -0,0 +1,141 @@
|
||||
<template>
|
||||
<div class="space-y-6">
|
||||
<!-- Header -->
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 class="text-2xl font-bold text-[var(--wa-text)]">Debug</h1>
|
||||
<p class="text-[var(--wa-text-muted)]">Herramientas de depuracion para Baileys</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Warning Banner -->
|
||||
<div class="p-4 rounded-lg bg-yellow-900/20 border border-yellow-600/50">
|
||||
<div class="flex items-center gap-2 text-yellow-400">
|
||||
<UIcon name="i-lucide-alert-triangle" class="w-5 h-5" />
|
||||
<span class="font-medium">Modo Debug</span>
|
||||
</div>
|
||||
<p class="text-sm text-yellow-300/80 mt-1">
|
||||
Estas funciones ejecutan comandos raw de Baileys. Usar con precaucion.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Instance Selector -->
|
||||
<div class="flex items-center gap-4">
|
||||
<USelectMenu
|
||||
v-model="selectedInstance"
|
||||
:items="instanceOptions"
|
||||
placeholder="Seleccionar instancia conectada"
|
||||
class="w-64"
|
||||
/>
|
||||
<span v-if="!selectedInstance" class="text-sm text-[var(--wa-text-muted)]">
|
||||
Selecciona una instancia para usar las herramientas de debug
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Tabs -->
|
||||
<div v-if="selectedInstance" class="instance-card">
|
||||
<UTabs :items="tabs" class="w-full">
|
||||
<template #blocklist>
|
||||
<DebugBlocklistSection
|
||||
:instance-id="selectedInstance?.value"
|
||||
@response="handleResponse"
|
||||
/>
|
||||
</template>
|
||||
<template #privacy>
|
||||
<DebugPrivacySection
|
||||
:instance-id="selectedInstance?.value"
|
||||
@response="handleResponse"
|
||||
/>
|
||||
</template>
|
||||
<template #groups>
|
||||
<DebugGroupsSection
|
||||
:instance-id="selectedInstance?.value"
|
||||
@response="handleResponse"
|
||||
/>
|
||||
</template>
|
||||
<template #history>
|
||||
<DebugHistorySection
|
||||
:instance-id="selectedInstance?.value"
|
||||
@response="handleResponse"
|
||||
/>
|
||||
</template>
|
||||
<template #chat>
|
||||
<DebugChatSection
|
||||
:instance-id="selectedInstance?.value"
|
||||
@response="handleResponse"
|
||||
/>
|
||||
</template>
|
||||
<template #media>
|
||||
<DebugMediaSection
|
||||
:instance-id="selectedInstance?.value"
|
||||
@response="handleResponse"
|
||||
/>
|
||||
</template>
|
||||
</UTabs>
|
||||
</div>
|
||||
|
||||
<!-- Response Viewer -->
|
||||
<div v-if="lastResponse" class="instance-card p-4">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<span class="text-sm font-medium text-[var(--wa-text)]">Ultima Respuesta</span>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-xs text-[var(--wa-text-muted)]">{{ lastResponseTime }}</span>
|
||||
<UButton size="xs" variant="ghost" color="neutral" @click="lastResponse = null">
|
||||
Limpiar
|
||||
</UButton>
|
||||
</div>
|
||||
</div>
|
||||
<pre
|
||||
class="text-xs font-mono p-4 rounded overflow-auto max-h-96"
|
||||
:class="lastResponse.success ? 'text-green-400 bg-green-900/20' : 'text-red-400 bg-red-900/20'"
|
||||
>{{ JSON.stringify(lastResponse, null, 2) }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
definePageMeta({
|
||||
layout: 'dashboard',
|
||||
title: 'Debug',
|
||||
icon: 'i-lucide-bug'
|
||||
})
|
||||
|
||||
const { instances, fetchInstances } = useInstances()
|
||||
|
||||
const selectedInstance = ref<{ label: string; value: string } | null>(null)
|
||||
const lastResponse = ref<any>(null)
|
||||
const lastResponseTime = ref<string>('')
|
||||
|
||||
// Instance options for selector (only connected instances)
|
||||
const instanceOptions = computed(() =>
|
||||
instances.value
|
||||
.filter(i => i.status === 'connected')
|
||||
.map(i => ({ label: i.name, value: i.id }))
|
||||
)
|
||||
|
||||
// Auto-select first connected instance
|
||||
watch(instanceOptions, (opts) => {
|
||||
if (opts.length > 0 && !selectedInstance.value) {
|
||||
selectedInstance.value = opts[0]
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
const tabs = [
|
||||
{ label: 'Blocklist', value: 'blocklist', icon: 'i-lucide-ban' },
|
||||
{ label: 'Privacy', value: 'privacy', icon: 'i-lucide-shield' },
|
||||
{ label: 'Groups', value: 'groups', icon: 'i-lucide-users' },
|
||||
{ label: 'History', value: 'history', icon: 'i-lucide-history' },
|
||||
{ label: 'Chat', value: 'chat', icon: 'i-lucide-message-circle' },
|
||||
{ label: 'Media', value: 'media', icon: 'i-lucide-image' },
|
||||
]
|
||||
|
||||
const handleResponse = (response: any) => {
|
||||
lastResponse.value = response
|
||||
lastResponseTime.value = new Date().toLocaleTimeString()
|
||||
}
|
||||
|
||||
// Load instances on mount
|
||||
onMounted(() => {
|
||||
fetchInstances()
|
||||
})
|
||||
</script>
|
||||
6433
docs/baileys-api-reference.md
Normal file
6433
docs/baileys-api-reference.md
Normal file
File diff suppressed because it is too large
Load Diff
300
scripts/scrape-baileys-docs.ts
Normal file
300
scripts/scrape-baileys-docs.ts
Normal file
@@ -0,0 +1,300 @@
|
||||
/**
|
||||
* Script to scrape Baileys documentation from baileys.wiki
|
||||
* Creates a comprehensive markdown file for Claude Code reference
|
||||
*/
|
||||
|
||||
import * as fs from 'fs'
|
||||
|
||||
const BASE_URL = 'https://baileys.wiki/docs/api'
|
||||
|
||||
interface DocSection {
|
||||
name: string
|
||||
path: string
|
||||
type: 'interface' | 'type' | 'function' | 'variable' | 'class' | 'enum'
|
||||
}
|
||||
|
||||
// Relevant documentation sections to scrape
|
||||
const SECTIONS: DocSection[] = [
|
||||
// Interfaces
|
||||
{ name: 'Contact', path: '/interfaces/Contact', type: 'interface' },
|
||||
{ name: 'GroupMetadata', path: '/interfaces/GroupMetadata', type: 'interface' },
|
||||
{ name: 'GroupModificationResponse', path: '/interfaces/GroupModificationResponse', type: 'interface' },
|
||||
{ name: 'PresenceData', path: '/interfaces/PresenceData', type: 'interface' },
|
||||
{ name: 'BaileysEventEmitter', path: '/interfaces/BaileysEventEmitter', type: 'interface' },
|
||||
{ name: 'WAUrlInfo', path: '/interfaces/WAUrlInfo', type: 'interface' },
|
||||
{ name: 'RecentMessage', path: '/interfaces/RecentMessage', type: 'interface' },
|
||||
|
||||
// Type Aliases - Chat
|
||||
{ name: 'Chat', path: '/type-aliases/Chat', type: 'type' },
|
||||
{ name: 'ChatModification', path: '/type-aliases/ChatModification', type: 'type' },
|
||||
{ name: 'ChatUpdate', path: '/type-aliases/ChatUpdate', type: 'type' },
|
||||
{ name: 'ChatMutation', path: '/type-aliases/ChatMutation', type: 'type' },
|
||||
|
||||
// Type Aliases - Messages
|
||||
{ name: 'WAMessage', path: '/type-aliases/WAMessage', type: 'type' },
|
||||
{ name: 'WAMessageContent', path: '/type-aliases/WAMessageContent', type: 'type' },
|
||||
{ name: 'WAMessageKey', path: '/type-aliases/WAMessageKey', type: 'type' },
|
||||
{ name: 'WAMessageUpdate', path: '/type-aliases/WAMessageUpdate', type: 'type' },
|
||||
{ name: 'MessageType', path: '/type-aliases/MessageType', type: 'type' },
|
||||
{ name: 'MessageUpsertType', path: '/type-aliases/MessageUpsertType', type: 'type' },
|
||||
{ name: 'AnyMessageContent', path: '/type-aliases/AnyMessageContent', type: 'type' },
|
||||
{ name: 'AnyMediaMessageContent', path: '/type-aliases/AnyMediaMessageContent', type: 'type' },
|
||||
{ name: 'AnyRegularMessageContent', path: '/type-aliases/AnyRegularMessageContent', type: 'type' },
|
||||
{ name: 'MessageGenerationOptions', path: '/type-aliases/MessageGenerationOptions', type: 'type' },
|
||||
{ name: 'MessageContentGenerationOptions', path: '/type-aliases/MessageContentGenerationOptions', type: 'type' },
|
||||
{ name: 'MinimalMessage', path: '/type-aliases/MinimalMessage', type: 'type' },
|
||||
|
||||
// Type Aliases - Media
|
||||
{ name: 'MediaType', path: '/type-aliases/MediaType', type: 'type' },
|
||||
{ name: 'MediaDownloadOptions', path: '/type-aliases/MediaDownloadOptions', type: 'type' },
|
||||
{ name: 'WAMediaUpload', path: '/type-aliases/WAMediaUpload', type: 'type' },
|
||||
{ name: 'DownloadableMessage', path: '/type-aliases/DownloadableMessage', type: 'type' },
|
||||
{ name: 'MediaGenerationOptions', path: '/type-aliases/MediaGenerationOptions', type: 'type' },
|
||||
|
||||
// Type Aliases - Groups
|
||||
{ name: 'GroupParticipant', path: '/type-aliases/GroupParticipant', type: 'type' },
|
||||
{ name: 'GroupInviteInfo', path: '/type-aliases/GroupInviteInfo', type: 'type' },
|
||||
{ name: 'ParticipantAction', path: '/type-aliases/ParticipantAction', type: 'type' },
|
||||
|
||||
// Type Aliases - Presence & Status
|
||||
{ name: 'WAPresence', path: '/type-aliases/WAPresence', type: 'type' },
|
||||
{ name: 'ConnectionState', path: '/type-aliases/ConnectionState', type: 'type' },
|
||||
|
||||
// Type Aliases - Events
|
||||
{ name: 'BaileysEventMap', path: '/type-aliases/BaileysEventMap', type: 'type' },
|
||||
{ name: 'BaileysEvent', path: '/type-aliases/BaileysEvent', type: 'type' },
|
||||
|
||||
// Type Aliases - Auth
|
||||
{ name: 'AuthenticationCreds', path: '/type-aliases/AuthenticationCreds', type: 'type' },
|
||||
{ name: 'AuthenticationState', path: '/type-aliases/AuthenticationState', type: 'type' },
|
||||
|
||||
// Type Aliases - Socket
|
||||
{ name: 'WASocket', path: '/type-aliases/WASocket', type: 'type' },
|
||||
{ name: 'SocketConfig', path: '/type-aliases/SocketConfig', type: 'type' },
|
||||
{ name: 'UserFacingSocketConfig', path: '/type-aliases/UserFacingSocketConfig', type: 'type' },
|
||||
|
||||
// Functions - Messages
|
||||
{ name: 'generateWAMessage', path: '/functions/generateWAMessage', type: 'function' },
|
||||
{ name: 'generateWAMessageContent', path: '/functions/generateWAMessageContent', type: 'function' },
|
||||
{ name: 'generateWAMessageFromContent', path: '/functions/generateWAMessageFromContent', type: 'function' },
|
||||
{ name: 'extractMessageContent', path: '/functions/extractMessageContent', type: 'function' },
|
||||
{ name: 'getContentType', path: '/functions/getContentType', type: 'function' },
|
||||
{ name: 'normalizeMessageContent', path: '/functions/normalizeMessageContent', type: 'function' },
|
||||
|
||||
// Functions - Media
|
||||
{ name: 'downloadMediaMessage', path: '/functions/downloadMediaMessage', type: 'function' },
|
||||
{ name: 'downloadContentFromMessage', path: '/functions/downloadContentFromMessage', type: 'function' },
|
||||
{ name: 'prepareWAMessageMedia', path: '/functions/prepareWAMessageMedia', type: 'function' },
|
||||
{ name: 'extractImageThumb', path: '/functions/extractImageThumb', type: 'function' },
|
||||
{ name: 'generateThumbnail', path: '/functions/generateThumbnail', type: 'function' },
|
||||
{ name: 'generateProfilePicture', path: '/functions/generateProfilePicture', type: 'function' },
|
||||
{ name: 'getMediaKeys', path: '/functions/getMediaKeys', type: 'function' },
|
||||
{ name: 'encryptedStream', path: '/functions/encryptedStream', type: 'function' },
|
||||
|
||||
// Functions - JID
|
||||
{ name: 'jidDecode', path: '/functions/jidDecode', type: 'function' },
|
||||
{ name: 'jidEncode', path: '/functions/jidEncode', type: 'function' },
|
||||
{ name: 'jidNormalizedUser', path: '/functions/jidNormalizedUser', type: 'function' },
|
||||
{ name: 'isJidGroup', path: '/functions/isJidGroup', type: 'function' },
|
||||
{ name: 'isJidBroadcast', path: '/functions/isJidBroadcast', type: 'function' },
|
||||
{ name: 'isJidStatusBroadcast', path: '/functions/isJidStatusBroadcast', type: 'function' },
|
||||
{ name: 'areJidsSameUser', path: '/functions/areJidsSameUser', type: 'function' },
|
||||
{ name: 'isLidUser', path: '/functions/isLidUser', type: 'function' },
|
||||
|
||||
// Functions - History
|
||||
{ name: 'downloadAndProcessHistorySyncNotification', path: '/functions/downloadAndProcessHistorySyncNotification', type: 'function' },
|
||||
{ name: 'processHistoryMessage', path: '/functions/processHistoryMessage', type: 'function' },
|
||||
{ name: 'getHistoryMsg', path: '/functions/getHistoryMsg', type: 'function' },
|
||||
|
||||
// Functions - Socket
|
||||
{ name: 'makeWASocket', path: '/functions/makeWASocket', type: 'function' },
|
||||
{ name: 'makeCacheableSignalKeyStore', path: '/functions/makeCacheableSignalKeyStore', type: 'function' },
|
||||
{ name: 'useMultiFileAuthState', path: '/functions/useMultiFileAuthState', type: 'function' },
|
||||
|
||||
// Functions - Utility
|
||||
{ name: 'delay', path: '/functions/delay', type: 'function' },
|
||||
{ name: 'toNumber', path: '/functions/toNumber', type: 'function' },
|
||||
{ name: 'toBuffer', path: '/functions/toBuffer', type: 'function' },
|
||||
{ name: 'unixTimestampSeconds', path: '/functions/unixTimestampSeconds', type: 'function' },
|
||||
|
||||
// Variables
|
||||
{ name: 'WAMessageStatus', path: '/variables/WAMessageStatus', type: 'variable' },
|
||||
{ name: 'WAMessageStubType', path: '/variables/WAMessageStubType', type: 'variable' },
|
||||
{ name: 'S_WHATSAPP_NET', path: '/variables/S_WHATSAPP_NET', type: 'variable' },
|
||||
{ name: 'Browsers', path: '/variables/Browsers', type: 'variable' },
|
||||
{ name: 'MEDIA_KEYS', path: '/variables/MEDIA_KEYS', type: 'variable' },
|
||||
{ name: 'DEFAULT_CONNECTION_CONFIG', path: '/variables/DEFAULT_CONNECTION_CONFIG', type: 'variable' },
|
||||
|
||||
// Enums
|
||||
{ name: 'DisconnectReason', path: '/enumerations/DisconnectReason', type: 'enum' },
|
||||
]
|
||||
|
||||
async function fetchPage(url: string): Promise<string> {
|
||||
const response = await fetch(url)
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch ${url}: ${response.status}`)
|
||||
}
|
||||
return response.text()
|
||||
}
|
||||
|
||||
function extractContent(html: string, name: string, type: string): string {
|
||||
// Remove script tags and style tags
|
||||
html = html.replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '')
|
||||
html = html.replace(/<style[^>]*>[\s\S]*?<\/style>/gi, '')
|
||||
html = html.replace(/<nav[^>]*>[\s\S]*?<\/nav>/gi, '')
|
||||
html = html.replace(/<footer[^>]*>[\s\S]*?<\/footer>/gi, '')
|
||||
html = html.replace(/<header[^>]*>[\s\S]*?<\/header>/gi, '')
|
||||
html = html.replace(/<aside[^>]*>[\s\S]*?<\/aside>/gi, '')
|
||||
|
||||
// Extract main/article content
|
||||
let mainMatch = html.match(/<main[^>]*>([\s\S]*?)<\/main>/i)
|
||||
if (!mainMatch) {
|
||||
mainMatch = html.match(/<article[^>]*>([\s\S]*?)<\/article>/i)
|
||||
}
|
||||
const content = mainMatch ? mainMatch[1] : html
|
||||
|
||||
// Convert HTML to markdown-like text
|
||||
let text = 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')
|
||||
// Paragraphs
|
||||
.replace(/<p[^>]*>([\s\S]*?)<\/p>/gi, '\n$1\n')
|
||||
// Links - keep only text for cleaner output
|
||||
.replace(/<a[^>]*>([\s\S]*?)<\/a>/gi, '$1')
|
||||
// Bold/Italic
|
||||
.replace(/<strong[^>]*>([\s\S]*?)<\/strong>/gi, '**$1**')
|
||||
.replace(/<em[^>]*>([\s\S]*?)<\/em>/gi, '*$1*')
|
||||
// Line breaks
|
||||
.replace(/<br\s*\/?>/gi, '\n')
|
||||
// Divs and spans
|
||||
.replace(/<div[^>]*>/gi, '\n')
|
||||
.replace(/<\/div>/gi, '\n')
|
||||
.replace(/<span[^>]*>/gi, '')
|
||||
.replace(/<\/span>/gi, '')
|
||||
// Tables (simplified)
|
||||
.replace(/<table[^>]*>/gi, '\n')
|
||||
.replace(/<\/table>/gi, '\n')
|
||||
.replace(/<tr[^>]*>/gi, '')
|
||||
.replace(/<\/tr>/gi, '\n')
|
||||
.replace(/<td[^>]*>([\s\S]*?)<\/td>/gi, '| $1 ')
|
||||
.replace(/<th[^>]*>([\s\S]*?)<\/th>/gi, '| **$1** ')
|
||||
// Remove remaining tags
|
||||
.replace(/<[^>]+>/g, '')
|
||||
// Decode HTML entities
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/&/g, '&')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, "'")
|
||||
.replace(/ /g, ' ')
|
||||
// Clean up whitespace
|
||||
.replace(/\n\s*\n\s*\n/g, '\n\n')
|
||||
.replace(/^\s+|\s+$/g, '')
|
||||
|
||||
return text
|
||||
}
|
||||
|
||||
async function scrapeSection(section: DocSection): Promise<string> {
|
||||
const url = `${BASE_URL}${section.path}`
|
||||
console.log(`Fetching ${section.name}...`)
|
||||
|
||||
try {
|
||||
const html = await fetchPage(url)
|
||||
const content = extractContent(html, section.name, section.type)
|
||||
|
||||
return `
|
||||
---
|
||||
|
||||
## ${section.type.charAt(0).toUpperCase() + section.type.slice(1)}: ${section.name}
|
||||
|
||||
**Source:** ${url}
|
||||
|
||||
${content}
|
||||
`
|
||||
} catch (error) {
|
||||
console.error(`Error fetching ${section.name}:`, (error as Error).message)
|
||||
return `
|
||||
---
|
||||
|
||||
## ${section.type.charAt(0).toUpperCase() + section.type.slice(1)}: ${section.name}
|
||||
|
||||
**Source:** ${url}
|
||||
|
||||
*Error: Could not fetch documentation*
|
||||
`
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('Starting Baileys documentation scrape...\n')
|
||||
|
||||
const markdown: string[] = [
|
||||
`# Baileys API Documentation Reference
|
||||
|
||||
> Auto-generated documentation for WhatsApp Nucleo development
|
||||
> Source: https://baileys.wiki
|
||||
> Generated: ${new Date().toISOString()}
|
||||
|
||||
This document contains the relevant Baileys API documentation for developing the WhatsApp Nucleo messaging features.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
### Interfaces
|
||||
${SECTIONS.filter(s => s.type === 'interface').map(s => `- [${s.name}](#interface-${s.name.toLowerCase()})`).join('\n')}
|
||||
|
||||
### Type Aliases
|
||||
${SECTIONS.filter(s => s.type === 'type').map(s => `- [${s.name}](#type-${s.name.toLowerCase()})`).join('\n')}
|
||||
|
||||
### Functions
|
||||
${SECTIONS.filter(s => s.type === 'function').map(s => `- [${s.name}](#function-${s.name.toLowerCase()})`).join('\n')}
|
||||
|
||||
### Variables
|
||||
${SECTIONS.filter(s => s.type === 'variable').map(s => `- [${s.name}](#variable-${s.name.toLowerCase()})`).join('\n')}
|
||||
|
||||
### Enumerations
|
||||
${SECTIONS.filter(s => s.type === 'enum').map(s => `- [${s.name}](#enum-${s.name.toLowerCase()})`).join('\n')}
|
||||
|
||||
`
|
||||
]
|
||||
|
||||
// Group sections by type
|
||||
const groupedSections = {
|
||||
interface: SECTIONS.filter(s => s.type === 'interface'),
|
||||
type: SECTIONS.filter(s => s.type === 'type'),
|
||||
function: SECTIONS.filter(s => s.type === 'function'),
|
||||
variable: SECTIONS.filter(s => s.type === 'variable'),
|
||||
enum: SECTIONS.filter(s => s.type === 'enum'),
|
||||
}
|
||||
|
||||
// Process each group
|
||||
for (const [type, sections] of Object.entries(groupedSections)) {
|
||||
markdown.push(`\n# ${type.charAt(0).toUpperCase() + type.slice(1)}s\n`)
|
||||
|
||||
for (const section of sections) {
|
||||
const content = await scrapeSection(section)
|
||||
markdown.push(content)
|
||||
|
||||
// Small delay to be nice to the server
|
||||
await new Promise(r => setTimeout(r, 300))
|
||||
}
|
||||
}
|
||||
|
||||
// Write to file
|
||||
const outputPath = './docs/baileys-api-reference.md'
|
||||
fs.writeFileSync(outputPath, markdown.join('\n'))
|
||||
|
||||
console.log(`\nDocumentation saved to ${outputPath}`)
|
||||
console.log(`Total sections: ${SECTIONS.length}`)
|
||||
}
|
||||
|
||||
main().catch(console.error)
|
||||
76
server/api/debug/chat/modify.post.ts
Normal file
76
server/api/debug/chat/modify.post.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* POST /api/debug/chat/modify
|
||||
* Modify chat state (archive, mute, mark read, pin)
|
||||
*/
|
||||
import { baileysManager } from '../../../services/baileys/manager'
|
||||
|
||||
type ModificationType = 'archive' | 'mute' | 'markRead' | 'pin'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const username = getHeader(event, 'x-authentik-username')
|
||||
if (!username) {
|
||||
throw createError({ statusCode: 401, message: 'Unauthorized' })
|
||||
}
|
||||
|
||||
const body = await readBody(event)
|
||||
const { instanceId, jid, type, value, lastMessages } = body as {
|
||||
instanceId: string
|
||||
jid: string
|
||||
type: ModificationType
|
||||
value: boolean | number | null
|
||||
lastMessages?: any[]
|
||||
}
|
||||
|
||||
if (!instanceId) {
|
||||
throw createError({ statusCode: 400, message: 'instanceId is required' })
|
||||
}
|
||||
|
||||
if (!jid) {
|
||||
throw createError({ statusCode: 400, message: 'jid is required' })
|
||||
}
|
||||
|
||||
const validTypes: ModificationType[] = ['archive', 'mute', 'markRead', 'pin']
|
||||
if (!type || !validTypes.includes(type)) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
message: `type must be one of: ${validTypes.join(', ')}`
|
||||
})
|
||||
}
|
||||
|
||||
if (value === undefined) {
|
||||
throw createError({ statusCode: 400, message: 'value is required' })
|
||||
}
|
||||
|
||||
const socket = baileysManager.getSocket(instanceId)
|
||||
if (!socket) {
|
||||
throw createError({ statusCode: 400, message: 'Instance not connected' })
|
||||
}
|
||||
|
||||
try {
|
||||
let modification: any
|
||||
|
||||
switch (type) {
|
||||
case 'archive':
|
||||
modification = { archive: value, lastMessages: lastMessages || [] }
|
||||
break
|
||||
case 'mute':
|
||||
// value should be timestamp for mute duration, null to unmute
|
||||
modification = { mute: value }
|
||||
break
|
||||
case 'markRead':
|
||||
modification = { markRead: value, lastMessages: lastMessages || [] }
|
||||
break
|
||||
case 'pin':
|
||||
modification = { pin: value }
|
||||
break
|
||||
}
|
||||
|
||||
await socket.chatModify(modification, jid)
|
||||
return { success: true, message: `Chat ${type} modified successfully` }
|
||||
} catch (error) {
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
message: `Failed to modify chat: ${(error as Error).message}`
|
||||
})
|
||||
}
|
||||
})
|
||||
42
server/api/debug/groups/create.post.ts
Normal file
42
server/api/debug/groups/create.post.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* POST /api/debug/groups/create
|
||||
* Create a new group
|
||||
*/
|
||||
import { baileysManager } from '../../../services/baileys/manager'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const username = getHeader(event, 'x-authentik-username')
|
||||
if (!username) {
|
||||
throw createError({ statusCode: 401, message: 'Unauthorized' })
|
||||
}
|
||||
|
||||
const body = await readBody(event)
|
||||
const { instanceId, name, participants } = body
|
||||
|
||||
if (!instanceId) {
|
||||
throw createError({ statusCode: 400, message: 'instanceId is required' })
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
throw createError({ statusCode: 400, message: 'name is required' })
|
||||
}
|
||||
|
||||
if (!participants || !Array.isArray(participants) || participants.length === 0) {
|
||||
throw createError({ statusCode: 400, message: 'participants array is required' })
|
||||
}
|
||||
|
||||
const socket = baileysManager.getSocket(instanceId)
|
||||
if (!socket) {
|
||||
throw createError({ statusCode: 400, message: 'Instance not connected' })
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await socket.groupCreate(name, participants)
|
||||
return { success: true, data: result }
|
||||
} catch (error) {
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
message: `Failed to create group: ${(error as Error).message}`
|
||||
})
|
||||
}
|
||||
})
|
||||
42
server/api/debug/groups/description.post.ts
Normal file
42
server/api/debug/groups/description.post.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* POST /api/debug/groups/description
|
||||
* Update group description
|
||||
*/
|
||||
import { baileysManager } from '../../../services/baileys/manager'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const username = getHeader(event, 'x-authentik-username')
|
||||
if (!username) {
|
||||
throw createError({ statusCode: 401, message: 'Unauthorized' })
|
||||
}
|
||||
|
||||
const body = await readBody(event)
|
||||
const { instanceId, jid, description } = body
|
||||
|
||||
if (!instanceId) {
|
||||
throw createError({ statusCode: 400, message: 'instanceId is required' })
|
||||
}
|
||||
|
||||
if (!jid) {
|
||||
throw createError({ statusCode: 400, message: 'jid is required' })
|
||||
}
|
||||
|
||||
if (description === undefined) {
|
||||
throw createError({ statusCode: 400, message: 'description is required' })
|
||||
}
|
||||
|
||||
const socket = baileysManager.getSocket(instanceId)
|
||||
if (!socket) {
|
||||
throw createError({ statusCode: 400, message: 'Instance not connected' })
|
||||
}
|
||||
|
||||
try {
|
||||
await socket.groupUpdateDescription(jid, description)
|
||||
return { success: true, message: 'Group description updated successfully' }
|
||||
} catch (error) {
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
message: `Failed to update group description: ${(error as Error).message}`
|
||||
})
|
||||
}
|
||||
})
|
||||
44
server/api/debug/groups/invite-code.post.ts
Normal file
44
server/api/debug/groups/invite-code.post.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* POST /api/debug/groups/invite-code
|
||||
* Get group invite code
|
||||
*/
|
||||
import { baileysManager } from '../../../services/baileys/manager'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const username = getHeader(event, 'x-authentik-username')
|
||||
if (!username) {
|
||||
throw createError({ statusCode: 401, message: 'Unauthorized' })
|
||||
}
|
||||
|
||||
const body = await readBody(event)
|
||||
const { instanceId, jid } = body
|
||||
|
||||
if (!instanceId) {
|
||||
throw createError({ statusCode: 400, message: 'instanceId is required' })
|
||||
}
|
||||
|
||||
if (!jid) {
|
||||
throw createError({ statusCode: 400, message: 'jid is required' })
|
||||
}
|
||||
|
||||
const socket = baileysManager.getSocket(instanceId)
|
||||
if (!socket) {
|
||||
throw createError({ statusCode: 400, message: 'Instance not connected' })
|
||||
}
|
||||
|
||||
try {
|
||||
const code = await socket.groupInviteCode(jid)
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
code,
|
||||
link: `https://chat.whatsapp.com/${code}`
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
message: `Failed to get invite code: ${(error as Error).message}`
|
||||
})
|
||||
}
|
||||
})
|
||||
38
server/api/debug/groups/metadata.post.ts
Normal file
38
server/api/debug/groups/metadata.post.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* POST /api/debug/groups/metadata
|
||||
* Get group metadata
|
||||
*/
|
||||
import { baileysManager } from '../../../services/baileys/manager'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const username = getHeader(event, 'x-authentik-username')
|
||||
if (!username) {
|
||||
throw createError({ statusCode: 401, message: 'Unauthorized' })
|
||||
}
|
||||
|
||||
const body = await readBody(event)
|
||||
const { instanceId, jid } = body
|
||||
|
||||
if (!instanceId) {
|
||||
throw createError({ statusCode: 400, message: 'instanceId is required' })
|
||||
}
|
||||
|
||||
if (!jid) {
|
||||
throw createError({ statusCode: 400, message: 'jid is required' })
|
||||
}
|
||||
|
||||
const socket = baileysManager.getSocket(instanceId)
|
||||
if (!socket) {
|
||||
throw createError({ statusCode: 400, message: 'Instance not connected' })
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await socket.groupMetadata(jid)
|
||||
return { success: true, data: result }
|
||||
} catch (error) {
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
message: `Failed to get group metadata: ${(error as Error).message}`
|
||||
})
|
||||
}
|
||||
})
|
||||
57
server/api/debug/groups/participants.post.ts
Normal file
57
server/api/debug/groups/participants.post.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* POST /api/debug/groups/participants
|
||||
* Update group participants (add, remove, promote, demote)
|
||||
*/
|
||||
import { baileysManager } from '../../../services/baileys/manager'
|
||||
|
||||
type ParticipantAction = 'add' | 'remove' | 'promote' | 'demote'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const username = getHeader(event, 'x-authentik-username')
|
||||
if (!username) {
|
||||
throw createError({ statusCode: 401, message: 'Unauthorized' })
|
||||
}
|
||||
|
||||
const body = await readBody(event)
|
||||
const { instanceId, jid, participants, action } = body as {
|
||||
instanceId: string
|
||||
jid: string
|
||||
participants: string[]
|
||||
action: ParticipantAction
|
||||
}
|
||||
|
||||
if (!instanceId) {
|
||||
throw createError({ statusCode: 400, message: 'instanceId is required' })
|
||||
}
|
||||
|
||||
if (!jid) {
|
||||
throw createError({ statusCode: 400, message: 'jid is required' })
|
||||
}
|
||||
|
||||
if (!participants || !Array.isArray(participants) || participants.length === 0) {
|
||||
throw createError({ statusCode: 400, message: 'participants array is required' })
|
||||
}
|
||||
|
||||
const validActions: ParticipantAction[] = ['add', 'remove', 'promote', 'demote']
|
||||
if (!action || !validActions.includes(action)) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
message: `action must be one of: ${validActions.join(', ')}`
|
||||
})
|
||||
}
|
||||
|
||||
const socket = baileysManager.getSocket(instanceId)
|
||||
if (!socket) {
|
||||
throw createError({ statusCode: 400, message: 'Instance not connected' })
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await socket.groupParticipantsUpdate(jid, participants, action)
|
||||
return { success: true, data: result }
|
||||
} catch (error) {
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
message: `Failed to update participants: ${(error as Error).message}`
|
||||
})
|
||||
}
|
||||
})
|
||||
42
server/api/debug/groups/subject.post.ts
Normal file
42
server/api/debug/groups/subject.post.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* POST /api/debug/groups/subject
|
||||
* Update group subject (name)
|
||||
*/
|
||||
import { baileysManager } from '../../../services/baileys/manager'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const username = getHeader(event, 'x-authentik-username')
|
||||
if (!username) {
|
||||
throw createError({ statusCode: 401, message: 'Unauthorized' })
|
||||
}
|
||||
|
||||
const body = await readBody(event)
|
||||
const { instanceId, jid, subject } = body
|
||||
|
||||
if (!instanceId) {
|
||||
throw createError({ statusCode: 400, message: 'instanceId is required' })
|
||||
}
|
||||
|
||||
if (!jid) {
|
||||
throw createError({ statusCode: 400, message: 'jid is required' })
|
||||
}
|
||||
|
||||
if (!subject) {
|
||||
throw createError({ statusCode: 400, message: 'subject is required' })
|
||||
}
|
||||
|
||||
const socket = baileysManager.getSocket(instanceId)
|
||||
if (!socket) {
|
||||
throw createError({ statusCode: 400, message: 'Instance not connected' })
|
||||
}
|
||||
|
||||
try {
|
||||
await socket.groupUpdateSubject(jid, subject)
|
||||
return { success: true, message: 'Group subject updated successfully' }
|
||||
} catch (error) {
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
message: `Failed to update group subject: ${(error as Error).message}`
|
||||
})
|
||||
}
|
||||
})
|
||||
41
server/api/debug/history/fetch.post.ts
Normal file
41
server/api/debug/history/fetch.post.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* POST /api/debug/history/fetch
|
||||
* Request message history on-demand
|
||||
*/
|
||||
import { baileysManager } from '../../../services/baileys/manager'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const username = getHeader(event, 'x-authentik-username')
|
||||
if (!username) {
|
||||
throw createError({ statusCode: 401, message: 'Unauthorized' })
|
||||
}
|
||||
|
||||
const body = await readBody(event)
|
||||
const { instanceId, count, oldestMsgKey, oldestMsgTimestamp } = body
|
||||
|
||||
if (!instanceId) {
|
||||
throw createError({ statusCode: 400, message: 'instanceId is required' })
|
||||
}
|
||||
|
||||
if (!count || typeof count !== 'number') {
|
||||
throw createError({ statusCode: 400, message: 'count (number) is required' })
|
||||
}
|
||||
|
||||
const socket = baileysManager.getSocket(instanceId)
|
||||
if (!socket) {
|
||||
throw createError({ statusCode: 400, message: 'Instance not connected' })
|
||||
}
|
||||
|
||||
try {
|
||||
await socket.fetchMessageHistory(count, oldestMsgKey, oldestMsgTimestamp)
|
||||
return {
|
||||
success: true,
|
||||
message: `Requested ${count} messages from history. Check messaging-history.set event for results.`
|
||||
}
|
||||
} catch (error) {
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
message: `Failed to fetch message history: ${(error as Error).message}`
|
||||
})
|
||||
}
|
||||
})
|
||||
38
server/api/debug/media/update.post.ts
Normal file
38
server/api/debug/media/update.post.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* POST /api/debug/media/update
|
||||
* Update expired media message
|
||||
*/
|
||||
import { baileysManager } from '../../../services/baileys/manager'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const username = getHeader(event, 'x-authentik-username')
|
||||
if (!username) {
|
||||
throw createError({ statusCode: 401, message: 'Unauthorized' })
|
||||
}
|
||||
|
||||
const body = await readBody(event)
|
||||
const { instanceId, message } = body
|
||||
|
||||
if (!instanceId) {
|
||||
throw createError({ statusCode: 400, message: 'instanceId is required' })
|
||||
}
|
||||
|
||||
if (!message) {
|
||||
throw createError({ statusCode: 400, message: 'message (proto.IWebMessageInfo) is required' })
|
||||
}
|
||||
|
||||
const socket = baileysManager.getSocket(instanceId)
|
||||
if (!socket) {
|
||||
throw createError({ statusCode: 400, message: 'Instance not connected' })
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await socket.updateMediaMessage(message)
|
||||
return { success: true, data: result }
|
||||
} catch (error) {
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
message: `Failed to update media message: ${(error as Error).message}`
|
||||
})
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user