@bian-womp/spark-remote 0.2.28 → 0.2.29

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