@bian-womp/spark-remote 0.2.31 → 0.2.33

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
@@ -219,8 +219,10 @@ class RemoteEngine {
219
219
  this.emit("stats", msg.payload);
220
220
  }
221
221
  }
222
- launch() {
223
- this.transport.send({ message: { type: "Launch" } });
222
+ launch(invalidate) {
223
+ this.transport.send({
224
+ message: { type: "Launch", payload: { invalidate } },
225
+ });
224
226
  }
225
227
  setInput(nodeId, handle, value) {
226
228
  this.transport.send({
@@ -437,7 +439,7 @@ async function handleCommand(label, env, runtimeApi, ack) {
437
439
  }
438
440
  case "Launch": {
439
441
  console.debug(`[${label}] rx Launch seq=${env.seq}`);
440
- runtimeApi.launch();
442
+ runtimeApi.launch(msg.payload.invalidate);
441
443
  ack();
442
444
  break;
443
445
  }
@@ -521,191 +523,189 @@ async function createRuntimeAdapter(createRegistry, send, extensions) {
521
523
  extData,
522
524
  });
523
525
  // Original implementations - define as separate functions first to allow cross-references
524
- const originals = {};
525
- // Define methods that can reference each other
526
- originals.coerce = async (from, to, value) => {
527
- const resolved = registry.resolveCoercion(from, to);
528
- if (!resolved)
529
- return value;
530
- if (resolved.kind === "sync")
531
- return resolved.convert(value);
532
- const ac = new AbortController();
533
- return await resolved.convertAsync(value, ac.signal);
534
- };
535
- originals.getEnvironment = () => {
536
- return graphRuntime?.getEnvironment?.() ?? {};
537
- };
538
- originals.applyRegistry = async (deltas) => {
539
- // Pause runtime if exists
540
- // Apply each delta to the live registry
541
- for (const d of deltas || []) {
542
- if (!d || typeof d !== "object")
543
- continue;
544
- if (d.kind === "register-enum") {
545
- registry.registerEnum({
546
- id: d.id,
547
- displayName: d.displayName,
548
- options: d.options || [],
549
- bakeTarget: d.bakeTarget,
550
- opts: d.opts,
551
- });
526
+ const originalApi = {
527
+ coerce: async (from, to, value) => {
528
+ const resolved = registry.resolveCoercion(from, to);
529
+ if (!resolved)
530
+ return value;
531
+ if (resolved.kind === "sync")
532
+ return resolved.convert(value);
533
+ const ac = new AbortController();
534
+ return await resolved.convertAsync(value, ac.signal);
535
+ },
536
+ getEnvironment: () => {
537
+ return graphRuntime?.getEnvironment?.() ?? {};
538
+ },
539
+ applyRegistry: async (deltas) => {
540
+ // Pause runtime if exists
541
+ // Apply each delta to the live registry
542
+ for (const d of deltas || []) {
543
+ if (!d || typeof d !== "object")
544
+ continue;
545
+ if (d.kind === "register-enum") {
546
+ registry.registerEnum({
547
+ id: d.id,
548
+ displayName: d.displayName,
549
+ options: d.options || [],
550
+ bakeTarget: d.bakeTarget,
551
+ opts: d.opts,
552
+ });
553
+ }
554
+ else if (d.kind === "register-type") {
555
+ registry.registerType({
556
+ id: d.id,
557
+ displayName: d.displayName,
558
+ bakeTarget: d.bakeTarget,
559
+ validate: (_v) => true,
560
+ });
561
+ }
562
+ else if (d.kind === "register-node") {
563
+ const desc = d.desc || {};
564
+ registry.registerNode({
565
+ id: String(desc.id || ""),
566
+ categoryId: String(desc.categoryId || "compute"),
567
+ displayName: desc.displayName,
568
+ inputs: desc.inputs || {},
569
+ outputs: desc.outputs || {},
570
+ // impl must be empty per frontend registration contract
571
+ impl: () => { },
572
+ });
573
+ }
552
574
  }
553
- else if (d.kind === "register-type") {
554
- registry.registerType({
555
- id: d.id,
556
- displayName: d.displayName,
557
- bakeTarget: d.bakeTarget,
558
- validate: (_v) => true,
559
- });
575
+ // Notify clients (include deltas in invalidate payload)
576
+ send({
577
+ message: {
578
+ type: "invalidate",
579
+ payload: { reason: "registry-changed", deltas },
580
+ },
581
+ });
582
+ },
583
+ build: async (def, opts) => {
584
+ const env = opts || {};
585
+ graphRuntime = builder.build(def, { environment: env });
586
+ graphRuntime.on("value", (p) => send({ message: { type: "value", payload: p } }));
587
+ graphRuntime.on("invalidate", (p) => send({ message: { type: "invalidate", payload: p } }));
588
+ graphRuntime.on("error", (p) => send({ message: { type: "error", payload: p } }));
589
+ graphRuntime.on("stats", (p) => send({ message: { type: "stats", payload: p } }));
590
+ },
591
+ setExtData: (data) => {
592
+ if (!data || typeof data !== "object") {
593
+ extData = {};
594
+ return;
560
595
  }
561
- else if (d.kind === "register-node") {
562
- const desc = d.desc || {};
563
- registry.registerNode({
564
- id: String(desc.id || ""),
565
- categoryId: String(desc.categoryId || "compute"),
566
- displayName: desc.displayName,
567
- inputs: desc.inputs || {},
568
- outputs: desc.outputs || {},
569
- // impl must be empty per frontend registration contract
570
- impl: () => { },
571
- });
596
+ // Replace to keep semantics deterministic
597
+ extData = { ...data };
598
+ },
599
+ getExtData: () => {
600
+ return extData;
601
+ },
602
+ snapshot: () => {
603
+ const inputs = {};
604
+ const outputs = {};
605
+ if (!graphRuntime)
606
+ return { inputs, outputs };
607
+ const nodes = graphRuntime.getNodeIds();
608
+ for (const nodeId of nodes) {
609
+ const data = graphRuntime.getNodeData(nodeId);
610
+ if (data?.inputs && Object.keys(data.inputs).length > 0) {
611
+ inputs[nodeId] = { ...data.inputs };
612
+ }
613
+ if (data?.outputs && Object.keys(data.outputs).length > 0) {
614
+ outputs[nodeId] = { ...data.outputs };
615
+ }
572
616
  }
573
- }
574
- // Notify clients (include deltas in invalidate payload)
575
- send({
576
- message: {
577
- type: "invalidate",
578
- payload: { reason: "registry-changed", deltas },
579
- },
580
- });
581
- };
582
- originals.build = async (def, opts) => {
583
- const env = opts || {};
584
- graphRuntime = builder.build(def, { environment: env });
585
- graphRuntime.on("value", (p) => send({ message: { type: "value", payload: p } }));
586
- graphRuntime.on("invalidate", (p) => send({ message: { type: "invalidate", payload: p } }));
587
- graphRuntime.on("error", (p) => send({ message: { type: "error", payload: p } }));
588
- graphRuntime.on("stats", (p) => send({ message: { type: "stats", payload: p } }));
589
- };
590
- originals.setExtData = (data) => {
591
- if (!data || typeof data !== "object") {
592
- extData = {};
593
- return;
594
- }
595
- // Replace to keep semantics deterministic
596
- extData = { ...data };
597
- };
598
- originals.getExtData = () => {
599
- return extData;
600
- };
601
- originals.snapshot = () => {
602
- const inputs = {};
603
- const outputs = {};
604
- if (!graphRuntime)
605
617
  return { inputs, outputs };
606
- const nodes = graphRuntime.getNodeIds();
607
- for (const nodeId of nodes) {
608
- const data = graphRuntime.getNodeData(nodeId);
609
- if (data?.inputs && Object.keys(data.inputs).length > 0) {
610
- inputs[nodeId] = { ...data.inputs };
611
- }
612
- if (data?.outputs && Object.keys(data.outputs).length > 0) {
613
- outputs[nodeId] = { ...data.outputs };
614
- }
615
- }
616
- return { inputs, outputs };
617
- };
618
- originals.snapshotFull = () => {
619
- const snap = originals.snapshot();
620
- const env = graphRuntime?.getEnvironment?.() ?? {};
621
- const def = graphRuntime?.getGraphDef();
622
- return {
623
- def,
624
- environment: env,
625
- inputs: snap.inputs,
626
- outputs: snap.outputs,
627
- };
628
- };
629
- originals.applySnapshotFull = async (payload) => {
630
- const def = payload.def;
631
- if (!def)
632
- return;
633
- await originals.build(def, payload.environment);
634
- // Hydrate inputs/outputs exactly, then re-emit outputs without scheduling runs
635
- graphRuntime?.hydrate({ inputs: payload.inputs, outputs: payload.outputs }, { reemit: true });
636
- };
637
- originals.describeRegistry = () => {
638
- // types (include enum options when available)
639
- const types = Array.from(registry.types.entries()).map(([id, d]) => {
640
- const en = registry.enums.get(id);
618
+ },
619
+ snapshotFull: () => {
620
+ const snap = originalApi.snapshot();
621
+ const env = graphRuntime?.getEnvironment?.() ?? {};
622
+ const def = graphRuntime?.getGraphDef();
641
623
  return {
642
- id,
643
- displayName: d.displayName,
644
- bakeTarget: d.bakeTarget,
645
- ...(en ? { options: en.options } : {}),
624
+ def,
625
+ environment: env,
626
+ inputs: snap.inputs,
627
+ outputs: snap.outputs,
646
628
  };
647
- });
648
- // categories: not directly enumerable; derive from node descriptors
649
- const nodeDescs = Array.from(registry.nodes.values());
650
- const catIds = new Set(nodeDescs.map((n) => n.categoryId));
651
- const categories = Array.from(catIds).map((id) => {
652
- const cat = registry.categories.get?.(id);
653
- return { id, displayName: cat?.displayName };
654
- });
655
- const nodes = nodeDescs.map((n) => ({
656
- id: n.id,
657
- categoryId: n.categoryId,
658
- displayName: n.displayName,
659
- inputs: n.inputs || {},
660
- outputs: n.outputs || {},
661
- inputDefaults: n.inputDefaults || {},
662
- }));
663
- const coercions = registry.listCoercions();
664
- return { types, categories, nodes, coercions, schemaVersion: 4 };
665
- };
666
- originals.update = async (def) => {
667
- if (!graphRuntime)
668
- return;
669
- graphRuntime.update(def, registry);
670
- send({
671
- message: {
672
- type: "invalidate",
673
- payload: { reason: "graph-updated" },
674
- },
675
- });
676
- };
677
- originals.setEnvironment = (env, opts) => {
678
- if (!graphRuntime)
679
- return;
680
- if (opts?.merge) {
681
- const current = graphRuntime.getEnvironment();
682
- const next = { ...(current || {}), ...(env || {}) };
683
- graphRuntime.setEnvironment(next);
684
- return;
685
- }
686
- graphRuntime.setEnvironment(env);
687
- };
688
- originals.setInput = (nodeId, handle, value) => {
689
- graphRuntime?.setInput(nodeId, handle, value);
690
- };
691
- originals.setInputs = (nodeId, inputs) => {
692
- graphRuntime?.setInputs(nodeId, inputs);
693
- };
694
- originals.triggerExternal = (nodeId, event) => {
695
- graphRuntime?.triggerExternal(nodeId, event);
696
- };
697
- originals.launch = () => {
698
- graphRuntime?.launch();
699
- };
700
- originals.whenIdle = () => {
701
- return graphRuntime?.whenIdle?.() ?? Promise.resolve();
702
- };
703
- originals.dispose = () => {
704
- graphRuntime?.dispose?.();
705
- graphRuntime = undefined;
629
+ },
630
+ applySnapshotFull: async (payload) => {
631
+ const def = payload.def;
632
+ if (!def)
633
+ return;
634
+ await originalApi.build(def, payload.environment);
635
+ // Hydrate inputs/outputs exactly, then re-emit outputs without scheduling runs
636
+ graphRuntime?.hydrate({ inputs: payload.inputs, outputs: payload.outputs }, { reemit: true });
637
+ },
638
+ describeRegistry: () => {
639
+ // types (include enum options when available)
640
+ const types = Array.from(registry.types.entries()).map(([id, d]) => {
641
+ const en = registry.enums.get(id);
642
+ return {
643
+ id,
644
+ displayName: d.displayName,
645
+ bakeTarget: d.bakeTarget,
646
+ ...(en ? { options: en.options } : {}),
647
+ };
648
+ });
649
+ // categories: not directly enumerable; derive from node descriptors
650
+ const nodeDescs = Array.from(registry.nodes.values());
651
+ const catIds = new Set(nodeDescs.map((n) => n.categoryId));
652
+ const categories = Array.from(catIds).map((id) => {
653
+ const cat = registry.categories.get?.(id);
654
+ return { id, displayName: cat?.displayName };
655
+ });
656
+ const nodes = nodeDescs.map((n) => ({
657
+ id: n.id,
658
+ categoryId: n.categoryId,
659
+ displayName: n.displayName,
660
+ inputs: n.inputs || {},
661
+ outputs: n.outputs || {},
662
+ inputDefaults: n.inputDefaults || {},
663
+ }));
664
+ const coercions = registry.listCoercions();
665
+ return { types, categories, nodes, coercions, schemaVersion: 4 };
666
+ },
667
+ update: async (def) => {
668
+ if (!graphRuntime)
669
+ return;
670
+ graphRuntime.update(def, registry);
671
+ send({
672
+ message: {
673
+ type: "invalidate",
674
+ payload: { reason: "graph-updated" },
675
+ },
676
+ });
677
+ },
678
+ setEnvironment: (env, opts) => {
679
+ if (!graphRuntime)
680
+ return;
681
+ if (opts?.merge) {
682
+ const current = graphRuntime.getEnvironment();
683
+ const next = { ...(current || {}), ...(env || {}) };
684
+ graphRuntime.setEnvironment(next);
685
+ return;
686
+ }
687
+ graphRuntime.setEnvironment(env);
688
+ },
689
+ setInput: (nodeId, handle, value) => {
690
+ graphRuntime?.setInput(nodeId, handle, value);
691
+ },
692
+ setInputs: (nodeId, inputs) => {
693
+ graphRuntime?.setInputs(nodeId, inputs);
694
+ },
695
+ triggerExternal: (nodeId, event) => {
696
+ graphRuntime?.triggerExternal(nodeId, event);
697
+ },
698
+ launch: (invalidate) => {
699
+ graphRuntime?.launch(invalidate);
700
+ },
701
+ whenIdle: () => {
702
+ return graphRuntime?.whenIdle?.() ?? Promise.resolve();
703
+ },
704
+ dispose: () => {
705
+ graphRuntime?.dispose?.();
706
+ graphRuntime = undefined;
707
+ },
706
708
  };
707
- // Cast to RuntimeApi now that all methods are defined
708
- const originalsApi = originals;
709
709
  // Helper to wrap a method with extension support
710
710
  const wrapMethod = (key, original) => {
711
711
  const extension = extensions?.[key];
@@ -717,27 +717,27 @@ async function createRuntimeAdapter(createRegistry, send, extensions) {
717
717
  });
718
718
  };
719
719
  // Create API with extensions applied
720
- const api = {
721
- coerce: wrapMethod("coerce", originalsApi.coerce),
722
- getEnvironment: wrapMethod("getEnvironment", originalsApi.getEnvironment),
723
- applyRegistry: wrapMethod("applyRegistry", originalsApi.applyRegistry),
724
- build: wrapMethod("build", originalsApi.build),
725
- setExtData: wrapMethod("setExtData", originalsApi.setExtData),
726
- getExtData: wrapMethod("getExtData", originalsApi.getExtData),
727
- snapshot: wrapMethod("snapshot", originalsApi.snapshot),
728
- snapshotFull: wrapMethod("snapshotFull", originalsApi.snapshotFull),
729
- applySnapshotFull: wrapMethod("applySnapshotFull", originalsApi.applySnapshotFull),
730
- describeRegistry: wrapMethod("describeRegistry", originalsApi.describeRegistry),
731
- update: wrapMethod("update", originalsApi.update),
732
- setEnvironment: wrapMethod("setEnvironment", originalsApi.setEnvironment),
733
- setInput: wrapMethod("setInput", originalsApi.setInput),
734
- setInputs: wrapMethod("setInputs", originalsApi.setInputs),
735
- triggerExternal: wrapMethod("triggerExternal", originalsApi.triggerExternal),
736
- launch: wrapMethod("launch", originalsApi.launch),
737
- whenIdle: wrapMethod("whenIdle", originalsApi.whenIdle),
738
- dispose: wrapMethod("dispose", originalsApi.dispose),
720
+ const extendedApi = {
721
+ coerce: wrapMethod("coerce", originalApi.coerce),
722
+ getEnvironment: wrapMethod("getEnvironment", originalApi.getEnvironment),
723
+ applyRegistry: wrapMethod("applyRegistry", originalApi.applyRegistry),
724
+ build: wrapMethod("build", originalApi.build),
725
+ setExtData: wrapMethod("setExtData", originalApi.setExtData),
726
+ getExtData: wrapMethod("getExtData", originalApi.getExtData),
727
+ snapshot: wrapMethod("snapshot", originalApi.snapshot),
728
+ snapshotFull: wrapMethod("snapshotFull", originalApi.snapshotFull),
729
+ applySnapshotFull: wrapMethod("applySnapshotFull", originalApi.applySnapshotFull),
730
+ describeRegistry: wrapMethod("describeRegistry", originalApi.describeRegistry),
731
+ update: wrapMethod("update", originalApi.update),
732
+ setEnvironment: wrapMethod("setEnvironment", originalApi.setEnvironment),
733
+ setInput: wrapMethod("setInput", originalApi.setInput),
734
+ setInputs: wrapMethod("setInputs", originalApi.setInputs),
735
+ triggerExternal: wrapMethod("triggerExternal", originalApi.triggerExternal),
736
+ launch: wrapMethod("launch", originalApi.launch),
737
+ whenIdle: wrapMethod("whenIdle", originalApi.whenIdle),
738
+ dispose: wrapMethod("dispose", originalApi.dispose),
739
739
  };
740
- return api;
740
+ return extendedApi;
741
741
  }
742
742
 
743
743
  export { HttpPollingTransport, RemoteEngine, RemoteRunner, WebSocketTransport, createRuntimeAdapter, handleCommand, serializeError, summarize };