Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e5df21e165 | ||
|
|
792029b13f | ||
|
|
0ef49d7116 | ||
|
|
600d3291eb | ||
|
|
b78413190c | ||
|
|
c9729af139 | ||
|
|
697f267fc3 | ||
|
|
ac49ce3cc5 | ||
|
|
555daf6888 | ||
|
|
8f0c2994a6 | ||
|
|
873e66db19 | ||
|
|
38b542def4 | ||
|
|
a646e5efc0 | ||
|
|
31590c9229 | ||
|
|
98c2172908 | ||
|
|
314b02daf1 | ||
|
|
d2ab78b65c | ||
|
|
db2c352fd1 | ||
|
|
6e79ad2793 | ||
|
|
77eaa287fe | ||
|
|
a64820048c | ||
|
|
4ff4a5a893 | ||
|
|
5ea5681d2b | ||
|
|
2bb327b747 | ||
|
|
4dcdf60309 | ||
|
|
009fd5b2ec | ||
|
|
091e7e5bc1 | ||
|
|
ea1202bb65 | ||
|
|
cb413febaa | ||
|
|
364e55d477 | ||
|
|
680a35a26d | ||
|
|
08ff59e463 | ||
|
|
9db4c8c333 | ||
|
|
2489c2da46 | ||
|
|
fbc58b0707 | ||
|
|
d5a525789e | ||
|
|
34066921e1 | ||
|
|
901c594311 | ||
|
|
5f619e608b | ||
|
|
49295090ad | ||
|
|
a6e43adb0a | ||
|
|
1f165bb6cb | ||
|
|
8fc9d88d2e | ||
|
|
d7e5a5ce05 | ||
|
|
09d446fdeb | ||
|
|
c0bbd60e15 | ||
|
|
af3fc137be | ||
|
|
0ee5e1bd88 | ||
|
|
f92ea18651 |
No files matched your search
@@ -126,7 +126,11 @@ jobs:
|
||||
working-directory: tests/smoke
|
||||
timeout-minutes: 2
|
||||
run: |
|
||||
docker run -d --name smoke --rm -p3000:3000 ${{ vars.DOCKER_IMAGE }}:${{ matrix.tag }}
|
||||
docker run -d \
|
||||
--name smoke \
|
||||
--rm -p3000:3000 \
|
||||
${{ vars.DOCKER_IMAGE }}:${{ matrix.tag }}
|
||||
|
||||
sleep 3
|
||||
docker logs smoke
|
||||
goss validate --retry-timeout 30s --sleep 1s
|
||||
|
||||
@@ -39,6 +39,7 @@ repos:
|
||||
(?x)^(
|
||||
docs/.*|
|
||||
README.md|
|
||||
tests/smoke/goss.yaml|
|
||||
)$
|
||||
- repo: https://github.com/Lucas-C/pre-commit-hooks-nodejs
|
||||
rev: v1.1.2
|
||||
|
||||
+28
-7
@@ -1,8 +1,10 @@
|
||||
ARG NODE_IMAGE_TAG=22.16-bookworm-slim
|
||||
ARG GOLANG_IMAGE_TAG=1.23-bookworm
|
||||
|
||||
#
|
||||
# Build
|
||||
#
|
||||
ARG NODE_VERSION=22.16-bullseye
|
||||
FROM node:${NODE_VERSION} AS build
|
||||
FROM node:${NODE_IMAGE_TAG} AS build
|
||||
ENV PUPPETEER_SKIP_DOWNLOAD=True
|
||||
|
||||
# npm packages
|
||||
@@ -10,6 +12,10 @@ WORKDIR /git
|
||||
COPY package.json .
|
||||
COPY yarn.lock .
|
||||
ENV YARN_CHECKSUM_BEHAVIOR=update
|
||||
|
||||
# git
|
||||
RUN apt-get update && apt-get install -y git
|
||||
|
||||
RUN npm install -g corepack && corepack enable
|
||||
RUN yarn set version 3.6.3
|
||||
RUN yarn install
|
||||
@@ -23,11 +29,14 @@ RUN yarn build && find ./dist -name "*.d.ts" -delete
|
||||
#
|
||||
# Dashboard
|
||||
#
|
||||
FROM node:${NODE_VERSION} AS dashboard
|
||||
FROM node:${NODE_IMAGE_TAG} AS dashboard
|
||||
|
||||
# jq to parse json
|
||||
RUN apt-get update && apt-get install -y jq && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# wget, unzip
|
||||
RUN apt-get update && apt-get install -y wget unzip && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY waha.config.json /tmp/waha.config.json
|
||||
RUN \
|
||||
WAHA_DASHBOARD_GITHUB_REPO=$(jq -r '.waha.dashboard.repo' /tmp/waha.config.json) && \
|
||||
@@ -42,7 +51,7 @@ RUN \
|
||||
#
|
||||
# GOWS
|
||||
#
|
||||
FROM golang:1.23-bullseye AS gows
|
||||
FROM golang:${GOLANG_IMAGE_TAG} AS gows
|
||||
|
||||
# jq to parse json
|
||||
RUN apt-get update && apt-get install -y jq && rm -rf /var/lib/apt/lists/*
|
||||
@@ -73,7 +82,7 @@ RUN \
|
||||
#
|
||||
# Final
|
||||
#
|
||||
FROM node:${NODE_VERSION} AS release
|
||||
FROM node:${NODE_IMAGE_TAG} AS release
|
||||
ENV PUPPETEER_SKIP_DOWNLOAD=True
|
||||
# Quick fix for memory potential memory leaks
|
||||
# https://github.com/devlikeapro/waha/issues/347
|
||||
@@ -98,6 +107,13 @@ RUN if [ "$USE_BROWSER" = "chromium" ] || [ "$USE_BROWSER" = "chrome" ]; then \
|
||||
&& rm -rf /var/lib/apt/lists/*; \
|
||||
fi
|
||||
|
||||
# Install wget - either for chromium or chrome
|
||||
RUN if [ "$USE_BROWSER" = "chromium" ] || [ "$USE_BROWSER" = "chrome" ]; then \
|
||||
apt-get update \
|
||||
&& apt-get install -y wget \
|
||||
&& rm -rf /var/lib/apt/lists/*; \
|
||||
fi
|
||||
|
||||
# Install fonts if using either chromium or chrome
|
||||
RUN if [ "$USE_BROWSER" = "chromium" ] || [ "$USE_BROWSER" = "chrome" ]; then \
|
||||
apt-get update \
|
||||
@@ -119,10 +135,11 @@ RUN if [ "$USE_BROWSER" = "chromium" ] || [ "$USE_BROWSER" = "chrome" ]; then \
|
||||
&& rm -rf /var/lib/apt/lists/*; \
|
||||
fi
|
||||
|
||||
# Install xvfb
|
||||
# Install xvfb, xauth
|
||||
RUN if [ "$USE_BROWSER" = "chromium" ] || [ "$USE_BROWSER" = "chrome" ]; then \
|
||||
apt-get update && apt-get install -y --no-install-recommends \
|
||||
xvfb \
|
||||
xauth \
|
||||
libnss3 \
|
||||
libxss1 \
|
||||
libasound2 \
|
||||
@@ -130,7 +147,6 @@ RUN if [ "$USE_BROWSER" = "chromium" ] || [ "$USE_BROWSER" = "chrome" ]; then \
|
||||
libgtk-3-0 \
|
||||
libdrm2 \
|
||||
ca-certificates \
|
||||
curl \
|
||||
&& rm -rf /var/lib/apt/lists/*; \
|
||||
fi
|
||||
|
||||
@@ -155,6 +171,11 @@ RUN if [ "$USE_BROWSER" = "chrome" ]; then \
|
||||
&& rm -rf /var/lib/apt/lists/*; \
|
||||
fi
|
||||
|
||||
# curl
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y curl \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# GOWS requirements
|
||||
# libc6
|
||||
RUN apt-get update \
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
build-all: build-plus build-chrome build-gows build-noweb
|
||||
|
||||
build:
|
||||
docker build . -t devlikeapro/waha
|
||||
|
||||
build-plus:
|
||||
docker build . -t devlikeapro/waha-plus
|
||||
|
||||
build-chrome:
|
||||
docker build . -t devlikeapro/waha-plus:chrome --build-arg USE_BROWSER=chrome
|
||||
|
||||
build-noweb:
|
||||
docker build . -t devlikeapro/waha:noweb --build-arg USE_BROWSER=none --build-arg WHATSAPP_DEFAULT_ENGINE=NOWEB
|
||||
docker build . -t devlikeapro/waha-plus:noweb --build-arg USE_BROWSER=none --build-arg WHATSAPP_DEFAULT_ENGINE=NOWEB
|
||||
|
||||
build-plus-gows:
|
||||
build-gows:
|
||||
docker build . -t devlikeapro/waha-plus:gows --build-arg USE_BROWSER=none --build-arg WHATSAPP_DEFAULT_ENGINE=GOWS
|
||||
|
||||
build-all: build build-chrome build-noweb
|
||||
|
||||
build-plus:
|
||||
docker build . -t devlikeapro/waha-plus
|
||||
|
||||
build-ssh:
|
||||
# check IMAGE provided
|
||||
@[ "${IMAGE}" ] || ( echo "Add APP: make build-ssh image=devlikeapro/waha"; exit 1 );
|
||||
|
||||
@@ -8,6 +8,11 @@ services:
|
||||
# WAHA Core
|
||||
# image: devlikeapro/waha:latest
|
||||
|
||||
# Add "dns" if you have a problem with resolving "web.whatsapp.com"
|
||||
dns:
|
||||
- 1.1.1.1
|
||||
- 8.8.8.8
|
||||
|
||||
logging:
|
||||
driver: 'json-file'
|
||||
options:
|
||||
|
||||
+19
-23
@@ -1,16 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Run Xvfb if exists
|
||||
#
|
||||
if command -v Xvfb > /dev/null 2>&1; then
|
||||
# Start virtual X server in the background
|
||||
Xvfb :99 -screen 0 1280x720x24 &
|
||||
export DISPLAY=:99
|
||||
sleep 2
|
||||
else
|
||||
echo "Xvfb command not found, skipping virtual X server setup"
|
||||
fi
|
||||
|
||||
#
|
||||
# Calculate UV_THREADPOOL_SIZE based on number of CPUs
|
||||
@@ -47,24 +36,31 @@ if [ -n "$key" ]; then
|
||||
echo "WARNING: Plain text API key detected. Converting to hashed format for security."
|
||||
echo "For better security, use WAHA_API_KEY=sha512:{SHA512_HASH_FOR_YOUR_API_KEY}"
|
||||
echo "⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️"
|
||||
|
||||
# Start a background task to display another warning after 5 seconds
|
||||
(
|
||||
sleep 5
|
||||
echo "⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️"
|
||||
echo "SECURITY REMINDER: Your plain text API key has been hashed for this session."
|
||||
echo "In the future, please use WAHA_API_KEY=sha512:{SHA512_HASH_FOR_YOUR_API_KEY}"
|
||||
echo "to avoid exposing your API key in environment variables or process lists."
|
||||
echo "⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️"
|
||||
) &
|
||||
|
||||
# Hash the key using sha512sum
|
||||
HASHED_KEY=$(echo -n "$key" | sha512sum | awk '{print $1}')
|
||||
export WAHA_API_KEY="sha512:$HASHED_KEY"
|
||||
fi
|
||||
fi
|
||||
|
||||
#
|
||||
# xvfb-run
|
||||
#
|
||||
USE_XVFB=false
|
||||
if [ -z "$WHATSAPP_DEFAULT_ENGINE" ] || [ "$WHATSAPP_DEFAULT_ENGINE" = "WEBJS" ]; then
|
||||
# Try to run xvfb-run with a test command
|
||||
if xvfb-run --auto-servernum echo "xvfb-run is working!"; then
|
||||
USE_XVFB=true
|
||||
else
|
||||
echo "xvfb-run test failed, do not run it"
|
||||
USE_XVFB=false
|
||||
fi
|
||||
fi
|
||||
|
||||
#
|
||||
# Start your application using node with exec to ensure proper signal handling
|
||||
#
|
||||
exec node dist/main
|
||||
if [ "$USE_XVFB" = "true" ]; then
|
||||
exec xvfb-run --auto-servernum node dist/main
|
||||
else
|
||||
exec node dist/main
|
||||
fi
|
||||
+3
-3
@@ -56,7 +56,7 @@
|
||||
"chokidar": "^3.6.0",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "0.14.0",
|
||||
"del": "^6.0.0",
|
||||
"del": "^8.0.0",
|
||||
"express-basic-auth": "^1.2.1",
|
||||
"file-type": "16.5.4",
|
||||
"fs-extra": "^11.2.0",
|
||||
@@ -79,11 +79,11 @@
|
||||
"pino-pretty": "^11.2.1",
|
||||
"pretty-bytes": "5.6.0",
|
||||
"promise-retry": "^2.0.1",
|
||||
"puppeteer": "^23.6.0",
|
||||
"puppeteer": "^24.10.0",
|
||||
"qrcode": "^1.5.1",
|
||||
"qrcode-terminal": "^0.12.0",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rimraf": "^3.0.2",
|
||||
"rimraf": "^4.3.0",
|
||||
"rxjs": "^7.8.1",
|
||||
"sharp": "^0.33.4",
|
||||
"swagger-ui-express": "^4.1.4",
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
import * as process from 'node:process';
|
||||
import * as v8 from 'node:v8';
|
||||
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Get,
|
||||
Logger,
|
||||
NotFoundException,
|
||||
Post,
|
||||
Query,
|
||||
StreamableFile,
|
||||
UsePipes,
|
||||
} from '@nestjs/common';
|
||||
import { ApiOperation, ApiSecurity, ApiTags } from '@nestjs/swagger';
|
||||
@@ -112,34 +109,3 @@ export class ServerController {
|
||||
return { stopping: true };
|
||||
}
|
||||
}
|
||||
|
||||
@ApiSecurity('api_key')
|
||||
@Controller('api/server/debug')
|
||||
@ApiTags('🔍 Observability')
|
||||
export class ServerDebugController {
|
||||
private logger: Logger;
|
||||
private readonly enabled: boolean;
|
||||
|
||||
constructor(protected config: WhatsappConfigService) {
|
||||
this.logger = new Logger('ServerDebugController');
|
||||
this.enabled = this.config.debugModeEnabled;
|
||||
}
|
||||
|
||||
@Get('heapsnapshot')
|
||||
@ApiOperation({
|
||||
summary: 'Return a heapsnapshot',
|
||||
description: "Return a heapsnapshot of the server's memory",
|
||||
})
|
||||
async heapsnapshot() {
|
||||
if (!this.enabled) {
|
||||
throw new NotFoundException('WAHA_DEBUG_MODE is disabled');
|
||||
}
|
||||
this.logger.log('Creating a heap snapshot...');
|
||||
const heap = v8.getHeapSnapshot();
|
||||
const fileName = `${Date.now()}.heapsnapshot`;
|
||||
return new StreamableFile(heap, {
|
||||
type: 'application/octet-stream',
|
||||
disposition: `attachment; filename=${fileName}`,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
import * as v8 from 'node:v8';
|
||||
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Logger,
|
||||
NotFoundException,
|
||||
Query,
|
||||
StreamableFile,
|
||||
UsePipes,
|
||||
} from '@nestjs/common';
|
||||
import { ApiOperation, ApiSecurity, ApiTags } from '@nestjs/swagger';
|
||||
import { WhatsappConfigService } from '@waha/config.service';
|
||||
import { SessionManager } from '@waha/core/abc/manager.abc';
|
||||
import { WhatsappSession } from '@waha/core/abc/session.abc';
|
||||
import {
|
||||
SessionApiParam,
|
||||
WorkingSessionParam,
|
||||
} from '@waha/nestjs/params/SessionApiParam';
|
||||
import { WAHAValidationPipe } from '@waha/nestjs/pipes/WAHAValidationPipe';
|
||||
import { BrowserTraceQuery } from '@waha/structures/server.debug.dto';
|
||||
import { createReadStream } from 'fs';
|
||||
|
||||
@ApiSecurity('api_key')
|
||||
@Controller('api/server/debug')
|
||||
@ApiTags('🔍 Observability')
|
||||
export class ServerDebugController {
|
||||
private logger: Logger;
|
||||
private readonly enabled: boolean;
|
||||
|
||||
constructor(
|
||||
private config: WhatsappConfigService,
|
||||
private manager: SessionManager,
|
||||
) {
|
||||
this.logger = new Logger('ServerDebugController');
|
||||
this.enabled = this.config.debugModeEnabled;
|
||||
}
|
||||
|
||||
@Get('heapsnapshot')
|
||||
@ApiOperation({
|
||||
summary: 'Return a heapsnapshot for the current nodejs process',
|
||||
description: "Return a heapsnapshot of the server's memory",
|
||||
})
|
||||
async heapsnapshot() {
|
||||
if (!this.enabled) {
|
||||
throw new NotFoundException('WAHA_DEBUG_MODE is disabled');
|
||||
}
|
||||
this.logger.log('Creating a heap snapshot...');
|
||||
const heap = v8.getHeapSnapshot();
|
||||
const fileName = `${Date.now()}.heapsnapshot`;
|
||||
return new StreamableFile(heap, {
|
||||
type: 'application/octet-stream',
|
||||
disposition: `attachment; filename=${fileName}`,
|
||||
});
|
||||
}
|
||||
|
||||
@Get('browser/trace/:session')
|
||||
@ApiOperation({
|
||||
summary: 'Collect and get a trace.json for Chrome DevTools ',
|
||||
description: 'Uses https://pptr.dev/api/puppeteer.tracing',
|
||||
})
|
||||
@SessionApiParam
|
||||
@UsePipes(new WAHAValidationPipe())
|
||||
async browserTrace(
|
||||
@WorkingSessionParam session: WhatsappSession,
|
||||
@Query() query: BrowserTraceQuery,
|
||||
) {
|
||||
if (!this.enabled) {
|
||||
throw new NotFoundException('WAHA_DEBUG_MODE is disabled');
|
||||
}
|
||||
const filepath = await session.browserTrace(query);
|
||||
const stream = createReadStream(filepath);
|
||||
const filename = `trace - ${session.name} - ${new Date()}.json`;
|
||||
return new StreamableFile(stream, {
|
||||
type: 'application/octet-stream',
|
||||
disposition: `attachment; filename=${filename}`,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,7 @@ import { Label, LabelDTO, LabelID } from '@waha/structures/labels.dto';
|
||||
import { LidToPhoneNumber } from '@waha/structures/lids.dto';
|
||||
import { PaginationParams } from '@waha/structures/pagination.dto';
|
||||
import { MessageSource, WAMessage } from '@waha/structures/responses.dto';
|
||||
import { BrowserTraceQuery } from '@waha/structures/server.debug.dto';
|
||||
import { DefaultMap } from '@waha/utils/DefaultMap';
|
||||
import { generatePrefixedId } from '@waha/utils/ids';
|
||||
import { LoggerBuilder } from '@waha/utils/logging';
|
||||
@@ -285,7 +286,6 @@ export abstract class WhatsappSession {
|
||||
'--aggressive-cache-discard',
|
||||
'--disable-accelerated-2d-canvas',
|
||||
'--disable-application-cache',
|
||||
// '--disable-background-networking', // COMMENTED to test WEBJS stability
|
||||
// DO NOT disable software rasterizer, it will break the video
|
||||
// https://github.com/devlikeapro/waha/issues/629
|
||||
// '--disable-software-rasterizer',
|
||||
@@ -296,7 +296,7 @@ export abstract class WhatsappSession {
|
||||
'--disable-dev-shm-usage',
|
||||
'--disable-extensions',
|
||||
// '--disable-features=site-per-process', // COMMENTED to test WEBJS stability
|
||||
//'--disable-gpu', // COMMENTED to test WEBJS stability
|
||||
'--disable-gpu', // COMMENTED to test WEBJS stability
|
||||
'--disable-offer-store-unmasked-wallet-cards',
|
||||
'--disable-offline-load-stale-cache',
|
||||
'--disable-popup-blocking',
|
||||
@@ -320,9 +320,8 @@ export abstract class WhatsappSession {
|
||||
'--no-sandbox',
|
||||
'--no-zygote',
|
||||
'--password-store=basic',
|
||||
// '--renderer-process-limit=2', // COMMENTED to test WEBJS stability
|
||||
'--renderer-process-limit=1',
|
||||
'--safebrowsing-disable-auto-update',
|
||||
// '--single-process',
|
||||
'--use-mock-keychain',
|
||||
'--window-size=1280,720',
|
||||
];
|
||||
@@ -351,6 +350,10 @@ export abstract class WhatsappSession {
|
||||
* START - Methods for API
|
||||
*/
|
||||
|
||||
public browserTrace(query: BrowserTraceQuery): Promise<string> {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Auth methods
|
||||
*/
|
||||
@@ -682,10 +685,17 @@ export abstract class WhatsappSession {
|
||||
}
|
||||
|
||||
protected async refreshProfilePicture(id: string) {
|
||||
let fn: Promise<string>;
|
||||
if (isJidBroadcast(id)) {
|
||||
this.logger.debug(`Refreshing profile picture for id "${id}"...`);
|
||||
// Have no pictures
|
||||
if (id === '0@c.us' || id === '0@s.whatsapp.net') {
|
||||
return null;
|
||||
} else if (isJidNewsletter(id)) {
|
||||
} else if (isJidBroadcast(id)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Find the right method
|
||||
let fn: Promise<string>;
|
||||
if (isJidNewsletter(id)) {
|
||||
fn = this.channelsGetChannel(id).then(
|
||||
(channel: Channel) => channel.picture || channel.preview,
|
||||
);
|
||||
|
||||
@@ -10,10 +10,8 @@ import { TerminusModule } from '@nestjs/terminus';
|
||||
import { ChannelsController } from '@waha/api/channels.controller';
|
||||
import { LidsController } from '@waha/api/lids.controller';
|
||||
import { ProfileController } from '@waha/api/profile.controller';
|
||||
import {
|
||||
ServerController,
|
||||
ServerDebugController,
|
||||
} from '@waha/api/server.controller';
|
||||
import { ServerController } from '@waha/api/server.controller';
|
||||
import { ServerDebugController } from '@waha/api/server.debug.controller';
|
||||
import { WebsocketGatewayCore } from '@waha/api/websocket.gateway.core';
|
||||
import { ApiKeyStrategy } from '@waha/core/auth/apiKey.strategy';
|
||||
import { IApiKeyAuth } from '@waha/core/auth/auth';
|
||||
@@ -76,6 +74,7 @@ export const IMPORTS_CORE = [
|
||||
autoLogging: {
|
||||
ignore: (req) => {
|
||||
return (
|
||||
req.url.startsWith('/ping') ||
|
||||
req.url.startsWith('/dashboard/') ||
|
||||
req.url.startsWith('/api/files/') ||
|
||||
req.url.startsWith('/api/s3/')
|
||||
|
||||
@@ -7031,6 +7031,8 @@ export namespace messages {
|
||||
constructor(data?: any[] | {
|
||||
session?: Session;
|
||||
message?: string;
|
||||
jid?: string;
|
||||
messageId?: string;
|
||||
}) {
|
||||
super();
|
||||
pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls);
|
||||
@@ -7041,6 +7043,12 @@ export namespace messages {
|
||||
if ("message" in data && data.message != undefined) {
|
||||
this.message = data.message;
|
||||
}
|
||||
if ("jid" in data && data.jid != undefined) {
|
||||
this.jid = data.jid;
|
||||
}
|
||||
if ("messageId" in data && data.messageId != undefined) {
|
||||
this.messageId = data.messageId;
|
||||
}
|
||||
}
|
||||
}
|
||||
get session() {
|
||||
@@ -7058,9 +7066,23 @@ export namespace messages {
|
||||
set message(value: string) {
|
||||
pb_1.Message.setField(this, 2, value);
|
||||
}
|
||||
get jid() {
|
||||
return pb_1.Message.getFieldWithDefault(this, 3, "") as string;
|
||||
}
|
||||
set jid(value: string) {
|
||||
pb_1.Message.setField(this, 3, value);
|
||||
}
|
||||
get messageId() {
|
||||
return pb_1.Message.getFieldWithDefault(this, 4, "") as string;
|
||||
}
|
||||
set messageId(value: string) {
|
||||
pb_1.Message.setField(this, 4, value);
|
||||
}
|
||||
static fromObject(data: {
|
||||
session?: ReturnType<typeof Session.prototype.toObject>;
|
||||
message?: string;
|
||||
jid?: string;
|
||||
messageId?: string;
|
||||
}): DownloadMediaRequest {
|
||||
const message = new DownloadMediaRequest({});
|
||||
if (data.session != null) {
|
||||
@@ -7069,12 +7091,20 @@ export namespace messages {
|
||||
if (data.message != null) {
|
||||
message.message = data.message;
|
||||
}
|
||||
if (data.jid != null) {
|
||||
message.jid = data.jid;
|
||||
}
|
||||
if (data.messageId != null) {
|
||||
message.messageId = data.messageId;
|
||||
}
|
||||
return message;
|
||||
}
|
||||
toObject() {
|
||||
const data: {
|
||||
session?: ReturnType<typeof Session.prototype.toObject>;
|
||||
message?: string;
|
||||
jid?: string;
|
||||
messageId?: string;
|
||||
} = {};
|
||||
if (this.session != null) {
|
||||
data.session = this.session.toObject();
|
||||
@@ -7082,6 +7112,12 @@ export namespace messages {
|
||||
if (this.message != null) {
|
||||
data.message = this.message;
|
||||
}
|
||||
if (this.jid != null) {
|
||||
data.jid = this.jid;
|
||||
}
|
||||
if (this.messageId != null) {
|
||||
data.messageId = this.messageId;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
serialize(): Uint8Array;
|
||||
@@ -7092,6 +7128,10 @@ export namespace messages {
|
||||
writer.writeMessage(1, this.session, () => this.session.serialize(writer));
|
||||
if (this.message.length)
|
||||
writer.writeString(2, this.message);
|
||||
if (this.jid.length)
|
||||
writer.writeString(3, this.jid);
|
||||
if (this.messageId.length)
|
||||
writer.writeString(4, this.messageId);
|
||||
if (!w)
|
||||
return writer.getResultBuffer();
|
||||
}
|
||||
@@ -7107,6 +7147,12 @@ export namespace messages {
|
||||
case 2:
|
||||
message.message = reader.readString();
|
||||
break;
|
||||
case 3:
|
||||
message.jid = reader.readString();
|
||||
break;
|
||||
case 4:
|
||||
message.messageId = reader.readString();
|
||||
break;
|
||||
default: reader.skipField();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14889,7 +14889,9 @@ proto.messages.DownloadMediaRequest.prototype.toObject = function(opt_includeIns
|
||||
proto.messages.DownloadMediaRequest.toObject = function(includeInstance, msg) {
|
||||
var f, obj = {
|
||||
session: (f = msg.getSession()) && proto.messages.Session.toObject(includeInstance, f),
|
||||
message: jspb.Message.getFieldWithDefault(msg, 2, "")
|
||||
message: jspb.Message.getFieldWithDefault(msg, 2, ""),
|
||||
jid: jspb.Message.getFieldWithDefault(msg, 3, ""),
|
||||
messageid: jspb.Message.getFieldWithDefault(msg, 4, "")
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
@@ -14935,6 +14937,14 @@ proto.messages.DownloadMediaRequest.deserializeBinaryFromReader = function(msg,
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setMessage(value);
|
||||
break;
|
||||
case 3:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setJid(value);
|
||||
break;
|
||||
case 4:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setMessageid(value);
|
||||
break;
|
||||
default:
|
||||
reader.skipField();
|
||||
break;
|
||||
@@ -14979,6 +14989,20 @@ proto.messages.DownloadMediaRequest.serializeBinaryToWriter = function(message,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getJid();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
3,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getMessageid();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
4,
|
||||
f
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -15037,6 +15061,42 @@ proto.messages.DownloadMediaRequest.prototype.setMessage = function(value) {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string jid = 3;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.messages.DownloadMediaRequest.prototype.getJid = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.messages.DownloadMediaRequest} returns this
|
||||
*/
|
||||
proto.messages.DownloadMediaRequest.prototype.setJid = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 3, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string messageId = 4;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.messages.DownloadMediaRequest.prototype.getMessageid = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 4, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.messages.DownloadMediaRequest} returns this
|
||||
*/
|
||||
proto.messages.DownloadMediaRequest.prototype.setMessageid = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 4, value);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -2152,6 +2152,8 @@ export class GOWSEngineMediaProcessor implements IMediaEngineProcessor<any> {
|
||||
// double "session" it's not a mistake here
|
||||
session: this.session.session,
|
||||
message: data,
|
||||
jid: message.Info.Chat,
|
||||
messageId: message.Info.ID,
|
||||
});
|
||||
const response = await promisify(this.session.client.DownloadMedia)(
|
||||
request,
|
||||
|
||||
@@ -1805,6 +1805,7 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
const messagesUpsert$ = fromEvent(this.sock.ev, 'messages.upsert').pipe(
|
||||
map((event: BaileysEventMap['messages.upsert']) => event.messages),
|
||||
mergeAll(),
|
||||
share(),
|
||||
);
|
||||
let [messagesFromMe$, messagesFromOthers$] = partition(
|
||||
messagesUpsert$,
|
||||
@@ -1888,6 +1889,7 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
).pipe(
|
||||
// @ts-ignore
|
||||
mergeAll(),
|
||||
share(),
|
||||
);
|
||||
const messageAckDirect$ = messageUpdates$.pipe(
|
||||
filter(isMine), // ack comes only for MY messages
|
||||
@@ -1898,6 +1900,7 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
fromEvent(this.sock.ev, 'message-receipt.update').pipe(
|
||||
// @ts-ignore
|
||||
mergeAll(),
|
||||
share(),
|
||||
);
|
||||
|
||||
const messageAckGroups$ = messageReceiptUpdate$.pipe(
|
||||
@@ -1914,7 +1917,7 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
//
|
||||
this.events2
|
||||
.get(WAHAEvents.STATE_CHANGE)
|
||||
.switch(fromEvent(this.sock.ev, 'connection.update'));
|
||||
.switch(fromEvent(this.sock.ev, 'connection.update').pipe(share()));
|
||||
|
||||
const groupsUpsert$: Observable<GroupMetadata> = fromEvent(
|
||||
this.sock.ev,
|
||||
@@ -1922,6 +1925,7 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
).pipe(
|
||||
// @ts-ignore
|
||||
mergeAll(),
|
||||
share(),
|
||||
);
|
||||
const groupsUpdate$: Observable<Partial<GroupMetadata>> = fromEvent(
|
||||
this.sock.ev,
|
||||
@@ -1929,11 +1933,12 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
).pipe(
|
||||
// @ts-ignore
|
||||
mergeAll(),
|
||||
share(),
|
||||
);
|
||||
const groupsParticipantsUpdate$: Observable<any> = fromEvent(
|
||||
this.sock.ev,
|
||||
'group-participants.update',
|
||||
);
|
||||
).pipe(share());
|
||||
|
||||
this.events2.get(WAHAEvents.GROUP_JOIN).switch(groupsUpsert$);
|
||||
|
||||
@@ -1960,13 +1965,12 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
);
|
||||
this.events2.get(WAHAEvents.GROUP_V2_LEAVE).switch(groupV2Leave$);
|
||||
|
||||
this.events2
|
||||
.get(WAHAEvents.PRESENCE_UPDATE)
|
||||
.switch(
|
||||
fromEvent(this.sock.ev, 'presence.update').pipe(
|
||||
map((data: any) => this.toWahaPresences(data.id, data.presences)),
|
||||
),
|
||||
);
|
||||
this.events2.get(WAHAEvents.PRESENCE_UPDATE).switch(
|
||||
fromEvent(this.sock.ev, 'presence.update').pipe(
|
||||
map((data: any) => this.toWahaPresences(data.id, data.presences)),
|
||||
share(),
|
||||
),
|
||||
);
|
||||
|
||||
//
|
||||
// Poll votes
|
||||
@@ -1993,7 +1997,7 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
//
|
||||
// @ts-ignore
|
||||
const calls$: Observable<WACallEvent[]> = fromEvent(this.sock.ev, 'call');
|
||||
const call$ = calls$.pipe(mergeMap(identity));
|
||||
const call$ = calls$.pipe(mergeMap(identity), share());
|
||||
this.events2.get(WAHAEvents.CALL_RECEIVED).switch(
|
||||
call$.pipe(
|
||||
filter((call: WACallEvent) => call.status === 'offer'),
|
||||
@@ -2026,7 +2030,7 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
const labelsEdit$: Observable<NOWEBLabel> = fromEvent(
|
||||
this.sock.ev,
|
||||
'labels.edit',
|
||||
);
|
||||
).pipe(share());
|
||||
this.events2.get(WAHAEvents.LABEL_UPSERT).switch(
|
||||
labelsEdit$.pipe(
|
||||
exclude((data: NOWEBLabel) => data.deleted),
|
||||
@@ -2039,7 +2043,10 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
map(this.toLabel.bind(this)),
|
||||
),
|
||||
);
|
||||
const labelsAssociation$ = fromEvent(this.sock.ev, 'labels.association');
|
||||
const labelsAssociation$ = fromEvent(
|
||||
this.sock.ev,
|
||||
'labels.association',
|
||||
).pipe(share());
|
||||
const labelsAssociationAdd$: Observable<ChatLabelAssociation> =
|
||||
labelsAssociation$.pipe(
|
||||
filter(({ type }: any) => type === 'add'),
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
import { Schema } from '@waha/core/storage/Schema';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const Database = require('better-sqlite3');
|
||||
import Knex from 'knex';
|
||||
|
||||
export class Sqlite3SchemaValidation {
|
||||
constructor(
|
||||
private table: Schema,
|
||||
private db,
|
||||
private knex: Knex.Knex,
|
||||
) {}
|
||||
|
||||
validate() {
|
||||
async validate() {
|
||||
const table = this.table;
|
||||
|
||||
// Check table has the columns
|
||||
const columns = this.db.prepare(`PRAGMA table_info(${table.name})`).all();
|
||||
// Check exact number of columns
|
||||
const columns = await this.knex.raw(`PRAGMA table_info(${table.name})`);
|
||||
// Check the exact number of columns
|
||||
if (columns.length !== table.columns.length) {
|
||||
throw new Error(
|
||||
`Table '${table.name}' does not have expected number of columns. Expected ${table.columns.length}, got ${columns.length}`,
|
||||
@@ -37,7 +35,7 @@ export class Sqlite3SchemaValidation {
|
||||
}
|
||||
|
||||
// Check table has expected indexes
|
||||
const indexes = this.db.prepare(`PRAGMA index_list(${table.name})`).all();
|
||||
const indexes = await this.knex.raw(`PRAGMA index_list(${table.name})`);
|
||||
const indexNames = indexes.map((index) => index.name);
|
||||
for (const index of table.indexes) {
|
||||
if (!indexNames.includes(index.name)) {
|
||||
|
||||
@@ -6,6 +6,7 @@ import { Sqlite3LabelAssociationsRepository } from '@waha/core/engines/noweb/sto
|
||||
import { Sqlite3LabelsRepository } from '@waha/core/engines/noweb/store/sqlite3/Sqlite3LabelsRepository';
|
||||
import { Sqlite3LidPNRepository } from '@waha/core/engines/noweb/store/sqlite3/Sqlite3LidPNRepository';
|
||||
import { Schema } from '@waha/core/storage/Schema';
|
||||
import Knex from 'knex';
|
||||
|
||||
import { INowebStorage } from '../INowebStorage';
|
||||
import { Migrations, NOWEB_STORE_SCHEMA } from '../schemas';
|
||||
@@ -14,70 +15,71 @@ import { Sqlite3ContactRepository } from './Sqlite3ContactRepository';
|
||||
import { Sqlite3MessagesRepository } from './Sqlite3MessagesRepository';
|
||||
import { Sqlite3SchemaValidation } from './Sqlite3SchemaValidation';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const Database = require('better-sqlite3');
|
||||
|
||||
export class Sqlite3Storage extends INowebStorage {
|
||||
private readonly db: any;
|
||||
private readonly tables: Schema[];
|
||||
private readonly knex: Knex.Knex;
|
||||
|
||||
constructor(filePath: string) {
|
||||
super();
|
||||
this.db = new Database(filePath);
|
||||
this.knex = Knex({
|
||||
client: 'better-sqlite3',
|
||||
connection: { filename: filePath },
|
||||
useNullAsDefault: true,
|
||||
});
|
||||
this.tables = NOWEB_STORE_SCHEMA;
|
||||
}
|
||||
|
||||
async init() {
|
||||
this.db.pragma('journal_mode = WAL;');
|
||||
this.migrate();
|
||||
this.validateSchema();
|
||||
await this.knex.raw('PRAGMA journal_mode = WAL;');
|
||||
await this.migrate();
|
||||
await this.validateSchema();
|
||||
}
|
||||
|
||||
private migrate() {
|
||||
this.migration0001init();
|
||||
private async migrate() {
|
||||
await this.migration0001init();
|
||||
}
|
||||
|
||||
private validateSchema() {
|
||||
private async validateSchema() {
|
||||
for (const table of this.tables) {
|
||||
new Sqlite3SchemaValidation(table, this.db).validate();
|
||||
await new Sqlite3SchemaValidation(table, this.knex).validate();
|
||||
}
|
||||
}
|
||||
|
||||
private migration0001init() {
|
||||
private async migration0001init() {
|
||||
for (const migration of Migrations) {
|
||||
this.db.exec(migration);
|
||||
await this.knex.raw(migration);
|
||||
}
|
||||
}
|
||||
|
||||
async close() {
|
||||
return this.db.close();
|
||||
return this.knex.destroy();
|
||||
}
|
||||
|
||||
getContactsRepository() {
|
||||
return new Sqlite3ContactRepository(this.db);
|
||||
return new Sqlite3ContactRepository(this.knex);
|
||||
}
|
||||
|
||||
getChatRepository() {
|
||||
return new Sqlite3ChatRepository(this.db);
|
||||
return new Sqlite3ChatRepository(this.knex);
|
||||
}
|
||||
|
||||
getGroupRepository() {
|
||||
return new Sqlite3GroupRepository(this.db);
|
||||
return new Sqlite3GroupRepository(this.knex);
|
||||
}
|
||||
|
||||
getLabelsRepository(): ILabelsRepository {
|
||||
return new Sqlite3LabelsRepository(this.db);
|
||||
return new Sqlite3LabelsRepository(this.knex);
|
||||
}
|
||||
|
||||
getLabelAssociationRepository(): ILabelAssociationRepository {
|
||||
return new Sqlite3LabelAssociationsRepository(this.db);
|
||||
return new Sqlite3LabelAssociationsRepository(this.knex);
|
||||
}
|
||||
|
||||
getMessagesRepository() {
|
||||
return new Sqlite3MessagesRepository(this.db);
|
||||
return new Sqlite3MessagesRepository(this.knex);
|
||||
}
|
||||
|
||||
getLidPNRepository(): INowebLidPNRepository {
|
||||
return new Sqlite3LidPNRepository(this.db);
|
||||
return new Sqlite3LidPNRepository(this.knex);
|
||||
}
|
||||
}
|
||||
@@ -119,4 +119,8 @@ export class WPage extends EventEmitter {
|
||||
this.page.on(event, listener);
|
||||
return this.page as any;
|
||||
}
|
||||
|
||||
get tracing() {
|
||||
return this.page.tracing;
|
||||
}
|
||||
}
|
||||
@@ -106,6 +106,7 @@ import {
|
||||
WAHAPresenceData,
|
||||
} from '@waha/structures/presence.dto';
|
||||
import { WAMessage, WAMessageReaction } from '@waha/structures/responses.dto';
|
||||
import { BrowserTraceQuery } from '@waha/structures/server.debug.dto';
|
||||
import { MeInfo } from '@waha/structures/sessions.dto';
|
||||
import { StatusRequest, TextStatus } from '@waha/structures/status.dto';
|
||||
import {
|
||||
@@ -117,7 +118,9 @@ import {
|
||||
import { PaginatorInMemory } from '@waha/utils/Paginator';
|
||||
import { sleep, waitUntil } from '@waha/utils/promiseTimeout';
|
||||
import { SingleDelayedJobRunner } from '@waha/utils/SingleDelayedJobRunner';
|
||||
import { TmpDir } from '@waha/utils/tmpdir';
|
||||
import * as lodash from 'lodash';
|
||||
import * as path from 'path';
|
||||
import { ProtocolError } from 'puppeteer';
|
||||
import { filter, fromEvent, merge, mergeMap, Observable, share } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
@@ -194,13 +197,19 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
|
||||
if (cacheType === 'local') {
|
||||
this.logger.info(`Using web version: '${webVersion}'`);
|
||||
}
|
||||
const args = this.getBrowserArgsForPuppeteer();
|
||||
// add at the start
|
||||
args.unshift(`--a-waha-timestamp=${new Date()}`);
|
||||
args.unshift(`--a-waha-session=${this.name}`);
|
||||
return {
|
||||
puppeteer: {
|
||||
headless: true,
|
||||
executablePath: this.getBrowserExecutablePath(),
|
||||
args: this.getBrowserArgsForPuppeteer(),
|
||||
args: args,
|
||||
dumpio: this.isDebugEnabled(),
|
||||
},
|
||||
userAgent:
|
||||
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36',
|
||||
webVersion: webVersion,
|
||||
webVersionCache: {
|
||||
type: cacheType,
|
||||
@@ -513,6 +522,23 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
|
||||
/**
|
||||
* START - Methods for API
|
||||
*/
|
||||
public async browserTrace(query: BrowserTraceQuery): Promise<string> {
|
||||
const tmpdir = new TmpDir(
|
||||
this.logger,
|
||||
`waha-browser-trace-${this.name}-`,
|
||||
(10 * query.seconds + 120) * 1000,
|
||||
);
|
||||
const page = this.whatsapp.pupPage;
|
||||
return await tmpdir.use(async (dir) => {
|
||||
this.logger.info({ query }, `Starting browser tracing...`);
|
||||
const filepath = path.join(dir, 'trace.json');
|
||||
await page.tracing.start({ path: filepath });
|
||||
await sleep(query.seconds * 1000);
|
||||
await page.tracing.stop();
|
||||
this.logger.info(`Browser tracing finished, saved to ${filepath}`);
|
||||
return filepath;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Auth methods
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import { UnprocessableEntityException } from '@nestjs/common';
|
||||
import {
|
||||
NotImplementedException,
|
||||
UnprocessableEntityException,
|
||||
} from '@nestjs/common';
|
||||
|
||||
export const DOCS_URL = 'https://waha.devlike.pro/';
|
||||
|
||||
export class NotImplementedByEngineError extends UnprocessableEntityException {
|
||||
export class NotImplementedByEngineError extends NotImplementedException {
|
||||
constructor(msg = '') {
|
||||
let error = 'The method is not implemented by the engine.';
|
||||
if (msg) {
|
||||
|
||||
@@ -4,8 +4,8 @@ import * as fsp from 'fs/promises';
|
||||
import * as path from 'path';
|
||||
import { Logger } from 'pino';
|
||||
import fs = require('fs');
|
||||
import del = require('del');
|
||||
import { fileExists } from '@waha/utils/files';
|
||||
import { deleteAsync } from 'del';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const writeFileAtomic = require('write-file-atomic');
|
||||
@@ -59,7 +59,7 @@ export class MediaLocalStorage implements IMediaStorage {
|
||||
}
|
||||
|
||||
if (fs.existsSync(this.filesFolder)) {
|
||||
del([`${this.filesFolder}/*`], { force: true }).then((paths) => {
|
||||
deleteAsync([`${this.filesFolder}/*`], { force: true }).then((paths) => {
|
||||
if (paths.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import Knex from 'knex';
|
||||
|
||||
import { DataStore } from '../abc/DataStore';
|
||||
|
||||
export abstract class LocalStore extends DataStore {
|
||||
@@ -23,5 +25,5 @@ export abstract class LocalStore extends DataStore {
|
||||
*/
|
||||
abstract getFilePath(session: string, file: string): string;
|
||||
|
||||
abstract getWAHADatabase(): any;
|
||||
abstract getWAHADatabase(): Knex.Knex;
|
||||
}
|
||||
@@ -1,18 +1,16 @@
|
||||
import { safeJoin } from '@waha/utils/files';
|
||||
import * as fs from 'fs/promises';
|
||||
import Knex from 'knex';
|
||||
import * as path from 'path';
|
||||
|
||||
import { LocalStore } from './LocalStore';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const Database = require('better-sqlite3');
|
||||
|
||||
export class LocalStoreCore extends LocalStore {
|
||||
protected readonly baseDirectory: string =
|
||||
process.env.WAHA_LOCAL_STORE_BASE_DIR || './.sessions';
|
||||
|
||||
private readonly engine: string;
|
||||
private db: any;
|
||||
private knex: Knex.Knex;
|
||||
|
||||
constructor(engine: string) {
|
||||
super();
|
||||
@@ -21,6 +19,11 @@ export class LocalStoreCore extends LocalStore {
|
||||
|
||||
async init(sessionName?: string) {
|
||||
await fs.mkdir(this.getEngineDirectory(), { recursive: true });
|
||||
if (!this.knex) {
|
||||
this.knex = this.buildKnex();
|
||||
await this.knex.raw('PRAGMA journal_mode = WAL;');
|
||||
await this.knex.raw('PRAGMA foreign_keys = ON;');
|
||||
}
|
||||
if (sessionName) {
|
||||
await fs.mkdir(this.getSessionDirectory(sessionName), {
|
||||
recursive: true,
|
||||
@@ -54,17 +57,24 @@ export class LocalStoreCore extends LocalStore {
|
||||
return safeJoin(this.getEngineDirectory(), name);
|
||||
}
|
||||
|
||||
getWAHADatabase(): any {
|
||||
if (!this.db) {
|
||||
const engineDir = this.getEngineDirectory();
|
||||
const database = safeJoin(engineDir, 'waha.sqlite3');
|
||||
this.db = new Database(database);
|
||||
this.db.pragma('journal_mode = WAL;');
|
||||
getWAHADatabase(): Knex.Knex {
|
||||
if (!this.knex) {
|
||||
throw new Error('Knex is not initialized, call LocalStore.init() first');
|
||||
}
|
||||
return this.db;
|
||||
return this.knex;
|
||||
}
|
||||
|
||||
buildKnex(): Knex.Knex {
|
||||
const engineDir = this.getEngineDirectory();
|
||||
const database = path.join(engineDir, 'waha.sqlite3');
|
||||
return Knex({
|
||||
client: 'better-sqlite3',
|
||||
connection: { filename: database },
|
||||
useNullAsDefault: true,
|
||||
});
|
||||
}
|
||||
|
||||
async close() {
|
||||
this.db?.close();
|
||||
await this.knex.destroy();
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
import Knex from 'knex';
|
||||
|
||||
export interface ISQLEngine {
|
||||
/**
|
||||
* Run a query that does not return any data
|
||||
*/
|
||||
run(query: Knex.QueryBuilder): Promise<void>;
|
||||
|
||||
/**
|
||||
* Get a single row from the database
|
||||
*/
|
||||
get(query: Knex.QueryBuilder): Promise<any | null>;
|
||||
|
||||
/**
|
||||
* Get all rows from the database
|
||||
*/
|
||||
all(query: Knex.QueryBuilder): Promise<any[]>;
|
||||
|
||||
/**
|
||||
* Run a raw SQL query with bindings
|
||||
*/
|
||||
raw(sql: string, bindings: any[]): Promise<void>;
|
||||
|
||||
/**
|
||||
* Execute a raw SQL query
|
||||
*/
|
||||
exec(sql: string): Promise<void>;
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
import { Field, Schema } from '@waha/core/storage/Schema';
|
||||
import { IJsonQuery } from '@waha/core/storage/sql/IJsonQuery';
|
||||
import { ISQLEngine } from '@waha/core/storage/sql/ISQLEngine';
|
||||
import { PaginationParams } from '@waha/structures/pagination.dto';
|
||||
import { KnexPaginator } from '@waha/utils/Paginator';
|
||||
import Knex from 'knex';
|
||||
import { Knex } from 'knex';
|
||||
import * as lodash from 'lodash';
|
||||
|
||||
export type Migration = string;
|
||||
@@ -26,10 +25,7 @@ export class SqlKVRepository<Entity> {
|
||||
return [];
|
||||
}
|
||||
|
||||
constructor(
|
||||
private engine: ISQLEngine,
|
||||
protected knex: Knex.Knex,
|
||||
) {}
|
||||
constructor(protected knex: Knex) {}
|
||||
|
||||
get columns(): Field[] {
|
||||
return this.schema.columns;
|
||||
@@ -49,7 +45,7 @@ export class SqlKVRepository<Entity> {
|
||||
|
||||
protected async applyMigrations() {
|
||||
for (const migration of this.migrations) {
|
||||
await this.engine.exec(migration);
|
||||
await this.knex.raw(migration);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,7 +115,7 @@ export class SqlKVRepository<Entity> {
|
||||
|
||||
async getCount(): Promise<number> {
|
||||
const query = this.select().count({ count: 'id' });
|
||||
const row = await this.engine.get(query);
|
||||
const row = await query.first();
|
||||
if (!row) {
|
||||
return 0;
|
||||
}
|
||||
@@ -138,7 +134,7 @@ export class SqlKVRepository<Entity> {
|
||||
return new Map();
|
||||
}
|
||||
|
||||
const rows = await this.engine.all(this.select().whereIn('id', ids));
|
||||
const rows = await this.select().whereIn('id', ids);
|
||||
const entitiesMap = new Map<string, Entity | null>();
|
||||
|
||||
// Initialize a map with null values for all requested IDs
|
||||
@@ -191,15 +187,15 @@ export class SqlKVRepository<Entity> {
|
||||
* SQL Implementation details
|
||||
*/
|
||||
public async raw(sql: string, bindings: any[]): Promise<void> {
|
||||
await this.engine.raw(sql, bindings);
|
||||
await this.knex.raw(sql, bindings);
|
||||
}
|
||||
|
||||
protected async run(query: Knex.QueryBuilder): Promise<void> {
|
||||
await this.engine.run(query);
|
||||
await query;
|
||||
}
|
||||
|
||||
protected async get(query: Knex.QueryBuilder): Promise<Entity | null> {
|
||||
const row = await this.engine.get(query);
|
||||
const row = await query.first();
|
||||
if (!row) {
|
||||
return null;
|
||||
}
|
||||
@@ -207,7 +203,7 @@ export class SqlKVRepository<Entity> {
|
||||
}
|
||||
|
||||
public async all(query: Knex.QueryBuilder): Promise<Entity[]> {
|
||||
const rows = await this.engine.all(query);
|
||||
const rows = await query;
|
||||
return rows.map((row) => this.parse(row));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
import { ISQLEngine } from '@waha/core/storage/sql/ISQLEngine';
|
||||
import { Database } from 'better-sqlite3';
|
||||
import { Knex } from 'knex';
|
||||
|
||||
export class Sqlite3Engine implements ISQLEngine {
|
||||
constructor(protected db: Database) {}
|
||||
|
||||
async all(query: Knex.QueryBuilder): Promise<any[]> {
|
||||
const sql = query.toSQL().sql;
|
||||
const bind = query.toSQL().bindings;
|
||||
return this.db.prepare(sql).all(bind);
|
||||
}
|
||||
|
||||
async get(query: Knex.QueryBuilder): Promise<any | null> {
|
||||
const sql = query.toSQL().sql;
|
||||
const bind = query.toSQL().bindings;
|
||||
const row: any = this.db.prepare(sql).get(bind);
|
||||
if (!row) {
|
||||
return null;
|
||||
}
|
||||
return row;
|
||||
}
|
||||
|
||||
async run(query: Knex.QueryBuilder): Promise<void> {
|
||||
const sql = query.toSQL().sql;
|
||||
const bind = query.toSQL().bindings;
|
||||
this.db.prepare(sql).run(bind);
|
||||
return;
|
||||
}
|
||||
|
||||
async raw(sql: string, bindings: any[]) {
|
||||
this.db.prepare(sql).run(bindings);
|
||||
}
|
||||
|
||||
async exec(sql): Promise<void> {
|
||||
this.db.exec(sql);
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,17 @@
|
||||
import { SqlKVRepository } from '@waha/core/storage/sql/SqlKVRepository';
|
||||
import { Sqlite3Engine } from '@waha/core/storage/sqlite3/Sqlite3Engine';
|
||||
import { Sqlite3JsonQuery } from '@waha/core/storage/sqlite3/Sqlite3JsonQuery';
|
||||
import { sleep } from '@waha/utils/promiseTimeout';
|
||||
import { Database } from 'better-sqlite3';
|
||||
import Knex from 'knex';
|
||||
|
||||
/**
|
||||
* Key value repository with extra metadata
|
||||
*/
|
||||
export class Sqlite3KVRepository<Entity> extends SqlKVRepository<Entity> {
|
||||
protected db: Database;
|
||||
protected knex: Knex.Knex;
|
||||
protected jsonQuery = new Sqlite3JsonQuery();
|
||||
|
||||
constructor(db: Database) {
|
||||
// sqlite does not support inserting default values. Set the `useNullAsDefault` flag to hide this warning. (see docs https://knexjs.org/guide/query-builder.html#insert).
|
||||
const knex = Knex({ client: 'better-sqlite3', useNullAsDefault: true });
|
||||
const engine = new Sqlite3Engine(db);
|
||||
super(engine, knex);
|
||||
this.db = db;
|
||||
constructor(knex: Knex.Knex) {
|
||||
super(knex);
|
||||
}
|
||||
|
||||
protected async upsertBatch(entities: Entity[]): Promise<void> {
|
||||
|
||||
@@ -23,8 +23,8 @@ export class Sqlite3SessionMeRepository
|
||||
}
|
||||
|
||||
constructor(store: LocalStore) {
|
||||
const db = store.getWAHADatabase();
|
||||
super(db);
|
||||
const knex = store.getWAHADatabase();
|
||||
super(knex);
|
||||
}
|
||||
|
||||
upsertMe(sessionName: string, me: MeInfo): Promise<void> {
|
||||
@@ -41,7 +41,7 @@ export class Sqlite3SessionMeRepository
|
||||
}
|
||||
|
||||
protected async validateSchema() {
|
||||
const validation = new Sqlite3SchemaValidation(this.schema, this.db);
|
||||
validation.validate();
|
||||
const validation = new Sqlite3SchemaValidation(this.schema, this.knex);
|
||||
await validation.validate();
|
||||
}
|
||||
}
|
||||
@@ -23,8 +23,8 @@ export class Sqlite3SessionWorkerRepository
|
||||
}
|
||||
|
||||
constructor(store: LocalStore) {
|
||||
const db = store.getWAHADatabase();
|
||||
super(db);
|
||||
const knex = store.getWAHADatabase();
|
||||
super(knex);
|
||||
}
|
||||
|
||||
assign(session: string, worker: string): Promise<void> {
|
||||
@@ -45,7 +45,7 @@ export class Sqlite3SessionWorkerRepository
|
||||
}
|
||||
|
||||
protected async validateSchema() {
|
||||
const validation = new Sqlite3SchemaValidation(this.schema, this.db);
|
||||
validation.validate();
|
||||
const validation = new Sqlite3SchemaValidation(this.schema, this.knex);
|
||||
await validation.validate();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { Transform, Type } from 'class-transformer';
|
||||
import { IsArray, IsNumber, IsOptional, IsString } from 'class-validator';
|
||||
|
||||
export class BrowserTraceQuery {
|
||||
@Type(() => Number)
|
||||
@IsNumber()
|
||||
@ApiProperty({
|
||||
description: 'How many seconds to trace',
|
||||
example: 30,
|
||||
required: true,
|
||||
})
|
||||
seconds: number = 30;
|
||||
|
||||
@IsArray()
|
||||
@IsString({ each: true })
|
||||
@Transform(({ value }) => (Array.isArray(value) ? value : [value]))
|
||||
@IsOptional()
|
||||
@ApiProperty({
|
||||
description: 'Categories to trace (all by default)',
|
||||
example: ['*'],
|
||||
required: true,
|
||||
})
|
||||
categories: string[] = ['*'];
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
import * as fs from 'fs/promises';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import { Logger } from 'pino';
|
||||
|
||||
function sanitize(input: string) {
|
||||
return input.replace(/[^a-zA-Z0-9-_]/g, '_');
|
||||
}
|
||||
|
||||
export class TmpDir {
|
||||
private readonly prefix: string;
|
||||
constructor(
|
||||
private logger: Logger,
|
||||
prefix: string,
|
||||
private cleanupTimeout = 10_000,
|
||||
) {
|
||||
this.prefix = sanitize(prefix);
|
||||
if (this.prefix.length > 249) {
|
||||
this.prefix = this.prefix.slice(0, 249);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a temporary directory and passes it to the callback.
|
||||
* The directory is automatically cleaned up after the callback returns.
|
||||
* @param callback Function that receives the temporary directory path
|
||||
* @returns The result of the callback
|
||||
*/
|
||||
public async use<T>(callback: (dir: string) => Promise<T>): Promise<T> {
|
||||
const dir = await fs.mkdtemp(path.join(os.tmpdir(), this.prefix));
|
||||
try {
|
||||
return await callback(dir);
|
||||
} finally {
|
||||
setTimeout(async () => {
|
||||
fs.rm(dir, { recursive: true, force: true })
|
||||
.then(() => {
|
||||
this.logger.trace(`Cleaned up temporary directory '${dir}'`);
|
||||
})
|
||||
.catch((err) => {
|
||||
this.logger.warn(
|
||||
`Failed to clean up temporary directory '${dir}': ${err.message}`,
|
||||
);
|
||||
});
|
||||
}, this.cleanupTimeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -33,7 +33,7 @@ export function getEngineName(): string {
|
||||
}
|
||||
|
||||
export const VERSION: WAHAEnvironment = {
|
||||
version: '2025.6.5',
|
||||
version: '2025.7.3',
|
||||
engine: getEngineName(),
|
||||
tier: getWAHAVersion(),
|
||||
browser:
|
||||
|
||||
@@ -4,4 +4,4 @@ http:
|
||||
allow-insecure: true
|
||||
no-follow-redirects: true
|
||||
timeout: 5000
|
||||
body: ['version']
|
||||
body: ['version']
|
||||
+2
-2
@@ -2,11 +2,11 @@
|
||||
"waha": {
|
||||
"gows": {
|
||||
"repo": "devlikeapro/gows",
|
||||
"ref": "v1.0.8"
|
||||
"ref": "v1.0.9"
|
||||
},
|
||||
"dashboard": {
|
||||
"repo": "devlikeapro/dashboard",
|
||||
"ref": "52750393583e215d212d22bc613d75c106add3a1"
|
||||
"ref": "fd8594d89ef369ed669c8b8b529ab29058c0d13c"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ __metadata:
|
||||
|
||||
"@adiwajshing/baileys@github:devlikeapro/Baileys#fork-master-2025-05-01":
|
||||
version: 6.7.16
|
||||
resolution: "@adiwajshing/baileys@https://github.com/devlikeapro/Baileys.git#commit=5835c558607cb85ff81a32ea93f12a4bd3e36648"
|
||||
resolution: "@adiwajshing/baileys@https://github.com/devlikeapro/Baileys.git#commit=17db13bd44d54e00d5740b002aca0b33c15b6e7b"
|
||||
dependencies:
|
||||
"@cacheable/node-cache": ^1.4.0
|
||||
"@hapi/boom": ^9.1.3
|
||||
@@ -34,7 +34,7 @@ __metadata:
|
||||
optional: true
|
||||
sharp:
|
||||
optional: true
|
||||
checksum: e90ede6bdfd1a79afe4a3f1946ba820f92796f06e13414106cdefbc0060a7e826a04b5d9f7ef47f4233e12e7f9130ace4dd3f80e1a754191a72b6650bd769410
|
||||
checksum: f89150418538cc3d11ed94da91ff5ba89a49b9a29c1d8a060fd8a211c3ab2e9cdf84c2f8bd3962e67835decc4fb78783dd8f1d297b8caf6d4b026dfa3bd42126
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -2665,6 +2665,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@sindresorhus/merge-streams@npm:^2.1.0":
|
||||
version: 2.3.0
|
||||
resolution: "@sindresorhus/merge-streams@npm:2.3.0"
|
||||
checksum: e989d53dee68d7e49b4ac02ae49178d561c461144cea83f66fa91ff012d981ad0ad2340cbd13f2fdb57989197f5c987ca22a74eb56478626f04e79df84291159
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@sinonjs/commons@npm:^3.0.0":
|
||||
version: 3.0.1
|
||||
resolution: "@sinonjs/commons@npm:3.0.1"
|
||||
@@ -4316,16 +4323,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"aggregate-error@npm:^3.0.0":
|
||||
version: 3.1.0
|
||||
resolution: "aggregate-error@npm:3.1.0"
|
||||
dependencies:
|
||||
clean-stack: ^2.0.0
|
||||
indent-string: ^4.0.0
|
||||
checksum: 1101a33f21baa27a2fa8e04b698271e64616b886795fd43c31068c07533c7b3facfcaf4e9e0cab3624bd88f729a592f1c901a1a229c9e490eafce411a8644b79
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ajv-formats@npm:3.0.1":
|
||||
version: 3.0.1
|
||||
resolution: "ajv-formats@npm:3.0.1"
|
||||
@@ -4624,13 +4621,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"array-union@npm:^2.1.0":
|
||||
version: 2.1.0
|
||||
resolution: "array-union@npm:2.1.0"
|
||||
checksum: 5bee12395cba82da674931df6d0fea23c4aa4660cb3b338ced9f828782a65caa232573e6bf3968f23e0c5eb301764a382cef2f128b170a9dc59de0e36c39f98d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"array.prototype.findlastindex@npm:^1.2.5":
|
||||
version: 1.2.6
|
||||
resolution: "array.prototype.findlastindex@npm:1.2.6"
|
||||
@@ -5516,13 +5506,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"clean-stack@npm:^2.0.0":
|
||||
version: 2.2.0
|
||||
resolution: "clean-stack@npm:2.2.0"
|
||||
checksum: 2ac8cd2b2f5ec986a3c743935ec85b07bc174d5421a5efc8017e1f146a1cf5f781ae962618f416352103b32c9cd7e203276e8c28241bbe946160cab16149fb68
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"cli-boxes@npm:^2.2.1":
|
||||
version: 2.2.1
|
||||
resolution: "cli-boxes@npm:2.2.1"
|
||||
@@ -6140,19 +6123,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"del@npm:^6.0.0":
|
||||
version: 6.1.1
|
||||
resolution: "del@npm:6.1.1"
|
||||
"del@npm:^8.0.0":
|
||||
version: 8.0.0
|
||||
resolution: "del@npm:8.0.0"
|
||||
dependencies:
|
||||
globby: ^11.0.1
|
||||
graceful-fs: ^4.2.4
|
||||
is-glob: ^4.0.1
|
||||
is-path-cwd: ^2.2.0
|
||||
is-path-inside: ^3.0.2
|
||||
p-map: ^4.0.0
|
||||
rimraf: ^3.0.2
|
||||
slash: ^3.0.0
|
||||
checksum: 563288b73b8b19a7261c47fd21a330eeab6e2acd7c6208c49790dfd369127120dd7836cdf0c1eca216b77c94782a81507eac6b4734252d3bef2795cb366996b6
|
||||
globby: ^14.0.2
|
||||
is-glob: ^4.0.3
|
||||
is-path-cwd: ^3.0.0
|
||||
is-path-inside: ^4.0.0
|
||||
p-map: ^7.0.2
|
||||
slash: ^5.1.0
|
||||
checksum: 502dea7a846f989e1d921733f5d41ae4ae9b3eff168d335bfc050c9ce938ddc46198180be133814269268c4b0aed441a82fbace948c0ec5eed4ed086a4ad3b0e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -6226,15 +6207,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"dir-glob@npm:^3.0.1":
|
||||
version: 3.0.1
|
||||
resolution: "dir-glob@npm:3.0.1"
|
||||
dependencies:
|
||||
path-type: ^4.0.0
|
||||
checksum: fa05e18324510d7283f55862f3161c6759a3f2f8dbce491a2fc14c8324c498286c54282c1f0e933cb930da8419b30679389499b919122952a4f8592362ef4615
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"doctrine@npm:^2.1.0":
|
||||
version: 2.1.0
|
||||
resolution: "doctrine@npm:2.1.0"
|
||||
@@ -7074,7 +7046,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"fast-glob@npm:^3.2.9, fast-glob@npm:^3.3.2":
|
||||
"fast-glob@npm:^3.3.2, fast-glob@npm:^3.3.3":
|
||||
version: 3.3.3
|
||||
resolution: "fast-glob@npm:3.3.3"
|
||||
dependencies:
|
||||
@@ -7701,6 +7673,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"glob@npm:^9.2.0":
|
||||
version: 9.3.5
|
||||
resolution: "glob@npm:9.3.5"
|
||||
dependencies:
|
||||
fs.realpath: ^1.0.0
|
||||
minimatch: ^8.0.2
|
||||
minipass: ^4.2.4
|
||||
path-scurry: ^1.6.1
|
||||
checksum: 94b093adbc591bc36b582f77927d1fb0dbf3ccc231828512b017601408be98d1fe798fc8c0b19c6f2d1a7660339c3502ce698de475e9d938ccbb69b47b647c84
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"globals@npm:^11.1.0":
|
||||
version: 11.12.0
|
||||
resolution: "globals@npm:11.12.0"
|
||||
@@ -7727,17 +7711,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"globby@npm:^11.0.1":
|
||||
version: 11.1.0
|
||||
resolution: "globby@npm:11.1.0"
|
||||
"globby@npm:^14.0.2":
|
||||
version: 14.1.0
|
||||
resolution: "globby@npm:14.1.0"
|
||||
dependencies:
|
||||
array-union: ^2.1.0
|
||||
dir-glob: ^3.0.1
|
||||
fast-glob: ^3.2.9
|
||||
ignore: ^5.2.0
|
||||
merge2: ^1.4.1
|
||||
slash: ^3.0.0
|
||||
checksum: b4be8885e0cfa018fc783792942d53926c35c50b3aefd3fdcfb9d22c627639dc26bd2327a40a0b74b074100ce95bb7187bfeae2f236856aa3de183af7a02aea6
|
||||
"@sindresorhus/merge-streams": ^2.1.0
|
||||
fast-glob: ^3.3.3
|
||||
ignore: ^7.0.3
|
||||
path-type: ^6.0.0
|
||||
slash: ^5.1.0
|
||||
unicorn-magic: ^0.3.0
|
||||
checksum: b1f27dccc999c010ee7e0ce7c6581fd2326ac86cf0508474d526d699a029b66b35d6fa4361c8b4ad8e80809582af71d5e2080e671cf03c26e98ca67aba8834bd
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -7990,14 +7974,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ignore@npm:^5.2.0":
|
||||
version: 5.3.2
|
||||
resolution: "ignore@npm:5.3.2"
|
||||
checksum: 2acfd32a573260ea522ea0bfeff880af426d68f6831f973129e2ba7363f422923cf53aab62f8369cbf4667c7b25b6f8a3761b34ecdb284ea18e87a5262a865be
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ignore@npm:^7.0.0":
|
||||
"ignore@npm:^7.0.0, ignore@npm:^7.0.3":
|
||||
version: 7.0.5
|
||||
resolution: "ignore@npm:7.0.5"
|
||||
checksum: d0862bf64d3d58bf34d5fb0a9f725bec9ca5ce8cd1aecc8f28034269e8f69b8009ffd79ca3eda96962a6a444687781cd5efdb8c7c8ddc0a6996e36d31c217f14
|
||||
@@ -8033,13 +8010,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"indent-string@npm:^4.0.0":
|
||||
version: 4.0.0
|
||||
resolution: "indent-string@npm:4.0.0"
|
||||
checksum: 824cfb9929d031dabf059bebfe08cf3137365e112019086ed3dcff6a0a7b698cb80cf67ccccde0e25b9e2d7527aa6cc1fed1ac490c752162496caba3e6699612
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"inflight@npm:^1.0.4":
|
||||
version: 1.0.6
|
||||
resolution: "inflight@npm:1.0.6"
|
||||
@@ -8298,17 +8268,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"is-path-cwd@npm:^2.2.0":
|
||||
version: 2.2.0
|
||||
resolution: "is-path-cwd@npm:2.2.0"
|
||||
checksum: 46a840921bb8cc0dc7b5b423a14220e7db338072a4495743a8230533ce78812dc152548c86f4b828411fe98c5451959f07cf841c6a19f611e46600bd699e8048
|
||||
"is-path-cwd@npm:^3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "is-path-cwd@npm:3.0.0"
|
||||
checksum: bc34d13b6a03dfca4a3ab6a8a5ba78ae4b24f4f1db4b2b031d2760c60d0913bd16a4b980dcb4e590adfc906649d5f5132684079a3972bd219da49deebb9adea8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"is-path-inside@npm:^3.0.2":
|
||||
version: 3.0.3
|
||||
resolution: "is-path-inside@npm:3.0.3"
|
||||
checksum: abd50f06186a052b349c15e55b182326f1936c89a78bf6c8f2b707412517c097ce04bc49a0ca221787bc44e1049f51f09a2ffb63d22899051988d3a618ba13e9
|
||||
"is-path-inside@npm:^4.0.0":
|
||||
version: 4.0.0
|
||||
resolution: "is-path-inside@npm:4.0.0"
|
||||
checksum: 8810fa11c58e6360b82c3e0d6cd7d9c7d0392d3ac9eb10f980b81f9839f40ac6d1d6d6f05d069db0d227759801228f0b072e1b6c343e4469b065ab5fe0b68fe5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -9552,7 +9522,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"merge2@npm:^1.3.0, merge2@npm:^1.4.1":
|
||||
"merge2@npm:^1.3.0":
|
||||
version: 1.4.1
|
||||
resolution: "merge2@npm:1.4.1"
|
||||
checksum: 7268db63ed5169466540b6fb947aec313200bcf6d40c5ab722c22e242f651994619bcd85601602972d3c85bd2cc45a358a4c61937e9f11a061919a1da569b0c2
|
||||
@@ -9667,6 +9637,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"minimatch@npm:^8.0.2":
|
||||
version: 8.0.4
|
||||
resolution: "minimatch@npm:8.0.4"
|
||||
dependencies:
|
||||
brace-expansion: ^2.0.1
|
||||
checksum: 2e46cffb86bacbc524ad45a6426f338920c529dd13f3a732cc2cf7618988ee1aae88df4ca28983285aca9e0f45222019ac2d14ebd17c1edadd2ee12221ab801a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"minimatch@npm:^9.0.4":
|
||||
version: 9.0.5
|
||||
resolution: "minimatch@npm:9.0.5"
|
||||
@@ -9743,6 +9722,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"minipass@npm:^4.2.4":
|
||||
version: 4.2.8
|
||||
resolution: "minipass@npm:4.2.8"
|
||||
checksum: 7f4914d5295a9a30807cae5227a37a926e6d910c03f315930fde52332cf0575dfbc20295318f91f0baf0e6bb11a6f668e30cde8027dea7a11b9d159867a3c830
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"minipass@npm:^5.0.0":
|
||||
version: 5.0.0
|
||||
resolution: "minipass@npm:5.0.0"
|
||||
@@ -10344,15 +10330,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"p-map@npm:^4.0.0":
|
||||
version: 4.0.0
|
||||
resolution: "p-map@npm:4.0.0"
|
||||
dependencies:
|
||||
aggregate-error: ^3.0.0
|
||||
checksum: cb0ab21ec0f32ddffd31dfc250e3afa61e103ef43d957cc45497afe37513634589316de4eb88abdfd969fe6410c22c0b93ab24328833b8eb1ccc087fc0442a1c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"p-map@npm:^7.0.2":
|
||||
version: 7.0.3
|
||||
resolution: "p-map@npm:7.0.3"
|
||||
@@ -10503,7 +10480,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"path-scurry@npm:^1.11.1":
|
||||
"path-scurry@npm:^1.11.1, path-scurry@npm:^1.6.1":
|
||||
version: 1.11.1
|
||||
resolution: "path-scurry@npm:1.11.1"
|
||||
dependencies:
|
||||
@@ -10544,6 +10521,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"path-type@npm:^6.0.0":
|
||||
version: 6.0.0
|
||||
resolution: "path-type@npm:6.0.0"
|
||||
checksum: b9f6eaf7795c48d5c9bc4c6bc3ac61315b8d36975a73497ab2e02b764c0836b71fb267ea541863153f633a069a1c2ed3c247cb781633842fc571c655ac57c00e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"pause@npm:0.0.1":
|
||||
version: 0.0.1
|
||||
resolution: "pause@npm:0.0.1"
|
||||
@@ -11482,6 +11466,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"rimraf@npm:^4.3.0":
|
||||
version: 4.4.1
|
||||
resolution: "rimraf@npm:4.4.1"
|
||||
dependencies:
|
||||
glob: ^9.2.0
|
||||
bin:
|
||||
rimraf: dist/cjs/src/bin.js
|
||||
checksum: b786adc02651e2e24bbedb04bbdea80652fc9612632931ff2d9f898c5e4708fe30956186597373c568bd5230a4dc2fadfc816ccacba8a1daded3a006a6b74f1a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"router@npm:^2.2.0":
|
||||
version: 2.2.0
|
||||
resolution: "router@npm:2.2.0"
|
||||
@@ -11925,6 +11920,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"slash@npm:^5.1.0":
|
||||
version: 5.1.0
|
||||
resolution: "slash@npm:5.1.0"
|
||||
checksum: 70434b34c50eb21b741d37d455110258c42d2cf18c01e6518aeb7299f3c6e626330c889c0c552b5ca2ef54a8f5a74213ab48895f0640717cacefeef6830a1ba4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"slice-ansi@npm:^2.1.0":
|
||||
version: 2.1.0
|
||||
resolution: "slice-ansi@npm:2.1.0"
|
||||
@@ -13057,6 +13059,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"unicorn-magic@npm:^0.3.0":
|
||||
version: 0.3.0
|
||||
resolution: "unicorn-magic@npm:0.3.0"
|
||||
checksum: bdd7d7c522f9456f32a0b77af23f8854f9a7db846088c3868ec213f9550683ab6a2bdf3803577eacbafddb4e06900974385841ccb75338d17346ccef45f9cb01
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"unique-filename@npm:^4.0.0":
|
||||
version: 4.0.0
|
||||
resolution: "unique-filename@npm:4.0.0"
|
||||
@@ -13248,7 +13257,7 @@ __metadata:
|
||||
chokidar: ^3.6.0
|
||||
class-transformer: ^0.5.1
|
||||
class-validator: 0.14.0
|
||||
del: ^6.0.0
|
||||
del: ^8.0.0
|
||||
eslint: 7.7.0
|
||||
eslint-config-prettier: ^6.10.0
|
||||
eslint-plugin-import: ^2.20.1
|
||||
@@ -13279,11 +13288,11 @@ __metadata:
|
||||
pretty-bytes: 5.6.0
|
||||
promise-retry: ^2.0.1
|
||||
protoc-gen-ts: ^0.8.7
|
||||
puppeteer: ^23.6.0
|
||||
puppeteer: ^24.10.0
|
||||
qrcode: ^1.5.1
|
||||
qrcode-terminal: ^0.12.0
|
||||
reflect-metadata: ^0.1.13
|
||||
rimraf: ^3.0.2
|
||||
rimraf: ^4.3.0
|
||||
rxjs: ^7.8.1
|
||||
sharp: ^0.33.4
|
||||
supertest: ^4.0.2
|
||||
@@ -13390,7 +13399,7 @@ __metadata:
|
||||
|
||||
"whatsapp-web.js@github:devlikeapro/whatsapp-web.js#fork-main-2025-06-09":
|
||||
version: 1.30.1-alpha.2
|
||||
resolution: "whatsapp-web.js@https://github.com/devlikeapro/whatsapp-web.js.git#commit=f0e8284c9a281fa15ce2086d5668c02011947416"
|
||||
resolution: "whatsapp-web.js@https://github.com/devlikeapro/whatsapp-web.js.git#commit=c133ae4a347ba7b21b647c8c6811f58c55b21069"
|
||||
dependencies:
|
||||
"@pedroslopez/moduleraid": ^5.0.2
|
||||
archiver: ^5.3.1
|
||||
@@ -13408,7 +13417,7 @@ __metadata:
|
||||
optional: true
|
||||
unzipper:
|
||||
optional: true
|
||||
checksum: ad0b97ac3b5246801af33e4e7cc34ce34b8541a3737bb97f53322f4612b8eb435eec2b47a6ef9f7f794649324d70041e3f6f6f5453be8d4b74da0051334ee98e
|
||||
checksum: e99e0c5172e4045098ef0cd027304b1f5d37b6ce1ae00f1b50f0ca59e5a0894faeca9972e7db88f1d0e6aebb3ca67c3d3cac333f594ab31ffeb166414e4eeb19
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
Reference in new issue
Block a user