@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
|
@@ -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 };
|
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
+
var __esm = (fn, res) => function __init() {
|
|
4
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
5
|
+
};
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
// src/adapters/xmtp/adapter.ts
|
|
12
|
+
var adapter_exports = {};
|
|
13
|
+
__export(adapter_exports, {
|
|
14
|
+
XMTPAdapter: () => XMTPAdapter,
|
|
15
|
+
createXMTPAdapter: () => createXMTPAdapter
|
|
16
|
+
});
|
|
17
|
+
import { randomUUID } from "crypto";
|
|
18
|
+
import { readACLAllowFrom } from "@hybrid/memory";
|
|
19
|
+
import { Agent } from "@xmtp/agent-sdk";
|
|
20
|
+
import express from "express";
|
|
21
|
+
import pc from "picocolors";
|
|
22
|
+
async function createXMTPAdapter(config) {
|
|
23
|
+
const adapter = new XMTPAdapter(config);
|
|
24
|
+
await adapter.start();
|
|
25
|
+
return adapter;
|
|
26
|
+
}
|
|
27
|
+
var log, XMTPAdapter;
|
|
28
|
+
var init_adapter = __esm({
|
|
29
|
+
"src/adapters/xmtp/adapter.ts"() {
|
|
30
|
+
"use strict";
|
|
31
|
+
log = {
|
|
32
|
+
info: (msg) => console.log(`${pc.magenta("[xmtp]")} ${msg}`),
|
|
33
|
+
error: (msg) => console.error(`${pc.red("[xmtp]")} ${msg}`),
|
|
34
|
+
warn: (msg) => console.log(`${pc.yellow("[xmtp]")} ${msg}`),
|
|
35
|
+
success: (msg) => console.log(`${pc.green("[xmtp]")} ${msg}`)
|
|
36
|
+
};
|
|
37
|
+
XMTPAdapter = class {
|
|
38
|
+
channel = "xmtp";
|
|
39
|
+
port;
|
|
40
|
+
config;
|
|
41
|
+
agent = null;
|
|
42
|
+
server = null;
|
|
43
|
+
app;
|
|
44
|
+
botInboxId = null;
|
|
45
|
+
processedMessages = /* @__PURE__ */ new Set();
|
|
46
|
+
addressCache = /* @__PURE__ */ new Map();
|
|
47
|
+
constructor(config) {
|
|
48
|
+
this.port = config.port;
|
|
49
|
+
this.config = config;
|
|
50
|
+
this.app = express();
|
|
51
|
+
this.app.use(express.json());
|
|
52
|
+
}
|
|
53
|
+
async start() {
|
|
54
|
+
await this.startXMTPClient();
|
|
55
|
+
this.startTriggerServer();
|
|
56
|
+
}
|
|
57
|
+
async stop() {
|
|
58
|
+
this.server?.close();
|
|
59
|
+
}
|
|
60
|
+
async startXMTPClient() {
|
|
61
|
+
const { createUser: createUser2 } = await import("@xmtp/agent-sdk");
|
|
62
|
+
const { toBytes } = await import("viem");
|
|
63
|
+
const user = createUser2(this.config.walletKey);
|
|
64
|
+
const identifier = {
|
|
65
|
+
identifier: user.account.address.toLowerCase(),
|
|
66
|
+
identifierKind: 0
|
|
67
|
+
};
|
|
68
|
+
const signer = {
|
|
69
|
+
type: "EOA",
|
|
70
|
+
getIdentifier: () => identifier,
|
|
71
|
+
getChainId: async () => BigInt(1),
|
|
72
|
+
signMessage: async (message) => {
|
|
73
|
+
const sig = await user.account.signMessage({ message });
|
|
74
|
+
return toBytes(sig);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
this.agent = await Agent.create(
|
|
78
|
+
signer,
|
|
79
|
+
{
|
|
80
|
+
env: this.config.xmtpEnv ?? "dev",
|
|
81
|
+
dbEncryptionKey: this.config.dbEncryptionKey,
|
|
82
|
+
dbPath: this.config.dbPath
|
|
83
|
+
}
|
|
84
|
+
);
|
|
85
|
+
log.success("connected to XMTP network");
|
|
86
|
+
this.botInboxId = this.agent.client.inboxId;
|
|
87
|
+
this.agent.on("text", async (ctx) => {
|
|
88
|
+
const { conversation, message } = ctx;
|
|
89
|
+
await this.handleInbound(conversation, message);
|
|
90
|
+
});
|
|
91
|
+
await this.agent.start();
|
|
92
|
+
log.success("listening for XMTP messages");
|
|
93
|
+
}
|
|
94
|
+
startTriggerServer() {
|
|
95
|
+
this.app.post("/api/trigger", async (req, res) => {
|
|
96
|
+
const result = await this.handleTrigger(req.body);
|
|
97
|
+
res.json(result);
|
|
98
|
+
});
|
|
99
|
+
this.server = this.app.listen(this.port, "127.0.0.1", () => {
|
|
100
|
+
log.success(`trigger server listening on 127.0.0.1:${this.port}`);
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
async resolveSenderAddress(inboxId, conversation) {
|
|
104
|
+
const cached = this.addressCache.get(inboxId);
|
|
105
|
+
if (cached) return cached;
|
|
106
|
+
try {
|
|
107
|
+
const members = await conversation.members();
|
|
108
|
+
const sender = members.find(
|
|
109
|
+
(m) => m.inboxId.toLowerCase() === inboxId.toLowerCase()
|
|
110
|
+
);
|
|
111
|
+
if (sender) {
|
|
112
|
+
const ethIdentifier = sender.accountIdentifiers.find(
|
|
113
|
+
(id) => id.identifierKind === 0
|
|
114
|
+
);
|
|
115
|
+
if (ethIdentifier) {
|
|
116
|
+
const address = ethIdentifier.identifier.toLowerCase();
|
|
117
|
+
this.addressCache.set(inboxId, address);
|
|
118
|
+
return address;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const inboxState = await this.agent?.client.preferences.inboxStateFromInboxIds([inboxId]);
|
|
122
|
+
const firstState = inboxState?.[0];
|
|
123
|
+
if (firstState?.identifiers?.[0]?.identifier) {
|
|
124
|
+
const address = firstState.identifiers[0].identifier.toLowerCase();
|
|
125
|
+
this.addressCache.set(inboxId, address);
|
|
126
|
+
return address;
|
|
127
|
+
}
|
|
128
|
+
} catch (err) {
|
|
129
|
+
log.warn(`failed to resolve address for ${inboxId.slice(0, 16)}...`);
|
|
130
|
+
}
|
|
131
|
+
return inboxId;
|
|
132
|
+
}
|
|
133
|
+
async isSenderAllowed(senderAddress) {
|
|
134
|
+
if (!this.config.workspaceDir) {
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
try {
|
|
138
|
+
const allowFrom = await readACLAllowFrom(this.config.workspaceDir);
|
|
139
|
+
if (allowFrom.length === 0) {
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
const normalized = senderAddress.toLowerCase();
|
|
143
|
+
return allowFrom.includes(normalized);
|
|
144
|
+
} catch (err) {
|
|
145
|
+
log.warn(`failed to read ACL, allowing sender: ${err.message}`);
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
async handleInbound(conversation, message) {
|
|
150
|
+
log.info(`message ${pc.gray(message.id.slice(0, 8))}`);
|
|
151
|
+
if (this.processedMessages.has(message.id)) {
|
|
152
|
+
log.warn(`skipping duplicate: ${message.id.slice(0, 8)}`);
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
this.processedMessages.add(message.id);
|
|
156
|
+
if (this.processedMessages.size > 1e3) {
|
|
157
|
+
const arr = Array.from(this.processedMessages);
|
|
158
|
+
arr.slice(0, 500).forEach((id) => this.processedMessages.delete(id));
|
|
159
|
+
}
|
|
160
|
+
const senderAddress = await this.resolveSenderAddress(
|
|
161
|
+
message.senderInboxId,
|
|
162
|
+
conversation
|
|
163
|
+
);
|
|
164
|
+
const isAllowed = await this.isSenderAllowed(senderAddress);
|
|
165
|
+
if (!isAllowed) {
|
|
166
|
+
log.warn(
|
|
167
|
+
`blocked message from ${senderAddress.slice(0, 10)}... (not on allowlist)`
|
|
168
|
+
);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
await this.runAgentAndReply({
|
|
172
|
+
conversationId: conversation.id,
|
|
173
|
+
message: message.content,
|
|
174
|
+
conversation
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
async trigger(req) {
|
|
178
|
+
return this.handleTrigger(req);
|
|
179
|
+
}
|
|
180
|
+
async handleTrigger(req) {
|
|
181
|
+
if (!this.agent) {
|
|
182
|
+
return { delivered: false, error: "XMTP client not initialized" };
|
|
183
|
+
}
|
|
184
|
+
const conversations = await this.agent.client.conversations.list();
|
|
185
|
+
const conversation = conversations.find(
|
|
186
|
+
(c) => c.id === req.to
|
|
187
|
+
);
|
|
188
|
+
if (!conversation) {
|
|
189
|
+
return { delivered: false, error: "Conversation not found" };
|
|
190
|
+
}
|
|
191
|
+
return this.runAgentAndReply({
|
|
192
|
+
conversationId: req.to,
|
|
193
|
+
message: req.message,
|
|
194
|
+
conversation
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
async runAgentAndReply(params) {
|
|
198
|
+
const { conversation, message, conversationId } = params;
|
|
199
|
+
try {
|
|
200
|
+
const res = await fetch(`${this.config.agentUrl}/api/chat`, {
|
|
201
|
+
method: "POST",
|
|
202
|
+
headers: {
|
|
203
|
+
"Content-Type": "application/json",
|
|
204
|
+
"X-Request-ID": randomUUID(),
|
|
205
|
+
"X-Source": "xmtp-adapter"
|
|
206
|
+
},
|
|
207
|
+
body: JSON.stringify({
|
|
208
|
+
messages: [{ id: randomUUID(), role: "user", content: message }],
|
|
209
|
+
chatId: conversationId
|
|
210
|
+
})
|
|
211
|
+
});
|
|
212
|
+
if (!res.ok) {
|
|
213
|
+
log.error(`HTTP ${res.status}`);
|
|
214
|
+
return { delivered: false, error: `HTTP ${res.status}` };
|
|
215
|
+
}
|
|
216
|
+
const reader = res.body?.getReader();
|
|
217
|
+
if (!reader) {
|
|
218
|
+
return { delivered: false, error: "No response body" };
|
|
219
|
+
}
|
|
220
|
+
const decoder = new TextDecoder();
|
|
221
|
+
let reply = "";
|
|
222
|
+
while (true) {
|
|
223
|
+
const { done, value } = await reader.read();
|
|
224
|
+
if (done) break;
|
|
225
|
+
for (const line of decoder.decode(value).split("\n")) {
|
|
226
|
+
if (line.startsWith("data: ") && line !== "data: [DONE]") {
|
|
227
|
+
try {
|
|
228
|
+
const p = JSON.parse(line.slice(6));
|
|
229
|
+
if (p.type === "text" && p.content) reply += p.content;
|
|
230
|
+
} catch {
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
if (reply) {
|
|
236
|
+
await conversation.send(reply);
|
|
237
|
+
log.success(`replied (${reply.length} chars)`);
|
|
238
|
+
return { delivered: true };
|
|
239
|
+
}
|
|
240
|
+
return { delivered: false, error: "No reply generated" };
|
|
241
|
+
} catch (err) {
|
|
242
|
+
log.error(err.message);
|
|
243
|
+
return { delivered: false, error: err.message };
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// src/adapters/xmtp/index.ts
|
|
251
|
+
init_adapter();
|
|
252
|
+
import fs from "fs";
|
|
253
|
+
import path from "path";
|
|
254
|
+
import { resolveAgentSecret } from "@hybrd/xmtp";
|
|
255
|
+
import { readACLAllowFrom as readACLAllowFrom2 } from "@hybrid/memory";
|
|
256
|
+
import { createUser } from "@xmtp/agent-sdk";
|
|
257
|
+
import pc2 from "picocolors";
|
|
258
|
+
var log2 = {
|
|
259
|
+
info: (msg) => console.log(`${pc2.magenta("[xmtp]")} ${msg}`),
|
|
260
|
+
error: (msg) => console.error(`${pc2.red("[xmtp]")} ${msg}`),
|
|
261
|
+
warn: (msg) => console.log(`${pc2.yellow("[xmtp]")} ${msg}`),
|
|
262
|
+
success: (msg) => console.log(`${pc2.green("[xmtp]")} ${msg}`)
|
|
263
|
+
};
|
|
264
|
+
var AGENT_PORT = process.env.AGENT_PORT || "8454";
|
|
265
|
+
var XMTP_ENV = process.env.XMTP_ENV || "dev";
|
|
266
|
+
var XMTP_ADAPTER_PORT = Number.parseInt(
|
|
267
|
+
process.env.XMTP_ADAPTER_PORT || "8455",
|
|
268
|
+
10
|
|
269
|
+
);
|
|
270
|
+
process.on("uncaughtException", (err) => {
|
|
271
|
+
log2.error(`FATAL: ${err.message}`);
|
|
272
|
+
process.exit(1);
|
|
273
|
+
});
|
|
274
|
+
process.on("unhandledRejection", (reason) => {
|
|
275
|
+
log2.error(`FATAL: ${reason}`);
|
|
276
|
+
process.exit(1);
|
|
277
|
+
});
|
|
278
|
+
function printBanner(walletAddress, aclCount) {
|
|
279
|
+
const isHotReload = process.env.TSX_WATCH === "true";
|
|
280
|
+
console.log("");
|
|
281
|
+
console.log(
|
|
282
|
+
pc2.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")
|
|
283
|
+
);
|
|
284
|
+
console.log(
|
|
285
|
+
pc2.magenta(" \u2502") + pc2.bold(pc2.white(" XMTP Channel Adapter")) + pc2.magenta(" \u2502")
|
|
286
|
+
);
|
|
287
|
+
console.log(
|
|
288
|
+
pc2.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")
|
|
289
|
+
);
|
|
290
|
+
console.log("");
|
|
291
|
+
console.log(
|
|
292
|
+
` ${pc2.bold("Network")} ${XMTP_ENV === "production" ? pc2.green("production") : pc2.cyan("dev")}`
|
|
293
|
+
);
|
|
294
|
+
console.log(
|
|
295
|
+
` ${pc2.bold("Wallet")} ${walletAddress ? pc2.cyan(walletAddress) : pc2.gray("(not configured)")}`
|
|
296
|
+
);
|
|
297
|
+
console.log(` ${pc2.bold("Agent")} http://localhost:${AGENT_PORT}`);
|
|
298
|
+
console.log(
|
|
299
|
+
` ${pc2.bold("Trigger")} http://127.0.0.1:${XMTP_ADAPTER_PORT}/api/trigger`
|
|
300
|
+
);
|
|
301
|
+
if (aclCount !== void 0) {
|
|
302
|
+
const aclStatus = aclCount > 0 ? pc2.green(`${aclCount} allowed`) : pc2.yellow("open (no allowlist)");
|
|
303
|
+
console.log(` ${pc2.bold("ACL")} ${aclStatus}`);
|
|
304
|
+
}
|
|
305
|
+
console.log("");
|
|
306
|
+
if (isHotReload) {
|
|
307
|
+
console.log(
|
|
308
|
+
` ${pc2.yellow("\u26A1")} Hot reload enabled - watching for changes...`
|
|
309
|
+
);
|
|
310
|
+
} else {
|
|
311
|
+
console.log(` ${pc2.green("\u2713")} Listening for messages...`);
|
|
312
|
+
}
|
|
313
|
+
console.log("");
|
|
314
|
+
}
|
|
315
|
+
async function start() {
|
|
316
|
+
const key = process.env.AGENT_WALLET_KEY;
|
|
317
|
+
if (!key) {
|
|
318
|
+
log2.warn("AGENT_WALLET_KEY not set");
|
|
319
|
+
printBanner();
|
|
320
|
+
await new Promise(() => {
|
|
321
|
+
});
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
const user = createUser(key);
|
|
325
|
+
let aclCount;
|
|
326
|
+
try {
|
|
327
|
+
const allowFrom = await readACLAllowFrom2(process.cwd());
|
|
328
|
+
aclCount = allowFrom.length;
|
|
329
|
+
} catch {
|
|
330
|
+
aclCount = 0;
|
|
331
|
+
}
|
|
332
|
+
printBanner(user.account.address, aclCount);
|
|
333
|
+
const secret = resolveAgentSecret(key);
|
|
334
|
+
const dbEncryptionKey = new Uint8Array(Buffer.from(secret, "hex"));
|
|
335
|
+
const dbDir = path.join(process.cwd(), ".hybrid", ".xmtp");
|
|
336
|
+
if (!fs.existsSync(dbDir)) {
|
|
337
|
+
fs.mkdirSync(dbDir, { recursive: true });
|
|
338
|
+
}
|
|
339
|
+
const dbPath = path.join(
|
|
340
|
+
dbDir,
|
|
341
|
+
`xmtp-${XMTP_ENV}-${user.account.address.toLowerCase().slice(0, 8)}.db3`
|
|
342
|
+
);
|
|
343
|
+
const config = {
|
|
344
|
+
port: XMTP_ADAPTER_PORT,
|
|
345
|
+
agentUrl: `http://localhost:${AGENT_PORT}`,
|
|
346
|
+
xmtpEnv: XMTP_ENV,
|
|
347
|
+
walletKey: key,
|
|
348
|
+
dbEncryptionKey,
|
|
349
|
+
dbPath,
|
|
350
|
+
workspaceDir: process.cwd()
|
|
351
|
+
};
|
|
352
|
+
await Promise.resolve().then(() => (init_adapter(), adapter_exports)).then(
|
|
353
|
+
({ createXMTPAdapter: createXMTPAdapter2 }) => createXMTPAdapter2(config)
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
start().catch((e) => {
|
|
357
|
+
log2.error(e.message);
|
|
358
|
+
process.exit(1);
|
|
359
|
+
});
|
|
360
|
+
export {
|
|
361
|
+
XMTPAdapter,
|
|
362
|
+
createXMTPAdapter
|
|
363
|
+
};
|
|
364
|
+
//# sourceMappingURL=index.js.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":["createUser","readACLAllowFrom","pc","log","createXMTPAdapter"]}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
DEFAULT_ADAPTER_PORTS: () => DEFAULT_ADAPTER_PORTS,
|
|
24
|
+
dispatchToChannel: () => dispatchToChannel
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(index_exports);
|
|
27
|
+
|
|
28
|
+
// src/dispatcher.ts
|
|
29
|
+
var DEFAULT_ADAPTER_PORTS = {
|
|
30
|
+
xmtp: 8455
|
|
31
|
+
// telegram: 8456, // future
|
|
32
|
+
// slack: 8457, // future
|
|
33
|
+
};
|
|
34
|
+
async function dispatchToChannel(params) {
|
|
35
|
+
const port = DEFAULT_ADAPTER_PORTS[params.channel];
|
|
36
|
+
if (!port) {
|
|
37
|
+
return { delivered: false, error: `Unknown channel: ${params.channel}` };
|
|
38
|
+
}
|
|
39
|
+
const url = `http://127.0.0.1:${port}/api/trigger`;
|
|
40
|
+
try {
|
|
41
|
+
const res = await fetch(url, {
|
|
42
|
+
method: "POST",
|
|
43
|
+
headers: { "Content-Type": "application/json" },
|
|
44
|
+
body: JSON.stringify({
|
|
45
|
+
to: params.to,
|
|
46
|
+
message: params.message,
|
|
47
|
+
metadata: params.metadata
|
|
48
|
+
})
|
|
49
|
+
});
|
|
50
|
+
if (!res.ok) {
|
|
51
|
+
return {
|
|
52
|
+
delivered: false,
|
|
53
|
+
error: `Channel adapter returned ${res.status}: ${res.statusText}`
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
return await res.json();
|
|
57
|
+
} catch (err) {
|
|
58
|
+
return {
|
|
59
|
+
delivered: false,
|
|
60
|
+
error: err instanceof Error ? err.message : "Failed to connect to channel adapter"
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
65
|
+
0 && (module.exports = {
|
|
66
|
+
DEFAULT_ADAPTER_PORTS,
|
|
67
|
+
dispatchToChannel
|
|
68
|
+
});
|
|
69
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/dispatcher.ts"],"sourcesContent":["export type {\n\tChannelId,\n\tCronDeliveryMode,\n\tCronDelivery,\n\tTriggerRequest,\n\tTriggerResponse,\n\tChannelAdapter,\n\tChannelDispatcher\n} from \"@hybrd/types\"\n\nexport { dispatchToChannel, DEFAULT_ADAPTER_PORTS } from \"./dispatcher.js\"\n","import type { ChannelId, TriggerRequest, TriggerResponse } from \"@hybrd/types\"\n\nexport const DEFAULT_ADAPTER_PORTS: Record<string, number> = {\n\txmtp: 8455\n\t// telegram: 8456, // future\n\t// slack: 8457, // future\n}\n\nexport async function dispatchToChannel(params: {\n\tchannel: ChannelId\n\tto: string\n\tmessage: string\n\tmetadata?: TriggerRequest[\"metadata\"]\n}): Promise<TriggerResponse> {\n\tconst port = DEFAULT_ADAPTER_PORTS[params.channel]\n\n\tif (!port) {\n\t\treturn { delivered: false, error: `Unknown channel: ${params.channel}` }\n\t}\n\n\tconst url = `http://127.0.0.1:${port}/api/trigger`\n\n\ttry {\n\t\tconst res = await fetch(url, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\tbody: JSON.stringify({\n\t\t\t\tto: params.to,\n\t\t\t\tmessage: params.message,\n\t\t\t\tmetadata: params.metadata\n\t\t\t})\n\t\t})\n\n\t\tif (!res.ok) {\n\t\t\treturn {\n\t\t\t\tdelivered: false,\n\t\t\t\terror: `Channel adapter returned ${res.status}: ${res.statusText}`\n\t\t\t}\n\t\t}\n\n\t\treturn (await res.json()) as TriggerResponse\n\t} catch (err) {\n\t\treturn {\n\t\t\tdelivered: false,\n\t\t\terror:\n\t\t\t\terr instanceof Error\n\t\t\t\t\t? err.message\n\t\t\t\t\t: \"Failed to connect to channel adapter\"\n\t\t}\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEO,IAAM,wBAAgD;AAAA,EAC5D,MAAM;AAAA;AAAA;AAGP;AAEA,eAAsB,kBAAkB,QAKX;AAC5B,QAAM,OAAO,sBAAsB,OAAO,OAAO;AAEjD,MAAI,CAAC,MAAM;AACV,WAAO,EAAE,WAAW,OAAO,OAAO,oBAAoB,OAAO,OAAO,GAAG;AAAA,EACxE;AAEA,QAAM,MAAM,oBAAoB,IAAI;AAEpC,MAAI;AACH,UAAM,MAAM,MAAM,MAAM,KAAK;AAAA,MAC5B,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU;AAAA,QACpB,IAAI,OAAO;AAAA,QACX,SAAS,OAAO;AAAA,QAChB,UAAU,OAAO;AAAA,MAClB,CAAC;AAAA,IACF,CAAC;AAED,QAAI,CAAC,IAAI,IAAI;AACZ,aAAO;AAAA,QACN,WAAW;AAAA,QACX,OAAO,4BAA4B,IAAI,MAAM,KAAK,IAAI,UAAU;AAAA,MACjE;AAAA,IACD;AAEA,WAAQ,MAAM,IAAI,KAAK;AAAA,EACxB,SAAS,KAAK;AACb,WAAO;AAAA,MACN,WAAW;AAAA,MACX,OACC,eAAe,QACZ,IAAI,UACJ;AAAA,IACL;AAAA,EACD;AACD;","names":[]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ChannelId, TriggerRequest, TriggerResponse } from '@hybrd/types';
|
|
2
|
+
export { ChannelAdapter, ChannelDispatcher, ChannelId, CronDelivery, CronDeliveryMode, TriggerRequest, TriggerResponse } from '@hybrd/types';
|
|
3
|
+
|
|
4
|
+
declare const DEFAULT_ADAPTER_PORTS: Record<string, number>;
|
|
5
|
+
declare function dispatchToChannel(params: {
|
|
6
|
+
channel: ChannelId;
|
|
7
|
+
to: string;
|
|
8
|
+
message: string;
|
|
9
|
+
metadata?: TriggerRequest["metadata"];
|
|
10
|
+
}): Promise<TriggerResponse>;
|
|
11
|
+
|
|
12
|
+
export { DEFAULT_ADAPTER_PORTS, dispatchToChannel };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ChannelId, TriggerRequest, TriggerResponse } from '@hybrd/types';
|
|
2
|
+
export { ChannelAdapter, ChannelDispatcher, ChannelId, CronDelivery, CronDeliveryMode, TriggerRequest, TriggerResponse } from '@hybrd/types';
|
|
3
|
+
|
|
4
|
+
declare const DEFAULT_ADAPTER_PORTS: Record<string, number>;
|
|
5
|
+
declare function dispatchToChannel(params: {
|
|
6
|
+
channel: ChannelId;
|
|
7
|
+
to: string;
|
|
8
|
+
message: string;
|
|
9
|
+
metadata?: TriggerRequest["metadata"];
|
|
10
|
+
}): Promise<TriggerResponse>;
|
|
11
|
+
|
|
12
|
+
export { DEFAULT_ADAPTER_PORTS, dispatchToChannel };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// src/dispatcher.ts
|
|
2
|
+
var DEFAULT_ADAPTER_PORTS = {
|
|
3
|
+
xmtp: 8455
|
|
4
|
+
// telegram: 8456, // future
|
|
5
|
+
// slack: 8457, // future
|
|
6
|
+
};
|
|
7
|
+
async function dispatchToChannel(params) {
|
|
8
|
+
const port = DEFAULT_ADAPTER_PORTS[params.channel];
|
|
9
|
+
if (!port) {
|
|
10
|
+
return { delivered: false, error: `Unknown channel: ${params.channel}` };
|
|
11
|
+
}
|
|
12
|
+
const url = `http://127.0.0.1:${port}/api/trigger`;
|
|
13
|
+
try {
|
|
14
|
+
const res = await fetch(url, {
|
|
15
|
+
method: "POST",
|
|
16
|
+
headers: { "Content-Type": "application/json" },
|
|
17
|
+
body: JSON.stringify({
|
|
18
|
+
to: params.to,
|
|
19
|
+
message: params.message,
|
|
20
|
+
metadata: params.metadata
|
|
21
|
+
})
|
|
22
|
+
});
|
|
23
|
+
if (!res.ok) {
|
|
24
|
+
return {
|
|
25
|
+
delivered: false,
|
|
26
|
+
error: `Channel adapter returned ${res.status}: ${res.statusText}`
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
return await res.json();
|
|
30
|
+
} catch (err) {
|
|
31
|
+
return {
|
|
32
|
+
delivered: false,
|
|
33
|
+
error: err instanceof Error ? err.message : "Failed to connect to channel adapter"
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export {
|
|
38
|
+
DEFAULT_ADAPTER_PORTS,
|
|
39
|
+
dispatchToChannel
|
|
40
|
+
};
|
|
41
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/dispatcher.ts"],"sourcesContent":["import type { ChannelId, TriggerRequest, TriggerResponse } from \"@hybrd/types\"\n\nexport const DEFAULT_ADAPTER_PORTS: Record<string, number> = {\n\txmtp: 8455\n\t// telegram: 8456, // future\n\t// slack: 8457, // future\n}\n\nexport async function dispatchToChannel(params: {\n\tchannel: ChannelId\n\tto: string\n\tmessage: string\n\tmetadata?: TriggerRequest[\"metadata\"]\n}): Promise<TriggerResponse> {\n\tconst port = DEFAULT_ADAPTER_PORTS[params.channel]\n\n\tif (!port) {\n\t\treturn { delivered: false, error: `Unknown channel: ${params.channel}` }\n\t}\n\n\tconst url = `http://127.0.0.1:${port}/api/trigger`\n\n\ttry {\n\t\tconst res = await fetch(url, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\tbody: JSON.stringify({\n\t\t\t\tto: params.to,\n\t\t\t\tmessage: params.message,\n\t\t\t\tmetadata: params.metadata\n\t\t\t})\n\t\t})\n\n\t\tif (!res.ok) {\n\t\t\treturn {\n\t\t\t\tdelivered: false,\n\t\t\t\terror: `Channel adapter returned ${res.status}: ${res.statusText}`\n\t\t\t}\n\t\t}\n\n\t\treturn (await res.json()) as TriggerResponse\n\t} catch (err) {\n\t\treturn {\n\t\t\tdelivered: false,\n\t\t\terror:\n\t\t\t\terr instanceof Error\n\t\t\t\t\t? err.message\n\t\t\t\t\t: \"Failed to connect to channel adapter\"\n\t\t}\n\t}\n}\n"],"mappings":";AAEO,IAAM,wBAAgD;AAAA,EAC5D,MAAM;AAAA;AAAA;AAGP;AAEA,eAAsB,kBAAkB,QAKX;AAC5B,QAAM,OAAO,sBAAsB,OAAO,OAAO;AAEjD,MAAI,CAAC,MAAM;AACV,WAAO,EAAE,WAAW,OAAO,OAAO,oBAAoB,OAAO,OAAO,GAAG;AAAA,EACxE;AAEA,QAAM,MAAM,oBAAoB,IAAI;AAEpC,MAAI;AACH,UAAM,MAAM,MAAM,MAAM,KAAK;AAAA,MAC5B,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU;AAAA,QACpB,IAAI,OAAO;AAAA,QACX,SAAS,OAAO;AAAA,QAChB,UAAU,OAAO;AAAA,MAClB,CAAC;AAAA,IACF,CAAC;AAED,QAAI,CAAC,IAAI,IAAI;AACZ,aAAO;AAAA,QACN,WAAW;AAAA,QACX,OAAO,4BAA4B,IAAI,MAAM,KAAK,IAAI,UAAU;AAAA,MACjE;AAAA,IACD;AAEA,WAAQ,MAAM,IAAI,KAAK;AAAA,EACxB,SAAS,KAAK;AACb,WAAO;AAAA,MACN,WAAW;AAAA,MACX,OACC,eAAe,QACZ,IAAI,UACJ;AAAA,IACL;AAAA,EACD;AACD;","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hybrd/channels",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"keywords": [
|
|
5
|
+
"channels",
|
|
6
|
+
"xmtp",
|
|
7
|
+
"telegram",
|
|
8
|
+
"slack",
|
|
9
|
+
"hybrid",
|
|
10
|
+
"adapter"
|
|
11
|
+
],
|
|
12
|
+
"type": "module",
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"src"
|
|
16
|
+
],
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"import": "./dist/index.js",
|
|
21
|
+
"require": "./dist/index.cjs"
|
|
22
|
+
},
|
|
23
|
+
"./adapters/xmtp": {
|
|
24
|
+
"types": "./dist/adapters/xmtp/index.d.ts",
|
|
25
|
+
"import": "./dist/adapters/xmtp/index.js",
|
|
26
|
+
"require": "./dist/adapters/xmtp/index.cjs"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@xmtp/agent-sdk": "0.0.14",
|
|
31
|
+
"@xmtp/node-bindings": "^1.9.1",
|
|
32
|
+
"@xmtp/node-sdk": "^4.1.0",
|
|
33
|
+
"express": "^5.0.0",
|
|
34
|
+
"hono": "^4.6.12",
|
|
35
|
+
"picocolors": "^1.1.1",
|
|
36
|
+
"viem": "^2.23.0",
|
|
37
|
+
"@hybrd/types": "2.0.0",
|
|
38
|
+
"@hybrd/xmtp": "2.0.0",
|
|
39
|
+
"@hybrid/memory": "2.0.0"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/express": "^5.0.0",
|
|
43
|
+
"@types/node": "22.8.6",
|
|
44
|
+
"tsup": "^8.5.0",
|
|
45
|
+
"vitest": "^3.2.4",
|
|
46
|
+
"@config/biome": "0.0.0",
|
|
47
|
+
"@config/tsconfig": "0.0.0"
|
|
48
|
+
},
|
|
49
|
+
"scripts": {
|
|
50
|
+
"build": "tsup",
|
|
51
|
+
"build:watch": "tsup --watch",
|
|
52
|
+
"clean": "rm -rf .turbo dist",
|
|
53
|
+
"typecheck": "tsc --noEmit",
|
|
54
|
+
"lint": "biome lint --unsafe",
|
|
55
|
+
"lint:fix": "biome lint --write --unsafe",
|
|
56
|
+
"format": "biome format --write",
|
|
57
|
+
"test": "vitest run",
|
|
58
|
+
"test:watch": "vitest"
|
|
59
|
+
}
|
|
60
|
+
}
|