@bian-womp/spark-remote 0.2.47 → 0.2.49

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/esm/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { WebSocket } from 'ws';
2
- import { GraphBuilder } from '@bian-womp/spark-graph';
2
+ import { GraphBuilder, createEngine } from '@bian-womp/spark-graph';
3
3
 
4
4
  class SeqGenerator {
5
5
  constructor() {
@@ -239,12 +239,14 @@ async function createRuntimeAdapter(createRegistry, send, extensions) {
239
239
  const registry = await createRegistry();
240
240
  const builder = new GraphBuilder(registry);
241
241
  let graphRuntime;
242
+ let engine;
242
243
  let extData = {};
243
244
  // Helper to get current context
244
245
  const getContext = () => ({
245
246
  registry,
246
247
  builder,
247
248
  graphRuntime,
249
+ engine,
248
250
  extData,
249
251
  });
250
252
  // Original implementations - define as separate functions first to allow cross-references
@@ -415,21 +417,81 @@ async function createRuntimeAdapter(createRegistry, send, extensions) {
415
417
  graphRuntime.setEnvironment(env);
416
418
  },
417
419
  setInput: (nodeId, handle, value) => {
418
- graphRuntime?.setInput(nodeId, handle, value);
420
+ // If engine exists, use it; otherwise fall back to direct runtime access
421
+ if (engine) {
422
+ engine.setInput(nodeId, handle, value);
423
+ }
424
+ else {
425
+ graphRuntime?.setInput(nodeId, handle, value);
426
+ }
419
427
  },
420
428
  setInputs: (nodeId, inputs) => {
421
- graphRuntime?.setInputs(nodeId, inputs);
429
+ if (engine) {
430
+ engine.setInputs(nodeId, inputs);
431
+ }
432
+ else {
433
+ graphRuntime?.setInputs(nodeId, inputs);
434
+ }
422
435
  },
423
436
  triggerExternal: (nodeId, event) => {
424
- graphRuntime?.triggerExternal(nodeId, event);
437
+ if (engine) {
438
+ engine.triggerExternal(nodeId, event);
439
+ }
440
+ else {
441
+ graphRuntime?.triggerExternal(nodeId, event);
442
+ }
443
+ },
444
+ launch: (opts) => {
445
+ if (!graphRuntime) {
446
+ throw new Error("Cannot launch: graph runtime not built");
447
+ }
448
+ // Dispose existing engine if any
449
+ if (engine) {
450
+ engine.dispose();
451
+ engine = undefined;
452
+ }
453
+ // Create new engine using shared factory
454
+ engine = createEngine(graphRuntime, opts);
455
+ // Launch the engine
456
+ if (engine) {
457
+ engine.launch(opts?.invalidate);
458
+ }
459
+ },
460
+ step: async () => {
461
+ if (!engine)
462
+ return;
463
+ // Type guard for StepEngine
464
+ if ("step" in engine && typeof engine.step === "function") {
465
+ await engine.step();
466
+ }
467
+ },
468
+ computeNode: async (nodeId) => {
469
+ if (!engine)
470
+ return;
471
+ // Type guard for PullEngine
472
+ if ("computeNode" in engine && typeof engine.computeNode === "function") {
473
+ await engine.computeNode(nodeId);
474
+ }
425
475
  },
426
- launch: (invalidate) => {
427
- graphRuntime?.launch(invalidate);
476
+ flush: async () => {
477
+ if (!engine)
478
+ return;
479
+ // Type guard for BatchedEngine
480
+ if ("flush" in engine && typeof engine.flush === "function") {
481
+ await engine.flush();
482
+ }
428
483
  },
429
484
  whenIdle: () => {
485
+ if (engine) {
486
+ return engine.whenIdle();
487
+ }
430
488
  return graphRuntime?.whenIdle?.() ?? Promise.resolve();
431
489
  },
432
490
  dispose: () => {
491
+ if (engine) {
492
+ engine.dispose();
493
+ engine = undefined;
494
+ }
433
495
  graphRuntime?.dispose?.();
434
496
  graphRuntime = undefined;
435
497
  },
@@ -440,6 +502,10 @@ async function createRuntimeAdapter(createRegistry, send, extensions) {
440
502
  if (!extension) {
441
503
  return original;
442
504
  }
505
+ // Handle optional methods that might be undefined
506
+ if (!original) {
507
+ return original;
508
+ }
443
509
  return ((...args) => {
444
510
  return extension(original, getContext(), ...args);
445
511
  });
@@ -497,9 +563,12 @@ class RemoteEngine {
497
563
  this.emit("stats", msg.payload);
498
564
  }
499
565
  }
500
- launch(invalidate) {
566
+ launch(invalidate, engineConfig) {
501
567
  this.transport.send({
502
- message: { type: "Launch", payload: { invalidate } },
568
+ message: {
569
+ type: "Launch",
570
+ payload: { invalidate, ...engineConfig },
571
+ },
503
572
  });
504
573
  }
505
574
  setInput(nodeId, handle, value) {
@@ -643,6 +712,7 @@ class RuntimeApiClient {
643
712
  this.transportEventListeners = new Set();
644
713
  this.disposed = false;
645
714
  this.config = config;
715
+ this.runnerId = options?.runnerId;
646
716
  if (options?.onCustomEvent) {
647
717
  this.customEventListeners.add(options.onCustomEvent);
648
718
  }
@@ -691,8 +761,11 @@ class RuntimeApiClient {
691
761
  if (this.connectingPromise) {
692
762
  return this.connectingPromise;
693
763
  }
694
- const kind = this.config.kind;
695
- this.emitTransportStatus({ state: "connecting", kind });
764
+ this.emitTransportStatus({
765
+ state: "connecting",
766
+ kind: this.config.kind,
767
+ runnerId: this.runnerId,
768
+ });
696
769
  // Create connection promise to prevent concurrent connections
697
770
  this.connectingPromise = (async () => {
698
771
  try {
@@ -705,12 +778,20 @@ class RuntimeApiClient {
705
778
  });
706
779
  // Create engine with connected transport
707
780
  this.engine = new RemoteEngine(transport);
708
- this.emitTransportStatus({ state: "connected", kind });
781
+ this.emitTransportStatus({
782
+ state: "connected",
783
+ kind: this.config.kind,
784
+ runnerId: this.runnerId,
785
+ });
709
786
  }
710
787
  catch (error) {
711
788
  // Clear connecting promise on error so retry is possible
712
789
  this.connectingPromise = undefined;
713
- this.emitTransportStatus({ state: "disconnected", kind });
790
+ this.emitTransportStatus({
791
+ state: "disconnected",
792
+ kind: this.config.kind,
793
+ runnerId: this.runnerId,
794
+ });
714
795
  throw error;
715
796
  }
716
797
  finally {
@@ -731,7 +812,7 @@ class RuntimeApiClient {
731
812
  const type = msg.type;
732
813
  // Standard runtime events: stats, value, error, invalidate
733
814
  // These are handled by RemoteEngine via transport subscription
734
- // Custom events are anything else (e.g., flow-opened, flow-latest)
815
+ // Custom events are anything else
735
816
  if (!["stats", "value", "error", "invalidate"].includes(type)) {
736
817
  // Emit to custom event listeners (constructor callback is auto-subscribed)
737
818
  for (const listener of this.customEventListeners) {
@@ -747,8 +828,11 @@ class RuntimeApiClient {
747
828
  this.transportEventListeners.add(listener);
748
829
  // Immediately emit current status if connected
749
830
  if (this.transport) {
750
- const kind = this.config.kind;
751
- listener({ state: "connected", kind });
831
+ listener({
832
+ state: "connected",
833
+ kind: this.config.kind,
834
+ runnerId: this.runnerId,
835
+ });
752
836
  }
753
837
  return () => {
754
838
  this.transportEventListeners.delete(listener);
@@ -869,6 +953,33 @@ class RuntimeApiClient {
869
953
  }
870
954
  return this.engine;
871
955
  }
956
+ async launch(opts) {
957
+ const transport = await this.ensureConnected();
958
+ await transport.request({
959
+ message: {
960
+ type: "Launch",
961
+ payload: opts,
962
+ },
963
+ });
964
+ }
965
+ async step() {
966
+ const transport = await this.ensureConnected();
967
+ await transport.request({
968
+ message: { type: "Step" },
969
+ });
970
+ }
971
+ async computeNode(nodeId) {
972
+ const transport = await this.ensureConnected();
973
+ await transport.request({
974
+ message: { type: "ComputeNode", payload: { nodeId } },
975
+ });
976
+ }
977
+ async flush() {
978
+ const transport = await this.ensureConnected();
979
+ await transport.request({
980
+ message: { type: "Flush" },
981
+ });
982
+ }
872
983
  /**
873
984
  * Dispose the client and close the transport connection.
874
985
  * Idempotent: safe to call multiple times.
@@ -896,7 +1007,11 @@ class RuntimeApiClient {
896
1007
  // Clear listeners
897
1008
  this.customEventListeners.clear();
898
1009
  this.transportEventListeners.clear();
899
- this.emitTransportStatus({ state: "disconnected", kind: this.config.kind });
1010
+ this.emitTransportStatus({
1011
+ state: "disconnected",
1012
+ kind: this.config.kind,
1013
+ runnerId: this.runnerId,
1014
+ });
900
1015
  }
901
1016
  }
902
1017
 
@@ -1007,8 +1122,43 @@ class RuntimeApiServer {
1007
1122
  break;
1008
1123
  }
1009
1124
  case "Launch": {
1010
- this.logCommand("Launch", env);
1011
- this.runtimeApi.launch(msg.payload.invalidate);
1125
+ const launchPayload = msg.payload;
1126
+ this.logCommand("Launch", env, {
1127
+ engine: launchPayload.engine,
1128
+ invalidate: launchPayload.invalidate,
1129
+ });
1130
+ this.runtimeApi.launch({
1131
+ invalidate: launchPayload.invalidate,
1132
+ engine: launchPayload.engine,
1133
+ batched: launchPayload.batched,
1134
+ hybrid: launchPayload.hybrid,
1135
+ });
1136
+ ack();
1137
+ break;
1138
+ }
1139
+ case "Step": {
1140
+ this.logCommand("Step", env);
1141
+ if (this.runtimeApi.step) {
1142
+ await this.runtimeApi.step();
1143
+ }
1144
+ ack();
1145
+ break;
1146
+ }
1147
+ case "ComputeNode": {
1148
+ this.logCommand("ComputeNode", env, {
1149
+ nodeId: msg.payload.nodeId,
1150
+ });
1151
+ if (this.runtimeApi.computeNode) {
1152
+ await this.runtimeApi.computeNode(msg.payload.nodeId);
1153
+ }
1154
+ ack();
1155
+ break;
1156
+ }
1157
+ case "Flush": {
1158
+ this.logCommand("Flush", env);
1159
+ if (this.runtimeApi.flush) {
1160
+ await this.runtimeApi.flush();
1161
+ }
1012
1162
  ack();
1013
1163
  break;
1014
1164
  }