@elizaos/plugin-line 2.0.0-beta.1 → 2.0.3-beta.2

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 (39) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +3 -3
  3. package/package.json +22 -6
  4. package/dist/accounts.d.ts +0 -152
  5. package/dist/accounts.d.ts.map +0 -1
  6. package/dist/accounts.js +0 -258
  7. package/dist/accounts.js.map +0 -1
  8. package/dist/actions/index.d.ts +0 -1
  9. package/dist/actions/index.d.ts.map +0 -1
  10. package/dist/actions/index.js +0 -3
  11. package/dist/actions/index.js.map +0 -1
  12. package/dist/connector-account-provider.d.ts +0 -16
  13. package/dist/connector-account-provider.d.ts.map +0 -1
  14. package/dist/connector-account-provider.js +0 -82
  15. package/dist/connector-account-provider.js.map +0 -1
  16. package/dist/index.d.ts +0 -18
  17. package/dist/index.d.ts.map +0 -1
  18. package/dist/index.js +0 -60
  19. package/dist/index.js.map +0 -1
  20. package/dist/messaging.d.ts +0 -142
  21. package/dist/messaging.d.ts.map +0 -1
  22. package/dist/messaging.js +0 -357
  23. package/dist/messaging.js.map +0 -1
  24. package/dist/providers/index.d.ts +0 -7
  25. package/dist/providers/index.d.ts.map +0 -1
  26. package/dist/providers/index.js +0 -8
  27. package/dist/providers/index.js.map +0 -1
  28. package/dist/service.d.ts +0 -110
  29. package/dist/service.d.ts.map +0 -1
  30. package/dist/service.js +0 -766
  31. package/dist/service.js.map +0 -1
  32. package/dist/types.d.ts +0 -279
  33. package/dist/types.d.ts.map +0 -1
  34. package/dist/types.js +0 -106
  35. package/dist/types.js.map +0 -1
  36. package/dist/workflow-credential-provider.d.ts +0 -21
  37. package/dist/workflow-credential-provider.d.ts.map +0 -1
  38. package/dist/workflow-credential-provider.js +0 -32
  39. package/dist/workflow-credential-provider.js.map +0 -1
