agent-messenger 2.37.0 → 2.37.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.
- package/.claude-plugin/plugin.json +1 -1
- package/dist/package.json +1 -1
- package/dist/src/platforms/kakaotalk/chat-classifier.d.ts +4 -4
- package/dist/src/platforms/kakaotalk/chat-classifier.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/chat-classifier.js +7 -3
- package/dist/src/platforms/kakaotalk/chat-classifier.js.map +1 -1
- package/dist/src/platforms/kakaotalk/client.d.ts +12 -0
- package/dist/src/platforms/kakaotalk/client.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/client.js +122 -14
- package/dist/src/platforms/kakaotalk/client.js.map +1 -1
- package/dist/src/platforms/kakaotalk/index.d.ts +1 -0
- package/dist/src/platforms/kakaotalk/index.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/index.js.map +1 -1
- package/dist/src/platforms/kakaotalk/protocol/connection.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/protocol/connection.js +13 -2
- package/dist/src/platforms/kakaotalk/protocol/connection.js.map +1 -1
- package/dist/src/platforms/kakaotalk/protocol/login-response.d.ts +1 -0
- package/dist/src/platforms/kakaotalk/protocol/login-response.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/protocol/login-response.js +1 -1
- package/dist/src/platforms/kakaotalk/protocol/login-response.js.map +1 -1
- package/dist/src/platforms/kakaotalk/types.d.ts +4 -2
- package/dist/src/platforms/kakaotalk/types.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/types.js +6 -1
- package/dist/src/platforms/kakaotalk/types.js.map +1 -1
- package/package.json +1 -1
- package/skills/agent-channeltalk/SKILL.md +1 -1
- package/skills/agent-channeltalkbot/SKILL.md +1 -1
- package/skills/agent-discord/SKILL.md +1 -1
- package/skills/agent-discordbot/SKILL.md +1 -1
- package/skills/agent-imessage/SKILL.md +1 -1
- package/skills/agent-instagram/SKILL.md +1 -1
- package/skills/agent-kakaotalk/SKILL.md +1 -1
- package/skills/agent-line/SKILL.md +1 -1
- package/skills/agent-slack/SKILL.md +1 -1
- package/skills/agent-slackbot/SKILL.md +1 -1
- package/skills/agent-teams/SKILL.md +1 -1
- package/skills/agent-telegram/SKILL.md +1 -1
- package/skills/agent-telegrambot/SKILL.md +1 -1
- package/skills/agent-webex/SKILL.md +1 -1
- package/skills/agent-webexbot/SKILL.md +1 -1
- package/skills/agent-wechatbot/SKILL.md +1 -1
- package/skills/agent-whatsapp/SKILL.md +1 -1
- package/skills/agent-whatsappbot/SKILL.md +1 -1
- package/src/platforms/kakaotalk/chat-classifier.test.ts +22 -0
- package/src/platforms/kakaotalk/chat-classifier.ts +7 -4
- package/src/platforms/kakaotalk/client.test.ts +638 -4
- package/src/platforms/kakaotalk/client.ts +156 -15
- package/src/platforms/kakaotalk/index.test.ts +27 -0
- package/src/platforms/kakaotalk/index.ts +5 -0
- package/src/platforms/kakaotalk/protocol/connection.test.ts +87 -0
- package/src/platforms/kakaotalk/protocol/connection.ts +15 -2
- package/src/platforms/kakaotalk/protocol/login-response.test.ts +13 -2
- package/src/platforms/kakaotalk/protocol/login-response.ts +1 -1
- package/src/platforms/kakaotalk/types.ts +10 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-messenger",
|
|
3
|
-
"version": "2.37.
|
|
3
|
+
"version": "2.37.2",
|
|
4
4
|
"description": "Messaging platform interaction skills for AI agents. Interact with Slack, Discord, Microsoft Teams, Webex, Telegram, Telegram Bot, WhatsApp, LINE, iMessage, Instagram, KakaoTalk, and Channel Talk - send messages, read channels, manage reactions, upload files, and more through simple CLI interfaces.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "agent-messenger",
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-messenger",
|
|
3
|
-
"version": "2.37.
|
|
3
|
+
"version": "2.37.2",
|
|
4
4
|
"description": "Multi-platform messaging CLI for AI agents (Slack, Discord, Teams, Webex, Telegram, Telegram Bot, WhatsApp, LINE, iMessage, Instagram, KakaoTalk, Channel Talk)",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type KakaoChat, type KakaoOpenChatType } from './types.js';
|
|
2
2
|
export type KakaoChatKind = 'dm' | 'group' | 'open' | 'unknown';
|
|
3
3
|
export declare function isOpenKakaoChatType(type: unknown): type is KakaoOpenChatType;
|
|
4
4
|
/**
|
|
@@ -11,9 +11,9 @@ export declare function isOpenKakaoChatType(type: unknown): type is KakaoOpenCha
|
|
|
11
11
|
* NOT "simplify" this back to a pure type-code mapping without verifying
|
|
12
12
|
* against a real KakaoTalk session.
|
|
13
13
|
*
|
|
14
|
-
* `'unknown'` is reserved for future protocol drift
|
|
15
|
-
*
|
|
16
|
-
*
|
|
14
|
+
* `'unknown'` is reserved for future string protocol drift so consumers fail
|
|
15
|
+
* closed instead of silently classifying an unrecognized server value by
|
|
16
|
+
* member count.
|
|
17
17
|
*/
|
|
18
18
|
export declare function classifyKakaoChat(chat: Pick<KakaoChat, 'type' | 'active_members'>): KakaoChatKind;
|
|
19
19
|
//# sourceMappingURL=chat-classifier.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-classifier.d.ts","sourceRoot":"","sources":["../../../../src/platforms/kakaotalk/chat-classifier.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"chat-classifier.d.ts","sourceRoot":"","sources":["../../../../src/platforms/kakaotalk/chat-classifier.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,KAAK,SAAS,EAAE,KAAK,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAE5F,MAAM,MAAM,aAAa,GAAG,IAAI,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAA;AAO/D,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,iBAAiB,CAE5E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,CAAC,GAAG,aAAa,CASjG"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isKnownKakaoChatStringType } from './types.js';
|
|
1
2
|
// OpenChat-family `type` values observed on the wire. Login/chat-list data
|
|
2
3
|
// uses numeric codes while CHATINFO may return the protocol string tags
|
|
3
4
|
// `OM` / `OD`; both forms must share this single classification owner.
|
|
@@ -15,13 +16,16 @@ export function isOpenKakaoChatType(type) {
|
|
|
15
16
|
* NOT "simplify" this back to a pure type-code mapping without verifying
|
|
16
17
|
* against a real KakaoTalk session.
|
|
17
18
|
*
|
|
18
|
-
* `'unknown'` is reserved for future protocol drift
|
|
19
|
-
*
|
|
20
|
-
*
|
|
19
|
+
* `'unknown'` is reserved for future string protocol drift so consumers fail
|
|
20
|
+
* closed instead of silently classifying an unrecognized server value by
|
|
21
|
+
* member count.
|
|
21
22
|
*/
|
|
22
23
|
export function classifyKakaoChat(chat) {
|
|
23
24
|
if (isOpenKakaoChatType(chat.type))
|
|
24
25
|
return 'open';
|
|
26
|
+
if (typeof chat.type === 'string' && !isKnownKakaoChatStringType(chat.type)) {
|
|
27
|
+
return 'unknown';
|
|
28
|
+
}
|
|
25
29
|
// active_members counts the logged-in user, so a 1:1 DM is exactly 2
|
|
26
30
|
// (self + one other) and a "lone" room with only self is 1.
|
|
27
31
|
if (chat.active_members <= 2)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-classifier.js","sourceRoot":"","sources":["../../../../src/platforms/kakaotalk/chat-classifier.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"chat-classifier.js","sourceRoot":"","sources":["../../../../src/platforms/kakaotalk/chat-classifier.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAA0C,MAAM,SAAS,CAAA;AAI5F,2EAA2E;AAC3E,wEAAwE;AACxE,uEAAuE;AACvE,MAAM,eAAe,GAAmC,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAA;AAEhG,MAAM,UAAU,mBAAmB,CAAC,IAAa;IAC/C,OAAO,eAAe,CAAC,GAAG,CAAC,IAAyB,CAAC,CAAA;AACvD,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAgD;IAChF,IAAI,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,MAAM,CAAA;IACjD,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,0BAA0B,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC5E,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,qEAAqE;IACrE,4DAA4D;IAC5D,IAAI,IAAI,CAAC,cAAc,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA;IACzC,OAAO,OAAO,CAAA;AAChB,CAAC"}
|
|
@@ -13,12 +13,21 @@ export type KakaoSessionEvent = {
|
|
|
13
13
|
};
|
|
14
14
|
export type KakaoPushHandler = (packet: LocoPacket) => void;
|
|
15
15
|
export type KakaoSessionEventHandler = (event: KakaoSessionEvent) => void;
|
|
16
|
+
export type KakaoTalkResponseFailureKind = 'provider_rejection' | 'transient_or_unknown';
|
|
17
|
+
export type KakaoTalkResponseStatusSource = 'packet' | 'body';
|
|
18
|
+
export type KakaoTalkGetChatFailureReason = 'provider_rejection' | 'synthetic_connection_close' | 'chat_info_absent' | 'transport_or_unknown';
|
|
16
19
|
export declare class KakaoTalkError extends Error {
|
|
17
20
|
code: string;
|
|
18
21
|
readonly serverStatus?: number;
|
|
22
|
+
readonly responseFailureKind?: KakaoTalkResponseFailureKind;
|
|
23
|
+
readonly responseStatusSource?: KakaoTalkResponseStatusSource;
|
|
24
|
+
readonly getChatFailureReason?: KakaoTalkGetChatFailureReason;
|
|
19
25
|
constructor(message: string, code: string, options?: {
|
|
20
26
|
cause?: unknown;
|
|
21
27
|
serverStatus?: number;
|
|
28
|
+
responseFailureKind?: KakaoTalkResponseFailureKind;
|
|
29
|
+
responseStatusSource?: KakaoTalkResponseStatusSource;
|
|
30
|
+
getChatFailureReason?: KakaoTalkGetChatFailureReason;
|
|
22
31
|
});
|
|
23
32
|
}
|
|
24
33
|
export declare class KakaoTalkClient {
|
|
@@ -66,6 +75,9 @@ export declare class KakaoTalkClient {
|
|
|
66
75
|
* Unlike `getChats()`, this does not depend on the login-time snapshot or
|
|
67
76
|
* LCHATLIST pagination, so a room first observed from a live push can be
|
|
68
77
|
* resolved without interpreting protocol fields outside this SDK.
|
|
78
|
+
* The returned chat type preserves numeric values and non-empty protocol
|
|
79
|
+
* strings, including DirectChat, MultiChat, PlusChat, MemoChat, OM, and OD;
|
|
80
|
+
* unknown non-empty strings are preserved for forward compatibility.
|
|
69
81
|
*/
|
|
70
82
|
getChat(chatId: string): Promise<KakaoChat>;
|
|
71
83
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../../src/platforms/kakaotalk/client.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,KAAK,eAAe,EAA4C,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../../src/platforms/kakaotalk/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,17 +9,36 @@ import { isOpenKakaoChatType } from './chat-classifier.js';
|
|
|
9
9
|
import { detectImageDimensions } from './image-meta.js';
|
|
10
10
|
import { sha1Hex } from './media-upload.js';
|
|
11
11
|
import { LANG, PC_OS_NAME, getLocoDeviceConfig } from './protocol/config.js';
|
|
12
|
+
import { isSyntheticConnectionClose } from './protocol/login-response.js';
|
|
12
13
|
import { uploadMediaToLoco, uploadMultiMediaEntry } from './protocol/media-uploader.js';
|
|
13
14
|
import { LocoSession } from './protocol/session.js';
|
|
14
15
|
import { KAKAO_MESSAGE_TYPE, } from './types.js';
|
|
15
16
|
export class KakaoTalkError extends Error {
|
|
16
17
|
code;
|
|
17
18
|
serverStatus;
|
|
19
|
+
responseFailureKind;
|
|
20
|
+
responseStatusSource;
|
|
21
|
+
getChatFailureReason;
|
|
18
22
|
constructor(message, code, options) {
|
|
19
23
|
super(message, options);
|
|
20
24
|
this.name = 'KakaoTalkError';
|
|
21
25
|
this.code = code;
|
|
22
26
|
this.serverStatus = options?.serverStatus;
|
|
27
|
+
this.responseFailureKind = options?.responseFailureKind;
|
|
28
|
+
this.responseStatusSource = options?.responseStatusSource;
|
|
29
|
+
this.getChatFailureReason = options?.getChatFailureReason;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
class LocoResponseError extends Error {
|
|
33
|
+
serverStatus;
|
|
34
|
+
responseFailureKind;
|
|
35
|
+
responseStatusSource;
|
|
36
|
+
constructor(message, responseFailureKind, options) {
|
|
37
|
+
super(message);
|
|
38
|
+
this.name = 'LocoResponseError';
|
|
39
|
+
this.serverStatus = options?.serverStatus;
|
|
40
|
+
this.responseFailureKind = responseFailureKind;
|
|
41
|
+
this.responseStatusSource = options?.responseStatusSource;
|
|
23
42
|
}
|
|
24
43
|
}
|
|
25
44
|
class MemberNameCache {
|
|
@@ -76,6 +95,19 @@ function bsonToLong(v) {
|
|
|
76
95
|
}
|
|
77
96
|
return undefined;
|
|
78
97
|
}
|
|
98
|
+
// LCHATLIST cursor fields (lastTokenId/lastChatId) arrive as plain numbers when the
|
|
99
|
+
// value fits in a safe integer, because bson promotes them, and as { low, high }
|
|
100
|
+
// otherwise. bsonToLong only accepts the object form, so a numeric cursor became
|
|
101
|
+
// undefined and getChatList() re-requested the first page until MAX_PAGES.
|
|
102
|
+
// Kept separate from bsonToLong on purpose: its other callers (log ids, open link
|
|
103
|
+
// ids) rely on a numeric 0 staying absent rather than becoming a Long.
|
|
104
|
+
function cursorToLong(v) {
|
|
105
|
+
if (typeof v === 'number' && Number.isSafeInteger(v))
|
|
106
|
+
return Long.fromNumber(v);
|
|
107
|
+
if (typeof v === 'bigint')
|
|
108
|
+
return Long.fromBigInt(v);
|
|
109
|
+
return bsonToLong(v);
|
|
110
|
+
}
|
|
79
111
|
function longToString(v) {
|
|
80
112
|
if (v && typeof v === 'object' && 'high' in v && 'low' in v) {
|
|
81
113
|
const { high, low } = v;
|
|
@@ -142,7 +174,7 @@ function formatChat(chat, title, nameCache) {
|
|
|
142
174
|
const chatId = longToString(chat.c);
|
|
143
175
|
return {
|
|
144
176
|
chat_id: chatId,
|
|
145
|
-
type: chat.t,
|
|
177
|
+
type: requiredChatType(chat.t),
|
|
146
178
|
display_name: displayName,
|
|
147
179
|
title,
|
|
148
180
|
active_members: chat.a,
|
|
@@ -185,7 +217,7 @@ function requiredNonNegativeInteger(value, field) {
|
|
|
185
217
|
return value;
|
|
186
218
|
}
|
|
187
219
|
function requiredChatType(value) {
|
|
188
|
-
if (typeof value === 'string' &&
|
|
220
|
+
if (typeof value === 'string' && value.length > 0) {
|
|
189
221
|
return value;
|
|
190
222
|
}
|
|
191
223
|
return requiredNonNegativeInteger(value, 'type');
|
|
@@ -267,11 +299,39 @@ function collectChats(chatDatas, into, seen) {
|
|
|
267
299
|
}
|
|
268
300
|
}
|
|
269
301
|
}
|
|
270
|
-
function wrapError(error, code) {
|
|
271
|
-
if (error instanceof KakaoTalkError)
|
|
272
|
-
|
|
302
|
+
function wrapError(error, code, options) {
|
|
303
|
+
if (error instanceof KakaoTalkError) {
|
|
304
|
+
const responseFailureKind = error.responseFailureKind ?? (options?.classifyResponseFailure ? 'transient_or_unknown' : undefined);
|
|
305
|
+
const getChatFailureReason = error.getChatFailureReason ?? (options?.classifyGetChatFailure ? 'transport_or_unknown' : undefined);
|
|
306
|
+
if (responseFailureKind === error.responseFailureKind && getChatFailureReason === error.getChatFailureReason) {
|
|
307
|
+
return error;
|
|
308
|
+
}
|
|
309
|
+
return new KakaoTalkError(error.message, error.code, {
|
|
310
|
+
cause: error.cause ?? error,
|
|
311
|
+
serverStatus: error.serverStatus,
|
|
312
|
+
responseFailureKind,
|
|
313
|
+
responseStatusSource: error.responseStatusSource,
|
|
314
|
+
getChatFailureReason,
|
|
315
|
+
});
|
|
316
|
+
}
|
|
273
317
|
const message = error instanceof Error ? error.message : String(error);
|
|
274
|
-
return new KakaoTalkError(message, code, {
|
|
318
|
+
return new KakaoTalkError(message, code, {
|
|
319
|
+
cause: error,
|
|
320
|
+
serverStatus: error instanceof LocoResponseError ? error.serverStatus : undefined,
|
|
321
|
+
responseStatusSource: error instanceof LocoResponseError ? error.responseStatusSource : undefined,
|
|
322
|
+
responseFailureKind: error instanceof LocoResponseError
|
|
323
|
+
? error.responseFailureKind
|
|
324
|
+
: options?.classifyResponseFailure
|
|
325
|
+
? 'transient_or_unknown'
|
|
326
|
+
: undefined,
|
|
327
|
+
getChatFailureReason: options?.classifyGetChatFailure
|
|
328
|
+
? error instanceof LocoResponseError && error.responseFailureKind === 'provider_rejection'
|
|
329
|
+
? 'provider_rejection'
|
|
330
|
+
: error instanceof LocoResponseError && error.responseStatusSource === 'packet' && error.serverStatus === -1
|
|
331
|
+
? 'synthetic_connection_close'
|
|
332
|
+
: 'transport_or_unknown'
|
|
333
|
+
: undefined,
|
|
334
|
+
});
|
|
275
335
|
}
|
|
276
336
|
function isLoginResponseError(error) {
|
|
277
337
|
if (!(error instanceof Error))
|
|
@@ -393,12 +453,27 @@ function isNonZeroLong(v) {
|
|
|
393
453
|
// caller-visible error channel (e.g. GETMEM/MEMBER return `[]` for both empty rooms and dead
|
|
394
454
|
// sockets). Throwing here lets executeWithReconnect detect session death and reconnect.
|
|
395
455
|
function assertLocoOk(response, command) {
|
|
456
|
+
if (typeof response.statusCode !== 'number' || !Number.isFinite(response.statusCode)) {
|
|
457
|
+
throw new LocoResponseError(`${command} failed: response status unavailable`, 'transient_or_unknown');
|
|
458
|
+
}
|
|
459
|
+
if (isSyntheticConnectionClose(response)) {
|
|
460
|
+
throw new LocoResponseError(`${command} failed: connection closed`, 'transient_or_unknown', {
|
|
461
|
+
serverStatus: response.statusCode,
|
|
462
|
+
responseStatusSource: 'packet',
|
|
463
|
+
});
|
|
464
|
+
}
|
|
396
465
|
if (response.statusCode !== 0) {
|
|
397
|
-
throw new
|
|
466
|
+
throw new LocoResponseError(`${command} failed: statusCode=${response.statusCode}`, 'provider_rejection', {
|
|
467
|
+
serverStatus: response.statusCode,
|
|
468
|
+
responseStatusSource: 'packet',
|
|
469
|
+
});
|
|
398
470
|
}
|
|
399
471
|
const bodyStatus = response.body.status;
|
|
400
472
|
if (typeof bodyStatus === 'number' && bodyStatus !== 0) {
|
|
401
|
-
throw new
|
|
473
|
+
throw new LocoResponseError(`${command} failed: body.status=${bodyStatus}`, 'provider_rejection', {
|
|
474
|
+
serverStatus: bodyStatus,
|
|
475
|
+
responseStatusSource: 'body',
|
|
476
|
+
});
|
|
402
477
|
}
|
|
403
478
|
}
|
|
404
479
|
function formatMember(member) {
|
|
@@ -767,6 +842,7 @@ export class KakaoTalkClient {
|
|
|
767
842
|
if (options?.all || options?.search || snapshotEmpty) {
|
|
768
843
|
let cursor = loginResult;
|
|
769
844
|
let pages = 0;
|
|
845
|
+
const requireCompleteList = options?.all === true;
|
|
770
846
|
while (pages < MAX_PAGES) {
|
|
771
847
|
// Trust eof only when the snapshot had data. When the snapshot was empty
|
|
772
848
|
// (new device), ignore eof for the first iteration so we always attempt
|
|
@@ -775,17 +851,29 @@ export class KakaoTalkClient {
|
|
|
775
851
|
break;
|
|
776
852
|
if (cursor.eof && snapshotEmpty && pages > 0)
|
|
777
853
|
break;
|
|
778
|
-
const lastTokenId =
|
|
779
|
-
const lastChatId =
|
|
854
|
+
const lastTokenId = cursorToLong(cursor.lastTokenId);
|
|
855
|
+
const lastChatId = cursorToLong(cursor.lastChatId);
|
|
780
856
|
const response = await session.getChatList(lastTokenId, lastChatId);
|
|
857
|
+
if (requireCompleteList)
|
|
858
|
+
assertLocoOk(response, 'LCHATLIST');
|
|
781
859
|
const body = response.body;
|
|
860
|
+
if (requireCompleteList && !Array.isArray(body.chatDatas)) {
|
|
861
|
+
throw new Error('LCHATLIST pagination incomplete: chatDatas unavailable');
|
|
862
|
+
}
|
|
782
863
|
const chatDatas = (body.chatDatas ?? []);
|
|
783
|
-
|
|
864
|
+
cursor = body;
|
|
865
|
+
pages++;
|
|
866
|
+
if (chatDatas.length === 0) {
|
|
867
|
+
if (requireCompleteList && body.eof !== true) {
|
|
868
|
+
throw new Error('LCHATLIST pagination incomplete: empty non-EOF page');
|
|
869
|
+
}
|
|
784
870
|
break;
|
|
871
|
+
}
|
|
785
872
|
collectChats(chatDatas, allChats, seenChatIds);
|
|
786
873
|
this.nameCache.ingest(chatDatas);
|
|
787
|
-
|
|
788
|
-
|
|
874
|
+
}
|
|
875
|
+
if (requireCompleteList && cursor.eof !== true) {
|
|
876
|
+
throw new Error(`LCHATLIST pagination incomplete after ${pages} pages`);
|
|
789
877
|
}
|
|
790
878
|
}
|
|
791
879
|
allChats.sort((a, b) => (b.o ?? 0) - (a.o ?? 0));
|
|
@@ -809,6 +897,9 @@ export class KakaoTalkClient {
|
|
|
809
897
|
* Unlike `getChats()`, this does not depend on the login-time snapshot or
|
|
810
898
|
* LCHATLIST pagination, so a room first observed from a live push can be
|
|
811
899
|
* resolved without interpreting protocol fields outside this SDK.
|
|
900
|
+
* The returned chat type preserves numeric values and non-empty protocol
|
|
901
|
+
* strings, including DirectChat, MultiChat, PlusChat, MemoChat, OM, and OD;
|
|
902
|
+
* unknown non-empty strings are preserved for forward compatibility.
|
|
812
903
|
*/
|
|
813
904
|
async getChat(chatId) {
|
|
814
905
|
const parsedChatId = parseChatId(chatId);
|
|
@@ -818,6 +909,20 @@ export class KakaoTalkClient {
|
|
|
818
909
|
const response = await session.getChannelInfo(parsedChatId);
|
|
819
910
|
assertLocoOk(response, 'CHATINFO');
|
|
820
911
|
const body = response.body;
|
|
912
|
+
const chatInfo = body.chatInfo;
|
|
913
|
+
const isLeftChatInfo = chatInfo !== null &&
|
|
914
|
+
typeof chatInfo === 'object' &&
|
|
915
|
+
!Array.isArray(chatInfo) &&
|
|
916
|
+
chatInfo.left === true;
|
|
917
|
+
if (isLeftChatInfo) {
|
|
918
|
+
extractChannelInfo(body, normalizedChatId);
|
|
919
|
+
}
|
|
920
|
+
if (chatInfo === undefined || chatInfo === null || isLeftChatInfo) {
|
|
921
|
+
throw new KakaoTalkError('CHATINFO response missing chatInfo', 'get_chat_failed', {
|
|
922
|
+
responseFailureKind: 'transient_or_unknown',
|
|
923
|
+
getChatFailureReason: 'chat_info_absent',
|
|
924
|
+
});
|
|
925
|
+
}
|
|
821
926
|
const chat = channelInfoToChatData(body, normalizedChatId);
|
|
822
927
|
this.nameCache.ingest([chat]);
|
|
823
928
|
let title = extractTitle(body);
|
|
@@ -836,7 +941,10 @@ export class KakaoTalkClient {
|
|
|
836
941
|
return formatChat(chat, title, this.nameCache);
|
|
837
942
|
}
|
|
838
943
|
catch (error) {
|
|
839
|
-
throw wrapError(error, 'get_chat_failed'
|
|
944
|
+
throw wrapError(error, 'get_chat_failed', {
|
|
945
|
+
classifyResponseFailure: true,
|
|
946
|
+
classifyGetChatFailure: true,
|
|
947
|
+
});
|
|
840
948
|
}
|
|
841
949
|
});
|
|
842
950
|
}
|