@hybrd/xmtp 1.0.0 → 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.
Files changed (45) hide show
  1. package/.cache/tsbuildinfo.json +1 -1
  2. package/.turbo/turbo-build.log +5 -0
  3. package/.turbo/turbo-lint$colon$fix.log +6 -0
  4. package/dist/scripts/generate-keys.d.ts +1 -0
  5. package/dist/scripts/generate-keys.js +19 -0
  6. package/dist/scripts/refresh-identity.d.ts +1 -0
  7. package/dist/scripts/refresh-identity.js +93 -0
  8. package/dist/scripts/register-wallet.d.ts +1 -0
  9. package/dist/scripts/register-wallet.js +75 -0
  10. package/dist/scripts/revoke-all-installations.d.ts +2 -0
  11. package/dist/scripts/revoke-all-installations.js +68 -0
  12. package/dist/scripts/revoke-installations.d.ts +2 -0
  13. package/dist/scripts/revoke-installations.js +62 -0
  14. package/dist/src/abi/l2_resolver.d.ts +992 -0
  15. package/dist/src/abi/l2_resolver.js +699 -0
  16. package/dist/src/client.d.ts +76 -0
  17. package/dist/src/client.js +709 -0
  18. package/dist/src/constants.d.ts +3 -0
  19. package/dist/src/constants.js +6 -0
  20. package/dist/src/index.d.ts +22 -0
  21. package/dist/src/index.js +46 -0
  22. package/dist/src/lib/message-listener.d.ts +69 -0
  23. package/dist/src/lib/message-listener.js +235 -0
  24. package/dist/src/lib/message-listener.test.d.ts +1 -0
  25. package/dist/src/lib/message-listener.test.js +303 -0
  26. package/dist/src/lib/subjects.d.ts +24 -0
  27. package/dist/src/lib/subjects.js +68 -0
  28. package/dist/src/resolver/address-resolver.d.ts +57 -0
  29. package/dist/src/resolver/address-resolver.js +168 -0
  30. package/dist/src/resolver/basename-resolver.d.ts +134 -0
  31. package/dist/src/resolver/basename-resolver.js +409 -0
  32. package/dist/src/resolver/ens-resolver.d.ts +95 -0
  33. package/dist/src/resolver/ens-resolver.js +249 -0
  34. package/dist/src/resolver/index.d.ts +1 -0
  35. package/dist/src/resolver/index.js +1 -0
  36. package/dist/src/resolver/resolver.d.ts +162 -0
  37. package/dist/src/resolver/resolver.js +238 -0
  38. package/dist/src/resolver/xmtp-resolver.d.ts +95 -0
  39. package/dist/src/resolver/xmtp-resolver.js +297 -0
  40. package/dist/src/service-client.d.ts +77 -0
  41. package/dist/src/service-client.js +198 -0
  42. package/dist/src/types.d.ts +123 -0
  43. package/dist/src/types.js +5 -0
  44. package/package.json +5 -4
  45. package/tsconfig.json +3 -1
