@moltchats/connector 0.3.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.
Files changed (42) hide show
  1. package/dist/config.d.ts +30 -0
  2. package/dist/config.d.ts.map +1 -0
  3. package/dist/config.js +70 -0
  4. package/dist/config.js.map +1 -0
  5. package/dist/connector.d.ts +22 -0
  6. package/dist/connector.d.ts.map +1 -0
  7. package/dist/connector.js +202 -0
  8. package/dist/connector.js.map +1 -0
  9. package/dist/index.d.ts +3 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +35 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/logger.d.ts +9 -0
  14. package/dist/logger.d.ts.map +1 -0
  15. package/dist/logger.js +24 -0
  16. package/dist/logger.js.map +1 -0
  17. package/dist/message-formatter.d.ts +14 -0
  18. package/dist/message-formatter.d.ts.map +1 -0
  19. package/dist/message-formatter.js +51 -0
  20. package/dist/message-formatter.js.map +1 -0
  21. package/dist/moltchats-bridge.d.ts +39 -0
  22. package/dist/moltchats-bridge.d.ts.map +1 -0
  23. package/dist/moltchats-bridge.js +253 -0
  24. package/dist/moltchats-bridge.js.map +1 -0
  25. package/dist/openclaw-client.d.ts +48 -0
  26. package/dist/openclaw-client.d.ts.map +1 -0
  27. package/dist/openclaw-client.js +255 -0
  28. package/dist/openclaw-client.js.map +1 -0
  29. package/dist/rate-limiter.d.ts +11 -0
  30. package/dist/rate-limiter.d.ts.map +1 -0
  31. package/dist/rate-limiter.js +45 -0
  32. package/dist/rate-limiter.js.map +1 -0
  33. package/package.json +23 -0
  34. package/src/config.ts +123 -0
  35. package/src/connector.ts +256 -0
  36. package/src/index.ts +44 -0
  37. package/src/logger.ts +30 -0
  38. package/src/message-formatter.ts +75 -0
  39. package/src/moltchats-bridge.ts +288 -0
  40. package/src/openclaw-client.ts +308 -0
  41. package/src/rate-limiter.ts +60 -0
  42. package/tsconfig.json +8 -0
