How to Extend LINEJS with Custom Services: A Complete Developer Guide
Extend LINEJS by implementing the BaseService interface to create modular service classes that automatically inherit HTTP request handling, Thrift serialization, and end-to-end encryption capabilities from the shared BaseClient.
LINEJS is built around a modular service architecture where each LINE API feature (Talk, Square, Auth) lives in its own service class. To extend LINEJS with custom services, you create a class implementing the BaseService interface and instantiate it within a BaseClient subclass, giving your custom code immediate access to the library's core infrastructure without modifying the upstream source.
Understanding the Service Architecture
The LINEJS codebase separates concerns through a strict service layer. Every built-in service follows the same pattern you will use for custom extensions.
The BaseService Interface
All services must satisfy the contract defined in packages/linejs/base/service/types.ts. The interface requires four properties:
client: TheBaseClientinstance providing shared utilitiesprotocolType: Thrift protocol identifier (e.g.,4for TalkService-compatible binary protocol)requestPath: API endpoint path (e.g.,/S4)errorName: String identifier for error reporting
As implemented in evex-dev/linejs, this interface ensures every service can access the same low-level request infrastructure.
BaseClient Shared Utilities
When you create a custom service, the BaseClient instance passed to your constructor provides enterprise-grade features out of the box:
- HTTP request handling via
client.request.request(defined inpackages/linejs/base/core/mod.tslines 68-71) - Thrift definitions via
client.thrift.def(line 70) - Device and endpoint configuration (lines 60-64)
- Continuable pagination via
client.continueRequest(lines 13-14) - End-to-end encryption via
client.e2ee(lines 72-73) - Event emitter via
TypedEventEmitter(lines 1-2)
The BaseClient constructor wires built-in services at lines 78-86 of packages/linejs/base/core/mod.ts, creating the pattern you will replicate for custom services.
Step-by-Step Implementation
Follow these four steps to add a production-ready custom service to your LINEJS application.
1. Create the Service Class
Create a new folder under packages/linejs/base/service/ (e.g., myservice/) containing a mod.ts file. Implement BaseService and define your API methods using the inherited request handler.
// packages/linejs/base/service/myservice/mod.ts
import type { BaseClient } from "../../core/mod.ts";
import type { BaseService } from "../types.ts";
import type * as LINETypes from "@evex/linejs-types";
export class MyService implements BaseService {
client: BaseClient;
protocolType: number = 4; // Matches TalkService protocol
requestPath = "/S4"; // Adjust based on your API endpoint
errorName = "MyServiceError";
constructor(client: BaseClient) {
this.client = client;
}
/** Example API call using LINEJS request infrastructure */
async getFoo(id: string): Promise<LINETypes.Foo> {
return await this.client.request.request(
[["fooId", 1, id]], // Thrift payload
"getFoo", // Method name
this.protocolType, // Protocol identifier
true, // Requires auth
this.requestPath, // Endpoint path
);
}
}
2. Export from the Service Barrel
To make your service importable alongside built-in services, add it to the barrel export at packages/linejs/base/service/mod.ts. This step is optional if you intend to keep the service private to your application.
// packages/linejs/base/service/mod.ts
export { MyService } from "./myservice/mod.ts"; // Add this line
The existing barrel exports built-in services from lines 1-8 of this file.
3. Extend BaseClient
Instead of modifying the core library, subclass BaseClient to expose your service as a strongly-typed property. This approach preserves your changes across LINEJS updates.
// custom-client.ts
import { BaseClient } from "./base/core/mod.ts";
import { MyService } from "./base/service/mod.ts";
export class ExtendedClient extends BaseClient {
readonly myService: MyService;
constructor(init: ConstructorParameters<typeof BaseClient>[0]) {
super(init);
this.myService = new MyService(this);
}
}
This pattern mirrors the internal implementation where BaseClient instantiates built-in services like TalkService and SquareService within its constructor.
4. Use Your Custom Service
Instantiate your extended client and call custom methods with full TypeScript support and automatic error handling.
// usage.ts
import { ExtendedClient } from "./custom-client.ts";
const client = new ExtendedClient({
device: "Android",
version: "12.0",
});
await client.loginProcess.loginWithEmail("you@example.com", "password");
// Access your custom service
const result = await client.myService.getFoo("abc123");
console.log("Foo:", result);
Why Subclass Instead of Modify?
Subclassing BaseClient offers three critical advantages for extending LINEJS with custom services:
- Update isolation: Core library updates from
evex-dev/linejswill not overwrite your custom service implementations - Type safety: You add strongly-typed properties without altering the generated typings of the original package
- Future compatibility: New built-in services added to
BaseClientautomatically propagate to your subclass
If you must patch the core library directly—such as when maintaining a public fork—add your service instantiation within the BaseClient constructor following the pattern at lines 78-86 of packages/linejs/base/core/mod.ts.
Summary
- Service contract: Implement
BaseServicefrompackages/linejs/base/service/types.tsto ensure compatibility with LINEJS request handling - Infrastructure access: Your service receives a
BaseClientinstance providing HTTP requests, Thrift serialization, E2EE, and pagination viathis.client - Implementation path: Create the class → export from
mod.ts→ subclassBaseClient→ instantiate withnew MyService(this) - Best practice: Use client subclassing rather than editing
BaseClientdirectly to maintain update compatibility - Code locations: Reference
packages/linejs/base/core/mod.tsfor the core client andpackages/linejs/base/service/mod.tsfor service exports
Frequently Asked Questions
Do I need to implement my own HTTP client or encryption layer?
No. When you implement BaseService and receive the BaseClient instance in your constructor, you inherit the existing infrastructure. According to the LINEJS source code, BaseClient provides this.client.request.request for HTTP handling, this.client.e2ee for end-to-end encryption, and this.client.thrift.def for serialization. Your service class focuses solely on defining the Thrift payload structure and method names.
Can I use custom services without modifying the LINEJS source code?
Yes. You can keep your service implementation entirely within your application codebase. Simply import BaseClient and BaseService from the LINEJS package, implement your service class in your own files, and subclass BaseClient to wire it together. You only need to edit packages/linejs/base/service/mod.ts if you want your service exported from the library's public API surface.
What protocol type should I use for custom LINE API endpoints?
Use protocolType = 4 for standard LINE API services, which matches the binary protocol used by TalkService and other core services in the LINE ecosystem. The requestPath should match your specific endpoint (e.g., /S4 for certain service types). If you are implementing a completely custom microservice unrelated to LINE's Thrift infrastructure, you may use the raw HTTP utilities from BaseClient instead of the Thrift request method.
How do I handle pagination in custom service methods?
Use the client.continueRequest utility defined in packages/linejs/base/core/mod.ts at lines 13-14. Wrap your async fetch method with continueRequest to automatically handle continuation tokens and paginated responses. This ensures your custom service behaves identically to built-in services like getNextMessages, providing a consistent interface for consuming large result sets.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →