echoclaw-relay-agent 0.22.2 → 0.22.4
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/RelayAgent.js +43 -4
- package/dist/RelayClient.js +34 -6
- package/dist/cli.js +1 -1
- package/dist/gateway/GatewayWatchdog.d.ts +12 -3
- package/dist/gateway/GatewayWatchdog.js +47 -15
- package/dist/gateway/types.d.ts +4 -4
- package/dist/gateway/types.js +2 -2
- package/package.json +1 -1
package/dist/RelayAgent.js
CHANGED
|
@@ -157,6 +157,8 @@ export class RelayAgent extends EventEmitter {
|
|
|
157
157
|
this.transport = null;
|
|
158
158
|
}
|
|
159
159
|
this.frameCrypto = null;
|
|
160
|
+
this._dataHandler = null;
|
|
161
|
+
this._dataHandlerInner = null;
|
|
160
162
|
try {
|
|
161
163
|
if (pairingCode) {
|
|
162
164
|
// New pairing — overwrite any existing session
|
|
@@ -173,6 +175,21 @@ export class RelayAgent extends EventEmitter {
|
|
|
173
175
|
}
|
|
174
176
|
}
|
|
175
177
|
}
|
|
178
|
+
catch (err) {
|
|
179
|
+
// Clean up zombie transport on failure (prevents auto-reconnect loop)
|
|
180
|
+
const t = this.transport;
|
|
181
|
+
if (t) {
|
|
182
|
+
t.removeAllListeners();
|
|
183
|
+
t.disconnect();
|
|
184
|
+
this.transport = null;
|
|
185
|
+
}
|
|
186
|
+
this.frameCrypto = null;
|
|
187
|
+
this.sessionKey = null;
|
|
188
|
+
this._dataHandler = null;
|
|
189
|
+
this._dataHandlerInner = null;
|
|
190
|
+
this.setStatus('disconnected');
|
|
191
|
+
throw err;
|
|
192
|
+
}
|
|
176
193
|
finally {
|
|
177
194
|
this._starting = false;
|
|
178
195
|
}
|
|
@@ -236,7 +253,7 @@ export class RelayAgent extends EventEmitter {
|
|
|
236
253
|
async freshPairing(code) {
|
|
237
254
|
this.setStatus('connecting');
|
|
238
255
|
// Connect to relay server as agent
|
|
239
|
-
const agentUrl = `${this.config.relayServer}/agent/connect?code=${code}`;
|
|
256
|
+
const agentUrl = `${this.config.relayServer}/agent/connect?code=${code}&protocol=2`;
|
|
240
257
|
this.transport = new RelayTransport({
|
|
241
258
|
url: agentUrl,
|
|
242
259
|
reconnect: this.config.reconnect,
|
|
@@ -281,7 +298,7 @@ export class RelayAgent extends EventEmitter {
|
|
|
281
298
|
this.frameCrypto = new FrameCrypto(this.sessionKey);
|
|
282
299
|
// _paired stays false until HELLO confirmed — prevents on('open') from
|
|
283
300
|
// emitting 'connected' before server confirms the session exists.
|
|
284
|
-
const resumeUrl = `${this.config.relayServer}/agent/connect?resume=${session.relaySessionId}`;
|
|
301
|
+
const resumeUrl = `${this.config.relayServer}/agent/connect?resume=${session.relaySessionId}&protocol=2`;
|
|
285
302
|
this.transport = new RelayTransport({
|
|
286
303
|
url: resumeUrl,
|
|
287
304
|
reconnect: this.config.reconnect,
|
|
@@ -318,7 +335,7 @@ export class RelayAgent extends EventEmitter {
|
|
|
318
335
|
}
|
|
319
336
|
else if (msg.type === 'CLOSE' && msg.sender_role === 'server') {
|
|
320
337
|
const payload = msg.payload || 'unknown';
|
|
321
|
-
if (['SESSION_NOT_FOUND', 'SESSION_EXPIRED', 'INVALID_SESSION', 'DEVICE_TOKEN_MISMATCH'].includes(payload)) {
|
|
338
|
+
if (['SESSION_NOT_FOUND', 'SESSION_EXPIRED', 'INVALID_SESSION', 'DEVICE_TOKEN_MISMATCH', 'SESSION_PROTOCOL_MISMATCH'].includes(payload)) {
|
|
322
339
|
this.sessionStore.clear().catch(() => { });
|
|
323
340
|
}
|
|
324
341
|
settle(() => reject(new Error(`Relay server closed: ${payload}`)));
|
|
@@ -356,7 +373,7 @@ export class RelayAgent extends EventEmitter {
|
|
|
356
373
|
this._paired = true;
|
|
357
374
|
// Update transport URL so auto-reconnect uses ?resume=sessionId
|
|
358
375
|
if (this.transport) {
|
|
359
|
-
this.transport.setUrl(`${this.config.relayServer}/agent/connect?resume=${result.sessionId}`);
|
|
376
|
+
this.transport.setUrl(`${this.config.relayServer}/agent/connect?resume=${result.sessionId}&protocol=2`);
|
|
360
377
|
}
|
|
361
378
|
// Build session data with sessionKey for persistence
|
|
362
379
|
const sessionData = {
|
|
@@ -452,6 +469,28 @@ export class RelayAgent extends EventEmitter {
|
|
|
452
469
|
this.transport.on('connect_timeout', (timeoutMs) => {
|
|
453
470
|
this.emit('error', Object.assign(new Error(`Connection timed out after ${timeoutMs / 1000}s`), { code: 'CONNECT_TIMEOUT' }));
|
|
454
471
|
});
|
|
472
|
+
// Handle server fatal CLOSE messages (SESSION_NOT_FOUND, SESSION_PROTOCOL_MISMATCH, etc.)
|
|
473
|
+
const SESSION_FATAL = new Set(['SESSION_NOT_FOUND', 'INVALID_SESSION', 'SESSION_PROTOCOL_MISMATCH']);
|
|
474
|
+
this.transport.on('message', (msg) => {
|
|
475
|
+
if ((msg.type === 'CLOSE' || msg.type === 'STATUS') && msg.sender_role === 'server') {
|
|
476
|
+
const payload = typeof msg.payload === 'string' ? msg.payload : '';
|
|
477
|
+
if (payload === 'UNPAIRED' || SESSION_FATAL.has(payload)) {
|
|
478
|
+
this.sessionStore.clear().catch(() => { });
|
|
479
|
+
this._paired = false;
|
|
480
|
+
this._stopped = true;
|
|
481
|
+
this.gatewayManager?.stop();
|
|
482
|
+
this.transport?.disconnect();
|
|
483
|
+
this.transport = null;
|
|
484
|
+
this.sessionKey = null;
|
|
485
|
+
this.frameCrypto = null;
|
|
486
|
+
this._dataHandler = null;
|
|
487
|
+
this._dataHandlerInner = null;
|
|
488
|
+
this.setStatus('disconnected');
|
|
489
|
+
this.emit(payload === 'UNPAIRED' ? 'unpaired' : 'session_fatal', { reason: payload });
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
});
|
|
455
494
|
this.transport.on('open', () => {
|
|
456
495
|
if (!this.transport || !this._paired || !this.sessionKey)
|
|
457
496
|
return;
|
package/dist/RelayClient.js
CHANGED
|
@@ -126,6 +126,7 @@ export class RelayClient extends EventEmitter {
|
|
|
126
126
|
this._stopped = false;
|
|
127
127
|
// Teardown previous transport before starting new
|
|
128
128
|
if (this.transport) {
|
|
129
|
+
this.transport.removeAllListeners();
|
|
129
130
|
this.transport.disconnect();
|
|
130
131
|
this.transport = null;
|
|
131
132
|
}
|
|
@@ -139,6 +140,19 @@ export class RelayClient extends EventEmitter {
|
|
|
139
140
|
await this.freshPairing();
|
|
140
141
|
}
|
|
141
142
|
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
// Clean up zombie transport on failure (prevents auto-reconnect loop)
|
|
145
|
+
const t = this.transport;
|
|
146
|
+
if (t) {
|
|
147
|
+
t.removeAllListeners();
|
|
148
|
+
t.disconnect();
|
|
149
|
+
this.transport = null;
|
|
150
|
+
}
|
|
151
|
+
this.frameCrypto = null;
|
|
152
|
+
this.sessionKey = null;
|
|
153
|
+
this.setStatus('disconnected');
|
|
154
|
+
throw err;
|
|
155
|
+
}
|
|
142
156
|
finally {
|
|
143
157
|
this._connecting = false;
|
|
144
158
|
}
|
|
@@ -200,7 +214,7 @@ export class RelayClient extends EventEmitter {
|
|
|
200
214
|
}
|
|
201
215
|
async freshPairing() {
|
|
202
216
|
this.setStatus('connecting');
|
|
203
|
-
const clientUrl = `${this.config.relayServer}/client/connect`;
|
|
217
|
+
const clientUrl = `${this.config.relayServer}/client/connect?protocol=2`;
|
|
204
218
|
this.transport = new RelayTransport({
|
|
205
219
|
url: clientUrl,
|
|
206
220
|
reconnect: this.config.reconnect,
|
|
@@ -244,7 +258,7 @@ export class RelayClient extends EventEmitter {
|
|
|
244
258
|
this.frameCrypto = new FrameCrypto(this.sessionKey);
|
|
245
259
|
// _paired stays false until HELLO confirmed — prevents on('open') from
|
|
246
260
|
// emitting 'connected' before server confirms the session exists.
|
|
247
|
-
const resumeUrl = `${this.config.relayServer}/client/connect?resume=${session.relaySessionId}`;
|
|
261
|
+
const resumeUrl = `${this.config.relayServer}/client/connect?resume=${session.relaySessionId}&protocol=2`;
|
|
248
262
|
this.transport = new RelayTransport({
|
|
249
263
|
url: resumeUrl,
|
|
250
264
|
reconnect: this.config.reconnect,
|
|
@@ -281,7 +295,7 @@ export class RelayClient extends EventEmitter {
|
|
|
281
295
|
}
|
|
282
296
|
else if (msg.type === 'CLOSE' && msg.sender_role === 'server') {
|
|
283
297
|
const payload = msg.payload || 'unknown';
|
|
284
|
-
if (['SESSION_NOT_FOUND', 'SESSION_EXPIRED', 'INVALID_SESSION', 'DEVICE_TOKEN_MISMATCH'].includes(payload)) {
|
|
298
|
+
if (['SESSION_NOT_FOUND', 'SESSION_EXPIRED', 'INVALID_SESSION', 'DEVICE_TOKEN_MISMATCH', 'SESSION_PROTOCOL_MISMATCH'].includes(payload)) {
|
|
285
299
|
this.sessionStore.clear().catch(() => { });
|
|
286
300
|
}
|
|
287
301
|
settle(() => reject(new Error(`Relay server closed: ${payload}`)));
|
|
@@ -308,7 +322,7 @@ export class RelayClient extends EventEmitter {
|
|
|
308
322
|
this._paired = true;
|
|
309
323
|
// Update transport URL so auto-reconnect uses ?resume=sessionId
|
|
310
324
|
if (this.transport) {
|
|
311
|
-
this.transport.setUrl(`${this.config.relayServer}/client/connect?resume=${result.sessionId}`);
|
|
325
|
+
this.transport.setUrl(`${this.config.relayServer}/client/connect?resume=${result.sessionId}&protocol=2`);
|
|
312
326
|
}
|
|
313
327
|
// Persist session with sessionKey for future resume
|
|
314
328
|
const sessionData = {
|
|
@@ -381,7 +395,7 @@ export class RelayClient extends EventEmitter {
|
|
|
381
395
|
});
|
|
382
396
|
// Handle server messages (CLOSE/STATUS)
|
|
383
397
|
const PEER_STATUS = new Set(['AGENT_WARNING', 'AGENT_ONLINE', 'DESKTOP_DISCONNECTED']);
|
|
384
|
-
const SESSION_FATAL = new Set(['SESSION_NOT_FOUND', 'INVALID_SESSION']);
|
|
398
|
+
const SESSION_FATAL = new Set(['SESSION_NOT_FOUND', 'INVALID_SESSION', 'SESSION_PROTOCOL_MISMATCH']);
|
|
385
399
|
this.transport.on('message', (msg) => {
|
|
386
400
|
if ((msg.type === 'CLOSE' || msg.type === 'STATUS') && msg.sender_role === 'server') {
|
|
387
401
|
const payload = typeof msg.payload === 'string' ? msg.payload : '';
|
|
@@ -394,12 +408,26 @@ export class RelayClient extends EventEmitter {
|
|
|
394
408
|
}
|
|
395
409
|
if (payload === 'UNPAIRED') {
|
|
396
410
|
this.sessionStore.clear().catch(() => { });
|
|
397
|
-
this.
|
|
411
|
+
this._paired = false;
|
|
412
|
+
this._stopped = true;
|
|
398
413
|
this.transport?.disconnect();
|
|
414
|
+
this.transport = null;
|
|
415
|
+
this.sessionKey = null;
|
|
416
|
+
this.frameCrypto = null;
|
|
417
|
+
this.setStatus('disconnected');
|
|
418
|
+
this.emit('unpaired');
|
|
399
419
|
return;
|
|
400
420
|
}
|
|
401
421
|
if (SESSION_FATAL.has(payload)) {
|
|
402
422
|
this.sessionStore.clear().catch(() => { });
|
|
423
|
+
this._paired = false;
|
|
424
|
+
this._stopped = true;
|
|
425
|
+
this.transport?.disconnect();
|
|
426
|
+
this.transport = null;
|
|
427
|
+
this.sessionKey = null;
|
|
428
|
+
this.frameCrypto = null;
|
|
429
|
+
this.setStatus('disconnected');
|
|
430
|
+
this.emit('session_fatal', { reason: payload });
|
|
403
431
|
return;
|
|
404
432
|
}
|
|
405
433
|
}
|
package/dist/cli.js
CHANGED
|
@@ -175,7 +175,7 @@ ${BOLD}Usage:${RESET}
|
|
|
175
175
|
|
|
176
176
|
${BOLD}Setup Options:${RESET}
|
|
177
177
|
--relay=URL Relay server URL (default: ${DEFAULT_RELAY})
|
|
178
|
-
--bridge-port=PORT Local OpenClaw bridge port (default:
|
|
178
|
+
--bridge-port=PORT Local OpenClaw bridge port (default: 18789)
|
|
179
179
|
-h, --help Show this help
|
|
180
180
|
|
|
181
181
|
${BOLD}How it works:${RESET}
|
|
@@ -5,9 +5,15 @@
|
|
|
5
5
|
* Requires N consecutive failures before declaring bridge down (failureThreshold).
|
|
6
6
|
* Uses jittered intervals to prevent synchronized spikes.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
8
|
+
* When bridge goes down, attempts to restart the OpenClaw process
|
|
9
9
|
* via platform service manager (launchctl on macOS, systemctl on Linux).
|
|
10
10
|
* Rate limited: max 3 restart attempts per 10 minute window.
|
|
11
|
+
*
|
|
12
|
+
* Fixes applied (external AI review):
|
|
13
|
+
* - Restart retries on every tick while down (not just on state transition)
|
|
14
|
+
* - 5s cooldown after restart before next health check
|
|
15
|
+
* - Immediate re-check after successful restart
|
|
16
|
+
* - Exceptions in _check() count as failures (not silently swallowed)
|
|
11
17
|
*/
|
|
12
18
|
import { EventEmitter } from 'node:events';
|
|
13
19
|
import { TokenDiscovery } from './TokenDiscovery.js';
|
|
@@ -37,13 +43,16 @@ export declare class GatewayWatchdog extends EventEmitter {
|
|
|
37
43
|
start(): void;
|
|
38
44
|
/** Stop health checks. Idempotent / re-entrant safe. */
|
|
39
45
|
stop(): void;
|
|
40
|
-
/**
|
|
46
|
+
/** Schedule the next tick with jitter. */
|
|
47
|
+
private _scheduleNext;
|
|
48
|
+
/** Run one check, then schedule next. Prevents overlap. */
|
|
41
49
|
private _tick;
|
|
42
50
|
private _check;
|
|
43
51
|
private _transition;
|
|
44
52
|
/**
|
|
45
|
-
* Attempt to restart the OpenClaw process when bridge
|
|
53
|
+
* Attempt to restart the OpenClaw process when bridge is down.
|
|
46
54
|
* Rate limited: max 3 attempts per 10 minute window.
|
|
55
|
+
* Called on every tick while down — internal guards prevent over-restarting.
|
|
47
56
|
*/
|
|
48
57
|
private _attemptRestart;
|
|
49
58
|
}
|
|
@@ -5,9 +5,15 @@
|
|
|
5
5
|
* Requires N consecutive failures before declaring bridge down (failureThreshold).
|
|
6
6
|
* Uses jittered intervals to prevent synchronized spikes.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
8
|
+
* When bridge goes down, attempts to restart the OpenClaw process
|
|
9
9
|
* via platform service manager (launchctl on macOS, systemctl on Linux).
|
|
10
10
|
* Rate limited: max 3 restart attempts per 10 minute window.
|
|
11
|
+
*
|
|
12
|
+
* Fixes applied (external AI review):
|
|
13
|
+
* - Restart retries on every tick while down (not just on state transition)
|
|
14
|
+
* - 5s cooldown after restart before next health check
|
|
15
|
+
* - Immediate re-check after successful restart
|
|
16
|
+
* - Exceptions in _check() count as failures (not silently swallowed)
|
|
11
17
|
*/
|
|
12
18
|
import { EventEmitter } from 'node:events';
|
|
13
19
|
import { restartOpenClaw } from './ProcessRestart.js';
|
|
@@ -15,6 +21,7 @@ import { DEFAULT_GATEWAY_CONFIG } from './types.js';
|
|
|
15
21
|
// ── Restart rate limiting ────────────────────────────────────
|
|
16
22
|
const RESTART_WINDOW_MS = 10 * 60 * 1000; // 10 minutes
|
|
17
23
|
const MAX_RESTARTS_PER_WINDOW = 3;
|
|
24
|
+
const RESTART_COOLDOWN_MS = 5000; // wait for process to start before next check
|
|
18
25
|
export class GatewayWatchdog extends EventEmitter {
|
|
19
26
|
constructor(config) {
|
|
20
27
|
super();
|
|
@@ -72,7 +79,7 @@ export class GatewayWatchdog extends EventEmitter {
|
|
|
72
79
|
writable: true,
|
|
73
80
|
value: false
|
|
74
81
|
});
|
|
75
|
-
//
|
|
82
|
+
// Restart tracking
|
|
76
83
|
Object.defineProperty(this, "_restartTimestamps", {
|
|
77
84
|
enumerable: true,
|
|
78
85
|
configurable: true,
|
|
@@ -121,17 +128,28 @@ export class GatewayWatchdog extends EventEmitter {
|
|
|
121
128
|
}
|
|
122
129
|
}
|
|
123
130
|
// ── Private ────────────────────────────────────────────────
|
|
124
|
-
/**
|
|
131
|
+
/** Schedule the next tick with jitter. */
|
|
132
|
+
_scheduleNext(delayMs) {
|
|
133
|
+
if (this._stopped)
|
|
134
|
+
return;
|
|
135
|
+
const jitter = 1 + (Math.random() * 0.4 - 0.2);
|
|
136
|
+
const delay = delayMs ?? Math.round(this.checkIntervalMs * jitter);
|
|
137
|
+
this.timer = setTimeout(() => this._tick(), delay);
|
|
138
|
+
}
|
|
139
|
+
/** Run one check, then schedule next. Prevents overlap. */
|
|
125
140
|
_tick() {
|
|
126
141
|
this._check()
|
|
127
|
-
.catch(() => {
|
|
142
|
+
.catch((err) => {
|
|
143
|
+
// Unexpected error in check logic itself — count as failure
|
|
144
|
+
this.consecutiveFailures++;
|
|
145
|
+
if (this.consecutiveFailures >= this.failureThreshold) {
|
|
146
|
+
this._transition('down');
|
|
147
|
+
this._attemptRestart();
|
|
148
|
+
}
|
|
149
|
+
this.emit('error', err instanceof Error ? err : new Error(String(err)));
|
|
150
|
+
})
|
|
128
151
|
.finally(() => {
|
|
129
|
-
|
|
130
|
-
return;
|
|
131
|
-
// Per-tick jitter (±20%) — recalculated each cycle
|
|
132
|
-
const jitter = 1 + (Math.random() * 0.4 - 0.2);
|
|
133
|
-
const delayMs = Math.round(this.checkIntervalMs * jitter);
|
|
134
|
-
this.timer = setTimeout(() => this._tick(), delayMs);
|
|
152
|
+
this._scheduleNext();
|
|
135
153
|
});
|
|
136
154
|
}
|
|
137
155
|
async _check() {
|
|
@@ -151,7 +169,7 @@ export class GatewayWatchdog extends EventEmitter {
|
|
|
151
169
|
}
|
|
152
170
|
if (alive) {
|
|
153
171
|
this.consecutiveFailures = 0;
|
|
154
|
-
//
|
|
172
|
+
// Reset restart exhaustion on recovery
|
|
155
173
|
if (this._status === 'down') {
|
|
156
174
|
this._restartExhausted = false;
|
|
157
175
|
}
|
|
@@ -161,6 +179,9 @@ export class GatewayWatchdog extends EventEmitter {
|
|
|
161
179
|
this.consecutiveFailures++;
|
|
162
180
|
if (this.consecutiveFailures >= this.failureThreshold) {
|
|
163
181
|
this._transition('down');
|
|
182
|
+
// Attempt restart on every tick while down (not just on state transition).
|
|
183
|
+
// _attemptRestart has its own rate limiting.
|
|
184
|
+
this._attemptRestart();
|
|
164
185
|
}
|
|
165
186
|
// Below threshold: stay in current state (don't flap on transient failures)
|
|
166
187
|
}
|
|
@@ -185,14 +206,13 @@ export class GatewayWatchdog extends EventEmitter {
|
|
|
185
206
|
baseUrl: this._endpoint?.baseUrl,
|
|
186
207
|
consecutiveFailures: this.consecutiveFailures,
|
|
187
208
|
});
|
|
188
|
-
// V2: Attempt restart
|
|
189
|
-
this._attemptRestart();
|
|
190
209
|
}
|
|
191
210
|
}
|
|
192
|
-
// ──
|
|
211
|
+
// ── Process restart ────────────────────────────────────
|
|
193
212
|
/**
|
|
194
|
-
* Attempt to restart the OpenClaw process when bridge
|
|
213
|
+
* Attempt to restart the OpenClaw process when bridge is down.
|
|
195
214
|
* Rate limited: max 3 attempts per 10 minute window.
|
|
215
|
+
* Called on every tick while down — internal guards prevent over-restarting.
|
|
196
216
|
*/
|
|
197
217
|
_attemptRestart() {
|
|
198
218
|
if (this._restartInProgress || this._restartExhausted || this._stopped)
|
|
@@ -222,6 +242,18 @@ export class GatewayWatchdog extends EventEmitter {
|
|
|
222
242
|
method: result.method,
|
|
223
243
|
output: result.output,
|
|
224
244
|
});
|
|
245
|
+
// After successful restart, wait for process to start then re-check
|
|
246
|
+
if (!this._stopped) {
|
|
247
|
+
// Cancel the already-scheduled next tick, replace with cooldown + immediate check
|
|
248
|
+
if (this.timer) {
|
|
249
|
+
clearTimeout(this.timer);
|
|
250
|
+
this.timer = null;
|
|
251
|
+
}
|
|
252
|
+
this.timer = setTimeout(() => {
|
|
253
|
+
if (!this._stopped)
|
|
254
|
+
this._tick();
|
|
255
|
+
}, RESTART_COOLDOWN_MS);
|
|
256
|
+
}
|
|
225
257
|
}
|
|
226
258
|
else {
|
|
227
259
|
this.emit('restart_failed', {
|
package/dist/gateway/types.d.ts
CHANGED
|
@@ -10,11 +10,11 @@ import type { TunnelPayload } from 'echoclaw-crypto';
|
|
|
10
10
|
export interface GatewayConfig {
|
|
11
11
|
/** Enable the gateway layer. When false, RelayAgent behaves as V1. */
|
|
12
12
|
enabled: boolean;
|
|
13
|
-
/** Local bridge port. Default:
|
|
13
|
+
/** Local bridge port. Default: 18789 */
|
|
14
14
|
bridgePort?: number;
|
|
15
15
|
/** Local bridge host. Default: 'localhost'. Forced to loopback only. */
|
|
16
16
|
bridgeHost?: string;
|
|
17
|
-
/** Ports to probe during discovery. Default: [
|
|
17
|
+
/** Ports to probe during discovery. Default: [18789] */
|
|
18
18
|
discoveryPorts?: number[];
|
|
19
19
|
/** Health check interval in ms. Default: 30_000 */
|
|
20
20
|
healthCheckIntervalMs?: number;
|
|
@@ -36,9 +36,9 @@ export interface GatewayConfig {
|
|
|
36
36
|
deviceName?: string;
|
|
37
37
|
}
|
|
38
38
|
export declare const DEFAULT_GATEWAY_CONFIG: {
|
|
39
|
-
readonly bridgePort:
|
|
39
|
+
readonly bridgePort: 18789;
|
|
40
40
|
readonly bridgeHost: "localhost";
|
|
41
|
-
readonly discoveryPorts: readonly [
|
|
41
|
+
readonly discoveryPorts: readonly [18789];
|
|
42
42
|
readonly healthCheckIntervalMs: 30000;
|
|
43
43
|
readonly healthCheckPath: "/health";
|
|
44
44
|
readonly heartbeatIntervalMs: 10000;
|
package/dist/gateway/types.js
CHANGED
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
* Key design: Ack + Heartbeat + Push async model for long-running AI tasks.
|
|
8
8
|
*/
|
|
9
9
|
export const DEFAULT_GATEWAY_CONFIG = {
|
|
10
|
-
bridgePort:
|
|
10
|
+
bridgePort: 18789,
|
|
11
11
|
bridgeHost: 'localhost',
|
|
12
|
-
discoveryPorts: [
|
|
12
|
+
discoveryPorts: [18789],
|
|
13
13
|
healthCheckIntervalMs: 30000,
|
|
14
14
|
healthCheckPath: '/health',
|
|
15
15
|
heartbeatIntervalMs: 10000,
|
package/package.json
CHANGED