@meet-im/meet-bot-jssdk 1.0.0 → 1.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/dist/index.d.cts CHANGED
@@ -216,6 +216,37 @@ interface ReceivedAttachmentInfo {
216
216
  mimeType?: string;
217
217
  }
218
218
 
219
+ interface MeetUser {
220
+ userID: number;
221
+ nickName: string;
222
+ nickNamePinyin?: string;
223
+ aliasName?: string;
224
+ aliasNamePinyin?: string;
225
+ gender?: number;
226
+ birthday?: string;
227
+ avatar?: string;
228
+ avatarUrl?: string;
229
+ email?: string;
230
+ mobile?: string;
231
+ jobNumber?: string;
232
+ tag?: string;
233
+ tags?: string[];
234
+ companyId?: number;
235
+ status?: number;
236
+ statusMsg?: string[];
237
+ sourceType?: number;
238
+ employeeStatus?: number;
239
+ cleanStatus?: number;
240
+ deletedAt?: number;
241
+ isDepartmentAdmin?: boolean;
242
+ isHide?: boolean;
243
+ sort?: number;
244
+ oaUID?: number;
245
+ msgDelTimeStamp?: number;
246
+ userType?: number;
247
+ updatedAt?: number;
248
+ }
249
+
219
250
  declare class MeetBotError extends Error {
220
251
  readonly code: ErrorCode;
221
252
  constructor(message: string, code: ErrorCode);
@@ -227,10 +258,13 @@ declare class ApiError extends MeetBotError {
227
258
  }
228
259
  declare class NetworkError extends MeetBotError {
229
260
  readonly cause?: Error;
230
- constructor(message: string, cause?: Error);
261
+ readonly httpStatus?: number;
262
+ readonly responseSnippet?: string;
263
+ constructor(message: string, cause?: Error, httpStatus?: number, responseSnippet?: string);
231
264
  }
232
265
  declare class TimeoutError extends MeetBotError {
233
- constructor(message: string);
266
+ readonly isLocal: boolean;
267
+ constructor(message: string, isLocal?: boolean);
234
268
  }
235
269
  declare class ValidationError extends MeetBotError {
236
270
  readonly field: string;
@@ -238,6 +272,28 @@ declare class ValidationError extends MeetBotError {
238
272
  constructor(message: string, field: string, value: unknown);
239
273
  }
240
274
 
275
+ interface UserCacheOptions {
276
+ ttl?: number;
277
+ }
278
+ declare class UserCache {
279
+ private byId;
280
+ private byNickName;
281
+ private byAliasName;
282
+ private loadedAt;
283
+ private readonly ttl;
284
+ private loading;
285
+ constructor(options?: UserCacheOptions);
286
+ isExpired(): boolean;
287
+ load(fetchAll: () => Promise<MeetUser[]>): Promise<void>;
288
+ private rebuild;
289
+ ensureLoaded(fetchAll: () => Promise<MeetUser[]>): Promise<void>;
290
+ getById(userId: number): MeetUser | undefined;
291
+ getByIds(userIds: number[]): Map<number, MeetUser>;
292
+ getByName(name: string): MeetUser[];
293
+ searchByName(query: string): MeetUser[];
294
+ get size(): number;
295
+ }
296
+
241
297
  type EventHandler<T = unknown> = (data: T) => void;
242
298
  interface Events {
243
299
  message: {
@@ -258,7 +314,10 @@ declare class MeetBot {
258
314
  private polling;
259
315
  private offset;
260
316
  private abortController;
261
- constructor(config: MeetBotConfig);
317
+ private readonly userCache;
318
+ constructor(config: MeetBotConfig & {
319
+ userCacheOptions?: UserCacheOptions;
320
+ });
262
321
  on<K extends keyof Events>(event: K, handler: EventHandler<Events[K]>): this;
263
322
  off<K extends keyof Events>(event: K, handler: EventHandler<Events[K]>): this;
264
323
  private emit;
@@ -281,6 +340,12 @@ declare class MeetBot {
281
340
  getAccessURL(params: GetAccessURLParams | GetAccessURLBySessionParams): Promise<AccessURLResult>;
282
341
  uploadFile(buffer: Buffer, options: UploadFileOptions): Promise<UploadFileResult>;
283
342
  sendMedia(sessionInfo: SessionInfo, options: SendMediaOptions): Promise<SendMessageResult>;
343
+ refreshUserCache(): Promise<void>;
344
+ getUserById(userId: number): Promise<MeetUser | undefined>;
345
+ getUserByIds(userIds: number[]): Promise<Map<number, MeetUser>>;
346
+ getUserByName(name: string): Promise<MeetUser[]>;
347
+ searchUserByName(query: string): Promise<MeetUser[]>;
348
+ get userCacheSize(): number;
284
349
  private sleep;
285
350
  }
286
351
 
@@ -309,6 +374,11 @@ declare function computeMD5(buffer: Buffer): Promise<string>;
309
374
  declare function uploadFile(token: string, buffer: Buffer, options: UploadFileOptions, baseUrl?: string): Promise<UploadFileResult>;
310
375
  declare function sendMediaMessage(token: string, sessionInfo: SessionInfo, options: SendMediaOptions, baseUrl?: string): Promise<SendMessageResult>;
311
376
 
377
+ declare function getUsers(params: {
378
+ token: string;
379
+ baseUrl?: string;
380
+ }): Promise<MeetUser[]>;
381
+
312
382
  interface GetUpdatesParams {
313
383
  token: string;
314
384
  baseUrl?: string;
@@ -378,4 +448,4 @@ declare function getChunkNum(size: number): number;
378
448
  declare function getConvID(firstID: number, secondID: number, sessionType: number, companyID?: number): string;
379
449
  declare function getQuoteMsgKey(convID: string, seqID: number): string;
380
450
 
381
- export { API, type AccessURLResult, ApiError, type ApiErrorResponse, type ApiResponse, type AttachmentInfo, type BotChat, type BotFile, type BotMsg, type BotMsgUpdate, type BotUpdate, type BotUser, CHUNK_RULES, type ChatType, type CompleteMultipartUploadParams, type CompleteMultipartUploadResult, DEFAULT_BASE_URL, type ErrorCode, type ExtraInfo, type GetAccessURLBySessionParams, type GetAccessURLParams, type GetMultiPartUploadURLParams, type GetUpdatesOptions, type GetUpdatesV2Result, type GetUploadURLParams, HTTP, type LogLevel, MeetBot, type MeetBotConfig, MeetBotError, type MsgContent, type MsgType, type MultiPartUploadURLResult, NetworkError, POLLING, type PollingOptions, type QuoteMsgMap, type ReceivedAttachmentInfo, SESSION_TYPE, type SendMediaOptions, type SendMessageOptions, type SendMessageResult, type SessionInfo, type SessionType, TimeoutError, UPLOAD, type UploadFileOptions, type UploadFileResult, type UploadPart, type UploadProgress, type UploadURLResult, ValidationError, completeMultipartUpload, computeMD5, getAccessURL, getChunkNum, getConvID, getMultiPartUploadURL, getQuoteMsgKey, getUpdates, getUpdatesV2, getUploadURL, sendMediaMessage, sendMessage, uploadFile };
451
+ export { API, type AccessURLResult, ApiError, type ApiErrorResponse, type ApiResponse, type AttachmentInfo, type BotChat, type BotFile, type BotMsg, type BotMsgUpdate, type BotUpdate, type BotUser, CHUNK_RULES, type ChatType, type CompleteMultipartUploadParams, type CompleteMultipartUploadResult, DEFAULT_BASE_URL, type ErrorCode, type ExtraInfo, type GetAccessURLBySessionParams, type GetAccessURLParams, type GetMultiPartUploadURLParams, type GetUpdatesOptions, type GetUpdatesV2Result, type GetUploadURLParams, HTTP, type LogLevel, MeetBot, type MeetBotConfig, MeetBotError, type MeetUser, type MsgContent, type MsgType, type MultiPartUploadURLResult, NetworkError, POLLING, type PollingOptions, type QuoteMsgMap, type ReceivedAttachmentInfo, SESSION_TYPE, type SendMediaOptions, type SendMessageOptions, type SendMessageResult, type SessionInfo, type SessionType, TimeoutError, UPLOAD, type UploadFileOptions, type UploadFileResult, type UploadPart, type UploadProgress, type UploadURLResult, UserCache, type UserCacheOptions, ValidationError, completeMultipartUpload, computeMD5, getAccessURL, getChunkNum, getConvID, getMultiPartUploadURL, getQuoteMsgKey, getUpdates, getUpdatesV2, getUploadURL, getUsers, sendMediaMessage, sendMessage, uploadFile };
package/dist/index.d.ts CHANGED
@@ -216,6 +216,37 @@ interface ReceivedAttachmentInfo {
216
216
  mimeType?: string;
217
217
  }
218
218
 
219
+ interface MeetUser {
220
+ userID: number;
221
+ nickName: string;
222
+ nickNamePinyin?: string;
223
+ aliasName?: string;
224
+ aliasNamePinyin?: string;
225
+ gender?: number;
226
+ birthday?: string;
227
+ avatar?: string;
228
+ avatarUrl?: string;
229
+ email?: string;
230
+ mobile?: string;
231
+ jobNumber?: string;
232
+ tag?: string;
233
+ tags?: string[];
234
+ companyId?: number;
235
+ status?: number;
236
+ statusMsg?: string[];
237
+ sourceType?: number;
238
+ employeeStatus?: number;
239
+ cleanStatus?: number;
240
+ deletedAt?: number;
241
+ isDepartmentAdmin?: boolean;
242
+ isHide?: boolean;
243
+ sort?: number;
244
+ oaUID?: number;
245
+ msgDelTimeStamp?: number;
246
+ userType?: number;
247
+ updatedAt?: number;
248
+ }
249
+
219
250
  declare class MeetBotError extends Error {
220
251
  readonly code: ErrorCode;
221
252
  constructor(message: string, code: ErrorCode);
@@ -227,10 +258,13 @@ declare class ApiError extends MeetBotError {
227
258
  }
228
259
  declare class NetworkError extends MeetBotError {
229
260
  readonly cause?: Error;
230
- constructor(message: string, cause?: Error);
261
+ readonly httpStatus?: number;
262
+ readonly responseSnippet?: string;
263
+ constructor(message: string, cause?: Error, httpStatus?: number, responseSnippet?: string);
231
264
  }
232
265
  declare class TimeoutError extends MeetBotError {
233
- constructor(message: string);
266
+ readonly isLocal: boolean;
267
+ constructor(message: string, isLocal?: boolean);
234
268
  }
235
269
  declare class ValidationError extends MeetBotError {
236
270
  readonly field: string;
@@ -238,6 +272,28 @@ declare class ValidationError extends MeetBotError {
238
272
  constructor(message: string, field: string, value: unknown);
239
273
  }
240
274
 
275
+ interface UserCacheOptions {
276
+ ttl?: number;
277
+ }
278
+ declare class UserCache {
279
+ private byId;
280
+ private byNickName;
281
+ private byAliasName;
282
+ private loadedAt;
283
+ private readonly ttl;
284
+ private loading;
285
+ constructor(options?: UserCacheOptions);
286
+ isExpired(): boolean;
287
+ load(fetchAll: () => Promise<MeetUser[]>): Promise<void>;
288
+ private rebuild;
289
+ ensureLoaded(fetchAll: () => Promise<MeetUser[]>): Promise<void>;
290
+ getById(userId: number): MeetUser | undefined;
291
+ getByIds(userIds: number[]): Map<number, MeetUser>;
292
+ getByName(name: string): MeetUser[];
293
+ searchByName(query: string): MeetUser[];
294
+ get size(): number;
295
+ }
296
+
241
297
  type EventHandler<T = unknown> = (data: T) => void;
242
298
  interface Events {
243
299
  message: {
@@ -258,7 +314,10 @@ declare class MeetBot {
258
314
  private polling;
259
315
  private offset;
260
316
  private abortController;
261
- constructor(config: MeetBotConfig);
317
+ private readonly userCache;
318
+ constructor(config: MeetBotConfig & {
319
+ userCacheOptions?: UserCacheOptions;
320
+ });
262
321
  on<K extends keyof Events>(event: K, handler: EventHandler<Events[K]>): this;
263
322
  off<K extends keyof Events>(event: K, handler: EventHandler<Events[K]>): this;
264
323
  private emit;
@@ -281,6 +340,12 @@ declare class MeetBot {
281
340
  getAccessURL(params: GetAccessURLParams | GetAccessURLBySessionParams): Promise<AccessURLResult>;
282
341
  uploadFile(buffer: Buffer, options: UploadFileOptions): Promise<UploadFileResult>;
283
342
  sendMedia(sessionInfo: SessionInfo, options: SendMediaOptions): Promise<SendMessageResult>;
343
+ refreshUserCache(): Promise<void>;
344
+ getUserById(userId: number): Promise<MeetUser | undefined>;
345
+ getUserByIds(userIds: number[]): Promise<Map<number, MeetUser>>;
346
+ getUserByName(name: string): Promise<MeetUser[]>;
347
+ searchUserByName(query: string): Promise<MeetUser[]>;
348
+ get userCacheSize(): number;
284
349
  private sleep;
285
350
  }
286
351
 
@@ -309,6 +374,11 @@ declare function computeMD5(buffer: Buffer): Promise<string>;
309
374
  declare function uploadFile(token: string, buffer: Buffer, options: UploadFileOptions, baseUrl?: string): Promise<UploadFileResult>;
310
375
  declare function sendMediaMessage(token: string, sessionInfo: SessionInfo, options: SendMediaOptions, baseUrl?: string): Promise<SendMessageResult>;
311
376
 
377
+ declare function getUsers(params: {
378
+ token: string;
379
+ baseUrl?: string;
380
+ }): Promise<MeetUser[]>;
381
+
312
382
  interface GetUpdatesParams {
313
383
  token: string;
314
384
  baseUrl?: string;
@@ -378,4 +448,4 @@ declare function getChunkNum(size: number): number;
378
448
  declare function getConvID(firstID: number, secondID: number, sessionType: number, companyID?: number): string;
379
449
  declare function getQuoteMsgKey(convID: string, seqID: number): string;
380
450
 
381
- export { API, type AccessURLResult, ApiError, type ApiErrorResponse, type ApiResponse, type AttachmentInfo, type BotChat, type BotFile, type BotMsg, type BotMsgUpdate, type BotUpdate, type BotUser, CHUNK_RULES, type ChatType, type CompleteMultipartUploadParams, type CompleteMultipartUploadResult, DEFAULT_BASE_URL, type ErrorCode, type ExtraInfo, type GetAccessURLBySessionParams, type GetAccessURLParams, type GetMultiPartUploadURLParams, type GetUpdatesOptions, type GetUpdatesV2Result, type GetUploadURLParams, HTTP, type LogLevel, MeetBot, type MeetBotConfig, MeetBotError, type MsgContent, type MsgType, type MultiPartUploadURLResult, NetworkError, POLLING, type PollingOptions, type QuoteMsgMap, type ReceivedAttachmentInfo, SESSION_TYPE, type SendMediaOptions, type SendMessageOptions, type SendMessageResult, type SessionInfo, type SessionType, TimeoutError, UPLOAD, type UploadFileOptions, type UploadFileResult, type UploadPart, type UploadProgress, type UploadURLResult, ValidationError, completeMultipartUpload, computeMD5, getAccessURL, getChunkNum, getConvID, getMultiPartUploadURL, getQuoteMsgKey, getUpdates, getUpdatesV2, getUploadURL, sendMediaMessage, sendMessage, uploadFile };
451
+ export { API, type AccessURLResult, ApiError, type ApiErrorResponse, type ApiResponse, type AttachmentInfo, type BotChat, type BotFile, type BotMsg, type BotMsgUpdate, type BotUpdate, type BotUser, CHUNK_RULES, type ChatType, type CompleteMultipartUploadParams, type CompleteMultipartUploadResult, DEFAULT_BASE_URL, type ErrorCode, type ExtraInfo, type GetAccessURLBySessionParams, type GetAccessURLParams, type GetMultiPartUploadURLParams, type GetUpdatesOptions, type GetUpdatesV2Result, type GetUploadURLParams, HTTP, type LogLevel, MeetBot, type MeetBotConfig, MeetBotError, type MeetUser, type MsgContent, type MsgType, type MultiPartUploadURLResult, NetworkError, POLLING, type PollingOptions, type QuoteMsgMap, type ReceivedAttachmentInfo, SESSION_TYPE, type SendMediaOptions, type SendMessageOptions, type SendMessageResult, type SessionInfo, type SessionType, TimeoutError, UPLOAD, type UploadFileOptions, type UploadFileResult, type UploadPart, type UploadProgress, type UploadURLResult, UserCache, type UserCacheOptions, ValidationError, completeMultipartUpload, computeMD5, getAccessURL, getChunkNum, getConvID, getMultiPartUploadURL, getQuoteMsgKey, getUpdates, getUpdatesV2, getUploadURL, getUsers, sendMediaMessage, sendMessage, uploadFile };
package/dist/index.js CHANGED
@@ -44,16 +44,34 @@ var init_error = __esm({
44
44
  };
45
45
  NetworkError = class extends MeetBotError {
46
46
  cause;
47
- constructor(message, cause) {
47
+ /**
48
+ * HTTP 状态码(如果有的话)
49
+ * 例如:504 表示网关超时,0 表示无 HTTP 响应
50
+ */
51
+ httpStatus;
52
+ /**
53
+ * 响应内容片段(用于调试)
54
+ */
55
+ responseSnippet;
56
+ constructor(message, cause, httpStatus, responseSnippet) {
48
57
  super(message, "NETWORK_ERROR");
49
58
  this.name = "NetworkError";
50
59
  this.cause = cause;
60
+ this.httpStatus = httpStatus;
61
+ this.responseSnippet = responseSnippet;
51
62
  }
52
63
  };
53
64
  TimeoutError = class extends MeetBotError {
54
- constructor(message) {
65
+ /**
66
+ * 是否为本地客户端超时(AbortController 触发)
67
+ * true: 本地 HTTP 请求超时
68
+ * false: 服务端/网关返回的超时(如 504 Gateway Timeout)
69
+ */
70
+ isLocal;
71
+ constructor(message, isLocal = true) {
55
72
  super(message, "TIMEOUT_ERROR");
56
73
  this.name = "TimeoutError";
74
+ this.isLocal = isLocal;
57
75
  }
58
76
  };
59
77
  ValidationError = class extends MeetBotError {
@@ -196,8 +214,8 @@ function extractBotToken(token) {
196
214
  const parts = token.split(":");
197
215
  return parts.length >= 2 ? parts.slice(1).join(":") : token;
198
216
  }
199
- function buildUrl(baseUrl, path, params) {
200
- const url = new URL(`/im/bot/${path}`, baseUrl);
217
+ function buildUrl(baseUrl, path, pathPrefix, params) {
218
+ const url = new URL(`${pathPrefix}${path}`, baseUrl);
201
219
  if (params) {
202
220
  for (const [key, value] of Object.entries(params)) {
203
221
  if (value !== void 0) {
@@ -208,9 +226,19 @@ function buildUrl(baseUrl, path, params) {
208
226
  return url.toString();
209
227
  }
210
228
  async function request(options) {
211
- const { token, baseUrl, method = "GET", path, params, body, timeout = HTTP.DEFAULT_TIMEOUT } = options;
229
+ const {
230
+ token,
231
+ baseUrl,
232
+ method = "GET",
233
+ path,
234
+ pathPrefix = "/im/bot/",
235
+ params,
236
+ body,
237
+ timeout = HTTP.DEFAULT_TIMEOUT,
238
+ raw = false
239
+ } = options;
212
240
  validateToken(token);
213
- const url = buildUrl(baseUrl || DEFAULT_BASE_URL, path, method === "GET" ? params : void 0);
241
+ const url = buildUrl(baseUrl || DEFAULT_BASE_URL, path, pathPrefix, method === "GET" ? params : void 0);
214
242
  const controller = new AbortController();
215
243
  const timeoutId = setTimeout(() => controller.abort(), timeout);
216
244
  const headers = {
@@ -239,18 +267,40 @@ async function request(options) {
239
267
  const responseText = await response.text();
240
268
  if (!contentType.includes("application/json")) {
241
269
  logger.error("[Response] Non-JSON response:", responseText.substring(0, 500));
242
- throw new NetworkError(`Server returned non-JSON response (status ${response.status})`, void 0);
270
+ if (response.status === 504) {
271
+ throw new TimeoutError(`Gateway timeout (status ${response.status})`, false);
272
+ }
273
+ throw new NetworkError(
274
+ `Server returned non-JSON response (status ${response.status})`,
275
+ void 0,
276
+ response.status,
277
+ responseText.substring(0, 200)
278
+ );
243
279
  }
244
280
  let data;
245
281
  try {
246
282
  data = JSON.parse(responseText);
247
283
  } catch {
248
284
  logger.error("[Response] Failed to parse JSON:", responseText.substring(0, 500));
249
- throw new NetworkError("Failed to parse server response", void 0);
285
+ throw new NetworkError(
286
+ "Failed to parse server response",
287
+ void 0,
288
+ response.status,
289
+ responseText.substring(0, 200)
290
+ );
250
291
  }
251
292
  logger.info("[Response Body]", JSON.stringify(data));
293
+ if (raw) {
294
+ return data;
295
+ }
252
296
  if (!response.ok || !data.ok) {
253
297
  const errorData = data;
298
+ if (response.status === 504) {
299
+ throw new TimeoutError(
300
+ errorData.description || `Gateway timeout (status ${response.status})`,
301
+ false
302
+ );
303
+ }
254
304
  throw new ApiError(
255
305
  errorData.description || `HTTP ${response.status}`,
256
306
  response.status,
@@ -266,7 +316,7 @@ async function request(options) {
266
316
  }
267
317
  if (error instanceof Error) {
268
318
  if (error.name === "AbortError") {
269
- throw new TimeoutError(`Request timeout after ${timeout}ms`);
319
+ throw new TimeoutError(`Request timeout after ${timeout}ms`, true);
270
320
  }
271
321
  throw new NetworkError(`Network error: ${error.message}`, error);
272
322
  }
@@ -541,6 +591,25 @@ async function sendMediaMessage(token, sessionInfo, options, baseUrl) {
541
591
  });
542
592
  }
543
593
 
594
+ // src/api/user.ts
595
+ async function getUsers(params) {
596
+ const { token, baseUrl } = params;
597
+ const result = await request({
598
+ token,
599
+ baseUrl,
600
+ method: "POST",
601
+ path: "general/SyncCompanyUser",
602
+ pathPrefix: "/",
603
+ body: { syncAt: 0 },
604
+ timeout: HTTP.DEFAULT_TIMEOUT,
605
+ raw: true
606
+ });
607
+ return Object.values(result.users).map((user) => ({
608
+ userID: user.userID,
609
+ nickName: user.nickName
610
+ }));
611
+ }
612
+
544
613
  // src/api/index.ts
545
614
  async function getUpdates(params) {
546
615
  const { token, baseUrl, timeout = API.DEFAULT_TIMEOUT, offset, limit = API.DEFAULT_LIMIT } = params;
@@ -593,6 +662,115 @@ async function sendMessage(params) {
593
662
 
594
663
  // src/client.ts
595
664
  init_error();
665
+
666
+ // src/user-cache.ts
667
+ var UserCache = class {
668
+ byId = /* @__PURE__ */ new Map();
669
+ byNickName = /* @__PURE__ */ new Map();
670
+ byAliasName = /* @__PURE__ */ new Map();
671
+ loadedAt = 0;
672
+ ttl;
673
+ loading = null;
674
+ constructor(options) {
675
+ this.ttl = options?.ttl ?? 60 * 60 * 1e3;
676
+ }
677
+ isExpired() {
678
+ return this.byId.size === 0 || this.ttl > 0 && Date.now() - this.loadedAt > this.ttl;
679
+ }
680
+ async load(fetchAll) {
681
+ if (this.loading) {
682
+ return this.loading;
683
+ }
684
+ this.loading = (async () => {
685
+ try {
686
+ const users = await fetchAll();
687
+ this.rebuild(users);
688
+ logger.info(`\u7528\u6237\u7F13\u5B58\u5DF2\u52A0\u8F7D\uFF0C\u5171 ${users.length} \u4E2A\u7528\u6237`);
689
+ } finally {
690
+ this.loading = null;
691
+ }
692
+ })();
693
+ return this.loading;
694
+ }
695
+ rebuild(users) {
696
+ this.byId.clear();
697
+ this.byNickName.clear();
698
+ this.byAliasName.clear();
699
+ for (const user of users) {
700
+ this.byId.set(user.userID, user);
701
+ const nickKey = user.nickName.toLowerCase();
702
+ let nickList = this.byNickName.get(nickKey);
703
+ if (!nickList) {
704
+ nickList = [];
705
+ this.byNickName.set(nickKey, nickList);
706
+ }
707
+ nickList.push(user);
708
+ if (user.aliasName) {
709
+ const aliasKey = user.aliasName.toLowerCase();
710
+ let aliasList = this.byAliasName.get(aliasKey);
711
+ if (!aliasList) {
712
+ aliasList = [];
713
+ this.byAliasName.set(aliasKey, aliasList);
714
+ }
715
+ aliasList.push(user);
716
+ }
717
+ }
718
+ this.loadedAt = Date.now();
719
+ }
720
+ async ensureLoaded(fetchAll) {
721
+ if (!this.isExpired()) return;
722
+ await this.load(fetchAll);
723
+ }
724
+ getById(userId) {
725
+ return this.byId.get(userId);
726
+ }
727
+ getByIds(userIds) {
728
+ const result = /* @__PURE__ */ new Map();
729
+ for (const id of userIds) {
730
+ const user = this.byId.get(id);
731
+ if (user) {
732
+ result.set(id, user);
733
+ }
734
+ }
735
+ return result;
736
+ }
737
+ getByName(name) {
738
+ const key = name.toLowerCase();
739
+ const byNick = this.byNickName.get(key);
740
+ const byAlias = this.byAliasName.get(key);
741
+ if (!byNick && !byAlias) return [];
742
+ if (!byNick) return [...byAlias];
743
+ if (!byAlias) return [...byNick];
744
+ const seen = /* @__PURE__ */ new Set();
745
+ const result = [];
746
+ for (const u of [...byNick, ...byAlias]) {
747
+ if (!seen.has(u.userID)) {
748
+ seen.add(u.userID);
749
+ result.push(u);
750
+ }
751
+ }
752
+ return result;
753
+ }
754
+ searchByName(query) {
755
+ const q = query.toLowerCase();
756
+ const result = [];
757
+ const seen = /* @__PURE__ */ new Set();
758
+ for (const user of this.byId.values()) {
759
+ if (user.nickName.toLowerCase().includes(q) || user.aliasName && user.aliasName.toLowerCase().includes(q) || user.nickNamePinyin && user.nickNamePinyin.toLowerCase().includes(q) || user.aliasNamePinyin && user.aliasNamePinyin.toLowerCase().includes(q)) {
760
+ if (!seen.has(user.userID)) {
761
+ seen.add(user.userID);
762
+ result.push(user);
763
+ }
764
+ }
765
+ }
766
+ return result;
767
+ }
768
+ get size() {
769
+ return this.byId.size;
770
+ }
771
+ };
772
+
773
+ // src/client.ts
596
774
  var MeetBot = class {
597
775
  token;
598
776
  baseUrl;
@@ -603,6 +781,7 @@ var MeetBot = class {
603
781
  polling = false;
604
782
  offset = 0;
605
783
  abortController = null;
784
+ userCache;
606
785
  constructor(config) {
607
786
  if (config.token) {
608
787
  if (!config.token.includes(":")) {
@@ -618,6 +797,7 @@ var MeetBot = class {
618
797
  this.pollingLimit = config.pollingLimit ?? POLLING.DEFAULT_LIMIT;
619
798
  this.longPollingTimeout = config.longPollingTimeout ?? POLLING.DEFAULT_TIMEOUT;
620
799
  this.useV2 = config.useV2 ?? false;
800
+ this.userCache = new UserCache(config.userCacheOptions);
621
801
  logger.setLevel(config.logLevel ?? "silent");
622
802
  }
623
803
  on(event, handler) {
@@ -799,6 +979,56 @@ var MeetBot = class {
799
979
  async sendMedia(sessionInfo, options) {
800
980
  return sendMediaMessage(this.token, sessionInfo, options, this.baseUrl);
801
981
  }
982
+ /**
983
+ * 刷新用户缓存
984
+ */
985
+ async refreshUserCache() {
986
+ await this.userCache.load(async () => {
987
+ return getUsers({ token: this.token, baseUrl: this.baseUrl });
988
+ });
989
+ }
990
+ /**
991
+ * 根据用户 ID 获取用户信息
992
+ */
993
+ async getUserById(userId) {
994
+ await this.userCache.ensureLoaded(async () => {
995
+ return getUsers({ token: this.token, baseUrl: this.baseUrl });
996
+ });
997
+ return this.userCache.getById(userId);
998
+ }
999
+ /**
1000
+ * 批量根据用户 ID 获取用户信息
1001
+ */
1002
+ async getUserByIds(userIds) {
1003
+ await this.userCache.ensureLoaded(async () => {
1004
+ return getUsers({ token: this.token, baseUrl: this.baseUrl });
1005
+ });
1006
+ return this.userCache.getByIds(userIds);
1007
+ }
1008
+ /**
1009
+ * 根据昵称或别名精确查找用户
1010
+ */
1011
+ async getUserByName(name) {
1012
+ await this.userCache.ensureLoaded(async () => {
1013
+ return getUsers({ token: this.token, baseUrl: this.baseUrl });
1014
+ });
1015
+ return this.userCache.getByName(name);
1016
+ }
1017
+ /**
1018
+ * 根据昵称或别名模糊搜索用户
1019
+ */
1020
+ async searchUserByName(query) {
1021
+ await this.userCache.ensureLoaded(async () => {
1022
+ return getUsers({ token: this.token, baseUrl: this.baseUrl });
1023
+ });
1024
+ return this.userCache.searchByName(query);
1025
+ }
1026
+ /**
1027
+ * 获取缓存用户数
1028
+ */
1029
+ get userCacheSize() {
1030
+ return this.userCache.size;
1031
+ }
802
1032
  sleep(ms) {
803
1033
  return new Promise((resolve) => setTimeout(resolve, ms));
804
1034
  }
@@ -807,6 +1037,4 @@ var MeetBot = class {
807
1037
  // src/index.ts
808
1038
  init_error();
809
1039
 
810
- export { API, ApiError, CHUNK_RULES, DEFAULT_BASE_URL, HTTP, MeetBot, MeetBotError, NetworkError, POLLING, SESSION_TYPE, TimeoutError, UPLOAD, ValidationError, completeMultipartUpload, computeMD5, getAccessURL, getChunkNum, getConvID, getMultiPartUploadURL, getQuoteMsgKey, getUpdates, getUpdatesV2, getUploadURL, sendMediaMessage, sendMessage, uploadFile };
811
- //# sourceMappingURL=index.js.map
812
- //# sourceMappingURL=index.js.map
1040
+ export { API, ApiError, CHUNK_RULES, DEFAULT_BASE_URL, HTTP, MeetBot, MeetBotError, NetworkError, POLLING, SESSION_TYPE, TimeoutError, UPLOAD, UserCache, ValidationError, completeMultipartUpload, computeMD5, getAccessURL, getChunkNum, getConvID, getMultiPartUploadURL, getQuoteMsgKey, getUpdates, getUpdatesV2, getUploadURL, getUsers, sendMediaMessage, sendMessage, uploadFile };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meet-im/meet-bot-jssdk",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "MeetIM Chatbot JavaScript SDK - 支持 Long Polling 消息获取和消息发送",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",