@noverachat/sdk-web 0.0.3 → 0.1.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.ko.md +8 -8
- package/README.md +8 -8
- package/dist/index.cjs +386 -258
- package/dist/index.d.cts +163 -170
- package/dist/index.d.ts +163 -170
- package/dist/index.js +386 -258
- package/package.json +1 -1
- package/src/client.ts +50 -157
- package/src/features/room.ts +187 -344
- package/src/generated/rest.ts +480 -0
- package/src/index.ts +1 -0
- package/src/types.ts +59 -177
package/dist/index.cjs
CHANGED
|
@@ -27,6 +27,200 @@ __export(index_exports, {
|
|
|
27
27
|
});
|
|
28
28
|
module.exports = __toCommonJS(index_exports);
|
|
29
29
|
|
|
30
|
+
// src/generated/rest.ts
|
|
31
|
+
function parseAppPolicy(j) {
|
|
32
|
+
return {
|
|
33
|
+
appId: j["app_id"],
|
|
34
|
+
allowMemberBulkDelete: j["allow_member_bulk_delete"],
|
|
35
|
+
readReceiptsEnabled: j["read_receipts_enabled"],
|
|
36
|
+
typingIndicatorsEnabled: j["typing_indicators_enabled"],
|
|
37
|
+
allowMemberDeleteAnyMessage: j["allow_member_delete_any_message"]
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function parseUnreadSummary(j) {
|
|
41
|
+
return {
|
|
42
|
+
total: j["total"],
|
|
43
|
+
rooms: j["rooms"].map((e) => parseUnreadRoomItem(e))
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function parseUnreadRoomItem(j) {
|
|
47
|
+
return {
|
|
48
|
+
roomId: j["room_id"],
|
|
49
|
+
name: j["name"],
|
|
50
|
+
roomType: j["room_type"],
|
|
51
|
+
unreadCount: j["unread_count"],
|
|
52
|
+
lastMessageId: j["last_message_id"],
|
|
53
|
+
lastReadMessageId: j["last_read_message_id"],
|
|
54
|
+
lastMessagePreview: j["last_message_preview"],
|
|
55
|
+
memberCount: j["member_count"],
|
|
56
|
+
membersPreview: j["members_preview"] == null ? void 0 : j["members_preview"].map((e) => parseMemberPreview(e))
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function parseMemberPreview(j) {
|
|
60
|
+
return {
|
|
61
|
+
userId: j["user_id"],
|
|
62
|
+
nickname: j["nickname"],
|
|
63
|
+
profileImageUrl: j["profile_image_url"],
|
|
64
|
+
isOnline: j["is_online"]
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function parseRoomUnread(j) {
|
|
68
|
+
return {
|
|
69
|
+
roomId: j["room_id"],
|
|
70
|
+
unreadCount: j["unread_count"],
|
|
71
|
+
lastReadMessageId: j["last_read_message_id"],
|
|
72
|
+
lastMessageId: j["last_message_id"]
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function parseMessageOut(j) {
|
|
76
|
+
return {
|
|
77
|
+
appId: j["app_id"],
|
|
78
|
+
roomId: j["room_id"],
|
|
79
|
+
messageId: j["message_id"],
|
|
80
|
+
sender: j["sender"] == null ? null : parseSenderMini(j["sender"]),
|
|
81
|
+
senderId: j["sender_id"],
|
|
82
|
+
messageType: j["message_type"],
|
|
83
|
+
customType: j["custom_type"],
|
|
84
|
+
content: j["content"],
|
|
85
|
+
data: j["data"],
|
|
86
|
+
meta: j["meta"],
|
|
87
|
+
fileId: j["file_id"],
|
|
88
|
+
file: j["file"],
|
|
89
|
+
files: j["files"],
|
|
90
|
+
replyToId: j["reply_to_id"],
|
|
91
|
+
reactions: j["reactions"] == null ? void 0 : j["reactions"].map((e) => parseReactionEntry(e)),
|
|
92
|
+
createdAt: j["created_at"],
|
|
93
|
+
updatedAt: j["updated_at"],
|
|
94
|
+
deletedAt: j["deleted_at"],
|
|
95
|
+
deletedByUserId: j["deleted_by_user_id"],
|
|
96
|
+
deleteScope: j["delete_scope"],
|
|
97
|
+
editedCount: j["edited_count"],
|
|
98
|
+
createdAtMs: j["created_at_ms"],
|
|
99
|
+
updatedAtMs: j["updated_at_ms"]
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function parseAnnouncementOut(j) {
|
|
103
|
+
return {
|
|
104
|
+
id: j["id"],
|
|
105
|
+
roomId: j["room_id"],
|
|
106
|
+
content: j["content"],
|
|
107
|
+
createdBy: j["created_by"],
|
|
108
|
+
createdAt: j["created_at"],
|
|
109
|
+
updatedAt: j["updated_at"]
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function parseInviteTokenOut(j) {
|
|
113
|
+
return {
|
|
114
|
+
token: j["token"],
|
|
115
|
+
roomId: j["room_id"],
|
|
116
|
+
createdBy: j["created_by"],
|
|
117
|
+
createdAt: j["created_at"],
|
|
118
|
+
expiresAt: j["expires_at"],
|
|
119
|
+
maxUses: j["max_uses"],
|
|
120
|
+
usedCount: j["used_count"],
|
|
121
|
+
revokedAt: j["revoked_at"]
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function parseInviteAcceptResponse(j) {
|
|
125
|
+
return {
|
|
126
|
+
roomId: j["room_id"],
|
|
127
|
+
roomName: j["room_name"],
|
|
128
|
+
wasAlreadyMember: j["was_already_member"]
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function parseDeviceOut(j) {
|
|
132
|
+
return {
|
|
133
|
+
deviceId: j["device_id"],
|
|
134
|
+
tokenType: j["token_type"],
|
|
135
|
+
tokenPreview: j["token_preview"],
|
|
136
|
+
os: j["os"],
|
|
137
|
+
appVersion: j["app_version"],
|
|
138
|
+
pushEnabled: j["push_enabled"],
|
|
139
|
+
lastActiveAt: j["last_active_at"],
|
|
140
|
+
createdAt: j["created_at"]
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
function parseDeviceListResponse(j) {
|
|
144
|
+
return {
|
|
145
|
+
items: j["items"].map((e) => parseDeviceOut(e)),
|
|
146
|
+
total: j["total"]
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
function parsePushPreferencesOut(j) {
|
|
150
|
+
return {
|
|
151
|
+
pushEnabled: j["push_enabled"]
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function parseFileOut(j) {
|
|
155
|
+
return {
|
|
156
|
+
id: j["id"],
|
|
157
|
+
kind: j["kind"],
|
|
158
|
+
mime: j["mime"],
|
|
159
|
+
sizeBytes: j["size_bytes"],
|
|
160
|
+
originalName: j["original_name"],
|
|
161
|
+
width: j["width"],
|
|
162
|
+
height: j["height"],
|
|
163
|
+
durationSec: j["duration_sec"],
|
|
164
|
+
thumbnailStatus: j["thumbnail_status"],
|
|
165
|
+
uploadStatus: j["upload_status"],
|
|
166
|
+
createdAt: j["created_at"],
|
|
167
|
+
committedAt: j["committed_at"],
|
|
168
|
+
forwardBlocked: j["forward_blocked"]
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
function parseFileCreateResponse(j) {
|
|
172
|
+
return {
|
|
173
|
+
fileId: j["file_id"],
|
|
174
|
+
uploadUrl: j["upload_url"],
|
|
175
|
+
headers: j["headers"],
|
|
176
|
+
expiresAtMs: j["expires_at_ms"]
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
function parseBlockOut(j) {
|
|
180
|
+
return {
|
|
181
|
+
blockedUserId: j["blocked_user_id"],
|
|
182
|
+
reason: j["reason"],
|
|
183
|
+
createdAt: j["created_at"]
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
function parseRoomMemberOut(j) {
|
|
187
|
+
return {
|
|
188
|
+
userId: j["user_id"],
|
|
189
|
+
nickname: j["nickname"],
|
|
190
|
+
role: j["role"],
|
|
191
|
+
pushTrigger: j["push_trigger"],
|
|
192
|
+
lastReadMessageId: j["last_read_message_id"],
|
|
193
|
+
joinedAt: j["joined_at"],
|
|
194
|
+
isOnline: j["is_online"],
|
|
195
|
+
mutedUntil: j["muted_until"]
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
function parseBulkDeleteResult(j) {
|
|
199
|
+
return {
|
|
200
|
+
cleared: j["cleared"],
|
|
201
|
+
upToMessageId: j["up_to_message_id"]
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
function parseBulkDeleteBySenderResult(j) {
|
|
205
|
+
return {
|
|
206
|
+
cleared: j["cleared"]
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
function parseSenderMini(j) {
|
|
210
|
+
return {
|
|
211
|
+
userId: j["user_id"],
|
|
212
|
+
nickname: j["nickname"],
|
|
213
|
+
profileImageUrl: j["profile_image_url"]
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
function parseReactionEntry(j) {
|
|
217
|
+
return {
|
|
218
|
+
key: j["key"],
|
|
219
|
+
userIds: j["user_ids"],
|
|
220
|
+
updatedAt: j["updated_at"]
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
30
224
|
// src/errors.ts
|
|
31
225
|
var ErrorCode = {
|
|
32
226
|
INTERNAL: "NC-GEN-001",
|
|
@@ -322,64 +516,31 @@ function tempId() {
|
|
|
322
516
|
}
|
|
323
517
|
|
|
324
518
|
// src/features/room.ts
|
|
325
|
-
function
|
|
326
|
-
|
|
519
|
+
function toFileInline(f) {
|
|
520
|
+
return {
|
|
521
|
+
id: f.id,
|
|
522
|
+
kind: f.kind,
|
|
523
|
+
mime: f.mime,
|
|
524
|
+
size: f.size,
|
|
525
|
+
name: f.name ?? null,
|
|
526
|
+
width: f.width ?? null,
|
|
527
|
+
height: f.height ?? null,
|
|
528
|
+
durationSec: f.duration_sec ?? null,
|
|
529
|
+
thumbnailStatus: f.thumbnail_status,
|
|
530
|
+
forwardBlocked: Boolean(f.forward_blocked)
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
function toMessageOut(j) {
|
|
534
|
+
const base = parseMessageOut(j);
|
|
535
|
+
const raw = j;
|
|
536
|
+
const dataObj = base.data ?? null;
|
|
327
537
|
const customMeta = dataObj && typeof dataObj === "object" && "_customMeta" in dataObj ? dataObj._customMeta : null;
|
|
328
538
|
return {
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
nickname: r.sender.nickname ?? null,
|
|
335
|
-
profileImageUrl: r.sender.profile_image_url ?? null
|
|
336
|
-
} : null,
|
|
337
|
-
senderId: r.sender_id ?? null,
|
|
338
|
-
messageType: r.message_type,
|
|
339
|
-
customType: r.custom_type ?? null,
|
|
340
|
-
content: r.content ?? null,
|
|
341
|
-
data: dataObj,
|
|
342
|
-
meta: r.meta ?? null,
|
|
343
|
-
customMeta,
|
|
344
|
-
fileId: r.file_id ?? null,
|
|
345
|
-
file: r.file ? {
|
|
346
|
-
id: r.file.id,
|
|
347
|
-
kind: r.file.kind,
|
|
348
|
-
mime: r.file.mime,
|
|
349
|
-
size: r.file.size,
|
|
350
|
-
name: r.file.name ?? null,
|
|
351
|
-
width: r.file.width ?? null,
|
|
352
|
-
height: r.file.height ?? null,
|
|
353
|
-
durationSec: r.file.duration_sec ?? null,
|
|
354
|
-
thumbnailStatus: r.file.thumbnail_status,
|
|
355
|
-
forwardBlocked: Boolean(r.file.forward_blocked)
|
|
356
|
-
} : null,
|
|
357
|
-
files: r.files && r.files.length > 0 ? r.files.map((f) => ({
|
|
358
|
-
id: f.id,
|
|
359
|
-
kind: f.kind,
|
|
360
|
-
mime: f.mime,
|
|
361
|
-
size: f.size,
|
|
362
|
-
name: f.name ?? null,
|
|
363
|
-
width: f.width ?? null,
|
|
364
|
-
height: f.height ?? null,
|
|
365
|
-
durationSec: f.duration_sec ?? null,
|
|
366
|
-
thumbnailStatus: f.thumbnail_status,
|
|
367
|
-
forwardBlocked: Boolean(f.forward_blocked)
|
|
368
|
-
})) : null,
|
|
369
|
-
replyToId: r.reply_to_id ?? null,
|
|
370
|
-
reactions: (r.reactions ?? []).map((x) => ({
|
|
371
|
-
key: x.key,
|
|
372
|
-
userIds: x.user_ids,
|
|
373
|
-
updatedAt: x.updated_at
|
|
374
|
-
})),
|
|
375
|
-
createdAt: r.created_at,
|
|
376
|
-
createdAtMs: r.created_at_ms,
|
|
377
|
-
updatedAt: r.updated_at ?? null,
|
|
378
|
-
updatedAtMs: r.updated_at_ms ?? null,
|
|
379
|
-
deletedAt: r.deleted_at ?? null,
|
|
380
|
-
deletedByUserId: r.deleted_by_user_id ?? null,
|
|
381
|
-
deleteScope: r.delete_scope ?? null,
|
|
382
|
-
editedCount: r.edited_count ?? 0
|
|
539
|
+
...base,
|
|
540
|
+
file: raw.file ? toFileInline(raw.file) : null,
|
|
541
|
+
files: raw.files && raw.files.length > 0 ? raw.files.map(toFileInline) : null,
|
|
542
|
+
reactions: base.reactions ?? [],
|
|
543
|
+
customMeta
|
|
383
544
|
};
|
|
384
545
|
}
|
|
385
546
|
var Room = class _Room {
|
|
@@ -565,20 +726,24 @@ var Room = class _Room {
|
|
|
565
726
|
async sendFile(file, opts = {}) {
|
|
566
727
|
const kind = opts.kind ?? (file.type.startsWith("image/") ? "image" : file.type.startsWith("video/") ? "video" : "file");
|
|
567
728
|
const name = opts.name ?? file.name;
|
|
568
|
-
const
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
729
|
+
const created = parseFileCreateResponse(
|
|
730
|
+
await this.http.request("POST", "/api/v1/files", {
|
|
731
|
+
kind,
|
|
732
|
+
mime: file.type || "application/octet-stream",
|
|
733
|
+
size: file.size,
|
|
734
|
+
original_name: name,
|
|
735
|
+
// 파일 전달 제한 — uploader-set at presign time. When true,
|
|
736
|
+
// other users can't forward this file to a different room.
|
|
737
|
+
forward_blocked: Boolean(opts.forwardBlocked)
|
|
738
|
+
})
|
|
739
|
+
);
|
|
577
740
|
const presigned = {
|
|
578
|
-
fileId:
|
|
579
|
-
uploadUrl:
|
|
580
|
-
headers
|
|
581
|
-
|
|
741
|
+
fileId: created.fileId,
|
|
742
|
+
uploadUrl: created.uploadUrl,
|
|
743
|
+
// Presigned S3 headers are always string-valued; the generated
|
|
744
|
+
// model types the JSON object loosely as Record<string, unknown>.
|
|
745
|
+
headers: created.headers,
|
|
746
|
+
expiresAtMs: created.expiresAtMs
|
|
582
747
|
};
|
|
583
748
|
await new Promise((resolve, reject) => {
|
|
584
749
|
const xhr = new XMLHttpRequest();
|
|
@@ -633,17 +798,19 @@ var Room = class _Room {
|
|
|
633
798
|
async uploadFileOnly(file, opts = {}) {
|
|
634
799
|
const kind = opts.kind ?? (file.type.startsWith("image/") ? "image" : file.type.startsWith("video/") ? "video" : "file");
|
|
635
800
|
const name = opts.name ?? file.name;
|
|
636
|
-
const
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
801
|
+
const created = parseFileCreateResponse(
|
|
802
|
+
await this.http.request("POST", "/api/v1/files", {
|
|
803
|
+
kind,
|
|
804
|
+
mime: file.type || "application/octet-stream",
|
|
805
|
+
size: file.size,
|
|
806
|
+
original_name: name,
|
|
807
|
+
forward_blocked: Boolean(opts.forwardBlocked)
|
|
808
|
+
})
|
|
809
|
+
);
|
|
643
810
|
await new Promise((resolve, reject) => {
|
|
644
811
|
const xhr = new XMLHttpRequest();
|
|
645
|
-
xhr.open("PUT",
|
|
646
|
-
for (const [k, v] of Object.entries(
|
|
812
|
+
xhr.open("PUT", created.uploadUrl);
|
|
813
|
+
for (const [k, v] of Object.entries(created.headers)) {
|
|
647
814
|
xhr.setRequestHeader(k, v);
|
|
648
815
|
}
|
|
649
816
|
if (opts.onProgress) {
|
|
@@ -670,10 +837,10 @@ var Room = class _Room {
|
|
|
670
837
|
});
|
|
671
838
|
await this.http.request(
|
|
672
839
|
"POST",
|
|
673
|
-
`/api/v1/files/${
|
|
840
|
+
`/api/v1/files/${created.fileId}/commit`,
|
|
674
841
|
{}
|
|
675
842
|
);
|
|
676
|
-
return
|
|
843
|
+
return created.fileId;
|
|
677
844
|
}
|
|
678
845
|
/**
|
|
679
846
|
* List files shared in this room — newest-first, paginated.
|
|
@@ -698,23 +865,26 @@ var Room = class _Room {
|
|
|
698
865
|
}
|
|
699
866
|
);
|
|
700
867
|
return {
|
|
701
|
-
items: raw.items.map((r) =>
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
868
|
+
items: raw.items.map((r) => {
|
|
869
|
+
const f = parseFileOut(r.file);
|
|
870
|
+
return {
|
|
871
|
+
messageId: r.message_id,
|
|
872
|
+
senderId: r.sender_id,
|
|
873
|
+
createdAtMs: r.created_at_ms,
|
|
874
|
+
file: {
|
|
875
|
+
id: f.id,
|
|
876
|
+
kind: f.kind,
|
|
877
|
+
mime: f.mime,
|
|
878
|
+
size: f.sizeBytes,
|
|
879
|
+
name: f.originalName ?? null,
|
|
880
|
+
width: f.width ?? null,
|
|
881
|
+
height: f.height ?? null,
|
|
882
|
+
durationSec: f.durationSec ?? null,
|
|
883
|
+
thumbnailStatus: f.thumbnailStatus,
|
|
884
|
+
forwardBlocked: Boolean(f.forwardBlocked)
|
|
885
|
+
}
|
|
886
|
+
};
|
|
887
|
+
}),
|
|
718
888
|
nextCursor: raw.next_cursor,
|
|
719
889
|
hasMore: raw.has_more
|
|
720
890
|
};
|
|
@@ -752,11 +922,12 @@ var Room = class _Room {
|
|
|
752
922
|
this.ws.send({ type: "typing", room_id: this.roomId, is_typing: isTyping });
|
|
753
923
|
}
|
|
754
924
|
async edit(messageId, patch) {
|
|
755
|
-
|
|
925
|
+
const raw = await this.http.request(
|
|
756
926
|
"PUT",
|
|
757
927
|
`/api/v1/rooms/${this.roomId}/messages/${messageId}`,
|
|
758
928
|
patch
|
|
759
929
|
);
|
|
930
|
+
return toMessageOut(raw);
|
|
760
931
|
}
|
|
761
932
|
async delete(messageId, scope = "ALL") {
|
|
762
933
|
await this.http.request(
|
|
@@ -781,12 +952,39 @@ var Room = class _Room {
|
|
|
781
952
|
* Other members get a `MEMBER_LEFT` [`roomEvent`](../reference/noverachat.md#events).
|
|
782
953
|
* Idempotent if already a non-member; throws 409 if the caller was KICKED
|
|
783
954
|
* (ask an operator to restore first). For GROUP/SUPER_GROUP, re-entry needs
|
|
784
|
-
* an operator add; for ONE, re-creating the 1:1 rejoins with history kept.
|
|
785
|
-
|
|
955
|
+
* an operator add; for ONE, re-creating the 1:1 rejoins with history kept.
|
|
956
|
+
*
|
|
957
|
+
* Optional `deleteMessages` — atomically clean up chat history as part
|
|
958
|
+
* of leaving. Default is `"none"` (messages survive so the room's
|
|
959
|
+
* history keeps making sense to remaining members).
|
|
960
|
+
* - `"none"` — leave only.
|
|
961
|
+
* - `"mine"` — soft-delete every message YOU sent, then leave. Other
|
|
962
|
+
* members' messages are untouched. Broadcasts
|
|
963
|
+
* `messages_cleared_by_sender` so connected clients hide
|
|
964
|
+
* them locally.
|
|
965
|
+
* - `"all"` — wipe every message in the room, then leave. Subject to
|
|
966
|
+
* the app's `allow_member_bulk_delete` gate and per-room
|
|
967
|
+
* OPERATOR check — a plain member gets 403 back. */
|
|
968
|
+
async leave(options) {
|
|
969
|
+
const mode = options?.deleteMessages ?? "none";
|
|
970
|
+
const query = mode === "none" ? "" : `?delete_messages=${encodeURIComponent(mode)}`;
|
|
786
971
|
await this.http.request(
|
|
787
972
|
"POST",
|
|
788
|
-
`/api/v1/rooms/${this.roomId}/leave`
|
|
973
|
+
`/api/v1/rooms/${this.roomId}/leave${query}`
|
|
974
|
+
);
|
|
975
|
+
}
|
|
976
|
+
/** Delete every message YOU sent in this room. Standalone version of
|
|
977
|
+
* `leave({ deleteMessages: "mine" })` — useful when a user wants to
|
|
978
|
+
* scrub their history without actually leaving. Other members'
|
|
979
|
+
* messages are untouched; broadcasts `messages_cleared_by_sender`
|
|
980
|
+
* so connected clients hide the vanished ones locally.
|
|
981
|
+
* No OPERATOR gate — you own your messages. */
|
|
982
|
+
async deleteMyMessages() {
|
|
983
|
+
const raw = await this.http.request(
|
|
984
|
+
"DELETE",
|
|
985
|
+
`/api/v1/rooms/${this.roomId}/messages/mine`
|
|
789
986
|
);
|
|
987
|
+
return parseBulkDeleteBySenderResult(raw);
|
|
790
988
|
}
|
|
791
989
|
/**
|
|
792
990
|
* Set the caller's per-room push preference — like long-pressing a
|
|
@@ -812,11 +1010,11 @@ var Room = class _Room {
|
|
|
812
1010
|
* hide rendered messages up to (and including) that id.
|
|
813
1011
|
*/
|
|
814
1012
|
async deleteAllMessages() {
|
|
815
|
-
const raw = await this.http.request(
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
1013
|
+
const raw = await this.http.request(
|
|
1014
|
+
"DELETE",
|
|
1015
|
+
`/api/v1/rooms/${this.roomId}/messages`
|
|
1016
|
+
);
|
|
1017
|
+
return parseBulkDeleteResult(raw);
|
|
820
1018
|
}
|
|
821
1019
|
async react(messageId, key) {
|
|
822
1020
|
await this.http.request(
|
|
@@ -903,17 +1101,11 @@ var Room = class _Room {
|
|
|
903
1101
|
* rooms, so the caller must already be a member to read this.
|
|
904
1102
|
*/
|
|
905
1103
|
async listMembers() {
|
|
906
|
-
const raw = await this.http.request(
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
pushTrigger: m.push_trigger,
|
|
912
|
-
lastReadMessageId: m.last_read_message_id,
|
|
913
|
-
joinedAt: m.joined_at,
|
|
914
|
-
isOnline: m.is_online ?? null,
|
|
915
|
-
mutedUntil: m.muted_until ?? null
|
|
916
|
-
}));
|
|
1104
|
+
const raw = await this.http.request(
|
|
1105
|
+
"GET",
|
|
1106
|
+
`/api/v1/rooms/${this.roomId}/members`
|
|
1107
|
+
);
|
|
1108
|
+
return raw.map((m) => parseRoomMemberOut(m));
|
|
917
1109
|
}
|
|
918
1110
|
// -------- mute --------
|
|
919
1111
|
/** OPERATOR-only: mute a member so they can't send messages in this
|
|
@@ -941,13 +1133,11 @@ var Room = class _Room {
|
|
|
941
1133
|
* newer than the caller's `read_watermark`, plus the room's
|
|
942
1134
|
* `last_message_id` so the UI can show a "•" dot regardless of count. */
|
|
943
1135
|
async unread() {
|
|
944
|
-
const raw = await this.http.request(
|
|
945
|
-
|
|
946
|
-
roomId
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
lastMessageId: raw.last_message_id
|
|
950
|
-
};
|
|
1136
|
+
const raw = await this.http.request(
|
|
1137
|
+
"GET",
|
|
1138
|
+
`/api/v1/rooms/${this.roomId}/unread`
|
|
1139
|
+
);
|
|
1140
|
+
return parseRoomUnread(raw);
|
|
951
1141
|
}
|
|
952
1142
|
// -------- freeze --------
|
|
953
1143
|
/** OPERATOR-only moderation: freeze this room. Non-admin messages are
|
|
@@ -982,49 +1172,35 @@ var Room = class _Room {
|
|
|
982
1172
|
}
|
|
983
1173
|
// -------- announcements --------
|
|
984
1174
|
async listAnnouncements() {
|
|
985
|
-
const raw = await this.http.request(
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
createdBy: a.created_by,
|
|
991
|
-
createdAt: a.created_at,
|
|
992
|
-
updatedAt: a.updated_at
|
|
993
|
-
}));
|
|
1175
|
+
const raw = await this.http.request(
|
|
1176
|
+
"GET",
|
|
1177
|
+
`/api/v1/rooms/${this.roomId}/announcements`
|
|
1178
|
+
);
|
|
1179
|
+
return raw.map((a) => parseAnnouncementOut(a));
|
|
994
1180
|
}
|
|
995
1181
|
async getCurrentAnnouncement() {
|
|
996
|
-
const raw = await this.http.request(
|
|
1182
|
+
const raw = await this.http.request(
|
|
1183
|
+
"GET",
|
|
1184
|
+
`/api/v1/rooms/${this.roomId}/announcements/current`
|
|
1185
|
+
);
|
|
997
1186
|
if (!raw) return null;
|
|
998
|
-
return
|
|
999
|
-
id: raw.id,
|
|
1000
|
-
roomId: raw.room_id,
|
|
1001
|
-
content: raw.content,
|
|
1002
|
-
createdBy: raw.created_by,
|
|
1003
|
-
createdAt: raw.created_at,
|
|
1004
|
-
updatedAt: raw.updated_at
|
|
1005
|
-
};
|
|
1187
|
+
return parseAnnouncementOut(raw);
|
|
1006
1188
|
}
|
|
1007
1189
|
async postAnnouncement(content) {
|
|
1008
|
-
const raw = await this.http.request(
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
createdAt: raw.created_at,
|
|
1015
|
-
updatedAt: raw.updated_at
|
|
1016
|
-
};
|
|
1190
|
+
const raw = await this.http.request(
|
|
1191
|
+
"POST",
|
|
1192
|
+
`/api/v1/rooms/${this.roomId}/announcements`,
|
|
1193
|
+
{ content }
|
|
1194
|
+
);
|
|
1195
|
+
return parseAnnouncementOut(raw);
|
|
1017
1196
|
}
|
|
1018
1197
|
async updateAnnouncement(id, content) {
|
|
1019
|
-
const raw = await this.http.request(
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
createdAt: raw.created_at,
|
|
1026
|
-
updatedAt: raw.updated_at
|
|
1027
|
-
};
|
|
1198
|
+
const raw = await this.http.request(
|
|
1199
|
+
"PATCH",
|
|
1200
|
+
`/api/v1/rooms/${this.roomId}/announcements/${id}`,
|
|
1201
|
+
{ content }
|
|
1202
|
+
);
|
|
1203
|
+
return parseAnnouncementOut(raw);
|
|
1028
1204
|
}
|
|
1029
1205
|
async deleteAnnouncement(id) {
|
|
1030
1206
|
await this.http.request(
|
|
@@ -1046,32 +1222,21 @@ var Room = class _Room {
|
|
|
1046
1222
|
const body = {};
|
|
1047
1223
|
if (opts && "expiresInHours" in opts) body.expires_in_hours = opts.expiresInHours;
|
|
1048
1224
|
if (opts && "maxUses" in opts) body.max_uses = opts.maxUses;
|
|
1049
|
-
const raw = await this.http.request(
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
expiresAt: raw.expires_at,
|
|
1056
|
-
maxUses: raw.max_uses,
|
|
1057
|
-
usedCount: raw.used_count,
|
|
1058
|
-
revokedAt: raw.revoked_at
|
|
1059
|
-
};
|
|
1225
|
+
const raw = await this.http.request(
|
|
1226
|
+
"POST",
|
|
1227
|
+
`/api/v1/rooms/${this.roomId}/invites`,
|
|
1228
|
+
body
|
|
1229
|
+
);
|
|
1230
|
+
return parseInviteTokenOut(raw);
|
|
1060
1231
|
}
|
|
1061
1232
|
/** OPERATOR-only: list all invite tokens for this room (including
|
|
1062
1233
|
* revoked / expired / exhausted), newest first. */
|
|
1063
1234
|
async listInvites() {
|
|
1064
|
-
const raw = await this.http.request(
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
createdAt: r.created_at,
|
|
1070
|
-
expiresAt: r.expires_at,
|
|
1071
|
-
maxUses: r.max_uses,
|
|
1072
|
-
usedCount: r.used_count,
|
|
1073
|
-
revokedAt: r.revoked_at
|
|
1074
|
-
}));
|
|
1235
|
+
const raw = await this.http.request(
|
|
1236
|
+
"GET",
|
|
1237
|
+
`/api/v1/rooms/${this.roomId}/invites`
|
|
1238
|
+
);
|
|
1239
|
+
return raw.map((r) => parseInviteTokenOut(r));
|
|
1075
1240
|
}
|
|
1076
1241
|
/** OPERATOR-only: revoke a token immediately. Idempotent — revoking
|
|
1077
1242
|
* an already-revoked token returns 204 as well. */
|
|
@@ -1329,13 +1494,7 @@ var NoveraChat = class {
|
|
|
1329
1494
|
* destructive buttons to expose. */
|
|
1330
1495
|
async appPolicy() {
|
|
1331
1496
|
const raw = await this.http.request("GET", "/api/v1/app/policy");
|
|
1332
|
-
return
|
|
1333
|
-
appId: raw.app_id,
|
|
1334
|
-
allowMemberBulkDelete: raw.allow_member_bulk_delete,
|
|
1335
|
-
readReceiptsEnabled: raw.read_receipts_enabled ?? true,
|
|
1336
|
-
typingIndicatorsEnabled: raw.typing_indicators_enabled ?? true,
|
|
1337
|
-
deleteAnyMessageEnabled: raw.allow_member_delete_any_message ?? false
|
|
1338
|
-
};
|
|
1497
|
+
return parseAppPolicy(raw);
|
|
1339
1498
|
}
|
|
1340
1499
|
// ---- device tokens (push) ----
|
|
1341
1500
|
/**
|
|
@@ -1345,19 +1504,23 @@ var NoveraChat = class {
|
|
|
1345
1504
|
* safe. Returns the stored device record (token shown only as a prefix).
|
|
1346
1505
|
*/
|
|
1347
1506
|
async registerDevice(params) {
|
|
1348
|
-
const raw = await this.http.request(
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1507
|
+
const raw = await this.http.request(
|
|
1508
|
+
"POST",
|
|
1509
|
+
"/api/v1/users/me/devices",
|
|
1510
|
+
{
|
|
1511
|
+
device_id: params.deviceId,
|
|
1512
|
+
token: params.token,
|
|
1513
|
+
token_type: params.tokenType,
|
|
1514
|
+
os: params.os ?? null,
|
|
1515
|
+
app_version: params.appVersion ?? null
|
|
1516
|
+
}
|
|
1517
|
+
);
|
|
1518
|
+
return parseDeviceOut(raw);
|
|
1356
1519
|
}
|
|
1357
1520
|
/** List the devices registered for the authenticated user. */
|
|
1358
1521
|
async listDevices() {
|
|
1359
1522
|
const raw = await this.http.request("GET", "/api/v1/users/me/devices");
|
|
1360
|
-
return raw.items
|
|
1523
|
+
return parseDeviceListResponse(raw).items;
|
|
1361
1524
|
}
|
|
1362
1525
|
/**
|
|
1363
1526
|
* Turn push delivery on/off for one device without unregistering it —
|
|
@@ -1395,7 +1558,7 @@ var NoveraChat = class {
|
|
|
1395
1558
|
"GET",
|
|
1396
1559
|
"/api/v1/users/me/push-preferences"
|
|
1397
1560
|
);
|
|
1398
|
-
return
|
|
1561
|
+
return parsePushPreferencesOut(raw);
|
|
1399
1562
|
}
|
|
1400
1563
|
/**
|
|
1401
1564
|
* Flip the caller's global push kill switch. Pass `false` to mute
|
|
@@ -1408,7 +1571,7 @@ var NoveraChat = class {
|
|
|
1408
1571
|
"/api/v1/users/me/push-preferences",
|
|
1409
1572
|
{ push_enabled: enabled }
|
|
1410
1573
|
);
|
|
1411
|
-
return
|
|
1574
|
+
return parsePushPreferencesOut(raw);
|
|
1412
1575
|
}
|
|
1413
1576
|
// -------------------------------------------------------------------------
|
|
1414
1577
|
// User blocks — KakaoTalk-style one-way block.
|
|
@@ -1432,11 +1595,7 @@ var NoveraChat = class {
|
|
|
1432
1595
|
`/api/v1/users/me/blocks/${encodeURIComponent(userId)}`,
|
|
1433
1596
|
{ reason: reason ?? null }
|
|
1434
1597
|
);
|
|
1435
|
-
return
|
|
1436
|
-
blockedUserId: raw.blocked_user_id,
|
|
1437
|
-
reason: raw.reason,
|
|
1438
|
-
createdAt: raw.created_at
|
|
1439
|
-
};
|
|
1598
|
+
return parseBlockOut(raw);
|
|
1440
1599
|
}
|
|
1441
1600
|
/** Unblock a user. Idempotent — resolves either way. */
|
|
1442
1601
|
async unblockUser(userId) {
|
|
@@ -1448,23 +1607,7 @@ var NoveraChat = class {
|
|
|
1448
1607
|
/** List every user the caller has blocked, newest first. */
|
|
1449
1608
|
async listBlocks() {
|
|
1450
1609
|
const raw = await this.http.request("GET", "/api/v1/users/me/blocks");
|
|
1451
|
-
return raw.map((r) => (
|
|
1452
|
-
blockedUserId: r.blocked_user_id,
|
|
1453
|
-
reason: r.reason,
|
|
1454
|
-
createdAt: r.created_at
|
|
1455
|
-
}));
|
|
1456
|
-
}
|
|
1457
|
-
_toDeviceInfo(raw) {
|
|
1458
|
-
return {
|
|
1459
|
-
deviceId: raw.device_id,
|
|
1460
|
-
tokenType: raw.token_type,
|
|
1461
|
-
tokenPreview: raw.token_preview,
|
|
1462
|
-
os: raw.os,
|
|
1463
|
-
appVersion: raw.app_version,
|
|
1464
|
-
pushEnabled: raw.push_enabled,
|
|
1465
|
-
lastActiveAt: raw.last_active_at,
|
|
1466
|
-
createdAt: raw.created_at
|
|
1467
|
-
};
|
|
1610
|
+
return raw.map((r) => parseBlockOut(r));
|
|
1468
1611
|
}
|
|
1469
1612
|
/**
|
|
1470
1613
|
* Authorization-gated URL for downloading a file attachment.
|
|
@@ -1522,41 +1665,27 @@ var NoveraChat = class {
|
|
|
1522
1665
|
* shipping date.
|
|
1523
1666
|
*/
|
|
1524
1667
|
async getFileMeta(fileId) {
|
|
1525
|
-
const raw = await this.http.request(
|
|
1668
|
+
const raw = await this.http.request(
|
|
1669
|
+
"GET",
|
|
1670
|
+
`/api/v1/files/${encodeURIComponent(fileId)}/meta`
|
|
1671
|
+
);
|
|
1672
|
+
const f = parseFileOut(raw);
|
|
1526
1673
|
return {
|
|
1527
|
-
id:
|
|
1528
|
-
kind:
|
|
1529
|
-
mime:
|
|
1530
|
-
size:
|
|
1531
|
-
name:
|
|
1532
|
-
width:
|
|
1533
|
-
height:
|
|
1534
|
-
durationSec:
|
|
1535
|
-
thumbnailStatus:
|
|
1536
|
-
forwardBlocked: Boolean(
|
|
1674
|
+
id: f.id,
|
|
1675
|
+
kind: f.kind,
|
|
1676
|
+
mime: f.mime,
|
|
1677
|
+
size: f.sizeBytes,
|
|
1678
|
+
name: f.originalName ?? null,
|
|
1679
|
+
width: f.width ?? null,
|
|
1680
|
+
height: f.height ?? null,
|
|
1681
|
+
durationSec: f.durationSec ?? null,
|
|
1682
|
+
thumbnailStatus: f.thumbnailStatus,
|
|
1683
|
+
forwardBlocked: Boolean(f.forwardBlocked)
|
|
1537
1684
|
};
|
|
1538
1685
|
}
|
|
1539
1686
|
async unreadSummary() {
|
|
1540
1687
|
const raw = await this.http.request("GET", "/api/v1/users/me/unread");
|
|
1541
|
-
return
|
|
1542
|
-
total: raw.total,
|
|
1543
|
-
rooms: raw.rooms.map((r) => ({
|
|
1544
|
-
roomId: r.room_id,
|
|
1545
|
-
name: r.name,
|
|
1546
|
-
roomType: r.room_type ?? null,
|
|
1547
|
-
unreadCount: r.unread_count,
|
|
1548
|
-
lastMessageId: r.last_message_id,
|
|
1549
|
-
lastMessagePreview: r.last_message_preview ?? null,
|
|
1550
|
-
lastReadMessageId: r.last_read_message_id,
|
|
1551
|
-
memberCount: r.member_count ?? 0,
|
|
1552
|
-
members: (r.members_preview ?? []).map((m) => ({
|
|
1553
|
-
userId: m.user_id,
|
|
1554
|
-
nickname: m.nickname ?? null,
|
|
1555
|
-
profileImageUrl: m.profile_image_url ?? null,
|
|
1556
|
-
isOnline: m.is_online ?? null
|
|
1557
|
-
}))
|
|
1558
|
-
}))
|
|
1559
|
-
};
|
|
1688
|
+
return parseUnreadSummary(raw);
|
|
1560
1689
|
}
|
|
1561
1690
|
/**
|
|
1562
1691
|
* Accept an invite link — call this in flows where you receive a
|
|
@@ -1574,12 +1703,11 @@ var NoveraChat = class {
|
|
|
1574
1703
|
* kicked from the target room.
|
|
1575
1704
|
*/
|
|
1576
1705
|
async acceptInvite(token) {
|
|
1577
|
-
const raw = await this.http.request(
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
};
|
|
1706
|
+
const raw = await this.http.request(
|
|
1707
|
+
"POST",
|
|
1708
|
+
`/api/v1/invites/${encodeURIComponent(token)}/accept`
|
|
1709
|
+
);
|
|
1710
|
+
return parseInviteAcceptResponse(raw);
|
|
1583
1711
|
}
|
|
1584
1712
|
// ---- internal ----
|
|
1585
1713
|
dispatch(msg) {
|