package/dist/service.js DELETED
@@ -1,766 +0,0 @@
1
- /**
2
- * LINE service implementation for ElizaOS.
3
- */
4
- import { logger, Service } from "@elizaos/core";
5
- import { messagingApi, middleware } from "@line/bot-sdk";
6
- import { getChatTypeFromId, LINE_SERVICE_NAME, LineApiError, LineConfigurationError, LineEventTypes, MAX_LINE_BATCH_SIZE, normalizeLineTarget, splitMessageForLine, } from "./types.js";
7
- function objectToMetadataValue(obj) {
8
- return JSON.parse(JSON.stringify(obj));
9
- }
10
- function normalizeLineQuery(query) {
11
- return query.trim().toLowerCase();
12
- }
13
- function scoreLineCandidate(values, query) {
14
- const normalized = normalizeLineQuery(query);
15
- if (!normalized) {
16
- return 0.45;
17
- }
18
- const candidates = values
19
- .filter((value) => typeof value === "string" && value.trim().length > 0)
20
- .map((value) => value.trim().toLowerCase());
21
- if (candidates.some((candidate) => candidate === normalized)) {
22
- return 1;
23
- }
24
- return candidates.some((candidate) => candidate.includes(normalized)) ? 0.8 : 0;
25
- }
26
- function lineRoomToConnectorTarget(room, score = 0.55) {
27
- const channelId = String(room.channelId ?? "");
28
- const chatType = channelId ? getChatTypeFromId(channelId) : undefined;
29
- return {
30
- target: {
31
- source: LINE_SERVICE_NAME,
32
- roomId: room.id,
33
- channelId,
34
- },
35
- label: room.name || channelId || String(room.id),
36
- kind: chatType === "user" ? "contact" : chatType || "room",
37
- description: "LINE chat from stored room context",
38
- score,
39
- contexts: ["social", "connectors"],
40
- metadata: {
41
- chatType,
42
- channelId,
43
- roomType: room.type,
44
- },
45
- };
46
- }
47
- function normalizeConnectorLimit(limit, fallback = 50) {
48
- if (!Number.isFinite(limit) || !limit || limit <= 0) {
49
- return fallback;
50
- }
51
- return Math.min(Math.floor(limit), 200);
52
- }
53
- async function readStoredMessageMemories(runtime, roomId, limit) {
54
- return runtime.getMemories({
55
- tableName: "messages",
56
- roomId,
57
- limit,
58
- orderBy: "createdAt",
59
- orderDirection: "desc",
60
- });
61
- }
62
- async function readStoredMessagesForTargets(runtime, targets, limit) {
63
- const roomIds = Array.from(new Set(targets.map((target) => target.target.roomId).filter((id) => Boolean(id))));
64
- const chunks = await Promise.all(roomIds.map((roomId) => readStoredMessageMemories(runtime, roomId, limit)));
65
- return chunks
66
- .flat()
67
- .sort((left, right) => (right.createdAt ?? 0) - (left.createdAt ?? 0))
68
- .slice(0, limit);
69
- }
70
- function filterMemoriesByQuery(memories, query, limit) {
71
- const normalized = query.trim().toLowerCase();
72
- if (!normalized) {
73
- return memories.slice(0, limit);
74
- }
75
- return memories
76
- .filter((memory) => {
77
- const text = typeof memory.content?.text === "string" ? memory.content.text : "";
78
- return text.toLowerCase().includes(normalized);
79
- })
80
- .slice(0, limit);
81
- }
82
- function quickReplyItemsFromStrings(values) {
83
- if (!Array.isArray(values)) {
84
- return undefined;
85
- }
86
- const items = values
87
- .filter((value) => typeof value === "string" && value.trim().length > 0)
88
- .slice(0, 13)
89
- .map((text) => ({
90
- type: "action",
91
- action: {
92
- type: "message",
93
- label: text.slice(0, 20),
94
- text,
95
- },
96
- }));
97
- return items.length > 0 ? items : undefined;
98
- }
99
- function lineDataFromContent(content) {
100
- const data = content.data;
101
- if (data?.line && typeof data.line === "object") {
102
- return data.line;
103
- }
104
- return data ?? {};
105
- }
106
- /**
107
- * LINE messaging service for ElizaOS agents.
108
- */
109
- export class LineService extends Service {
110
- static serviceType = LINE_SERVICE_NAME;
111
- capabilityDescription = "The agent is able to send and receive messages via LINE";
112
- settings = null;
113
- client = null;
114
- connected = false;
115
- constructor(runtime) {
116
- super(runtime);
117
- if (!runtime)
118
- return;
119
- this.settings = this.loadSettings();
120
- }
121
- /**
122
- * Start the LINE service.
123
- */
124
- static async start(runtime) {
125
- const service = new LineService(runtime);
126
- await service.initialize();
127
- return service;
128
- }
129
- static registerSendHandlers(runtime, service) {
130
- const sendHandler = async (handlerRuntime, target, content) => {
131
- await service.handleSendMessage(handlerRuntime, target, content);
132
- return undefined;
133
- };
134
- if (typeof runtime.registerMessageConnector === "function") {
135
- const registration = {
136
- source: LINE_SERVICE_NAME,
137
- label: "LINE",
138
- capabilities: [
139
- "send_message",
140
- "send_flex_message",
141
- "send_location",
142
- "send_template_message",
143
- "quick_reply",
144
- ],
145
- supportedTargetKinds: ["contact", "group", "room", "channel"],
146
- contexts: ["social", "connectors"],
147
- description: "Send LINE text, flex/card, template, quick reply, and location messages to known LINE chats.",
148
- sendHandler,
149
- resolveTargets: async (query, context) => {
150
- const normalizedTarget = normalizeLineTarget(query);
151
- const exactTarget = normalizedTarget
152
- ? [
153
- {
154
- target: {
155
- source: LINE_SERVICE_NAME,
156
- channelId: normalizedTarget,
157
- },
158
- label: normalizedTarget,
159
- kind: getChatTypeFromId(normalizedTarget) === "user"
160
- ? "contact"
161
- : getChatTypeFromId(normalizedTarget),
162
- score: 1,
163
- contexts: ["social", "connectors"],
164
- metadata: {
165
- chatType: getChatTypeFromId(normalizedTarget),
166
- },
167
- },
168
- ]
169
- : [];
170
- const roomTargets = (await service.listConnectorRooms(context.runtime))
171
- .map((room) => ({
172
- room,
173
- score: scoreLineCandidate([room.name, room.channelId, String(room.id)], query),
174
- }))
175
- .filter(({ score }) => score > 0)
176
- .map(({ room, score }) => lineRoomToConnectorTarget(room, score));
177
- return [...exactTarget, ...roomTargets]
178
- .sort((left, right) => (right.score ?? 0) - (left.score ?? 0))
179
- .slice(0, 10);
180
- },
181
- listRecentTargets: async (context) => (await service.listConnectorRooms(context.runtime))
182
- .slice(0, 10)
183
- .map((room) => lineRoomToConnectorTarget(room)),
184
- listRooms: async (context) => (await service.listConnectorRooms(context.runtime)).map((room) => lineRoomToConnectorTarget(room)),
185
- fetchMessages: async (context, params) => {
186
- const limit = normalizeConnectorLimit(params?.limit);
187
- const target = params?.target ?? context.target;
188
- if (target?.roomId) {
189
- return readStoredMessageMemories(context.runtime, target.roomId, limit);
190
- }
191
- const targets = (await service.listConnectorRooms(context.runtime))
192
- .slice(0, 10)
193
- .map((room) => lineRoomToConnectorTarget(room));
194
- return readStoredMessagesForTargets(context.runtime, targets, limit);
195
- },
196
- searchMessages: async (context, params) => {
197
- const limit = normalizeConnectorLimit(params?.limit);
198
- const target = params?.target ?? context.target;
199
- const messages = target?.roomId
200
- ? await readStoredMessageMemories(context.runtime, target.roomId, Math.max(limit, 100))
201
- : await readStoredMessagesForTargets(context.runtime, (await service.listConnectorRooms(context.runtime))
202
- .slice(0, 10)
203
- .map((room) => lineRoomToConnectorTarget(room)), Math.max(limit, 100));
204
- return filterMemoriesByQuery(messages, params.query, limit);
205
- },
206
- leaveHandler: async (handlerRuntime, params) => {
207
- const target = params.target ?? { source: LINE_SERVICE_NAME };
208
- const room = target.roomId ? await handlerRuntime.getRoom(target.roomId) : null;
209
- const channelId = String(params?.channelId ?? target.channelId ?? room?.channelId ?? "");
210
- const chatType = getChatTypeFromId(channelId);
211
- if (chatType !== "group" && chatType !== "room") {
212
- throw new Error("LINE leaveHandler requires a group or room target");
213
- }
214
- await service.leaveChat(channelId, chatType);
215
- },
216
- getUser: async (_handlerRuntime, params) => {
217
- const userId = String(params.userId ??
218
- params.username ??
219
- params.handle ??
220
- params.target?.entityId ??
221
- params.target?.channelId ??
222
- "").trim();
223
- if (!userId || getChatTypeFromId(userId) !== "user") {
224
- return null;
225
- }
226
- const user = await service.getUserProfile(userId).catch(() => null);
227
- if (!user) {
228
- return null;
229
- }
230
- return {
231
- id: user.userId,
232
- names: [user.displayName, user.userId].filter((value) => value.length > 0),
233
- agentId: _handlerRuntime.agentId,
234
- metadata: { line: objectToMetadataValue(user) },
235
- };
236
- },
237
- getChatContext: async (target, context) => {
238
- const room = target.roomId ? await context.runtime.getRoom(target.roomId) : null;
239
- const channelId = String(target.channelId ?? room?.channelId ?? "").trim();
240
- if (!channelId) {
241
- return null;
242
- }
243
- const chatType = getChatTypeFromId(channelId);
244
- let label = room?.name || channelId;
245
- let metadata = { chatType, channelId };
246
- if (chatType === "group" || chatType === "room") {
247
- const group = await service.getGroupInfo(channelId).catch(() => null);
248
- if (group?.groupName) {
249
- label = group.groupName;
250
- }
251
- metadata = {
252
- ...metadata,
253
- ...(group ? { group: objectToMetadataValue(group) } : {}),
254
- };
255
- }
256
- else {
257
- const user = await service.getUserProfile(channelId).catch(() => null);
258
- if (user?.displayName) {
259
- label = user.displayName;
260
- }
261
- metadata = {
262
- ...metadata,
263
- ...(user ? { user: objectToMetadataValue(user) } : {}),
264
- };
265
- }
266
- return {
267
- target: {
268
- source: LINE_SERVICE_NAME,
269
- roomId: target.roomId,
270
- channelId,
271
- },
272
- label,
273
- summary: `LINE ${chatType} chat`,
274
- metadata,
275
- };
276
- },
277
- getUserContext: async (entityId, context) => {
278
- const entity = typeof context.runtime.getEntityById === "function"
279
- ? await context.runtime.getEntityById(String(entityId))
280
- : null;
281
- if (!entity) {
282
- return null;
283
- }
284
- return {
285
- entityId,
286
- label: entity.names?.[0],
287
- aliases: entity.names,
288
- handles: {},
289
- metadata: entity.metadata,
290
- };
291
- },
292
- };
293
- runtime.registerMessageConnector(registration);
294
- return;
295
- }
296
- runtime.registerSendHandler(LINE_SERVICE_NAME, sendHandler);
297
- }
298
- /**
299
- * Initialize the service.
300
- */
301
- async initialize() {
302
- if (!this.runtime)
303
- return;
304
- logger.info("Starting LINE service...");
305
- // Load settings
306
- if (!this.settings) {
307
- this.settings = this.loadSettings();
308
- }
309
- this.validateSettings();
310
- // Initialize LINE client
311
- this.client = new messagingApi.MessagingApiClient({
312
- channelAccessToken: this.settings.channelAccessToken,
313
- });
314
- this.connected = true;
315
- logger.info("LINE service started");
316
- // Emit connection ready event
317
- if (this.runtime) {
318
- this.runtime.emitEvent([LineEventTypes.CONNECTION_READY], {
319
- runtime: this.runtime,
320
- source: "line",
321
- service: this,
322
- });
323
- }
324
- }
325
- /**
326
- * Stop the LINE service.
327
- */
328
- async stop() {
329
- logger.info("Stopping LINE service...");
330
- this.connected = false;
331
- this.client = null;
332
- this.settings = null;
333
- logger.info("LINE service stopped");
334
- }
335
- /**
336
- * Check if the service is connected.
337
- */
338
- isConnected() {
339
- return this.connected && this.client !== null;
340
- }
341
- /**
342
- * Get bot info.
343
- */
344
- async getBotInfo() {
345
- if (!this.client) {
346
- return null;
347
- }
348
- const info = await this.client.getBotInfo();
349
- return {
350
- userId: info.userId,
351
- displayName: info.displayName,
352
- pictureUrl: info.pictureUrl,
353
- };
354
- }
355
- /**
356
- * Send a text message.
357
- */
358
- async sendMessage(to, text, options) {
359
- if (!this.client) {
360
- return { success: false, error: "Service not connected" };
361
- }
362
- const chunks = splitMessageForLine(text);
363
- const messages = chunks.map((chunk) => ({
364
- type: "text",
365
- text: chunk,
366
- }));
367
- // Add quick replies to last message if provided
368
- if (options?.quickReplyItems && messages.length > 0) {
369
- const lastIdx = messages.length - 1;
370
- // Cast to unknown first to avoid strict type checking with LINE SDK types
371
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
372
- messages[lastIdx].quickReply = {
373
- items: options.quickReplyItems,
374
- };
375
- }
376
- return this.pushMessages(to, messages);
377
- }
378
- /**
379
- * Send multiple messages.
380
- */
381
- async sendMessages(to, messages) {
382
- return this.pushMessages(to, messages);
383
- }
384
- /**
385
- * Send a flex message.
386
- */
387
- async sendFlexMessage(to, flex) {
388
- if (!this.client) {
389
- return { success: false, error: "Service not connected" };
390
- }
391
- const message = {
392
- type: "flex",
393
- altText: flex.altText.slice(0, 400),
394
- contents: flex.contents,
395
- };
396
- return this.pushMessages(to, [message]);
397
- }
398
- /**
399
- * Send a template message.
400
- */
401
- async sendTemplateMessage(to, template) {
402
- if (!this.client) {
403
- return { success: false, error: "Service not connected" };
404
- }
405
- const message = {
406
- type: "template",
407
- altText: template.altText.slice(0, 400),
408
- template: template.template,
409
- };
410
- return this.pushMessages(to, [message]);
411
- }
412
- /**
413
- * Send a location message.
414
- */
415
- async sendLocationMessage(to, location) {
416
- if (!this.client) {
417
- return { success: false, error: "Service not connected" };
418
- }
419
- const message = {
420
- type: "location",
421
- title: location.title.slice(0, 100),
422
- address: location.address.slice(0, 100),
423
- latitude: location.latitude,
424
- longitude: location.longitude,
425
- };
426
- return this.pushMessages(to, [message]);
427
- }
428
- /**
429
- * Reply to a message using reply token.
430
- */
431
- async replyMessage(replyToken, messages) {
432
- if (!this.client) {
433
- return { success: false, error: "Service not connected" };
434
- }
435
- await this.client.replyMessage({
436
- replyToken,
437
- messages: messages.slice(0, MAX_LINE_BATCH_SIZE),
438
- });
439
- return {
440
- success: true,
441
- messageId: "reply",
442
- chatId: "reply",
443
- };
444
- }
445
- /**
446
- * Get user profile.
447
- */
448
- async getUserProfile(userId) {
449
- if (!this.client) {
450
- return null;
451
- }
452
- const profile = await this.client.getProfile(userId);
453
- return {
454
- userId: profile.userId,
455
- displayName: profile.displayName,
456
- pictureUrl: profile.pictureUrl,
457
- statusMessage: profile.statusMessage,
458
- language: profile.language,
459
- };
460
- }
461
- /**
462
- * Get group info.
463
- */
464
- async getGroupInfo(groupId) {
465
- if (!this.client) {
466
- return null;
467
- }
468
- const chatType = getChatTypeFromId(groupId);
469
- if (chatType === "group") {
470
- const summary = await this.client.getGroupSummary(groupId);
471
- return {
472
- groupId: summary.groupId,
473
- groupName: summary.groupName,
474
- pictureUrl: summary.pictureUrl,
475
- type: "group",
476
- };
477
- }
478
- else if (chatType === "room") {
479
- // Rooms don't have summary, just return ID
480
- return {
481
- groupId,
482
- type: "room",
483
- };
484
- }
485
- return null;
486
- }
487
- /**
488
- * Leave a group or room.
489
- */
490
- async leaveChat(chatId, chatType) {
491
- if (!this.client) {
492
- throw new LineApiError("Service not connected");
493
- }
494
- if (chatType === "group") {
495
- await this.client.leaveGroup(chatId);
496
- }
497
- else {
498
- await this.client.leaveRoom(chatId);
499
- }
500
- }
501
- /**
502
- * Get the middleware config for webhook verification.
503
- */
504
- getMiddlewareConfig() {
505
- if (!this.settings) {
506
- throw new LineConfigurationError("Service not configured");
507
- }
508
- return {
509
- channelSecret: this.settings.channelSecret,
510
- };
511
- }
512
- /**
513
- * Create Express middleware for webhook handling.
514
- */
515
- createMiddleware() {
516
- return middleware(this.getMiddlewareConfig());
517
- }
518
- /**
519
- * Handle webhook events.
520
- */
521
- async handleWebhookEvents(events) {
522
- if (!this.runtime) {
523
- return;
524
- }
525
- for (const event of events) {
526
- await this.handleWebhookEvent(event);
527
- }
528
- }
529
- /**
530
- * Get current settings.
531
- */
532
- getSettings() {
533
- return this.settings;
534
- }
535
- async sendDirectMessage(target, content) {
536
- await this.sendConnectorContent(target, content);
537
- }
538
- async sendRoomMessage(target, content) {
539
- await this.sendConnectorContent(target, content);
540
- }
541
- // Private methods
542
- async handleSendMessage(runtime, target, content) {
543
- const room = target.roomId ? await runtime.getRoom(target.roomId) : null;
544
- const chatId = String(target.channelId ?? room?.channelId ?? "").trim();
545
- if (!chatId) {
546
- throw new Error("LINE target is missing a user, group, or room ID");
547
- }
548
- await this.sendConnectorContent(chatId, content);
549
- }
550
- async sendConnectorContent(to, content) {
551
- const data = lineDataFromContent(content);
552
- const flexMessage = data.flexMessage;
553
- if (flexMessage) {
554
- const result = await this.sendFlexMessage(to, flexMessage);
555
- if (!result.success) {
556
- throw new Error(result.error || "LINE flex message send failed");
557
- }
558
- return;
559
- }
560
- const location = data.location;
561
- if (location) {
562
- const result = await this.sendLocationMessage(to, location);
563
- if (!result.success) {
564
- throw new Error(result.error || "LINE location send failed");
565
- }
566
- return;
567
- }
568
- const templateMessage = data.templateMessage;
569
- if (templateMessage) {
570
- const result = await this.sendTemplateMessage(to, templateMessage);
571
- if (!result.success) {
572
- throw new Error(result.error || "LINE template message send failed");
573
- }
574
- return;
575
- }
576
- const text = typeof content.text === "string" ? content.text.trim() : "";
577
- if (!text) {
578
- return;
579
- }
580
- const result = await this.sendMessage(to, text, {
581
- quickReplyItems: quickReplyItemsFromStrings(data.quickReplies),
582
- });
583
- if (!result.success) {
584
- throw new Error(result.error || "LINE message send failed");
585
- }
586
- }
587
- async listConnectorRooms(runtime) {
588
- if (typeof runtime.getRoomsForParticipant !== "function") {
589
- return [];
590
- }
591
- const roomIds = await runtime.getRoomsForParticipant(runtime.agentId).catch(() => []);
592
- const rooms = [];
593
- for (const roomId of roomIds) {
594
- const room = await runtime.getRoom(roomId).catch(() => null);
595
- if (room?.source === LINE_SERVICE_NAME && room.channelId) {
596
- rooms.push(room);
597
- }
598
- }
599
- return rooms;
600
- }
601
- loadSettings() {
602
- if (!this.runtime) {
603
- throw new LineConfigurationError("Runtime not initialized");
604
- }
605
- const getStringSetting = (key) => {
606
- const value = this.runtime?.getSetting(key);
607
- return typeof value === "string" ? value : "";
608
- };
609
- const channelAccessToken = getStringSetting("LINE_CHANNEL_ACCESS_TOKEN") || process.env.LINE_CHANNEL_ACCESS_TOKEN || "";
610
- const channelSecret = getStringSetting("LINE_CHANNEL_SECRET") || process.env.LINE_CHANNEL_SECRET || "";
611
- const webhookPath = getStringSetting("LINE_WEBHOOK_PATH") || process.env.LINE_WEBHOOK_PATH || "/webhooks/line";
612
- const dmPolicyRaw = getStringSetting("LINE_DM_POLICY") || process.env.LINE_DM_POLICY || "pairing";
613
- const dmPolicy = dmPolicyRaw;
614
- const groupPolicyRaw = getStringSetting("LINE_GROUP_POLICY") || process.env.LINE_GROUP_POLICY || "allowlist";
615
- const groupPolicy = groupPolicyRaw;
616
- const allowFromRaw = getStringSetting("LINE_ALLOW_FROM") || process.env.LINE_ALLOW_FROM || "";
617
- const allowFrom = allowFromRaw
618
- .split(",")
619
- .map((s) => s.trim())
620
- .filter(Boolean);
621
- const enabledRaw = getStringSetting("LINE_ENABLED") || process.env.LINE_ENABLED || "true";
622
- const enabled = enabledRaw !== "false";
623
- return {
624
- channelAccessToken,
625
- channelSecret,
626
- webhookPath,
627
- dmPolicy,
628
- groupPolicy,
629
- allowFrom,
630
- enabled,
631
- };
632
- }
633
- validateSettings() {
634
- if (!this.settings) {
635
- throw new LineConfigurationError("Settings not loaded");
636
- }
637
- if (!this.settings.channelAccessToken) {
638
- throw new LineConfigurationError("LINE_CHANNEL_ACCESS_TOKEN is required", "LINE_CHANNEL_ACCESS_TOKEN");
639
- }
640
- if (!this.settings.channelSecret) {
641
- throw new LineConfigurationError("LINE_CHANNEL_SECRET is required", "LINE_CHANNEL_SECRET");
642
- }
643
- }
644
- async pushMessages(to, messages) {
645
- if (!this.client) {
646
- return { success: false, error: "Service not connected" };
647
- }
648
- // Send in batches of 5
649
- for (let i = 0; i < messages.length; i += MAX_LINE_BATCH_SIZE) {
650
- const batch = messages.slice(i, i + MAX_LINE_BATCH_SIZE);
651
- await this.client.pushMessage({
652
- to,
653
- messages: batch,
654
- });
655
- }
656
- // Emit sent event
657
- if (this.runtime) {
658
- this.runtime.emitEvent(LineEventTypes.MESSAGE_SENT, {
659
- runtime: this.runtime,
660
- source: "line",
661
- to,
662
- messageCount: messages.length,
663
- });
664
- }
665
- return {
666
- success: true,
667
- messageId: Date.now().toString(),
668
- chatId: to,
669
- };
670
- }
671
- async handleWebhookEvent(event) {
672
- if (!this.runtime) {
673
- return;
674
- }
675
- switch (event.type) {
676
- case "message":
677
- await this.handleMessageEvent(event);
678
- break;
679
- case "follow":
680
- this.runtime.emitEvent([LineEventTypes.FOLLOW], {
681
- runtime: this.runtime,
682
- source: "line",
683
- userId: event.source?.userId,
684
- timestamp: event.timestamp,
685
- });
686
- break;
687
- case "unfollow":
688
- this.runtime.emitEvent([LineEventTypes.UNFOLLOW], {
689
- runtime: this.runtime,
690
- source: "line",
691
- userId: event.source?.userId,
692
- timestamp: event.timestamp,
693
- });
694
- break;
695
- case "join":
696
- this.runtime.emitEvent([LineEventTypes.JOIN_GROUP], {
697
- runtime: this.runtime,
698
- source: "line",
699
- groupId: event.source?.type === "group"
700
- ? event.source.groupId
701
- : event.source?.type === "room"
702
- ? event.source.roomId
703
- : undefined,
704
- type: event.source?.type,
705
- timestamp: event.timestamp,
706
- });
707
- break;
708
- case "leave":
709
- this.runtime.emitEvent([LineEventTypes.LEAVE_GROUP], {
710
- runtime: this.runtime,
711
- source: "line",
712
- groupId: event.source?.type === "group"
713
- ? event.source.groupId
714
- : event.source?.type === "room"
715
- ? event.source.roomId
716
- : undefined,
717
- type: event.source?.type,
718
- timestamp: event.timestamp,
719
- });
720
- break;
721
- case "postback":
722
- this.runtime.emitEvent([LineEventTypes.POSTBACK], {
723
- runtime: this.runtime,
724
- source: "line",
725
- userId: event.source?.userId,
726
- data: event.postback.data,
727
- params: event.postback.params,
728
- timestamp: event.timestamp,
729
- });
730
- break;
731
- }
732
- }
733
- async handleMessageEvent(event) {
734
- if (!this.runtime) {
735
- return;
736
- }
737
- const message = {
738
- id: event.message.id,
739
- type: event.message.type,
740
- userId: event.source?.userId || "",
741
- timestamp: event.timestamp,
742
- replyToken: event.replyToken,
743
- };
744
- // Add text for text messages
745
- if (event.message.type === "text") {
746
- message.text = event.message.text;
747
- message.mention = event.message.mention;
748
- }
749
- // Add group/room ID if applicable
750
- if (event.source?.type === "group") {
751
- message.groupId = event.source.groupId;
752
- }
753
- else if (event.source?.type === "room") {
754
- message.roomId = event.source.roomId;
755
- }
756
- // Emit message received event
757
- this.runtime.emitEvent([LineEventTypes.MESSAGE_RECEIVED], {
758
- runtime: this.runtime,
759
- source: "line",
760
- message,
761
- lineSource: event.source,
762
- replyToken: event.replyToken,
763
- });
764
- }
765
- }
766
- //# sourceMappingURL=service.js.map