@hybrd/xmtp 1.4.5 β†’ 2.0.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/README.md CHANGED
@@ -1,414 +1,304 @@
1
- # Enhanced XMTP SDK with Robust Reliability πŸš€
1
+ # @hybrd/xmtp
2
2
 
3
- This package provides an enhanced XMTP client with robust connection management, retry logic, and health monitoring capabilities.
3
+ XMTP integration library for Hybrid AI agents. Provides client creation with R2 database persistence, an `XMTPPlugin` for the agent framework, ENS/Basename/address resolvers, and JWT utilities.
4
4
 
5
- ## Links
5
+ ## Overview
6
6
 
7
- - Main repo: [github.com/ian/hybrid](https://github.com/ian/hybrid)
8
- - Website & docs: [hybrid.dev](https://hybrid.dev)
7
+ This package handles all XMTP network connectivity for Hybrid agents:
9
8
 
10
- ### XMTP Plugin Filters
9
+ - **Client creation** with installation revocation, retry logic, and Cloudflare R2 database sync
10
+ - **XMTPPlugin** integrating XMTP into the `Agent` + `Plugin` framework architecture
11
+ - **Resolvers** for XMTP inbox IDs, ENS names, and Base network Basenames
12
+ - **JWT utilities** for securing XMTP tool API endpoints
13
+ - **Scripts** for wallet registration and installation management
11
14
 
12
- You can scope which messages are processed by providing XMTP Agent SDK filters to the plugin. These are the same built-in filters and combinators documented in the Agent SDK.
15
+ ## OpenClaw Compatibility
13
16
 
14
- ```typescript
15
- import { XMTPPlugin } from "@hybrd/xmtp"
16
- import { filter } from "hybrid"
17
-
18
- // As a standalone plugin instance
19
- const xmtp = XMTPPlugin({
20
- filters: [
21
- filter.isText,
22
- filter.not(filter.isFromSelf),
23
- filter.startsWith("@agent")
24
- ]
25
- })
26
- ```
17
+ This package is a Hybrid-native XMTP integration, not derived from the OpenClaw SDK. It wraps `@xmtp/node-sdk` and `@xmtp/agent-sdk` with production-ready reliability features.
27
18
 
28
- When using the Hybrid server `listen()` helper, pass `filters` directly (the helper wires them into `XMTPPlugin` under the hood):
19
+ ## Architecture
29
20
 
30
- ```typescript
31
- await agent.listen({
32
- port: process.env.PORT || "8454",
33
- filters: [filter.isText, filter.startsWith("@agent")]
34
- })
35
21
  ```
36
-
37
- See the Agent SDK documentation for all available filters and the `withFilter` helper: https://github.com/xmtp/xmtp-js/tree/main/sdks/agent-sdk#3-builtin-filters
38
-
39
- ## πŸ†™ Upgraded Features
40
-
41
- - **XMTP Node SDK**: Upgraded to `^3.1.0` (latest version)
42
- - **Enhanced Connection Management**: Automatic reconnection and health monitoring
43
- - **Robust Retry Logic**: Exponential backoff and configurable retry strategies
44
- - **Health Monitoring**: Real-time connection health tracking with metrics
45
- - **Production Ready**: Built for scalable, reliable XMTP integrations
46
-
47
- ## πŸ—οΈ Architecture Overview
48
-
49
- Your system uses a **"Thin Listener + QStash Callbacks"** architecture that already provides excellent reliability:
50
-
51
- ```
52
- β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
53
- β”‚ XMTP Network│───▢│Thin Server │───▢│ QStash β”‚
54
- β”‚ β”‚ β”‚(Enhanced) β”‚ β”‚ (Reliable) β”‚
55
- β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
56
- β”‚
57
- β–Ό
58
- β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
59
- β”‚ Agent │◀───│App/Webhook β”‚
60
- β”‚ Processing β”‚ β”‚ (Scalable) β”‚
61
- β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
22
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
23
+ β”‚ @hybrd/xmtp β”‚
24
+ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
25
+ β”‚ β”‚
26
+ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
27
+ β”‚ β”‚ XMTPPlugin (plugin.ts) β”‚ β”‚
28
+ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚
29
+ β”‚ β”‚ β”‚ XmtpAgent β”‚ β”‚ XmtpClient (low-level) β”‚ β”‚ β”‚
30
+ β”‚ β”‚ β”‚ (event listener) β”‚ β”‚ (resolvers, direct API) β”‚ β”‚ β”‚
31
+ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚
32
+ β”‚ β”‚ β”‚ β”‚
33
+ β”‚ β”‚ Behavior chain: executeBefore β†’ agent.generate β†’ send β”‚ β”‚
34
+ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
35
+ β”‚ β”‚
36
+ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
37
+ β”‚ β”‚ Client (client.ts) β”‚ β”‚
38
+ β”‚ β”‚ createXMTPClient() β†’ retry loop: β”‚ β”‚
39
+ β”‚ β”‚ 1. Download .db3 from R2 (if XMTP_STORAGE bound) β”‚ β”‚
40
+ β”‚ β”‚ 2. Create Client with codecs β”‚ β”‚
41
+ β”‚ β”‚ 3. On install limit: revoke old β†’ retry β”‚ β”‚
42
+ β”‚ β”‚ 4. On identity error: refresh identity β†’ retry β”‚ β”‚
43
+ β”‚ β”‚ 5. Upload .db3 to R2 after connect β”‚ β”‚
44
+ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
45
+ β”‚ β”‚
46
+ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
47
+ β”‚ β”‚ Resolvers (resolver/) β”‚ β”‚
48
+ β”‚ β”‚ Resolver β†’ AddressResolver, ENSResolver, BasenameResolver β”‚ β”‚
49
+ β”‚ β”‚ XmtpResolver (inbox IDs + message chains) β”‚ β”‚
50
+ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
51
+ β”‚ β”‚
52
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
62
53
  ```
63
54
 
64
- ### βœ… Built-in Reliability Features
65
-
66
- 1. **QStash Automatic Retries**: Built-in exponential backoff
67
- 2. **No Persistent Connections**: Eliminates connection drop issues
68
- 3. **Horizontal Scalability**: Multiple instances supported
69
- 4. **Dead Letter Queues**: Failed messages are preserved
70
- 5. **At-least-once Delivery**: Messages guaranteed to be processed
55
+ ## Features
71
56
 
72
- ## πŸ”§ Enhanced Connection Management
73
-
74
- ### Basic Usage
57
+ ### Client Creation
75
58
 
76
59
  ```typescript
77
- import {
78
- createSigner,
79
- createXMTPConnectionManager,
80
- type XMTPConnectionConfig
81
- } from "@hybrd/xmtp"
60
+ import { createXMTPClient } from "@hybrd/xmtp"
82
61
 
83
- // Enhanced connection with reliability features
84
- const signer = createSigner(process.env.XMTP_WALLET_KEY!)
85
-
86
- const connectionConfig: XMTPConnectionConfig = {
87
- maxRetries: 5, // Connection attempts
88
- retryDelayMs: 1000, // Base retry delay
89
- healthCheckIntervalMs: 30000, // Health check interval
90
- connectionTimeoutMs: 15000, // Connection timeout
91
- reconnectOnFailure: true // Auto-reconnect
92
- }
93
-
94
- const connectionManager = await createXMTPConnectionManager(
95
- signer,
96
- connectionConfig
97
- )
98
-
99
- // Get health metrics
100
- const health = connectionManager.getHealth()
101
- console.log('Connection Health:', health)
62
+ const client = await createXMTPClient(process.env.AGENT_WALLET_KEY!, {
63
+ persist: true, // Persist conversations locally
64
+ maxRetries: 3, // Installation revocation retry limit
65
+ storagePath: ".xmtp" // Custom DB storage path
66
+ })
102
67
  ```
103
68
 
104
- ### Advanced Production Usage
69
+ **Automatic resilience:**
70
+ - If the installation limit is reached, revokes old installations and retries
71
+ - If an identity association error occurs, refreshes identity and retries
72
+ - If `XMTP_STORAGE` (Cloudflare R2) is in `globalThis`, downloads the `.db3` database before connecting and uploads it after β€” enabling stateless containers to persist XMTP state
105
73
 
106
- ```typescript
107
- import { RobustXMTPService } from "@hybrd/xmtp/scripts/enhanced-connection-example"
108
-
109
- const service = new RobustXMTPService()
110
- await service.start()
111
-
112
- // Process messages with automatic retry/reconnection
113
- await service.processMessage(conversationId, "Hello!")
114
-
115
- // Monitor health
116
- const health = service.getConnectionHealth()
117
- if (!health?.isConnected) {
118
- console.warn("XMTP connection unhealthy")
119
- }
120
- ```
74
+ Registered content type codecs: `Text`, `Reply`, `Reaction`, `WalletSendCalls`, `TransactionReference`
121
75
 
122
- ## πŸ”„ Connection Health Monitoring
123
-
124
- The enhanced client provides real-time health metrics:
76
+ ### User/Signer Creation
125
77
 
126
78
  ```typescript
127
- interface XMTPConnectionHealth {
128
- isConnected: boolean // Current connection status
129
- lastHealthCheck: Date // Last health check timestamp
130
- consecutiveFailures: number // Failed health checks in a row
131
- totalReconnects: number // Total reconnection attempts
132
- avgResponseTime: number // Average response time in ms
133
- }
134
- ```
135
-
136
- ## πŸš€ Quick Start
79
+ import { createUser, createSigner } from "@hybrd/xmtp"
137
80
 
138
- ### 1. Install Dependencies
81
+ const user = createUser(process.env.AGENT_WALLET_KEY!)
82
+ // { key, account, wallet } β€” viem wallet client on Sepolia
139
83
 
140
- ```bash
141
- pnpm with-env pnpm --filter @hybrd/xmtp install
84
+ const signer = createSigner(process.env.AGENT_WALLET_KEY!)
85
+ // XMTP Signer: { getIdentifier(), signMessage() }
142
86
  ```
143
87
 
144
- ### 2. Run Enhanced Connection Demo
88
+ ### Connection Manager
145
89
 
146
- ```bash
147
- pnpm with-env pnpm --filter @hybrd/xmtp enhanced:demo
148
- ```
149
-
150
- ### 3. Integrate in Your Code
90
+ For long-running services that need health monitoring and auto-reconnection:
151
91
 
152
92
  ```typescript
153
- // Replace basic XMTP client creation
154
- // OLD:
155
- const client = await createXMTPClient(signer)
93
+ import { XMTPConnectionManager } from "@hybrd/xmtp"
156
94
 
157
- // NEW: With enhanced reliability
158
- const connectionManager = await createXMTPConnectionManager(signer, {
95
+ const manager = new XMTPConnectionManager(process.env.AGENT_WALLET_KEY!, {
159
96
  maxRetries: 5,
97
+ retryDelayMs: 1000,
160
98
  healthCheckIntervalMs: 30000,
99
+ connectionTimeoutMs: 15000,
161
100
  reconnectOnFailure: true
162
101
  })
163
- const client = connectionManager.getClient()
164
- ```
165
-
166
- ## πŸ“Š Why Your Current Architecture is Already Robust
167
-
168
- Your **QStash-based webhook system** already provides superior reliability compared to traditional streaming:
169
-
170
- ### Traditional Streaming Issues ❌
171
- - Connection drops require manual reconnection
172
- - Memory leaks from long-running connections
173
- - Difficult to scale horizontally
174
- - Complex heartbeat/keepalive management
175
- - Single point of failure
176
102
 
177
- ### Your QStash Architecture Benefits βœ…
178
- - **Automatic Retries**: QStash handles exponential backoff
179
- - **No Connection Drops**: Stateless webhook calls
180
- - **Horizontal Scaling**: Multiple app instances supported
181
- - **Built-in Monitoring**: QStash provides delivery metrics
182
- - **Dead Letter Queues**: Failed messages preserved
183
- - **At-least-once Delivery**: Guaranteed message processing
103
+ const client = await manager.connect()
184
104
 
185
- ## πŸ”§ Configuration Options
105
+ const health = manager.getHealth()
106
+ // { isConnected, lastHealthCheck, consecutiveFailures, totalReconnects, avgResponseTime }
186
107
 
187
- ### Environment Variables
108
+ await manager.disconnect()
109
+ ```
188
110
 
189
- | Variable | Description | Default |
190
- | ------------------------ | ---------------------------------------- | --------------------------------------- |
191
- | `XMTP_STORAGE_PATH` | Custom path for XMTP database storage | `.data/xmtp` (relative to project root) |
192
- | `XMTP_WALLET_KEY` | Private key for XMTP wallet | Required |
193
- | `XMTP_DB_ENCRYPTION_KEY` | Encryption key for database | Required for persistent mode |
194
- | `XMTP_ENV` | XMTP environment (`dev` or `production`) | `dev` |
195
- | `PROJECT_ROOT` | Override project root path | Auto-detected |
111
+ ### XMTPPlugin
196
112
 
197
- ### Connection Configuration
113
+ Integrates XMTP into the agent framework's `Plugin` architecture:
198
114
 
199
115
  ```typescript
200
- interface XMTPConnectionConfig {
201
- maxRetries?: number // Default: 5
202
- retryDelayMs?: number // Default: 1000ms
203
- healthCheckIntervalMs?: number // Default: 30000ms
204
- connectionTimeoutMs?: number // Default: 10000ms
205
- reconnectOnFailure?: boolean // Default: true
206
- }
207
- ```
208
-
209
- ### Custom Storage Location
116
+ import { XMTPPlugin } from "@hybrd/xmtp"
210
117
 
211
- You can specify a custom storage location for XMTP database files:
118
+ // Applied via agent.use() or agent.listen()
119
+ const plugin = XMTPPlugin()
212
120
 
213
- ```bash
214
- # Absolute path
215
- export XMTP_STORAGE_PATH=/custom/path/to/xmtp/storage
121
+ await agent.listen({
122
+ port: "8454",
123
+ plugins: [plugin],
124
+ behaviors: [myBehavior()]
125
+ })
126
+ ```
216
127
 
217
- # Relative path (relative to current working directory)
218
- export XMTP_STORAGE_PATH=./custom/xmtp/storage
128
+ For each incoming message (text, reply, reaction), the plugin:
129
+ 1. Builds conversation history (up to 20 messages)
130
+ 2. Creates `AgentRuntime` with conversation, message, and xmtpClient
131
+ 3. Runs `behaviors.executeBefore(context)` β€” stops chain if `context.stopped = true`
132
+ 4. Calls `agent.generate(messages, { runtime })`
133
+ 5. Sets `context.response = reply`
134
+ 6. Runs `behaviors.executeAfter(context)` β€” stops chain if `context.stopped = true`
135
+ 7. Sends reply (plain text or threaded via `ContentTypeReply`)
219
136
 
220
- # Use with pnpm with-env
221
- pnpm with-env your-xmtp-command
222
- ```
137
+ ### Resolver
223
138
 
224
- ### Testing Custom Storage
139
+ Universal name and address resolution across XMTP, ENS, and Basenames:
225
140
 
226
- Run the custom storage example to test your configuration:
141
+ ```typescript
142
+ import { Resolver } from "@hybrd/xmtp"
143
+ import { createPublicClient, http } from "viem"
144
+ import { mainnet, base } from "viem/chains"
227
145
 
228
- ```bash
229
- # Test with default storage location
230
- pnpm with-env pnpm --filter @hybrd/xmtp custom:storage
146
+ const resolver = new Resolver({
147
+ xmtpClient,
148
+ mainnetClient: createPublicClient({ chain: mainnet, transport: http() }),
149
+ baseClient: createPublicClient({ chain: base, transport: http() }),
150
+ maxCacheSize: 1000,
151
+ cacheTtl: 3_600_000 // 1 hour
152
+ })
231
153
 
232
- # Test with custom storage location
233
- export XMTP_STORAGE_PATH=/tmp/my-custom-xmtp-storage
234
- pnpm with-env pnpm --filter @hybrd/xmtp custom:storage
154
+ // Universal resolution (tries ENS then Basename)
155
+ const address = await resolver.resolveName("vitalik.eth")
156
+ const address2 = await resolver.resolveName("myname.base.eth")
235
157
 
236
- # Test with relative path
237
- export XMTP_STORAGE_PATH=./my-xmtp-data
238
- pnpm with-env pnpm --filter @hybrd/xmtp custom:storage
239
- ```
158
+ // Reverse resolution (tries Basename then ENS)
159
+ const name = await resolver.resolveAddressToName("0x...")
240
160
 
241
- ## πŸ› οΈ Available Scripts
161
+ // Complete profile
162
+ const profile = await resolver.getCompleteProfile("0x...")
163
+ // { address, ensName, basename, ensProfile, basenameProfile }
242
164
 
243
- | Script | Command | Description |
244
- | ------------------ | -------------------------------------------- | --------------------------------- |
245
- | `keys` | `pnpm --filter @hybrd/xmtp keys` | Generate new XMTP wallet keys |
246
- | `register` | `pnpm --filter @hybrd/xmtp register` | Register wallet on XMTP network |
247
- | `revoke` | `pnpm --filter @hybrd/xmtp revoke` | Revoke old XMTP installations |
248
- | `enhanced:demo` | `pnpm --filter @hybrd/xmtp enhanced:demo` | Demo enhanced connection features |
249
- | `test:messages` | `pnpm --filter @hybrd/xmtp test:messages` | Test message reception |
250
- | `refresh:identity` | `pnpm --filter @hybrd/xmtp refresh:identity` | Refresh XMTP identity |
251
- | `custom:storage` | `pnpm --filter @hybrd/xmtp custom:storage` | Test custom storage configuration |
165
+ // XMTP-specific
166
+ const address3 = await resolver.resolveAddress(inboxId, conversationId)
167
+ const sender = await resolver.createXmtpSender(inboxId, conversationId)
168
+ // { address, inboxId, name, basename? }
252
169
 
253
- > **Note**: Always use `pnpm with-env` to ensure environment variables are loaded:
254
- > ```bash
255
- > pnpm with-env pnpm --filter @hybrd/xmtp <script-name>
256
- > ```
170
+ // ENS
171
+ const ensProfile = await resolver.getENSProfile("vitalik.eth")
172
+ // { ensName, address, avatar, description, twitter, github, url }
257
173
 
258
- ## 🎯 Best Practices
174
+ // Basenames (Base network)
175
+ const basename = await resolver.getBasename("0x...")
176
+ const basenameProfile = await resolver.resolveBasenameProfile("0x...")
259
177
 
260
- ### 1. Use Connection Manager for Long-Running Services
261
- ```typescript
262
- // For services that need persistent XMTP connections
263
- const manager = await createXMTPConnectionManager(signer, config)
178
+ // Message resolution
179
+ const message = await resolver.findMessage(messageId)
180
+ const rootMessage = await resolver.findRootMessage(messageId) // Traverses reply chain
264
181
  ```
265
182
 
266
- ### 2. Leverage Your Existing QStash Architecture
267
- ```typescript
268
- // For message processing, your webhook system is ideal
269
- // No changes needed - it's already robust!
270
- ```
183
+ #### Individual Resolvers
271
184
 
272
- ### 3. Monitor Connection Health
273
185
  ```typescript
274
- setInterval(() => {
275
- const health = connectionManager.getHealth()
276
- if (health.consecutiveFailures > 3) {
277
- console.warn("XMTP connection degraded")
278
- }
279
- }, 60000)
280
- ```
186
+ import { AddressResolver, ENSResolver, BasenameResolver, XmtpResolver } from "@hybrd/xmtp/resolver"
281
187
 
282
- ### 4. Use Environment Variables
283
- ```typescript
284
- // Always use the project's environment wrapper
285
- pnpm with-env [your-command]
188
+ const ensResolver = new ENSResolver({ mainnetClient })
189
+ const basenameResolver = new BasenameResolver({ publicClient: baseClient })
190
+ const addressResolver = new AddressResolver({ xmtpClient })
191
+ const xmtpResolver = new XmtpResolver({ xmtpClient })
286
192
  ```
287
193
 
288
- ## πŸ§ͺ Testing
194
+ ### JWT Utilities
289
195
 
290
- Run the enhanced connection demo to see health monitoring in action:
196
+ Secure XMTP tool API endpoints with short-lived JWTs:
291
197
 
292
- ```bash
293
- # Start the demo (runs for 2 minutes showing health checks)
294
- pnpm with-env pnpm --filter @hybrd/xmtp enhanced:demo
295
- ```
198
+ ```typescript
199
+ import { generateXMTPToolsToken, validateXMTPToolsToken, getValidatedPayload } from "@hybrd/xmtp"
296
200
 
297
- ## πŸ” Debugging
201
+ // Generate a 5-minute token (signed with derived secret)
202
+ const token = generateXMTPToolsToken({
203
+ action: "send",
204
+ conversationId: "conv-123",
205
+ content: "Hello!"
206
+ })
298
207
 
299
- Enable debug logging:
208
+ // Validate (returns null if invalid or expired)
209
+ const payload = validateXMTPToolsToken(token)
300
210
 
301
- ```bash
302
- DEBUG=xmtp-sdk* pnpm with-env pnpm --filter @hybrd/xmtp enhanced:demo
211
+ // Extract from Hono request context (Authorization: Bearer or ?token=)
212
+ const payload = getValidatedPayload(honoContext)
303
213
  ```
304
214
 
305
- ## πŸ“ˆ Metrics & Monitoring
306
-
307
- The enhanced client provides detailed metrics:
215
+ `XMTP_API_KEY` env var is also accepted as a static alternative to JWT.
308
216
 
309
- - **Connection Status**: Real-time connection state
310
- - **Response Times**: Average XMTP response latency
311
- - **Failure Counts**: Track connection reliability
312
- - **Reconnection Events**: Monitor stability over time
313
-
314
- ## 🚨 Migration Guide
315
-
316
- ### From Basic XMTP Client
217
+ ### Mention Extraction
317
218
 
318
219
  ```typescript
319
- // Before
320
- const client = await createXMTPClient(signer)
321
-
322
- // After
323
- const manager = await createXMTPConnectionManager(signer)
324
- const client = manager.getClient()
220
+ import { extractSubjects } from "@hybrd/xmtp"
325
221
 
326
- // Remember to cleanup
327
- await manager.disconnect()
222
+ // Extracts @basename.eth and @name.base.eth mentions and resolves to addresses
223
+ const subjects = await extractSubjects(messageContent, basenameResolver, ensResolver)
224
+ // { "vitalik": "0x...", "myname": "0x..." }
328
225
  ```
329
226
 
330
- ### Keep Your Webhook Architecture
331
-
332
- **No changes needed!** Your QStash webhook system is already providing:
333
- - βœ… Automatic retries with exponential backoff
334
- - βœ… Reliable message delivery guarantees
335
- - βœ… Horizontal scalability
336
- - βœ… Built-in monitoring and alerting
337
- - βœ… Dead letter queue handling
227
+ ## Scripts
338
228
 
339
- ## πŸ“š Additional Resources
340
-
341
- - [XMTP Node SDK Documentation](https://xmtp.org/docs/build/get-started/overview)
342
- - [QStash Documentation](https://upstash.com/docs/qstash)
343
- - [Project Architecture](../../ARCHITECTURE.md)
344
-
345
- ---
229
+ ```bash
230
+ # Register wallet on XMTP network
231
+ hybrid register
346
232
 
347
- Your system is already built with production-grade reliability. The enhanced XMTP client provides additional connection management features for edge cases, but your webhook-based architecture is the recommended approach for scalable XMTP integrations! πŸŽ‰
233
+ # Revoke specific inbox installations
234
+ hybrid revoke <inboxId>
348
235
 
349
- # XMTP Package
236
+ # Auto-detect inbox ID and revoke all installations
237
+ hybrid revoke-all
238
+ ```
350
239
 
351
- This package provides XMTP client functionality and various resolvers for address, ENS, and basename resolution.
240
+ Or run directly:
352
241
 
353
- ## Resolvers
242
+ ```bash
243
+ pnpm --filter @hybrd/xmtp register
244
+ pnpm --filter @hybrd/xmtp revoke
245
+ pnpm --filter @hybrd/xmtp revoke-all
246
+ ```
354
247
 
355
- ### Master Resolver
248
+ ## Re-exports
356
249
 
357
- The `Resolver` class provides a unified interface for all resolution types:
250
+ This package re-exports the complete `@xmtp/node-sdk` surface and all content type codecs:
358
251
 
359
252
  ```typescript
360
- import { Resolver } from '@hybrd/xmtp/resolver'
361
- import { createPublicClient, http } from 'viem'
362
- import { mainnet, base } from 'viem/chains'
363
-
364
- // Create clients
365
- const mainnetClient = createPublicClient({
366
- chain: mainnet,
367
- transport: http()
368
- })
253
+ import {
254
+ Client,
255
+ Signer,
256
+ type XmtpEnv,
257
+ // Content types:
258
+ ContentTypeReaction,
259
+ ContentTypeReply,
260
+ ContentTypeGroupUpdated,
261
+ ContentTypeTransactionReference,
262
+ ContentTypeWalletSendCalls,
263
+ ContentTypeText
264
+ } from "@hybrd/xmtp"
265
+ ```
369
266
 
370
- const baseClient = createPublicClient({
371
- chain: base,
372
- transport: http()
373
- })
267
+ ## Database Path Resolution
374
268
 
375
- // Initialize the master resolver
376
- const resolver = new Resolver({
377
- xmtpClient: yourXmtpClient,
378
- mainnetClient,
379
- baseClient,
380
- maxCacheSize: 1000,
381
- cacheTtl: 3600000 // 1 hour
382
- })
269
+ ```typescript
270
+ import { getDbPath } from "@hybrd/xmtp"
383
271
 
384
- // Universal name resolution
385
- const address = await resolver.resolveName('vitalik.eth')
386
- const basenameAddress = await resolver.resolveName('myname.base.eth')
272
+ const dbPath = await getDbPath("my-agent", "/custom/storage")
273
+ // Priority: XMTP_STORAGE_PATH env β†’ storagePath param β†’ .hybrid/.xmtp/
274
+ // If XMTP_STORAGE (R2) is in globalThis, downloads existing DB first
275
+ ```
387
276
 
388
- // Universal reverse resolution
389
- const name = await resolver.resolveAddressToName('0x...')
277
+ ## Encryption Key Generation
390
278
 
391
- // Get complete profile (ENS + basename data)
392
- const profile = await resolver.getCompleteProfile('0x...')
279
+ ```typescript
280
+ import { generateEncryptionKeyHex } from "@hybrd/xmtp"
393
281
 
394
- // Individual resolver methods are also available
395
- const ensName = await resolver.resolveENSName('vitalik.eth')
396
- const basename = await resolver.getBasename('0x...')
397
- const message = await resolver.findMessage('messageId')
282
+ const key = generateEncryptionKeyHex() // 32-byte random hex string
398
283
  ```
399
284
 
400
- ### Individual Resolvers
285
+ ## Environment Variables
401
286
 
402
- You can also use individual resolvers directly:
287
+ | Variable | Description |
288
+ |----------|-------------|
289
+ | `AGENT_WALLET_KEY` | Private key for the agent wallet (required) |
290
+ | `XMTP_ENV` | XMTP environment: `dev` or `production` (default: `dev`) |
291
+ | `XMTP_STORAGE_PATH` | Custom path for XMTP database files |
292
+ | `XMTP_API_KEY` | Static API key for XMTP tool endpoints (alternative to JWT) |
293
+ | `XMTP_DEBUG` | Enable debug logging |
403
294
 
404
- - `AddressResolver` - XMTP address resolution
405
- - `XmtpResolver` - XMTP message and address resolution with advanced features
406
- - `ENSResolver` - ENS name resolution
407
- - `BasenameResolver` - Basename resolution for Base network
295
+ ## Testing
408
296
 
409
- ```typescript
410
- import { ENSResolver, BasenameResolver } from '@hybrd/xmtp/resolver'
297
+ ```bash
298
+ cd packages/xmtp
299
+ pnpm test
300
+ ```
411
301
 
412
- const ensResolver = new ENSResolver({ mainnetClient })
413
- const basenameResolver = new BasenameResolver({ publicClient: baseClient })
414
- ```
302
+ ## License
303
+
304
+ MIT