@@ -0,0 +1,249 @@
1
+ /**
2
+ * ENS Resolver for mainnet .eth names
3
+ * Handles resolution of ENS names to addresses and reverse resolution
4
+ */
5
+ export class ENSResolver {
6
+ constructor(options) {
7
+ this.cache = new Map();
8
+ this.reverseCache = new Map();
9
+ this.maxCacheSize = options.maxCacheSize ?? 500;
10
+ this.cacheTtl = options.cacheTtl ?? 3600000; // 1 hour
11
+ this.mainnetClient = options.mainnetClient;
12
+ }
13
+ /**
14
+ * Resolve an ENS name to an Ethereum address
15
+ */
16
+ async resolveENSName(ensName) {
17
+ console.log(`🔍 Resolving ENS name: ${ensName}`);
18
+ try {
19
+ // Check cache first
20
+ const cached = this.getCachedAddress(ensName);
21
+ if (cached) {
22
+ console.log(`✅ Resolved ENS from cache: ${ensName} → ${cached}`);
23
+ return cached;
24
+ }
25
+ console.log(`📭 No cached address found for ENS: ${ensName}`);
26
+ // Resolve using mainnet ENS
27
+ console.log("🔄 Reading ENS contract...");
28
+ const address = await this.mainnetClient.getEnsAddress({
29
+ name: ensName
30
+ });
31
+ console.log(`📋 ENS contract returned address: "${address}"`);
32
+ if (address && address !== "0x0000000000000000000000000000000000000000") {
33
+ this.setCachedAddress(ensName, address);
34
+ console.log(`✅ Resolved ENS: ${ensName} → ${address}`);
35
+ return address;
36
+ }
37
+ console.log(`❌ No address found for ENS: ${ensName}`);
38
+ return null;
39
+ }
40
+ catch (error) {
41
+ console.error(`❌ Error resolving ENS name ${ensName}:`, error);
42
+ if (error instanceof Error) {
43
+ console.error(`❌ Error details: ${error.message}`);
44
+ }
45
+ return null;
46
+ }
47
+ }
48
+ /**
49
+ * Resolve an address to its primary ENS name (reverse resolution)
50
+ */
51
+ async resolveAddressToENS(address) {
52
+ console.log(`🔍 Reverse resolving address to ENS: ${address}`);
53
+ try {
54
+ // Check cache first
55
+ const cached = this.getCachedENSName(address);
56
+ if (cached) {
57
+ console.log(`✅ Resolved ENS from reverse cache: ${address} → ${cached}`);
58
+ return cached;
59
+ }
60
+ console.log(`📭 No cached ENS name found for address: ${address}`);
61
+ // Reverse resolve using mainnet ENS
62
+ console.log("🔄 Reading ENS reverse resolver...");
63
+ const ensName = await this.mainnetClient.getEnsName({
64
+ address: address
65
+ });
66
+ console.log(`📋 ENS reverse resolver returned: "${ensName}"`);
67
+ if (ensName && ensName.length > 0) {
68
+ this.setCachedENSName(address, ensName);
69
+ console.log(`✅ Reverse resolved: ${address} → ${ensName}`);
70
+ return ensName;
71
+ }
72
+ console.log(`❌ No ENS name found for address: ${address}`);
73
+ return null;
74
+ }
75
+ catch (error) {
76
+ console.error(`❌ Error reverse resolving address ${address}:`, error);
77
+ if (error instanceof Error) {
78
+ console.error(`❌ Error details: ${error.message}`);
79
+ }
80
+ return null;
81
+ }
82
+ }
83
+ /**
84
+ * Get ENS avatar for a name
85
+ */
86
+ async getENSAvatar(ensName) {
87
+ console.log(`🖼️ Getting ENS avatar for: ${ensName}`);
88
+ try {
89
+ const avatar = await this.mainnetClient.getEnsAvatar({
90
+ name: ensName
91
+ });
92
+ if (avatar) {
93
+ console.log(`✅ Found ENS avatar: ${avatar}`);
94
+ return avatar;
95
+ }
96
+ console.log(`❌ No avatar found for ENS: ${ensName}`);
97
+ return null;
98
+ }
99
+ catch (error) {
100
+ console.error(`❌ Error getting ENS avatar for ${ensName}:`, error);
101
+ return null;
102
+ }
103
+ }
104
+ /**
105
+ * Get ENS text record
106
+ */
107
+ async getENSTextRecord(ensName, key) {
108
+ console.log(`📝 Getting ENS text record "${key}" for: ${ensName}`);
109
+ try {
110
+ const textRecord = await this.mainnetClient.getEnsText({
111
+ name: ensName,
112
+ key: key
113
+ });
114
+ if (textRecord && textRecord.length > 0) {
115
+ console.log(`✅ Found ENS text record: ${key}=${textRecord}`);
116
+ return textRecord;
117
+ }
118
+ console.log(`❌ No text record "${key}" found for ENS: ${ensName}`);
119
+ return null;
120
+ }
121
+ catch (error) {
122
+ console.error(`❌ Error getting ENS text record ${key} for ${ensName}:`, error);
123
+ return null;
124
+ }
125
+ }
126
+ /**
127
+ * Get comprehensive ENS profile
128
+ */
129
+ async getENSProfile(ensName) {
130
+ console.log(`👤 Getting ENS profile for: ${ensName}`);
131
+ try {
132
+ const [address, avatar, description, twitter, github, url] = await Promise.all([
133
+ this.resolveENSName(ensName),
134
+ this.getENSAvatar(ensName),
135
+ this.getENSTextRecord(ensName, "description"),
136
+ this.getENSTextRecord(ensName, "com.twitter"),
137
+ this.getENSTextRecord(ensName, "com.github"),
138
+ this.getENSTextRecord(ensName, "url")
139
+ ]);
140
+ const profile = {
141
+ ensName,
142
+ address,
143
+ avatar,
144
+ description,
145
+ twitter,
146
+ github,
147
+ url
148
+ };
149
+ console.log(`✅ ENS profile for ${ensName}:`, profile);
150
+ return profile;
151
+ }
152
+ catch (error) {
153
+ console.error(`❌ Error getting ENS profile for ${ensName}:`, error);
154
+ return null;
155
+ }
156
+ }
157
+ /**
158
+ * Check if a name is a valid ENS name (.eth)
159
+ */
160
+ isENSName(name) {
161
+ return name.endsWith(".eth") && !name.endsWith(".base.eth");
162
+ }
163
+ /**
164
+ * Get cached address if not expired
165
+ */
166
+ getCachedAddress(ensName) {
167
+ const entry = this.cache.get(ensName.toLowerCase());
168
+ if (!entry) {
169
+ return null;
170
+ }
171
+ const now = Date.now();
172
+ if (now - entry.timestamp > this.cacheTtl) {
173
+ this.cache.delete(ensName.toLowerCase());
174
+ return null;
175
+ }
176
+ return entry.address;
177
+ }
178
+ /**
179
+ * Cache address with LRU eviction
180
+ */
181
+ setCachedAddress(ensName, address) {
182
+ if (this.cache.size >= this.maxCacheSize) {
183
+ const firstKey = this.cache.keys().next().value;
184
+ if (firstKey) {
185
+ this.cache.delete(firstKey);
186
+ }
187
+ }
188
+ this.cache.set(ensName.toLowerCase(), {
189
+ address,
190
+ timestamp: Date.now()
191
+ });
192
+ }
193
+ /**
194
+ * Get cached ENS name if not expired
195
+ */
196
+ getCachedENSName(address) {
197
+ const entry = this.reverseCache.get(address.toLowerCase());
198
+ if (!entry) {
199
+ return null;
200
+ }
201
+ const now = Date.now();
202
+ if (now - entry.timestamp > this.cacheTtl) {
203
+ this.reverseCache.delete(address.toLowerCase());
204
+ return null;
205
+ }
206
+ return entry.ensName;
207
+ }
208
+ /**
209
+ * Cache ENS name with LRU eviction
210
+ */
211
+ setCachedENSName(address, ensName) {
212
+ if (this.reverseCache.size >= this.maxCacheSize) {
213
+ const firstKey = this.reverseCache.keys().next().value;
214
+ if (firstKey) {
215
+ this.reverseCache.delete(firstKey);
216
+ }
217
+ }
218
+ this.reverseCache.set(address.toLowerCase(), {
219
+ ensName,
220
+ timestamp: Date.now()
221
+ });
222
+ }
223
+ /**
224
+ * Clear all caches
225
+ */
226
+ clearCache() {
227
+ const addressCount = this.cache.size;
228
+ const ensCount = this.reverseCache.size;
229
+ this.cache.clear();
230
+ this.reverseCache.clear();
231
+ console.log(`🗑️ ENS address cache cleared (${addressCount} entries removed)`);
232
+ console.log(`🗑️ ENS reverse cache cleared (${ensCount} entries removed)`);
233
+ }
234
+ /**
235
+ * Get cache statistics
236
+ */
237
+ getCacheStats() {
238
+ return {
239
+ addressCache: {
240
+ size: this.cache.size,
241
+ maxSize: this.maxCacheSize
242
+ },
243
+ reverseCache: {
244
+ size: this.reverseCache.size,
245
+ maxSize: this.maxCacheSize
246
+ }
247
+ };
248
+ }
249
+ }
@@ -0,0 +1 @@
1
+ export * from "./resolver";
@@ -0,0 +1 @@
1
+ export * from "./resolver";
@@ -0,0 +1,162 @@
1
+ import { type Address, type PublicClient } from "viem";
2
+ import type { XmtpClient, XmtpMessage, XmtpSender } from "../types";
3
+ import { type BaseName, type BasenameTextRecordKey } from "./basename-resolver";
4
+ interface ResolverOptions {
5
+ /**
6
+ * XMTP Client for message and address resolution
7
+ */
8
+ xmtpClient: XmtpClient;
9
+ /**
10
+ * Mainnet public client for ENS resolution
11
+ */
12
+ mainnetClient: PublicClient;
13
+ /**
14
+ * Base network public client for basename resolution
15
+ */
16
+ baseClient: PublicClient;
17
+ /**
18
+ * Maximum cache size for each resolver
19
+ * @default 1000
20
+ */
21
+ maxCacheSize?: number;
22
+ /**
23
+ * Cache TTL in milliseconds
24
+ * @default 3600000 (1 hour)
25
+ */
26
+ cacheTtl?: number;
27
+ }
28
+ /**
29
+ * Master Resolver that wraps all individual resolvers
30
+ * Provides a unified interface for basename, ENS, address, and XMTP resolution
31
+ */
32
+ export declare class Resolver {
33
+ private addressResolver;
34
+ private ensResolver;
35
+ private basenameResolver;
36
+ private xmtpResolver;
37
+ constructor(options: ResolverOptions);
38
+ /**
39
+ * Resolve user address from inbox ID with caching
40
+ * Uses both AddressResolver and XmtpResolver for redundancy
41
+ */
42
+ resolveAddress(inboxId: string, conversationId?: string): Promise<`0x${string}` | null>;
43
+ /**
44
+ * Resolve an ENS name to an Ethereum address
45
+ */
46
+ resolveENSName(ensName: string): Promise<Address | null>;
47
+ /**
48
+ * Resolve an address to its primary ENS name (reverse resolution)
49
+ */
50
+ resolveAddressToENS(address: Address): Promise<string | null>;
51
+ /**
52
+ * Get ENS avatar for a given ENS name
53
+ */
54
+ getENSAvatar(ensName: string): Promise<string | null>;
55
+ /**
56
+ * Get ENS text record for a given ENS name and key
57
+ */
58
+ getENSTextRecord(ensName: string, key: string): Promise<string | null>;
59
+ /**
60
+ * Get complete ENS profile for a given ENS name
61
+ */
62
+ getENSProfile(ensName: string): Promise<{
63
+ ensName: string;
64
+ address: `0x${string}` | null;
65
+ avatar: string | null;
66
+ description: string | null;
67
+ twitter: string | null;
68
+ github: string | null;
69
+ url: string | null;
70
+ } | null>;
71
+ /**
72
+ * Get basename from an Ethereum address
73
+ */
74
+ getBasename(address: Address): Promise<string | null>;
75
+ /**
76
+ * Get basename avatar for a given basename
77
+ */
78
+ getBasenameAvatar(basename: BaseName): Promise<string | null>;
79
+ /**
80
+ * Get basename text record for a given basename and key
81
+ */
82
+ getBasenameTextRecord(basename: BaseName, key: BasenameTextRecordKey): Promise<string | null>;
83
+ /**
84
+ * Resolve basename to an Ethereum address
85
+ */
86
+ getBasenameAddress(basename: BaseName): Promise<Address | null>;
87
+ /**
88
+ * Get basename metadata for a given basename
89
+ */
90
+ getBasenameMetadata(basename: BaseName): Promise<{
91
+ basename: string;
92
+ avatar: string | null;
93
+ description: string | null;
94
+ twitter: string | null;
95
+ github: string | null;
96
+ url: string | null;
97
+ } | null>;
98
+ /**
99
+ * Get complete basename profile for a given address
100
+ */
101
+ resolveBasenameProfile(address: Address): Promise<{
102
+ basename?: string | undefined;
103
+ avatar?: string | null | undefined;
104
+ description?: string | null | undefined;
105
+ twitter?: string | null | undefined;
106
+ github?: string | null | undefined;
107
+ url?: string | null | undefined;
108
+ address: `0x${string}`;
109
+ } | null>;
110
+ /**
111
+ * Find any message by ID with caching
112
+ */
113
+ findMessage(messageId: string): Promise<XmtpMessage | null>;
114
+ /**
115
+ * Find root message by ID (traverses reply chain)
116
+ */
117
+ findRootMessage(messageId: string): Promise<XmtpMessage | null>;
118
+ /**
119
+ * Universal name resolution - tries to resolve any name (ENS or basename) to an address
120
+ */
121
+ resolveName(name: string): Promise<Address | null>;
122
+ /**
123
+ * Universal reverse resolution - tries to resolve an address to any name (ENS or basename)
124
+ */
125
+ resolveAddressToName(address: Address): Promise<string | null>;
126
+ /**
127
+ * Get complete profile for an address (combines ENS and basename data)
128
+ */
129
+ getCompleteProfile(address: Address): Promise<{
130
+ address: `0x${string}`;
131
+ ensName: string | null;
132
+ basename: string | null;
133
+ ensProfile: {
134
+ ensName: string;
135
+ address: `0x${string}` | null;
136
+ avatar: string | null;
137
+ description: string | null;
138
+ twitter: string | null;
139
+ github: string | null;
140
+ url: string | null;
141
+ } | null;
142
+ basenameProfile: {
143
+ basename?: string | undefined;
144
+ avatar?: string | null | undefined;
145
+ description?: string | null | undefined;
146
+ twitter?: string | null | undefined;
147
+ github?: string | null | undefined;
148
+ url?: string | null | undefined;
149
+ address: `0x${string}`;
150
+ } | null;
151
+ }>;
152
+ /**
153
+ * Pre-populate all resolver caches
154
+ */
155
+ prePopulateAllCaches(): Promise<void>;
156
+ /**
157
+ * Create a complete XmtpSender object from an address or inboxId
158
+ * Uses the resolver to get the best available name and profile information
159
+ */
160
+ createXmtpSender(addressOrInboxId: string, conversationId?: string): Promise<XmtpSender>;
161
+ }
162
+ export {};
@@ -0,0 +1,238 @@
1
+ import { AddressResolver } from "./address-resolver";
2
+ import { BasenameResolver } from "./basename-resolver";
3
+ import { ENSResolver } from "./ens-resolver";
4
+ import { XmtpResolver } from "./xmtp-resolver";
5
+ /**
6
+ * Master Resolver that wraps all individual resolvers
7
+ * Provides a unified interface for basename, ENS, address, and XMTP resolution
8
+ */
9
+ export class Resolver {
10
+ constructor(options) {
11
+ const resolverOptions = {
12
+ maxCacheSize: options.maxCacheSize ?? 1000,
13
+ cacheTtl: options.cacheTtl ?? 3600000
14
+ };
15
+ this.addressResolver = new AddressResolver(options.xmtpClient, resolverOptions);
16
+ this.xmtpResolver = new XmtpResolver(options.xmtpClient, resolverOptions);
17
+ // Type assertions needed due to viem version differences across monorepo packages
18
+ // Both clients are PublicClient-compatible but TypeScript sees them as incompatible types
19
+ this.ensResolver = new ENSResolver({
20
+ ...resolverOptions,
21
+ mainnetClient: options.mainnetClient
22
+ });
23
+ this.basenameResolver = new BasenameResolver({
24
+ ...resolverOptions,
25
+ publicClient: options.baseClient
26
+ });
27
+ }
28
+ // === Address Resolution Methods ===
29
+ /**
30
+ * Resolve user address from inbox ID with caching
31
+ * Uses both AddressResolver and XmtpResolver for redundancy
32
+ */
33
+ async resolveAddress(inboxId, conversationId) {
34
+ // Try AddressResolver first, fallback to XmtpResolver
35
+ let result = await this.addressResolver.resolveAddress(inboxId, conversationId);
36
+ if (!result) {
37
+ result = await this.xmtpResolver.resolveAddress(inboxId, conversationId);
38
+ }
39
+ return result;
40
+ }
41
+ // === ENS Resolution Methods ===
42
+ /**
43
+ * Resolve an ENS name to an Ethereum address
44
+ */
45
+ async resolveENSName(ensName) {
46
+ return this.ensResolver.resolveENSName(ensName);
47
+ }
48
+ /**
49
+ * Resolve an address to its primary ENS name (reverse resolution)
50
+ */
51
+ async resolveAddressToENS(address) {
52
+ return this.ensResolver.resolveAddressToENS(address);
53
+ }
54
+ /**
55
+ * Get ENS avatar for a given ENS name
56
+ */
57
+ async getENSAvatar(ensName) {
58
+ return this.ensResolver.getENSAvatar(ensName);
59
+ }
60
+ /**
61
+ * Get ENS text record for a given ENS name and key
62
+ */
63
+ async getENSTextRecord(ensName, key) {
64
+ return this.ensResolver.getENSTextRecord(ensName, key);
65
+ }
66
+ /**
67
+ * Get complete ENS profile for a given ENS name
68
+ */
69
+ async getENSProfile(ensName) {
70
+ return this.ensResolver.getENSProfile(ensName);
71
+ }
72
+ // === Basename Resolution Methods ===
73
+ /**
74
+ * Get basename from an Ethereum address
75
+ */
76
+ async getBasename(address) {
77
+ return this.basenameResolver.getBasename(address);
78
+ }
79
+ /**
80
+ * Get basename avatar for a given basename
81
+ */
82
+ async getBasenameAvatar(basename) {
83
+ return this.basenameResolver.getBasenameAvatar(basename);
84
+ }
85
+ /**
86
+ * Get basename text record for a given basename and key
87
+ */
88
+ async getBasenameTextRecord(basename, key) {
89
+ return this.basenameResolver.getBasenameTextRecord(basename, key);
90
+ }
91
+ /**
92
+ * Resolve basename to an Ethereum address
93
+ */
94
+ async getBasenameAddress(basename) {
95
+ return this.basenameResolver.getBasenameAddress(basename);
96
+ }
97
+ /**
98
+ * Get basename metadata for a given basename
99
+ */
100
+ async getBasenameMetadata(basename) {
101
+ return this.basenameResolver.getBasenameMetadata(basename);
102
+ }
103
+ /**
104
+ * Get complete basename profile for a given address
105
+ */
106
+ async resolveBasenameProfile(address) {
107
+ return this.basenameResolver.resolveBasenameProfile(address);
108
+ }
109
+ // === XMTP Message Methods ===
110
+ /**
111
+ * Find any message by ID with caching
112
+ */
113
+ async findMessage(messageId) {
114
+ return this.xmtpResolver.findMessage(messageId);
115
+ }
116
+ /**
117
+ * Find root message by ID (traverses reply chain)
118
+ */
119
+ async findRootMessage(messageId) {
120
+ return this.xmtpResolver.findRootMessage(messageId);
121
+ }
122
+ // === Universal Resolution Methods ===
123
+ /**
124
+ * Universal name resolution - tries to resolve any name (ENS or basename) to an address
125
+ */
126
+ async resolveName(name) {
127
+ // Try ENS first (more common)
128
+ if (name.endsWith(".eth")) {
129
+ return this.resolveENSName(name);
130
+ }
131
+ // Try basename
132
+ if (name.endsWith(".base.eth")) {
133
+ return this.getBasenameAddress(name);
134
+ }
135
+ // If no TLD, try both
136
+ const ensResult = await this.resolveENSName(name);
137
+ if (ensResult) {
138
+ return ensResult;
139
+ }
140
+ return this.getBasenameAddress(name);
141
+ }
142
+ /**
143
+ * Universal reverse resolution - tries to resolve an address to any name (ENS or basename)
144
+ */
145
+ async resolveAddressToName(address) {
146
+ // Try basename first (more relevant for this project)
147
+ const basename = await this.getBasename(address);
148
+ if (basename) {
149
+ return basename;
150
+ }
151
+ // Try ENS as fallback
152
+ return this.resolveAddressToENS(address);
153
+ }
154
+ /**
155
+ * Get complete profile for an address (combines ENS and basename data)
156
+ */
157
+ async getCompleteProfile(address) {
158
+ const [ensName, basename, ensProfile, basenameProfile] = await Promise.allSettled([
159
+ this.resolveAddressToENS(address),
160
+ this.getBasename(address),
161
+ this.resolveAddressToENS(address).then((name) => name ? this.getENSProfile(name) : null),
162
+ this.resolveBasenameProfile(address)
163
+ ]);
164
+ return {
165
+ address,
166
+ ensName: ensName.status === "fulfilled" ? ensName.value : null,
167
+ basename: basename.status === "fulfilled" ? basename.value : null,
168
+ ensProfile: ensProfile.status === "fulfilled" ? ensProfile.value : null,
169
+ basenameProfile: basenameProfile.status === "fulfilled" ? basenameProfile.value : null
170
+ };
171
+ }
172
+ // === Cache Management Methods ===
173
+ /**
174
+ * Pre-populate all resolver caches
175
+ */
176
+ async prePopulateAllCaches() {
177
+ await Promise.allSettled([
178
+ this.addressResolver.prePopulateCache(),
179
+ this.xmtpResolver.prePopulateCache()
180
+ ]);
181
+ }
182
+ /**
183
+ * Create a complete XmtpSender object from an address or inboxId
184
+ * Uses the resolver to get the best available name and profile information
185
+ */
186
+ async createXmtpSender(addressOrInboxId, conversationId) {
187
+ let address = null;
188
+ let inboxId = addressOrInboxId;
189
+ // Check if input looks like an Ethereum address
190
+ if (addressOrInboxId.startsWith("0x") && addressOrInboxId.length === 42) {
191
+ address = addressOrInboxId;
192
+ // When we have an address, we need to find the actual inboxId
193
+ // For now, use address as fallback but this should be resolved from XMTP
194
+ inboxId = addressOrInboxId; // This will be improved when we have proper address->inboxId resolution
195
+ }
196
+ else {
197
+ // Assume it's an inboxId, try to resolve to address
198
+ address = await this.resolveAddress(addressOrInboxId, conversationId);
199
+ }
200
+ // Get the best available name using universal resolution
201
+ let name = "Unknown";
202
+ let basename;
203
+ if (address) {
204
+ // Try basename first since that's what we expect for this address
205
+ const basenameResult = await this.getBasename(address);
206
+ console.log(`🔍 [RESOLVER] Direct basename lookup for ${address}:`, basenameResult);
207
+ // Try to get a human-readable name
208
+ const resolvedName = await this.resolveAddressToName(address);
209
+ console.log(`🔍 [RESOLVER] Universal name resolution for ${address}:`, resolvedName);
210
+ if (resolvedName) {
211
+ name = resolvedName;
212
+ // Check if it's a basename specifically
213
+ if (resolvedName.endsWith(".base.eth")) {
214
+ basename = resolvedName;
215
+ }
216
+ }
217
+ else {
218
+ // Fallback to shortened address
219
+ name = `${address.slice(0, 6)}...${address.slice(-4)}`;
220
+ }
221
+ // Always try to get basename even if ENS was found
222
+ if (!basename) {
223
+ const resolvedBasename = await this.getBasename(address);
224
+ basename = resolvedBasename || undefined;
225
+ }
226
+ }
227
+ else {
228
+ // No address resolution available, use inboxId
229
+ name = `${inboxId.slice(0, 8)}...${inboxId.slice(-4)}`;
230
+ }
231
+ return {
232
+ address: address || addressOrInboxId,
233
+ inboxId,
234
+ name,
235
+ basename
236
+ };
237
+ }
238
+ }