@kakao-bot/sdk 0.4.0 → 0.5.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/README.md CHANGED
@@ -45,7 +45,13 @@ await kakao.sendMessage({
45
45
  });
46
46
  ```
47
47
 
48
- 방에 누가 있는지는 `listRoomMembers`로 봅니다(`rooms:read` 권한). 카톡 방 정보에서 온 계정 ID와, 그 방에서 본 적 있는 표시 이름을 돌려줍니다.
48
+ 이름만 알면 `mentions`로 태그할 수 있습니다. 그 방 참여자 한 명으로 정해져야 보내고, 없거나 여럿이면 `KakaoApiError`(`mention_name_unknown` / `mention_name_ambiguous`, `body.candidates`)로 거절됩니다.
49
+
50
+ ```ts
51
+ await bot.sendMessage({ roomSlug: "tf", text: "@이현근 확인 부탁해요", mentions: ["이현근"] });
52
+ ```
53
+
54
+ 방에 누가 있는지는 `listRoomMembers`(목록만) 또는 `getRoomMembers`(검색 `q`, 인원 `known`/`total`, 오픈채팅 여부, 마지막 동기화)로 봅니다(`rooms:read` 권한). 카톡 방 정보에서 온 계정 ID와, 그 방에서 본 적 있는 표시 이름을 돌려줍니다.
49
55
 
50
56
  ```ts
51
57
  const members = await bot.listRoomMembers({ roomSlug: "tf" });
package/dist/index.d.ts CHANGED
@@ -31,6 +31,12 @@ export type SendMessageInput = ({
31
31
  text: string;
32
32
  /** Reuse this ID for the same logical send. No automatic retries are performed. */
33
33
  requestId?: string;
34
+ /**
35
+ * Tag people by display name (e.g. `["이현근"]`). Each must match exactly one room member;
36
+ * `@이름` in `text` becomes the tag, otherwise tags go first. Unknown or ambiguous names
37
+ * reject with `mention_name_unknown` / `mention_name_ambiguous` (and `candidates`), unsent.
38
+ */
39
+ mentions?: string[];
34
40
  };
35
41
  export interface SendMessageResult {
36
42
  ok: true;
@@ -57,6 +63,18 @@ export interface RoomMember {
57
63
  /** `<@userId>`; tags the member when included in message text. */
58
64
  mention: string;
59
65
  }
66
+ /** A room's members plus how complete the list is. */
67
+ export interface RoomMembers {
68
+ members: RoomMember[];
69
+ /** Members the hub knows. */
70
+ known: number;
71
+ /** KakaoTalk's own member count, when reported. */
72
+ total: number | null;
73
+ /** Open chat. Full lists come from Kakao's server hourly; `total` may briefly exceed `known`. */
74
+ openChat: boolean;
75
+ /** Last full member sync (epoch ms), or null before the first one. */
76
+ syncedAt: number | null;
77
+ }
60
78
  /** Hub-signed inbound webhook. Validate the HMAC on the raw body before parsing. */
61
79
  export interface InboundWebhookEvent {
62
80
  event_id: string;
@@ -95,5 +113,16 @@ export declare class KakaoBot {
95
113
  } | {
96
114
  roomSlug: string;
97
115
  }, options?: RequestOptions): Promise<RoomMember[]>;
116
+ /**
117
+ * Members with list completeness (`known`, `total`, `openChat`, `syncedAt`). `q` filters by
118
+ * name (case-insensitive substring) or exact user ID. Requires the `rooms:read` scope.
119
+ */
120
+ getRoomMembers(room: ({
121
+ roomId: string;
122
+ } | {
123
+ roomSlug: string;
124
+ }) & {
125
+ q?: string;
126
+ }, options?: RequestOptions): Promise<RoomMembers>;
98
127
  private request;
99
128
  }
package/dist/index.js CHANGED
@@ -53,7 +53,12 @@ export class KakaoBot {
53
53
  ? `/v1/rooms/id/${encodeURIComponent(input.roomId)}/messages`
54
54
  : input.roomSlug !== undefined
55
55
  ? `/v1/rooms/${encodeURIComponent(input.roomSlug)}/messages`
56
- : "/v1/messages", "POST", { room: input.room, msg: input.text, request_id: requestId }, options.signal, requestId);
56
+ : "/v1/messages", "POST", {
57
+ room: input.room,
58
+ msg: input.text,
59
+ request_id: requestId,
60
+ ...(input.mentions ? { mentions: input.mentions } : {}),
61
+ }, options.signal, requestId);
57
62
  if (!object(data) ||
58
63
  data.ok !== true ||
59
64
  typeof data.queued !== "boolean" ||
@@ -79,9 +84,17 @@ export class KakaoBot {
79
84
  }
80
85
  /** Members of a room bound to this service. Requires the `rooms:read` scope. */
81
86
  async listRoomMembers(room, options = {}) {
82
- const path = "roomId" in room
87
+ return (await this.getRoomMembers(room, options)).members;
88
+ }
89
+ /**
90
+ * Members with list completeness (`known`, `total`, `openChat`, `syncedAt`). `q` filters by
91
+ * name (case-insensitive substring) or exact user ID. Requires the `rooms:read` scope.
92
+ */
93
+ async getRoomMembers(room, options = {}) {
94
+ const base = "roomId" in room
83
95
  ? `/v1/rooms/id/${encodeURIComponent(room.roomId)}/members`
84
96
  : `/v1/rooms/${encodeURIComponent(room.roomSlug)}/members`;
97
+ const path = room.q ? `${base}?q=${encodeURIComponent(room.q)}` : base;
85
98
  const data = await this.request(path, "GET", undefined, options.signal);
86
99
  if (!object(data) ||
87
100
  !Array.isArray(data.members) ||
@@ -91,7 +104,13 @@ export class KakaoBot {
91
104
  (member.name === null || typeof member.name === "string") &&
92
105
  member.mention === `<@${member.userId}>`))
93
106
  throw new KakaoProtocolError();
94
- return data.members;
107
+ return {
108
+ members: data.members,
109
+ known: typeof data.known === "number" ? data.known : data.members.length,
110
+ total: typeof data.total === "number" ? data.total : null,
111
+ openChat: data.openChat === true,
112
+ syncedAt: typeof data.syncedAt === "number" ? data.syncedAt : null,
113
+ };
95
114
  }
96
115
  async request(path, method, body, signal, requestId) {
97
116
  const timeout = AbortSignal.timeout(this.timeoutMs);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kakao-bot/sdk",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Typed server-side client for the Kakao Bot Hub API",
5
5
  "license": "MIT",
6
6
  "author": "Jeongmin Lee",