LINEJS
repository·main·Indexed 43 days ago
https://github.com/evex-dev/linejsA 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.
What's inside LINEJS
- 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.
Overview of LINEJS packages
mainLINEJS is organized into several specialized packages:
@evex/linejs: Contains the mainClientfor the LINE SelfBot.@evex/linejs/base: ProvidesBaseClient(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 includingBaseStorage,MemoryStorage, andFileStorage.@evex/linejs-types: All TypeScript types and enums (e.g.,ReactionType,MessageType) used by LINE.
How LINEJS calls work: Control plane vs Media plane
mainLINE calls are split into two distinct layers that must be managed sequentially:
- Control Plane: Responsible for signaling and negotiation. You must first ask LINE for a route, connect to the PLANET relay, send a
setup_reqto make the peer ring, wait for aconn_reqwhen they answer, and finally send aconn_rspto complete the handshake. - 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- Control Plane: Responsible for signaling and negotiation. You must first ask LINE for a route, connect to the PLANET relay, send a
Configure device types for feature access
mainThe
deviceoption in theBaseClientconstructor 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 likegetContactsV3,getContactCalendarEvents, and VOOM/Timeline REST API access viaclient.voomRest().
If you encounter an
API method not capableerror, you likely need to switch your device type.Work around CORS restrictions for LINEJS in Browser
mainWhen 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:
- Proxy Server: Set up a proxy server that forwards requests to the LINE endpoint.
- 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.
Extend BaseStorage to create custom storage
mainIf 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
BaseStorageclass.import { BaseStorage } from "@evex/linejs/storage"; // Implement your own storage logic by extending BaseStorage class MyCloudStorage extends BaseStorage { // ... implementation }Use the Client wrapper for high-level features
mainWhile
BaseClientprovides low-level Thrift RPC access, theClientwrapper (built on top ofBaseClient) provides a richer, more developer-friendly API for common tasks. UseClientif 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()andliff.getToken()
- Manage profile:
How the outgoing audio call flow works
mainAn 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:
- Acquire a Call Route: Use
client.call.acquireRouteto get routing metadata, PLANET endpoints, and bootstrap parameters (mpkey). Routes are short-lived. - Connect the PLANET Transport: Use
PlanetTransport.connect({ route })to initialize the UDP socket and derive transport encryption keys via ECDH. - Send
setup_req: Usetransport.inviteDetailed({ to })to start ringing the peer. This sends a Cassini setup message inside an encrypted PLANET frame. - Learn Remote Nonce: The first server reply (
setup_rsp) provides the relay's nonce, which is required for subsequent valid PLANET headers. - Wait for
conn_req: When the peer answers, the relay sends a connection request. Usetransport.waitForAnswerDetailedto handle this. - Send SRTP/Opus Media: Once
mediaReadyis true, send audio usingtransport.send(). The payload must be the LINE audio payload (Opus with a specific prefix), not a raw RTP packet. - 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();- Acquire a Call Route: Use
Understand the extractor's auto-apply logic and tiers
mainThe extractor uses three tiers of evidence to decide whether to automatically apply changes from an APK to the
linejstypes. This prevents incorrect mappings caused by R8/ProGuard obfuscation.Evidence Tiers
Tier Method Reliability A Canonical name Identity: LINE does not obfuscate com.linecorp.square.protocol.thrift.*B Wire RPC string Strong: Keyed by R8 short name; only kept if field names overlap C Field-name overlap Weak: Useful for large enums, but unreliable for small, generic structures Auto-apply Rules
Change Kind Auto-applied? Condition New enum value (Tier A) Yes Additive New enum value (Tier B/C) Conditional Only if enum has $\ge$ --enum-add-min-members(default: 16)New struct field (Tier A) Yes Additive New struct field (Tier B) Conditional Only if overlap $> $ --min-overlap(0.6) AND shares $\ge$--min-shared-fields(3)New struct field (Tier C) No Reported for manual review New type (enum/struct) Yes Canonical names only Field change (Tier A) Yes High confidence Field change (Tier B/C) Conditional Requires --min-overlap(0.6) and unique field-name setsObfuscated R8-synthetic names No Prevents noise Note: A full report of what was applied, held, or mismatched is generated at
<decompiled-dir>/extract_report.json.Handle E2EE (End-to-End Encryption) requirements
mainMost LINE chat messages are encrypted. You cannot read
op.message.textdirectly from a polling event. You must use thee2eeservice to decrypt the message chunks.Required Pattern:
const msg = await client.e2ee.decryptE2EEMessage(op.message); console.log(msg.text);Key Features of LINEJS
mainLINEJS 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
RateLimitare enabled to protect your account from automated detection or bans.
Install LINEJS
mainLINEJS 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/linejsBun (via JSR):
bunx --bun jsr add @evex/linejsDeno (via JSR):
deno add @evex/linejsnpx jsr add @evex/linejs