@whanext/core 0.12.0 → 0.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.13.1
4
+
5
+ - Corrigido download de mídias para mensagens visualização única citadas, através do cache do payload citado carregado em `contextInfo`.
6
+ - Adicionado desempacotamento explícito para envelopes de mensagens efêmeras e de visualização única, incluindo `viewOnceMessageV2Extension`.
7
+
8
+ ## 0.13.0
9
+
10
+ - Adicionado `MessageService.repost()` para republicar qualquer mensagem do WhatsApp recebida recentemente, sem criar uma resposta.
11
+ - Adicionado suporte a `repostMessage()` em nível de provedor, com injeção de menções.
12
+ - As republicações preservam o payload estruturado original, permitindo que textos, mídias, figurinhas, enquetes, localizações, contatos e mensagens de catálogo sejam reutilizados através da API de alto nível.
13
+
3
14
 
4
15
  ## 0.12.0 - Message content classification
5
16
 
package/README.md CHANGED
@@ -803,3 +803,16 @@ MIT. Consulte [LICENSE](./LICENSE).
803
803
  ## Aviso
804
804
 
805
805
  WhaNext não é afiliado, autorizado ou mantido pelo WhatsApp ou pela Meta. O provider padrão usa uma integração não oficial; quem utiliza o projeto é responsável pelos termos aplicáveis e pelos riscos de bloqueio da conta.
806
+
807
+
808
+ ### Reposting received messages
809
+
810
+ WhaNext can repost a recently received message while preserving its original WhatsApp payload:
811
+
812
+ ```ts
813
+ await app.message.repost(message.quoted!.key, message.chatId, {
814
+ mentions: users,
815
+ });
816
+ ```
817
+
818
+ The source message must still be present in the provider recent-message cache. This avoids downloading and reconstructing media or structured messages.
package/dist/index.d.ts CHANGED
@@ -129,6 +129,11 @@ type MediaSource = Uint8Array | {
129
129
  path: string;
130
130
  };
131
131
  type MentionTarget = string | User;
