zaileys 4.8.9 → 4.9.0

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.
@@ -1,7 +1,7 @@
1
1
  import { type WAMessageKey } from 'baileys';
2
2
  import { EditBuilder, MessageBuilder, type DeleteOptions, type PinOptions } from '../builder/index.js';
3
3
  import { CommunityModule, GroupModule, BusinessModule, ChatModule, ContactModule, NewsletterModule, PrivacyModule, ProfileModule } from '../domain/index.js';
4
- import { type CommandHandler, type Middleware } from '../command/index.js';
4
+ import { type CommandHandler, type CommandSpec, type Middleware, type RegisteredCommand } from '../command/index.js';
5
5
  import { PresenceModule, type BroadcastOptions, type BroadcastResult, type ScheduleHandle } from '../automation/index.js';
6
6
  import type { CallPayload, MediaDownloadResult } from '../events/types.js';
7
7
  import type { AuthStoreBundle } from '../auth/types.js';
@@ -119,11 +119,15 @@ export declare class Client extends TypedEventEmitter<ClientEventMap> {
119
119
  private disconnectCloud;
120
120
  disconnect(): Promise<void>;
121
121
  logout(): Promise<void>;
122
- command(spec: string, handler: CommandHandler): this;
123
- unregisterCommand(spec: string): this;
122
+ command(spec: string | CommandSpec, handler: CommandHandler): this;
123
+ unregisterCommand(spec: string | CommandSpec): this;
124
+ /** Every registered command with its description and guards — build a help menu from this. */
125
+ commands(): RegisteredCommand[];
124
126
  use(middleware: Middleware): this;
125
127
  unuse(middleware: Middleware): this;
126
128
  private attachCommandsIfReady;
129
+ /** Admin lookup for the `admin` guard. Never throws — an unreachable group means "not an admin". */
130
+ private isGroupAdmin;
127
131
  private buildCommandContext;
128
132
  private detachCommands;
129
133
  send(to: string): MessageBuilder<'init'>;
@@ -6,7 +6,8 @@ import type { OperationGuardOptions } from '../automation/operation-guard.js';
6
6
  import type { PresenceThrottleOptions } from '../automation/presence.js';
7
7
  import type { AuthGuardOptions } from '../connection/auth-guard.js';
8
8
  import type { DisconnectReasonDomain } from '../connection/disconnect-reason.js';
9
- import type { CitationConfig } from '../events/context.js';
9
+ import type { CommandBlockedReason, CommandContext } from '../command/types.js';
10
+ import type { CitationConfig, MessageContext } from '../events/context.js';
10
11
  import type { InboundEventMap } from '../events/types.js';
11
12
  import type { MessageStore } from '../store/types.js';
12
13
  import type { PluginsOptions } from '../plugin/types.js';
@@ -109,6 +110,25 @@ export type ConnectionEventMap = {
109
110
  sessionId: string;
110
111
  error: Error;
111
112
  };
113
+ /** A command matched but a guard stopped it. zaileys sends nothing — reply here if you want to. */
114
+ 'command-blocked': {
115
+ command: string;
116
+ reason: CommandBlockedReason;
117
+ /** Seconds until the sender may retry. Only present when `reason` is `cooldown`. */
118
+ retryIn?: number;
119
+ ctx: CommandContext;
120
+ };
121
+ /** A command handler threw. Listening takes ownership: zaileys stops logging it as an error. */
122
+ 'command-error': {
123
+ command: string;
124
+ error: unknown;
125
+ ctx: CommandContext;
126
+ };
127
+ /** A prefixed message matched no command. Only emitted when something is listening. */
128
+ 'command-not-found': {
129
+ command: string;
130
+ message: MessageContext;
131
+ };
112
132
  /** Cloud provider: delivery lifecycle of outbound messages (sent/delivered/read/failed). */
113
133
  'message-status': CloudStatusEvent;
114
134
  /** Cloud provider: template review lifecycle (APPROVED/REJECTED/PAUSED...). */
@@ -1,5 +1,6 @@
1
1
  import type { Logger } from '../client/types.js';
2
2
  import type { MessageContext } from '../events/context.js';
3
+ import { type GuardBlock } from './guards.js';
3
4
  import type { CommandRegistry } from './registry.js';
4
5
  import type { CommandContext, Middleware } from './types.js';
5
6
  export interface ResolvedCommand {
@@ -16,6 +17,11 @@ export interface DispatcherDeps {
16
17
  onText: (handler: (msg: MessageContext) => void) => () => void;
17
18
  buildContext: (resolved: ResolvedCommand, msg: MessageContext) => CommandContext;
18
19
  logger: Logger;
20
+ isAdmin?: (groupJid: string, senderJid: string) => Promise<boolean>;
21
+ onBlocked?: (block: GuardBlock, ctx: CommandContext) => void;
22
+ /** Return `true` to claim the failure; otherwise the dispatcher logs it. */
23
+ onError?: (error: unknown, ctx: CommandContext) => boolean;
24
+ onNotFound?: (name: string, msg: MessageContext) => void;
19
25
  }
20
26
  export interface DispatcherHandle {
21
27
  detach(): void;
@@ -0,0 +1,17 @@
1
+ import type { CommandBlockedReason, CommandContext, CommandGuards } from './types.js';
2
+ export interface GuardBlock {
3
+ reason: CommandBlockedReason;
4
+ /** Seconds left before the sender may retry. Only set for `cooldown`. */
5
+ retryIn?: number;
6
+ }
7
+ export interface GuardDeps {
8
+ /** Resolves whether the sender is an admin of the group the command ran in. */
9
+ isAdmin: (groupJid: string, senderJid: string) => Promise<boolean>;
10
+ now: () => number;
11
+ }
12
+ export declare const resetCooldowns: () => void;
13
+ /**
14
+ * Checks a command's guards. Returns the block, or `null` when the handler may run. Nothing is sent
15
+ * to the chat here — the caller emits `command-blocked` so the wording stays the bot author's.
16
+ */
17
+ export declare const checkGuards: (guards: CommandGuards, ctx: CommandContext, deps: GuardDeps) => Promise<GuardBlock | null>;
@@ -3,5 +3,6 @@ export * from './errors.js';
3
3
  export { parseCommand } from './parser.js';
4
4
  export { CommandRegistry } from './registry.js';
5
5
  export { runMiddleware } from './middleware.js';
6
+ export { checkGuards, resetCooldowns, type GuardBlock } from './guards.js';
6
7
  export { attachCommandDispatcher } from './dispatcher.js';
7
8
  export type { DispatcherDeps, DispatcherHandle, ResolvedCommand } from './dispatcher.js';
@@ -1,13 +1,15 @@
1
- import type { CommandDefinition, CommandHandler, ParsedArgs } from './types.js';
1
+ import type { CommandDefinition, CommandHandler, CommandSpec, ParsedArgs, RegisteredCommand } from './types.js';
2
2
  export declare class CommandRegistry {
3
3
  private readonly paths;
4
4
  private readonly defs;
5
5
  private maxDepth;
6
- register(spec: string, handler: CommandHandler): void;
6
+ register(spec: string | CommandSpec, handler: CommandHandler): void;
7
7
  resolve(parsed: ParsedArgs): {
8
8
  def: CommandDefinition;
9
9
  args: string[];
10
10
  } | undefined;
11
- unregister(spec: string): void;
11
+ unregister(spec: string | CommandSpec): void;
12
12
  list(): CommandDefinition[];
13
+ /** The registered commands without their handlers — what a help menu is built from. */
14
+ describe(): RegisteredCommand[];
13
15
  }
@@ -22,9 +22,43 @@ export interface CommandContext extends MessageContext {
22
22
  }
23
23
  export type CommandHandler = (ctx: CommandContext) => Promise<void> | void;
24
24
  export type Middleware = (ctx: CommandContext, next: () => Promise<void>) => Promise<void> | void;
25
+ /** Descriptive fields a command carries so a help menu can be generated instead of hand-written. */
26
+ export interface CommandMeta {
27
+ description?: string;
28
+ /** Argument hint shown next to the name, e.g. `<@user>`. */
29
+ usage?: string;
30
+ /** Menu grouping. Plugins default it to the folder the file sits in. */
31
+ category?: string;
32
+ /** Keeps the command callable but leaves it out of listings. */
33
+ hidden?: boolean;
34
+ /** Anything else you want to hang off the command; zaileys never reads it. */
35
+ metadata?: Record<string, unknown>;
36
+ }
37
+ /** Conditions checked before a handler runs. A blocked command emits `command-blocked` instead. */
38
+ export interface CommandGuards {
39
+ /** Only runs inside a group. */
40
+ group?: boolean;
41
+ /** Only runs in a one-to-one chat. */
42
+ private?: boolean;
43
+ /** Only runs for a group admin. Implies `group`. */
44
+ admin?: boolean;
45
+ /** Seconds the same sender must wait before reusing this command. */
46
+ cooldown?: number;
47
+ }
48
+ export interface CommandSpec extends CommandMeta, CommandGuards {
49
+ name: string;
50
+ aliases?: string[];
51
+ }
52
+ /** A command as registered, with its guards and metadata resolved. */
53
+ export interface RegisteredCommand extends CommandMeta, CommandGuards {
54
+ name: string;
55
+ aliases: string[];
56
+ }
57
+ export type CommandBlockedReason = 'group-only' | 'private-only' | 'admin-only' | 'cooldown';
25
58
  export interface CommandDefinition {
26
59
  name: string;
27
60
  aliases: string[];
28
61
  parts: string[];
29
62
  handler: CommandHandler;
63
+ meta: CommandMeta & CommandGuards;
30
64
  }