agent-messenger 2.34.0 → 2.35.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/.claude-plugin/plugin.json +1 -1
- package/dist/package.json +1 -1
- package/dist/src/platforms/kakaotalk/auth/kakao-login.d.ts +2 -0
- package/dist/src/platforms/kakaotalk/auth/kakao-login.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/auth/kakao-login.js +2 -2
- package/dist/src/platforms/kakaotalk/auth/kakao-login.js.map +1 -1
- package/dist/src/platforms/kakaotalk/auth/oauth-refresh.d.ts +28 -0
- package/dist/src/platforms/kakaotalk/auth/oauth-refresh.d.ts.map +1 -0
- package/dist/src/platforms/kakaotalk/auth/oauth-refresh.js +100 -0
- package/dist/src/platforms/kakaotalk/auth/oauth-refresh.js.map +1 -0
- package/dist/src/platforms/kakaotalk/client.d.ts +2 -0
- package/dist/src/platforms/kakaotalk/client.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/client.js +14 -1
- package/dist/src/platforms/kakaotalk/client.js.map +1 -1
- package/dist/src/platforms/kakaotalk/index.d.ts +3 -1
- package/dist/src/platforms/kakaotalk/index.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/index.js +1 -0
- package/dist/src/platforms/kakaotalk/index.js.map +1 -1
- package/dist/src/platforms/kakaotalk/protocol/login-response.d.ts +9 -0
- package/dist/src/platforms/kakaotalk/protocol/login-response.d.ts.map +1 -0
- package/dist/src/platforms/kakaotalk/protocol/login-response.js +32 -0
- package/dist/src/platforms/kakaotalk/protocol/login-response.js.map +1 -0
- package/dist/src/platforms/kakaotalk/protocol/session.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/protocol/session.js +29 -20
- package/dist/src/platforms/kakaotalk/protocol/session.js.map +1 -1
- package/dist/src/platforms/kakaotalk/protocol/types.d.ts +1 -0
- package/dist/src/platforms/kakaotalk/protocol/types.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/protocol/types.js.map +1 -1
- package/dist/src/platforms/kakaotalk/types.d.ts +1 -0
- package/dist/src/platforms/kakaotalk/types.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/types.js.map +1 -1
- package/docs/content/docs/cli/kakaotalk.mdx +10 -0
- package/docs/content/docs/sdk/kakaotalk.mdx +54 -0
- 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 +27 -1
- package/skills/agent-kakaotalk/references/authentication.md +59 -0
- package/skills/agent-kakaotalk/references/common-patterns.md +8 -0
- 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/auth/kakao-login.ts +2 -2
- package/src/platforms/kakaotalk/auth/oauth-refresh.test.ts +225 -0
- package/src/platforms/kakaotalk/auth/oauth-refresh.ts +144 -0
- package/src/platforms/kakaotalk/client.test.ts +55 -0
- package/src/platforms/kakaotalk/client.ts +19 -2
- package/src/platforms/kakaotalk/index.test.ts +11 -0
- package/src/platforms/kakaotalk/index.ts +8 -0
- package/src/platforms/kakaotalk/protocol/NOTICE.md +19 -4
- package/src/platforms/kakaotalk/protocol/login-response.test.ts +64 -0
- package/src/platforms/kakaotalk/protocol/login-response.ts +40 -0
- package/src/platforms/kakaotalk/protocol/session.ts +29 -21
- package/src/platforms/kakaotalk/protocol/types.ts +1 -0
- package/src/platforms/kakaotalk/types.ts +1 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { describe, expect, it } from 'bun:test'
|
|
2
|
+
|
|
3
|
+
import { validateLoginListResponse } from './login-response'
|
|
4
|
+
import type { LocoPacket } from './types'
|
|
5
|
+
|
|
6
|
+
function packet(statusCode: number, body: Record<string, unknown>): LocoPacket {
|
|
7
|
+
return { packetId: 1, statusCode, method: 'LOGINLIST', bodyType: 0, body }
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function captureError(fn: () => unknown): unknown {
|
|
11
|
+
try {
|
|
12
|
+
fn()
|
|
13
|
+
return undefined
|
|
14
|
+
} catch (error) {
|
|
15
|
+
return error
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
describe('LOGINLIST response classification', () => {
|
|
20
|
+
it('accepts status=0 and returns the login snapshot', () => {
|
|
21
|
+
const body = { status: 0, chatDatas: [], eof: true }
|
|
22
|
+
|
|
23
|
+
expect(validateLoginListResponse(packet(0, body))).toBe(body)
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
it('accepts a successful response when body.status is omitted', () => {
|
|
27
|
+
const body = { chatDatas: [], eof: true }
|
|
28
|
+
|
|
29
|
+
expect(validateLoginListResponse(packet(0, body))).toBe(body)
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('classifies body.status=-950 as invalid_access_token', () => {
|
|
33
|
+
expect(() => validateLoginListResponse(packet(0, { status: -950 }))).toThrow(
|
|
34
|
+
expect.objectContaining({ code: 'invalid_access_token', serverStatus: -950 }),
|
|
35
|
+
)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('classifies packet statusCode=-950 as invalid_access_token', () => {
|
|
39
|
+
expect(() => validateLoginListResponse(packet(-950, {}))).toThrow(
|
|
40
|
+
expect.objectContaining({ code: 'invalid_access_token', serverStatus: -950 }),
|
|
41
|
+
)
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('classifies an unknown non-zero body status as login_rejected', () => {
|
|
45
|
+
expect(() => validateLoginListResponse(packet(0, { status: -777 }))).toThrow(
|
|
46
|
+
expect.objectContaining({ code: 'login_rejected', serverStatus: -777 }),
|
|
47
|
+
)
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it('classifies an unknown non-zero packet status as login_rejected', () => {
|
|
51
|
+
expect(() => validateLoginListResponse(packet(-777, {}))).toThrow(
|
|
52
|
+
expect.objectContaining({ code: 'login_rejected', serverStatus: -777 }),
|
|
53
|
+
)
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it('keeps a synthetic socket close on the transport-error path', () => {
|
|
57
|
+
const error = captureError(() => validateLoginListResponse(packet(-1, { error: 'connection closed' })))
|
|
58
|
+
|
|
59
|
+
expect(error).toBeInstanceOf(Error)
|
|
60
|
+
expect(error).toMatchObject({ message: 'KakaoTalk LOGINLIST transport failed: connection closed' })
|
|
61
|
+
expect(error).not.toHaveProperty('code')
|
|
62
|
+
expect(error).not.toHaveProperty('serverStatus')
|
|
63
|
+
})
|
|
64
|
+
})
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { KakaoAuthErrorCode } from '../types'
|
|
2
|
+
import type { LoginListResponse, LocoPacket } from './types'
|
|
3
|
+
|
|
4
|
+
const CONNECTION_CLOSED_STATUS = -1
|
|
5
|
+
const INVALID_ACCESS_TOKEN_STATUS = -950
|
|
6
|
+
|
|
7
|
+
export class KakaoLoginResponseError extends Error {
|
|
8
|
+
readonly code: KakaoAuthErrorCode
|
|
9
|
+
readonly serverStatus: number
|
|
10
|
+
|
|
11
|
+
constructor(code: KakaoAuthErrorCode, serverStatus: number) {
|
|
12
|
+
const reason = code === 'invalid_access_token' ? 'invalid access token' : 'rejected'
|
|
13
|
+
super(`KakaoTalk LOGINLIST ${reason} (status ${serverStatus})`)
|
|
14
|
+
this.name = 'KakaoLoginResponseError'
|
|
15
|
+
this.code = code
|
|
16
|
+
this.serverStatus = serverStatus
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function isSyntheticConnectionClose(response: LocoPacket): boolean {
|
|
21
|
+
return response.statusCode === CONNECTION_CLOSED_STATUS && response.body.error === 'connection closed'
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function throwAuthenticationError(serverStatus: number): never {
|
|
25
|
+
const code: KakaoAuthErrorCode =
|
|
26
|
+
serverStatus === INVALID_ACCESS_TOKEN_STATUS ? 'invalid_access_token' : 'login_rejected'
|
|
27
|
+
throw new KakaoLoginResponseError(code, serverStatus)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function validateLoginListResponse(response: LocoPacket): LoginListResponse {
|
|
31
|
+
if (isSyntheticConnectionClose(response)) {
|
|
32
|
+
throw new Error('KakaoTalk LOGINLIST transport failed: connection closed')
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const bodyStatus = typeof response.body.status === 'number' ? response.body.status : 0
|
|
36
|
+
if (bodyStatus !== 0) throwAuthenticationError(bodyStatus)
|
|
37
|
+
if (response.statusCode !== 0) throwAuthenticationError(response.statusCode)
|
|
38
|
+
|
|
39
|
+
return response.body as unknown as LoginListResponse
|
|
40
|
+
}
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
getLocoDeviceConfig,
|
|
16
16
|
} from './config'
|
|
17
17
|
import { LocoConnection } from './connection'
|
|
18
|
+
import { validateLoginListResponse } from './login-response'
|
|
18
19
|
import type { BookingResponse, CheckinResponse, LoginListResponse, LocoPacket, SyncState } from './types'
|
|
19
20
|
|
|
20
21
|
// LOCO opcode string emitted on the wire for typing indicator pulses.
|
|
@@ -81,27 +82,34 @@ export class LocoSession {
|
|
|
81
82
|
const lastTokenId = syncState ? new Long(syncState.lastTokenId.low, syncState.lastTokenId.high) : Long.fromNumber(0)
|
|
82
83
|
const lbk = syncState?.lbk ?? 0
|
|
83
84
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
85
|
+
try {
|
|
86
|
+
const response = await this.connection.sendPacket('LOGINLIST', {
|
|
87
|
+
appVer: deviceConfig.appVersion,
|
|
88
|
+
prtVer: PROTOCOL_VERSION,
|
|
89
|
+
os: deviceConfig.os,
|
|
90
|
+
lang: LANG,
|
|
91
|
+
dtype: DTYPE,
|
|
92
|
+
duuid: deviceUuid,
|
|
93
|
+
oauthToken,
|
|
94
|
+
ntype: 0,
|
|
95
|
+
MCCMNC: MCCMNC,
|
|
96
|
+
revision: syncState?.revision ?? 0,
|
|
97
|
+
chatIds,
|
|
98
|
+
maxIds,
|
|
99
|
+
lastTokenId,
|
|
100
|
+
lbk,
|
|
101
|
+
rp: new Binary(Buffer.from([0x00, 0x00, 0xff, 0xff, 0x00, 0x00])),
|
|
102
|
+
bg: false,
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
const loginResult = validateLoginListResponse(response)
|
|
106
|
+
this.startPing()
|
|
107
|
+
return loginResult
|
|
108
|
+
} catch (error) {
|
|
109
|
+
this.connection.close()
|
|
110
|
+
this.connection = null
|
|
111
|
+
throw error
|
|
112
|
+
}
|
|
105
113
|
}
|
|
106
114
|
|
|
107
115
|
private async bookAndCheckin(
|