@bian-womp/spark-remote 0.2.49 → 0.2.51
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/lib/cjs/index.cjs +83 -38
- package/lib/cjs/index.cjs.map +1 -1
- package/lib/cjs/src/RemoteEngine.d.ts +0 -1
- package/lib/cjs/src/RemoteEngine.d.ts.map +1 -1
- package/lib/cjs/src/RuntimeApiClient.d.ts.map +1 -1
- package/lib/cjs/src/examples/shared.d.ts.map +1 -1
- package/lib/cjs/src/server/RuntimeApiServer.d.ts.map +1 -1
- package/lib/cjs/src/server/runtime.d.ts +0 -1
- package/lib/cjs/src/server/runtime.d.ts.map +1 -1
- package/lib/cjs/src/transport/WebSocketTransport.d.ts +12 -1
- package/lib/cjs/src/transport/WebSocketTransport.d.ts.map +1 -1
- package/lib/esm/index.js +83 -38
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/src/RemoteEngine.d.ts +0 -1
- package/lib/esm/src/RemoteEngine.d.ts.map +1 -1
- package/lib/esm/src/RuntimeApiClient.d.ts.map +1 -1
- package/lib/esm/src/examples/shared.d.ts.map +1 -1
- package/lib/esm/src/server/RuntimeApiServer.d.ts.map +1 -1
- package/lib/esm/src/server/runtime.d.ts +0 -1
- package/lib/esm/src/server/runtime.d.ts.map +1 -1
- package/lib/esm/src/transport/WebSocketTransport.d.ts +12 -1
- package/lib/esm/src/transport/WebSocketTransport.d.ts.map +1 -1
- package/package.json +3 -3
package/lib/cjs/index.cjs
CHANGED
|
@@ -23,22 +23,23 @@ class SeqGenerator {
|
|
|
23
23
|
|
|
24
24
|
const OPEN = 1;
|
|
25
25
|
class WebSocketTransport {
|
|
26
|
-
constructor(url) {
|
|
26
|
+
constructor(url, options) {
|
|
27
27
|
this.listeners = new Set();
|
|
28
28
|
this.seq = new SeqGenerator();
|
|
29
|
+
this.isAlive = false;
|
|
30
|
+
this.PING_INTERVAL_MS = 30000;
|
|
31
|
+
this.PONG_TIMEOUT_MS = 10000;
|
|
29
32
|
this.baseUrl = url;
|
|
33
|
+
this.onConnectionLost = options?.onConnectionLost;
|
|
30
34
|
}
|
|
31
35
|
async connect(options) {
|
|
32
36
|
if (this.ws && this.ws.readyState === OPEN)
|
|
33
37
|
return;
|
|
34
|
-
// Build URL with connection params
|
|
35
|
-
// Handle both ws:///wss:// URLs and http:///https:// URLs (convert to ws)
|
|
36
38
|
let url;
|
|
37
39
|
if (this.baseUrl.startsWith("ws://") || this.baseUrl.startsWith("wss://")) {
|
|
38
40
|
url = new URL(this.baseUrl);
|
|
39
41
|
}
|
|
40
42
|
else {
|
|
41
|
-
// Convert http/https to ws/wss
|
|
42
43
|
const wsBaseUrl = this.baseUrl.replace(/^http/, "ws");
|
|
43
44
|
url = new URL(wsBaseUrl);
|
|
44
45
|
}
|
|
@@ -56,7 +57,10 @@ class WebSocketTransport {
|
|
|
56
57
|
await new Promise((resolve, reject) => {
|
|
57
58
|
if (!this.ws)
|
|
58
59
|
return reject(new Error("ws init failed"));
|
|
59
|
-
this.ws.onopen = () =>
|
|
60
|
+
this.ws.onopen = () => {
|
|
61
|
+
this.startHeartbeat();
|
|
62
|
+
resolve();
|
|
63
|
+
};
|
|
60
64
|
this.ws.onerror = (e) => reject(e);
|
|
61
65
|
this.ws.onmessage = (ev) => {
|
|
62
66
|
try {
|
|
@@ -66,10 +70,72 @@ class WebSocketTransport {
|
|
|
66
70
|
}
|
|
67
71
|
catch { }
|
|
68
72
|
};
|
|
73
|
+
this.ws.onclose = () => {
|
|
74
|
+
this.stopHeartbeat();
|
|
75
|
+
};
|
|
69
76
|
});
|
|
70
77
|
}
|
|
78
|
+
startHeartbeat() {
|
|
79
|
+
this.stopHeartbeat();
|
|
80
|
+
this.isAlive = true;
|
|
81
|
+
if (typeof window !== "undefined" || !this.ws)
|
|
82
|
+
return;
|
|
83
|
+
this.pongHandler = () => {
|
|
84
|
+
this.isAlive = true;
|
|
85
|
+
if (this.pongTimeout) {
|
|
86
|
+
clearTimeout(this.pongTimeout);
|
|
87
|
+
this.pongTimeout = undefined;
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
this.ws.on("pong", this.pongHandler);
|
|
91
|
+
this.pingInterval = setInterval(() => {
|
|
92
|
+
if (!this.ws || this.ws.readyState !== OPEN) {
|
|
93
|
+
this.stopHeartbeat();
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (!this.isAlive) {
|
|
97
|
+
this.onConnectionLost?.();
|
|
98
|
+
this.stopHeartbeat();
|
|
99
|
+
this.ws.terminate();
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
this.isAlive = false;
|
|
103
|
+
try {
|
|
104
|
+
this.ws.ping();
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
console.warn("[WebSocketTransport] Failed to send ping:", err);
|
|
108
|
+
this.onConnectionLost?.();
|
|
109
|
+
this.stopHeartbeat();
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
this.pongTimeout = setTimeout(() => {
|
|
113
|
+
if (!this.isAlive) {
|
|
114
|
+
this.onConnectionLost?.();
|
|
115
|
+
this.stopHeartbeat();
|
|
116
|
+
if (this.ws) {
|
|
117
|
+
this.ws.terminate();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}, this.PONG_TIMEOUT_MS);
|
|
121
|
+
}, this.PING_INTERVAL_MS);
|
|
122
|
+
}
|
|
123
|
+
stopHeartbeat() {
|
|
124
|
+
if (this.pingInterval) {
|
|
125
|
+
clearInterval(this.pingInterval);
|
|
126
|
+
this.pingInterval = undefined;
|
|
127
|
+
}
|
|
128
|
+
if (this.pongTimeout) {
|
|
129
|
+
clearTimeout(this.pongTimeout);
|
|
130
|
+
this.pongTimeout = undefined;
|
|
131
|
+
}
|
|
132
|
+
if (this.ws && this.pongHandler) {
|
|
133
|
+
this.ws.off("pong", this.pongHandler);
|
|
134
|
+
this.pongHandler = undefined;
|
|
135
|
+
}
|
|
136
|
+
this.isAlive = false;
|
|
137
|
+
}
|
|
71
138
|
async request(msg) {
|
|
72
|
-
// For now, just send and wait for the next message with matching seq (simple demo)
|
|
73
139
|
const seq = this.seq.next();
|
|
74
140
|
const env = { ...msg, seq };
|
|
75
141
|
const p = new Promise((resolve) => {
|
|
@@ -93,6 +159,7 @@ class WebSocketTransport {
|
|
|
93
159
|
return () => this.listeners.delete(cb);
|
|
94
160
|
}
|
|
95
161
|
async close() {
|
|
162
|
+
this.stopHeartbeat();
|
|
96
163
|
if (!this.ws)
|
|
97
164
|
return;
|
|
98
165
|
const ws = this.ws;
|
|
@@ -418,15 +485,6 @@ async function createRuntimeAdapter(createRegistry, send, extensions) {
|
|
|
418
485
|
}
|
|
419
486
|
graphRuntime.setEnvironment(env);
|
|
420
487
|
},
|
|
421
|
-
setInput: (nodeId, handle, value) => {
|
|
422
|
-
// If engine exists, use it; otherwise fall back to direct runtime access
|
|
423
|
-
if (engine) {
|
|
424
|
-
engine.setInput(nodeId, handle, value);
|
|
425
|
-
}
|
|
426
|
-
else {
|
|
427
|
-
graphRuntime?.setInput(nodeId, handle, value);
|
|
428
|
-
}
|
|
429
|
-
},
|
|
430
488
|
setInputs: (nodeId, inputs) => {
|
|
431
489
|
if (engine) {
|
|
432
490
|
engine.setInputs(nodeId, inputs);
|
|
@@ -526,9 +584,11 @@ async function createRuntimeAdapter(createRegistry, send, extensions) {
|
|
|
526
584
|
describeRegistry: wrapMethod("describeRegistry", originalApi.describeRegistry),
|
|
527
585
|
update: wrapMethod("update", originalApi.update),
|
|
528
586
|
setEnvironment: wrapMethod("setEnvironment", originalApi.setEnvironment),
|
|
529
|
-
setInput: wrapMethod("setInput", originalApi.setInput),
|
|
530
587
|
setInputs: wrapMethod("setInputs", originalApi.setInputs),
|
|
531
588
|
triggerExternal: wrapMethod("triggerExternal", originalApi.triggerExternal),
|
|
589
|
+
step: wrapMethod("step", originalApi.step),
|
|
590
|
+
computeNode: wrapMethod("computeNode", originalApi.computeNode),
|
|
591
|
+
flush: wrapMethod("flush", originalApi.flush),
|
|
532
592
|
launch: wrapMethod("launch", originalApi.launch),
|
|
533
593
|
whenIdle: wrapMethod("whenIdle", originalApi.whenIdle),
|
|
534
594
|
dispose: wrapMethod("dispose", originalApi.dispose),
|
|
@@ -573,11 +633,6 @@ class RemoteEngine {
|
|
|
573
633
|
},
|
|
574
634
|
});
|
|
575
635
|
}
|
|
576
|
-
setInput(nodeId, handle, value) {
|
|
577
|
-
this.transport.send({
|
|
578
|
-
message: { type: "SetInput", payload: { nodeId, handle, value } },
|
|
579
|
-
});
|
|
580
|
-
}
|
|
581
636
|
// Batch inputs for a single network round-trip
|
|
582
637
|
setInputs(nodeId, inputs) {
|
|
583
638
|
this.transport.send({
|
|
@@ -736,7 +791,13 @@ class RuntimeApiClient {
|
|
|
736
791
|
if (!WebSocketTransport) {
|
|
737
792
|
throw new Error("WebSocketTransport not available");
|
|
738
793
|
}
|
|
739
|
-
return new WebSocketTransport(this.config.url
|
|
794
|
+
return new WebSocketTransport(this.config.url, {
|
|
795
|
+
onConnectionLost: () => {
|
|
796
|
+
this.dispose().catch((err) => {
|
|
797
|
+
console.warn("[RuntimeApiClient] Error disposing on connection loss:", err);
|
|
798
|
+
});
|
|
799
|
+
},
|
|
800
|
+
});
|
|
740
801
|
}
|
|
741
802
|
else if (kind === "remote-unix") {
|
|
742
803
|
// Dynamic import to avoid bundling in browser builds
|
|
@@ -1093,16 +1154,6 @@ class RuntimeApiServer {
|
|
|
1093
1154
|
ack();
|
|
1094
1155
|
break;
|
|
1095
1156
|
}
|
|
1096
|
-
case "SetInput": {
|
|
1097
|
-
this.logCommand("SetInput", env, {
|
|
1098
|
-
nodeId: msg.payload.nodeId,
|
|
1099
|
-
handle: msg.payload.handle,
|
|
1100
|
-
value: summarize(msg.payload.value),
|
|
1101
|
-
});
|
|
1102
|
-
this.runtimeApi.setInput(msg.payload.nodeId, msg.payload.handle, msg.payload.value);
|
|
1103
|
-
ack();
|
|
1104
|
-
break;
|
|
1105
|
-
}
|
|
1106
1157
|
case "SetInputs": {
|
|
1107
1158
|
this.logCommand("SetInputs", env, {
|
|
1108
1159
|
nodeId: msg.payload.nodeId,
|
|
@@ -1221,12 +1272,6 @@ class RuntimeApiServer {
|
|
|
1221
1272
|
ack();
|
|
1222
1273
|
break;
|
|
1223
1274
|
}
|
|
1224
|
-
case "Pause":
|
|
1225
|
-
case "Resume": {
|
|
1226
|
-
this.logCommand(`${msg.type} (not-impl)`, env);
|
|
1227
|
-
ack();
|
|
1228
|
-
break;
|
|
1229
|
-
}
|
|
1230
1275
|
default: {
|
|
1231
1276
|
this.logCommand("Unknown type", env);
|
|
1232
1277
|
ack();
|