@noverachat/sdk-web 0.0.3 → 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/README.ko.md +8 -8
- package/README.md +8 -8
- package/dist/index.cjs +485 -258
- package/dist/index.d.cts +212 -169
- package/dist/index.d.ts +212 -169
- package/dist/index.js +485 -258
- package/package.json +1 -1
- package/src/client.ts +50 -157
- package/src/features/room.ts +274 -344
- package/src/generated/rest.ts +529 -0
- package/src/index.ts +4 -0
- package/src/types.ts +62 -177
package/src/types.ts
CHANGED
|
@@ -37,175 +37,73 @@ export type {
|
|
|
37
37
|
WsError, WsCloseNotice,
|
|
38
38
|
};
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
/* ------------------------------------------------------------------ *
|
|
41
|
+
* REST DTO 는 GENERATED 이다 — packages/protocol/schema/openapi.dev.json
|
|
42
|
+
* (dev 서버 OpenAPI vendor 본) 이 SSOT. camelCase 인터페이스 + `parseX(json)`
|
|
43
|
+
* 변환 함수는 ./generated/rest.ts 에 함께 방출된다(REST_MODELS 화이트리스트,
|
|
44
|
+
* scripts/gen.mjs). 손으로 고치지 말고 vendor 본을 갱신한 뒤 `pnpm gen`.
|
|
45
|
+
* 아래에서 그대로 re-export 하고, 기존 공개 이름은 alias 로 유지한다.
|
|
46
|
+
* ------------------------------------------------------------------ */
|
|
47
|
+
export type {
|
|
48
|
+
SenderMini,
|
|
49
|
+
ReactionEntry,
|
|
50
|
+
MemberPreview,
|
|
51
|
+
RoomUnread,
|
|
52
|
+
UnreadRoomItem,
|
|
53
|
+
UnreadSummary,
|
|
54
|
+
AppPolicy,
|
|
55
|
+
MessageListResponse,
|
|
56
|
+
RoomMemberOut,
|
|
57
|
+
RoomMemberListResponse,
|
|
58
|
+
BulkDeleteResult,
|
|
59
|
+
BulkDeleteBySenderResult,
|
|
60
|
+
FileOut,
|
|
61
|
+
FileCreateResponse,
|
|
62
|
+
RoomOut,
|
|
63
|
+
DeviceListResponse,
|
|
64
|
+
PushPreferencesOut,
|
|
65
|
+
JoinRequestOut,
|
|
66
|
+
JoinRequestListResponse,
|
|
67
|
+
JoinRequestCreateResponse,
|
|
68
|
+
} from "./generated/rest.js";
|
|
45
69
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
70
|
+
// 공개 이름 유지 — 이전 손 DTO 이름을 생성물 이름으로 alias (0.x, minor 브레이킹 허용).
|
|
71
|
+
export type {
|
|
72
|
+
AnnouncementOut as Announcement,
|
|
73
|
+
BlockOut as Block,
|
|
74
|
+
InviteTokenOut as InviteToken,
|
|
75
|
+
InviteAcceptResponse as AcceptInviteResult,
|
|
76
|
+
DeviceOut as DeviceInfo,
|
|
77
|
+
MessageListResponse as MessagePage,
|
|
78
|
+
} from "./generated/rest.js";
|
|
51
79
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
fileId?: MessageIdStr | null;
|
|
71
|
-
/** Inline file metadata embedded by the server on chat_receive — lets
|
|
72
|
-
* the UI render a placeholder (filename, size, dimensions, thumbnail
|
|
73
|
-
* status) without an extra round-trip. May be null even when `fileId`
|
|
74
|
-
* is set (e.g. for messages loaded via REST history before the inline
|
|
75
|
-
* metadata feature shipped); call ``getFileMeta()`` in that case. */
|
|
80
|
+
import type { MessageOut as RestMessageOut, ReactionEntry } from "./generated/rest.js";
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Canonical message shape surfaced to SDK callers. Structurally the
|
|
84
|
+
* GENERATED REST `MessageOut` PLUS two client-side enhancements the server
|
|
85
|
+
* doesn't send verbatim:
|
|
86
|
+
* - `file` / `files` parsed into the camelCase `FileInline` shape (the
|
|
87
|
+
* generated model leaves them free-form since the OpenAPI schema does),
|
|
88
|
+
* - `customMeta` lifted out of `data._customMeta`.
|
|
89
|
+
* Built by `toMessageOut` in features/room.ts.
|
|
90
|
+
*/
|
|
91
|
+
export interface MessageOut
|
|
92
|
+
extends Omit<RestMessageOut, "file" | "files" | "reactions"> {
|
|
93
|
+
/** Inline file metadata embedded by the server on chat_receive / REST
|
|
94
|
+
* history — lets the UI render a placeholder (filename, size, dims,
|
|
95
|
+
* thumbnail status) without an extra round-trip. May be null even when
|
|
96
|
+
* `fileId` is set (older history predating inline meta); call
|
|
97
|
+
* ``getFileMeta()`` in that case. */
|
|
76
98
|
file?: FileInline | null;
|
|
77
|
-
/** Multi-file bundle
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
* UIs should check ``files?.length > 0`` first and only fall through
|
|
81
|
-
* to the ``file`` singleton when the bundle field is absent. */
|
|
99
|
+
/** Multi-file bundle (kind = "file_group"). Null for single-file /
|
|
100
|
+
* text-only messages. Check ``files?.length`` first, then fall back to
|
|
101
|
+
* the ``file`` singleton. */
|
|
82
102
|
files?: FileInline[] | null;
|
|
83
|
-
replyToId?: MessageIdStr | null;
|
|
84
103
|
reactions: ReactionEntry[];
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
updatedAtMs?: number | null;
|
|
89
|
-
deletedAt?: string | null;
|
|
90
|
-
deletedByUserId?: string | null;
|
|
91
|
-
deleteScope?: DeleteScope | null;
|
|
92
|
-
editedCount: number;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
export interface RoomUnread {
|
|
96
|
-
roomId: string;
|
|
97
|
-
unreadCount: number;
|
|
98
|
-
lastReadMessageId: MessageIdStr | null;
|
|
99
|
-
lastMessageId: MessageIdStr | null;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
export interface Announcement {
|
|
103
|
-
id: number;
|
|
104
|
-
roomId: string;
|
|
105
|
-
content: string;
|
|
106
|
-
createdBy: string;
|
|
107
|
-
createdAt: string;
|
|
108
|
-
updatedAt: string;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/** One-way user block — KakaoTalk-style.
|
|
112
|
-
*
|
|
113
|
-
* A row in the caller's block list. The blocked user is NOT told they're
|
|
114
|
-
* blocked; they keep sending messages that just don't reach the blocker.
|
|
115
|
-
* See ``chat.blockUser`` / ``chat.unblockUser`` / ``chat.listBlocks``.
|
|
116
|
-
*/
|
|
117
|
-
export interface Block {
|
|
118
|
-
blockedUserId: string;
|
|
119
|
-
reason: string | null;
|
|
120
|
-
/** ISO-8601 UTC. */
|
|
121
|
-
createdAt: string;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/** 방 초대 링크 (카톡 오픈채팅 URL 스타일). Minted by an OPERATOR via
|
|
125
|
-
* ``room.createInvite()``; consumed by any user via ``chat.acceptInvite()``. */
|
|
126
|
-
export interface InviteToken {
|
|
127
|
-
/** URL-safe short id (~22 chars). Embed in the shareable URL as-is. */
|
|
128
|
-
token: string;
|
|
129
|
-
roomId: string;
|
|
130
|
-
createdBy: string;
|
|
131
|
-
/** ISO-8601 UTC. */
|
|
132
|
-
createdAt: string;
|
|
133
|
-
/** ISO-8601 UTC. `null` = never expires. */
|
|
134
|
-
expiresAt: string | null;
|
|
135
|
-
/** `null` = unlimited uses. */
|
|
136
|
-
maxUses: number | null;
|
|
137
|
-
/** Successful `accept` calls so far. */
|
|
138
|
-
usedCount: number;
|
|
139
|
-
/** ISO-8601 UTC. `null` = still active (assuming not expired / exhausted). */
|
|
140
|
-
revokedAt: string | null;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/** Result of `chat.acceptInvite(token)`. */
|
|
144
|
-
export interface AcceptInviteResult {
|
|
145
|
-
roomId: string;
|
|
146
|
-
roomName: string | null;
|
|
147
|
-
/** True when the caller was already an active member — the call is a
|
|
148
|
-
* no-op and does NOT bump the invite's `used_count`. Useful for
|
|
149
|
-
* deep-link flows that may be triggered on re-open. */
|
|
150
|
-
wasAlreadyMember: boolean;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/** One member shown in a channel-list avatar mosaic. */
|
|
154
|
-
export interface MemberPreview {
|
|
155
|
-
userId: string;
|
|
156
|
-
nickname: string | null;
|
|
157
|
-
profileImageUrl: string | null;
|
|
158
|
-
/** Cluster-wide presence dot. `null` = not resolved (endpoint didn't
|
|
159
|
-
* include it). Consumers rendering a green/gray dot should treat
|
|
160
|
-
* `null` and `false` differently only if they care about the
|
|
161
|
-
* "unknown" state. */
|
|
162
|
-
isOnline: boolean | null;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
export interface UnreadRoomItem {
|
|
166
|
-
roomId: string;
|
|
167
|
-
name: string | null;
|
|
168
|
-
/** "ONE" | "GROUP" | "SUPER_GROUP" — lets the UI pick a 1-up vs mosaic avatar. */
|
|
169
|
-
roomType: string | null;
|
|
170
|
-
unreadCount: number;
|
|
171
|
-
lastMessageId: MessageIdStr | null;
|
|
172
|
-
/** One-line preview shown under the room name in the channel list.
|
|
173
|
-
* TEXT/SYSTEM → first 200 chars, EMOTICON → "[이모티콘]", images/videos/
|
|
174
|
-
* files → "[사진]" / "[동영상]" / "[파일] name". Null when the room has
|
|
175
|
-
* no messages yet (or was just cleared). */
|
|
176
|
-
lastMessagePreview: string | null;
|
|
177
|
-
lastReadMessageId: MessageIdStr | null;
|
|
178
|
-
/** Total active (non-KICKED) members incl. the caller — the count badge. */
|
|
179
|
-
memberCount: number;
|
|
180
|
-
/** Up to 4 OTHER members (caller excluded) for the avatar mosaic. */
|
|
181
|
-
members: MemberPreview[];
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
export interface UnreadSummary {
|
|
185
|
-
total: number;
|
|
186
|
-
rooms: UnreadRoomItem[];
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
export interface AppPolicy {
|
|
190
|
-
appId: string;
|
|
191
|
-
/** When true, any non-KICKED room member can call
|
|
192
|
-
* `room.deleteAllMessages()`. When false, only operators (or super-admin)
|
|
193
|
-
* can. UIs should gate the destructive button on this. */
|
|
194
|
-
allowMemberBulkDelete: boolean;
|
|
195
|
-
/** When false, server does NOT broadcast `sync_tick` frames — hide
|
|
196
|
-
* read-receipt badges client-side. Per-user unread counts via REST
|
|
197
|
-
* still work (DB tracking is independent of the broadcast). */
|
|
198
|
-
readReceiptsEnabled: boolean;
|
|
199
|
-
/** When false, the server silently drops inbound `typing` frames and
|
|
200
|
-
* no peer ever sees "alice is typing…". SDK callers should also
|
|
201
|
-
* short-circuit `room.setTyping()` based on this flag so a disabled
|
|
202
|
-
* app doesn't pay the WS frame cost per keystroke. */
|
|
203
|
-
typingIndicatorsEnabled: boolean;
|
|
204
|
-
/** When true, any non-KICKED room member can hard-delete another
|
|
205
|
-
* member's message (scope=ALL). Default false — sender-or-operator
|
|
206
|
-
* only. UIs should gate the "Delete for everyone" button on other
|
|
207
|
-
* users' messages by this flag. */
|
|
208
|
-
deleteAnyMessageEnabled: boolean;
|
|
104
|
+
/** Custom metadata attached by the sender (extracted from
|
|
105
|
+
* `data._customMeta`). Null when the sender didn't attach anything. */
|
|
106
|
+
customMeta?: Record<string, unknown> | null;
|
|
209
107
|
}
|
|
210
108
|
|
|
211
109
|
/** Push providers we can deliver to. Matches the backend `TokenType`. */
|
|
@@ -227,19 +125,6 @@ export interface RegisterDeviceParams {
|
|
|
227
125
|
appVersion?: string;
|
|
228
126
|
}
|
|
229
127
|
|
|
230
|
-
export interface DeviceInfo {
|
|
231
|
-
deviceId: string;
|
|
232
|
-
tokenType: DeviceTokenType;
|
|
233
|
-
/** Server returns only a short prefix of the token — it's a credential
|
|
234
|
-
* and the caller already holds the full value. */
|
|
235
|
-
tokenPreview: string;
|
|
236
|
-
os: DeviceOS | null;
|
|
237
|
-
appVersion: string | null;
|
|
238
|
-
pushEnabled: boolean;
|
|
239
|
-
lastActiveAt: string | null;
|
|
240
|
-
createdAt: string;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
128
|
export interface SendParams {
|
|
244
129
|
content?: string;
|
|
245
130
|
messageType?: "TEXT" | "FILE" | "EMOTICON";
|