132
+ /** Options for reposting a previously received message without quoting it. */
133
+ interface RepostMessageOptions {
134
+ /** Hidden or visible mentions injected into the reposted payload. */
135
+ mentions?: readonly MentionTarget[];
136
+ }
132
137
  interface TextContent {
133
138
  text: string;
134
139
  mentions?: MentionTarget[];
@@ -238,6 +243,7 @@ interface WhatsAppProvider {
238
243
  requestPairingCode(phone: string): Promise<string>;
239
244
  on<Event extends keyof ProviderEvents>(event: Event, listener: (payload: ProviderEvents[Event]) => void | Promise<void>): Unsubscribe;
240
245
  sendMessage(chatId: string, content: MessageContent, replyTo?: MessageKey): Promise<SentMessage>;
246
+ repostMessage(source: MessageKey, chatId: string, options?: RepostMessageOptions): Promise<SentMessage>;
241
247
  reactToMessage(key: MessageKey, emoji?: string): Promise<SentMessage>;
242
248
  downloadMedia(key: MessageKey): Promise<DownloadedMedia>;
243
249
  editMessage(key: MessageKey, content: string): Promise<SentMessage>;
@@ -440,6 +446,12 @@ declare class MessageService {
440
446
  constructor(provider: WhatsAppProvider);
441
447
  send(chatId: string, content: MessageContent): Promise<SentMessage>;
442
448
  reply(message: Message, content: MessageContent): Promise<SentMessage>;
449
+ /**
450
+ * Reposts a cached received message into a chat without creating a reply.
451
+ * The original payload is preserved by the provider, so this works for
452
+ * media and structured WhatsApp messages as well as text.
453
+ */
454
+ repost(source: Message | MessageKey, chatId: string, options?: RepostMessageOptions): Promise<SentMessage>;
443
455
  edit(message: Message | SentMessage | MessageKey, text: string): Promise<SentMessage>;
444
456
  delete(message: Message | SentMessage | MessageKey): Promise<void>;
445
457
  react(message: Message | SentMessage | MessageKey, emoji: string): Promise<SentMessage>;
@@ -800,4 +812,4 @@ declare class SqliteMuteStore implements MuteStore {
800
812
  close(): void;
801
813
  }
802
814
 
803
- export { type AddMuteOptions, type AddMuteResult, type AppEvents, type AppHealth, type AppHealthStatus, ArgsParser, type AudioContent, type BooleanOption, Browser, type CacheOptions, type CacheStore, type CallEvent, type CallStatus, type ChangeResult, type CommandCatalogOptions, type CommandCatalogView, type CommandChatContext, type CommandConcurrency, type CommandContext, type CommandCooldown, type CommandDefinition, type CommandErrorHandler, type CommandGroupContext, type CommandGroupDefinition, type CommandGuard, type CommandHelpOptions, type CommandHooks, type CommandLocalization, type CommandMetadata, type CommandMiddleware, type CommandOptionDefinition, type CommandOptionSchema, type CommandOptionValue, type CommandOptionValues, type CommandRegistrar, CommandRouter, type CommandRuntimeServices, type CommandScope, type ConcurrencyStrategy, type ConnectionState, type ConnectionUpdate, type CreateOptions, DeferredReply, type DownloadedMedia, type DurationOption, type EnumOption, type ExecutableCommandDefinition, type GroupAccess, type GroupAddressingMode, type GroupParticipant, type GroupParticipantAction, type GroupParticipantsChanged, type GroupRole, type GroupSnapshot, type GuardResult, type ImageContent, type InviteResult, type LoadCommandsOptions, type LoadCommandsResult, type LoadedCommand, type LogContext, type LogEntry, type LogFormat, type LogLevel, type LogWriter, Logger, type LoggerConfig, type LoggerOptions, type LoginOptions, type MediaKind, type MediaSource, type MemberActionState, MemoryCache, type MemoryCacheStats, type MentionTarget, type Message, type MessageContent, type MessageContentKind, type MessageKey, type MessageMedia, type MuteChangeResult, type MuteEnforcement, type MuteOptions, type MuteRecord, MuteService, type MuteStore, type NumberOption, ParsedCommandOptions, type ParticipantUpdateResult, type PresenceState, type QuotedMessage, type ReconnectOptions, type RegisteredCommand, type RemoveMuteResult, type ReplyOptions, type RouterOptions, type SentMessage, SqliteMuteStore, type StickerContent, type StoredMute, type StringOption, type TextContent, User, type UserData, type UserOption, type VideoContent, WhaNextApp, WhaNextError, type WhaNextErrorCode, type WhatsAppProvider, create, defineCommand, defineCommandGroup, defineCommands, defineSubcommand, guards, isCommandGroup, loadCommands, option, toWhaNextError };
815
+ export { type AddMuteOptions, type AddMuteResult, type AppEvents, type AppHealth, type AppHealthStatus, ArgsParser, type AudioContent, type BooleanOption, Browser, type CacheOptions, type CacheStore, type CallEvent, type CallStatus, type ChangeResult, type CommandCatalogOptions, type CommandCatalogView, type CommandChatContext, type CommandConcurrency, type CommandContext, type CommandCooldown, type CommandDefinition, type CommandErrorHandler, type CommandGroupContext, type CommandGroupDefinition, type CommandGuard, type CommandHelpOptions, type CommandHooks, type CommandLocalization, type CommandMetadata, type CommandMiddleware, type CommandOptionDefinition, type CommandOptionSchema, type CommandOptionValue, type CommandOptionValues, type CommandRegistrar, CommandRouter, type CommandRuntimeServices, type CommandScope, type ConcurrencyStrategy, type ConnectionState, type ConnectionUpdate, type CreateOptions, DeferredReply, type DownloadedMedia, type DurationOption, type EnumOption, type ExecutableCommandDefinition, type GroupAccess, type GroupAddressingMode, type GroupParticipant, type GroupParticipantAction, type GroupParticipantsChanged, type GroupRole, type GroupSnapshot, type GuardResult, type ImageContent, type InviteResult, type LoadCommandsOptions, type LoadCommandsResult, type LoadedCommand, type LogContext, type LogEntry, type LogFormat, type LogLevel, type LogWriter, Logger, type LoggerConfig, type LoggerOptions, type LoginOptions, type MediaKind, type MediaSource, type MemberActionState, MemoryCache, type MemoryCacheStats, type MentionTarget, type Message, type MessageContent, type MessageContentKind, type MessageKey, type MessageMedia, type MuteChangeResult, type MuteEnforcement, type MuteOptions, type MuteRecord, MuteService, type MuteStore, type NumberOption, ParsedCommandOptions, type ParticipantUpdateResult, type PresenceState, type QuotedMessage, type ReconnectOptions, type RegisteredCommand, type RemoveMuteResult, type ReplyOptions, type RepostMessageOptions, type RouterOptions, type SentMessage, SqliteMuteStore, type StickerContent, type StoredMute, type StringOption, type TextContent, User, type UserData, type UserOption, type VideoContent, WhaNextApp, WhaNextError, type WhaNextErrorCode, type WhatsAppProvider, create, defineCommand, defineCommandGroup, defineCommands, defineSubcommand, guards, isCommandGroup, loadCommands, option, toWhaNextError };
package/dist/index.js CHANGED
@@ -1946,6 +1946,15 @@ var MessageService = class {
1946
1946
  reply(message, content) {
1947
1947
  return this.#provider.sendMessage(message.chatId, content, message.keys);
1948
1948
  }
1949
+ /**
1950
+ * Reposts a cached received message into a chat without creating a reply.
1951
+ * The original payload is preserved by the provider, so this works for
1952
+ * media and structured WhatsApp messages as well as text.
1953
+ */
1954
+ repost(source, chatId, options = {}) {
1955
+ const key = "keys" in source ? source.keys : source;
1956
+ return this.#provider.repostMessage(key, chatId, options);
1957
+ }
1949
1958
  edit(message, text) {
1950
1959
  const key = "keys" in message ? message.keys : message;
1951
1960
  return this.#provider.editMessage(key, text);
@@ -2272,14 +2281,39 @@ import {
2272
2281
  getContentType,
2273
2282
  normalizeMessageContent
2274
2283
  } from "@whiskeysockets/baileys";
2284
+ function unwrapMessageContent(input) {
2285
+ if (!input) return void 0;
2286
+ const normalized = normalizeMessageContent(input);
2287
+ const content = extractMessageContent(normalized);
2288
+ if (!content) return void 0;
2289
+ const nested = content.ephemeralMessage?.message ?? content.viewOnceMessage?.message ?? content.viewOnceMessageV2?.message ?? content.viewOnceMessageV2Extension?.message;
2290
+ return nested ? unwrapMessageContent(nested) : content;
2291
+ }
2292
+ function extractQuotedBaileysMessage(input) {
2293
+ const chatId = input.key.remoteJid;
2294
+ const content = unwrapMessageContent(input.message);
2295
+ if (!chatId || !content) return void 0;
2296
+ const type = getContentType(content);
2297
+ const node = type ? content[type] : void 0;
2298
+ const context = getContextInfo(node);
2299
+ if (!context?.stanzaId || !context.quotedMessage) return void 0;
2300
+ return {
2301
+ key: {
2302
+ id: context.stanzaId,
2303
+ remoteJid: context.remoteJid ?? chatId,
2304
+ fromMe: false,
2305
+ ...context.participant ? { participant: context.participant } : {}
2306
+ },
2307
+ message: context.quotedMessage
2308
+ };
2309
+ }
2275
2310
  function normalizeBaileysMessage(input) {
2276
2311
  const chatId = input.key.remoteJid;
2277
2312
  const id = input.key.id;
2278
2313
  if (!chatId || !id || !input.message) {
2279
2314
  return void 0;
2280
2315
  }
2281
- const normalized = normalizeMessageContent(input.message);
2282
- const content = extractMessageContent(normalized);
2316
+ const content = unwrapMessageContent(input.message);
2283
2317
  if (!content) {
2284
2318
  return void 0;
2285
2319
  }
@@ -2420,8 +2454,7 @@ function getQuoted(context, chatId) {
2420
2454
  return void 0;
2421
2455
  }
2422
2456
  const quoted = context.quotedMessage;
2423
- const normalized = normalizeMessageContent(quoted);
2424
- const content = extractMessageContent(normalized);
2457
+ const content = unwrapMessageContent(quoted);
2425
2458
  const result = {
2426
2459
  key: {
2427
2460
  id: context.stanzaId,
@@ -2583,6 +2616,25 @@ var BaileysProvider = class {
2583
2616
  const result = await socket.sendMessage(chatId, this.#toContent(content), options);
2584
2617
  return this.#sent(result);
2585
2618
  }
2619
+ async repostMessage(source, chatId, options = {}) {
2620
+ const original = this.#messageStore.get(this.#messageStoreKey(source));
2621
+ if (!original?.message) {
2622
+ throw new WhaNextError(
2623
+ "MESSAGE_NOT_FOUND",
2624
+ "The source message is no longer available in the recent-message cache.",
2625
+ {
2626
+ context: { messageId: source.id, chatId: source.chatId },
2627
+ recoverable: true
2628
+ }
2629
+ );
2630
+ }
2631
+ const content = {
2632
+ forward: original,
2633
+ ...options.mentions && options.mentions.length > 0 ? { mentions: this.#mentions(options.mentions) } : {}
2634
+ };
2635
+ const result = await this.#requireSocket().sendMessage(chatId, content);
2636
+ return this.#sent(result);
2637
+ }
2586
2638
  async reactToMessage(key, emoji) {
2587
2639
  const result = await this.#requireSocket().sendMessage(key.chatId, {
2588
2640
  react: {
@@ -2703,6 +2755,8 @@ var BaileysProvider = class {
2703
2755
  if (type !== "notify") return;
2704
2756
  for (const raw of messages) {
2705
2757
  if (raw.key.id && raw.message) this.#remember(raw);
2758
+ const quoted = extractQuotedBaileysMessage(raw);
2759
+ if (quoted?.key.id && quoted.message) this.#remember(quoted);
2706
2760
  const message = normalizeBaileysMessage(raw);
2707
2761
  if (message) void this.#events.emit("message", message);
2708
2762
  }