zca-js

repository·main·Indexed 20 days ago

https://github.com/rfs-adreno/zca-js

An unofficial Zalo API for JavaScript designed for personal accounts. It simulates a browser to interact with Zalo Web, enabling developers to automate messaging, listen for events, manage stickers, create groups and polls, and handle zBusiness product catalogs.

Tokens
10K
Snippets
44
Records
47
Agent score
69%

What's inside zca-js

  1. Migrate to V2: Provide imageMetadataGetter

    main

    Since version 2.0.0, zca-js no longer includes the sharp dependency for image metadata extraction. If you need to send images or GIFs using a file path, you must provide your own imageMetadataGetter function when initializing the Zalo class.

    An implementation using sharp looks like this:

    import { Zalo } from "zca-js";
    import sharp from "sharp";
    import fs from "node:fs";
    
    async function imageMetadataGetter(filePath) {
        const data = await fs.promises.readFile(filePath);
        const metadata = await sharp(data).metadata();
        return {
            height: metadata.height,
            width: metadata.width,
            size: metadata.size || data.length,
        };
    }
    
    const zalo = new Zalo({
        imageMetadataGetter,
    });
  2. Install zca-js

    main

    You can install zca-js using bun or npm.

    Warning: This is an unofficial Zalo API for personal accounts that works by simulating a browser. Using this API could result in your account being locked or banned. Use it at your own risk.

    bun add zca-js # or npm install zca-js
  3. Login via QR Code

    main

    To authenticate, instantiate the Zalo class and call loginQR(). This method returns an API object used for subsequent interactions.

    import { Zalo } from "zca-js";
    
    const zalo = new Zalo();
    const api = await zalo.loginQR();
  4. Listen for new messages

    main

    Use api.listener.on('message', callback) to react to incoming messages. You can distinguish between direct messages and group messages using ThreadType.

    Important: Only one web listener can run per account at a time. If you open Zalo in a browser while the listener is active, the listener will be automatically stopped.

    import { Zalo, ThreadType } from "zca-js";
    
    const zalo = new Zalo();
    const api = await zalo.loginQR();
    
    api.listener.on("message", (message) => {
        const isPlainText = typeof message.data.content === "string";
    
        switch (message.type) {
            case ThreadType.User: {
                if (isPlainText) {
                    // received plain text direct message
                }
                break;
            }
            case ThreadType.Group: {
                if (isPlainText) {
                    // received plain text group message
                }
                break;
            }
        }
    });
    
    api.listener.start();
  5. Send a message

    main

    Use api.sendMessage(payload, threadId, threadType) to send messages.

    Payload options:

    • msg: The text content of the message.
    • quote: (Optional) The message object to reply to.
    import { Zalo, ThreadType } from "zca-js";
    
    const zalo = new Zalo();
    const api = await zalo.loginQR();
    
    // Example: Echo bot logic
    api.listener.on("message", (message) => {
        const isPlainText = typeof message.data.content === "string";
        if (message.isSelf || !isPlainText) return;
    
        api.sendMessage(
            {
                msg: "echo: " + message.data.content,
                quote: message.data, // the message to reply to (optional)
            },
            message.threadId,
            message.type, // ThreadType.User or ThreadType.Group
        );
    });
    
    api.listener.start();
  6. Get and send stickers

    main

    You can search for stickers by keyword using api.getStickers(keyword), retrieve detailed sticker information with api.getStickersDetail(stickerId), and send them using api.sendMessageSticker(stickerObject, threadId, threadType).

    api.getStickers("hello").then(async (stickerIds) => {
        // Get the first sticker
        const stickerObject = await api.getStickersDetail(stickerIds[0]);
        api.sendMessageSticker(
            stickerObject,
            message.threadId,
            message.type, // ThreadType.User or ThreadType.Group
        );
    });
  7. Send attachments and media

    main

    Attachments can be sent as part of a MessageContent object. The attachments field accepts a single AttachmentSource or an array of them. An AttachmentSource can be a file path (string) or an object containing data.

    Supported types:

    • Images/Videos/Others: Handled via uploadAttachment internally.
    • GIFs: Handled specially with metadata extraction and chunked uploading.

    Constraints:

    • The number of attachments is limited by the sharefile.max_file setting.
    • File size is limited by sharefile.max_size_share_file_v3.
    • If you send an image (jpg, jpeg, png, webp) as the only attachment, the message text can be used as the image description.
    // Sending a single image with a caption
    await sendMessage({
        msg: "Check this out!",
        attachments: ["/path/to/photo.jpg"]
    }, "USER_ID");
    
    // Sending multiple files
    await sendMessage({
        msg: "Files collection",
        attachments: ["file1.pdf", "file2.zip"]
    }, "GROUP_ID", ThreadType.Group);
  8. Retrieve a list of reminders with getListReminder

    main

    Use getListReminder to fetch a list of reminders for a specific thread. The function supports both individual user threads and group threads.

    Parameters

    • options: An object of type ListReminderOptions to control pagination.
    • threadId: The unique identifier for the user or group thread.
    • type: The type of thread, either ThreadType.User (default) or ThreadType.Group.

    Options (ListReminderOptions)

    • page: The page number to retrieve (defaults to 1).
    • count: The number of items to retrieve per page (defaults to 20).

    Response

    Returns a promise that resolves to an array of GetListReminderResponse. This array contains objects that are a union of ReminderListUser and ReminderListGroup types.

    Note that ReminderListGroup objects include additional metadata such as groupId, eventType, responseMem (tracking member responses), repeatInfo, and repeatData.

    // Example usage of getListReminder
    const reminders = await getListReminder(
      { page: 1, count: 10 },
      'thread_id_here',
      ThreadType.Group
    );
    
    console.log(reminders);
  9. Edit an existing note with editNote()

    main

    Use the editNote function to update the title or pinning status of an existing note within a group. The function requires an options object containing the new title and the target topic ID, along with the groupId where the note resides.

    Parameters:

    • options: An EditNoteOptions object.
      • title (string): The new title for the note.
      • topicId (string): The ID of the topic/note being edited.
      • pinAct (boolean, optional): If true, the note will be pinned. If false or omitted, it will be unpinned.
    • groupId (string): The ID of the group containing the note.

    Returns:

    • A Promise<NoteDetail> representing the updated note.

    Errors:

    • Throws a ZaloApiError if the parameter encryption fails or if the API request fails.
    // Assuming editNote has been initialized via editNoteFactory
    const updatedNote = await editNote({
      title: "Updated Note Title",
      topicId: "123456789",
      pinAct: true
    }, "group_id_here");
  10. Update group settings with updateGroupSettings()

    main

    Use the updateGroupSettings function to modify various configuration settings for a specific Zalo group.

    Permissions Note: If you do not have sufficient administrative permissions to change these settings, Zalo may return a ZaloApiError with error code 166.

    Parameters:

    • options: An UpdateGroupSettingsOptions object containing the settings to toggle.
    • groupId: The unique identifier for the group.

    Returns: A Promise<string> (empty string on success).

    // Example usage (assuming updateGroupSettings is obtained via the factory)
    await updateGroupSettings({
        lockSendMsg: true,
        joinAppr: true,
        blockName: false
    }, 'GROUP_ID_HERE');
  11. Use ZCA-JS error classes for error handling

    main

    ZCA-JS provides specialized error classes to help you distinguish between different failure modes when interacting with the Zalo API. You can use instanceof checks to handle specific error scenarios, such as login failures or missing metadata.

    Available error classes include:

    • ZaloApiError: The base error class for Zalo API related issues.
    • ZaloApiMissingImageMetadataGetter: Thrown when image metadata cannot be retrieved.
    • ZaloApiLoginQRAborted: Thrown when a Zalo login QR code session is aborted.
    • ZaloApiLoginQRDeclined: Thrown when a Zalo login QR code is declined by the user.
  12. Configure message text styles

    main

    You can apply text styling to specific ranges within a message using the styles array in a MessageContent object. Each style object requires a start index, a len (length), and a st (style type).

    Available TextStyle values:

    • Bold (b)
    • Italic (i)
    • Underline (u)
    • StrikeThrough (s)
    • Red (c_db342e)
    • Orange (c_f27806)
    • Yellow (c_f7b503)
    • Green (c_15a85f)
    • Small (f_13)
    • Big (f_18)
    • UnorderedList (lst_1)
    • OrderedList (lst_2)
    • Indent (ind_$): Requires an optional indentSize property.
    const message: MessageContent = {
        msg: "Styled text",
        styles: [
            { start: 0, len: 6, st: TextStyle.Bold },
            { start: 7, len: 4, st: TextStyle.Italic }
        ]
    };