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