discord-bridge 0.2.0 → 0.2.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "discord-bridge",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Claude Code <-> Discord bidirectional communication bridge",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,11 +1,20 @@
1
1
  #!/bin/bash
2
- # Discord Bridge ヘルスチェック
2
+ # Discord Bridge ヘルスチェック(チャンネル登録込み)
3
3
  # Usage: discord-status.sh
4
4
  PORT="${DISCORD_BRIDGE_PORT:-13456}"
5
5
  PROJECT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
6
6
  CHANNEL_ID=""
7
+ ALLOWED_USER_IDS=""
7
8
  if [ -n "$PROJECT_ROOT" ] && [ -f "$PROJECT_ROOT/.discord-bridge.json" ]; then
8
- CHANNEL_ID=$(python3 -c "import json; print(json.load(open('$PROJECT_ROOT/.discord-bridge.json'))['channelId'])" 2>/dev/null)
9
+ CHANNEL_ID=$(python3 -c "import json; print(json.load(open('$PROJECT_ROOT/.discord-bridge.json')).get('channelId', ''))" 2>/dev/null)
10
+ ALLOWED_USER_IDS=$(python3 -c "import json; print(json.dumps(json.load(open('$PROJECT_ROOT/.discord-bridge.json')).get('allowedUserIds', [])))" 2>/dev/null)
11
+ fi
12
+
13
+ # チャンネル設定をサーバーに登録
14
+ if [ -n "$CHANNEL_ID" ] && [ -n "$ALLOWED_USER_IDS" ]; then
15
+ curl -s -X POST "http://localhost:${PORT}/register-channel" \
16
+ -H "Content-Type: application/json" \
17
+ -d "{\"channelId\": \"${CHANNEL_ID}\", \"allowedUserIds\": ${ALLOWED_USER_IDS}}" > /dev/null
9
18
  fi
10
19
 
11
20
  if [ -n "$CHANNEL_ID" ]; then
package/server/index.js CHANGED
@@ -14,7 +14,6 @@ import path from "path";
14
14
 
15
15
  const CONFIG = {
16
16
  token: process.env.DISCORD_BRIDGE_TOKEN,
17
- allowedUserIds: [],
18
17
  host: "127.0.0.1",
19
18
  port: parseInt(process.env.DISCORD_BRIDGE_PORT || "13456", 10),
20
19
  defaultTimeout: 5 * 60 * 1000,
@@ -24,17 +23,19 @@ const CONFIG = {
24
23
  sseKeepAliveInterval: 30 * 1000,
25
24
  };
26
25
 
27
- function isAllowedUser(authorId) {
28
- return CONFIG.allowedUserIds.includes(authorId);
26
+ // Per-channel allowed user IDs (registered via POST /register-channel)
27
+ const channelAllowedUsers = new Map();
28
+
29
+ function isAllowedUser(authorId, channelId) {
30
+ const allowed = channelAllowedUsers.get(channelId);
31
+ if (!allowed || allowed.length === 0) return true; // 未登録チャンネルは全員許可
32
+ return allowed.includes(authorId);
29
33
  }
30
34
 
31
35
  function validateConfig() {
32
36
  if (!CONFIG.token) {
33
37
  throw new Error("Missing required environment variable: DISCORD_BRIDGE_TOKEN");
34
38
  }
35
- if (CONFIG.allowedUserIds.length === 0) {
36
- throw new Error("Missing required field in .discord-bridge.json: allowedUserIds (must have at least one entry)");
37
- }
38
39
  }
39
40
 
40
41
  // ---------------------------------------------------------------------------
@@ -97,8 +98,8 @@ async function initDiscord() {
97
98
  });
98
99
 
99
100
  discordClient.on("messageCreate", (message) => {
100
- if (!isAllowedUser(message.author.id)) return;
101
101
  if (message.author.bot) return;
102
+ if (!isAllowedUser(message.author.id, message.channel.id)) return;
102
103
 
103
104
  const chId = message.channel.id;
104
105
 
@@ -212,10 +213,25 @@ app.get("/health", (_req, res) => {
212
213
  response.channel = channelId;
213
214
  response.queuedMessages = getMessageQueue(channelId).length;
214
215
  response.sseSubscribers = getSseSubscribers(channelId).size;
216
+ response.allowedUserIds = channelAllowedUsers.get(channelId) ?? [];
215
217
  }
216
218
  res.json(response);
217
219
  });
218
220
 
221
+ // ---- POST /register-channel ----
222
+ app.post("/register-channel", (req, res) => {
223
+ const { channelId, allowedUserIds } = req.body;
224
+ if (!channelId) {
225
+ return res.status(400).json({ status: "error", error: "channelId is required" });
226
+ }
227
+ if (!Array.isArray(allowedUserIds)) {
228
+ return res.status(400).json({ status: "error", error: "allowedUserIds must be an array" });
229
+ }
230
+ const ids = allowedUserIds.filter((id) => typeof id === "string");
231
+ channelAllowedUsers.set(channelId, ids);
232
+ res.json({ status: "ok", channelId, allowedUserIds: ids });
233
+ });
234
+
219
235
  // ---- GET /events (SSE) ----
220
236
  app.get("/events", (req, res) => {
221
237
  const channelId = req.query.channelId;
@@ -297,7 +313,8 @@ app.post("/ask", async (req, res) => {
297
313
  fields,
298
314
  });
299
315
 
300
- await sendMessage(channelId, `<@${CONFIG.allowedUserIds[0]}>`, [embed]);
316
+ const mentionUser = channelAllowedUsers.get(channelId)?.[0];
317
+ await sendMessage(channelId, mentionUser ? `<@${mentionUser}>` : null, [embed]);
301
318
 
302
319
  try {
303
320
  const reply = await waitForReply(channelId, timeoutMs);
@@ -453,25 +470,7 @@ app.get("/messages", async (req, res) => {
453
470
  // Lifecycle
454
471
  // ---------------------------------------------------------------------------
455
472
 
456
- async function loadProjectConfig() {
457
- const configPath = path.join(process.cwd(), ".discord-bridge.json");
458
- let projectConfig;
459
- try {
460
- const raw = await readFile(configPath, "utf-8");
461
- projectConfig = JSON.parse(raw);
462
- } catch {
463
- throw new Error(`.discord-bridge.json not found or invalid JSON in ${process.cwd()}`);
464
- }
465
-
466
- if (Array.isArray(projectConfig.allowedUserIds)) {
467
- CONFIG.allowedUserIds = projectConfig.allowedUserIds.filter(
468
- (id) => typeof id === "string"
469
- );
470
- }
471
- }
472
-
473
473
  async function main() {
474
- await loadProjectConfig();
475
474
  validateConfig();
476
475
  await initDiscord();
477
476