Compare commits

...
15 Commits
Author SHA1 Message Date
devlikepro 8f867e0b5d [core] 2026.1.2
Release / WEBJS - chrome - amd64 - chrome (push) Waiting to run
Release / WEBJS - chromium - amd64 - latest (push) Waiting to run
Release / WEBJS - chromium - linux/arm64 - arm (push) Waiting to run
Release / GOWS - none - amd64 - gows (push) Waiting to run
Release / GOWS - none - linux/arm64 - gows-arm (push) Waiting to run
Release / NOWEB - none - amd64 - noweb (push) Waiting to run
Release / NOWEB - none - linux/arm64 - noweb-arm (push) Waiting to run
2026-01-12 16:52:10 +07:00
devlikepro d4f6ec18fd [core] GOWS - receive and send video note
fix #1798
2026-01-12 16:52:10 +07:00
devlikepro ac05dd83e9 [core] NOWEB - handle video note media 2026-01-12 16:50:35 +07:00
devlikepro 17c22f0cd4 [core] Up WEBSJ - fix send media to channels
fix #1775
2026-01-12 16:50:34 +07:00
devlikepro 971979c13f [core] Do not send double session.status
fix #1784
2026-01-12 16:50:34 +07:00
devlikepro 845e203637 [core] GOWS - stop sessions first, then grpc
fix #1784
2026-01-12 16:50:34 +07:00
devlikepro 7a2e1cd731 [core] GOWS - start session in the background 2026-01-12 16:50:34 +07:00
devlikepro 84ba011a4c [core] Up GOWS - add profiling 2026-01-12 16:50:33 +07:00
devlikepro 50399f1192 [core] Add associatedChildMessage to edited message
fix #1773
2026-01-12 16:50:33 +07:00
devlikepro a2517b248d [core] ChatWoot - handle not found app
fix #1290
fix #1790
2026-01-12 16:50:33 +07:00
devlikepro f02d95331a [core] ChatWoot - support @lid mention directly
fix #1767
closes devlikeapro/waha-plus#36
2026-01-12 16:50:32 +07:00
Berg Pinheiro cb1faff88c [core] ChatWoot - support @mention and @all in group messages
fix #1767
closes devlikeapro/waha-plus#36
2026-01-12 16:50:32 +07:00
devlikepro 3ff1c06eea [core] ChatWoot - add session info api in client 2026-01-12 16:50:32 +07:00
devlikepro c91d2c59eb [core] ChatWoot - add group participants api in client 2026-01-12 16:50:32 +07:00
devlikepro 4cf5a74d23 [core] Groups - allow @all be with other mentions - we resolve group participants anyway 2026-01-12 16:50:32 +07:00
20 changed files with 317 additions and 32 deletions

No files matched your search

