@mulmobridge/line 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +56 -2
  2. package/dist/index.js +14 -23
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -14,7 +14,11 @@ LINE bridge for [MulmoClaude](https://github.com/receptron/mulmoclaude). Uses we
14
14
 
15
15
  ### 2. Set up ngrok (for development)
16
16
 
17
+ [ngrok](https://ngrok.com) is a tunneling tool that exposes a local port to the internet so LINE's webhooks can reach your machine.
18
+
17
19
  ```bash
20
+ brew install ngrok
21
+ ngrok config add-authtoken <your-token> # from ngrok dashboard
18
22
  ngrok http 3002
19
23
  # Copy the https://xxxx.ngrok-free.app URL
20
24
  ```
@@ -22,9 +26,9 @@ ngrok http 3002
22
26
  ### 3. Configure the webhook
23
27
 
24
28
  In the LINE Developers Console → Messaging API tab:
25
- - **Webhook URL**: `https://xxxx.ngrok-free.app/webhook`
29
+ - **Webhook URL**: `https://xxxx.ngrok-free.app/webhook` — the trailing `/webhook` is **required** (without it you get 404)
26
30
  - **Use webhook**: enabled
27
- - **Auto-reply messages**: disabled (so LINE's default replies don't interfere)
31
+ - **Auto-reply messages**: disabled (LINE Official Account settings → Auto-reply messages → OFF, otherwise you get double replies)
28
32
 
29
33
  ### 4. Run the bridge
30
34
 
@@ -55,12 +59,62 @@ Scan the QR code in the LINE Developers Console → Messaging API tab. Send a me
55
59
  | `LINE_BRIDGE_PORT` | No | Webhook port (default: 3002) |
56
60
  | `MULMOCLAUDE_API_URL` | No | Default `http://localhost:3001` |
57
61
  | `MULMOCLAUDE_AUTH_TOKEN` | No | Bearer token |
62
+ | `LINE_BRIDGE_DEFAULT_ROLE` | No | Role id to seed new bridge sessions with (e.g. `coder`, `general`). Applied ONLY when a line session first appears — once the user switches role via `/role <id>` the session's own role wins. Unknown role ids silently fall back to the server's default with a warn log. |
63
+ | `BRIDGE_DEFAULT_ROLE` | No | Same as above but shared across every bridge. Transport-specific `LINE_BRIDGE_DEFAULT_ROLE` wins when both are set. |
58
64
 
59
65
  ## Notes
60
66
 
61
67
  - LINE reply tokens expire in **1 minute**. Since Claude responses can take longer, the bridge uses **push messages** instead of reply messages. This requires your bot to be a verified/certified account for push to work with all users, OR the user must have added the bot as a friend first.
62
68
  - LINE limits messages to 5 per push call and ~5000 chars per message. Long replies are automatically chunked.
63
69
 
70
+ ## Detailed Setup Guide
71
+
72
+ For step-by-step instructions with troubleshooting:
73
+
74
+ - [English](https://github.com/receptron/mulmoclaude/blob/main/docs/message_apps/line/README.md)
75
+ - [Japanese](https://github.com/receptron/mulmoclaude/blob/main/docs/message_apps/line/README.ja.md)
76
+
77
+ ## Ecosystem
78
+
79
+ Part of the [`@mulmobridge/*`](https://www.npmjs.com/~mulmobridge) package family.
80
+
81
+ **Shared libraries:**
82
+
83
+ - [`@mulmobridge/client`](https://www.npmjs.com/package/@mulmobridge/client) — socket.io client library used by every bridge below
84
+ - [`@mulmobridge/protocol`](https://www.npmjs.com/package/@mulmobridge/protocol) — wire types and constants
85
+ - [`@mulmobridge/chat-service`](https://www.npmjs.com/package/@mulmobridge/chat-service) — server-side relay + session store
86
+ - [`@mulmobridge/relay`](https://www.npmjs.com/package/@mulmobridge/relay) — Cloudflare Workers webhook proxy
87
+ - [`@mulmobridge/mock-server`](https://www.npmjs.com/package/@mulmobridge/mock-server) — mock server for local bridge development
88
+
89
+ **Bridges** (one npm package per platform):
90
+
91
+ - [`@mulmobridge/bluesky`](https://www.npmjs.com/package/@mulmobridge/bluesky) — Bluesky DMs over atproto
92
+ - [`@mulmobridge/chatwork`](https://www.npmjs.com/package/@mulmobridge/chatwork) — Chatwork (Japanese business chat)
93
+ - [`@mulmobridge/cli`](https://www.npmjs.com/package/@mulmobridge/cli) — interactive terminal bridge
94
+ - [`@mulmobridge/discord`](https://www.npmjs.com/package/@mulmobridge/discord) — Discord bot via Gateway
95
+ - [`@mulmobridge/email`](https://www.npmjs.com/package/@mulmobridge/email) — IMAP poll + SMTP reply, threading preserved
96
+ - [`@mulmobridge/google-chat`](https://www.npmjs.com/package/@mulmobridge/google-chat) — Google Chat via MulmoBridge relay
97
+ - [`@mulmobridge/irc`](https://www.npmjs.com/package/@mulmobridge/irc) — IRC (Libera, Freenode, custom)
98
+ - [`@mulmobridge/line`](https://www.npmjs.com/package/@mulmobridge/line) — LINE Messaging API via MulmoBridge relay ← **this package**
99
+ - [`@mulmobridge/line-works`](https://www.npmjs.com/package/@mulmobridge/line-works) — LINE Works (enterprise LINE)
100
+ - [`@mulmobridge/mastodon`](https://www.npmjs.com/package/@mulmobridge/mastodon) — Mastodon DMs + mentions
101
+ - [`@mulmobridge/matrix`](https://www.npmjs.com/package/@mulmobridge/matrix) — Matrix / Element
102
+ - [`@mulmobridge/mattermost`](https://www.npmjs.com/package/@mulmobridge/mattermost) — Mattermost
103
+ - [`@mulmobridge/messenger`](https://www.npmjs.com/package/@mulmobridge/messenger) — Facebook Messenger via MulmoBridge relay
104
+ - [`@mulmobridge/nostr`](https://www.npmjs.com/package/@mulmobridge/nostr) — Nostr NIP-04 encrypted DMs
105
+ - [`@mulmobridge/rocketchat`](https://www.npmjs.com/package/@mulmobridge/rocketchat) — Rocket.Chat
106
+ - [`@mulmobridge/signal`](https://www.npmjs.com/package/@mulmobridge/signal) — Signal via signal-cli-rest-api
107
+ - [`@mulmobridge/slack`](https://www.npmjs.com/package/@mulmobridge/slack) — Slack Socket Mode
108
+ - [`@mulmobridge/teams`](https://www.npmjs.com/package/@mulmobridge/teams) — Microsoft Teams via Bot Framework
109
+ - [`@mulmobridge/telegram`](https://www.npmjs.com/package/@mulmobridge/telegram) — Telegram bot
110
+ - [`@mulmobridge/twilio-sms`](https://www.npmjs.com/package/@mulmobridge/twilio-sms) — SMS via Twilio Programmable Messaging
111
+ - [`@mulmobridge/viber`](https://www.npmjs.com/package/@mulmobridge/viber) — Viber Public Account bots
112
+ - [`@mulmobridge/webhook`](https://www.npmjs.com/package/@mulmobridge/webhook) — generic HTTP webhook bridge
113
+ - [`@mulmobridge/whatsapp`](https://www.npmjs.com/package/@mulmobridge/whatsapp) — WhatsApp Cloud API via MulmoBridge relay
114
+ - [`@mulmobridge/xmpp`](https://www.npmjs.com/package/@mulmobridge/xmpp) — XMPP / Jabber
115
+ - [`@mulmobridge/zulip`](https://www.npmjs.com/package/@mulmobridge/zulip) — Zulip
116
+
117
+
64
118
  ## License
65
119
 
66
120
  MIT
package/dist/index.js CHANGED
@@ -15,36 +15,39 @@
15
15
  import "dotenv/config";
16
16
  import crypto from "crypto";
17
17
  import express from "express";
18
- import { createBridgeClient } from "@mulmobridge/client";
18
+ import { createBridgeClient, chunkText } from "@mulmobridge/client";
19
19
  const TRANSPORT_ID = "line";
20
20
  const PORT = Number(process.env.LINE_BRIDGE_PORT) || 3002;
21
21
  const channelSecret = process.env.LINE_CHANNEL_SECRET;
22
22
  const channelAccessToken = process.env.LINE_CHANNEL_ACCESS_TOKEN;
23
23
  if (!channelSecret || !channelAccessToken) {
24
- console.error("LINE_CHANNEL_SECRET and LINE_CHANNEL_ACCESS_TOKEN are required.\n" +
25
- "See README for setup instructions.");
24
+ console.error("LINE_CHANNEL_SECRET and LINE_CHANNEL_ACCESS_TOKEN are required.\n" + "See README for setup instructions.");
26
25
  process.exit(1);
27
26
  }
28
27
  const client = createBridgeClient({ transportId: TRANSPORT_ID });
29
- client.onPush((ev) => {
30
- pushMessage(ev.chatId, ev.message).catch((err) => console.error(`[line] push send failed: ${err}`));
28
+ client.onPush((pushEvent) => {
29
+ pushMessage(pushEvent.chatId, pushEvent.message).catch((err) => console.error(`[line] push send failed: ${err}`));
31
30
  });
32
31
  // ── LINE API helpers ────────────────────────────────────────────
33
32
  async function pushMessage(userId, text) {
34
- const messages = chunkText(text).map((t) => ({ type: "text", text: t }));
33
+ const messages = chunkText(text, 5000).map((messageText) => ({
34
+ type: "text",
35
+ text: messageText,
36
+ }));
35
37
  // LINE allows max 5 messages per push
36
38
  for (let i = 0; i < messages.length; i += 5) {
37
39
  try {
40
+ const requestBody = {
41
+ to: userId,
42
+ messages: messages.slice(i, i + 5),
43
+ };
38
44
  const res = await fetch("https://api.line.me/v2/bot/message/push", {
39
45
  method: "POST",
40
46
  headers: {
41
47
  "Content-Type": "application/json",
42
48
  Authorization: `Bearer ${channelAccessToken}`,
43
49
  },
44
- body: JSON.stringify({
45
- to: userId,
46
- messages: messages.slice(i, i + 5),
47
- }),
50
+ body: JSON.stringify(requestBody),
48
51
  signal: AbortSignal.timeout(30_000),
49
52
  });
50
53
  if (!res.ok) {
@@ -57,21 +60,9 @@ async function pushMessage(userId, text) {
57
60
  }
58
61
  }
59
62
  }
60
- function chunkText(text, max = 5000) {
61
- if (text.length === 0)
62
- return ["(empty reply)"];
63
- const chunks = [];
64
- for (let i = 0; i < text.length; i += max) {
65
- chunks.push(text.slice(i, i + max));
66
- }
67
- return chunks;
68
- }
69
63
  // ── Signature verification ──────────────────────────────────────
70
64
  function verifySignature(body, signature) {
71
- const expected = crypto
72
- .createHmac("SHA256", channelSecret)
73
- .update(body)
74
- .digest("base64");
65
+ const expected = crypto.createHmac("SHA256", channelSecret).update(body).digest("base64");
75
66
  if (expected.length !== signature.length)
76
67
  return false;
77
68
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mulmobridge/line",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "LINE bridge for MulmoBridge — connect a LINE bot to MulmoClaude",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -21,8 +21,8 @@
21
21
  "license": "MIT",
22
22
  "author": "Receptron Team",
23
23
  "dependencies": {
24
- "@mulmobridge/client": "^0.1.0",
25
- "@mulmobridge/protocol": "^0.1.0",
24
+ "@mulmobridge/client": "^0.1.4",
25
+ "@mulmobridge/protocol": "^0.1.4",
26
26
  "dotenv": "^17.0.0",
27
27
  "express": "^5.1.0"
28
28
  },