@hybrd/channels 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 +180 -0
- package/dist/adapters/xmtp/index.cjs +393 -0
- package/dist/adapters/xmtp/index.cjs.map +1 -0
- package/dist/adapters/xmtp/index.d.cts +36 -0
- package/dist/adapters/xmtp/index.d.ts +36 -0
- package/dist/adapters/xmtp/index.js +364 -0
- package/dist/adapters/xmtp/index.js.map +1 -0
- package/dist/index.cjs +69 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +12 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +41 -0
- package/dist/index.js.map +1 -0
- package/package.json +60 -0
- package/src/adapters/xmtp/adapter.test.ts +167 -0
- package/src/adapters/xmtp/adapter.ts +307 -0
- package/src/adapters/xmtp/index.ts +138 -0
- package/src/dispatcher.ts +51 -0
- package/src/index.ts +11 -0
package/README.md
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# @hybrd/channels
|
|
2
|
+
|
|
3
|
+
Channel adapter framework for Hybrid AI agents. Provides a pluggable, uniform interface for connecting different messaging networks to the agent, with local HTTP IPC for inter-process communication.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The channels package abstracts the "listen for inbound + deliver outbound" pattern behind a `ChannelAdapter` interface. Currently ships with a full XMTP adapter; the architecture supports adding Telegram, Slack, and other channels.
|
|
8
|
+
|
|
9
|
+
Key design decisions:
|
|
10
|
+
- **Local HTTP IPC**: All communication between the scheduler/dispatcher and channel adapters uses `http://127.0.0.1` on fixed ports — adapters are independently deployable processes
|
|
11
|
+
- **Port-based routing**: Each channel has a reserved port in `DEFAULT_ADAPTER_PORTS`
|
|
12
|
+
- **Decoupled from agent**: Adapters communicate with the agent via HTTP only, no direct function calls
|
|
13
|
+
|
|
14
|
+
## Architecture
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
┌──────────────────────────────────────────────────────────────────┐
|
|
18
|
+
│ @hybrd/channels │
|
|
19
|
+
├──────────────────────────────────────────────────────────────────┤
|
|
20
|
+
│ │
|
|
21
|
+
│ dispatchToChannel() │
|
|
22
|
+
│ │ │
|
|
23
|
+
│ └── POST http://127.0.0.1:{port}/api/trigger │
|
|
24
|
+
│ │ │
|
|
25
|
+
│ ▼ │
|
|
26
|
+
│ ┌─────────────────────┐ │
|
|
27
|
+
│ │ XMTPAdapter │ port 8455 │
|
|
28
|
+
│ │ ───────────── │ │
|
|
29
|
+
│ │ XmtpAgent │ ← inbound messages from XMTP network │
|
|
30
|
+
│ │ Express server │ ← outbound trigger from scheduler │
|
|
31
|
+
│ │ runAgentAndReply()│ → POST {agentUrl}/api/chat │
|
|
32
|
+
│ └─────────────────────┘ │
|
|
33
|
+
│ │
|
|
34
|
+
│ DEFAULT_ADAPTER_PORTS = { xmtp: 8455, ... } │
|
|
35
|
+
│ │
|
|
36
|
+
└──────────────────────────────────────────────────────────────────┘
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Features
|
|
40
|
+
|
|
41
|
+
### dispatchToChannel
|
|
42
|
+
|
|
43
|
+
Send a message to a user via any registered channel:
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
import { dispatchToChannel } from "@hybrd/channels"
|
|
47
|
+
|
|
48
|
+
const result = await dispatchToChannel({
|
|
49
|
+
channel: "xmtp",
|
|
50
|
+
to: "0x...", // Target address or conversation ID
|
|
51
|
+
message: "Hello from the scheduler!",
|
|
52
|
+
metadata: {
|
|
53
|
+
accountId: "0xagent...",
|
|
54
|
+
threadId: "optional-thread-id"
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
// { delivered: boolean, messageId?: string, error?: string }
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
This POSTs a `TriggerRequest` to the adapter's local HTTP server at `http://127.0.0.1:8455/api/trigger`.
|
|
62
|
+
|
|
63
|
+
### XMTPAdapter
|
|
64
|
+
|
|
65
|
+
The XMTP channel adapter. Handles both inbound messages from the XMTP network and outbound triggers from the scheduler.
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
import { createXMTPAdapter } from "@hybrd/channels"
|
|
69
|
+
|
|
70
|
+
const adapter = await createXMTPAdapter({
|
|
71
|
+
port: 8455,
|
|
72
|
+
agentUrl: "http://localhost:8454",
|
|
73
|
+
xmtpEnv: "dev",
|
|
74
|
+
walletKey: process.env.AGENT_WALLET_KEY!,
|
|
75
|
+
dbPath: "./.xmtp"
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
await adapter.start() // Connects to XMTP, starts HTTP server
|
|
79
|
+
await adapter.stop() // Closes HTTP server
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**Inbound flow** (XMTP → agent):
|
|
83
|
+
1. XMTP text message arrives
|
|
84
|
+
2. Deduplicates by message ID
|
|
85
|
+
3. Finds conversation, builds reply context
|
|
86
|
+
4. POSTs to `{agentUrl}/api/chat`
|
|
87
|
+
5. Reads SSE stream, assembles full response
|
|
88
|
+
6. Sends reply via `conversation.send(reply)`
|
|
89
|
+
|
|
90
|
+
**Outbound flow** (scheduler → XMTP):
|
|
91
|
+
1. `POST /api/trigger` received on adapter's HTTP server
|
|
92
|
+
2. Finds target conversation
|
|
93
|
+
3. Calls `runAgentAndReply()` — same flow as inbound
|
|
94
|
+
|
|
95
|
+
### Programmatic Trigger
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
// Trigger directly without HTTP
|
|
99
|
+
const result = await adapter.trigger({
|
|
100
|
+
to: "0xconversation-id-or-address",
|
|
101
|
+
message: "Scheduled reminder",
|
|
102
|
+
metadata: { accountId: "0xagent..." }
|
|
103
|
+
})
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Default Ports
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
import { DEFAULT_ADAPTER_PORTS } from "@hybrd/channels"
|
|
110
|
+
|
|
111
|
+
console.log(DEFAULT_ADAPTER_PORTS)
|
|
112
|
+
// { xmtp: 8455 }
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Running as a Standalone Process
|
|
116
|
+
|
|
117
|
+
The XMTP adapter can run as an independent process:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
# Environment variables required:
|
|
121
|
+
# AGENT_WALLET_KEY, XMTP_ENV, PORT (optional)
|
|
122
|
+
|
|
123
|
+
node packages/channels/src/adapters/xmtp/index.js
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Or from the adapter entry point — reads config from env vars, prints a banner, and starts the adapter.
|
|
127
|
+
|
|
128
|
+
## Adding a New Channel
|
|
129
|
+
|
|
130
|
+
1. Reserve a port in `DEFAULT_ADAPTER_PORTS`
|
|
131
|
+
2. Implement the `ChannelAdapter` interface from `@hybrd/types`:
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
import type { ChannelAdapter, TriggerRequest, TriggerResponse } from "@hybrd/types"
|
|
135
|
+
|
|
136
|
+
class TelegramAdapter implements ChannelAdapter {
|
|
137
|
+
channel = "telegram" as const
|
|
138
|
+
port = 8456
|
|
139
|
+
|
|
140
|
+
async start(): Promise<void> {
|
|
141
|
+
// Connect to Telegram, start local HTTP server on this.port
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async stop(): Promise<void> {
|
|
145
|
+
// Close HTTP server
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async trigger(req: TriggerRequest): Promise<TriggerResponse> {
|
|
149
|
+
// Send message to Telegram user
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
3. Export from `packages/channels/src/adapters/telegram/`
|
|
155
|
+
|
|
156
|
+
## Relation to Other Packages
|
|
157
|
+
|
|
158
|
+
- Types (`ChannelAdapter`, `TriggerRequest`, `TriggerResponse`, `CronDelivery`) come from `@hybrd/types`
|
|
159
|
+
- `dispatchToChannel()` is the counterpart to `SchedulerService`'s delivery mechanism in `@hybrd/scheduler`
|
|
160
|
+
- The `XMTPAdapter` is a clean factoring of the sidecar logic in `packages/agent/src/xmtp.ts`
|
|
161
|
+
- Communicates with `packages/agent` via HTTP — no direct imports from the agent package
|
|
162
|
+
|
|
163
|
+
## Environment Variables
|
|
164
|
+
|
|
165
|
+
| Variable | Description |
|
|
166
|
+
|----------|-------------|
|
|
167
|
+
| `AGENT_WALLET_KEY` | Private key for the agent's XMTP wallet |
|
|
168
|
+
| `XMTP_ENV` | XMTP environment: `dev` or `production` |
|
|
169
|
+
| `AGENT_URL` | Base URL for the agent server (default: `http://localhost:8454`) |
|
|
170
|
+
|
|
171
|
+
## Testing
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
cd packages/channels
|
|
175
|
+
pnpm test
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## License
|
|
179
|
+
|
|
180
|
+
MIT
|
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __esm = (fn, res) => function __init() {
|
|
9
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
10
|
+
};
|
|
11
|
+
var __export = (target, all) => {
|
|
12
|
+
for (var name in all)
|
|
13
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
14
|
+
};
|
|
15
|
+
var __copyProps = (to, from, except, desc) => {
|
|
16
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
17
|
+
for (let key of __getOwnPropNames(from))
|
|
18
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
19
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
20
|
+
}
|
|
21
|
+
return to;
|
|
22
|
+
};
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
24
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
25
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
26
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
27
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
28
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
29
|
+
mod
|
|
30
|
+
));
|
|
31
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
|
+
|
|
33
|
+
// src/adapters/xmtp/adapter.ts
|
|
34
|
+
var adapter_exports = {};
|
|
35
|
+
__export(adapter_exports, {
|
|
36
|
+
XMTPAdapter: () => XMTPAdapter,
|
|
37
|
+
createXMTPAdapter: () => createXMTPAdapter
|
|
38
|
+
});
|
|
39
|
+
async function createXMTPAdapter(config) {
|
|
40
|
+
const adapter = new XMTPAdapter(config);
|
|
41
|
+
await adapter.start();
|
|
42
|
+
return adapter;
|
|
43
|
+
}
|
|
44
|
+
var import_node_crypto, import_memory, import_agent_sdk, import_express, import_picocolors, log, XMTPAdapter;
|
|
45
|
+
var init_adapter = __esm({
|
|
46
|
+
"src/adapters/xmtp/adapter.ts"() {
|
|
47
|
+
"use strict";
|
|
48
|
+
import_node_crypto = require("crypto");
|
|
49
|
+
import_memory = require("@hybrid/memory");
|
|
50
|
+
import_agent_sdk = require("@xmtp/agent-sdk");
|
|
51
|
+
import_express = __toESM(require("express"), 1);
|
|
52
|
+
import_picocolors = __toESM(require("picocolors"), 1);
|
|
53
|
+
log = {
|
|
54
|
+
info: (msg) => console.log(`${import_picocolors.default.magenta("[xmtp]")} ${msg}`),
|
|
55
|
+
error: (msg) => console.error(`${import_picocolors.default.red("[xmtp]")} ${msg}`),
|
|
56
|
+
warn: (msg) => console.log(`${import_picocolors.default.yellow("[xmtp]")} ${msg}`),
|
|
57
|
+
success: (msg) => console.log(`${import_picocolors.default.green("[xmtp]")} ${msg}`)
|
|
58
|
+
};
|
|
59
|
+
XMTPAdapter = class {
|
|
60
|
+
channel = "xmtp";
|
|
61
|
+
port;
|
|
62
|
+
config;
|
|
63
|
+
agent = null;
|
|
64
|
+
server = null;
|
|
65
|
+
app;
|
|
66
|
+
botInboxId = null;
|
|
67
|
+
processedMessages = /* @__PURE__ */ new Set();
|
|
68
|
+
addressCache = /* @__PURE__ */ new Map();
|
|
69
|
+
constructor(config) {
|
|
70
|
+
this.port = config.port;
|
|
71
|
+
this.config = config;
|
|
72
|
+
this.app = (0, import_express.default)();
|
|
73
|
+
this.app.use(import_express.default.json());
|
|
74
|
+
}
|
|
75
|
+
async start() {
|
|
76
|
+
await this.startXMTPClient();
|
|
77
|
+
this.startTriggerServer();
|
|
78
|
+
}
|
|
79
|
+
async stop() {
|
|
80
|
+
this.server?.close();
|
|
81
|
+
}
|
|
82
|
+
async startXMTPClient() {
|
|
83
|
+
const { createUser: createUser2 } = await import("@xmtp/agent-sdk");
|
|
84
|
+
const { toBytes } = await import("viem");
|
|
85
|
+
const user = createUser2(this.config.walletKey);
|
|
86
|
+
const identifier = {
|
|
87
|
+
identifier: user.account.address.toLowerCase(),
|
|
88
|
+
identifierKind: 0
|
|
89
|
+
};
|
|
90
|
+
const signer = {
|
|
91
|
+
type: "EOA",
|
|
92
|
+
getIdentifier: () => identifier,
|
|
93
|
+
getChainId: async () => BigInt(1),
|
|
94
|
+
signMessage: async (message) => {
|
|
95
|
+
const sig = await user.account.signMessage({ message });
|
|
96
|
+
return toBytes(sig);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
this.agent = await import_agent_sdk.Agent.create(
|
|
100
|
+
signer,
|
|
101
|
+
{
|
|
102
|
+
env: this.config.xmtpEnv ?? "dev",
|
|
103
|
+
dbEncryptionKey: this.config.dbEncryptionKey,
|
|
104
|
+
dbPath: this.config.dbPath
|
|
105
|
+
}
|
|
106
|
+
);
|
|
107
|
+
log.success("connected to XMTP network");
|
|
108
|
+
this.botInboxId = this.agent.client.inboxId;
|
|
109
|
+
this.agent.on("text", async (ctx) => {
|
|
110
|
+
const { conversation, message } = ctx;
|
|
111
|
+
await this.handleInbound(conversation, message);
|
|
112
|
+
});
|
|
113
|
+
await this.agent.start();
|
|
114
|
+
log.success("listening for XMTP messages");
|
|
115
|
+
}
|
|
116
|
+
startTriggerServer() {
|
|
117
|
+
this.app.post("/api/trigger", async (req, res) => {
|
|
118
|
+
const result = await this.handleTrigger(req.body);
|
|
119
|
+
res.json(result);
|
|
120
|
+
});
|
|
121
|
+
this.server = this.app.listen(this.port, "127.0.0.1", () => {
|
|
122
|
+
log.success(`trigger server listening on 127.0.0.1:${this.port}`);
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
async resolveSenderAddress(inboxId, conversation) {
|
|
126
|
+
const cached = this.addressCache.get(inboxId);
|
|
127
|
+
if (cached) return cached;
|
|
128
|
+
try {
|
|
129
|
+
const members = await conversation.members();
|
|
130
|
+
const sender = members.find(
|
|
131
|
+
(m) => m.inboxId.toLowerCase() === inboxId.toLowerCase()
|
|
132
|
+
);
|
|
133
|
+
if (sender) {
|
|
134
|
+
const ethIdentifier = sender.accountIdentifiers.find(
|
|
135
|
+
(id) => id.identifierKind === 0
|
|
136
|
+
);
|
|
137
|
+
if (ethIdentifier) {
|
|
138
|
+
const address = ethIdentifier.identifier.toLowerCase();
|
|
139
|
+
this.addressCache.set(inboxId, address);
|
|
140
|
+
return address;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
const inboxState = await this.agent?.client.preferences.inboxStateFromInboxIds([inboxId]);
|
|
144
|
+
const firstState = inboxState?.[0];
|
|
145
|
+
if (firstState?.identifiers?.[0]?.identifier) {
|
|
146
|
+
const address = firstState.identifiers[0].identifier.toLowerCase();
|
|
147
|
+
this.addressCache.set(inboxId, address);
|
|
148
|
+
return address;
|
|
149
|
+
}
|
|
150
|
+
} catch (err) {
|
|
151
|
+
log.warn(`failed to resolve address for ${inboxId.slice(0, 16)}...`);
|
|
152
|
+
}
|
|
153
|
+
return inboxId;
|
|
154
|
+
}
|
|
155
|
+
async isSenderAllowed(senderAddress) {
|
|
156
|
+
if (!this.config.workspaceDir) {
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
try {
|
|
160
|
+
const allowFrom = await (0, import_memory.readACLAllowFrom)(this.config.workspaceDir);
|
|
161
|
+
if (allowFrom.length === 0) {
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
const normalized = senderAddress.toLowerCase();
|
|
165
|
+
return allowFrom.includes(normalized);
|
|
166
|
+
} catch (err) {
|
|
167
|
+
log.warn(`failed to read ACL, allowing sender: ${err.message}`);
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
async handleInbound(conversation, message) {
|
|
172
|
+
log.info(`message ${import_picocolors.default.gray(message.id.slice(0, 8))}`);
|
|
173
|
+
if (this.processedMessages.has(message.id)) {
|
|
174
|
+
log.warn(`skipping duplicate: ${message.id.slice(0, 8)}`);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
this.processedMessages.add(message.id);
|
|
178
|
+
if (this.processedMessages.size > 1e3) {
|
|
179
|
+
const arr = Array.from(this.processedMessages);
|
|
180
|
+
arr.slice(0, 500).forEach((id) => this.processedMessages.delete(id));
|
|
181
|
+
}
|
|
182
|
+
const senderAddress = await this.resolveSenderAddress(
|
|
183
|
+
message.senderInboxId,
|
|
184
|
+
conversation
|
|
185
|
+
);
|
|
186
|
+
const isAllowed = await this.isSenderAllowed(senderAddress);
|
|
187
|
+
if (!isAllowed) {
|
|
188
|
+
log.warn(
|
|
189
|
+
`blocked message from ${senderAddress.slice(0, 10)}... (not on allowlist)`
|
|
190
|
+
);
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
await this.runAgentAndReply({
|
|
194
|
+
conversationId: conversation.id,
|
|
195
|
+
message: message.content,
|
|
196
|
+
conversation
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
async trigger(req) {
|
|
200
|
+
return this.handleTrigger(req);
|
|
201
|
+
}
|
|
202
|
+
async handleTrigger(req) {
|
|
203
|
+
if (!this.agent) {
|
|
204
|
+
return { delivered: false, error: "XMTP client not initialized" };
|
|
205
|
+
}
|
|
206
|
+
const conversations = await this.agent.client.conversations.list();
|
|
207
|
+
const conversation = conversations.find(
|
|
208
|
+
(c) => c.id === req.to
|
|
209
|
+
);
|
|
210
|
+
if (!conversation) {
|
|
211
|
+
return { delivered: false, error: "Conversation not found" };
|
|
212
|
+
}
|
|
213
|
+
return this.runAgentAndReply({
|
|
214
|
+
conversationId: req.to,
|
|
215
|
+
message: req.message,
|
|
216
|
+
conversation
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
async runAgentAndReply(params) {
|
|
220
|
+
const { conversation, message, conversationId } = params;
|
|
221
|
+
try {
|
|
222
|
+
const res = await fetch(`${this.config.agentUrl}/api/chat`, {
|
|
223
|
+
method: "POST",
|
|
224
|
+
headers: {
|
|
225
|
+
"Content-Type": "application/json",
|
|
226
|
+
"X-Request-ID": (0, import_node_crypto.randomUUID)(),
|
|
227
|
+
"X-Source": "xmtp-adapter"
|
|
228
|
+
},
|
|
229
|
+
body: JSON.stringify({
|
|
230
|
+
messages: [{ id: (0, import_node_crypto.randomUUID)(), role: "user", content: message }],
|
|
231
|
+
chatId: conversationId
|
|
232
|
+
})
|
|
233
|
+
});
|
|
234
|
+
if (!res.ok) {
|
|
235
|
+
log.error(`HTTP ${res.status}`);
|
|
236
|
+
return { delivered: false, error: `HTTP ${res.status}` };
|
|
237
|
+
}
|
|
238
|
+
const reader = res.body?.getReader();
|
|
239
|
+
if (!reader) {
|
|
240
|
+
return { delivered: false, error: "No response body" };
|
|
241
|
+
}
|
|
242
|
+
const decoder = new TextDecoder();
|
|
243
|
+
let reply = "";
|
|
244
|
+
while (true) {
|
|
245
|
+
const { done, value } = await reader.read();
|
|
246
|
+
if (done) break;
|
|
247
|
+
for (const line of decoder.decode(value).split("\n")) {
|
|
248
|
+
if (line.startsWith("data: ") && line !== "data: [DONE]") {
|
|
249
|
+
try {
|
|
250
|
+
const p = JSON.parse(line.slice(6));
|
|
251
|
+
if (p.type === "text" && p.content) reply += p.content;
|
|
252
|
+
} catch {
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
if (reply) {
|
|
258
|
+
await conversation.send(reply);
|
|
259
|
+
log.success(`replied (${reply.length} chars)`);
|
|
260
|
+
return { delivered: true };
|
|
261
|
+
}
|
|
262
|
+
return { delivered: false, error: "No reply generated" };
|
|
263
|
+
} catch (err) {
|
|
264
|
+
log.error(err.message);
|
|
265
|
+
return { delivered: false, error: err.message };
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
// src/adapters/xmtp/index.ts
|
|
273
|
+
var xmtp_exports = {};
|
|
274
|
+
__export(xmtp_exports, {
|
|
275
|
+
XMTPAdapter: () => XMTPAdapter,
|
|
276
|
+
createXMTPAdapter: () => createXMTPAdapter
|
|
277
|
+
});
|
|
278
|
+
module.exports = __toCommonJS(xmtp_exports);
|
|
279
|
+
var import_node_fs = __toESM(require("fs"), 1);
|
|
280
|
+
var import_node_path = __toESM(require("path"), 1);
|
|
281
|
+
var import_xmtp = require("@hybrd/xmtp");
|
|
282
|
+
var import_memory2 = require("@hybrid/memory");
|
|
283
|
+
var import_agent_sdk2 = require("@xmtp/agent-sdk");
|
|
284
|
+
var import_picocolors2 = __toESM(require("picocolors"), 1);
|
|
285
|
+
init_adapter();
|
|
286
|
+
var log2 = {
|
|
287
|
+
info: (msg) => console.log(`${import_picocolors2.default.magenta("[xmtp]")} ${msg}`),
|
|
288
|
+
error: (msg) => console.error(`${import_picocolors2.default.red("[xmtp]")} ${msg}`),
|
|
289
|
+
warn: (msg) => console.log(`${import_picocolors2.default.yellow("[xmtp]")} ${msg}`),
|
|
290
|
+
success: (msg) => console.log(`${import_picocolors2.default.green("[xmtp]")} ${msg}`)
|
|
291
|
+
};
|
|
292
|
+
var AGENT_PORT = process.env.AGENT_PORT || "8454";
|
|
293
|
+
var XMTP_ENV = process.env.XMTP_ENV || "dev";
|
|
294
|
+
var XMTP_ADAPTER_PORT = Number.parseInt(
|
|
295
|
+
process.env.XMTP_ADAPTER_PORT || "8455",
|
|
296
|
+
10
|
|
297
|
+
);
|
|
298
|
+
process.on("uncaughtException", (err) => {
|
|
299
|
+
log2.error(`FATAL: ${err.message}`);
|
|
300
|
+
process.exit(1);
|
|
301
|
+
});
|
|
302
|
+
process.on("unhandledRejection", (reason) => {
|
|
303
|
+
log2.error(`FATAL: ${reason}`);
|
|
304
|
+
process.exit(1);
|
|
305
|
+
});
|
|
306
|
+
function printBanner(walletAddress, aclCount) {
|
|
307
|
+
const isHotReload = process.env.TSX_WATCH === "true";
|
|
308
|
+
console.log("");
|
|
309
|
+
console.log(
|
|
310
|
+
import_picocolors2.default.magenta(" \u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E")
|
|
311
|
+
);
|
|
312
|
+
console.log(
|
|
313
|
+
import_picocolors2.default.magenta(" \u2502") + import_picocolors2.default.bold(import_picocolors2.default.white(" XMTP Channel Adapter")) + import_picocolors2.default.magenta(" \u2502")
|
|
314
|
+
);
|
|
315
|
+
console.log(
|
|
316
|
+
import_picocolors2.default.magenta(" \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F")
|
|
317
|
+
);
|
|
318
|
+
console.log("");
|
|
319
|
+
console.log(
|
|
320
|
+
` ${import_picocolors2.default.bold("Network")} ${XMTP_ENV === "production" ? import_picocolors2.default.green("production") : import_picocolors2.default.cyan("dev")}`
|
|
321
|
+
);
|
|
322
|
+
console.log(
|
|
323
|
+
` ${import_picocolors2.default.bold("Wallet")} ${walletAddress ? import_picocolors2.default.cyan(walletAddress) : import_picocolors2.default.gray("(not configured)")}`
|
|
324
|
+
);
|
|
325
|
+
console.log(` ${import_picocolors2.default.bold("Agent")} http://localhost:${AGENT_PORT}`);
|
|
326
|
+
console.log(
|
|
327
|
+
` ${import_picocolors2.default.bold("Trigger")} http://127.0.0.1:${XMTP_ADAPTER_PORT}/api/trigger`
|
|
328
|
+
);
|
|
329
|
+
if (aclCount !== void 0) {
|
|
330
|
+
const aclStatus = aclCount > 0 ? import_picocolors2.default.green(`${aclCount} allowed`) : import_picocolors2.default.yellow("open (no allowlist)");
|
|
331
|
+
console.log(` ${import_picocolors2.default.bold("ACL")} ${aclStatus}`);
|
|
332
|
+
}
|
|
333
|
+
console.log("");
|
|
334
|
+
if (isHotReload) {
|
|
335
|
+
console.log(
|
|
336
|
+
` ${import_picocolors2.default.yellow("\u26A1")} Hot reload enabled - watching for changes...`
|
|
337
|
+
);
|
|
338
|
+
} else {
|
|
339
|
+
console.log(` ${import_picocolors2.default.green("\u2713")} Listening for messages...`);
|
|
340
|
+
}
|
|
341
|
+
console.log("");
|
|
342
|
+
}
|
|
343
|
+
async function start() {
|
|
344
|
+
const key = process.env.AGENT_WALLET_KEY;
|
|
345
|
+
if (!key) {
|
|
346
|
+
log2.warn("AGENT_WALLET_KEY not set");
|
|
347
|
+
printBanner();
|
|
348
|
+
await new Promise(() => {
|
|
349
|
+
});
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
const user = (0, import_agent_sdk2.createUser)(key);
|
|
353
|
+
let aclCount;
|
|
354
|
+
try {
|
|
355
|
+
const allowFrom = await (0, import_memory2.readACLAllowFrom)(process.cwd());
|
|
356
|
+
aclCount = allowFrom.length;
|
|
357
|
+
} catch {
|
|
358
|
+
aclCount = 0;
|
|
359
|
+
}
|
|
360
|
+
printBanner(user.account.address, aclCount);
|
|
361
|
+
const secret = (0, import_xmtp.resolveAgentSecret)(key);
|
|
362
|
+
const dbEncryptionKey = new Uint8Array(Buffer.from(secret, "hex"));
|
|
363
|
+
const dbDir = import_node_path.default.join(process.cwd(), ".hybrid", ".xmtp");
|
|
364
|
+
if (!import_node_fs.default.existsSync(dbDir)) {
|
|
365
|
+
import_node_fs.default.mkdirSync(dbDir, { recursive: true });
|
|
366
|
+
}
|
|
367
|
+
const dbPath = import_node_path.default.join(
|
|
368
|
+
dbDir,
|
|
369
|
+
`xmtp-${XMTP_ENV}-${user.account.address.toLowerCase().slice(0, 8)}.db3`
|
|
370
|
+
);
|
|
371
|
+
const config = {
|
|
372
|
+
port: XMTP_ADAPTER_PORT,
|
|
373
|
+
agentUrl: `http://localhost:${AGENT_PORT}`,
|
|
374
|
+
xmtpEnv: XMTP_ENV,
|
|
375
|
+
walletKey: key,
|
|
376
|
+
dbEncryptionKey,
|
|
377
|
+
dbPath,
|
|
378
|
+
workspaceDir: process.cwd()
|
|
379
|
+
};
|
|
380
|
+
await Promise.resolve().then(() => (init_adapter(), adapter_exports)).then(
|
|
381
|
+
({ createXMTPAdapter: createXMTPAdapter2 }) => createXMTPAdapter2(config)
|
|
382
|
+
);
|
|
383
|
+
}
|
|
384
|
+
start().catch((e) => {
|
|
385
|
+
log2.error(e.message);
|
|
386
|
+
process.exit(1);
|
|
387
|
+
});
|
|
388
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
389
|
+
0 && (module.exports = {
|
|
390
|
+
XMTPAdapter,
|
|
391
|
+
createXMTPAdapter
|
|
392
|
+
});
|
|
393
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/adapters/xmtp/adapter.ts","../../../src/adapters/xmtp/index.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\"\nimport type { Server } from \"node:http\"\nimport type {\n\tChannelAdapter,\n\tChannelId,\n\tTriggerRequest,\n\tTriggerResponse\n} from \"@hybrd/types\"\nimport { readACLAllowFrom } from \"@hybrid/memory\"\nimport { Agent } from \"@xmtp/agent-sdk\"\nimport type { Conversation } from \"@xmtp/node-sdk\"\nimport express from \"express\"\nimport pc from \"picocolors\"\n\nconst log = {\n\tinfo: (msg: string) => console.log(`${pc.magenta(\"[xmtp]\")} ${msg}`),\n\terror: (msg: string) => console.error(`${pc.red(\"[xmtp]\")} ${msg}`),\n\twarn: (msg: string) => console.log(`${pc.yellow(\"[xmtp]\")} ${msg}`),\n\tsuccess: (msg: string) => console.log(`${pc.green(\"[xmtp]\")} ${msg}`)\n}\n\nexport interface XMTPAdapterConfig {\n\tport: number\n\tagentUrl: string\n\txmtpEnv?: \"dev\" | \"production\"\n\twalletKey: `0x${string}`\n\tdbEncryptionKey: Uint8Array\n\tdbPath: string\n\tworkspaceDir?: string\n}\n\ninterface TextMessage {\n\tid: string\n\tcontent: string\n\tsenderInboxId: string\n}\n\nexport class XMTPAdapter implements ChannelAdapter {\n\treadonly channel: ChannelId = \"xmtp\"\n\treadonly port: number\n\n\tprivate config: XMTPAdapterConfig\n\tprivate agent: Agent | null = null\n\tprivate server: Server | null = null\n\tprivate app: express.Application\n\tprivate botInboxId: string | null = null\n\tprivate processedMessages: Set<string> = new Set()\n\tprivate addressCache: Map<string, string> = new Map()\n\n\tconstructor(config: XMTPAdapterConfig) {\n\t\tthis.port = config.port\n\t\tthis.config = config\n\t\tthis.app = express()\n\t\tthis.app.use(express.json())\n\t}\n\n\tasync start(): Promise<void> {\n\t\tawait this.startXMTPClient()\n\t\tthis.startTriggerServer()\n\t}\n\n\tasync stop(): Promise<void> {\n\t\tthis.server?.close()\n\t}\n\n\tprivate async startXMTPClient(): Promise<void> {\n\t\tconst { createUser } = await import(\"@xmtp/agent-sdk\")\n\t\tconst { toBytes } = await import(\"viem\")\n\n\t\tconst user = createUser(this.config.walletKey)\n\t\tconst identifier = {\n\t\t\tidentifier: user.account.address.toLowerCase(),\n\t\t\tidentifierKind: 0\n\t\t}\n\n\t\tconst signer = {\n\t\t\ttype: \"EOA\" as const,\n\t\t\tgetIdentifier: () => identifier,\n\t\t\tgetChainId: async () => BigInt(1),\n\t\t\tsignMessage: async (message: string) => {\n\t\t\t\tconst sig = await user.account.signMessage({ message })\n\t\t\t\treturn toBytes(sig)\n\t\t\t}\n\t\t}\n\n\t\tthis.agent = await Agent.create(\n\t\t\tsigner as unknown as Parameters<typeof Agent.create>[0],\n\t\t\t{\n\t\t\t\tenv: this.config.xmtpEnv ?? \"dev\",\n\t\t\t\tdbEncryptionKey: this.config.dbEncryptionKey,\n\t\t\t\tdbPath: this.config.dbPath\n\t\t\t}\n\t\t)\n\n\t\tlog.success(\"connected to XMTP network\")\n\n\t\tthis.botInboxId = this.agent.client.inboxId\n\n\t\tthis.agent.on(\"text\", async (ctx) => {\n\t\t\tconst { conversation, message } = ctx\n\t\t\tawait this.handleInbound(conversation, message as TextMessage)\n\t\t})\n\n\t\tawait this.agent.start()\n\t\tlog.success(\"listening for XMTP messages\")\n\t}\n\n\tprivate startTriggerServer(): void {\n\t\tthis.app.post(\"/api/trigger\", async (req, res) => {\n\t\t\tconst result = await this.handleTrigger(req.body)\n\t\t\tres.json(result)\n\t\t})\n\n\t\tthis.server = this.app.listen(this.port, \"127.0.0.1\", () => {\n\t\t\tlog.success(`trigger server listening on 127.0.0.1:${this.port}`)\n\t\t})\n\t}\n\n\tprivate async resolveSenderAddress(\n\t\tinboxId: string,\n\t\tconversation: Conversation\n\t): Promise<string> {\n\t\tconst cached = this.addressCache.get(inboxId)\n\t\tif (cached) return cached\n\n\t\ttry {\n\t\t\tconst members = await conversation.members()\n\t\t\tconst sender = members.find(\n\t\t\t\t(m: any) => m.inboxId.toLowerCase() === inboxId.toLowerCase()\n\t\t\t)\n\n\t\t\tif (sender) {\n\t\t\t\tconst ethIdentifier = sender.accountIdentifiers.find(\n\t\t\t\t\t(id: any) => id.identifierKind === 0\n\t\t\t\t)\n\t\t\t\tif (ethIdentifier) {\n\t\t\t\t\tconst address = ethIdentifier.identifier.toLowerCase()\n\t\t\t\t\tthis.addressCache.set(inboxId, address)\n\t\t\t\t\treturn address\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst inboxState =\n\t\t\t\tawait this.agent?.client.preferences.inboxStateFromInboxIds([inboxId])\n\t\t\tconst firstState = inboxState?.[0]\n\t\t\tif (firstState?.identifiers?.[0]?.identifier) {\n\t\t\t\tconst address = firstState.identifiers[0].identifier.toLowerCase()\n\t\t\t\tthis.addressCache.set(inboxId, address)\n\t\t\t\treturn address\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tlog.warn(`failed to resolve address for ${inboxId.slice(0, 16)}...`)\n\t\t}\n\n\t\treturn inboxId\n\t}\n\n\tprivate async isSenderAllowed(senderAddress: string): Promise<boolean> {\n\t\tif (!this.config.workspaceDir) {\n\t\t\treturn true\n\t\t}\n\n\t\ttry {\n\t\t\tconst allowFrom = await readACLAllowFrom(this.config.workspaceDir)\n\t\t\tif (allowFrom.length === 0) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tconst normalized = senderAddress.toLowerCase()\n\t\t\treturn allowFrom.includes(normalized)\n\t\t} catch (err) {\n\t\t\tlog.warn(`failed to read ACL, allowing sender: ${(err as Error).message}`)\n\t\t\treturn true\n\t\t}\n\t}\n\n\tprivate async handleInbound(\n\t\tconversation: Conversation,\n\t\tmessage: TextMessage\n\t): Promise<void> {\n\t\tlog.info(`message ${pc.gray(message.id.slice(0, 8))}`)\n\n\t\tif (this.processedMessages.has(message.id)) {\n\t\t\tlog.warn(`skipping duplicate: ${message.id.slice(0, 8)}`)\n\t\t\treturn\n\t\t}\n\t\tthis.processedMessages.add(message.id)\n\n\t\tif (this.processedMessages.size > 1000) {\n\t\t\tconst arr = Array.from(this.processedMessages)\n\t\t\tarr.slice(0, 500).forEach((id) => this.processedMessages.delete(id))\n\t\t}\n\n\t\t// Check if sender is on the allowlist\n\t\tconst senderAddress = await this.resolveSenderAddress(\n\t\t\tmessage.senderInboxId,\n\t\t\tconversation\n\t\t)\n\t\tconst isAllowed = await this.isSenderAllowed(senderAddress)\n\n\t\tif (!isAllowed) {\n\t\t\tlog.warn(\n\t\t\t\t`blocked message from ${senderAddress.slice(0, 10)}... (not on allowlist)`\n\t\t\t)\n\t\t\treturn\n\t\t}\n\n\t\tawait this.runAgentAndReply({\n\t\t\tconversationId: conversation.id,\n\t\t\tmessage: message.content,\n\t\t\tconversation\n\t\t})\n\t}\n\n\tasync trigger(req: TriggerRequest): Promise<TriggerResponse> {\n\t\treturn this.handleTrigger(req)\n\t}\n\n\tprivate async handleTrigger(req: TriggerRequest): Promise<TriggerResponse> {\n\t\tif (!this.agent) {\n\t\t\treturn { delivered: false, error: \"XMTP client not initialized\" }\n\t\t}\n\n\t\tconst conversations = await this.agent.client.conversations.list()\n\t\tconst conversation = conversations.find(\n\t\t\t(c: Conversation) => c.id === req.to\n\t\t)\n\n\t\tif (!conversation) {\n\t\t\treturn { delivered: false, error: \"Conversation not found\" }\n\t\t}\n\n\t\treturn this.runAgentAndReply({\n\t\t\tconversationId: req.to,\n\t\t\tmessage: req.message,\n\t\t\tconversation\n\t\t})\n\t}\n\n\tprivate async runAgentAndReply(params: {\n\t\tconversationId: string\n\t\tmessage: string\n\t\tconversation: Conversation\n\t}): Promise<TriggerResponse> {\n\t\tconst { conversation, message, conversationId } = params\n\n\t\ttry {\n\t\t\tconst res = await fetch(`${this.config.agentUrl}/api/chat`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\t\"X-Request-ID\": randomUUID(),\n\t\t\t\t\t\"X-Source\": \"xmtp-adapter\"\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tmessages: [{ id: randomUUID(), role: \"user\", content: message }],\n\t\t\t\t\tchatId: conversationId\n\t\t\t\t})\n\t\t\t})\n\n\t\t\tif (!res.ok) {\n\t\t\t\tlog.error(`HTTP ${res.status}`)\n\t\t\t\treturn { delivered: false, error: `HTTP ${res.status}` }\n\t\t\t}\n\n\t\t\tconst reader = res.body?.getReader()\n\t\t\tif (!reader) {\n\t\t\t\treturn { delivered: false, error: \"No response body\" }\n\t\t\t}\n\n\t\t\tconst decoder = new TextDecoder()\n\t\t\tlet reply = \"\"\n\n\t\t\twhile (true) {\n\t\t\t\tconst { done, value } = await reader.read()\n\t\t\t\tif (done) break\n\n\t\t\t\tfor (const line of decoder.decode(value).split(\"\\n\")) {\n\t\t\t\t\tif (line.startsWith(\"data: \") && line !== \"data: [DONE]\") {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst p = JSON.parse(line.slice(6))\n\t\t\t\t\t\t\tif (p.type === \"text\" && p.content) reply += p.content\n\t\t\t\t\t\t} catch {}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (reply) {\n\t\t\t\tawait conversation.send(reply)\n\t\t\t\tlog.success(`replied (${reply.length} chars)`)\n\t\t\t\treturn { delivered: true }\n\t\t\t}\n\n\t\t\treturn { delivered: false, error: \"No reply generated\" }\n\t\t} catch (err) {\n\t\t\tlog.error((err as Error).message)\n\t\t\treturn { delivered: false, error: (err as Error).message }\n\t\t}\n\t}\n}\n\nexport async function createXMTPAdapter(\n\tconfig: XMTPAdapterConfig\n): Promise<XMTPAdapter> {\n\tconst adapter = new XMTPAdapter(config)\n\tawait adapter.start()\n\treturn adapter\n}\n","import fs from \"node:fs\"\nimport path from \"node:path\"\nimport { resolveAgentSecret } from \"@hybrd/xmtp\"\nimport { readACLAllowFrom } from \"@hybrid/memory\"\nimport { createUser } from \"@xmtp/agent-sdk\"\nimport pc from \"picocolors\"\nimport { type XMTPAdapterConfig } from \"./adapter.js\"\n\nconst log = {\n\tinfo: (msg: string) => console.log(`${pc.magenta(\"[xmtp]\")} ${msg}`),\n\terror: (msg: string) => console.error(`${pc.red(\"[xmtp]\")} ${msg}`),\n\twarn: (msg: string) => console.log(`${pc.yellow(\"[xmtp]\")} ${msg}`),\n\tsuccess: (msg: string) => console.log(`${pc.green(\"[xmtp]\")} ${msg}`)\n}\n\nconst AGENT_PORT = process.env.AGENT_PORT || \"8454\"\nconst XMTP_ENV = (process.env.XMTP_ENV || \"dev\") as \"dev\" | \"production\"\nconst XMTP_ADAPTER_PORT = Number.parseInt(\n\tprocess.env.XMTP_ADAPTER_PORT || \"8455\",\n\t10\n)\n\nprocess.on(\"uncaughtException\", (err) => {\n\tlog.error(`FATAL: ${err.message}`)\n\tprocess.exit(1)\n})\n\nprocess.on(\"unhandledRejection\", (reason) => {\n\tlog.error(`FATAL: ${reason}`)\n\tprocess.exit(1)\n})\n\nfunction printBanner(walletAddress?: string, aclCount?: number) {\n\tconst isHotReload = process.env.TSX_WATCH === \"true\"\n\n\tconsole.log(\"\")\n\tconsole.log(\n\t\tpc.magenta(\" ╭───────────────────────────────────────────────────╮\")\n\t)\n\tconsole.log(\n\t\tpc.magenta(\" │\") +\n\t\t\tpc.bold(pc.white(\" XMTP Channel Adapter\")) +\n\t\t\tpc.magenta(\" │\")\n\t)\n\tconsole.log(\n\t\tpc.magenta(\" ╰───────────────────────────────────────────────────╯\")\n\t)\n\tconsole.log(\"\")\n\tconsole.log(\n\t\t` ${pc.bold(\"Network\")} ${XMTP_ENV === \"production\" ? pc.green(\"production\") : pc.cyan(\"dev\")}`\n\t)\n\tconsole.log(\n\t\t` ${pc.bold(\"Wallet\")} ${walletAddress ? pc.cyan(walletAddress) : pc.gray(\"(not configured)\")}`\n\t)\n\tconsole.log(` ${pc.bold(\"Agent\")} http://localhost:${AGENT_PORT}`)\n\tconsole.log(\n\t\t` ${pc.bold(\"Trigger\")} http://127.0.0.1:${XMTP_ADAPTER_PORT}/api/trigger`\n\t)\n\tif (aclCount !== undefined) {\n\t\tconst aclStatus =\n\t\t\taclCount > 0\n\t\t\t\t? pc.green(`${aclCount} allowed`)\n\t\t\t\t: pc.yellow(\"open (no allowlist)\")\n\t\tconsole.log(` ${pc.bold(\"ACL\")} ${aclStatus}`)\n\t}\n\tconsole.log(\"\")\n\n\tif (isHotReload) {\n\t\tconsole.log(\n\t\t\t` ${pc.yellow(\"⚡\")} Hot reload enabled - watching for changes...`\n\t\t)\n\t} else {\n\t\tconsole.log(` ${pc.green(\"✓\")} Listening for messages...`)\n\t}\n\tconsole.log(\"\")\n}\n\nasync function start() {\n\tconst key = process.env.AGENT_WALLET_KEY\n\n\tif (!key) {\n\t\tlog.warn(\"AGENT_WALLET_KEY not set\")\n\t\tprintBanner()\n\t\tawait new Promise(() => {})\n\t\treturn\n\t}\n\n\tconst user = createUser(key as `0x${string}`)\n\n\t// Read ACL count for banner\n\tlet aclCount: number | undefined\n\ttry {\n\t\tconst allowFrom = await readACLAllowFrom(process.cwd())\n\t\taclCount = allowFrom.length\n\t} catch {\n\t\t// ACL doesn't exist yet, that's fine\n\t\taclCount = 0\n\t}\n\n\tprintBanner(user.account.address, aclCount)\n\n\tconst secret = resolveAgentSecret(key)\n\tconst dbEncryptionKey = new Uint8Array(Buffer.from(secret, \"hex\"))\n\n\tconst dbDir = path.join(process.cwd(), \".hybrid\", \".xmtp\")\n\tif (!fs.existsSync(dbDir)) {\n\t\tfs.mkdirSync(dbDir, { recursive: true })\n\t}\n\tconst dbPath = path.join(\n\t\tdbDir,\n\t\t`xmtp-${XMTP_ENV}-${user.account.address.toLowerCase().slice(0, 8)}.db3`\n\t)\n\n\tconst config: XMTPAdapterConfig = {\n\t\tport: XMTP_ADAPTER_PORT,\n\t\tagentUrl: `http://localhost:${AGENT_PORT}`,\n\t\txmtpEnv: XMTP_ENV,\n\t\twalletKey: key as `0x${string}`,\n\t\tdbEncryptionKey,\n\t\tdbPath,\n\t\tworkspaceDir: process.cwd()\n\t}\n\n\tawait import(\"./adapter.js\").then(({ createXMTPAdapter }) =>\n\t\tcreateXMTPAdapter(config)\n\t)\n}\n\nstart().catch((e) => {\n\tlog.error(e.message)\n\tprocess.exit(1)\n})\n\nexport {\n\tXMTPAdapter,\n\ttype XMTPAdapterConfig,\n\tcreateXMTPAdapter\n} from \"./adapter.js\"\n"],"mappings":"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","names":["pc","express","createUser","import_memory","import_agent_sdk","import_picocolors","log","pc","path","fs","createXMTPAdapter"]}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { ChannelAdapter, ChannelId, TriggerRequest, TriggerResponse } from '@hybrd/types';
|
|
2
|
+
|
|
3
|
+
interface XMTPAdapterConfig {
|
|
4
|
+
port: number;
|
|
5
|
+
agentUrl: string;
|
|
6
|
+
xmtpEnv?: "dev" | "production";
|
|
7
|
+
walletKey: `0x${string}`;
|
|
8
|
+
dbEncryptionKey: Uint8Array;
|
|
9
|
+
dbPath: string;
|
|
10
|
+
workspaceDir?: string;
|
|
11
|
+
}
|
|
12
|
+
declare class XMTPAdapter implements ChannelAdapter {
|
|
13
|
+
readonly channel: ChannelId;
|
|
14
|
+
readonly port: number;
|
|
15
|
+
private config;
|
|
16
|
+
private agent;
|
|
17
|
+
private server;
|
|
18
|
+
private app;
|
|
19
|
+
private botInboxId;
|
|
20
|
+
private processedMessages;
|
|
21
|
+
private addressCache;
|
|
22
|
+
constructor(config: XMTPAdapterConfig);
|
|
23
|
+
start(): Promise<void>;
|
|
24
|
+
stop(): Promise<void>;
|
|
25
|
+
private startXMTPClient;
|
|
26
|
+
private startTriggerServer;
|
|
27
|
+
private resolveSenderAddress;
|
|
28
|
+
private isSenderAllowed;
|
|
29
|
+
private handleInbound;
|
|
30
|
+
trigger(req: TriggerRequest): Promise<TriggerResponse>;
|
|
31
|
+
private handleTrigger;
|
|
32
|
+
private runAgentAndReply;
|
|
33
|
+
}
|
|
34
|
+
declare function createXMTPAdapter(config: XMTPAdapterConfig): Promise<XMTPAdapter>;
|
|
35
|
+
|
|
36
|
+
export { XMTPAdapter, type XMTPAdapterConfig, createXMTPAdapter };
|