Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,17 @@ jobs:
run: export NODE_OPTIONS=--openssl-legacy-provider; npm run apidocs
- name: Test building docs
run: export NODE_OPTIONS=--openssl-legacy-provider; npm run docs:build
- name: Test building examples
- name: Test building examples (CJS)
run: |
cd examples/echo-bot-ts
npm run build-sdk
npm install
npm run build
cd -
- name: Test building examples (ESM)
run: |
cd examples/echo-bot-ts-esm
npm run build-sdk
npm install
npm run build
cd -
8 changes: 4 additions & 4 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
const utils = require('./utils.ts');
import { copyFile, rewriteFile } from './utils.js';

utils.copyFile('README.md', 'index.md');
utils.copyFile('CONTRIBUTING.md', 'CONTRIBUTING.md');
copyFile('README.md', 'index.md');
copyFile('CONTRIBUTING.md', 'CONTRIBUTING.md');

utils.rewriteFile('../apidocs/README.md', /\(CONTRIBUTING.md\)/g, '(../CONTRIBUTING.md)');
rewriteFile('../apidocs/README.md', /\(CONTRIBUTING.md\)/g, '(../CONTRIBUTING.md)');

export default {
title: 'line-bot-sdk-nodejs',
Expand Down
30 changes: 18 additions & 12 deletions docs/.vitepress/utils.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
const fs = require('fs');
const path = require('path');
import fs from 'node:fs';
import path from 'node:path';
import {fileURLToPath} from 'node:url';
import {dirname} from 'node:path';

// __dirname is not available in ESM, so we need to derive it
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

function copyFile(sourceFilename, targetFilename) {
const sourcePath = path.join(__dirname, '../../', sourceFilename);
const targetPath = path.join(__dirname, '../', targetFilename);
const md = fs.readFileSync(sourcePath, 'utf-8');
fs.writeFileSync(targetPath, md);
const sourcePath = path.join(__dirname, '../../', sourceFilename);
const targetPath = path.join(__dirname, '../', targetFilename);
const md = fs.readFileSync(sourcePath, 'utf-8');
fs.writeFileSync(targetPath, md);
}

function rewriteFile(filename, regex, replacement) {
console.log("Rewriting file: ", filename, " with regex: ", regex, " and replacement: ", replacement)
const content = fs.readFileSync(path.join(__dirname, filename), 'utf-8');
const newContent = content.replace(regex, replacement);
fs.writeFileSync(path.join(__dirname, filename), newContent);
console.log("Rewriting file: ", filename, " with regex: ", regex, " and replacement: ", replacement)
const content = fs.readFileSync(path.join(__dirname, filename), 'utf-8');
const newContent = content.replace(regex, replacement);
fs.writeFileSync(path.join(__dirname, filename), newContent);
}

export {
copyFile,
rewriteFile,
copyFile,
rewriteFile
};
59 changes: 59 additions & 0 deletions examples/echo-bot-ts-esm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Echo Bot for LINE using TypeScript and ESM

Welcome to this simple guide on how to create an Echo Bot for the LINE messaging platform using TypeScript and ECMAScript Modules (ESM).
An Echo Bot is a basic bot that replies to a user's message with the same content.
This tutorial will help you set up a LINE Echo Bot from scratch.

## Prerequisite

- Node.js version 18 or higher
- You've created a channel in the LINE Developers Console, and got your channel access token and channel secret.
- Read https://developers.line.biz/en/docs/messaging-api/getting-started/#using-console if you haven't done this yet.

## Installation

- Clone the repository.

```bash
git clone https://github.com/line/line-bot-sdk-nodejs.git
```

- Change directory to this example.

```bash
cd line-bot-sdk-nodejs/examples/echo-bot-ts-esm
```

- Install all dependencies.

```bash
npm run build-sdk
npm install
```

- Set the following environment variables.

```bash
export CHANNEL_ACCESS_TOKEN=<YOUR_CHANNEL_ACCESS_TOKEN>
export CHANNEL_SECRET=<YOUR_CHANNEL_SECRET>
export PORT=<YOUR_PORT>
```

- Set up your webhook URL in your LINE Official Account to be in the following format. Don't forget to disable the greeting messages and auto-response messages for convenience.

```bash
https://example.com/callback
```

- Build the application.

```bash
npm run build
```

- Run the application.

```bash
npm start
```

11 changes: 11 additions & 0 deletions examples/echo-bot-ts-esm/environment.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
declare global {
namespace NodeJS {
interface ProcessEnv {
CHANNEL_ACCESS_TOKEN: string;
CHANNEL_SECRET: string;
PORT: string;
}
}
}

export {};
110 changes: 110 additions & 0 deletions examples/echo-bot-ts-esm/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// Import all dependencies, mostly using destructuring for better view.
import {
ClientConfig,
MessageAPIResponseBase,
messagingApi,
middleware,
MiddlewareConfig,
webhook,
HTTPFetchError,
} from '@line/bot-sdk';
import express, {Application, Request, Response} from 'express';

// Setup all LINE client and Express configurations.
const clientConfig: ClientConfig = {
channelAccessToken: process.env.CHANNEL_ACCESS_TOKEN || '',
};

const middlewareConfig: MiddlewareConfig = {
channelSecret: process.env.CHANNEL_SECRET || '',
};

const PORT = process.env.PORT || 3000;

// Create a new LINE SDK client.
const client = new messagingApi.MessagingApiClient(clientConfig);

// Create a new Express application.
const app: Application = express();

const isTextEvent = (event: any): event is webhook.MessageEvent & { message: webhook.TextMessageContent } => {
return event.type === 'message' && event.message && event.message.type === 'text';
};

// Function handler to receive the text.
const textEventHandler = async (event: webhook.Event): Promise<MessageAPIResponseBase | undefined> => {
// Process all variables here.
if (!isTextEvent(event)) {
return;
}

// Process all message related variables here.
// Create a new message.
// Reply to the user.
await client.replyMessage({
replyToken: event.replyToken as string,
messages: [{
type: 'text',
text: event.message.text,
}],
});
};

// Register the LINE middleware.
// As an alternative, you could also pass the middleware in the route handler, which is what is used here.
// app.use(middleware(middlewareConfig));

// Route handler to receive webhook events.
// This route is used to receive connection tests.
app.get(
'/',
async (_: Request, res: Response): Promise<Response> => {
return res.status(200).json({
status: 'success',
message: 'Connected successfully!',
});
}
);

// This route is used for the Webhook.
app.post(
'/callback',
middleware(middlewareConfig),
async (req: Request, res: Response): Promise<Response> => {
const callbackRequest: webhook.CallbackRequest = req.body;
const events: webhook.Event[] = callbackRequest.events!;

// Process all the received events asynchronously.
const results = await Promise.all(
events.map(async (event: webhook.Event) => {
try {
await textEventHandler(event);
} catch (err: unknown) {
if (err instanceof HTTPFetchError) {
console.error(err.status);
console.error(err.headers.get('x-line-request-id'));
console.error(err.body);
} else if (err instanceof Error) {
console.error(err);
}

// Return an error message.
return res.status(500).json({
status: 'error',
});
}
})
);

// Return a successful message.
return res.status(200).json({
status: 'success',
results,
});
}
);

// Create a server and listen to it.
app.listen(PORT, () => {
console.log(`Application is live and listening on port ${PORT}`);
});
Loading