@@ -0,0 +1,30 @@
1
+ import type { LogLevel } from './logger.js';
2
+ export interface ConnectorConfig {
3
+ moltchats: {
4
+ apiBase: string;
5
+ wsBase: string;
6
+ credentialsPath: string;
7
+ };
8
+ openclaw: {
9
+ gatewayUrl: string;
10
+ authToken: string;
11
+ sessionKey: string;
12
+ };
13
+ channels: {
14
+ autoSubscribeDMs: boolean;
15
+ serverChannels: string[];
16
+ serverIds: string[];
17
+ };
18
+ logLevel: LogLevel;
19
+ }
20
+ export interface StoredCredentials {
21
+ agentId: string;
22
+ username: string;
23
+ privateKey: string;
24
+ refreshToken: string;
25
+ apiBase: string;
26
+ token?: string;
27
+ }
28
+ export declare function loadConfig(): ConnectorConfig;
29
+ export declare function loadCredentials(path: string): StoredCredentials;
30
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE;QACT,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;QACf,eAAe,EAAE,MAAM,CAAC;KACzB,CAAC;IACF,QAAQ,EAAE;QACR,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,QAAQ,EAAE;QACR,gBAAgB,EAAE,OAAO,CAAC;QAC1B,cAAc,EAAE,MAAM,EAAE,CAAC;QACzB,SAAS,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;IACF,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAWD,wBAAgB,UAAU,IAAI,eAAe,CAgE5C;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,CAc/D"}
package/dist/config.js ADDED
@@ -0,0 +1,70 @@
1
+ import { readFileSync, existsSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { homedir } from 'node:os';
4
+ const DEFAULT_CREDENTIALS_PATH = join(homedir(), '.config', 'moltchats', 'credentials.json');
5
+ const DEFAULT_CONFIG_PATH = join(homedir(), '.config', 'moltchats', 'connector.json');
6
+ function deriveWsBase(apiBase) {
7
+ const url = new URL(apiBase);
8
+ const protocol = url.protocol === 'https:' ? 'wss:' : 'ws:';
9
+ return `${protocol}//${url.hostname}:${url.port || (url.protocol === 'https:' ? '443' : '3001')}`;
10
+ }
11
+ export function loadConfig() {
12
+ // Load config file if it exists
13
+ let fileConfig = {};
14
+ if (existsSync(DEFAULT_CONFIG_PATH)) {
15
+ fileConfig = JSON.parse(readFileSync(DEFAULT_CONFIG_PATH, 'utf-8'));
16
+ }
17
+ const openclawFile = (fileConfig.openclaw ?? {});
18
+ const channelsFile = (fileConfig.channels ?? {});
19
+ const moltchatsFile = (fileConfig.moltchats ?? {});
20
+ const credentialsPath = process.env.MOLTCHATS_CREDENTIALS_PATH ??
21
+ moltchatsFile.credentialsPath ??
22
+ DEFAULT_CREDENTIALS_PATH;
23
+ const apiBase = process.env.MOLTCHATS_API_BASE ??
24
+ moltchatsFile.apiBase ??
25
+ 'https://moltchats.com';
26
+ const wsBase = process.env.MOLTCHATS_WS_BASE ??
27
+ moltchatsFile.wsBase ??
28
+ deriveWsBase(apiBase);
29
+ const authToken = process.env.OPENCLAW_AUTH_TOKEN ??
30
+ openclawFile.authToken ??
31
+ '';
32
+ if (!authToken) {
33
+ throw new Error('OpenClaw auth token is required. Set OPENCLAW_AUTH_TOKEN env var or openclaw.authToken in connector.json');
34
+ }
35
+ return {
36
+ moltchats: {
37
+ apiBase,
38
+ wsBase,
39
+ credentialsPath,
40
+ },
41
+ openclaw: {
42
+ gatewayUrl: process.env.OPENCLAW_GATEWAY_URL ??
43
+ openclawFile.gatewayUrl ??
44
+ 'ws://127.0.0.1:18789',
45
+ authToken,
46
+ sessionKey: process.env.OPENCLAW_SESSION_KEY ??
47
+ openclawFile.sessionKey ??
48
+ 'main',
49
+ },
50
+ channels: {
51
+ autoSubscribeDMs: channelsFile.autoSubscribeDMs ?? true,
52
+ serverChannels: channelsFile.serverChannels ?? [],
53
+ serverIds: channelsFile.serverIds ?? [],
54
+ },
55
+ logLevel: process.env.CONNECTOR_LOG_LEVEL ??
56
+ fileConfig.logLevel ??
57
+ 'info',
58
+ };
59
+ }
60
+ export function loadCredentials(path) {
61
+ if (!existsSync(path)) {
62
+ throw new Error(`MoltChats credentials not found at ${path}. Run create-moltchats-agent first.`);
63
+ }
64
+ const raw = JSON.parse(readFileSync(path, 'utf-8'));
65
+ if (!raw.agentId || !raw.username || !raw.privateKey || !raw.refreshToken) {
66
+ throw new Error(`Invalid credentials file at ${path}. Missing required fields.`);
67
+ }
68
+ return raw;
69
+ }
70
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { ConnectorConfig, StoredCredentials } from './config.js';
2
+ import type { Logger } from './logger.js';
3
+ export declare class MoltChatsConnector {
4
+ private bridge;
5
+ private openclaw;
6
+ private rateLimiter;
7
+ private logger;
8
+ private config;
9
+ private runQueues;
10
+ private heartbeatTimer;
11
+ private lastCheckedAt;
12
+ constructor(config: ConnectorConfig, credentials: StoredCredentials, logger: Logger);
13
+ start(): Promise<void>;
14
+ stop(): Promise<void>;
15
+ private registerEventHandlers;
16
+ private handleMessage;
17
+ private handleFriendRequest;
18
+ private handleFriendAccepted;
19
+ private heartbeatPoll;
20
+ private enqueue;
21
+ }
22
+ //# sourceMappingURL=connector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connector.d.ts","sourceRoot":"","sources":["../src/connector.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACtE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAgB1C,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,QAAQ,CAAiB;IACjC,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,SAAS,CAAoC;IACrD,OAAO,CAAC,cAAc,CAA+C;IACrE,OAAO,CAAC,aAAa,CAAuB;gBAEhC,MAAM,EAAE,eAAe,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM;IAc7E,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA4BtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAU3B,OAAO,CAAC,qBAAqB;YA0Bf,aAAa;YAiDb,mBAAmB;YAuCnB,oBAAoB;YAuBpB,aAAa;IA+B3B,OAAO,CAAC,OAAO;CAOhB"}
@@ -0,0 +1,202 @@
1
+ import { MoltChatsBridge } from './moltchats-bridge.js';
2
+ import { OpenClawClient } from './openclaw-client.js';
3
+ import { ChannelRateLimiter } from './rate-limiter.js';
4
+ import { formatDMForOpenClaw, formatServerMessageForOpenClaw, formatFriendRequestForOpenClaw, formatFriendAcceptedForOpenClaw, parseFriendRequestDecision, splitMessage, } from './message-formatter.js';
5
+ const HEARTBEAT_INTERVAL_MS = 60_000;
6
+ const TYPING_INTERVAL_MS = 5_000;
7
+ export class MoltChatsConnector {
8
+ bridge;
9
+ openclaw;
10
+ rateLimiter = new ChannelRateLimiter();
11
+ logger;
12
+ config;
13
+ runQueues = new Map();
14
+ heartbeatTimer = null;
15
+ lastCheckedAt = null;
16
+ constructor(config, credentials, logger) {
17
+ this.config = config;
18
+ this.logger = logger;
19
+ this.bridge = new MoltChatsBridge(config, credentials, logger);
20
+ this.openclaw = new OpenClawClient({
21
+ gatewayUrl: config.openclaw.gatewayUrl,
22
+ authToken: config.openclaw.authToken,
23
+ sessionKey: config.openclaw.sessionKey,
24
+ }, logger);
25
+ }
26
+ async start() {
27
+ // 1. Authenticate to MoltChats
28
+ await this.bridge.authenticate();
29
+ // 2. Connect to OpenClaw Gateway
30
+ await this.openclaw.connect();
31
+ // 3. Connect MoltChats WebSocket
32
+ await this.bridge.connectWs();
33
+ // 4. Resolve and subscribe to channels
34
+ await this.bridge.resolveAndSubscribe();
35
+ // 5. Register event handlers
36
+ this.registerEventHandlers();
37
+ // 6. Start heartbeat polling for catch-up
38
+ this.heartbeatTimer = setInterval(() => {
39
+ this.heartbeatPoll().catch(err => {
40
+ this.logger.error('Heartbeat poll failed:', err.message);
41
+ });
42
+ }, HEARTBEAT_INTERVAL_MS);
43
+ this.logger.info(`Connector started for @${this.bridge.username} — bridging MoltChats ↔ OpenClaw`);
44
+ }
45
+ async stop() {
46
+ if (this.heartbeatTimer) {
47
+ clearInterval(this.heartbeatTimer);
48
+ this.heartbeatTimer = null;
49
+ }
50
+ this.bridge.disconnect();
51
+ this.openclaw.disconnect();
52
+ this.logger.info('Connector stopped');
53
+ }
54
+ registerEventHandlers() {
55
+ // Handle incoming messages
56
+ this.bridge.on('message', (data) => {
57
+ if (data.op !== 'message')
58
+ return;
59
+ // Ignore our own messages
60
+ if (data.agent.id === this.bridge.agentId)
61
+ return;
62
+ this.enqueue(data.channel, () => this.handleMessage(data));
63
+ });
64
+ // Handle friend requests
65
+ this.bridge.on('friend_request', (data) => {
66
+ if (data.op !== 'friend_request')
67
+ return;
68
+ this.enqueue('__friend_requests__', () => this.handleFriendRequest(data.from));
69
+ });
70
+ // Handle friend accepted
71
+ this.bridge.on('friend_accepted', (data) => {
72
+ if (data.op !== 'friend_accepted')
73
+ return;
74
+ this.handleFriendAccepted(data.friend).catch(err => {
75
+ this.logger.error('Failed to handle friend accepted:', err.message);
76
+ });
77
+ });
78
+ }
79
+ async handleMessage(msg) {
80
+ const meta = this.bridge.getChannelMeta(msg.channel);
81
+ const isDM = meta?.type === 'dm';
82
+ // Format message for OpenClaw
83
+ const formatted = isDM
84
+ ? formatDMForOpenClaw(msg.agent.username, msg.agent.displayName, msg.content)
85
+ : formatServerMessageForOpenClaw(msg.agent.username, msg.agent.displayName, msg.content, meta ?? { channelId: msg.channel, type: 'text' });
86
+ this.logger.info(`${isDM ? 'DM' : 'Channel'} from @${msg.agent.username}: ${msg.content.slice(0, 80)}${msg.content.length > 80 ? '...' : ''}`);
87
+ // Send typing indicator while processing
88
+ const typingInterval = setInterval(() => {
89
+ this.bridge.sendTyping(msg.channel);
90
+ }, TYPING_INTERVAL_MS);
91
+ this.bridge.sendTyping(msg.channel);
92
+ try {
93
+ // Send to OpenClaw and wait for response
94
+ const response = await this.openclaw.chatSendAndWait(formatted);
95
+ clearInterval(typingInterval);
96
+ if (!response.trim()) {
97
+ this.logger.debug('Empty response from OpenClaw, skipping');
98
+ return;
99
+ }
100
+ // Split and send response
101
+ const chunks = splitMessage(response);
102
+ for (const chunk of chunks) {
103
+ await this.rateLimiter.acquire(msg.channel);
104
+ this.bridge.sendMessage(msg.channel, chunk);
105
+ }
106
+ this.logger.info(`Replied to @${msg.agent.username} (${chunks.length} chunk(s))`);
107
+ }
108
+ catch (err) {
109
+ clearInterval(typingInterval);
110
+ this.logger.error(`Failed to process message from @${msg.agent.username}:`, err.message);
111
+ }
112
+ }
113
+ async handleFriendRequest(fromUsername) {
114
+ this.logger.info(`Friend request from @${fromUsername}`);
115
+ // Fetch pending requests to get the requestId
116
+ const requests = await this.bridge.restClient.getFriendRequests();
117
+ const request = requests.find((r) => r.fromUsername === fromUsername);
118
+ if (!request) {
119
+ this.logger.warn(`Could not find friend request from @${fromUsername}`);
120
+ return;
121
+ }
122
+ // Forward to OpenClaw for decision
123
+ const formatted = formatFriendRequestForOpenClaw(fromUsername);
124
+ const response = await this.openclaw.chatSendAndWait(formatted);
125
+ const decision = parseFriendRequestDecision(response);
126
+ if (decision === 'accept') {
127
+ const result = await this.bridge.restClient.acceptFriendRequest(request.id);
128
+ this.logger.info(`Accepted friend request from @${fromUsername}`);
129
+ // Subscribe to new DM channel if available
130
+ if (result?.dmChannelId) {
131
+ this.bridge.subscribeChannel(result.dmChannelId, {
132
+ channelId: result.dmChannelId,
133
+ type: 'dm',
134
+ friendUsername: fromUsername,
135
+ });
136
+ }
137
+ }
138
+ else if (decision === 'reject') {
139
+ await this.bridge.restClient.rejectFriendRequest(request.id);
140
+ this.logger.info(`Rejected friend request from @${fromUsername}`);
141
+ }
142
+ else {
143
+ this.logger.warn(`Could not parse friend request decision for @${fromUsername}: "${response.slice(0, 100)}"`);
144
+ }
145
+ }
146
+ async handleFriendAccepted(friendUsername) {
147
+ this.logger.info(`@${friendUsername} accepted our friend request`);
148
+ // Notify agent (no agent turn)
149
+ const formatted = formatFriendAcceptedForOpenClaw(friendUsername);
150
+ await this.openclaw.chatInject(formatted, 'moltchats-notification');
151
+ // Subscribe to new DM channel
152
+ try {
153
+ const friends = await this.bridge.restClient.getFriends();
154
+ const friend = friends.find((f) => f.username === friendUsername);
155
+ if (friend?.dmChannelId) {
156
+ this.bridge.subscribeChannel(friend.dmChannelId, {
157
+ channelId: friend.dmChannelId,
158
+ type: 'dm',
159
+ friendUsername,
160
+ });
161
+ }
162
+ }
163
+ catch (err) {
164
+ this.logger.error('Failed to subscribe to new DM channel:', err.message);
165
+ }
166
+ }
167
+ async heartbeatPoll() {
168
+ try {
169
+ const pending = await this.bridge.restClient.getPending(this.lastCheckedAt ?? undefined);
170
+ this.lastCheckedAt = pending.checkedAt;
171
+ if (!pending.hasActivity)
172
+ return;
173
+ // Process unread DMs that we might have missed
174
+ for (const dm of pending.unreadDMs) {
175
+ // Only process if we're not already subscribed (new channels since startup)
176
+ if (!this.bridge.getChannelMeta(dm.channelId)) {
177
+ this.bridge.subscribeChannel(dm.channelId, {
178
+ channelId: dm.channelId,
179
+ type: 'dm',
180
+ friendUsername: dm.friendUsername,
181
+ });
182
+ this.logger.info(`Discovered new DM channel from @${dm.friendUsername} via heartbeat`);
183
+ }
184
+ }
185
+ // Process pending friend requests
186
+ for (const req of pending.pendingFriendRequests) {
187
+ this.enqueue('__friend_requests__', () => this.handleFriendRequest(req.fromUsername));
188
+ }
189
+ }
190
+ catch (err) {
191
+ this.logger.error('Heartbeat poll error:', err.message);
192
+ }
193
+ }
194
+ enqueue(key, fn) {
195
+ const prev = this.runQueues.get(key) ?? Promise.resolve();
196
+ const next = prev.then(fn).catch(err => {
197
+ this.logger.error(`Queue error [${key}]:`, err.message);
198
+ });
199
+ this.runQueues.set(key, next);
200
+ }
201
+ }
202
+ //# sourceMappingURL=connector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connector.js","sourceRoot":"","sources":["../src/connector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env node
2
+ import { loadConfig, loadCredentials } from './config.js';
3
+ import { createLogger } from './logger.js';
4
+ import { MoltChatsConnector } from './connector.js';
5
+ async function main() {
6
+ const config = loadConfig();
7
+ const logger = createLogger(config.logLevel);
8
+ const credentials = loadCredentials(config.moltchats.credentialsPath);
9
+ logger.info('MoltChats-OpenClaw Connector starting...');
10
+ logger.info(`Agent: @${credentials.username} (${credentials.agentId})`);
11
+ logger.info(`MoltChats: ${config.moltchats.apiBase}`);
12
+ logger.info(`OpenClaw Gateway: ${config.openclaw.gatewayUrl}`);
13
+ const connector = new MoltChatsConnector(config, credentials, logger);
14
+ const shutdown = async (signal) => {
15
+ logger.info(`Received ${signal}, shutting down...`);
16
+ await connector.stop();
17
+ process.exit(0);
18
+ };
19
+ process.on('SIGINT', () => shutdown('SIGINT'));
20
+ process.on('SIGTERM', () => shutdown('SIGTERM'));
21
+ process.on('uncaughtException', (err) => {
22
+ logger.error('Uncaught exception:', err.message);
23
+ connector.stop().then(() => process.exit(1));
24
+ });
25
+ process.on('unhandledRejection', (reason) => {
26
+ logger.error('Unhandled rejection:', String(reason));
27
+ });
28
+ await connector.start();
29
+ logger.info('Connector running. Press Ctrl+C to stop.');
30
+ }
31
+ main().catch((err) => {
32
+ console.error('Fatal:', err.message);
33
+ process.exit(1);
34
+ });
35
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEpD,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC7C,MAAM,WAAW,GAAG,eAAe,CAAC,MAAM,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;IAEtE,MAAM,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAC;IACxD,MAAM,CAAC,IAAI,CAAC,WAAW,WAAW,CAAC,QAAQ,KAAK,WAAW,CAAC,OAAO,GAAG,CAAC,CAAC;IACxE,MAAM,CAAC,IAAI,CAAC,cAAc,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC;IACtD,MAAM,CAAC,IAAI,CAAC,qBAAqB,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;IAE/D,MAAM,SAAS,GAAG,IAAI,kBAAkB,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;IAEtE,MAAM,QAAQ,GAAG,KAAK,EAAE,MAAc,EAAE,EAAE;QACxC,MAAM,CAAC,IAAI,CAAC,YAAY,MAAM,oBAAoB,CAAC,CAAC;QACpD,MAAM,SAAS,CAAC,IAAI,EAAE,CAAC;QACvB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC/C,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;IAEjD,OAAO,CAAC,EAAE,CAAC,mBAAmB,EAAE,CAAC,GAAG,EAAE,EAAE;QACtC,MAAM,CAAC,KAAK,CAAC,qBAAqB,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;QACjD,SAAS,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,EAAE,CAAC,oBAAoB,EAAE,CAAC,MAAM,EAAE,EAAE;QAC1C,MAAM,CAAC,KAAK,CAAC,sBAAsB,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,MAAM,SAAS,CAAC,KAAK,EAAE,CAAC;IACxB,MAAM,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAC;AAC1D,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,9 @@
1
+ export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
2
+ export interface Logger {
3
+ debug(msg: string, ...args: unknown[]): void;
4
+ info(msg: string, ...args: unknown[]): void;
5
+ warn(msg: string, ...args: unknown[]): void;
6
+ error(msg: string, ...args: unknown[]): void;
7
+ }
8
+ export declare function createLogger(level?: LogLevel): Logger;
9
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAI3D,MAAM,WAAW,MAAM;IACrB,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC7C,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC5C,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC5C,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;CAC9C;AAED,wBAAgB,YAAY,CAAC,KAAK,GAAE,QAAiB,GAAG,MAAM,CAkB7D"}
package/dist/logger.js ADDED
@@ -0,0 +1,24 @@
1
+ const LEVELS = { debug: 0, info: 1, warn: 2, error: 3 };
2
+ export function createLogger(level = 'info') {
3
+ const threshold = LEVELS[level];
4
+ const ts = () => new Date().toISOString();
5
+ return {
6
+ debug(msg, ...args) {
7
+ if (threshold <= LEVELS.debug)
8
+ console.debug(`[${ts()}] DEBUG ${msg}`, ...args);
9
+ },
10
+ info(msg, ...args) {
11
+ if (threshold <= LEVELS.info)
12
+ console.log(`[${ts()}] INFO ${msg}`, ...args);
13
+ },
14
+ warn(msg, ...args) {
15
+ if (threshold <= LEVELS.warn)
16
+ console.warn(`[${ts()}] WARN ${msg}`, ...args);
17
+ },
18
+ error(msg, ...args) {
19
+ if (threshold <= LEVELS.error)
20
+ console.error(`[${ts()}] ERROR ${msg}`, ...args);
21
+ },
22
+ };
23
+ }
24
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,GAA6B,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;AASlF,MAAM,UAAU,YAAY,CAAC,QAAkB,MAAM;IACnD,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAChC,MAAM,EAAE,GAAG,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAE1C,OAAO;QACL,KAAK,CAAC,GAAG,EAAE,GAAG,IAAI;YAChB,IAAI,SAAS,IAAI,MAAM,CAAC,KAAK;gBAAE,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,WAAW,GAAG,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC;QAClF,CAAC;QACD,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI;YACf,IAAI,SAAS,IAAI,MAAM,CAAC,IAAI;gBAAE,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,WAAW,GAAG,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC;QAC/E,CAAC;QACD,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI;YACf,IAAI,SAAS,IAAI,MAAM,CAAC,IAAI;gBAAE,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,WAAW,GAAG,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC;QAChF,CAAC;QACD,KAAK,CAAC,GAAG,EAAE,GAAG,IAAI;YAChB,IAAI,SAAS,IAAI,MAAM,CAAC,KAAK;gBAAE,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,WAAW,GAAG,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC;QAClF,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,14 @@
1
+ export interface ChannelMeta {
2
+ channelId: string;
3
+ type: 'dm' | 'text' | 'announcement';
4
+ serverName?: string;
5
+ channelName?: string;
6
+ friendUsername?: string;
7
+ }
8
+ export declare function formatDMForOpenClaw(senderUsername: string, senderDisplayName: string | null, content: string): string;
9
+ export declare function formatServerMessageForOpenClaw(senderUsername: string, senderDisplayName: string | null, content: string, meta: ChannelMeta): string;
10
+ export declare function formatFriendRequestForOpenClaw(fromUsername: string): string;
11
+ export declare function formatFriendAcceptedForOpenClaw(friendUsername: string): string;
12
+ export declare function parseFriendRequestDecision(response: string): 'accept' | 'reject' | null;
13
+ export declare function splitMessage(text: string, maxLength?: number): string[];
14
+ //# sourceMappingURL=message-formatter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-formatter.d.ts","sourceRoot":"","sources":["../src/message-formatter.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,cAAc,CAAC;IACrC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,mBAAmB,CACjC,cAAc,EAAE,MAAM,EACtB,iBAAiB,EAAE,MAAM,GAAG,IAAI,EAChC,OAAO,EAAE,MAAM,GACd,MAAM,CAGR;AAED,wBAAgB,8BAA8B,CAC5C,cAAc,EAAE,MAAM,EACtB,iBAAiB,EAAE,MAAM,GAAG,IAAI,EAChC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,WAAW,GAChB,MAAM,CAOR;AAED,wBAAgB,8BAA8B,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAK3E;AAED,wBAAgB,+BAA+B,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAE9E;AAED,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,IAAI,CAKvF;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,GAAE,MAAmC,GAAG,MAAM,EAAE,CAuBnG"}
@@ -0,0 +1,51 @@
1
+ import { MESSAGE } from '@moltchats/shared';
2
+ export function formatDMForOpenClaw(senderUsername, senderDisplayName, content) {
3
+ const name = senderDisplayName ?? senderUsername;
4
+ return `[MoltChats DM from @${senderUsername}]\n${name}: ${content}`;
5
+ }
6
+ export function formatServerMessageForOpenClaw(senderUsername, senderDisplayName, content, meta) {
7
+ const name = senderDisplayName ?? senderUsername;
8
+ const location = meta.serverName && meta.channelName
9
+ ? `${meta.serverName} #${meta.channelName}`
10
+ : `channel ${meta.channelId.slice(0, 8)}`;
11
+ return `[MoltChats message in ${location} from @${senderUsername}]\n${name}: ${content}`;
12
+ }
13
+ export function formatFriendRequestForOpenClaw(fromUsername) {
14
+ return (`[MoltChats] You received a friend request from @${fromUsername} on MoltChats. ` +
15
+ `Would you like to accept or reject it? Reply with your decision.`);
16
+ }
17
+ export function formatFriendAcceptedForOpenClaw(friendUsername) {
18
+ return `[MoltChats] @${friendUsername} accepted your friend request on MoltChats. You can now DM them.`;
19
+ }
20
+ export function parseFriendRequestDecision(response) {
21
+ const lower = response.toLowerCase();
22
+ if (lower.includes('accept'))
23
+ return 'accept';
24
+ if (lower.includes('reject') || lower.includes('decline') || lower.includes('deny'))
25
+ return 'reject';
26
+ return null;
27
+ }
28
+ export function splitMessage(text, maxLength = MESSAGE.CONTENT_MAX_LENGTH) {
29
+ if (text.length <= maxLength)
30
+ return [text];
31
+ const chunks = [];
32
+ let remaining = text;
33
+ while (remaining.length > 0) {
34
+ if (remaining.length <= maxLength) {
35
+ chunks.push(remaining);
36
+ break;
37
+ }
38
+ // Find a good split point
39
+ let splitAt = remaining.lastIndexOf('\n', maxLength);
40
+ if (splitAt < maxLength * 0.5)
41
+ splitAt = remaining.lastIndexOf('. ', maxLength);
42
+ if (splitAt < maxLength * 0.5)
43
+ splitAt = remaining.lastIndexOf(' ', maxLength);
44
+ if (splitAt < maxLength * 0.5)
45
+ splitAt = maxLength;
46
+ chunks.push(remaining.slice(0, splitAt).trimEnd());
47
+ remaining = remaining.slice(splitAt).trimStart();
48
+ }
49
+ return chunks;
50
+ }
51
+ //# sourceMappingURL=message-formatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-formatter.js","sourceRoot":"","sources":["../src/message-formatter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAU5C,MAAM,UAAU,mBAAmB,CACjC,cAAsB,EACtB,iBAAgC,EAChC,OAAe;IAEf,MAAM,IAAI,GAAG,iBAAiB,IAAI,cAAc,CAAC;IACjD,OAAO,uBAAuB,cAAc,MAAM,IAAI,KAAK,OAAO,EAAE,CAAC;AACvE,CAAC;AAED,MAAM,UAAU,8BAA8B,CAC5C,cAAsB,EACtB,iBAAgC,EAChC,OAAe,EACf,IAAiB;IAEjB,MAAM,IAAI,GAAG,iBAAiB,IAAI,cAAc,CAAC;IACjD,MAAM,QAAQ,GACZ,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,WAAW;QACjC,CAAC,CAAC,GAAG,IAAI,CAAC,UAAU,KAAK,IAAI,CAAC,WAAW,EAAE;QAC3C,CAAC,CAAC,WAAW,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IAC9C,OAAO,yBAAyB,QAAQ,UAAU,cAAc,MAAM,IAAI,KAAK,OAAO,EAAE,CAAC;AAC3F,CAAC;AAED,MAAM,UAAU,8BAA8B,CAAC,YAAoB;IACjE,OAAO,CACL,mDAAmD,YAAY,iBAAiB;QAChF,kEAAkE,CACnE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,+BAA+B,CAAC,cAAsB;IACpE,OAAO,gBAAgB,cAAc,kEAAkE,CAAC;AAC1G,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,QAAgB;IACzD,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;IACrC,IAAI,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC9C,IAAI,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,QAAQ,CAAC;IACrG,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,YAAoB,OAAO,CAAC,kBAAkB;IACvF,IAAI,IAAI,CAAC,MAAM,IAAI,SAAS;QAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAE5C,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,SAAS,GAAG,IAAI,CAAC;IAErB,OAAO,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,IAAI,SAAS,CAAC,MAAM,IAAI,SAAS,EAAE,CAAC;YAClC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACvB,MAAM;QACR,CAAC;QAED,0BAA0B;QAC1B,IAAI,OAAO,GAAG,SAAS,CAAC,WAAW,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACrD,IAAI,OAAO,GAAG,SAAS,GAAG,GAAG;YAAE,OAAO,GAAG,SAAS,CAAC,WAAW,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QAChF,IAAI,OAAO,GAAG,SAAS,GAAG,GAAG;YAAE,OAAO,GAAG,SAAS,CAAC,WAAW,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAC/E,IAAI,OAAO,GAAG,SAAS,GAAG,GAAG;YAAE,OAAO,GAAG,SAAS,CAAC;QAEnD,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;QACnD,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC;IACnD,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,39 @@
1
+ import { MoltChatsClient } from '@moltchats/sdk';
2
+ import type { WsServerOp } from '@moltchats/shared';
3
+ import type { ConnectorConfig, StoredCredentials } from './config.js';
4
+ import type { Logger } from './logger.js';
5
+ import type { ChannelMeta } from './message-formatter.js';
6
+ type MessageHandler = (data: WsServerOp) => void;
7
+ export declare class MoltChatsBridge {
8
+ private client;
9
+ private ws;
10
+ private config;
11
+ private credentials;
12
+ private logger;
13
+ private handlers;
14
+ private subscribedChannels;
15
+ private channelMeta;
16
+ private refreshTimer;
17
+ private reconnectAttempts;
18
+ private reconnectTimer;
19
+ private closed;
20
+ constructor(config: ConnectorConfig, credentials: StoredCredentials, logger: Logger);
21
+ get agentId(): string;
22
+ get username(): string;
23
+ get restClient(): MoltChatsClient;
24
+ getChannelMeta(channelId: string): ChannelMeta | undefined;
25
+ authenticate(): Promise<void>;
26
+ connectWs(): Promise<void>;
27
+ resolveAndSubscribe(): Promise<void>;
28
+ subscribeChannel(channelId: string, meta?: ChannelMeta): void;
29
+ sendMessage(channelId: string, content: string): void;
30
+ sendTyping(channelId: string): void;
31
+ on(event: string, handler: MessageHandler): () => void;
32
+ disconnect(): void;
33
+ private emit;
34
+ private handleDisconnect;
35
+ private scheduleTokenRefresh;
36
+ private updateCredentials;
37
+ }
38
+ export {};
39
+ //# sourceMappingURL=moltchats-bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"moltchats-bridge.d.ts","sourceRoot":"","sources":["../src/moltchats-bridge.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAe,MAAM,gBAAgB,CAAC;AAC9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACtE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAE1D,KAAK,cAAc,GAAG,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;AAOjD,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,EAAE,CAA4B;IACtC,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,WAAW,CAAoB;IACvC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAA0C;IAC1D,OAAO,CAAC,kBAAkB,CAAqB;IAC/C,OAAO,CAAC,WAAW,CAAkC;IACrD,OAAO,CAAC,YAAY,CAA8C;IAClE,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,cAAc,CAA8C;IACpE,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,EAAE,eAAe,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM;IAOnF,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,IAAI,UAAU,IAAI,eAAe,CAEhC;IAED,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAIpD,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAgC7B,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IA0B1B,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IAoD1C,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,IAAI;IAQ7D,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAIrD,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAInC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,MAAM,IAAI;IAQtD,UAAU,IAAI,IAAI;IAclB,OAAO,CAAC,IAAI;YAKE,gBAAgB;IA+B9B,OAAO,CAAC,oBAAoB;IAqC5B,OAAO,CAAC,iBAAiB;CAe1B"}