LINEJS

repository·main·Indexed 43 days ago

https://github.com/evex-dev/linejs

A JavaScript library for creating LINE SelfBots, supporting Node.js, Deno, and Bun. It includes specialized packages for the main Client, call control-plane and media, Thrift read/write functionality, and storage implementations. The library provides tools for interacting with LINE APIs, including a Thrift class for encoding/decoding data and a pipeline to sync Thrift schemas from LINE Android APKs.

Tokens
30.5K
Snippets
99
Records
126
Agent score
55%

What's inside LINEJS

  1. Overview of LINEJS

    main
    LINEJS is a JavaScript library designed for creating LINE SelfBots. It is built with a focus on cross-platform compatibility and developer experience, featuring enhanced TypeScript support and built-in safety mechanisms like rate limiting to prevent account issues.
  2. Overview of LINEJS packages

    main

    LINEJS is organized into several specialized packages:

    • @evex/linejs: Contains the main Client for the LINE SelfBot.
    • @evex/linejs/base: Provides BaseClient (the LINE SelfBot API Client).
    • @evex/linejs/call: Helpers for call control-plane and media.
    • @evex/linejs/thrift: Thrift read/write functionality.
    • @evex/linejs/storage: Storage implementations including BaseStorage, MemoryStorage, and FileStorage.
    • @evex/linejs-types: All TypeScript types and enums (e.g., ReactionType, MessageType) used by LINE.
  3. How LINEJS calls work: Control plane vs Media plane

    main

    LINE calls are split into two distinct layers that must be managed sequentially:

    1. Control Plane: Responsible for signaling and negotiation. You must first ask LINE for a route, connect to the PLANET relay, send a setup_req to make the peer ring, wait for a conn_req when they answer, and finally send a conn_rsp to complete the handshake.
    2. Media Plane: Responsible for the actual audio stream. Once negotiation is complete, you derive SRTP keys from the handshake material, encode your audio as Opus, wrap the frames according to PLANET requirements, and send them as SRTP-protected RTP packets.

    If signaling succeeds but no audio is heard, the issue typically lies in the media plane configuration (e.g., key mode, payload prefix, Opus frame size, or RTP timestamping).

    Control plane:
      ask LINE for a route
      connect to the PLANET relay
      send setup_req so the peer starts ringing
      wait for conn_req when the peer answers
      send conn_rsp to finish negotiation
    
    Media plane:
      derive SRTP keys from the answer material
      encode audio as Opus
      wrap each Opus frame the way native PLANET audio expects
      send RTP packets protected by SRTP
  4. Configure device types for feature access

    main

    The device option in the BaseClient constructor affects which APIs are available. Some features are gated by the device type used in the protocol.

    • DESKTOPWIN: Sufficient for most bot automation and message sending.
    • ANDROID / ANDROIDSECONDARY: Required for features like getContactsV3, getContactCalendarEvents, and VOOM/Timeline REST API access via client.voomRest().

    If you encounter an API method not capable error, you likely need to switch your device type.

  5. Work around CORS restrictions for LINEJS in Browser

    main

    When attempting to use LINEJS in a browser, you will encounter CORS (Cross-Origin Resource Sharing) errors when calling the LINE endpoint. You have two primary options to resolve this:

    1. Proxy Server: Set up a proxy server that forwards requests to the LINE endpoint.
    2. Origin-matching (Bookmarklet): Execute your LINEJS code on a page that shares the same origin as the LINE endpoint, such as https://legy-jp.line-apps.com/sn.
  6. Extend BaseStorage to create custom storage

    main

    If you need to persist data to a remote location (e.g., a cloud API) instead of a local file, you can implement a custom storage provider by extending the BaseStorage class.

    import { BaseStorage } from "@evex/linejs/storage";
    
    // Implement your own storage logic by extending BaseStorage
    class MyCloudStorage extends BaseStorage {
      // ... implementation
    }
  7. Use the Client wrapper for high-level features

    main

    While BaseClient provides low-level Thrift RPC access, the Client wrapper (built on top of BaseClient) provides a richer, more developer-friendly API for common tasks. Use Client if you need to:

    • Manage profile: getMyProfile(), updateMyDisplayName(), updateMyStatusMessage(), updateMyProfile(), uploadMyProfileImage(), uploadMyProfileBackground()
    • Manage chats/users: fetchJoinedChats(), getChat(), getUser(), rename(), setFavorite(), mute()
    • Manage media: getBgm(), setBgm()
    • LIFF: liff.shareMessages() and liff.getToken()
  8. How the outgoing audio call flow works

    main

    An outgoing 1:1 audio call in LINEJS follows a seven-phase lifecycle involving route acquisition, transport connection, signaling via Cassini, and media transmission via SRTP.

    The 7 Phases:

    1. Acquire a Call Route: Use client.call.acquireRoute to get routing metadata, PLANET endpoints, and bootstrap parameters (mpkey). Routes are short-lived.
    2. Connect the PLANET Transport: Use PlanetTransport.connect({ route }) to initialize the UDP socket and derive transport encryption keys via ECDH.
    3. Send setup_req: Use transport.inviteDetailed({ to }) to start ringing the peer. This sends a Cassini setup message inside an encrypted PLANET frame.
    4. Learn Remote Nonce: The first server reply (setup_rsp) provides the relay's nonce, which is required for subsequent valid PLANET headers.
    5. Wait for conn_req: When the peer answers, the relay sends a connection request. Use transport.waitForAnswerDetailed to handle this.
    6. Send SRTP/Opus Media: Once mediaReady is true, send audio using transport.send(). The payload must be the LINE audio payload (Opus with a specific prefix), not a raw RTP packet.
    7. Close the Call: Use transport.close() to tear down the session and close the UDP socket.
    // High-level conceptual flow
    const route = await client.call.acquireRoute({ to, callType: "AUDIO" });
    const transport = new PlanetTransport({ route });
    await transport.connect({ route });
    await transport.inviteDetailed({ to });
    const answer = await transport.waitForAnswerDetailed({ autoConnRsp: true, timeoutMs: 60_000 });
    
    if (answer.mediaReady) {
      // Start sending media
    }
    
    await transport.close();
  9. Understand the extractor's auto-apply logic and tiers

    main

    The extractor uses three tiers of evidence to decide whether to automatically apply changes from an APK to the linejs types. This prevents incorrect mappings caused by R8/ProGuard obfuscation.

    Evidence Tiers

    TierMethodReliability
    ACanonical nameIdentity: LINE does not obfuscate com.linecorp.square.protocol.thrift.*
    BWire RPC stringStrong: Keyed by R8 short name; only kept if field names overlap
    CField-name overlapWeak: Useful for large enums, but unreliable for small, generic structures

    Auto-apply Rules

    Change KindAuto-applied?Condition
    New enum value (Tier A)YesAdditive
    New enum value (Tier B/C)ConditionalOnly if enum has $\ge$ --enum-add-min-members (default: 16)
    New struct field (Tier A)YesAdditive
    New struct field (Tier B)ConditionalOnly if overlap $> $ --min-overlap (0.6) AND shares $\ge$ --min-shared-fields (3)
    New struct field (Tier C)NoReported for manual review
    New type (enum/struct)YesCanonical names only
    Field change (Tier A)YesHigh confidence
    Field change (Tier B/C)ConditionalRequires --min-overlap (0.6) and unique field-name sets
    Obfuscated R8-synthetic namesNoPrevents noise

    Note: A full report of what was applied, held, or mismatched is generated at <decompiled-dir>/extract_report.json.

  10. Handle E2EE (End-to-End Encryption) requirements

    main

    Most LINE chat messages are encrypted. You cannot read op.message.text directly from a polling event. You must use the e2ee service to decrypt the message chunks.

    Required Pattern:

    const msg = await client.e2ee.decryptE2EEMessage(op.message);
    console.log(msg.text);
  11. Key Features of LINEJS

    main

    LINEJS provides several core advantages for developers building LINE automation tools:

    • Cross-Platform Support: Works on Node.js, Deno, Bun, and other JavaScript runtimes.
    • Strong Typing: Highly typed API with enhanced TypeScript support for better developer ergonomics.
    • Safety Defaults: The library is 'Safety Locked' by default, meaning features like RateLimit are enabled to protect your account from automated detection or bans.
  12. Install LINEJS

    main

    LINEJS supports Node.js, Deno, and Bun runtimes, as well as TypeScript. You can install it using the following commands depending on your runtime:

    Node.js (via JSR):

    npx jsr add @evex/linejs

    Bun (via JSR):

    bunx --bun jsr add @evex/linejs

    Deno (via JSR):

    deno add @evex/linejs
    npx jsr add @evex/linejs