+19
View File
@@ -146,6 +146,17 @@ export class WAHASelf {
.then((response) => response.data);
}
async getGroupParticipants(
session: string,
groupId: string,
opts?: RequestOptions,
) {
const url = `/api/${session}/groups/${groupId}/participants/v2`;
return await this.client
.get(url, { signal: opts?.signal })
.then((response) => response.data);
}
async getChannel(
session: string,
channelId: string,
@@ -371,6 +382,10 @@ export class WAHASessionAPI {
return this.api.getGroup(this.session, groupId, opts);
}
getGroupParticipants(groupId: string, opts?: RequestOptions): Promise<any> {
return this.api.getGroupParticipants(this.session, groupId, opts);
}
getChannel(channelId: string, opts?: RequestOptions): Promise<Channel> {
return this.api.getChannel(this.session, channelId, opts);
}
@@ -459,4 +474,8 @@ export class WAHASessionAPI {
findLIDByPN(pn: string, opts?: RequestOptions) {
return this.api.findLIDByPN(this.session, pn, opts);
}
getSessionInfo(opts?: RequestOptions) {
return this.api.get(this.session, opts);
}
}
+10 -1
View File
@@ -8,6 +8,7 @@ import { InboxData } from '@waha/apps/chatwoot/consumers/types';
import { DIContainer } from '@waha/apps/chatwoot/di/DIContainer';
import {
ChatIDNotFoundForContactError,
ChatWootAppNotFoundError,
PhoneNumberNotFoundInWhatsAppError,
} from '@waha/apps/chatwoot/errors';
import { WAHASessionAPI } from '@waha/apps/app_sdk/waha/WAHASelf';
@@ -43,7 +44,11 @@ export abstract class ChatWootInboxMessageConsumer extends AppConsumer {
const knex = this.manager.store.getWAHADatabase();
this.appRepository = new AppRepository(knex);
const logger = new JobLoggerWrapper(job, this.logger);
const app = await this.appRepository.getById(appId);
const app = await this.appRepository.findEnabledAppById(appId);
if (!app) {
logger.warn(`Chatwoot app not found or disabled: ${appId}`);
throw new ChatWootAppNotFoundError(appId);
}
return new DIContainer(app.pk, app.config, logger, knex);
}
@@ -86,6 +91,10 @@ export abstract class ChatWootInboxMessageConsumer extends AppConsumer {
await this.ReportErrorRecovered(job, body);
return result;
} catch (err) {
if (err instanceof ChatWootAppNotFoundError) {
this.logger.warn(err.message);
throw err;
}
await this.ReportErrorForMessage(job, err, body);
throw err;
}
@@ -16,6 +16,7 @@ import {
MessageMappingService,
} from '@waha/apps/chatwoot/storage';
import { MarkdownToWhatsApp } from '@waha/apps/chatwoot/messages/to/whatsapp/markdown';
import { parseMentionsFromText } from '@waha/apps/chatwoot/messages/to/whatsapp/mentions';
import { SessionManager } from '@waha/core/abc/manager.abc';
import { RMutexService } from '@waha/modules/rmutex/rmutex.service';
import {
@@ -36,6 +37,7 @@ import {
LinkPreview,
} from '@waha/apps/chatwoot/dto/config.dto';
import { Locale } from '@waha/apps/chatwoot/i18n/locale';
import { isJidGroup } from '@waha/core/utils/jids';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const mime = require('mime-types');
@@ -90,7 +92,16 @@ export class MessageHandler {
return;
}
const content = MarkdownToWhatsApp(message.content);
let content: string = message.content;
let mentions: null | string[] = null;
if (isJidGroup(chatId)) {
// Parse any mention in the text and get a new clean text if required
const parsed = parseMentionsFromText(message.content);
content = parsed.text;
mentions = parsed.mentions;
}
content = MarkdownToWhatsApp(content);
const results = [];
let part = 0; // Start from 0 and increment before each send/check
const replyTo = await this.getReplyTo(message).catch((err) => {
@@ -116,7 +127,7 @@ export class MessageHandler {
content: content,
chatwoot: body,
});
const msg = await this.sendTextMessage(chatId, text, replyTo);
const msg = await this.sendTextMessage(chatId, text, replyTo, mentions);
results.push(msg);
await this.saveMapping(message, msg, part);
this.logger.info(`Text message sent: ${msg.id}`);
@@ -139,7 +150,7 @@ export class MessageHandler {
chatwoot: body,
singleAttachment: attachments.length == 1,
});
const msg = await this.sendFile(chatId, caption, file, replyTo);
const msg = await this.sendFile(chatId, caption, replyTo, mentions, file);
this.logger.info(
`File message sent: ${msg.id} - ${file.data_url} - ${file.file_type}`,
);
@@ -196,6 +207,7 @@ export class MessageHandler {
chatId: string,
content: string,
replyTo: string,
mentions: string[] | null,
) {
const request: MessageTextRequest = {
session: '',
@@ -206,6 +218,7 @@ export class MessageHandler {
this.config.linkPreview,
),
linkPreviewHighQuality: this.config.linkPreview == LinkPreview.HQ,
mentions: mentions,
};
const session = this.session;
await session.readMessages(chatId);
@@ -219,8 +232,9 @@ export class MessageHandler {
private async sendFile(
chatId: string,
content: string,
file: MessageAttachment,
replyTo: string,
mentions: string[] | null,
file: MessageAttachment,
) {
const url = file.data_url;
let filename = url.split('/').pop();
@@ -245,6 +259,7 @@ export class MessageHandler {
url: url,
mimetype: mimetype,
},
mentions: mentions,
};
return session.sendImage(imageRequest);
case 'video':
@@ -262,6 +277,7 @@ export class MessageHandler {
filename: filename,
},
convert: true,
mentions: mentions,
};
return session.sendVideo(videoRequest);
case 'audio':
@@ -288,6 +304,7 @@ export class MessageHandler {
url: url,
mimetype: mimetype,
},
mentions: mentions,
};
return session.sendFile(fileRequest);
}
+10 -1
View File
@@ -11,6 +11,7 @@ import { PinoLogger } from 'nestjs-pino';
import { AppRepository } from '../../storage';
import { TKey } from '@waha/apps/chatwoot/i18n/templates';
import { ChatWootAppNotFoundError } from '@waha/apps/chatwoot/errors';
/**
* Base class for ChatWoot scheduled consumers
@@ -35,7 +36,11 @@ export abstract class ChatWootScheduledConsumer extends AppConsumer {
const knex = this.manager.store.getWAHADatabase();
this.appRepository = new AppRepository(knex);
const logger = new JobLoggerWrapper(job, this.logger);
const app = await this.appRepository.getById(appId);
const app = await this.appRepository.findEnabledAppById(appId);
if (!app) {
logger.warn(`Chatwoot app not found or disabled: ${appId}`);
throw new ChatWootAppNotFoundError(appId);
}
return new DIContainer(app.pk, app.config, logger, knex);
}
@@ -62,6 +67,10 @@ export abstract class ChatWootScheduledConsumer extends AppConsumer {
await this.ReportErrorRecovered(job);
return result;
} catch (err) {
if (err instanceof ChatWootAppNotFoundError) {
this.logger.warn(err.message);
throw err;
}
await this.ReportErrorForJob(job, err);
throw err;
}
+10 -1
View File
@@ -13,6 +13,7 @@ import { AppRepository } from '../../storage';
import { TKey } from '@waha/apps/chatwoot/i18n/templates';
import { SignalRace } from '@waha/utils/abortable';
import { IsCommandsChat } from '@waha/apps/chatwoot/client/ids';
import { ChatWootAppNotFoundError } from '@waha/apps/chatwoot/errors';
/**
* Base class for ChatWoot background task consumers
@@ -36,7 +37,11 @@ export abstract class ChatWootTaskConsumer extends AppConsumer {
const knex = this.manager.store.getWAHADatabase();
this.appRepository = new AppRepository(knex);
const logger = new JobLoggerWrapper(job, this.logger);
const app = await this.appRepository.getById(appId);
const app = await this.appRepository.findEnabledAppById(appId);
if (!app) {
logger.warn(`Chatwoot app not found or disabled: ${appId}`);
throw new ChatWootAppNotFoundError(appId);
}
return new DIContainer(app.pk, app.config, logger, knex);
}
@@ -68,6 +73,10 @@ export abstract class ChatWootTaskConsumer extends AppConsumer {
await this.ReportErrorRecovered(job);
return result;
} catch (err) {
if (err instanceof ChatWootAppNotFoundError) {
this.logger.warn(err.message);
throw err;
}
this.ReportErrorForJob(job, err).catch((exc) =>
this.logger.error(`Failed to report error for job ${job.id}: ${exc}`),
);
+10 -1
View File
@@ -12,6 +12,7 @@ import { WhatsAppChatIdKey } from '@waha/apps/chatwoot/consumers/mutex';
import { EventData } from '@waha/apps/chatwoot/consumers/types';
import { WhatsAppContactInfo } from '@waha/apps/chatwoot/contacts/WhatsAppContactInfo';
import { DIContainer } from '@waha/apps/chatwoot/di/DIContainer';
import { ChatWootAppNotFoundError } from '@waha/apps/chatwoot/errors';
import { Locale } from '@waha/apps/chatwoot/i18n/locale';
import { WAHASelf, WAHASessionAPI } from '@waha/apps/app_sdk/waha/WAHASelf';
import {
@@ -83,6 +84,10 @@ export abstract class ChatWootWAHABaseConsumer extends AppConsumer {
await this.ReportErrorRecovered(errorReportInfo, job);
return result;
} catch (err) {
if (err instanceof ChatWootAppNotFoundError) {
this.logger.warn(err.message);
throw err;
}
await this.ReportErrorForMessage(errorReportInfo, job, err);
throw err;
}
@@ -95,7 +100,11 @@ export abstract class ChatWootWAHABaseConsumer extends AppConsumer {
const knex = this.manager.store.getWAHADatabase();
this.appRepository = new AppRepository(knex);
const logger = new JobLoggerWrapper(job, this.logger);
const app = await this.appRepository.getById(appId);
const app = await this.appRepository.findEnabledAppById(appId);
if (!app) {
logger.warn(`Chatwoot app not found or disabled: ${appId}`);
throw new ChatWootAppNotFoundError(appId);
}
return new DIContainer(app.pk, app.config, logger, knex);
}
@@ -45,6 +45,12 @@ export class ChatWootErrorReporter {
// There's retries more left - ignore it for now
return;
}
if (!conversation) {
this.logger.error(
'Chatwoot error report skipped: conversation not ready',
);
return;
}
const attempts = {
current: this.job.attemptsMade + 1,
max: this.job.opts?.attempts || 1,
@@ -87,6 +93,12 @@ export class ChatWootErrorReporter {
// https://github.com/devlikeapro/waha/issues/1395
return null;
if (!conversation) {
this.logger.warn(
'Chatwoot success report skipped: conversation not ready',
);
return;
}
const template = this.l.key(TKey.JOB_REPORT_SUCCEEDED);
const attempts = {
current: this.job.attemptsMade + 1,
+6
View File
@@ -15,3 +15,9 @@ export class UnknownJIDFormat extends Error {
super(`WhatsApp Chat ID is not recognized: ${jid}`);
}
}
export class ChatWootAppNotFoundError extends Error {
constructor(public appId: string) {
super(`Chatwoot app not found or disabled: ${appId}`);
}
}
@@ -0,0 +1,115 @@
import { parseMentionsFromText } from './mentions';
describe('parseMentionsFromText', () => {
it('returns null mentions when none exist', () => {
const input = 'Hello there';
expect(parseMentionsFromText(input)).toEqual({
text: 'Hello there',
mentions: null,
});
});
it('parses @all and removes it from the text', () => {
const input = 'Hello @all';
expect(parseMentionsFromText(input)).toEqual({
text: 'Hello',
mentions: ['all'],
});
});
it('parses @ALL case-insensitively', () => {
const input = 'Hello @ALL';
expect(parseMentionsFromText(input)).toEqual({
text: 'Hello',
mentions: ['all'],
});
});
it('uses a fallback text when only @all is present', () => {
const input = '@all';
expect(parseMentionsFromText(input)).toEqual({
text: ' ',
mentions: ['all'],
});
});
it('parses phone number mentions with a suffix', () => {
const input = 'Ping @558591203123';
expect(parseMentionsFromText(input)).toEqual({
text: 'Ping @558591203123',
mentions: ['558591203123@c.us'],
});
});
it('deduplicates phone number mentions', () => {
const input = 'Hi @1111111 and @1111111';
expect(parseMentionsFromText(input)).toEqual({
text: 'Hi @1111111 and @1111111',
mentions: ['1111111@c.us'],
});
});
it('handles @all alongside phone mentions', () => {
const input = '@all Hi @558591203123';
expect(parseMentionsFromText(input)).toEqual({
text: 'Hi @558591203123',
mentions: ['all', '558591203123@c.us'],
});
});
it('ignores quoted @all text', () => {
const input = "You can send '@all' to chat";
expect(parseMentionsFromText(input)).toEqual({
text: "You can send '@all' to chat",
mentions: null,
});
});
it('ignores email-like mentions', () => {
const input = 'Reach us at email@12341domain.com';
expect(parseMentionsFromText(input)).toEqual({
text: 'Reach us at email@12341domain.com',
mentions: null,
});
});
it('ignores @all when followed by letters', () => {
const input = 'Please ping @allx';
expect(parseMentionsFromText(input)).toEqual({
text: 'Please ping @allx',
mentions: null,
});
});
it('ignores phone mentions followed by letters', () => {
const input = 'Call @1234567abc';
expect(parseMentionsFromText(input)).toEqual({
text: 'Call @1234567abc',
mentions: null,
});
});
it('ignores @all inside email-like text', () => {
const input = 'Contact email@alldomain.com for details';
expect(parseMentionsFromText(input)).toEqual({
text: 'Contact email@alldomain.com for details',
mentions: null,
});
});
it('accepts phone mentions with trailing punctuation', () => {
const input = 'Ping @1231234, then @5555555.';
expect(parseMentionsFromText(input)).toEqual({
text: 'Ping @1231234, then @5555555.',
mentions: ['1231234@c.us', '5555555@c.us'],
});
});
it('parses @lid mentions without c.us suffix', () => {
const input = 'Notify @123123@lid now';
expect(parseMentionsFromText(input)).toEqual({
text: 'Notify @123123@lid now',
mentions: ['123123@lid'],
});
});
});
@@ -0,0 +1,79 @@
import { ensureSuffix } from '@waha/core/abc/session.abc';
import { isJidGroup } from '@waha/core/utils/jids';
export interface ParsedMentions {
text: string;
mentions?: string[];
}
/**
* Parse mentions from text message
* Supports:
* - @all - mentions all group participants
* - @558591203123 - mentions specific phone number
*
* @param text - The message text
* @returns Parsed mentions with cleaned text
*/
export function parseMentionsFromText(text: string): ParsedMentions {
const mentions: string[] = [];
let content = text;
// Regex to match @all (case-insensitive, word boundary)
// Use separate regex instances to avoid lastIndex issues with global flag
const allRegexTest = /(^|\s)@all\b/gi;
if (allRegexTest.test(text)) {
mentions.push('all');
// Remove @all from text - WAHA endpoint doesn't display it, only mentions all participants
// Create a new regex instance for replace to avoid lastIndex issues
const allRegexReplace = /(^|\s)@all\b/gi;
content = content.replace(allRegexReplace, '$1').trim();
}
const lidRegex = /(^|\s)@(\d{6,15})@lid\b/g;
const lidMatches = text.matchAll(lidRegex);
for (const match of lidMatches) {
const lidNumber = match[2];
const formattedLid = `${lidNumber}@lid`;
if (!mentions.includes(formattedLid)) {
mentions.push(formattedLid);
}
}
// Regex to match @ followed by phone number
// Matches: @558591203123, @5585991203123, etc.
// Phone numbers: 7-15 digits (international format)
const phoneRegex = /(^|\s)@(\d{7,15})(?!@lid)\b/g;
const phoneMatches = text.matchAll(phoneRegex);
for (const match of phoneMatches) {
const phoneNumber = match[2];
// Format phone number to @c.us format
const formattedJid = ensureSuffix(phoneNumber);
if (!mentions.includes(formattedJid)) {
mentions.push(formattedJid);
}
}
if (mentions.length == 0) {
// Nothing found
return {
text: text,
mentions: null,
};
}
// Ensure text is not empty when there are mentions
// If text becomes empty after removing mentions, use a default message
content = content.trim();
if (content === '') {
// When only mentions are present, use a minimal text to satisfy DTO requirements
// The mentions array will handle the actual mentions
content = ' ';
}
return {
text: content,
mentions: mentions,
};
}
+2 -2
View File
@@ -50,7 +50,6 @@ import * as lodash from 'lodash';
import * as NodeCache from 'node-cache';
import { Logger } from 'pino';
import {
BehaviorSubject,
catchError,
delay,
filter,
@@ -228,7 +227,8 @@ export abstract class WhatsappSession {
engineConfig,
ignore,
}: SessionParams) {
this.status$ = new BehaviorSubject(WAHASessionStatus.STOPPED);
this._status = WAHASessionStatus.STOPPED;
this.status$ = new Subject<WAHASessionStatus>();
this.name = name;
this.proxyConfig = proxyConfig;
+2 -1
View File
@@ -23,7 +23,8 @@ export namespace messages {
IMAGE = 0,
AUDIO = 1,
VIDEO = 2,
DOCUMENT = 3
DOCUMENT = 3,
PTV = 4
}
export enum Presence {
AVAILABLE = 0,
+2 -1
View File
@@ -21564,7 +21564,8 @@ proto.messages.MediaType = {
IMAGE: 0,
AUDIO: 1,
VIDEO: 2,
DOCUMENT: 3
DOCUMENT: 3,
PTV: 4
};
/**
+6 -9
View File
@@ -288,14 +288,12 @@ export class WhatsappSessionGoWSCore extends WhatsappSession {
grpc.credentials.createInsecure(),
);
try {
await promisify(this.client.StartSession)(request);
} catch (err) {
promisify(this.client.StartSession)(request).catch((err) => {
this.logger.error('Failed to start the client');
this.logger.error(err, err.stack);
this.status = WAHASessionStatus.FAILED;
throw err;
}
});
}
protected getProxyUrl(config: ProxyConfig): string {
@@ -766,15 +764,14 @@ export class WhatsappSessionGoWSCore extends WhatsappSession {
async stop(): Promise<void> {
this.cleanupPresenceTimeout();
if (this.client) {
const response = await promisify(this.client.StopSession)(this.session);
response.toObject();
}
this.status = WAHASessionStatus.STOPPED;
this.events?.stop();
this.stopEvents();
this.client?.close();
this.mediaManager.close();
if (this.client) {
await promisify(this.client.StopSession)(this.session);
this.client?.close();
}
}
public async requestCode(phoneNumber: string, method: string, params?: any) {
@@ -2910,6 +2910,12 @@ export function extractBody(message): string | null {
// @ts-ignore - AudioMessage doesn't have caption field
body = mediaContent?.caption;
}
if (!body && content.protocolMessage?.editedMessage) {
body = extractBody(content.protocolMessage.editedMessage);
}
if (!body && content.associatedChildMessage?.message) {
body = extractBody(content.associatedChildMessage.message);
}
// Response for buttons
if (!body) {
body = content.templateButtonReplyMessage?.selectedDisplayText;
+1
View File
@@ -10,6 +10,7 @@ export function extractMediaContent(
content?.imageMessage ||
content?.videoMessage ||
content?.audioMessage ||
content?.ptvMessage ||
content?.stickerMessage;
if (mediaContent) {
return mediaContent;
-5
View File
@@ -16,9 +16,4 @@ export function validateRequestMentions(request: {
`"mentions":["all"] can be used only in group chats, not in '${request.chatId}'`,
);
}
if (request.mentions.length > 1) {
throw new UnprocessableEntityException(
`"mentions":["all"] cannot be used with other mentions`,
);
}
}
+1 -1
View File
@@ -40,7 +40,7 @@ function getPlatform() {
}
export const VERSION: WAHAEnvironment = {
version: '2026.1.1',
version: '2026.1.2',
engine: getEngineName(),
tier: getWAHAVersion(),
browser: getBrowser(),
+1 -1
View File
@@ -2,7 +2,7 @@
"waha": {
"gows": {
"repo": "devlikeapro/gows",
"ref": "v1.0.28"
"ref": "v1.0.29"
},
"dashboard": {
"repo": "devlikeapro/dashboard",
+4 -4
View File
@@ -7,7 +7,7 @@ __metadata:
"@adiwajshing/baileys@github:devlikeapro/Baileys#fork-master-2025-12-17":
version: 7.0.0-rc.9
resolution: "@adiwajshing/baileys@https://github.com/devlikeapro/Baileys.git#commit=425b11f5b2d98c808210fab78afc6257f27f2fe5"
resolution: "@adiwajshing/baileys@https://github.com/devlikeapro/Baileys.git#commit=3d54943ebd83c56f1b5739c4d28da3f9af01020a"
dependencies:
"@cacheable/node-cache": "npm:^1.4.0"
"@hapi/boom": "npm:^9.1.3"
@@ -31,7 +31,7 @@ __metadata:
optional: true
link-preview-js:
optional: true
checksum: 10/2b58dffc216fe6518e3f72532de60765e7d8c371cdc17221b79c98d74752a5b6c08f5ea2af4543b12bd6c55f1434d1b6b697e4b31f33fea50069b7b4b774feb1
checksum: 10/6ec9803fea06e359f1e883c1e050b511350ec272cfb9e3fc3a14c1346ccc8bc18c4bfb3d22f90877d5aaf4f973b02cb8fda9f5a7ab801138d17e766c36b05dfc
languageName: node
linkType: hard
@@ -12756,7 +12756,7 @@ __metadata:
"whatsapp-web.js@github:devlikeapro/whatsapp-web.js#fork-main-2025-12-17":
version: 1.34.3
resolution: "whatsapp-web.js@https://github.com/devlikeapro/whatsapp-web.js.git#commit=8349fcd26fd2bbede0e6739b0da9b9ce97fe6c14"
resolution: "whatsapp-web.js@https://github.com/devlikeapro/whatsapp-web.js.git#commit=8823818e1db005aeca3cb75cf48622493c5e4cd2"
dependencies:
"@pedroslopez/moduleraid": "npm:^5.0.2"
archiver: "npm:^5.3.1"
@@ -12774,7 +12774,7 @@ __metadata:
optional: true
unzipper:
optional: true
checksum: 10/b53255dfd1c0336232f4f4683e67779bea2f002242084961ecec59844595414a80f7172859eb4a8983e9dd6c276de6a97bfdec5135c7d4ec6ee5ed638a6e8346
checksum: 10/3bcbb476ccf1fc330beccb67b26720b212a37d74d166291c346430feef955a85ffb5948f3802a7f14f9f620fbd7edcd292b049b54e77c80ce9c5f7f2c2474878
languageName: node
linkType: hard