kakaoforge 1.0.0
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/LICENSE +33 -0
- package/README.md +772 -0
- package/dist/auth/crypto.d.ts +4 -0
- package/dist/auth/crypto.js +69 -0
- package/dist/auth/login.d.ts +53 -0
- package/dist/auth/login.js +559 -0
- package/dist/crypto/v2sl.d.ts +14 -0
- package/dist/crypto/v2sl.js +118 -0
- package/dist/db/kakao-db.d.ts +51 -0
- package/dist/db/kakao-db.js +194 -0
- package/dist/db/kakao-schema-secondary.d.ts +2 -0
- package/dist/db/kakao-schema-secondary.js +57 -0
- package/dist/db/kakao-schema.d.ts +2 -0
- package/dist/db/kakao-schema.js +236 -0
- package/dist/db/kakao-secondary-db.d.ts +9 -0
- package/dist/db/kakao-secondary-db.js +69 -0
- package/dist/index.d.ts +634 -0
- package/dist/index.js +5181 -0
- package/dist/net/booking-client.d.ts +38 -0
- package/dist/net/booking-client.js +202 -0
- package/dist/net/brewery-client.d.ts +148 -0
- package/dist/net/brewery-client.js +419 -0
- package/dist/net/bubble-client.d.ts +45 -0
- package/dist/net/bubble-client.js +64 -0
- package/dist/net/calendar-client.d.ts +41 -0
- package/dist/net/calendar-client.js +80 -0
- package/dist/net/carriage-client.d.ts +56 -0
- package/dist/net/carriage-client.js +426 -0
- package/dist/net/loco-stream.d.ts +9 -0
- package/dist/net/loco-stream.js +39 -0
- package/dist/net/ticket-client.d.ts +11 -0
- package/dist/net/ticket-client.js +30 -0
- package/dist/net/upload-client.d.ts +18 -0
- package/dist/net/upload-client.js +209 -0
- package/dist/protocol/loco-packet.d.ts +19 -0
- package/dist/protocol/loco-packet.js +54 -0
- package/dist/types/attachments.d.ts +17 -0
- package/dist/types/attachments.js +14 -0
- package/dist/types/member-type.d.ts +8 -0
- package/dist/types/member-type.js +10 -0
- package/dist/types/message.d.ts +14 -0
- package/dist/types/message.js +16 -0
- package/dist/types/reaction.d.ts +10 -0
- package/dist/types/reaction.js +12 -0
- package/dist/util/client-msg-id.d.ts +1 -0
- package/dist/util/client-msg-id.js +48 -0
- package/dist/util/media.d.ts +6 -0
- package/dist/util/media.js +173 -0
- package/package.json +40 -0
package/README.md
ADDED
|
@@ -0,0 +1,772 @@
|
|
|
1
|
+
# KakaoForge
|
|
2
|
+
|
|
3
|
+
카카오톡 LOCO 프로토콜 기반 Node.js 봇 라이브러리
|
|
4
|
+
|
|
5
|
+
## 목차
|
|
6
|
+
|
|
7
|
+
- [설치](#설치)
|
|
8
|
+
- [빠른 시작](#빠른-시작)
|
|
9
|
+
- [주요 기능](#주요-기능)
|
|
10
|
+
- [API 레퍼런스](#api-레퍼런스)
|
|
11
|
+
- [설정 옵션](#설정-옵션)
|
|
12
|
+
- [타입 정의](#타입-정의)
|
|
13
|
+
- [예제](#예제)
|
|
14
|
+
- [주의사항](#주의사항)
|
|
15
|
+
- [라이선스](#라이선스)
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 설치
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install kakaoforge
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 빠른 시작
|
|
28
|
+
|
|
29
|
+
### 1. QR 코드 로그인
|
|
30
|
+
|
|
31
|
+
처음 사용 시 QR 코드를 통해 인증해야 합니다.
|
|
32
|
+
기본적으로 ./auth.json 위치에 로그인 정보가 저장됩니다.
|
|
33
|
+
|
|
34
|
+
```javascript
|
|
35
|
+
const { createAuthByQR } = require('kakaoforge');
|
|
36
|
+
|
|
37
|
+
// QR 코드가 터미널에 표시됩니다
|
|
38
|
+
// 카카오톡 앱에서 QR 코드를 스캔하세요
|
|
39
|
+
await createAuthByQR();
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
저장 위치를 변경하려면 `authPath` 옵션을 사용하세요:
|
|
43
|
+
|
|
44
|
+
```javascript
|
|
45
|
+
await createAuthByQR({
|
|
46
|
+
authPath: './config/my-auth.json' // 원하는 경로 지정
|
|
47
|
+
});
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
### 2. 봇 클라이언트 생성
|
|
52
|
+
|
|
53
|
+
```javascript
|
|
54
|
+
const { createClient } = require('kakaoforge');
|
|
55
|
+
|
|
56
|
+
const client = createClient();
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
옵션을 지정하여 클라이언트를 생성할 수 있습니다:
|
|
60
|
+
|
|
61
|
+
```javascript
|
|
62
|
+
const client = createClient({
|
|
63
|
+
authPath: './auth.json', // 인증 파일 경로 (기본: './auth.json')
|
|
64
|
+
debug: true, // 디버그 로깅 활성화 (기본: false)
|
|
65
|
+
autoConnect: true, // 자동 연결 (기본: true)
|
|
66
|
+
autoReconnect: true, // 연결 끊김 시 자동 재연결 (기본: true)
|
|
67
|
+
pingIntervalMs: 60000, // Ping 간격 (기본: 60초)
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### 3. 메시지 수신 및 응답
|
|
72
|
+
|
|
73
|
+
```javascript
|
|
74
|
+
client.onReady((chat) => {
|
|
75
|
+
console.log('KakaoForge 준비 완료!');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
client.onMessage(async (chat, msg) => {
|
|
79
|
+
// 자신의 메시지는 무시
|
|
80
|
+
if (msg.sender.id === client.userId) return;
|
|
81
|
+
|
|
82
|
+
console.log(`[${msg.sender.name}] ${msg.message.text}`);
|
|
83
|
+
|
|
84
|
+
// "안녕"이라고 보내면 "안녕하세요!"로 응답
|
|
85
|
+
if (msg.message.text === '안녕') {
|
|
86
|
+
await chat.sendText(msg.room.id, '안녕하세요!');
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## 주요 기능
|
|
94
|
+
|
|
95
|
+
### 메시지 송수신
|
|
96
|
+
|
|
97
|
+
```javascript
|
|
98
|
+
// 텍스트 메시지
|
|
99
|
+
await chat.sendText(roomId, '안녕하세요');
|
|
100
|
+
|
|
101
|
+
// 답장
|
|
102
|
+
await chat.sendReply(roomId, '답장입니다', msg);
|
|
103
|
+
|
|
104
|
+
// 스레드 댓글
|
|
105
|
+
await chat.sendThreadReply(roomId, msg.message.id, '댓글');
|
|
106
|
+
|
|
107
|
+
// 스레드 댓글 + 채팅방에도 전송
|
|
108
|
+
await chat.sendThreadReply(roomId, msg.message.id, '댓글', { sendToChatRoom: true });
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### 미디어 전송
|
|
112
|
+
|
|
113
|
+
```javascript
|
|
114
|
+
// 사진
|
|
115
|
+
await chat.sendPhoto(roomId, '/path/to/image.jpg', { text: '사진 설명' });
|
|
116
|
+
|
|
117
|
+
// 동영상
|
|
118
|
+
await chat.sendVideo(roomId, '/path/to/video.mp4', { text: '동영상 설명' });
|
|
119
|
+
|
|
120
|
+
// 음성
|
|
121
|
+
await chat.sendAudio(roomId, '/path/to/audio.mp3');
|
|
122
|
+
|
|
123
|
+
// 파일
|
|
124
|
+
await chat.sendFile(roomId, '/path/to/file.txt');
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### 스레드에 미디어 전송
|
|
128
|
+
|
|
129
|
+
```javascript
|
|
130
|
+
await chat.sendPhotoAtThread(roomId, msg.message.id, '/path/to/image.jpg');
|
|
131
|
+
await chat.sendVideoAtThread(roomId, msg.message.id, '/path/to/video.mp4');
|
|
132
|
+
await chat.sendAudioAtThread(roomId, msg.message.id, '/path/to/audio.mp3');
|
|
133
|
+
await chat.sendFileAtThread(roomId, msg.message.id, '/path/to/file.txt');
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### 멘션 및 스포일러
|
|
137
|
+
|
|
138
|
+
```javascript
|
|
139
|
+
const { Mention, Spoiler } = require('kakaoforge');
|
|
140
|
+
|
|
141
|
+
// 사용자 멘션
|
|
142
|
+
await chat.sendText(roomId, `${Mention(userId)} 안녕하세요!`);
|
|
143
|
+
|
|
144
|
+
// 스포일러 텍스트
|
|
145
|
+
await chat.sendText(roomId, `스포일러: ${Spoiler('비밀 내용')}`);
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### 이모지 반응
|
|
149
|
+
|
|
150
|
+
```javascript
|
|
151
|
+
const { Reactions } = require('kakaoforge');
|
|
152
|
+
|
|
153
|
+
await chat.sendReaction(roomId, msg, Reactions.HEART); // 하트
|
|
154
|
+
await chat.sendReaction(roomId, msg, Reactions.LIKE); // 좋아요
|
|
155
|
+
await chat.sendReaction(roomId, msg, Reactions.CHECK); // 체크
|
|
156
|
+
await chat.sendReaction(roomId, msg, Reactions.LAUGH); // 웃음
|
|
157
|
+
await chat.sendReaction(roomId, msg, Reactions.SURPRISE); // 놀람
|
|
158
|
+
await chat.sendReaction(roomId, msg, Reactions.SAD); // 슬픔
|
|
159
|
+
await chat.sendReaction(roomId, msg, Reactions.CANCEL); // 반응 취소
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### 특수 메시지
|
|
163
|
+
|
|
164
|
+
```javascript
|
|
165
|
+
// 연락처
|
|
166
|
+
await chat.sendContact(roomId, {
|
|
167
|
+
name: '홍길동',
|
|
168
|
+
phone: '01012345678',
|
|
169
|
+
email: 'hong@example.com'
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// 카카오 프로필
|
|
173
|
+
await chat.sendKakaoProfile(roomId, { userId: 123456789 });
|
|
174
|
+
|
|
175
|
+
// 위치
|
|
176
|
+
await chat.sendLocation(roomId, {
|
|
177
|
+
lat: 37.4979,
|
|
178
|
+
lng: 127.0276,
|
|
179
|
+
address: '서울시 강남구'
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// 일정
|
|
183
|
+
await chat.sendSchedule(roomId, {
|
|
184
|
+
eventAt: new Date('2025-02-15'),
|
|
185
|
+
title: '회의',
|
|
186
|
+
location: '회의실'
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
// 링크
|
|
190
|
+
await chat.sendLink(roomId, {
|
|
191
|
+
url: 'https://example.com',
|
|
192
|
+
text: '링크 설명'
|
|
193
|
+
});
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### 메시지 수정 및 삭제
|
|
197
|
+
|
|
198
|
+
```javascript
|
|
199
|
+
// 메시지 수정
|
|
200
|
+
const sentMsg = await chat.sendText(roomId, '원본 메시지');
|
|
201
|
+
await chat.editMessage(roomId, sentMsg, '수정된 메시지');
|
|
202
|
+
|
|
203
|
+
// 메시지 삭제
|
|
204
|
+
await chat.deleteMessage(roomId, sentMsg);
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### 오픈채팅 관리
|
|
208
|
+
|
|
209
|
+
```javascript
|
|
210
|
+
const { MemberType } = require('kakaoforge');
|
|
211
|
+
|
|
212
|
+
// 권한 확인
|
|
213
|
+
if (client.type === MemberType.OpenChat.Owner ||
|
|
214
|
+
client.type === MemberType.OpenChat.Manager) {
|
|
215
|
+
|
|
216
|
+
// 강제퇴장
|
|
217
|
+
await chat.openChatKick(roomId, memberId);
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### 메시지 조회 (테스트 되지 않음)
|
|
222
|
+
|
|
223
|
+
```javascript
|
|
224
|
+
// 특정 메시지 조회
|
|
225
|
+
const message = await chat.fetchMessage(roomId, logId);
|
|
226
|
+
|
|
227
|
+
// 특정 사용자의 메시지 조회
|
|
228
|
+
const messages = await chat.fetchMessagesByUser(roomId, userId, {
|
|
229
|
+
since: 0,
|
|
230
|
+
count: 50,
|
|
231
|
+
maxPages: 5,
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
// 사용자명 조회
|
|
235
|
+
const username = await chat.getUsernameById(roomId, userId);
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## API 레퍼런스
|
|
241
|
+
|
|
242
|
+
### 인증
|
|
243
|
+
|
|
244
|
+
#### `createAuthByQR(options?)`
|
|
245
|
+
|
|
246
|
+
QR 코드를 통한 인증을 수행합니다.
|
|
247
|
+
|
|
248
|
+
```javascript
|
|
249
|
+
await createAuthByQR({
|
|
250
|
+
onQrUrl: (url) => console.log('QR URL:', url),
|
|
251
|
+
onPasscode: (code) => console.log('Passcode:', code),
|
|
252
|
+
save: true, // auth.json에 저장
|
|
253
|
+
authPath: './auth.json'
|
|
254
|
+
});
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### 클라이언트
|
|
258
|
+
|
|
259
|
+
#### `createClient(config)`
|
|
260
|
+
|
|
261
|
+
KakaoForge 클라이언트를 생성합니다.
|
|
262
|
+
|
|
263
|
+
```javascript
|
|
264
|
+
const client = createClient({
|
|
265
|
+
authPath: './auth.json',
|
|
266
|
+
debug: true,
|
|
267
|
+
autoConnect: true,
|
|
268
|
+
autoReconnect: true,
|
|
269
|
+
});
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### 이벤트 핸들러
|
|
273
|
+
|
|
274
|
+
#### `client.onReady(callback)`
|
|
275
|
+
|
|
276
|
+
연결이 완료되면 호출됩니다.
|
|
277
|
+
|
|
278
|
+
```javascript
|
|
279
|
+
client.onReady((chat) => {
|
|
280
|
+
console.log('준비 완료!');
|
|
281
|
+
console.log('User ID:', client.userId);
|
|
282
|
+
});
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
#### `client.onMessage(callback)`
|
|
286
|
+
|
|
287
|
+
메시지를 수신하면 호출됩니다.
|
|
288
|
+
|
|
289
|
+
```javascript
|
|
290
|
+
client.onMessage(async (chat, msg) => {
|
|
291
|
+
console.log('메시지:', msg.message.text);
|
|
292
|
+
console.log('발신자:', msg.sender.name);
|
|
293
|
+
console.log('채팅방:', msg.room.name);
|
|
294
|
+
});
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
#### `client.onJoin(callback)`
|
|
298
|
+
|
|
299
|
+
사용자가 입장하면 호출됩니다.
|
|
300
|
+
|
|
301
|
+
```javascript
|
|
302
|
+
client.onJoin((chat, evt) => {
|
|
303
|
+
console.log('입장:', evt.member.names);
|
|
304
|
+
});
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
#### `client.onLeave(callback)`
|
|
308
|
+
|
|
309
|
+
사용자가 퇴장하면 호출됩니다.
|
|
310
|
+
|
|
311
|
+
```javascript
|
|
312
|
+
client.onLeave((chat, evt) => {
|
|
313
|
+
console.log('퇴장:', evt.member.names);
|
|
314
|
+
});
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
#### `client.onInvite(callback)`
|
|
318
|
+
|
|
319
|
+
사용자가 초대되면 호출됩니다.
|
|
320
|
+
|
|
321
|
+
```javascript
|
|
322
|
+
client.onInvite((chat, evt) => {
|
|
323
|
+
console.log('초대:', evt.member.names);
|
|
324
|
+
console.log('초대한 사람:', evt.actor.name);
|
|
325
|
+
});
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
#### `client.onKick(callback)`
|
|
329
|
+
|
|
330
|
+
사용자가 강제퇴장되면 호출됩니다.
|
|
331
|
+
|
|
332
|
+
```javascript
|
|
333
|
+
client.onKick((chat, evt) => {
|
|
334
|
+
console.log('강제퇴장:', evt.member.names);
|
|
335
|
+
});
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
#### `client.onDelete(callback)`
|
|
339
|
+
|
|
340
|
+
메시지가 삭제되면 호출됩니다.
|
|
341
|
+
|
|
342
|
+
```javascript
|
|
343
|
+
client.onDelete((chat, evt) => {
|
|
344
|
+
console.log('삭제된 메시지');
|
|
345
|
+
});
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
#### `client.onHide(callback)`
|
|
349
|
+
|
|
350
|
+
메시지가 숨겨지면 호출됩니다 (오픈채팅).
|
|
351
|
+
|
|
352
|
+
```javascript
|
|
353
|
+
client.onHide((chat, evt) => {
|
|
354
|
+
console.log('숨겨진 메시지');
|
|
355
|
+
});
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
#### `client.onPush(method, callback)`
|
|
359
|
+
|
|
360
|
+
특정 LOCO push를 직접 수신합니다.
|
|
361
|
+
|
|
362
|
+
```javascript
|
|
363
|
+
client.onPush('SYNCREWR', (payload) => {
|
|
364
|
+
console.log('Raw push:', payload);
|
|
365
|
+
});
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
### 메시지 전송
|
|
369
|
+
|
|
370
|
+
#### `chat.sendText(roomId, text)`
|
|
371
|
+
|
|
372
|
+
텍스트 메시지를 전송합니다.
|
|
373
|
+
|
|
374
|
+
```javascript
|
|
375
|
+
const sentMsg = await chat.sendText(roomId, '안녕하세요');
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
#### `chat.sendReply(roomId, text, msg)`
|
|
379
|
+
|
|
380
|
+
메시지에 답장합니다.
|
|
381
|
+
|
|
382
|
+
```javascript
|
|
383
|
+
await chat.sendReply(roomId, '답장입니다', msg);
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
#### `chat.sendThreadReply(roomId, msgId, text, options?)`
|
|
387
|
+
|
|
388
|
+
스레드에 댓글을 답니다.
|
|
389
|
+
|
|
390
|
+
```javascript
|
|
391
|
+
await chat.sendThreadReply(roomId, msgId, '댓글');
|
|
392
|
+
|
|
393
|
+
// 채팅방에도 전송
|
|
394
|
+
await chat.sendThreadReply(roomId, msgId, '댓글', { sendToChatRoom: true });
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
#### `chat.sendPhoto(roomId, path, options?)`
|
|
398
|
+
|
|
399
|
+
사진을 전송합니다.
|
|
400
|
+
|
|
401
|
+
```javascript
|
|
402
|
+
await chat.sendPhoto(roomId, '/path/to/image.jpg', { text: '사진' });
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
#### `chat.sendVideo(roomId, path, options?)`
|
|
406
|
+
|
|
407
|
+
동영상을 전송합니다.
|
|
408
|
+
|
|
409
|
+
```javascript
|
|
410
|
+
await chat.sendVideo(roomId, '/path/to/video.mp4', { text: '동영상' });
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
#### `chat.sendAudio(roomId, path)`
|
|
414
|
+
|
|
415
|
+
음성 파일을 전송합니다.
|
|
416
|
+
|
|
417
|
+
```javascript
|
|
418
|
+
await chat.sendAudio(roomId, '/path/to/audio.mp3');
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
#### `chat.sendFile(roomId, path)`
|
|
422
|
+
|
|
423
|
+
파일을 전송합니다.
|
|
424
|
+
|
|
425
|
+
```javascript
|
|
426
|
+
await chat.sendFile(roomId, '/path/to/file.txt');
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
#### `chat.sendReaction(roomId, msg, reactionId)`
|
|
430
|
+
|
|
431
|
+
이모지 반응을 보냅니다.
|
|
432
|
+
|
|
433
|
+
```javascript
|
|
434
|
+
await chat.sendReaction(roomId, msg, Reactions.HEART);
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
#### `chat.sendContact(roomId, contact)`
|
|
438
|
+
|
|
439
|
+
연락처를 전송합니다.
|
|
440
|
+
|
|
441
|
+
```javascript
|
|
442
|
+
await chat.sendContact(roomId, {
|
|
443
|
+
name: '홍길동',
|
|
444
|
+
phone: '01012345678',
|
|
445
|
+
email: 'hong@example.com'
|
|
446
|
+
});
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
#### `chat.sendKakaoProfile(roomId, options)`
|
|
450
|
+
|
|
451
|
+
카카오 프로필을 전송합니다.
|
|
452
|
+
|
|
453
|
+
```javascript
|
|
454
|
+
await chat.sendKakaoProfile(roomId, { userId: 123456789 });
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
#### `chat.sendLocation(roomId, location)`
|
|
458
|
+
|
|
459
|
+
위치를 전송합니다.
|
|
460
|
+
|
|
461
|
+
```javascript
|
|
462
|
+
await chat.sendLocation(roomId, {
|
|
463
|
+
lat: 37.4979,
|
|
464
|
+
lng: 127.0276,
|
|
465
|
+
address: '서울시 강남구',
|
|
466
|
+
title: '장소 이름'
|
|
467
|
+
});
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
#### `chat.sendSchedule(roomId, schedule)`
|
|
471
|
+
|
|
472
|
+
일정을 전송합니다.
|
|
473
|
+
|
|
474
|
+
```javascript
|
|
475
|
+
await chat.sendSchedule(roomId, {
|
|
476
|
+
eventAt: new Date('2025-02-15T10:00:00'),
|
|
477
|
+
title: '회의',
|
|
478
|
+
location: '회의실'
|
|
479
|
+
});
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
#### `chat.sendLink(roomId, link)`
|
|
483
|
+
|
|
484
|
+
링크를 전송합니다.
|
|
485
|
+
|
|
486
|
+
```javascript
|
|
487
|
+
await chat.sendLink(roomId, {
|
|
488
|
+
url: 'https://example.com',
|
|
489
|
+
text: '링크 설명'
|
|
490
|
+
});
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
### 메시지 관리
|
|
494
|
+
|
|
495
|
+
#### `chat.editMessage(roomId, msg, text)`
|
|
496
|
+
|
|
497
|
+
메시지를 수정합니다.
|
|
498
|
+
|
|
499
|
+
```javascript
|
|
500
|
+
await chat.editMessage(roomId, prevMsg, '수정된 내용');
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
#### `chat.deleteMessage(roomId, msg)`
|
|
504
|
+
|
|
505
|
+
메시지를 삭제합니다.
|
|
506
|
+
|
|
507
|
+
```javascript
|
|
508
|
+
await chat.deleteMessage(roomId, msg);
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
#### `chat.fetchMessage(roomId, logId)` *(테스트되지 않음)*
|
|
512
|
+
|
|
513
|
+
특정 메시지를 조회합니다.
|
|
514
|
+
|
|
515
|
+
```javascript
|
|
516
|
+
const message = await chat.fetchMessage(roomId, logId);
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
#### `chat.fetchMessagesByUser(roomId, userId, options)` *(테스트되지 않음)*
|
|
520
|
+
|
|
521
|
+
특정 사용자의 메시지를 조회합니다.
|
|
522
|
+
|
|
523
|
+
```javascript
|
|
524
|
+
const messages = await chat.fetchMessagesByUser(roomId, userId, {
|
|
525
|
+
since: 0, // 시작 시점
|
|
526
|
+
count: 50, // 조회 개수
|
|
527
|
+
maxPages: 5, // 최대 페이지 수
|
|
528
|
+
});
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
### 오픈채팅 관리
|
|
532
|
+
|
|
533
|
+
#### `chat.openChatKick(roomId, memberId)`
|
|
534
|
+
|
|
535
|
+
오픈채팅에서 멤버를 강제퇴장시킵니다.
|
|
536
|
+
|
|
537
|
+
```javascript
|
|
538
|
+
await chat.openChatKick(roomId, memberId);
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
### 사용자 정보
|
|
542
|
+
|
|
543
|
+
#### `chat.getUsernameById(roomId, userId)`
|
|
544
|
+
|
|
545
|
+
사용자 ID로 닉네임을 조회합니다.
|
|
546
|
+
|
|
547
|
+
```javascript
|
|
548
|
+
const username = await chat.getUsernameById(roomId, userId);
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
---
|
|
552
|
+
|
|
553
|
+
## 설정 옵션
|
|
554
|
+
|
|
555
|
+
`createClient(config)`에서 사용할 수 있는 설정 옵션입니다.
|
|
556
|
+
|
|
557
|
+
```typescript
|
|
558
|
+
interface KakaoForgeConfig {
|
|
559
|
+
// 인증
|
|
560
|
+
authPath?: string; // auth.json 경로 (기본: './auth.json')
|
|
561
|
+
userId?: number; // 사용자 ID (auth.json에서 로드)
|
|
562
|
+
oauthToken?: string; // OAuth 토큰 (auth.json에서 로드)
|
|
563
|
+
deviceUuid?: string; // 디바이스 UUID (auth.json에서 로드)
|
|
564
|
+
refreshToken?: string; // 리프레시 토큰 (auth.json에서 로드)
|
|
565
|
+
|
|
566
|
+
// 연결
|
|
567
|
+
autoConnect?: boolean; // 자동 연결 (기본: true)
|
|
568
|
+
autoReconnect?: boolean; // 자동 재연결 (기본: true)
|
|
569
|
+
reconnectMinDelayMs?: number; // 재연결 최소 대기 시간
|
|
570
|
+
reconnectMaxDelayMs?: number; // 재연결 최대 대기 시간
|
|
571
|
+
|
|
572
|
+
// 성능
|
|
573
|
+
pingIntervalMs?: number; // Ping 간격 (기본: 60000)
|
|
574
|
+
socketKeepAliveMs?: number; // 소켓 Keep-alive 간격
|
|
575
|
+
memberCacheTtlMs?: number; // 멤버 캐시 유효 시간
|
|
576
|
+
memberRefreshIntervalMs?: number; // 멤버 새로고침 간격
|
|
577
|
+
memberLookupTimeoutMs?: number; // 멤버 조회 타임아웃
|
|
578
|
+
|
|
579
|
+
// 비디오 설정
|
|
580
|
+
videoQuality?: 'low' | 'high'; // 비디오 품질
|
|
581
|
+
transcodeVideos?: boolean; // 비디오 트랜스코딩 여부
|
|
582
|
+
ffmpegPath?: string; // FFmpeg 경로
|
|
583
|
+
ffprobePath?: string; // FFprobe 경로
|
|
584
|
+
|
|
585
|
+
// 디바이스 정보
|
|
586
|
+
deviceId?: string; // 디바이스 ID
|
|
587
|
+
os?: string; // OS 버전
|
|
588
|
+
appVer?: string; // 앱 버전
|
|
589
|
+
lang?: string; // 언어 (기본: 'ko')
|
|
590
|
+
|
|
591
|
+
// 기타
|
|
592
|
+
debug?: boolean; // 디버그 로깅 (기본: false)
|
|
593
|
+
timeZone?: string; // 시간대
|
|
594
|
+
}
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
---
|
|
598
|
+
|
|
599
|
+
## 타입 정의
|
|
600
|
+
|
|
601
|
+
### MessageEvent
|
|
602
|
+
|
|
603
|
+
메시지 이벤트의 구조입니다.
|
|
604
|
+
|
|
605
|
+
```typescript
|
|
606
|
+
interface MessageEvent {
|
|
607
|
+
message: {
|
|
608
|
+
id: number | string; // 메시지 ID
|
|
609
|
+
text: string; // 메시지 텍스트
|
|
610
|
+
type: number; // 메시지 타입 (MessageType)
|
|
611
|
+
logId: number | string; // 로그 ID
|
|
612
|
+
};
|
|
613
|
+
sender: {
|
|
614
|
+
id: number | string; // 발신자 ID
|
|
615
|
+
name: string; // 발신자 이름
|
|
616
|
+
type: number; // 멤버 타입 (오픈채팅)
|
|
617
|
+
};
|
|
618
|
+
room: {
|
|
619
|
+
id: number | string; // 채팅방 ID
|
|
620
|
+
name: string; // 채팅방 이름
|
|
621
|
+
isGroupChat: boolean; // 단체 채팅 여부
|
|
622
|
+
isOpenChat: boolean; // 오픈채팅 여부
|
|
623
|
+
openLinkId?: number | string; // 오픈채팅 링크 ID
|
|
624
|
+
};
|
|
625
|
+
attachmentsRaw: any[]; // 첨부물 원본 데이터
|
|
626
|
+
raw: any; // 원본 LOCO 데이터
|
|
627
|
+
}
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
### MessageType
|
|
631
|
+
|
|
632
|
+
메시지 타입입니다.
|
|
633
|
+
|
|
634
|
+
```javascript
|
|
635
|
+
const { MessageType } = require('kakaoforge');
|
|
636
|
+
|
|
637
|
+
MessageType.Text; // 1 - 텍스트
|
|
638
|
+
MessageType.Photo; // 2 - 사진
|
|
639
|
+
MessageType.Video; // 3 - 동영상
|
|
640
|
+
MessageType.Contact; // 4 - 연락처
|
|
641
|
+
MessageType.Audio; // 5 - 음성
|
|
642
|
+
MessageType.Link; // 9 - 링크
|
|
643
|
+
MessageType.Schedule; // 13 - 일정
|
|
644
|
+
MessageType.Location; // 16 - 위치
|
|
645
|
+
MessageType.Profile; // 17 - 프로필
|
|
646
|
+
MessageType.File; // 18 - 파일
|
|
647
|
+
MessageType.Reply; // 26 - 답장
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
### MemberType
|
|
651
|
+
|
|
652
|
+
오픈채팅 멤버 타입입니다.
|
|
653
|
+
|
|
654
|
+
```javascript
|
|
655
|
+
const { MemberType } = require('kakaoforge');
|
|
656
|
+
|
|
657
|
+
MemberType.OpenChat.Owner; // 1 - 방장
|
|
658
|
+
MemberType.OpenChat.Member; // 2 - 일반 멤버
|
|
659
|
+
MemberType.OpenChat.Manager; // 4 - 매니저
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
### Reactions
|
|
663
|
+
|
|
664
|
+
이모지 반응 타입입니다.
|
|
665
|
+
|
|
666
|
+
```javascript
|
|
667
|
+
const { Reactions } = require('kakaoforge');
|
|
668
|
+
|
|
669
|
+
Reactions.CANCEL; // 0 - 반응 취소
|
|
670
|
+
Reactions.HEART; // 1 - 하트
|
|
671
|
+
Reactions.LIKE; // 2 - 좋아요
|
|
672
|
+
Reactions.CHECK; // 3 - 체크
|
|
673
|
+
Reactions.LAUGH; // 4 - 웃음
|
|
674
|
+
Reactions.SURPRISE; // 5 - 놀람
|
|
675
|
+
Reactions.SAD; // 6 - 슬픔
|
|
676
|
+
```
|
|
677
|
+
|
|
678
|
+
---
|
|
679
|
+
|
|
680
|
+
## 예제
|
|
681
|
+
|
|
682
|
+
### 에코 봇
|
|
683
|
+
|
|
684
|
+
```javascript
|
|
685
|
+
const { createClient } = require('kakaoforge');
|
|
686
|
+
|
|
687
|
+
const client = createClient();
|
|
688
|
+
|
|
689
|
+
client.onReady(() => {
|
|
690
|
+
console.log('에코 봇 준비 완료!');
|
|
691
|
+
});
|
|
692
|
+
|
|
693
|
+
client.onMessage(async (chat, msg) => {
|
|
694
|
+
if (msg.sender.id === client.userId) return;
|
|
695
|
+
|
|
696
|
+
// 받은 메시지를 그대로 전송
|
|
697
|
+
await chat.sendText(msg.room.id, msg.message.text);
|
|
698
|
+
});
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
### 명령어 봇
|
|
702
|
+
|
|
703
|
+
```javascript
|
|
704
|
+
const { createClient, Reactions, MemberType, Mention } = require('kakaoforge');
|
|
705
|
+
|
|
706
|
+
const client = createClient({ authPath: './auth.json' });
|
|
707
|
+
|
|
708
|
+
client.onMessage(async (chat, msg) => {
|
|
709
|
+
if (msg.sender.id === client.userId) return;
|
|
710
|
+
|
|
711
|
+
const text = msg.message.text;
|
|
712
|
+
if (!text) return;
|
|
713
|
+
|
|
714
|
+
// !ping 명령어
|
|
715
|
+
if (text === '!ping') {
|
|
716
|
+
await chat.sendText(msg.room.id, 'pong!');
|
|
717
|
+
await chat.sendReaction(msg.room.id, msg, Reactions.CHECK);
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
// !info 명령어
|
|
721
|
+
if (text === '!info') {
|
|
722
|
+
await chat.sendText(msg.room.id, `채팅방: ${msg.room.name}\n그룹채팅: ${msg.room.isGroupChat}\n오픈채팅: ${msg.room.isOpenChat}`)
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
// !hello
|
|
726
|
+
if (text === '!hello') {
|
|
727
|
+
await chat.sendText(msg.room.id, `${Mention(msg.sender.id)} 안녕하세요!`);
|
|
728
|
+
}
|
|
729
|
+
});
|
|
730
|
+
```
|
|
731
|
+
|
|
732
|
+
---
|
|
733
|
+
|
|
734
|
+
## 주의사항
|
|
735
|
+
|
|
736
|
+
### 오픈채팅
|
|
737
|
+
|
|
738
|
+
- 오픈채팅 관리 기능(강제퇴장)을 사용하려면 봇이 **방장** 또는 **매니저** 권한이 있어야 합니다.
|
|
739
|
+
- `client.type`으로 봇의 권한을 확인할 수 있습니다.
|
|
740
|
+
|
|
741
|
+
### 인증 정보
|
|
742
|
+
|
|
743
|
+
- 로그인 후 인증 정보는 `auth.json` 파일에 저장됩니다.
|
|
744
|
+
- 이 파일에는 OAuth 토큰이 포함되어 있으므로 **절대 공개하지 마세요**.
|
|
745
|
+
- `.gitignore`에 `auth.json`을 추가하는 것을 권장합니다.
|
|
746
|
+
|
|
747
|
+
### 연결 유지
|
|
748
|
+
|
|
749
|
+
- 봇은 자동으로 Ping을 전송하여 연결을 유지합니다.
|
|
750
|
+
- 연결이 끊어지면 `autoReconnect` 옵션에 따라 자동 재연결을 시도합니다.
|
|
751
|
+
|
|
752
|
+
### 미디어 전송
|
|
753
|
+
|
|
754
|
+
- 동영상 전송 시 `transcodeVideos` 옵션을 사용하면 자동으로 트랜스코딩됩니다.
|
|
755
|
+
- 트랜스코딩을 위해서는 FFmpeg가 설치되어 있어야 합니다.
|
|
756
|
+
|
|
757
|
+
---
|
|
758
|
+
|
|
759
|
+
## 라이선스
|
|
760
|
+
|
|
761
|
+
**Non-Commercial / No Abuse**
|
|
762
|
+
|
|
763
|
+
- 이 라이브러리는 비상업적 용도로만 사용할 수 있습니다.
|
|
764
|
+
- 스팸, 사기, 악의적인 목적으로 사용하는 것은 금지됩니다.
|
|
765
|
+
- 자세한 내용은 LICENSE 를 확인하세요.
|
|
766
|
+
|
|
767
|
+
---
|
|
768
|
+
|
|
769
|
+
## Github Issue
|
|
770
|
+
|
|
771
|
+
- 이 라이브러리를 사용하는 중 문제가 발생하였거나 질문이 생겼나요?
|
|
772
|
+
- https://github.com/aodjo/KakaoForge/issues
|