Compare commits

...
9 Commits
Author SHA1 Message Date
allburov f6f09747dc [core] pin node:20-bullseye
Release / deploy-docker (push) Canceled after 0s
2023-07-14 10:10:28 +07:00
allburov 27a534a605 [core] add set session presence endpoint 2023-07-12 16:46:15 +07:00
allburov 3cbd940843 [core] Add swagger image at the top of quick start 2023-07-07 14:26:23 +07:00
allburov e728eec01a [core] Move tiers
Release / deploy-docker (push) Canceled after 0s
2023-07-05 10:29:10 +07:00
allburov d06d2b78a8 [core] Move donations to top, add links 2023-07-05 10:27:32 +07:00
allburov 5878a9196e [core] Pin yarn version to 3.6.1 2023-07-03 21:52:32 +07:00
allburov 85dd061f96 [core] ignore .yaml folder 2023-07-03 21:52:29 +07:00
allburov 8381c3e946 [core] Set retention days 5 2023-07-03 11:01:51 +07:00
allburov 6ff8a9705d [core] Add cleanup github script 2023-07-03 10:59:56 +07:00
17 changed files with 239 additions and 48 deletions

No files matched your search

+1
View File
@@ -11,6 +11,7 @@ examples
# compiled output
/dist
/node_modules
.yarn
# Logs
logs
+18
View File
@@ -0,0 +1,18 @@
# Idea from
# https://stackoverflow.com/a/65539398/6753144
#
OWNER=devlikeapro
REPO=whatsapp-http-api-plus
# list workflows
gh api -X GET /repos/$OWNER/$REPO/actions/workflows | jq '.workflows[] | .name,.id'
# copy the ID of the workflow you want to clear and set it
WORKFLOW_ID=40218610
# list runs
gh api -X GET /repos/$OWNER/$REPO/actions/workflows/$WORKFLOW_ID/runs --paginate | jq '.workflow_runs[] | .id'
# delete runs
gh api -X GET /repos/$OWNER/$REPO/actions/workflows/$WORKFLOW_ID/runs --paginate | jq '.workflow_runs[] | .id' | xargs -I{} gh api -X DELETE /repos/$OWNER/$REPO/actions/runs/{} --silent
+1
View File
@@ -31,6 +31,7 @@ jobs:
with:
path: docs/site/public
name: public
retention-days: 5
deploy-github-pages:
needs: build
+1 -1
View File
@@ -1,3 +1,3 @@
nodeLinker: node-modules
yarnPath: .yarn/releases/yarn-3.6.0.cjs
yarnPath: .yarn/releases/yarn-3.6.1.cjs
+3 -3
View File
@@ -1,14 +1,14 @@
#
# Build
#
FROM node:18 as build
FROM node:20-bullseye as build
ENV PUPPETEER_SKIP_DOWNLOAD=True
# npm packages
WORKDIR /src
COPY package.json .
COPY yarn.lock .
RUN yarn set version berry
RUN yarn set version 3.6.1
RUN yarn install
# App
@@ -20,7 +20,7 @@ RUN yarn build && find ./dist -name "*.d.ts" -delete
#
# Final
#
FROM node:18 as release
FROM node:20-bullseye as release
ENV PUPPETEER_SKIP_DOWNLOAD=True
ARG USE_BROWSER=chromium
@@ -16,30 +16,19 @@ weight: 900
1. Core ![](/images/versions/core.png) the basic version that meet almost 80% people’s needs. 100% free and open source.
2. Plus ![](/images/versions/plus.png) the version with advanced messages, security, and reliability features.
### Features
The Plus additional features are:
1. [**Send images\files\voices** →]({{< relref "/docs/how-to/send-messages" >}})
2. [**Receive images\files\voices** →]({{< relref "/docs/how-to/receive-messages" >}})
3. [**Webhook retries** →]({{< relref "/docs/how-to/receive-messages#retries" >}})
4. [**Security** →]({{< relref "/docs/how-to/security" >}})
5. [**Saving sessions** →]({{< relref "/docs/how-to/sessions" >}})
6. [**Support multiple sessions** →]({{< relref "/docs/how-to/sessions" >}})
7. **Priority in support** - on both bugs and features
### Differences
What is the difference between **WAHA Plus** and other SaaS solutions for WhatsApp HTTP API?
| | WAHA Plus | Others |
|--------------------|:-------------------------------------------------:|----------------------------------------------------------------------------------:|
| **Sessions** | ✔️ No limits on **accounts** or **servers**! | ➖ One account for $50/month. |
| **Infrastructure** | ✔️ On-Premise - your server, your infrastructure! | ➖ Insecure cloud solution. |
| **Security** | ✔️ No data leaks! | ➖ You have to give access to customers' data - phone number, name, your messages. |
| **License Term** | ✔️ No license checks! | ➖ One month |
| **Message price** | ✔️ All messages are Free! | ➖ Some solutions have a price for messages - $1/100 messages. |
| **Expenses** | ✔️ $19 **donation**! | ➖ Monthly payment starts from $50 |
You support the project and get **WAHA Plus** on
<a href="https://boosty.to/wa-http-api" target="_blank">
<b>
Boosty ->
</b>
</a>
or
<a href="https://patreon.com/wa_http_api" target="_blank">
<b>
Patreon ->
</b>
</a>
.
### Donations
@@ -60,17 +49,37 @@ Treat **WAHA Plus** it as an additional episode, behind-the-scenes videos, our n
We donate most of the donations down to the stream to the underlying libraries and tools - JS-community, Node, other libraries authors, personal contributors.
By donating to the **WAHA** you donate to the Open Source world!
### Features
The Plus additional features are:
1. [**Send images\files\voices** →]({{< relref "/docs/how-to/send-messages" >}})
2. [**Receive images\files\voices** →]({{< relref "/docs/how-to/receive-messages" >}})
3. [**Webhook retries** →]({{< relref "/docs/how-to/receive-messages#retries" >}})
4. [**Security** →]({{< relref "/docs/how-to/security" >}})
5. [**Saving sessions** →]({{< relref "/docs/how-to/sessions" >}})
6. [**Support multiple sessions** →]({{< relref "/docs/how-to/sessions" >}})
7. **Priority in support** - on both bugs and features
### Why WAHA?
What is the difference between **WAHA Plus** and **other SaaS solutions** for WhatsApp HTTP API?
| | WAHA Plus | Others |
|--------------------|:-------------------------------------------------:|----------------------------------------------------------------------------------:|
| **Sessions** | ✔️ No limits on **accounts** or **servers**! | ➖ One account for $50/month. |
| **Infrastructure** | ✔️ On-Premise - your server, your infrastructure! | ➖ Insecure cloud solution. |
| **Security** | ✔️ No data leaks! | ➖ You have to give access to customers' data - phone number, name, your messages. |
| **License Term** | ✔️ No license checks! | ➖ One month |
| **Message price** | ✔️ All messages are Free! | ➖ Some solutions have a price for messages - $1/100 messages. |
| **Expenses** | ✔️ $19 **donation**! | ➖ Monthly payment starts from $50 |
## Get Plus ![](/images/versions/plus.png)
For **$19** donation you get:
1. **Secret password** for Docker Hub to download Plus image: `devlikeapro/whatsapp-http-api-plus`.
2. **All updates for one month** for the Plus image.
3. **NO LICENSE CHECKS** on installed instances!
4. **NO LICENSE EXPIRATION** on installed instances! We repeated it twice to make sure that you've got it 😊
The more you support the project - the more you get!
{{< alert icon="💡" text="If you stay subscribed - the donation amount will never change for you and always be $19 to get monthly updates!" />}}
Here's all available tiers with their perks:
Here's available tiers for our supporters:
| | Plus | Advanced | Pro |
|-------------------------------------------------------------------------------------|---------|:--------:|:-------:|
@@ -79,6 +88,13 @@ Here's all available tiers with their perks:
| Access to a Telegram group where we provide support and assistance. | ➖️ | ➖ | ✔️ |
| **Donation** | **$19** | **$39** | **$99** |
For **$19** donation you get:
1. **Secret password** for Docker Hub to download Plus image: `devlikeapro/whatsapp-http-api-plus`.
2. **All updates for one month** for the Plus image.
3. **NO LICENSE CHECKS** on installed instances!
4. **NO LICENSE EXPIRATION** on installed instances! We repeated it twice to make sure that you've got it 😊
{{< alert icon="💡" text="If you stay subscribed - the donation amount will never change for you and always be $19 to get monthly updates!" />}}
### Boosty
@@ -12,7 +12,55 @@ weight: 801
You can get presence information (online, offline with last seen, typing status) for a contact if they share their
presence information.
{{< alert icon="👉" text="Presence endpoints and webhook is available only in **NOWEB** engine." />}}
Possible presence statuses that you can set or get for chats:
- `online`
- `offline`
- `typing`
- `recording`
- `paused` resets the chat presence after you were `typing`
## Endpoints
### Set presence
You can set your global or chat-related presence with `POST /api/{session}/presence` endpoint
Start typing to a chat (you can use `POST /startTyping` instead)
```json
{
"chatId": "111111111@c.us",
"presence": "typing"
}
```
Clear "typing" state (you can use `POST /stopTyping` instead)
```json
{
"chatId": "111111111@c.us",
"presence": "paused"
}
```
Set global "online", all contacts will see it
```json
{
"presence": "online"
}
```
💡 In the multi-device version of WhatsApp - if a desktop client is active, WhatsApp doesn't send push notifications
to the device.
If you would like to receive said notifications - you need to mark a session's presence as `offline`.
```json
{
"presence": "offline"
}
```
### Get all chats presence
{{< alert icon="👉" text="Get presence endpoints and webhook is available only in **NOWEB** engine." />}}
[Read more about engines to choose right for you ->]({{< relref "/docs/how-to/engines" >}})
Here's few notes about fields:
@@ -22,9 +70,6 @@ Here's few notes about fields:
- `lastKnownPresence` - contains the last known presence status, which can be
`offline`, `online`, `typing`, `recording`, or `paused`
## Endpoints
### Get all presence
You can get all presence information available for a session by calling `GET /api/{session}/presence/`.
It returns both groups' and personal chats' presence information.
@@ -12,6 +12,12 @@ menu:
weight: 199
toc: true
---
## 2023.8
August 2023
- Added [set presence endpoint](https://waha.devlike.pro/docs/how-to/presence)!
- With `online` presence you can show your status as online [#121](https://github.com/devlikeapro/whatsapp-http-api/issues/121)
- With `offline` presence you can get notifications for your device [#28](https://github.com/devlikeapro/whatsapp-http-api/issues/28)
## 2023.7
July 2023
- Now session can have their own [Webhooks](https://waha.devlike.pro/docs/how-to/webhooks) -
@@ -16,6 +16,8 @@ toc: true
On this page you're going to install WAHA, run it, authenticate the client using QR code and send the first text message
to WhatsApp!
![](swagger.png)
## Requirements
Only thing that you must have - installed docker. Please follow the original
+43 -2
View File
@@ -1,10 +1,21 @@
import { Controller, Get, Param, Post } from '@nestjs/common';
import {
BadRequestException,
Body,
Controller,
Get,
Param,
Post,
} from '@nestjs/common';
import { ApiOperation, ApiSecurity, ApiTags } from '@nestjs/swagger';
import { SessionManager } from '../core/abc/manager.abc';
import { WhatsappSession } from '../core/abc/session.abc';
import { WAHAChatPresences } from '../structures/presence.dto';
import {
WAHAChatPresences,
WAHASessionPresence,
} from '../structures/presence.dto';
import { SessionApiParam, SessionParam } from './helpers';
import { WAHAPresenceStatus } from '../structures/enums.dto';
@ApiSecurity('api_key')
@Controller('api/:session/presence')
@@ -12,6 +23,36 @@ import { SessionApiParam, SessionParam } from './helpers';
export class PresenceController {
constructor(private manager: SessionManager) {}
@Post('')
@SessionApiParam
@ApiOperation({ summary: 'Set session presence' })
setPresence(
@SessionParam session: WhatsappSession,
@Body() request: WAHASessionPresence,
) {
// Validate request
const presencesWithoutChatId = [
WAHAPresenceStatus.ONLINE,
WAHAPresenceStatus.OFFLINE,
];
const requiresNoChatId = presencesWithoutChatId.includes(request.presence);
const requiresChatId = !requiresNoChatId;
if (requiresNoChatId && request.chatId) {
const msg = {
detail: `'${request.presence}' presence works on the global scope and doesn't require 'chatId' field.`,
};
throw new BadRequestException(msg);
} else if (requiresChatId && !request.chatId) {
const msg = {
detail: `'${request.presence}' presence requires 'chatId' field.`,
};
throw new BadRequestException(msg);
}
return session.setPresence(request.presence, request.chatId);
}
@Get('')
@SessionApiParam
@ApiOperation({ summary: 'Get all subscribed presence information.' })
+5
View File
@@ -22,6 +22,7 @@ import { ContactQuery, ContactRequest } from '../../structures/contacts.dto';
import {
WAHAEngine,
WAHAEvents,
WAHAPresenceStatus,
WAHASessionStatus,
} from '../../structures/enums.dto';
import {
@@ -257,6 +258,10 @@ export abstract class WhatsappSession {
throw new NotImplementedByEngineError();
}
public setPresence(presence: WAHAPresenceStatus, chatId?: string) {
throw new NotImplementedByEngineError();
}
public getPresences(): Promise<WAHAChatPresences[]> {
throw new NotImplementedByEngineError();
}
+12
View File
@@ -12,6 +12,7 @@ import { Agent } from 'https';
import * as lodash from 'lodash';
import { Message } from 'whatsapp-web.js';
import { flipObject } from '../helpers';
import {
Button,
ChatRequest,
@@ -78,6 +79,7 @@ const PresenceStatuses = {
recording: WAHAPresenceStatus.RECORDING,
paused: WAHAPresenceStatus.PAUSED,
};
const ToEnginePresenceStatus = flipObject(PresenceStatuses);
export class WhatsappSessionNoWebCore extends WhatsappSession {
engine = WAHAEngine.NOWEB;
@@ -414,6 +416,16 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
return this.sock.groupParticipantsUpdate(id, participants, 'demote');
}
public async setPresence(presence: WAHAPresenceStatus, chatId?: string) {
const enginePresence = ToEnginePresenceStatus[presence];
if (!enginePresence) {
throw new NotImplementedByEngineError(
`NOWEB engine doesn't support '${presence}' presence.`,
);
}
await this.sock.sendPresenceUpdate(enginePresence, chatId);
}
public async getPresences(): Promise<WAHAChatPresences[]> {
const result: WAHAChatPresences[] = [];
for (const remoteJid in this.store.presences) {
+29
View File
@@ -33,6 +33,7 @@ import { ContactQuery, ContactRequest } from '../structures/contacts.dto';
import {
WAHAEngine,
WAHAEvents,
WAHAPresenceStatus,
WAHASessionStatus,
} from '../structures/enums.dto';
import {
@@ -366,6 +367,34 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
return groupChat.demoteParticipants(participantIds);
}
public async setPresence(presence: WAHAPresenceStatus, chatId?: string) {
let chat: Chat;
switch (presence) {
case WAHAPresenceStatus.ONLINE:
await this.whatsapp.sendPresenceAvailable();
break;
case WAHAPresenceStatus.OFFLINE:
await this.whatsapp.sendPresenceUnavailable();
break;
case WAHAPresenceStatus.TYPING:
chat = await this.whatsapp.getChatById(chatId);
await chat.sendStateTyping();
break;
case WAHAPresenceStatus.RECORDING:
chat = await this.whatsapp.getChatById(chatId);
await chat.sendStateRecording();
break;
case WAHAPresenceStatus.PAUSED:
chat = await this.whatsapp.getChatById(chatId);
await chat.clearState();
break;
default:
throw new NotImplementedByEngineError(
`WEBJS engine doesn't support '${presence}' presence.`,
);
}
}
/**
* END - Methods for API
*/
+1 -4
View File
@@ -24,10 +24,7 @@ export class SwaggerModuleCore {
'E.g: \`12312312310\` OR \`12312312310@c.us\`<br>`,
)
.addTag('groups', `Groups methods.<br>`)
.addTag(
'presence',
`Presence information. Available in <b>NOWEB</b> engine only.<br>`,
)
.addTag('presence', `Presence information`)
.addTag('other', 'Other methods')
.addApiKey({
type: 'apiKey',
+9 -1
View File
@@ -1,4 +1,4 @@
export function parseBool(value: any): boolean {
function parseBool(value: any): boolean {
if (!value) {
return false;
}
@@ -18,3 +18,11 @@ export function parseBool(value: any): boolean {
'Error: parseBool got unexpected value - use "true" or "false" values',
);
}
function flipObject(object) {
return Object.fromEntries(
Object.entries(object).map(([key, value]) => [value, key]),
);
}
export { flipObject, parseBool };
+10
View File
@@ -22,3 +22,13 @@ export class WAHAChatPresences {
id: string;
presences: WAHAPresenceData[];
}
export class WAHASessionPresence {
presence: WAHAPresenceStatus;
@ApiProperty({
description: 'Chat ID - either group id or contact id',
example: '11111111111@c.us',
})
chatId: string;
}
+1 -1
View File
@@ -26,7 +26,7 @@ export function getWAHAVersion(): WAHAVersion {
}
export const VERSION = {
version: '2023.7.1',
version: '2023.7.12',
tier: getWAHAVersion(),
browser: getBrowserExecutablePath(),
};