mezon-light-sdk 1.0.3 → 1.0.4

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.
@@ -1,327 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DefaultSocket = exports.ConnectionState = void 0;
4
- const utils_1 = require("./utils");
5
- const web_socket_adapter_pb_1 = require("./web_socket_adapter_pb");
6
- /** A socket connection to Mezon server implemented with the DOM's WebSocket API. */
7
- let __hasConnectedOnce = false;
8
- exports.ConnectionState = {
9
- DISCONNECTED: "disconnected",
10
- CONNECTING: "connecting",
11
- CONNECTED: "connected",
12
- };
13
- class DefaultSocket {
14
- constructor(host, port, useSSL = false, verbose = false, adapter = new web_socket_adapter_pb_1.WebSocketAdapterPb(), sendTimeoutMs = DefaultSocket.DefaultSendTimeoutMs) {
15
- this.host = host;
16
- this.port = port;
17
- this.useSSL = useSSL;
18
- this.verbose = verbose;
19
- this.adapter = adapter;
20
- this.sendTimeoutMs = sendTimeoutMs;
21
- this.cIds = {};
22
- this.nextCid = 1;
23
- this._heartbeatTimeoutMs = DefaultSocket.DefaultHeartbeatTimeoutMs;
24
- this._connectionState = exports.ConnectionState.DISCONNECTED;
25
- }
26
- generatecid() {
27
- const cid = this.nextCid.toString();
28
- ++this.nextCid;
29
- return cid;
30
- }
31
- isOpen() {
32
- return this._connectionState === exports.ConnectionState.CONNECTED;
33
- }
34
- connect(session, createStatus = false, platform = "", connectTimeoutMs = DefaultSocket.DefaultConnectTimeoutMs, signal) {
35
- if (this._connectionState === exports.ConnectionState.CONNECTED) {
36
- return Promise.resolve(session);
37
- }
38
- if (this._connectionState === exports.ConnectionState.CONNECTING && this._connectPromise) {
39
- return this._connectPromise;
40
- }
41
- this.clearConnectTimeout();
42
- this._connectionState = exports.ConnectionState.CONNECTING;
43
- const scheme = this.useSSL ? "wss://" : "ws://";
44
- this.adapter.connect(scheme, this.host, this.port, createStatus, session.token, platform, signal);
45
- this.adapter.onClose = (evt) => {
46
- this._connectionState = exports.ConnectionState.DISCONNECTED;
47
- this.stopHeartbeatLoop();
48
- this.clearConnectTimeout();
49
- this.ondisconnect(evt);
50
- };
51
- this.adapter.onMessage = async (message) => {
52
- if (this.verbose && window && window.console) {
53
- console.log("Response: %o", JSON.stringify(message));
54
- }
55
- /** Inbound message from server. */
56
- if (!message.cid) {
57
- if (message.channel_message) {
58
- const channelMessage = createChannelMessageFromEvent(message);
59
- this.onchannelmessage(channelMessage);
60
- }
61
- else {
62
- if (this.verbose && window && window.console) {
63
- console.log("Unrecognized message received: %o", message);
64
- }
65
- }
66
- }
67
- else {
68
- const executor = this.cIds[message.cid];
69
- if (!executor) {
70
- if (this.verbose && window && window.console) {
71
- console.error("No promise executor for message: %o", message);
72
- }
73
- return;
74
- }
75
- delete this.cIds[message.cid];
76
- if (message.error) {
77
- executor.reject(message.error);
78
- }
79
- else {
80
- executor.resolve(message);
81
- }
82
- }
83
- };
84
- const connectPromise = new Promise((resolve, reject) => {
85
- this.adapter.onOpen = (evt) => {
86
- if (this.verbose && window && window.console) {
87
- console.log(evt);
88
- }
89
- const isReconnect = __hasConnectedOnce;
90
- __hasConnectedOnce = true;
91
- this.clearConnectTimeout();
92
- this._connectionState = exports.ConnectionState.CONNECTED;
93
- this.startHeartbeatLoop();
94
- this._connectPromise = undefined;
95
- resolve(session);
96
- if (isReconnect) {
97
- this.onreconnect(evt);
98
- }
99
- };
100
- this.adapter.onError = (evt) => {
101
- this._connectionState = exports.ConnectionState.DISCONNECTED;
102
- this.stopHeartbeatLoop();
103
- this.clearConnectTimeout();
104
- this.onerror(evt);
105
- this._connectPromise = undefined;
106
- this.adapter.close();
107
- reject(evt);
108
- };
109
- this._connectTimeoutTimer = setTimeout(() => {
110
- // if promise has resolved by now, the reject() is a no-op
111
- this._connectionState = exports.ConnectionState.DISCONNECTED;
112
- this.stopHeartbeatLoop();
113
- this.adapter.close();
114
- this._connectPromise = undefined;
115
- reject("The socket timed out when trying to connect.");
116
- this._connectTimeoutTimer = undefined;
117
- }, connectTimeoutMs);
118
- });
119
- this._connectPromise = connectPromise;
120
- return this._connectPromise;
121
- }
122
- disconnect(fireDisconnectEvent = true) {
123
- this._connectionState = exports.ConnectionState.DISCONNECTED;
124
- this.stopHeartbeatLoop();
125
- if (this.adapter.isOpen()) {
126
- this.adapter.close();
127
- }
128
- if (fireDisconnectEvent) {
129
- this.ondisconnect({});
130
- }
131
- }
132
- setHeartbeatTimeoutMs(ms) {
133
- this._heartbeatTimeoutMs = ms;
134
- }
135
- getHeartbeatTimeoutMs() {
136
- return this._heartbeatTimeoutMs;
137
- }
138
- onreconnect(evt) {
139
- if (this.verbose && window && window.console) {
140
- console.log(evt);
141
- }
142
- }
143
- ondisconnect(evt) {
144
- if (this.verbose && window && window.console) {
145
- console.log(evt);
146
- }
147
- }
148
- onerror(evt) {
149
- this._connectionState = exports.ConnectionState.DISCONNECTED;
150
- this.stopHeartbeatLoop();
151
- if (this.verbose && window && window.console) {
152
- console.log(evt);
153
- }
154
- }
155
- onheartbeattimeout() {
156
- if (this.verbose && window && window.console) {
157
- console.log("Heartbeat timeout.");
158
- }
159
- }
160
- onchannelmessage(channelMessage) {
161
- if (this.verbose && window && window.console) {
162
- console.log(channelMessage);
163
- }
164
- }
165
- // onuserchanneladded(user: UserChannelAddedEvent) {
166
- // if (this.verbose && window && window.console) {
167
- // console.log(user);
168
- // }
169
- // }
170
- send(message, sendTimeout = DefaultSocket.DefaultSendTimeoutMs) {
171
- const untypedMessage = message;
172
- return new Promise((resolve, reject) => {
173
- if (!this.adapter.isOpen()) {
174
- reject("Socket connection has not been established yet.");
175
- }
176
- else {
177
- if (untypedMessage.channel_message_send) {
178
- untypedMessage.channel_message_send.content = JSON.stringify(untypedMessage.channel_message_send.content);
179
- }
180
- else if (untypedMessage.channel_message_update) {
181
- untypedMessage.channel_message_update.content = JSON.stringify(untypedMessage.channel_message_update.content);
182
- }
183
- else if (untypedMessage.ephemeral_message_send) {
184
- untypedMessage.ephemeral_message_send.message.content = JSON.stringify(untypedMessage.ephemeral_message_send.message?.content);
185
- }
186
- else if (untypedMessage.quick_menu_event) {
187
- untypedMessage.quick_menu_event.message.content = JSON.stringify(untypedMessage.quick_menu_event.message?.content);
188
- }
189
- const cid = this.generatecid();
190
- this.cIds[cid] = { resolve, reject };
191
- if (sendTimeout !== Infinity && sendTimeout > 0) {
192
- setTimeout(() => {
193
- reject("The socket timed out while waiting for a response.");
194
- }, sendTimeout);
195
- }
196
- untypedMessage.cid = cid;
197
- this.adapter.send(untypedMessage);
198
- }
199
- });
200
- }
201
- async joinChat(clan_id, channel_id, channel_type, is_public) {
202
- const response = await this.send({
203
- channel_join: {
204
- clan_id: clan_id,
205
- channel_id: channel_id,
206
- channel_type: channel_type,
207
- is_public: is_public,
208
- },
209
- });
210
- return response.channel;
211
- }
212
- async leaveChat(clan_id, channel_id, channel_type, is_public) {
213
- return this.send({
214
- channel_leave: {
215
- clan_id: clan_id,
216
- channel_id: channel_id,
217
- channel_type: channel_type,
218
- is_public: is_public,
219
- },
220
- });
221
- }
222
- async writeChatMessage(clan_id, channel_id, mode, is_public, content, attachments, anonymous_message, mention_everyone, avatar, code, topic_id) {
223
- const response = await this.send({
224
- channel_message_send: {
225
- clan_id: clan_id,
226
- channel_id: channel_id,
227
- mode: mode,
228
- is_public: is_public,
229
- content: content,
230
- reactions: [],
231
- mentions: [],
232
- attachments: attachments,
233
- references: [],
234
- anonymous_message: anonymous_message,
235
- mention_everyone: mention_everyone,
236
- avatar: avatar,
237
- code: code,
238
- topic_id: topic_id,
239
- },
240
- }, Infinity);
241
- return response.channel_message_ack;
242
- }
243
- async pingPong() {
244
- if (!this.isOpen()) {
245
- this._connectionState = exports.ConnectionState.DISCONNECTED;
246
- this.stopHeartbeatLoop();
247
- return;
248
- }
249
- try {
250
- await this.send({ ping: {} }, this._heartbeatTimeoutMs);
251
- }
252
- catch {
253
- this._connectionState = exports.ConnectionState.DISCONNECTED;
254
- this.stopHeartbeatLoop();
255
- if (this.adapter.isOpen()) {
256
- if (window && window.console) {
257
- console.error("Server unreachable from heartbeat.");
258
- }
259
- this.onheartbeattimeout();
260
- this.adapter.close();
261
- }
262
- return;
263
- }
264
- this.startHeartbeatLoop();
265
- }
266
- startHeartbeatLoop() {
267
- this.stopHeartbeatLoop();
268
- this._heartbeatTimer = setTimeout(() => this.pingPong(), this._heartbeatTimeoutMs);
269
- }
270
- stopHeartbeatLoop() {
271
- if (this._heartbeatTimer !== undefined) {
272
- clearTimeout(this._heartbeatTimer);
273
- this._heartbeatTimer = undefined;
274
- }
275
- }
276
- clearConnectTimeout() {
277
- if (this._connectTimeoutTimer !== undefined) {
278
- clearTimeout(this._connectTimeoutTimer);
279
- this._connectTimeoutTimer = undefined;
280
- }
281
- }
282
- }
283
- exports.DefaultSocket = DefaultSocket;
284
- DefaultSocket.DefaultHeartbeatTimeoutMs = 10000;
285
- DefaultSocket.DefaultSendTimeoutMs = 10000;
286
- DefaultSocket.DefaultConnectTimeoutMs = 30000;
287
- function createChannelMessageFromEvent(message) {
288
- var content, attachments;
289
- try {
290
- content = (0, utils_1.safeJSONParse)(message.channel_message.content);
291
- }
292
- catch (e) {
293
- console.log("content is invalid", e);
294
- }
295
- try {
296
- attachments = (0, utils_1.decodeAttachments)(message.channel_message.attachments);
297
- }
298
- catch (e) {
299
- console.log("attachments is invalid", e);
300
- }
301
- var e = {
302
- id: message.id || message.channel_message.message_id,
303
- avatar: message.channel_message.avatar,
304
- channel_id: message.channel_message.channel_id,
305
- mode: message.channel_message.mode,
306
- channel_label: message.channel_message.channel_label,
307
- clan_id: message.channel_message.clan_id,
308
- code: message.channel_message.code,
309
- message_id: message.channel_message.message_id,
310
- sender_id: message.channel_message.sender_id,
311
- update_time: message.channel_message.update_time,
312
- clan_logo: message.channel_message.clan_logo,
313
- category_name: message.channel_message.category_name,
314
- username: message.channel_message.username,
315
- clan_nick: message.channel_message.clan_nick,
316
- clan_avatar: message.channel_message.clan_avatar,
317
- display_name: message.channel_message.display_name,
318
- content: content,
319
- attachments: attachments?.attachments,
320
- hide_editted: message.channel_message.hide_editted,
321
- is_public: message.channel_message.is_public,
322
- create_time_seconds: message.channel_message.create_time_seconds,
323
- update_time_seconds: message.channel_message.update_time_seconds,
324
- topic_id: message.channel_message.topic_id,
325
- };
326
- return e;
327
- }
package/dist/socket.js DELETED
@@ -1,249 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.LightSocket = exports.SocketError = void 0;
4
- const web_socket_adapter_pb_1 = require("./web_socket_adapter_pb");
5
- const constants_1 = require("./constants");
6
- /**
7
- * Error thrown when socket operations fail.
8
- */
9
- class SocketError extends Error {
10
- constructor(message) {
11
- super(message);
12
- this.name = "SocketError";
13
- }
14
- }
15
- exports.SocketError = SocketError;
16
- /**
17
- * Maps raw socket message data to a ChannelMessage interface.
18
- */
19
- function mapToChannelMessage(message) {
20
- return {
21
- ...message,
22
- clan_id: String(message.clan_id ?? ""),
23
- channel_id: String(message.channel_id ?? ""),
24
- message_id: String(message.message_id ?? ""),
25
- sender_id: String(message.sender_id ?? ""),
26
- content: String(message.content ?? ""),
27
- // reactions: [],
28
- // mentions: [],
29
- // attachments: Array.isArray(message.attachments) ? message.attachments : [],
30
- // references: Array.isArray(message.references) ? message.references : [],
31
- create_time_seconds: Number(message.create_time_seconds ?? 0),
32
- update_time_seconds: Number(message.update_time_seconds ?? 0),
33
- hide_editted: Boolean(message.hide_editted),
34
- };
35
- }
36
- /**
37
- * Waits for a socket to be in a ready state with exponential backoff.
38
- *
39
- * @param socket - The socket to wait for
40
- * @param maxRetries - Maximum number of retry attempts
41
- * @param initialDelay - Initial delay in milliseconds
42
- * @throws {SocketError} If socket doesn't become ready within retry limit
43
- */
44
- async function waitForSocketReady(socket, maxRetries = constants_1.SOCKET_READY_MAX_RETRY, initialDelay = constants_1.SOCKET_READY_RETRY_DELAY) {
45
- let retryCount = 0;
46
- let delay = initialDelay;
47
- // Type assertion to access internal adapter
48
- const socketWithAdapter = socket;
49
- while (retryCount < maxRetries) {
50
- if (socketWithAdapter.adapter?.isOpen()) {
51
- return;
52
- }
53
- await new Promise((resolve) => setTimeout(resolve, delay));
54
- delay *= 2; // Exponential backoff
55
- retryCount++;
56
- }
57
- throw new SocketError(`Socket failed to connect after ${maxRetries} attempts (total wait: ~${Math.pow(2, maxRetries) * initialDelay}ms)`);
58
- }
59
- /**
60
- * LightSocket provides a simplified interface for Mezon real-time messaging.
61
- *
62
- * @example
63
- * ```typescript
64
- * const socket = new LightSocket(client.client, client.session);
65
- *
66
- * await socket.connect({
67
- * onError: (err) => console.error('Socket error:', err),
68
- * onDisconnect: () => console.log('Disconnected')
69
- * });
70
- *
71
- * socket.onChannelMessage((msg) => {
72
- * console.log('Received message:', msg.content);
73
- * });
74
- *
75
- * await socket.joinDMChannel('channel-123');
76
- * await socket.sendDM({ channelId: 'channel-123', content: 'Hello!' });
77
- * ```
78
- */
79
- class LightSocket {
80
- constructor(_client, _session) {
81
- this._client = _client;
82
- this._session = _session;
83
- this._socket = null;
84
- this._isConnected = false;
85
- this._messageHandlers = [];
86
- }
87
- /**
88
- * Gets whether the socket is currently connected.
89
- */
90
- get isConnected() {
91
- return this._isConnected;
92
- }
93
- /**
94
- * Gets the underlying socket instance.
95
- * @throws {SocketError} If socket is not connected
96
- */
97
- get socket() {
98
- if (!this._socket) {
99
- throw new SocketError("Socket is not connected. Call connect() first.");
100
- }
101
- return this._socket;
102
- }
103
- /**
104
- * Connects to the Mezon real-time server.
105
- *
106
- * @param options - Connection options including error handlers
107
- * @throws {SocketError} If already connected or connection fails
108
- */
109
- async connect(options = {}) {
110
- if (this._isConnected) {
111
- throw new SocketError("Socket is already connected. Call disconnect() first.");
112
- }
113
- const { onError, onDisconnect, verbose = false } = options;
114
- this._errorHandler = onError;
115
- this._disconnectHandler = onDisconnect;
116
- this._socket = this._client.createSocket(verbose, new web_socket_adapter_pb_1.WebSocketAdapterPb());
117
- // Set up error handler
118
- this._socket.onerror = (error) => {
119
- this._errorHandler?.(error);
120
- };
121
- // Set up disconnect handler
122
- this._socket.ondisconnect = () => {
123
- this._isConnected = false;
124
- this._disconnectHandler?.();
125
- };
126
- // Set up message handler that dispatches to all registered handlers
127
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
128
- this._socket.onchannelmessage = (channelMessage) => {
129
- if (!channelMessage) {
130
- this._errorHandler?.(new SocketError("Received null or undefined channel message"));
131
- return;
132
- }
133
- this._messageHandlers.forEach((handler) => {
134
- try {
135
- handler(channelMessage);
136
- }
137
- catch (error) {
138
- console.error("Error in message handler:", error);
139
- }
140
- });
141
- };
142
- await this._socket.connect(this._session, true, "0");
143
- this._isConnected = true;
144
- }
145
- /**
146
- * Disconnects from the Mezon server.
147
- */
148
- disconnect() {
149
- if (this._socket) {
150
- this._socket.disconnect(true);
151
- this._socket = null;
152
- this._isConnected = false;
153
- }
154
- }
155
- /**
156
- * Registers a handler for incoming channel messages.
157
- * Multiple handlers can be registered and will all receive messages.
158
- *
159
- * @param handler - Callback function to handle messages
160
- */
161
- setChannelMessageHandler(cb) {
162
- this.onChannelMessage(cb);
163
- }
164
- /**
165
- * Registers a handler for incoming channel messages.
166
- * Multiple handlers can be registered and will all receive messages.
167
- *
168
- * @param handler - Callback function to handle messages
169
- * @returns A function to unsubscribe the handler
170
- */
171
- onChannelMessage(handler) {
172
- this._messageHandlers.push(handler);
173
- // Return unsubscribe function
174
- return () => {
175
- const index = this._messageHandlers.indexOf(handler);
176
- if (index !== -1) {
177
- this._messageHandlers.splice(index, 1);
178
- }
179
- };
180
- }
181
- /**
182
- * Joins a DM channel to receive messages from it.
183
- *
184
- * @param channelId - The DM channel ID to join
185
- * @throws {SocketError} If socket is not ready or join fails
186
- */
187
- async joinDMChannel(channelId) {
188
- await waitForSocketReady(this.socket);
189
- await this.socket.joinChat(constants_1.CLAN_DM, channelId, constants_1.CHANNEL_TYPE_DM, false);
190
- }
191
- /**
192
- * Joins a group channel to receive messages from it.
193
- *
194
- * @param channelId - The group channel ID to join
195
- * @throws {SocketError} If socket is not ready or join fails
196
- */
197
- async joinGroupChannel(channelId) {
198
- await waitForSocketReady(this.socket);
199
- await this.socket.joinChat(constants_1.CLAN_DM, channelId, constants_1.CHANNEL_TYPE_GROUP, false);
200
- }
201
- /**
202
- * Leaves a DM channel.
203
- *
204
- * @param channelId - The DM channel ID to leave
205
- */
206
- async leaveDMChannel(channelId) {
207
- await this.socket.leaveChat(constants_1.CLAN_DM, channelId, constants_1.CHANNEL_TYPE_DM, false);
208
- }
209
- /**
210
- * Leaves a group channel.
211
- *
212
- * @param channelId - The group channel ID to leave
213
- */
214
- async leaveGroupChannel(channelId) {
215
- await this.socket.leaveChat(constants_1.CLAN_DM, channelId, constants_1.CHANNEL_TYPE_GROUP, false);
216
- }
217
- /**
218
- * Sends a direct message to a channel.
219
- *
220
- * @param options - Message options including channelId, content, and attachments
221
- */
222
- async sendDM(payload) {
223
- const { channelId, content, attachments, hideLink = false } = payload;
224
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
225
- await this.socket.writeChatMessage(constants_1.CLAN_DM, channelId, constants_1.STREAM_MODE_DM, false, content, attachments, false, hideLink, "", 0);
226
- }
227
- /**
228
- * Sends a direct message to a channel.
229
- *
230
- * @param options - Message options including channelId, content, and attachments
231
- */
232
- async sendGroup(payload) {
233
- const { channelId, content, attachments, hideLink = false } = payload;
234
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
235
- await this.socket.writeChatMessage(constants_1.CLAN_DM, channelId, constants_1.STREAM_MODE_GROUP, false, content, attachments, false, hideLink, "", 0);
236
- }
237
- /**
238
- * Sets the error handler for socket errors.
239
- *
240
- * @param handler - Error handler callback
241
- */
242
- setErrorHandler(handler) {
243
- this._errorHandler = handler;
244
- if (this._socket) {
245
- this._socket.onerror = handler;
246
- }
247
- }
248
- }
249
- exports.LightSocket = LightSocket;
package/dist/types.d.ts DELETED
@@ -1,44 +0,0 @@
1
- import { ApiMessageAttachment } from "./api.gen";
2
- /**
3
- * Configuration for initializing a LightClient from existing tokens.
4
- */
5
- export interface ClientInitConfig {
6
- /** Authentication token */
7
- token: string;
8
- /** Refresh token for session renewal */
9
- refresh_token: string;
10
- /** API URL for the Mezon server */
11
- api_url: string;
12
- /** User ID associated with the session */
13
- user_id: string;
14
- /** Server key for authentication (optional, uses default if not provided) */
15
- serverkey?: string;
16
- }
17
- /**
18
- * Configuration for authenticating a new user.
19
- */
20
- export interface AuthenticateConfig {
21
- /** ID token from identity provider */
22
- id_token: string;
23
- /** User ID to associate with the account */
24
- user_id: string;
25
- /** Username for the account */
26
- username: string;
27
- /** Server key for authentication (optional, uses default if not provided) */
28
- serverkey?: string;
29
- /** Custom gateway URL (optional, uses default if not provided) */
30
- gateway_url?: string;
31
- }
32
- /**
33
- * Options for sending a message.
34
- */
35
- export interface SendMessagePayload {
36
- /** The channel ID to send the message to */
37
- channelId: string;
38
- /** Message content */
39
- content: unknown;
40
- /** File/media attachments (optional) */
41
- attachments?: ApiMessageAttachment[];
42
- /** Whether to hide link previews (optional) */
43
- hideLink?: boolean;
44
- }
package/dist/types.js DELETED
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
package/dist/utils.d.ts DELETED
@@ -1,3 +0,0 @@
1
- export declare function buildFetchOptions(method: string, options: any, bodyJson: string): any;
2
- export declare function safeJSONParse(raw: any): any;
3
- export declare function decodeAttachments(data: any): any;