mezon-light-sdk 1.0.2 → 1.0.3

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/client.d.ts CHANGED
@@ -1,26 +1,137 @@
1
- import { Session, Client } from 'mezon-js';
1
+ import { Session } from "./session";
2
+ import { ApiSession, MezonApi } from "./api.gen";
3
+ import { ClientInitConfig, AuthenticateConfig } from "./types";
4
+ import { ApiChannelDescription } from "./api.gen";
5
+ import { WebSocketAdapter } from "./web_socket_adapter_pb";
6
+ import { Socket } from "./socket.gen";
7
+ /**
8
+ * Error thrown when authentication fails.
9
+ */
10
+ export declare class AuthenticationError extends Error {
11
+ readonly statusCode?: number | undefined;
12
+ constructor(message?: string, statusCode?: number | undefined);
13
+ }
14
+ /**
15
+ * Error thrown when session-related operations fail.
16
+ */
17
+ export declare class SessionError extends Error {
18
+ constructor(message?: string);
19
+ }
20
+ /**
21
+ * LightClient provides a simplified interface for Mezon authentication and channel management.
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * // Initialize from existing tokens
26
+ * const client = LightClient.initClient({
27
+ * token: 'your-token',
28
+ * refresh_token: 'your-refresh-token',
29
+ * api_url: 'https://api.mezon.ai',
30
+ * user_id: 'user-123'
31
+ * });
32
+ *
33
+ * // Or authenticate with ID token
34
+ * const client = await LightClient.authenticate({
35
+ * id_token: 'id-token-from-provider',
36
+ * user_id: 'user-123',
37
+ * username: 'johndoe'
38
+ * });
39
+ * ```
40
+ */
2
41
  export declare class LightClient {
3
- private session;
4
- private client;
5
- user_id: string;
42
+ private readonly _session;
43
+ private readonly _client;
44
+ private readonly _userId;
45
+ /** Promise that resolves when the refresh token operation completes */
46
+ private refreshTokenPromise;
6
47
  private constructor();
7
- static initClient({ token, refresh_token, api_url, user_id, serverkey }: {
8
- token: string;
9
- refresh_token: string;
10
- api_url: string;
11
- user_id: string;
12
- serverkey: string;
13
- }): LightClient;
14
- static authenticate({ id_token, user_id, username, serverkey }: {
15
- id_token: string;
16
- user_id: string;
17
- username: string;
18
- serverkey: string;
19
- }): Promise<LightClient>;
20
- createDM(peer_id: string): Promise<import("mezon-js/dist/api.gen").ApiChannelDescription>;
21
- refreshSession(): Promise<void>;
22
- isSessionExpired(): Promise<boolean>;
23
- isRefreshSessionExpired(): Promise<boolean>;
48
+ /**
49
+ * Gets the current user ID.
50
+ */
51
+ get userId(): string;
52
+ /**
53
+ * Gets the underlying Mezon session.
54
+ */
55
+ get session(): Session;
56
+ /**
57
+ * Gets the underlying Mezon client.
58
+ */
59
+ get client(): MezonApi;
60
+ /**
61
+ * Initializes a LightClient from existing session tokens.
62
+ * Use this when you have stored tokens from a previous authentication.
63
+ *
64
+ * @param config - Configuration containing tokens and connection details
65
+ * @returns A new LightClient instance
66
+ * @throws {SessionError} If required fields are missing
67
+ */
68
+ static initClient(config: ClientInitConfig): LightClient;
69
+ /**
70
+ * Authenticates a user with an ID token from an identity provider.
71
+ *
72
+ * @param config - Authentication configuration
73
+ * @returns A promise that resolves to a new LightClient instance
74
+ * @throws {AuthenticationError} If authentication fails or response is invalid
75
+ */
76
+ static authenticate(config: AuthenticateConfig): Promise<LightClient>;
77
+ /**
78
+ * Creates a direct message channel with a single user.
79
+ *
80
+ * @param peerId - The user ID to create a DM channel with
81
+ * @returns A promise that resolves to the created channel descriptor
82
+ */
83
+ createDM(peerId: string): Promise<ApiChannelDescription>;
84
+ /**
85
+ * Creates a group direct message channel with multiple users.
86
+ *
87
+ * @param userIds - Array of user IDs to include in the group DM
88
+ * @returns A promise that resolves to the created channel descriptor
89
+ */
90
+ createGroupDM(userIds: string[]): Promise<ApiChannelDescription>;
91
+ /**
92
+ * Refreshes the current session using the refresh token.
93
+ * Call this before the session expires to maintain connectivity.
94
+ *
95
+ * @returns A promise that resolves when the session is refreshed
96
+ */
97
+ refreshSession(): Promise<Session>;
98
+ /** A socket created with the client's configuration. */
99
+ createSocket(verbose?: boolean, adapter?: WebSocketAdapter, sendTimeoutMs?: number): Socket;
100
+ /**
101
+ * Called when a token refresh is initiated.
102
+ * This is a placeholder method that subclasses or instances can override
103
+ * to perform actions before or after the refresh logic.
104
+ */
105
+ onRefreshSession(session: ApiSession): void;
106
+ /**
107
+ * Checks if the current session token has expired.
108
+ *
109
+ * @returns True if the session is expired, false otherwise
110
+ */
111
+ isSessionExpired(): boolean;
112
+ /**
113
+ * Checks if the refresh token has expired.
114
+ * If this returns true, the user needs to re-authenticate.
115
+ *
116
+ * @returns True if the refresh token is expired, false otherwise
117
+ */
118
+ isRefreshSessionExpired(): boolean;
119
+ /**
120
+ * Gets the authentication token for external use.
121
+ */
122
+ getToken(): string;
123
+ /**
124
+ * Gets the refresh token for storage.
125
+ */
126
+ getRefreshToken(): string;
127
+ /**
128
+ * Gets the current session.
129
+ */
24
130
  getSession(): Session;
25
- getClient(): Client;
131
+ /**
132
+ * Exports session data for storage and later restoration.
133
+ *
134
+ * @returns Object containing all data needed to restore the session
135
+ */
136
+ exportSession(): ClientInitConfig;
26
137
  }
