# How to Extend LINEJS with Custom Services: A Complete Developer Guide

> Learn to extend LINEJS with custom services by implementing BaseService. Inherit HTTP handling, Thrift serialization, and encryption from BaseClient. Complete developer guide.

- Repository: [Evex  Developers/linejs](https://github.com/evex-dev/linejs)
- Tags: how-to-guide
- Published: 2026-03-01

---

**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`](https://github.com/evex-dev/linejs/blob/main/packages/linejs/base/service/types.ts). The interface requires four properties:

- `client`: The `BaseClient` instance providing shared utilities
- `protocolType`: Thrift protocol identifier (e.g., `4` for TalkService-compatible binary protocol)
- `requestPath`: API endpoint path (e.g., `/S4`)
- `errorName`: String identifier for error reporting

As implemented in [evex-dev/linejs](https://github.com/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 in [`packages/linejs/base/core/mod.ts`](https://github.com/evex-dev/linejs/blob/main/packages/linejs/base/core/mod.ts) lines 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`](https://github.com/evex-dev/linejs/blob/main/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`](https://github.com/evex-dev/linejs/blob/main/mod.ts) file. Implement `BaseService` and define your API methods using the inherited request handler.

```ts
// 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`](https://github.com/evex-dev/linejs/blob/main/packages/linejs/base/service/mod.ts). This step is optional if you intend to keep the service private to your application.

```ts
// 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.

```ts
// 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.

```ts
// 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/linejs` will 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 `BaseClient` automatically 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`](https://github.com/evex-dev/linejs/blob/main/packages/linejs/base/core/mod.ts).

## Summary

- **Service contract**: Implement `BaseService` from [`packages/linejs/base/service/types.ts`](https://github.com/evex-dev/linejs/blob/main/packages/linejs/base/service/types.ts) to ensure compatibility with LINEJS request handling
- **Infrastructure access**: Your service receives a `BaseClient` instance providing HTTP requests, Thrift serialization, E2EE, and pagination via `this.client`
- **Implementation path**: Create the class → export from [`mod.ts`](https://github.com/evex-dev/linejs/blob/main/mod.ts) → subclass `BaseClient` → instantiate with `new MyService(this)`
- **Best practice**: Use client subclassing rather than editing `BaseClient` directly to maintain update compatibility
- **Code locations**: Reference [`packages/linejs/base/core/mod.ts`](https://github.com/evex-dev/linejs/blob/main/packages/linejs/base/core/mod.ts) for the core client and [`packages/linejs/base/service/mod.ts`](https://github.com/evex-dev/linejs/blob/main/packages/linejs/base/service/mod.ts) for 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`](https://github.com/evex-dev/linejs/blob/main/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`](https://github.com/evex-dev/linejs/blob/main/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.