@noverachat/sdk-web 0.1.0 → 0.2.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/dist/index.cjs +99 -0
- package/dist/index.d.cts +51 -1
- package/dist/index.d.ts +51 -1
- package/dist/index.js +99 -0
- package/package.json +1 -1
- package/src/features/room.ts +87 -0
- package/src/generated/rest.ts +49 -0
- package/src/index.ts +3 -0
- package/src/types.ts +3 -0
package/dist/index.cjs
CHANGED
|
@@ -206,6 +206,30 @@ function parseBulkDeleteBySenderResult(j) {
|
|
|
206
206
|
cleared: j["cleared"]
|
|
207
207
|
};
|
|
208
208
|
}
|
|
209
|
+
function parseJoinRequestOut(j) {
|
|
210
|
+
return {
|
|
211
|
+
userId: j["user_id"],
|
|
212
|
+
status: j["status"],
|
|
213
|
+
reason: j["reason"],
|
|
214
|
+
requestedAt: j["requested_at"],
|
|
215
|
+
processedAt: j["processed_at"],
|
|
216
|
+
processedByUserId: j["processed_by_user_id"]
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
function parseJoinRequestListResponse(j) {
|
|
220
|
+
return {
|
|
221
|
+
items: j["items"].map((e) => parseJoinRequestOut(e)),
|
|
222
|
+
total: j["total"],
|
|
223
|
+
limit: j["limit"],
|
|
224
|
+
offset: j["offset"]
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
function parseJoinRequestCreateResponse(j) {
|
|
228
|
+
return {
|
|
229
|
+
status: j["status"],
|
|
230
|
+
roomId: j["room_id"]
|
|
231
|
+
};
|
|
232
|
+
}
|
|
209
233
|
function parseSenderMini(j) {
|
|
210
234
|
return {
|
|
211
235
|
userId: j["user_id"],
|
|
@@ -1246,6 +1270,81 @@ var Room = class _Room {
|
|
|
1246
1270
|
`/api/v1/rooms/${this.roomId}/invites/${encodeURIComponent(token)}`
|
|
1247
1271
|
);
|
|
1248
1272
|
}
|
|
1273
|
+
// -------- join requests --------
|
|
1274
|
+
/**
|
|
1275
|
+
* Ask to join this room (self). Behavior depends on the room's
|
|
1276
|
+
* `joinPolicy`:
|
|
1277
|
+
* - `OPEN` → the caller is added immediately (`status: "joined"`);
|
|
1278
|
+
* - `APPROVAL_REQUIRED` → the request lands in the operators' inbox
|
|
1279
|
+
* (`status: "pending"`) until [`approveJoinRequest`] / reject.
|
|
1280
|
+
* Idempotent for members (`status: "already_member"`).
|
|
1281
|
+
*
|
|
1282
|
+
* @param reason Optional note shown to operators ("하은이 반 친구 엄마예요").
|
|
1283
|
+
*/
|
|
1284
|
+
async requestJoin(reason) {
|
|
1285
|
+
const raw = await this.http.request(
|
|
1286
|
+
"POST",
|
|
1287
|
+
`/api/v1/rooms/${this.roomId}/join-request`,
|
|
1288
|
+
reason ? { reason } : {}
|
|
1289
|
+
);
|
|
1290
|
+
return parseJoinRequestCreateResponse(raw);
|
|
1291
|
+
}
|
|
1292
|
+
/** Cancel the caller's own pending join request. */
|
|
1293
|
+
async cancelJoinRequest() {
|
|
1294
|
+
await this.http.request(
|
|
1295
|
+
"DELETE",
|
|
1296
|
+
`/api/v1/rooms/${this.roomId}/join-request`
|
|
1297
|
+
);
|
|
1298
|
+
}
|
|
1299
|
+
/** OPERATOR-only: list join requests for this room (the approval inbox).
|
|
1300
|
+
* Defaults to pending only — pass a status to see processed history. */
|
|
1301
|
+
async listJoinRequests(opts) {
|
|
1302
|
+
const raw = await this.http.request(
|
|
1303
|
+
"GET",
|
|
1304
|
+
`/api/v1/rooms/${this.roomId}/join-requests`,
|
|
1305
|
+
void 0,
|
|
1306
|
+
{
|
|
1307
|
+
...opts?.status ? { status: opts.status } : {},
|
|
1308
|
+
...opts?.limit !== void 0 ? { limit: opts.limit } : {},
|
|
1309
|
+
...opts?.offset !== void 0 ? { offset: opts.offset } : {}
|
|
1310
|
+
}
|
|
1311
|
+
);
|
|
1312
|
+
return parseJoinRequestListResponse(raw);
|
|
1313
|
+
}
|
|
1314
|
+
/** OPERATOR-only: approve a pending join request — the requester becomes
|
|
1315
|
+
* a MEMBER. [reason] is echoed back to them in later list calls. */
|
|
1316
|
+
async approveJoinRequest(userId, reason) {
|
|
1317
|
+
await this.http.request(
|
|
1318
|
+
"POST",
|
|
1319
|
+
`/api/v1/rooms/${this.roomId}/join-requests/${encodeURIComponent(userId)}/approve`,
|
|
1320
|
+
reason ? { reason } : {}
|
|
1321
|
+
);
|
|
1322
|
+
}
|
|
1323
|
+
/** OPERATOR-only: reject a pending join request. */
|
|
1324
|
+
async rejectJoinRequest(userId, reason) {
|
|
1325
|
+
await this.http.request(
|
|
1326
|
+
"POST",
|
|
1327
|
+
`/api/v1/rooms/${this.roomId}/join-requests/${encodeURIComponent(userId)}/reject`,
|
|
1328
|
+
reason ? { reason } : {}
|
|
1329
|
+
);
|
|
1330
|
+
}
|
|
1331
|
+
// -------- hide / unhide --------
|
|
1332
|
+
/** Hide this room from the caller's own room list (self, reversible —
|
|
1333
|
+
* the KakaoTalk "숨기기"). The room typically reappears via [unhide]
|
|
1334
|
+
* or on new activity, per server policy. Messages are untouched. */
|
|
1335
|
+
async hide() {
|
|
1336
|
+
await this.http.request(
|
|
1337
|
+
"POST",
|
|
1338
|
+
`/api/v1/rooms/${this.roomId}/hide`
|
|
1339
|
+
);
|
|
1340
|
+
}
|
|
1341
|
+
/** Undo [hide] — the room shows up in the caller's list again. */
|
|
1342
|
+
async unhide() {
|
|
1343
|
+
await this.http.request(
|
|
1344
|
+
"POST",
|
|
1345
|
+
`/api/v1/rooms/${this.roomId}/unhide`
|
|
1346
|
+
);
|
|
1347
|
+
}
|
|
1249
1348
|
// -------- internal dispatch --------
|
|
1250
1349
|
on(event, fn) {
|
|
1251
1350
|
return this.bus.on(event, fn);
|
package/dist/index.d.cts
CHANGED
|
@@ -320,6 +320,25 @@ interface RoomMemberOut {
|
|
|
320
320
|
isOnline?: boolean | null;
|
|
321
321
|
mutedUntil?: string | null;
|
|
322
322
|
}
|
|
323
|
+
interface JoinRequestOut {
|
|
324
|
+
userId: string;
|
|
325
|
+
status: "PENDING" | "APPROVED" | "REJECTED" | "CANCELLED";
|
|
326
|
+
reason: string | null;
|
|
327
|
+
requestedAt: string;
|
|
328
|
+
processedAt: string | null;
|
|
329
|
+
processedByUserId: string | null;
|
|
330
|
+
}
|
|
331
|
+
interface JoinRequestListResponse {
|
|
332
|
+
items: JoinRequestOut[];
|
|
333
|
+
total: number;
|
|
334
|
+
limit: number;
|
|
335
|
+
offset: number;
|
|
336
|
+
}
|
|
337
|
+
/** Synchronous response after `POST /join-request`. `status="joined"` — OPEN room, user was immediately added. `status="pending"` — APPROVAL_REQUIRED, request is pending. `status="already_member"` — caller is already an active member; no-op. */
|
|
338
|
+
interface JoinRequestCreateResponse {
|
|
339
|
+
status: "joined" | "pending" | "already_member";
|
|
340
|
+
roomId: string;
|
|
341
|
+
}
|
|
323
342
|
/** Minimal sender identity — no friend/block/profile-url fluff. */
|
|
324
343
|
interface SenderMini {
|
|
325
344
|
userId: string;
|
|
@@ -875,6 +894,37 @@ declare class Room {
|
|
|
875
894
|
/** OPERATOR-only: revoke a token immediately. Idempotent — revoking
|
|
876
895
|
* an already-revoked token returns 204 as well. */
|
|
877
896
|
revokeInvite(token: string): Promise<void>;
|
|
897
|
+
/**
|
|
898
|
+
* Ask to join this room (self). Behavior depends on the room's
|
|
899
|
+
* `joinPolicy`:
|
|
900
|
+
* - `OPEN` → the caller is added immediately (`status: "joined"`);
|
|
901
|
+
* - `APPROVAL_REQUIRED` → the request lands in the operators' inbox
|
|
902
|
+
* (`status: "pending"`) until [`approveJoinRequest`] / reject.
|
|
903
|
+
* Idempotent for members (`status: "already_member"`).
|
|
904
|
+
*
|
|
905
|
+
* @param reason Optional note shown to operators ("하은이 반 친구 엄마예요").
|
|
906
|
+
*/
|
|
907
|
+
requestJoin(reason?: string): Promise<JoinRequestCreateResponse>;
|
|
908
|
+
/** Cancel the caller's own pending join request. */
|
|
909
|
+
cancelJoinRequest(): Promise<void>;
|
|
910
|
+
/** OPERATOR-only: list join requests for this room (the approval inbox).
|
|
911
|
+
* Defaults to pending only — pass a status to see processed history. */
|
|
912
|
+
listJoinRequests(opts?: {
|
|
913
|
+
status?: "PENDING" | "APPROVED" | "REJECTED" | "CANCELLED";
|
|
914
|
+
limit?: number;
|
|
915
|
+
offset?: number;
|
|
916
|
+
}): Promise<JoinRequestListResponse>;
|
|
917
|
+
/** OPERATOR-only: approve a pending join request — the requester becomes
|
|
918
|
+
* a MEMBER. [reason] is echoed back to them in later list calls. */
|
|
919
|
+
approveJoinRequest(userId: string, reason?: string): Promise<void>;
|
|
920
|
+
/** OPERATOR-only: reject a pending join request. */
|
|
921
|
+
rejectJoinRequest(userId: string, reason?: string): Promise<void>;
|
|
922
|
+
/** Hide this room from the caller's own room list (self, reversible —
|
|
923
|
+
* the KakaoTalk "숨기기"). The room typically reappears via [unhide]
|
|
924
|
+
* or on new activity, per server policy. Messages are untouched. */
|
|
925
|
+
hide(): Promise<void>;
|
|
926
|
+
/** Undo [hide] — the room shows up in the caller's list again. */
|
|
927
|
+
unhide(): Promise<void>;
|
|
878
928
|
on<K extends keyof RoomEvents>(event: K, fn: (p: RoomEvents[K]) => void): () => void;
|
|
879
929
|
off<K extends keyof RoomEvents>(event: K, fn: (p: RoomEvents[K]) => void): void;
|
|
880
930
|
_dispatchAnnouncement(msg: WsAnnouncementEvent): void;
|
|
@@ -1141,4 +1191,4 @@ declare class NoveraChatError extends Error {
|
|
|
1141
1191
|
static fromResponse(status: number, body: unknown): NoveraChatError;
|
|
1142
1192
|
}
|
|
1143
1193
|
|
|
1144
|
-
export { type InviteAcceptResponse as AcceptInviteResult, type AnnouncementOut as Announcement, type AppPolicy, type BlockOut as Block, type ClientOptions, type DeleteScope, ErrorCode, type ErrorCodeValue, type InviteTokenOut as InviteToken, type MessageOut, type MessageType, NoveraChat, NoveraChatError, type ReactionEntry, Room, type RoomEvents, type RoomMemberOut, type RoomUnread, type SendParams, type SenderMini, type UnreadRoomItem, type UnreadSummary, type WsAnnouncementEvent, type WsInbound, type WsOutbound };
|
|
1194
|
+
export { type InviteAcceptResponse as AcceptInviteResult, type AnnouncementOut as Announcement, type AppPolicy, type BlockOut as Block, type ClientOptions, type DeleteScope, ErrorCode, type ErrorCodeValue, type InviteTokenOut as InviteToken, type JoinRequestCreateResponse, type JoinRequestListResponse, type JoinRequestOut, type MessageOut, type MessageType, NoveraChat, NoveraChatError, type ReactionEntry, Room, type RoomEvents, type RoomMemberOut, type RoomUnread, type SendParams, type SenderMini, type UnreadRoomItem, type UnreadSummary, type WsAnnouncementEvent, type WsInbound, type WsOutbound };
|
package/dist/index.d.ts
CHANGED
|
@@ -320,6 +320,25 @@ interface RoomMemberOut {
|
|
|
320
320
|
isOnline?: boolean | null;
|
|
321
321
|
mutedUntil?: string | null;
|
|
322
322
|
}
|
|
323
|
+
interface JoinRequestOut {
|
|
324
|
+
userId: string;
|
|
325
|
+
status: "PENDING" | "APPROVED" | "REJECTED" | "CANCELLED";
|
|
326
|
+
reason: string | null;
|
|
327
|
+
requestedAt: string;
|
|
328
|
+
processedAt: string | null;
|
|
329
|
+
processedByUserId: string | null;
|
|
330
|
+
}
|
|
331
|
+
interface JoinRequestListResponse {
|
|
332
|
+
items: JoinRequestOut[];
|
|
333
|
+
total: number;
|
|
334
|
+
limit: number;
|
|
335
|
+
offset: number;
|
|
336
|
+
}
|
|
337
|
+
/** Synchronous response after `POST /join-request`. `status="joined"` — OPEN room, user was immediately added. `status="pending"` — APPROVAL_REQUIRED, request is pending. `status="already_member"` — caller is already an active member; no-op. */
|
|
338
|
+
interface JoinRequestCreateResponse {
|
|
339
|
+
status: "joined" | "pending" | "already_member";
|
|
340
|
+
roomId: string;
|
|
341
|
+
}
|
|
323
342
|
/** Minimal sender identity — no friend/block/profile-url fluff. */
|
|
324
343
|
interface SenderMini {
|
|
325
344
|
userId: string;
|
|
@@ -875,6 +894,37 @@ declare class Room {
|
|
|
875
894
|
/** OPERATOR-only: revoke a token immediately. Idempotent — revoking
|
|
876
895
|
* an already-revoked token returns 204 as well. */
|
|
877
896
|
revokeInvite(token: string): Promise<void>;
|
|
897
|
+
/**
|
|
898
|
+
* Ask to join this room (self). Behavior depends on the room's
|
|
899
|
+
* `joinPolicy`:
|
|
900
|
+
* - `OPEN` → the caller is added immediately (`status: "joined"`);
|
|
901
|
+
* - `APPROVAL_REQUIRED` → the request lands in the operators' inbox
|
|
902
|
+
* (`status: "pending"`) until [`approveJoinRequest`] / reject.
|
|
903
|
+
* Idempotent for members (`status: "already_member"`).
|
|
904
|
+
*
|
|
905
|
+
* @param reason Optional note shown to operators ("하은이 반 친구 엄마예요").
|
|
906
|
+
*/
|
|
907
|
+
requestJoin(reason?: string): Promise<JoinRequestCreateResponse>;
|
|
908
|
+
/** Cancel the caller's own pending join request. */
|
|
909
|
+
cancelJoinRequest(): Promise<void>;
|
|
910
|
+
/** OPERATOR-only: list join requests for this room (the approval inbox).
|
|
911
|
+
* Defaults to pending only — pass a status to see processed history. */
|
|
912
|
+
listJoinRequests(opts?: {
|
|
913
|
+
status?: "PENDING" | "APPROVED" | "REJECTED" | "CANCELLED";
|
|
914
|
+
limit?: number;
|
|
915
|
+
offset?: number;
|
|
916
|
+
}): Promise<JoinRequestListResponse>;
|
|
917
|
+
/** OPERATOR-only: approve a pending join request — the requester becomes
|
|
918
|
+
* a MEMBER. [reason] is echoed back to them in later list calls. */
|
|
919
|
+
approveJoinRequest(userId: string, reason?: string): Promise<void>;
|
|
920
|
+
/** OPERATOR-only: reject a pending join request. */
|
|
921
|
+
rejectJoinRequest(userId: string, reason?: string): Promise<void>;
|
|
922
|
+
/** Hide this room from the caller's own room list (self, reversible —
|
|
923
|
+
* the KakaoTalk "숨기기"). The room typically reappears via [unhide]
|
|
924
|
+
* or on new activity, per server policy. Messages are untouched. */
|
|
925
|
+
hide(): Promise<void>;
|
|
926
|
+
/** Undo [hide] — the room shows up in the caller's list again. */
|
|
927
|
+
unhide(): Promise<void>;
|
|
878
928
|
on<K extends keyof RoomEvents>(event: K, fn: (p: RoomEvents[K]) => void): () => void;
|
|
879
929
|
off<K extends keyof RoomEvents>(event: K, fn: (p: RoomEvents[K]) => void): void;
|
|
880
930
|
_dispatchAnnouncement(msg: WsAnnouncementEvent): void;
|
|
@@ -1141,4 +1191,4 @@ declare class NoveraChatError extends Error {
|
|
|
1141
1191
|
static fromResponse(status: number, body: unknown): NoveraChatError;
|
|
1142
1192
|
}
|
|
1143
1193
|
|
|
1144
|
-
export { type InviteAcceptResponse as AcceptInviteResult, type AnnouncementOut as Announcement, type AppPolicy, type BlockOut as Block, type ClientOptions, type DeleteScope, ErrorCode, type ErrorCodeValue, type InviteTokenOut as InviteToken, type MessageOut, type MessageType, NoveraChat, NoveraChatError, type ReactionEntry, Room, type RoomEvents, type RoomMemberOut, type RoomUnread, type SendParams, type SenderMini, type UnreadRoomItem, type UnreadSummary, type WsAnnouncementEvent, type WsInbound, type WsOutbound };
|
|
1194
|
+
export { type InviteAcceptResponse as AcceptInviteResult, type AnnouncementOut as Announcement, type AppPolicy, type BlockOut as Block, type ClientOptions, type DeleteScope, ErrorCode, type ErrorCodeValue, type InviteTokenOut as InviteToken, type JoinRequestCreateResponse, type JoinRequestListResponse, type JoinRequestOut, type MessageOut, type MessageType, NoveraChat, NoveraChatError, type ReactionEntry, Room, type RoomEvents, type RoomMemberOut, type RoomUnread, type SendParams, type SenderMini, type UnreadRoomItem, type UnreadSummary, type WsAnnouncementEvent, type WsInbound, type WsOutbound };
|
package/dist/index.js
CHANGED
|
@@ -177,6 +177,30 @@ function parseBulkDeleteBySenderResult(j) {
|
|
|
177
177
|
cleared: j["cleared"]
|
|
178
178
|
};
|
|
179
179
|
}
|
|
180
|
+
function parseJoinRequestOut(j) {
|
|
181
|
+
return {
|
|
182
|
+
userId: j["user_id"],
|
|
183
|
+
status: j["status"],
|
|
184
|
+
reason: j["reason"],
|
|
185
|
+
requestedAt: j["requested_at"],
|
|
186
|
+
processedAt: j["processed_at"],
|
|
187
|
+
processedByUserId: j["processed_by_user_id"]
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
function parseJoinRequestListResponse(j) {
|
|
191
|
+
return {
|
|
192
|
+
items: j["items"].map((e) => parseJoinRequestOut(e)),
|
|
193
|
+
total: j["total"],
|
|
194
|
+
limit: j["limit"],
|
|
195
|
+
offset: j["offset"]
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
function parseJoinRequestCreateResponse(j) {
|
|
199
|
+
return {
|
|
200
|
+
status: j["status"],
|
|
201
|
+
roomId: j["room_id"]
|
|
202
|
+
};
|
|
203
|
+
}
|
|
180
204
|
function parseSenderMini(j) {
|
|
181
205
|
return {
|
|
182
206
|
userId: j["user_id"],
|
|
@@ -1217,6 +1241,81 @@ var Room = class _Room {
|
|
|
1217
1241
|
`/api/v1/rooms/${this.roomId}/invites/${encodeURIComponent(token)}`
|
|
1218
1242
|
);
|
|
1219
1243
|
}
|
|
1244
|
+
// -------- join requests --------
|
|
1245
|
+
/**
|
|
1246
|
+
* Ask to join this room (self). Behavior depends on the room's
|
|
1247
|
+
* `joinPolicy`:
|
|
1248
|
+
* - `OPEN` → the caller is added immediately (`status: "joined"`);
|
|
1249
|
+
* - `APPROVAL_REQUIRED` → the request lands in the operators' inbox
|
|
1250
|
+
* (`status: "pending"`) until [`approveJoinRequest`] / reject.
|
|
1251
|
+
* Idempotent for members (`status: "already_member"`).
|
|
1252
|
+
*
|
|
1253
|
+
* @param reason Optional note shown to operators ("하은이 반 친구 엄마예요").
|
|
1254
|
+
*/
|
|
1255
|
+
async requestJoin(reason) {
|
|
1256
|
+
const raw = await this.http.request(
|
|
1257
|
+
"POST",
|
|
1258
|
+
`/api/v1/rooms/${this.roomId}/join-request`,
|
|
1259
|
+
reason ? { reason } : {}
|
|
1260
|
+
);
|
|
1261
|
+
return parseJoinRequestCreateResponse(raw);
|
|
1262
|
+
}
|
|
1263
|
+
/** Cancel the caller's own pending join request. */
|
|
1264
|
+
async cancelJoinRequest() {
|
|
1265
|
+
await this.http.request(
|
|
1266
|
+
"DELETE",
|
|
1267
|
+
`/api/v1/rooms/${this.roomId}/join-request`
|
|
1268
|
+
);
|
|
1269
|
+
}
|
|
1270
|
+
/** OPERATOR-only: list join requests for this room (the approval inbox).
|
|
1271
|
+
* Defaults to pending only — pass a status to see processed history. */
|
|
1272
|
+
async listJoinRequests(opts) {
|
|
1273
|
+
const raw = await this.http.request(
|
|
1274
|
+
"GET",
|
|
1275
|
+
`/api/v1/rooms/${this.roomId}/join-requests`,
|
|
1276
|
+
void 0,
|
|
1277
|
+
{
|
|
1278
|
+
...opts?.status ? { status: opts.status } : {},
|
|
1279
|
+
...opts?.limit !== void 0 ? { limit: opts.limit } : {},
|
|
1280
|
+
...opts?.offset !== void 0 ? { offset: opts.offset } : {}
|
|
1281
|
+
}
|
|
1282
|
+
);
|
|
1283
|
+
return parseJoinRequestListResponse(raw);
|
|
1284
|
+
}
|
|
1285
|
+
/** OPERATOR-only: approve a pending join request — the requester becomes
|
|
1286
|
+
* a MEMBER. [reason] is echoed back to them in later list calls. */
|
|
1287
|
+
async approveJoinRequest(userId, reason) {
|
|
1288
|
+
await this.http.request(
|
|
1289
|
+
"POST",
|
|
1290
|
+
`/api/v1/rooms/${this.roomId}/join-requests/${encodeURIComponent(userId)}/approve`,
|
|
1291
|
+
reason ? { reason } : {}
|
|
1292
|
+
);
|
|
1293
|
+
}
|
|
1294
|
+
/** OPERATOR-only: reject a pending join request. */
|
|
1295
|
+
async rejectJoinRequest(userId, reason) {
|
|
1296
|
+
await this.http.request(
|
|
1297
|
+
"POST",
|
|
1298
|
+
`/api/v1/rooms/${this.roomId}/join-requests/${encodeURIComponent(userId)}/reject`,
|
|
1299
|
+
reason ? { reason } : {}
|
|
1300
|
+
);
|
|
1301
|
+
}
|
|
1302
|
+
// -------- hide / unhide --------
|
|
1303
|
+
/** Hide this room from the caller's own room list (self, reversible —
|
|
1304
|
+
* the KakaoTalk "숨기기"). The room typically reappears via [unhide]
|
|
1305
|
+
* or on new activity, per server policy. Messages are untouched. */
|
|
1306
|
+
async hide() {
|
|
1307
|
+
await this.http.request(
|
|
1308
|
+
"POST",
|
|
1309
|
+
`/api/v1/rooms/${this.roomId}/hide`
|
|
1310
|
+
);
|
|
1311
|
+
}
|
|
1312
|
+
/** Undo [hide] — the room shows up in the caller's list again. */
|
|
1313
|
+
async unhide() {
|
|
1314
|
+
await this.http.request(
|
|
1315
|
+
"POST",
|
|
1316
|
+
`/api/v1/rooms/${this.roomId}/unhide`
|
|
1317
|
+
);
|
|
1318
|
+
}
|
|
1220
1319
|
// -------- internal dispatch --------
|
|
1221
1320
|
on(event, fn) {
|
|
1222
1321
|
return this.bus.on(event, fn);
|
package/package.json
CHANGED
package/src/features/room.ts
CHANGED
|
@@ -42,10 +42,16 @@ import {
|
|
|
42
42
|
parseFileCreateResponse,
|
|
43
43
|
parseFileOut,
|
|
44
44
|
parseInviteTokenOut,
|
|
45
|
+
parseJoinRequestCreateResponse,
|
|
46
|
+
parseJoinRequestListResponse,
|
|
45
47
|
parseMessageOut,
|
|
46
48
|
parseRoomMemberOut,
|
|
47
49
|
parseRoomUnread,
|
|
48
50
|
} from "../generated/rest.js";
|
|
51
|
+
import type {
|
|
52
|
+
JoinRequestCreateResponse,
|
|
53
|
+
JoinRequestListResponse,
|
|
54
|
+
} from "../generated/rest.js";
|
|
49
55
|
// Note: previously used `utils/debounce`, replaced with a hand-rolled
|
|
50
56
|
// timer in Room so we can also expose `flushMarkRead()` — the util has
|
|
51
57
|
// no flush primitive.
|
|
@@ -1010,6 +1016,87 @@ export class Room {
|
|
|
1010
1016
|
);
|
|
1011
1017
|
}
|
|
1012
1018
|
|
|
1019
|
+
// -------- join requests --------
|
|
1020
|
+
|
|
1021
|
+
/**
|
|
1022
|
+
* Ask to join this room (self). Behavior depends on the room's
|
|
1023
|
+
* `joinPolicy`:
|
|
1024
|
+
* - `OPEN` → the caller is added immediately (`status: "joined"`);
|
|
1025
|
+
* - `APPROVAL_REQUIRED` → the request lands in the operators' inbox
|
|
1026
|
+
* (`status: "pending"`) until [`approveJoinRequest`] / reject.
|
|
1027
|
+
* Idempotent for members (`status: "already_member"`).
|
|
1028
|
+
*
|
|
1029
|
+
* @param reason Optional note shown to operators ("하은이 반 친구 엄마예요").
|
|
1030
|
+
*/
|
|
1031
|
+
async requestJoin(reason?: string): Promise<JoinRequestCreateResponse> {
|
|
1032
|
+
const raw = await this.http.request<unknown>(
|
|
1033
|
+
"POST", `/api/v1/rooms/${this.roomId}/join-request`,
|
|
1034
|
+
reason ? { reason } : {},
|
|
1035
|
+
);
|
|
1036
|
+
return parseJoinRequestCreateResponse(raw);
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
/** Cancel the caller's own pending join request. */
|
|
1040
|
+
async cancelJoinRequest(): Promise<void> {
|
|
1041
|
+
await this.http.request<void>(
|
|
1042
|
+
"DELETE", `/api/v1/rooms/${this.roomId}/join-request`,
|
|
1043
|
+
);
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
/** OPERATOR-only: list join requests for this room (the approval inbox).
|
|
1047
|
+
* Defaults to pending only — pass a status to see processed history. */
|
|
1048
|
+
async listJoinRequests(opts?: {
|
|
1049
|
+
status?: "PENDING" | "APPROVED" | "REJECTED" | "CANCELLED";
|
|
1050
|
+
limit?: number;
|
|
1051
|
+
offset?: number;
|
|
1052
|
+
}): Promise<JoinRequestListResponse> {
|
|
1053
|
+
const raw = await this.http.request<unknown>(
|
|
1054
|
+
"GET", `/api/v1/rooms/${this.roomId}/join-requests`, undefined, {
|
|
1055
|
+
...(opts?.status ? { status: opts.status } : {}),
|
|
1056
|
+
...(opts?.limit !== undefined ? { limit: opts.limit } : {}),
|
|
1057
|
+
...(opts?.offset !== undefined ? { offset: opts.offset } : {}),
|
|
1058
|
+
},
|
|
1059
|
+
);
|
|
1060
|
+
return parseJoinRequestListResponse(raw);
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
/** OPERATOR-only: approve a pending join request — the requester becomes
|
|
1064
|
+
* a MEMBER. [reason] is echoed back to them in later list calls. */
|
|
1065
|
+
async approveJoinRequest(userId: string, reason?: string): Promise<void> {
|
|
1066
|
+
await this.http.request<void>(
|
|
1067
|
+
"POST",
|
|
1068
|
+
`/api/v1/rooms/${this.roomId}/join-requests/${encodeURIComponent(userId)}/approve`,
|
|
1069
|
+
reason ? { reason } : {},
|
|
1070
|
+
);
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
/** OPERATOR-only: reject a pending join request. */
|
|
1074
|
+
async rejectJoinRequest(userId: string, reason?: string): Promise<void> {
|
|
1075
|
+
await this.http.request<void>(
|
|
1076
|
+
"POST",
|
|
1077
|
+
`/api/v1/rooms/${this.roomId}/join-requests/${encodeURIComponent(userId)}/reject`,
|
|
1078
|
+
reason ? { reason } : {},
|
|
1079
|
+
);
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
// -------- hide / unhide --------
|
|
1083
|
+
|
|
1084
|
+
/** Hide this room from the caller's own room list (self, reversible —
|
|
1085
|
+
* the KakaoTalk "숨기기"). The room typically reappears via [unhide]
|
|
1086
|
+
* or on new activity, per server policy. Messages are untouched. */
|
|
1087
|
+
async hide(): Promise<void> {
|
|
1088
|
+
await this.http.request<void>(
|
|
1089
|
+
"POST", `/api/v1/rooms/${this.roomId}/hide`,
|
|
1090
|
+
);
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
/** Undo [hide] — the room shows up in the caller's list again. */
|
|
1094
|
+
async unhide(): Promise<void> {
|
|
1095
|
+
await this.http.request<void>(
|
|
1096
|
+
"POST", `/api/v1/rooms/${this.roomId}/unhide`,
|
|
1097
|
+
);
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1013
1100
|
// -------- internal dispatch --------
|
|
1014
1101
|
|
|
1015
1102
|
on<K extends keyof RoomEvents>(event: K, fn: (p: RoomEvents[K]) => void): () => void {
|
package/src/generated/rest.ts
CHANGED
|
@@ -440,6 +440,55 @@ export function parseBulkDeleteBySenderResult(j: any): BulkDeleteBySenderResult
|
|
|
440
440
|
} as BulkDeleteBySenderResult;
|
|
441
441
|
}
|
|
442
442
|
|
|
443
|
+
export interface JoinRequestOut {
|
|
444
|
+
userId: string;
|
|
445
|
+
status: "PENDING" | "APPROVED" | "REJECTED" | "CANCELLED";
|
|
446
|
+
reason: string | null;
|
|
447
|
+
requestedAt: string;
|
|
448
|
+
processedAt: string | null;
|
|
449
|
+
processedByUserId: string | null;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
export function parseJoinRequestOut(j: any): JoinRequestOut {
|
|
453
|
+
return {
|
|
454
|
+
userId: j["user_id"],
|
|
455
|
+
status: j["status"],
|
|
456
|
+
reason: j["reason"],
|
|
457
|
+
requestedAt: j["requested_at"],
|
|
458
|
+
processedAt: j["processed_at"],
|
|
459
|
+
processedByUserId: j["processed_by_user_id"],
|
|
460
|
+
} as JoinRequestOut;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
export interface JoinRequestListResponse {
|
|
464
|
+
items: JoinRequestOut[];
|
|
465
|
+
total: number;
|
|
466
|
+
limit: number;
|
|
467
|
+
offset: number;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
export function parseJoinRequestListResponse(j: any): JoinRequestListResponse {
|
|
471
|
+
return {
|
|
472
|
+
items: (j["items"] as unknown[]).map((e: any) => parseJoinRequestOut(e)),
|
|
473
|
+
total: j["total"],
|
|
474
|
+
limit: j["limit"],
|
|
475
|
+
offset: j["offset"],
|
|
476
|
+
} as JoinRequestListResponse;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/** Synchronous response after `POST /join-request`. `status="joined"` — OPEN room, user was immediately added. `status="pending"` — APPROVAL_REQUIRED, request is pending. `status="already_member"` — caller is already an active member; no-op. */
|
|
480
|
+
export interface JoinRequestCreateResponse {
|
|
481
|
+
status: "joined" | "pending" | "already_member";
|
|
482
|
+
roomId: string;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
export function parseJoinRequestCreateResponse(j: any): JoinRequestCreateResponse {
|
|
486
|
+
return {
|
|
487
|
+
status: j["status"],
|
|
488
|
+
roomId: j["room_id"],
|
|
489
|
+
} as JoinRequestCreateResponse;
|
|
490
|
+
}
|
|
491
|
+
|
|
443
492
|
/** Minimal sender identity — no friend/block/profile-url fluff. */
|
|
444
493
|
export interface SenderMini {
|
|
445
494
|
userId: string;
|
package/src/index.ts
CHANGED
package/src/types.ts
CHANGED