@emotion-machine/claw-messenger 0.1.3 → 0.1.5

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/dist/channel.js CHANGED
@@ -156,6 +156,7 @@ export const clawMessengerPlugin = {
156
156
  messageToolHints: () => [
157
157
  "You can react to messages using iMessage tapbacks via the react action. Available: love (❤️), like (👍), dislike (👎), laugh (😂), emphasize (‼️), question (❓).",
158
158
  "Use reactions naturally — the way a real person would in iMessage.",
159
+ "If you encounter connection issues, the server is WebSocket-only — do NOT test with HTTP. Full API docs and troubleshooting: https://clawmessenger.com/docs",
159
160
  ],
160
161
  },
161
162
  // Legacy API (OpenClaw <2026.3.22): kept for backward compatibility
@@ -1,6 +1,10 @@
1
1
  /**
2
2
  * WebSocket client with reconnection and request/response correlation.
3
3
  * Connects to claw-messenger server with API key auth.
4
+ *
5
+ * Uses the `ws` npm package instead of the native WebSocket to avoid
6
+ * Node 22+ HTTP/2 compatibility issues (native WebSocket silently fails
7
+ * against HTTP/2 servers like Render.com).
4
8
  */
5
9
  type MessageHandler = (message: Record<string, unknown>) => void;
6
10
  export interface WsClientOptions {
package/dist/ws/client.js CHANGED
@@ -1,11 +1,22 @@
1
1
  /**
2
2
  * WebSocket client with reconnection and request/response correlation.
3
3
  * Connects to claw-messenger server with API key auth.
4
+ *
5
+ * Uses the `ws` npm package instead of the native WebSocket to avoid
6
+ * Node 22+ HTTP/2 compatibility issues (native WebSocket silently fails
7
+ * against HTTP/2 servers like Render.com).
4
8
  */
9
+ import WebSocket from "ws";
5
10
  const MAX_RECONNECT_DELAY_MS = 30_000;
11
+ const MAX_RECONNECT_ATTEMPTS = 50;
6
12
  const PING_INTERVAL_MS = 30_000;
7
13
  const REQUEST_TIMEOUT_MS = 30_000;
8
14
  const PONG_TIMEOUT_MS = 10_000;
15
+ /** Close codes that indicate the client should NOT reconnect. */
16
+ const NO_RECONNECT_CODES = new Set([
17
+ 1008, // Policy violation — connection limit reached (evicted)
18
+ 4003, // Subscription inactive (cancelled/expired)
19
+ ]);
9
20
  export class WsClient {
10
21
  ws = null;
11
22
  opts;
@@ -87,7 +98,9 @@ export class WsClient {
87
98
  const ws = new WebSocket(url.toString());
88
99
  this.ws = ws;
89
100
  ws.onopen = () => {
90
- this.reconnectAttempt = 0;
101
+ // Don't reset reconnectAttempt here — reset on first successful
102
+ // message exchange instead, so eviction loops can't keep the
103
+ // counter at 0 and bypass backoff.
91
104
  this.lastPongAt = Date.now();
92
105
  this.opts.log?.("Connected");
93
106
  // Reject stale pending requests from previous connection
@@ -108,15 +121,27 @@ export class WsClient {
108
121
  this.opts.log?.(`Disconnected (code=${event.code})`);
109
122
  this._clearTimers();
110
123
  this.opts.onDisconnect?.();
111
- if (!this.stopped) {
112
- this._scheduleReconnect();
124
+ if (this.stopped)
125
+ return;
126
+ if (NO_RECONNECT_CODES.has(event.code)) {
127
+ this.opts.log?.(`Not reconnecting (code=${event.code}: ${event.reason})`);
128
+ this.stopped = true;
129
+ return;
113
130
  }
131
+ if (this.reconnectAttempt >= MAX_RECONNECT_ATTEMPTS) {
132
+ this.opts.log?.(`Max reconnect attempts (${MAX_RECONNECT_ATTEMPTS}) reached — giving up`);
133
+ this.stopped = true;
134
+ return;
135
+ }
136
+ this._scheduleReconnect();
114
137
  };
115
138
  ws.onerror = (event) => {
116
139
  this.opts.log?.(`WebSocket error`);
117
140
  };
118
141
  }
119
142
  _handleMessage(data) {
143
+ // Connection is stable — reset backoff counter
144
+ this.reconnectAttempt = 0;
120
145
  // Check if this is a response to a pending request
121
146
  const id = data.id;
122
147
  if (id && this.pendingRequests.has(id)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@emotion-machine/claw-messenger",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "iMessage, RCS & SMS channel plugin for OpenClaw — no phone or Mac Mini required",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -50,10 +50,12 @@
50
50
  },
51
51
  "dependencies": {
52
52
  "@sinclair/typebox": "^0.34.48",
53
+ "ws": "^8.18.0",
53
54
  "zod": "^4.3.6"
54
55
  },
55
56
  "devDependencies": {
56
57
  "@types/node": "^20.14.0",
58
+ "@types/ws": "^8.5.0",
57
59
  "typescript": "^5.5.0"
58
60
  },
59
61
  "engines": {