| 671 | } |
| 672 | |
| 673 | async lookupUser(q: UserQuery): Promise<PlatformUser | undefined> { |
| 674 | const query = q.query.trim().toLowerCase(); |
| 675 | if (!query) return undefined; |
| 676 | try { |
| 677 | let cursor: string | undefined; |
| 678 | do { |
| 679 | const r = (await this.client.users.list({ cursor, limit: 200 })) as { |
| 680 | members?: Array<{ |
| 681 | id?: string; |
| 682 | name?: string; |
| 683 | real_name?: string; |
| 684 | deleted?: boolean; |
| 685 | is_bot?: boolean; |
| 686 | profile?: { display_name?: string; email?: string }; |
| 687 | }>; |
| 688 | response_metadata?: { next_cursor?: string }; |
| 689 | }; |
| 690 | for (const m of r.members ?? []) { |
| 691 | if (!m.id || m.deleted || m.is_bot) continue; |
| 692 | const candidates = [ |
| 693 | m.name, |
| 694 | m.real_name, |
| 695 | m.profile?.display_name, |
| 696 | m.profile?.email, |
| 697 | ] |
| 698 | .filter((s): s is string => Boolean(s)) |
| 699 | .map((s) => s.toLowerCase()); |
| 700 | if (candidates.some((c) => c === query || c.startsWith(query))) { |
| 701 | return { |
| 702 | id: m.id, |
| 703 | name: m.real_name ?? m.name, |
| 704 | handle: m.name, |
| 705 | email: m.profile?.email, |
| 706 | }; |
| 707 | } |
| 708 | } |
| 709 | cursor = r.response_metadata?.next_cursor || undefined; |
| 710 | } while (cursor); |
| 711 | } catch { |
| 712 | return undefined; |
| 713 | } |
| 714 | return undefined; |
| 715 | } |
| 716 | |
| 717 | /** |
| 718 | * Resolve a Slack user id to a richer `PlatformUser` (name + email) for each |