package/dist/client.js CHANGED
@@ -1,90 +1,267 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
2
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.LightClient = void 0;
27
- const mezon_js_1 = require("mezon-js");
3
+ exports.LightClient = exports.SessionError = exports.AuthenticationError = void 0;
4
+ const session_1 = require("./session");
5
+ const api_gen_1 = require("./api.gen");
28
6
  const constants_1 = require("./constants");
29
- const base64 = __importStar(require("js-base64"));
7
+ const web_socket_adapter_pb_1 = require("./web_socket_adapter_pb");
8
+ const socket_gen_1 = require("./socket.gen");
9
+ /**
10
+ * Error thrown when authentication fails.
11
+ */
12
+ class AuthenticationError extends Error {
13
+ constructor(message, statusCode) {
14
+ super(message ?? "Authentication failed.");
15
+ this.statusCode = statusCode;
16
+ this.name = "AuthenticationError";
17
+ }
18
+ }
19
+ exports.AuthenticationError = AuthenticationError;
20
+ /**
21
+ * Error thrown when session-related operations fail.
22
+ */
23
+ class SessionError extends Error {
24
+ constructor(message) {
25
+ super(message ?? "Session error.");
26
+ this.name = "SessionError";
27
+ }
28
+ }
29
+ exports.SessionError = SessionError;
30
+ /**
31
+ * Parses a URL and extracts client connection parameters.
32
+ */
33
+ function parseBaseUrl(apiUrl) {
34
+ const url = new URL(apiUrl);
35
+ const scheme = url.protocol === "https:" ? "https://" : "http://";
36
+ return `${scheme}${url.hostname}:${url.port}`;
37
+ }
38
+ /**
39
+ * LightClient provides a simplified interface for Mezon authentication and channel management.
40
+ *
41
+ * @example
42
+ * ```typescript
43
+ * // Initialize from existing tokens
44
+ * const client = LightClient.initClient({
45
+ * token: 'your-token',
46
+ * refresh_token: 'your-refresh-token',
47
+ * api_url: 'https://api.mezon.ai',
48
+ * user_id: 'user-123'
49
+ * });
50
+ *
51
+ * // Or authenticate with ID token
52
+ * const client = await LightClient.authenticate({
53
+ * id_token: 'id-token-from-provider',
54
+ * user_id: 'user-123',
55
+ * username: 'johndoe'
56
+ * });
57
+ * ```
58
+ */
30
59
  class LightClient {
31
- constructor(session, client, user_id) {
32
- this.session = session;
33
- this.client = client;
34
- this.user_id = user_id;
60
+ constructor(session, client, userId) {
61
+ /** Promise that resolves when the refresh token operation completes */
62
+ this.refreshTokenPromise = null;
63
+ this._session = session;
64
+ this._client = client;
65
+ this._userId = userId;
66
+ }
67
+ /**
68
+ * Gets the current user ID.
69
+ */
70
+ get userId() {
71
+ return this._userId;
35
72
  }
36
- static initClient({ token, refresh_token, api_url, user_id, serverkey }) {
73
+ /**
74
+ * Gets the underlying Mezon session.
75
+ */
76
+ get session() {
77
+ return this._session;
78
+ }
79
+ /**
80
+ * Gets the underlying Mezon client.
81
+ */
82
+ get client() {
83
+ return this._client;
84
+ }
85
+ /**
86
+ * Initializes a LightClient from existing session tokens.
87
+ * Use this when you have stored tokens from a previous authentication.
88
+ *
89
+ * @param config - Configuration containing tokens and connection details
90
+ * @returns A new LightClient instance
91
+ * @throws {SessionError} If required fields are missing
92
+ */
93
+ static initClient(config) {
94
+ const { token, refresh_token, api_url, user_id, serverkey } = config;
37
95
  if (!token || !refresh_token || !api_url || !user_id) {
38
- throw new Error('Missing required fields to restore session from storage');
96
+ throw new SessionError("Missing required fields: token, refresh_token, api_url, and user_id are all required");
39
97
  }
40
- const session = mezon_js_1.Session.restore(token, refresh_token, api_url, true);
41
- const url = new URL(api_url);
42
- const client = new mezon_js_1.Client(serverkey || 'DefaultServerKey', url.hostname, url.port || '', url.protocol === 'https:');
98
+ const session = session_1.Session.restore(token, refresh_token, api_url, true);
99
+ const client = new api_gen_1.MezonApi(serverkey || constants_1.DEFAULT_SERVER_KEY, 7000, parseBaseUrl(api_url));
43
100
  return new LightClient(session, client, user_id);
44
101
  }
45
- static async authenticate({ id_token, user_id, username, serverkey }) {
46
- const res = await fetch(constants_1.MEZON_GW_URL + '/v2/account/authenticate/idtoken', {
47
- method: 'POST',
48
- headers: {
49
- 'Content-Type': 'application/json',
50
- 'Authorization': 'Basic ' + base64.encode(serverkey || 'DefaultServerKey')
51
- },
52
- body: JSON.stringify({ id_token, user_id, username })
53
- });
54
- if (!res.ok) {
55
- const errData = await res.json().catch(() => ({}));
56
- throw new Error(errData.message || 'Error during authentication request');
102
+ /**
103
+ * Authenticates a user with an ID token from an identity provider.
104
+ *
105
+ * @param config - Authentication configuration
106
+ * @returns A promise that resolves to a new LightClient instance
107
+ * @throws {AuthenticationError} If authentication fails or response is invalid
108
+ */
109
+ static async authenticate(config) {
110
+ const { id_token, user_id, username, serverkey = constants_1.DEFAULT_SERVER_KEY, gateway_url = constants_1.MEZON_GW_URL } = config;
111
+ const client = new api_gen_1.MezonApi(serverkey || constants_1.DEFAULT_SERVER_KEY, 7000, parseBaseUrl(gateway_url));
112
+ const body = {
113
+ id_token,
114
+ user_id,
115
+ username,
116
+ };
117
+ const response = await client.authenticateIdToken(serverkey, "", body);
118
+ if (!response) {
119
+ throw new AuthenticationError("Authentication failed: No response from server.");
57
120
  }
58
- const data = await res.json();
59
- if (data && data.token && data.refresh_token && data.api_url && data.user_id) {
60
- const session = mezon_js_1.Session.restore(data.token, data.refresh_token, data.api_url, true);
61
- const url = new URL(data.api_url);
62
- const client = new mezon_js_1.Client(serverkey || 'DefaultServerKey', url.hostname, url.port || '', url.protocol === 'https:');
63
- return new LightClient(session, client, data.user_id);
64
- }
65
- else {
66
- throw new Error('Error during authentication or missing data fields!');
121
+ if (!response.token || !response.refresh_token || !response.api_url || !response.user_id) {
122
+ throw new AuthenticationError("Invalid authentication response: missing required fields");
67
123
  }
124
+ const session = session_1.Session.restore(response.token, response.refresh_token, response.api_url, true);
125
+ client.setBasePath(parseBaseUrl(response.api_url));
126
+ return new LightClient(session, client, response.user_id);
68
127
  }
69
- async createDM(peer_id) {
70
- const req = { type: mezon_js_1.ChannelType.CHANNEL_TYPE_DM, channel_private: 1, user_ids: [peer_id] };
71
- const channel = await this.client.createChannelDesc(this.session, req);
72
- return channel;
128
+ /**
129
+ * Creates a direct message channel with a single user.
130
+ *
131
+ * @param peerId - The user ID to create a DM channel with
132
+ * @returns A promise that resolves to the created channel descriptor
133
+ */
134
+ async createDM(peerId) {
135
+ const request = {
136
+ type: constants_1.CHANNEL_TYPE_DM,
137
+ channel_private: 1,
138
+ user_ids: [peerId],
139
+ };
140
+ return this._client.createChannelDesc(this._session.token, request);
73
141
  }
142
+ /**
143
+ * Creates a group direct message channel with multiple users.
144
+ *
145
+ * @param userIds - Array of user IDs to include in the group DM
146
+ * @returns A promise that resolves to the created channel descriptor
147
+ */
148
+ async createGroupDM(userIds) {
149
+ if (userIds.length === 0) {
150
+ throw new Error("At least one user ID is required for a group DM");
151
+ }
152
+ const request = {
153
+ type: constants_1.CHANNEL_TYPE_GROUP,
154
+ channel_private: 1,
155
+ user_ids: userIds,
156
+ };
157
+ return this._client.createChannelDesc(this._session.token, request);
158
+ }
159
+ /**
160
+ * Refreshes the current session using the refresh token.
161
+ * Call this before the session expires to maintain connectivity.
162
+ *
163
+ * @returns A promise that resolves when the session is refreshed
164
+ */
74
165
  async refreshSession() {
75
- await this.client.sessionRefresh(this.session);
166
+ if (!this._session) {
167
+ console.error("Cannot refresh a null session.");
168
+ return this._session;
169
+ }
170
+ if (this._session.created && this._session.expires_at - this._session.created_at < 70) {
171
+ console.warn("Session lifetime too short, please set '--session.token_expiry_sec' option. See the documentation for more info: https://mezon.vn/docs/mezon/getting-started/configuration/#session");
172
+ }
173
+ if (this._session.created && this._session.refresh_expires_at - this._session.created_at < 3700) {
174
+ console.warn("Session refresh lifetime too short, please set '--session.refresh_token_expiry_sec' option. See the documentation for more info: https://mezon.vn/docs/mezon/getting-started/configuration/#session");
175
+ }
176
+ if (this.refreshTokenPromise) {
177
+ return this.refreshTokenPromise;
178
+ }
179
+ this.refreshTokenPromise = new Promise(async (resolve, reject) => {
180
+ try {
181
+ const apiSession = await this.client.sessionRefresh(this._client.serverKey || constants_1.DEFAULT_SERVER_KEY, "", {
182
+ token: this._session.refresh_token,
183
+ vars: this._session.vars,
184
+ is_remember: this._session.is_remember,
185
+ });
186
+ this._session.update(apiSession.token, apiSession.refresh_token, apiSession.is_remember || false);
187
+ this.onRefreshSession(apiSession);
188
+ resolve(this._session);
189
+ }
190
+ catch (error) {
191
+ console.error("Session refresh failed:", error);
192
+ reject(error);
193
+ }
194
+ finally {
195
+ this.refreshTokenPromise = null;
196
+ }
197
+ });
198
+ return this.refreshTokenPromise;
199
+ }
200
+ /** A socket created with the client's configuration. */
201
+ createSocket(verbose = false, adapter = new web_socket_adapter_pb_1.WebSocketAdapterPb(), sendTimeoutMs = socket_gen_1.DefaultSocket.DefaultSendTimeoutMs) {
202
+ const url = new URL(this._client.basePath);
203
+ const { host, port, useSSL } = {
204
+ host: url.hostname,
205
+ port: url.port || (url.protocol === "https:" ? "443" : "80"),
206
+ useSSL: url.protocol === "https:",
207
+ };
208
+ return new socket_gen_1.DefaultSocket(host, port, useSSL, verbose, adapter, sendTimeoutMs);
209
+ }
210
+ /**
211
+ * Called when a token refresh is initiated.
212
+ * This is a placeholder method that subclasses or instances can override
213
+ * to perform actions before or after the refresh logic.
214
+ */
215
+ onRefreshSession(session) {
216
+ console.log(`Token refresh occurred. Token: ${session.token}`);
217
+ }
218
+ /**
219
+ * Checks if the current session token has expired.
220
+ *
221
+ * @returns True if the session is expired, false otherwise
222
+ */
223
+ isSessionExpired() {
224
+ return this._session.isexpired(Date.now() / 1000);
225
+ }
226
+ /**
227
+ * Checks if the refresh token has expired.
228
+ * If this returns true, the user needs to re-authenticate.
229
+ *
230
+ * @returns True if the refresh token is expired, false otherwise
231
+ */
232
+ isRefreshSessionExpired() {
233
+ return this._session.isrefreshexpired(Date.now() / 1000);
76
234
  }
77
- async isSessionExpired() {
78
- return this.session.isexpired(Date.now() / 1000);
235
+ /**
236
+ * Gets the authentication token for external use.
237
+ */
238
+ getToken() {
239
+ return this._session.token;
79
240
  }
80
- async isRefreshSessionExpired() {
81
- return this.session.isrefreshexpired(Date.now() / 1000);
241
+ /**
242
+ * Gets the refresh token for storage.
243
+ */
244
+ getRefreshToken() {
245
+ return this._session.refresh_token;
82
246
  }
247
+ /**
248
+ * Gets the current session.
249
+ */
83
250
  getSession() {
84
251
  return this.session;
85
252
  }
86
- getClient() {
87
- return this.client;
253
+ /**
254
+ * Exports session data for storage and later restoration.
255
+ *
256
+ * @returns Object containing all data needed to restore the session
257
+ */
258
+ exportSession() {
259
+ return {
260
+ token: this._session.token,
261
+ refresh_token: this._session.refresh_token,
262
+ api_url: this._session.api_url || "",
263
+ user_id: this._userId,
264
+ };
88
265
  }
89
266
  }
90
267
  exports.LightClient = LightClient;
@@ -1,4 +1,16 @@
1
+ /** Default Mezon Gateway URL */
1
2
  export declare const MEZON_GW_URL = "https://gw.mezon.ai";
3
+ /** Maximum number of retries when waiting for socket to be ready */
2
4
  export declare const SOCKET_READY_MAX_RETRY = 20;
5
+ /** Initial delay in milliseconds between socket ready retries (uses exponential backoff) */
3
6
  export declare const SOCKET_READY_RETRY_DELAY = 100;
7
+ /** Clan ID used for Direct Messages */
4
8
  export declare const CLAN_DM = "0";
9
+ /** Channel type for Direct Messages */
10
+ export declare const CHANNEL_TYPE_DM = 3;
11
+ export declare const CHANNEL_TYPE_GROUP = 2;
12
+ /** Stream mode for Direct Messages */
13
+ export declare const STREAM_MODE_DM = 4;
14
+ export declare const STREAM_MODE_GROUP = 3;
15
+ /** Default server key if none is provided */
16
+ export declare const DEFAULT_SERVER_KEY = "DefaultServerKey";
package/dist/constants.js CHANGED
@@ -1,7 +1,19 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CLAN_DM = exports.SOCKET_READY_RETRY_DELAY = exports.SOCKET_READY_MAX_RETRY = exports.MEZON_GW_URL = void 0;
3
+ exports.DEFAULT_SERVER_KEY = exports.STREAM_MODE_GROUP = exports.STREAM_MODE_DM = exports.CHANNEL_TYPE_GROUP = exports.CHANNEL_TYPE_DM = exports.CLAN_DM = exports.SOCKET_READY_RETRY_DELAY = exports.SOCKET_READY_MAX_RETRY = exports.MEZON_GW_URL = void 0;
4
+ /** Default Mezon Gateway URL */
4
5
  exports.MEZON_GW_URL = 'https://gw.mezon.ai';
6
+ /** Maximum number of retries when waiting for socket to be ready */
5
7
  exports.SOCKET_READY_MAX_RETRY = 20;
8
+ /** Initial delay in milliseconds between socket ready retries (uses exponential backoff) */
6
9
  exports.SOCKET_READY_RETRY_DELAY = 100;
10
+ /** Clan ID used for Direct Messages */
7
11
  exports.CLAN_DM = '0';
12
+ /** Channel type for Direct Messages */
13
+ exports.CHANNEL_TYPE_DM = 3;
14
+ exports.CHANNEL_TYPE_GROUP = 2;
15
+ /** Stream mode for Direct Messages */
16
+ exports.STREAM_MODE_DM = 4;
17
+ exports.STREAM_MODE_GROUP = 3;
18
+ /** Default server key if none is provided */
19
+ exports.DEFAULT_SERVER_KEY = 'DefaultServerKey';