@norskvideo/norsk-studio-alpha 1.27.0-2026-01-08-2828c8f7 → 1.27.0-2026-01-14-d7f304fc

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.
Files changed (43) hide show
  1. package/client/info.js +258 -92
  2. package/client/style.css +76 -0
  3. package/lib/output.fileMp4/_gen/types.d.ts +1 -0
  4. package/lib/output.fileMp4/_gen/zod.js +3 -0
  5. package/lib/output.fileMp4/_gen/zod.js.map +1 -1
  6. package/lib/output.fileMp4/info.d.ts +5 -4
  7. package/lib/output.fileMp4/info.js +20 -9
  8. package/lib/output.fileMp4/info.js.map +1 -1
  9. package/lib/output.fileMp4/runtime.js +24 -6
  10. package/lib/output.fileMp4/runtime.js.map +1 -1
  11. package/lib/output.fileMp4/types.yaml +6 -0
  12. package/lib/output.tams/info.js +2 -0
  13. package/lib/output.tams/info.js.map +1 -1
  14. package/lib/output.tams/inline-view.js +5 -5
  15. package/lib/output.tams/inline-view.js.map +1 -1
  16. package/lib/output.tams/runtime.d.ts +2 -0
  17. package/lib/output.tams/runtime.js +9 -3
  18. package/lib/output.tams/runtime.js.map +1 -1
  19. package/lib/processor.hardSourceSwitch/_gen/types.d.ts +9 -0
  20. package/lib/processor.hardSourceSwitch/_gen/zod.js +12 -3
  21. package/lib/processor.hardSourceSwitch/_gen/zod.js.map +1 -1
  22. package/lib/processor.hardSourceSwitch/fullscreen.js +18 -1
  23. package/lib/processor.hardSourceSwitch/fullscreen.js.map +1 -1
  24. package/lib/processor.hardSourceSwitch/info.d.ts +9 -0
  25. package/lib/processor.hardSourceSwitch/info.js +60 -2
  26. package/lib/processor.hardSourceSwitch/info.js.map +1 -1
  27. package/lib/processor.hardSourceSwitch/inline-view.d.ts +1 -1
  28. package/lib/processor.hardSourceSwitch/inline-view.js +24 -2
  29. package/lib/processor.hardSourceSwitch/inline-view.js.map +1 -1
  30. package/lib/processor.hardSourceSwitch/runtime.d.ts +6 -1
  31. package/lib/processor.hardSourceSwitch/runtime.js +145 -15
  32. package/lib/processor.hardSourceSwitch/runtime.js.map +1 -1
  33. package/lib/processor.hardSourceSwitch/source-selection.d.ts +7 -0
  34. package/lib/processor.hardSourceSwitch/source-selection.js +35 -0
  35. package/lib/processor.hardSourceSwitch/source-selection.js.map +1 -0
  36. package/lib/processor.hardSourceSwitch/types.yaml +41 -0
  37. package/lib/test/hard-source-switch.d.ts +1 -0
  38. package/lib/test/hard-source-switch.js +504 -0
  39. package/lib/test/hard-source-switch.js.map +1 -0
  40. package/lib/test/output.fileMp4.d.ts +1 -0
  41. package/lib/test/output.fileMp4.js +104 -0
  42. package/lib/test/output.fileMp4.js.map +1 -0
  43. package/package.json +5 -5
package/client/info.js CHANGED
@@ -41722,7 +41722,7 @@ var require_dist6 = __commonJS({
41722
41722
  unstable_createCollection: () => createCollection2
41723
41723
  });
41724
41724
  module.exports = __toCommonJS2(index_exports);
41725
- var import_react12 = __toESM2(require_react());
41725
+ var import_react14 = __toESM2(require_react());
41726
41726
  var import_react_context = require_dist3();
41727
41727
  var import_react_compose_refs = require_dist4();
41728
41728
  var import_react_slot = require_dist5();
@@ -41736,14 +41736,14 @@ var require_dist6 = __commonJS({
41736
41736
  );
41737
41737
  const CollectionProvider = (props) => {
41738
41738
  const { scope, children } = props;
41739
- const ref = import_react12.default.useRef(null);
41740
- const itemMap = import_react12.default.useRef(/* @__PURE__ */ new Map()).current;
41739
+ const ref = import_react14.default.useRef(null);
41740
+ const itemMap = import_react14.default.useRef(/* @__PURE__ */ new Map()).current;
41741
41741
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(CollectionProviderImpl, { scope, itemMap, collectionRef: ref, children });
41742
41742
  };
41743
41743
  CollectionProvider.displayName = PROVIDER_NAME;
41744
41744
  const COLLECTION_SLOT_NAME = name + "CollectionSlot";
41745
41745
  const CollectionSlotImpl = (0, import_react_slot.createSlot)(COLLECTION_SLOT_NAME);
41746
- const CollectionSlot = import_react12.default.forwardRef(
41746
+ const CollectionSlot = import_react14.default.forwardRef(
41747
41747
  (props, forwardedRef) => {
41748
41748
  const { scope, children } = props;
41749
41749
  const context = useCollectionContext(COLLECTION_SLOT_NAME, scope);
@@ -41755,13 +41755,13 @@ var require_dist6 = __commonJS({
41755
41755
  const ITEM_SLOT_NAME = name + "CollectionItemSlot";
41756
41756
  const ITEM_DATA_ATTR = "data-radix-collection-item";
41757
41757
  const CollectionItemSlotImpl = (0, import_react_slot.createSlot)(ITEM_SLOT_NAME);
41758
- const CollectionItemSlot = import_react12.default.forwardRef(
41758
+ const CollectionItemSlot = import_react14.default.forwardRef(
41759
41759
  (props, forwardedRef) => {
41760
41760
  const { scope, children, ...itemData } = props;
41761
- const ref = import_react12.default.useRef(null);
41761
+ const ref = import_react14.default.useRef(null);
41762
41762
  const composedRefs = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, ref);
41763
41763
  const context = useCollectionContext(ITEM_SLOT_NAME, scope);
41764
- import_react12.default.useEffect(() => {
41764
+ import_react14.default.useEffect(() => {
41765
41765
  context.itemMap.set(ref, { ref, ...itemData });
41766
41766
  return () => void context.itemMap.delete(ref);
41767
41767
  });
@@ -41771,7 +41771,7 @@ var require_dist6 = __commonJS({
41771
41771
  CollectionItemSlot.displayName = ITEM_SLOT_NAME;
41772
41772
  function useCollection(scope) {
41773
41773
  const context = useCollectionContext(name + "CollectionConsumer", scope);
41774
- const getItems = import_react12.default.useCallback(() => {
41774
+ const getItems = import_react14.default.useCallback(() => {
41775
41775
  const collectionNode = context.collectionRef.current;
41776
41776
  if (!collectionNode) return [];
41777
41777
  const orderedNodes = Array.from(collectionNode.querySelectorAll(`[${ITEM_DATA_ATTR}]`));
@@ -61747,18 +61747,41 @@ var require_FaSlidersH = __commonJS({
61747
61747
  }
61748
61748
  });
61749
61749
 
61750
+ // ../../node_modules/@react-icons/all-files/fa/FaTimes.js
61751
+ var require_FaTimes = __commonJS({
61752
+ "../../node_modules/@react-icons/all-files/fa/FaTimes.js"(exports, module) {
61753
+ var GenIcon = require_cjs().GenIcon;
61754
+ module.exports.FaTimes = function FaTimes2(props) {
61755
+ return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 352 512" }, "child": [{ "tag": "path", "attr": { "d": "M242.72 256l100.07-100.07c12.28-12.28 12.28-32.19 0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 75.93 89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 32.19 0 44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 22.24c12.28 12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 12.28 44.48 0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z" } }] })(props);
61756
+ };
61757
+ }
61758
+ });
61759
+
61760
+ // ../../node_modules/@react-icons/all-files/fa/FaPlay.js
61761
+ var require_FaPlay = __commonJS({
61762
+ "../../node_modules/@react-icons/all-files/fa/FaPlay.js"(exports, module) {
61763
+ var GenIcon = require_cjs().GenIcon;
61764
+ module.exports.FaPlay = function FaPlay2(props) {
61765
+ return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 448 512" }, "child": [{ "tag": "path", "attr": { "d": "M424.4 214.7L72.4 6.6C43.8-10.3 0 6.1 0 47.9V464c0 37.5 40.7 60.1 72.4 41.3l352-208c31.4-18.5 31.5-64.1 0-82.6z" } }] })(props);
61766
+ };
61767
+ }
61768
+ });
61769
+
61770
+ // ../../node_modules/@react-icons/all-files/fa/FaCircle.js
61771
+ var require_FaCircle = __commonJS({
61772
+ "../../node_modules/@react-icons/all-files/fa/FaCircle.js"(exports, module) {
61773
+ var GenIcon = require_cjs().GenIcon;
61774
+ module.exports.FaCircle = function FaCircle2(props) {
61775
+ return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 512 512" }, "child": [{ "tag": "path", "attr": { "d": "M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8z" } }] })(props);
61776
+ };
61777
+ }
61778
+ });
61779
+
61750
61780
  // build/client/output.fileMp4/info.js
61751
61781
  var import_FaFileVideo = __toESM(require_FaFileVideo());
61752
61782
 
61753
- // build/client/output.fileMp4/inline-view.js
61754
- var import_jsx_runtime = __toESM(require_jsx_runtime());
61755
- function InlineView({ state: _, config }) {
61756
- return (0, import_jsx_runtime.jsx)("div", { className: "file-output", id: `file-output-${config.id}` });
61757
- }
61758
- var inline_view_default = InlineView;
61759
-
61760
61783
  // build/client/output.fileMp4/summary-view.js
61761
- var import_jsx_runtime2 = __toESM(require_jsx_runtime());
61784
+ var import_jsx_runtime = __toESM(require_jsx_runtime());
61762
61785
  function SummaryView({ state: _, sendCommand }) {
61763
61786
  const handleWriteFile = () => {
61764
61787
  void writeFile();
@@ -61768,7 +61791,7 @@ function SummaryView({ state: _, sendCommand }) {
61768
61791
  type: "write-file"
61769
61792
  });
61770
61793
  };
61771
- return (0, import_jsx_runtime2.jsx)("div", { className: "mb-5", children: (0, import_jsx_runtime2.jsx)("div", { className: "flex items-center justify-between mb-3", children: (0, import_jsx_runtime2.jsx)("div", { children: (0, import_jsx_runtime2.jsx)("button", { onClick: handleWriteFile, className: "px-3 py-1 text-sm bg-red-600 hover:bg-red-700 text-white rounded", children: "Write Mp4 File" }) }) }) });
61794
+ return (0, import_jsx_runtime.jsx)("div", { className: "mb-5", children: (0, import_jsx_runtime.jsx)("div", { className: "flex items-center justify-between mb-3", children: (0, import_jsx_runtime.jsx)("div", { children: (0, import_jsx_runtime.jsx)("button", { onClick: handleWriteFile, className: "px-3 py-1 text-sm bg-red-600 hover:bg-red-700 text-white rounded", children: "Write Mp4 File" }) }) }) });
61772
61795
  }
61773
61796
  var summary_view_default = SummaryView;
61774
61797
 
@@ -61778,18 +61801,30 @@ function info_default(r) {
61778
61801
  return defineFileOutputComponent(r, {
61779
61802
  identifier: "output.fileMp4",
61780
61803
  name: "MP4 File",
61781
- description: "Sends audio and video streams to one or more remote RTMP servers simultaneously",
61804
+ description: "Write an MP4 output file. A streaming output file (e.g. fragmented MP4) is created continuously, with finalised MP4 files available on demand.",
61782
61805
  searchTags: ["mp4", "egest"],
61783
61806
  icon: import_FaFileVideo.FaFileVideo,
61784
61807
  configForm: {
61785
61808
  form: {
61786
61809
  fileName: {
61787
- help: "The base filename to write (without extension/path)",
61810
+ help: "The filename to write",
61788
61811
  hint: {
61789
61812
  type: "text",
61790
61813
  defaultValue: "output",
61791
61814
  envOverride: true,
61792
- validation: Z3.string().min(1).max(256).regex(/^[^./]+/, "Filename should not contain a path or extension")
61815
+ validation: Z3.string().min(1).max(256)
61816
+ }
61817
+ },
61818
+ writeMode: {
61819
+ help: "File write mode for the continuous output",
61820
+ hint: {
61821
+ type: "select",
61822
+ options: [
61823
+ { value: "non-fragmented", display: "Non-fragmented MP4" },
61824
+ { value: "fragmented", display: "Fragmented MP4" },
61825
+ { value: "incremental", display: "Incremental non-fragmented MP4" }
61826
+ ],
61827
+ defaultValue: "fragmented"
61793
61828
  }
61794
61829
  },
61795
61830
  notes: {
@@ -61808,8 +61843,7 @@ function defineFileOutputComponent({ defineComponent }, settings) {
61808
61843
  accepts: {
61809
61844
  type: "simple-stream",
61810
61845
  audio: true,
61811
- video: true,
61812
- subtitle: true
61846
+ video: true
61813
61847
  }
61814
61848
  },
61815
61849
  extraValidation: function(ctx) {
@@ -61819,9 +61853,9 @@ function defineFileOutputComponent({ defineComponent }, settings) {
61819
61853
  settings.extraValidation(ctx);
61820
61854
  }
61821
61855
  },
61822
- display: (_desc) => {
61856
+ display: (desc) => {
61823
61857
  return {
61824
- // url: desc.config.url
61858
+ fileName: desc.config.fileName
61825
61859
  };
61826
61860
  },
61827
61861
  runtime: {
@@ -61829,7 +61863,6 @@ function defineFileOutputComponent({ defineComponent }, settings) {
61829
61863
  handleEvent: (ev2, state) => {
61830
61864
  return { ...state };
61831
61865
  },
61832
- inline: inline_view_default,
61833
61866
  summary: summary_view_default
61834
61867
  }
61835
61868
  });
@@ -61839,7 +61872,7 @@ function defineFileOutputComponent({ defineComponent }, settings) {
61839
61872
  var import_util = __toESM(require_util());
61840
61873
 
61841
61874
  // build/client/output.tams/inline-view.js
61842
- var import_jsx_runtime3 = __toESM(require_jsx_runtime());
61875
+ var import_jsx_runtime2 = __toESM(require_jsx_runtime());
61843
61876
 
61844
61877
  // ../norsk-player-react/dist/norsk-player-react.es.js
61845
61878
  var import_react = __toESM(require_react());
@@ -69729,11 +69762,11 @@ var hc2 = ({
69729
69762
 
69730
69763
  // build/client/output.tams/inline-view.js
69731
69764
  var import_react2 = __toESM(require_react());
69732
- function InlineView2({ state }) {
69765
+ function InlineView({ state }) {
69733
69766
  const [playing, setPlaying] = (0, import_react2.useState)();
69734
69767
  const [hovered, setHovered] = (0, import_react2.useState)(false);
69735
69768
  if (playing) {
69736
- return (0, import_jsx_runtime3.jsx)("div", { className: "flex flex-col gap-2", children: (0, import_jsx_runtime3.jsxs)("div", { style: { width: 420, height: 280 }, className: "relative", children: [(0, import_jsx_runtime3.jsx)("button", { onClick: () => setPlaying(void 0), onMouseEnter: () => setHovered(true), onMouseLeave: () => setHovered(false), className: `
69769
+ return (0, import_jsx_runtime2.jsx)("div", { className: "flex flex-col gap-2", children: (0, import_jsx_runtime2.jsxs)("div", { style: { width: 420, height: 280 }, className: "relative", children: [(0, import_jsx_runtime2.jsx)("button", { onClick: () => setPlaying(void 0), onMouseEnter: () => setHovered(true), onMouseLeave: () => setHovered(false), className: `
69737
69770
  absolute top-1 right-1
69738
69771
  z-50 pointer-events-auto
69739
69772
  flex items-center justify-center
@@ -69746,30 +69779,30 @@ function InlineView2({ state }) {
69746
69779
  !p-0 leading-none
69747
69780
  transition-transform transition-colors duration-150 ease-out
69748
69781
  ${hovered ? "opacity-50" : "opacity-20"}
69749
- `, children: (0, import_jsx_runtime3.jsxs)("svg", { viewBox: "0 0 20 20", className: "w-4 h-4", stroke: "currentColor", strokeWidth: "2", fill: "none", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, import_jsx_runtime3.jsx)("line", { x1: "4", y1: "4", x2: "16", y2: "16" }), (0, import_jsx_runtime3.jsx)("line", { x1: "16", y1: "4", x2: "4", y2: "16" })] }) }), (0, import_jsx_runtime3.jsx)(hc2, { src: playing, className: "w-full h-full", fillContainer: true }, playing)] }) });
69782
+ `, children: (0, import_jsx_runtime2.jsxs)("svg", { viewBox: "0 0 20 20", className: "w-4 h-4", stroke: "currentColor", strokeWidth: "2", fill: "none", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, import_jsx_runtime2.jsx)("line", { x1: "4", y1: "4", x2: "16", y2: "16" }), (0, import_jsx_runtime2.jsx)("line", { x1: "16", y1: "4", x2: "4", y2: "16" })] }) }), (0, import_jsx_runtime2.jsx)(hc2, { src: playing, className: "w-full h-full", fillContainer: true }, playing)] }) });
69750
69783
  }
69751
69784
  const hasSessions = state.active || state.sessions.length > 0;
69752
- return (0, import_jsx_runtime3.jsxs)("div", { className: "bg-slate-950 p-6 overflow-auto", style: { maxHeight: "600px", maxWidth: "450px" }, children: [!hasSessions && (0, import_jsx_runtime3.jsx)("div", { className: "text-slate-400 text-center py-8", children: "No active or recorded sessions" }), displaySessions("Active Sessions", state.active ? [state.active] : [], setPlaying), displaySessions("Past Sessions", state.sessions, setPlaying)] });
69785
+ return (0, import_jsx_runtime2.jsxs)("div", { className: "bg-slate-950 p-6 overflow-auto", style: { maxHeight: "600px", maxWidth: "450px" }, children: [!hasSessions && (0, import_jsx_runtime2.jsx)("div", { className: "text-slate-400 text-center py-8", children: "No active or recorded sessions" }), displaySessions("Active Sessions", state.active ? [state.active] : [], state.tamsUrl, setPlaying), displaySessions("Past Sessions", state.sessions, state.tamsUrl, setPlaying)] });
69753
69786
  }
69754
- var sessionLink = ({ audio, video }) => {
69787
+ var sessionLink = (baseUrl, { audio, video }) => {
69755
69788
  if (!audio.tamsId || !video.tamsId)
69756
69789
  return;
69757
- const tamsUrl = ({ tamsId }) => `http://localhost:6791/x-tams/flows/${tamsId}`;
69790
+ const tamsUrl = ({ tamsId }) => `${baseUrl}/flows/${tamsId}`;
69758
69791
  return `${tamsUrl(audio)},${tamsUrl(video)}`;
69759
69792
  };
69760
- var displaySessions = (name, sessions, setPlaying) => {
69793
+ var displaySessions = (name, sessions, tamsUrl, setPlaying) => {
69761
69794
  if (!sessions.length)
69762
69795
  return null;
69763
- return (0, import_jsx_runtime3.jsxs)("div", { className: "mb-6", children: [(0, import_jsx_runtime3.jsx)("h3", { className: "text-lg font-semibold mb-3 text-slate-300", children: name }), (0, import_jsx_runtime3.jsx)("div", { className: "space-y-2", children: sessions.slice().reverse().map((session) => {
69764
- const url = sessionLink(session);
69796
+ return (0, import_jsx_runtime2.jsxs)("div", { className: "mb-6", children: [(0, import_jsx_runtime2.jsx)("h3", { className: "text-lg font-semibold mb-3 text-slate-300", children: name }), (0, import_jsx_runtime2.jsx)("div", { className: "space-y-2", children: sessions.slice().reverse().map((session) => {
69797
+ const url = sessionLink(tamsUrl, session);
69765
69798
  if (!url)
69766
69799
  return null;
69767
69800
  const duration = (session.video.durationMs / 6e4).toFixed(0);
69768
69801
  const time = new Date(session.video.startIso).toLocaleTimeString();
69769
- return (0, import_jsx_runtime3.jsxs)("button", { onClick: () => setPlaying(url), className: "w-full px-4 py-3 bg-slate-800 hover:bg-slate-700 text-slate-200 rounded-lg transition-colors text-left", children: ["Play session ", time, " (", duration, " minutes)"] }, session.video.startIso);
69802
+ return (0, import_jsx_runtime2.jsxs)("button", { onClick: () => setPlaying(url), className: "w-full px-4 py-3 bg-slate-800 hover:bg-slate-700 text-slate-200 rounded-lg transition-colors text-left", children: ["Play session ", time, " (", duration, " minutes)"] }, session.video.startIso);
69770
69803
  }) })] });
69771
69804
  };
69772
- var inline_view_default2 = InlineView2;
69805
+ var inline_view_default = InlineView;
69773
69806
 
69774
69807
  // build/client/output.tams/info.js
69775
69808
  function info_default2(R) {
@@ -69794,7 +69827,8 @@ function info_default2(R) {
69794
69827
  initialState: () => ({
69795
69828
  active: void 0,
69796
69829
  sessions: [],
69797
- cuts: []
69830
+ cuts: [],
69831
+ tamsUrl: ""
69798
69832
  }),
69799
69833
  handleEvent: (ev2, s) => {
69800
69834
  const evt = ev2.type;
@@ -69802,6 +69836,7 @@ function info_default2(R) {
69802
69836
  case "updated":
69803
69837
  s.active = ev2.active;
69804
69838
  s.sessions = ev2.sessions;
69839
+ s.tamsUrl = ev2.tamsUrl;
69805
69840
  break;
69806
69841
  case "cut-started":
69807
69842
  s.cuts.push({ id: ev2.id, percent: 0, createdMs: ev2.createdMs });
@@ -69820,7 +69855,7 @@ function info_default2(R) {
69820
69855
  }
69821
69856
  return { ...s };
69822
69857
  },
69823
- inline: inline_view_default2
69858
+ inline: inline_view_default
69824
69859
  },
69825
69860
  configForm: {
69826
69861
  form: {
@@ -69857,7 +69892,7 @@ function info_default2(R) {
69857
69892
  var import_config = __toESM(require_config());
69858
69893
 
69859
69894
  // build/client/processor.actionReplay/summary.js
69860
- var import_jsx_runtime4 = __toESM(require_jsx_runtime());
69895
+ var import_jsx_runtime3 = __toESM(require_jsx_runtime());
69861
69896
  var import_react3 = __toESM(require_react());
69862
69897
  var import_hls = __toESM(require_hls());
69863
69898
  var changingDuration = false;
@@ -69881,8 +69916,8 @@ function SummaryView2({ state, config, sendCommand }) {
69881
69916
  }
69882
69917
  }, [state.contentPlayerUrl]);
69883
69918
  if (!url)
69884
- return (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: "..." });
69885
- return (0, import_jsx_runtime4.jsxs)("div", { className: "mb-5", children: [(0, import_jsx_runtime4.jsx)("h5", { children: "Preview" }), (0, import_jsx_runtime4.jsx)("video", { ref: previewVideo, controls: true, onSeeked, autoPlay: true, muted: true, className: state.replaying ? "hidden" : "", id: `${id3}-video` }), state.replaying ? (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: "Current Performing Replay" }) : (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [lastSeek ? (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [(0, import_jsx_runtime4.jsxs)("p", { children: ["Replay from ", lastSeek.time.toFixed(1), "(s) "] }), (0, import_jsx_runtime4.jsxs)("p", { className: "block mb-2 text-sm font-medium text-gray-900 dark:text-white", children: ["Duration: ", playbackDuration, "s"] }), (0, import_jsx_runtime4.jsx)("input", { id: "duration-range", type: "range", min: currentMinDuration(), max: currentMaxDuration(), defaultValue: playbackDuration, className: "w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer dark:bg-gray-700", onChange: onDurationChange, onInput: onDurationChange })] }) : (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, {}), (0, import_jsx_runtime4.jsx)("button", { onClick: sendReplayCommand, type: "button", className: "mt-2 mb-2 text-white w-full justify-center bg-primary-700 hover:bg-primary-800 focus:ring-4 focus:outline-none focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800", children: "Replay" })] })] });
69919
+ return (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children: "..." });
69920
+ return (0, import_jsx_runtime3.jsxs)("div", { className: "mb-5", children: [(0, import_jsx_runtime3.jsx)("h5", { children: "Preview" }), (0, import_jsx_runtime3.jsx)("video", { ref: previewVideo, controls: true, onSeeked, autoPlay: true, muted: true, className: state.replaying ? "hidden" : "", id: `${id3}-video` }), state.replaying ? (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children: "Current Performing Replay" }) : (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [lastSeek ? (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [(0, import_jsx_runtime3.jsxs)("p", { children: ["Replay from ", lastSeek.time.toFixed(1), "(s) "] }), (0, import_jsx_runtime3.jsxs)("p", { className: "block mb-2 text-sm font-medium text-gray-900 dark:text-white", children: ["Duration: ", playbackDuration, "s"] }), (0, import_jsx_runtime3.jsx)("input", { id: "duration-range", type: "range", min: currentMinDuration(), max: currentMaxDuration(), defaultValue: playbackDuration, className: "w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer dark:bg-gray-700", onChange: onDurationChange, onInput: onDurationChange })] }) : (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, {}), (0, import_jsx_runtime3.jsx)("button", { onClick: sendReplayCommand, type: "button", className: "mt-2 mb-2 text-white w-full justify-center bg-primary-700 hover:bg-primary-800 focus:ring-4 focus:outline-none focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800", children: "Replay" })] })] });
69886
69921
  function sendReplayCommand() {
69887
69922
  if (!previewVideo.current)
69888
69923
  return;
@@ -69989,9 +70024,9 @@ function info_default3({ defineComponent, assertUnreachable: assertUnreachable7
69989
70024
  }
69990
70025
 
69991
70026
  // build/client/processor.audioLevel/inline-view.js
69992
- var import_jsx_runtime5 = __toESM(require_jsx_runtime());
70027
+ var import_jsx_runtime4 = __toESM(require_jsx_runtime());
69993
70028
  var import_react4 = __toESM(require_react());
69994
- function InlineView3({ state, raise }) {
70029
+ function InlineView2({ state, raise }) {
69995
70030
  (0, import_react4.useEffect)(() => {
69996
70031
  if (raise) {
69997
70032
  raise();
@@ -70010,16 +70045,16 @@ function InlineView3({ state, raise }) {
70010
70045
  return Math.max(0, 100 - snapped);
70011
70046
  }
70012
70047
  if (!state.levels) {
70013
- return (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, {});
70048
+ return (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, {});
70014
70049
  }
70015
70050
  {
70016
70051
  }
70017
- return (0, import_jsx_runtime5.jsx)("div", { className: "processor-audioLevel", children: (0, import_jsx_runtime5.jsx)("div", { className: "audio-level-container-inline", children: (0, import_jsx_runtime5.jsx)("div", { className: "preview-levels-inline", children: (0, import_jsx_runtime5.jsx)("div", { className: `preview-level clip-${percentage(state.levels)}` }) }) }) });
70052
+ return (0, import_jsx_runtime4.jsx)("div", { className: "processor-audioLevel", children: (0, import_jsx_runtime4.jsx)("div", { className: "audio-level-container-inline", children: (0, import_jsx_runtime4.jsx)("div", { className: "preview-levels-inline", children: (0, import_jsx_runtime4.jsx)("div", { className: `preview-level clip-${percentage(state.levels)}` }) }) }) });
70018
70053
  }
70019
- var inline_view_default3 = InlineView3;
70054
+ var inline_view_default2 = InlineView2;
70020
70055
 
70021
70056
  // build/client/processor.audioLevel/summary-view.js
70022
- var import_jsx_runtime6 = __toESM(require_jsx_runtime());
70057
+ var import_jsx_runtime5 = __toESM(require_jsx_runtime());
70023
70058
  var import_react5 = __toESM(require_react());
70024
70059
  function SummaryView3({ state, sendCommand }) {
70025
70060
  const [sliderValue, setSliderValue] = (0, import_react5.useState)(state.sliderGain || "0");
@@ -70040,7 +70075,7 @@ function SummaryView3({ state, sendCommand }) {
70040
70075
  const gainClasses = state.levels ? "col-start-2 self-end" : "col-start-1 col-end-3 self-end justify-self-start";
70041
70076
  {
70042
70077
  }
70043
- return (0, import_jsx_runtime6.jsx)("div", { className: "processor-audioLevel", children: (0, import_jsx_runtime6.jsxs)("div", { className: "audio-level-container grid mb-6 relative justify-items-center", children: [(0, import_jsx_runtime6.jsxs)("div", { className: `preview-levels-summary ${state.levels ? "" : "opacity-30"}`, children: [(0, import_jsx_runtime6.jsx)("div", { className: "relative w-full h-full", children: (0, import_jsx_runtime6.jsx)("div", { className: `preview-level absolute h-full w-4/6 clip-${percentage(state.levels)}` }) }), (0, import_jsx_runtime6.jsxs)("div", { className: "relative", children: [(0, import_jsx_runtime6.jsx)("div", { className: "text-sm absolute -top-1", children: "0dB" }), (0, import_jsx_runtime6.jsx)("div", { className: "text-sm absolute top-14", children: "-50dB" }), (0, import_jsx_runtime6.jsx)("div", { className: "text-sm absolute -bottom-2", children: "-100dB" })] })] }), (0, import_jsx_runtime6.jsx)("div", { className: "h-full flex items-center", children: (0, import_jsx_runtime6.jsx)("input", { id: "audio-slider", className: `-rotate-90 h-2.5 ${state.levels ? "" : "opacity-20"}`, type: "range", name: "gain", min: "-40", max: "40", step: "1", defaultValue: state.sliderGain || "0", disabled: !state.levels, onChange: (e) => {
70078
+ return (0, import_jsx_runtime5.jsx)("div", { className: "processor-audioLevel", children: (0, import_jsx_runtime5.jsxs)("div", { className: "audio-level-container grid mb-6 relative justify-items-center", children: [(0, import_jsx_runtime5.jsxs)("div", { className: `preview-levels-summary ${state.levels ? "" : "opacity-30"}`, children: [(0, import_jsx_runtime5.jsx)("div", { className: "relative w-full h-full", children: (0, import_jsx_runtime5.jsx)("div", { className: `preview-level absolute h-full w-4/6 clip-${percentage(state.levels)}` }) }), (0, import_jsx_runtime5.jsxs)("div", { className: "relative", children: [(0, import_jsx_runtime5.jsx)("div", { className: "text-sm absolute -top-1", children: "0dB" }), (0, import_jsx_runtime5.jsx)("div", { className: "text-sm absolute top-14", children: "-50dB" }), (0, import_jsx_runtime5.jsx)("div", { className: "text-sm absolute -bottom-2", children: "-100dB" })] })] }), (0, import_jsx_runtime5.jsx)("div", { className: "h-full flex items-center", children: (0, import_jsx_runtime5.jsx)("input", { id: "audio-slider", className: `-rotate-90 h-2.5 ${state.levels ? "" : "opacity-20"}`, type: "range", name: "gain", min: "-40", max: "40", step: "1", defaultValue: state.sliderGain || "0", disabled: !state.levels, onChange: (e) => {
70044
70079
  setSliderValue(e.target.value);
70045
70080
  if (canSetVolume) {
70046
70081
  setCanSetVolume(false);
@@ -70051,7 +70086,7 @@ function SummaryView3({ state, sendCommand }) {
70051
70086
  }
70052
70087
  }, onMouseUp: (_e3) => {
70053
70088
  sendCommand({ type: "set-gain", value: Number(sliderValue) });
70054
- } }) }), (0, import_jsx_runtime6.jsx)("div", { className: gainClasses, children: state.levels ? "Gain:" : "No incoming audio" }), (0, import_jsx_runtime6.jsx)("div", { className: "col-start-2", children: state.levels ? `${Number(sliderValue) > 0 ? "+" : ""} ${sliderValue} dB` : "" })] }) });
70089
+ } }) }), (0, import_jsx_runtime5.jsx)("div", { className: gainClasses, children: state.levels ? "Gain:" : "No incoming audio" }), (0, import_jsx_runtime5.jsx)("div", { className: "col-start-2", children: state.levels ? `${Number(sliderValue) > 0 ? "+" : ""} ${sliderValue} dB` : "" })] }) });
70055
70090
  }
70056
70091
  var summary_view_default2 = SummaryView3;
70057
70092
 
@@ -70103,7 +70138,7 @@ function info_default4({ defineComponent, validation: { Z: Z3 } }) {
70103
70138
  }
70104
70139
  return { ...state };
70105
70140
  },
70106
- inline: inline_view_default3,
70141
+ inline: inline_view_default2,
70107
70142
  summary: summary_view_default2
70108
70143
  },
70109
70144
  configForm: {
@@ -70122,12 +70157,12 @@ function assertUnreachable2(_) {
70122
70157
  var import_client_types = __toESM(require_client_types());
70123
70158
 
70124
70159
  // build/client/processor.chaos/form-views.js
70125
- var import_jsx_runtime7 = __toESM(require_jsx_runtime());
70160
+ var import_jsx_runtime6 = __toESM(require_jsx_runtime());
70126
70161
  function FrameDrop(cfg) {
70127
70162
  if (cfg) {
70128
- return (0, import_jsx_runtime7.jsxs)("div", { className: "grid grid-flow-row-dense grid-cols-3 text-sm", children: [(0, import_jsx_runtime7.jsx)("div", { className: "col-span-1", children: "Frame Drop" }), (0, import_jsx_runtime7.jsx)("div", { className: "col-span-2", children: cfg.kind })] });
70163
+ return (0, import_jsx_runtime6.jsxs)("div", { className: "grid grid-flow-row-dense grid-cols-3 text-sm", children: [(0, import_jsx_runtime6.jsx)("div", { className: "col-span-1", children: "Frame Drop" }), (0, import_jsx_runtime6.jsx)("div", { className: "col-span-2", children: cfg.kind })] });
70129
70164
  } else {
70130
- return (0, import_jsx_runtime7.jsx)("div", { className: "grid grid-flow-row-dense grid-cols-3 text-sm" });
70165
+ return (0, import_jsx_runtime6.jsx)("div", { className: "grid grid-flow-row-dense grid-cols-3 text-sm" });
70131
70166
  }
70132
70167
  }
70133
70168
 
@@ -70248,34 +70283,126 @@ function info_default6({ defineComponent }) {
70248
70283
  var import_FaSlidersH = __toESM(require_FaSlidersH());
70249
70284
 
70250
70285
  // build/client/processor.hardSourceSwitch/inline-view.js
70251
- var import_jsx_runtime8 = __toESM(require_jsx_runtime());
70252
- function InlineView4({ state }) {
70253
- return (0, import_jsx_runtime8.jsx)("div", { className: "flex flex-col h-full justify-between p-2 text-gray-900 dark:text-white", children: (0, import_jsx_runtime8.jsxs)("div", { children: [(0, import_jsx_runtime8.jsxs)("p", { className: "text-sm font-medium", children: ["Active: ", (0, import_jsx_runtime8.jsx)("span", { className: "font-normal", children: state.activeSource || "None" })] }), (0, import_jsx_runtime8.jsxs)("p", { className: "text-sm font-medium", children: ["Available: ", (0, import_jsx_runtime8.jsx)("span", { className: "font-normal", children: state.availableSources.length })] })] }) });
70286
+ var import_jsx_runtime7 = __toESM(require_jsx_runtime());
70287
+ var import_FaTimes = __toESM(require_FaTimes());
70288
+ var import_FaPlay = __toESM(require_FaPlay());
70289
+ var import_FaCircle = __toESM(require_FaCircle());
70290
+ var import_react7 = __toESM(require_react());
70291
+ function InlineView3({ state, config, sendCommand }) {
70292
+ const sourcePriority = state.sourcePriority || [];
70293
+ const handlePriorityChange = (0, import_react7.useCallback)((newOrder) => {
70294
+ sendCommand({ type: "set-priority-order", sources: newOrder });
70295
+ }, [sendCommand]);
70296
+ const availableSourceNames = state.availableSources.map((s) => s.sourceName);
70297
+ return (0, import_jsx_runtime7.jsx)("div", { className: "flex flex-col h-full justify-between p-2 text-gray-900 dark:text-white", children: (0, import_jsx_runtime7.jsxs)("div", { children: [(0, import_jsx_runtime7.jsxs)("p", { className: "text-sm font-medium", children: ["Active: ", (0, import_jsx_runtime7.jsx)("span", { className: "font-normal", children: state.activeSource || "None" })] }), (0, import_jsx_runtime7.jsxs)("p", { className: "text-sm font-medium", children: ["Available: ", (0, import_jsx_runtime7.jsx)("span", { className: "font-normal", children: state.availableSources.length })] }), sourcePriority.length > 0 && (0, import_jsx_runtime7.jsxs)("div", { className: "mt-2 space-y-2", children: [sourcePriority.map((sourceName, index3) => {
70298
+ const isActive = state.activeSource === sourceName;
70299
+ const isAvailable = availableSourceNames.includes(sourceName);
70300
+ const priorityRank = index3 + 1;
70301
+ return (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center gap-2", children: [(0, import_jsx_runtime7.jsx)("div", { className: "relative w-4 h-4 flex items-center justify-center flex-shrink-0", children: !isAvailable ? (0, import_jsx_runtime7.jsx)(import_FaTimes.FaTimes, { className: "w-4 h-4 text-red-500" }) : isActive ? (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [(0, import_jsx_runtime7.jsx)(import_FaPlay.FaPlay, { className: "w-3 h-3 text-green-500" }), (0, import_jsx_runtime7.jsx)("div", { className: "absolute inset-0 flex items-center justify-center opacity-30", children: (0, import_jsx_runtime7.jsx)("div", { className: "w-4 h-4 bg-green-500 animate-ping duration-150" }) })] }) : (0, import_jsx_runtime7.jsx)(import_FaCircle.FaCircle, { className: "w-2 h-2 text-green-500" }) }), (0, import_jsx_runtime7.jsx)("span", { className: "text-gray-900 dark:text-white flex-1 text-xs", children: sourceName }), (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center gap-1", children: [index3 > 0 && (0, import_jsx_runtime7.jsx)("button", { onClick: () => {
70302
+ const newOrder = [...sourcePriority];
70303
+ [newOrder[index3], newOrder[index3 - 1]] = [newOrder[index3 - 1], newOrder[index3]];
70304
+ handlePriorityChange(newOrder);
70305
+ }, className: "w-4 h-4 flex items-center justify-center text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200", title: "Move up", children: (0, import_jsx_runtime7.jsx)("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", strokeWidth: 2, stroke: "currentColor", className: "w-3 h-3", children: (0, import_jsx_runtime7.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4.5 15.75l7.5-7.5 7.5 7.5" }) }) }), index3 < sourcePriority.length - 1 && (0, import_jsx_runtime7.jsx)("button", { onClick: () => {
70306
+ const newOrder = [...sourcePriority];
70307
+ [newOrder[index3], newOrder[index3 + 1]] = [newOrder[index3 + 1], newOrder[index3]];
70308
+ handlePriorityChange(newOrder);
70309
+ }, className: "w-4 h-4 flex items-center justify-center text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200", title: "Move down", children: (0, import_jsx_runtime7.jsx)("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", strokeWidth: 2, stroke: "currentColor", className: "w-3 h-3", children: (0, import_jsx_runtime7.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19.5 8.25l-7.5 7.5-7.5-7.5" }) }) }), (0, import_jsx_runtime7.jsx)("span", { className: "text-gray-500 dark:text-gray-400 text-sm w-4 text-center", children: priorityRank })] })] }, sourceName);
70310
+ }), config.fallbackFilePath && (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center gap-2", children: [(0, import_jsx_runtime7.jsx)("div", { className: "relative w-4 h-4 flex items-center justify-center flex-shrink-0", children: state.activeSource === "fallback" ? (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [(0, import_jsx_runtime7.jsx)(import_FaPlay.FaPlay, { className: "w-3 h-3 text-green-500" }), (0, import_jsx_runtime7.jsx)("div", { className: "absolute inset-0 flex items-center justify-center opacity-30", children: (0, import_jsx_runtime7.jsx)("div", { className: "w-4 h-4 bg-green-500 animate-ping duration-150" }) })] }) : (0, import_jsx_runtime7.jsx)(import_FaCircle.FaCircle, { className: "w-2 h-2 text-green-500" }) }), (0, import_jsx_runtime7.jsx)("span", { className: "text-gray-900 dark:text-white flex-1 text-xs", children: "fallback" }), (0, import_jsx_runtime7.jsx)("span", { className: "text-gray-500 dark:text-gray-400 text-sm", children: "-" })] })] })] }) });
70254
70311
  }
70255
70312
 
70256
70313
  // build/client/processor.hardSourceSwitch/fullscreen.js
70257
- var import_jsx_runtime9 = __toESM(require_jsx_runtime());
70258
- var import_react7 = __toESM(require_react());
70314
+ var import_jsx_runtime8 = __toESM(require_jsx_runtime());
70315
+ var import_react8 = __toESM(require_react());
70259
70316
  function FullscreenView({ state, config: _config, sendCommand }) {
70260
- const handleSwitch = (0, import_react7.useCallback)((sourceName) => {
70317
+ const handleSwitch = (0, import_react8.useCallback)((sourceName) => {
70261
70318
  sendCommand({ type: "switch-to-source", source: sourceName });
70262
70319
  }, [sendCommand]);
70263
- return (0, import_jsx_runtime9.jsxs)("div", { className: "h-full w-full flex flex-col p-4 bg-gray-900 text-white", children: [(0, import_jsx_runtime9.jsxs)("div", { className: "flex-1 flex gap-4", children: [(0, import_jsx_runtime9.jsxs)("div", { className: "flex-1", children: [(0, import_jsx_runtime9.jsx)("h3", { className: "text-lg font-semibold mb-3", children: "Sources" }), (0, import_jsx_runtime9.jsx)("div", { className: "grid grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4", children: state.availableSources.map((source) => {
70320
+ const handlePriorityChange = (0, import_react8.useCallback)((newOrder) => {
70321
+ sendCommand({ type: "set-priority-order", sources: newOrder });
70322
+ }, [sendCommand]);
70323
+ return (0, import_jsx_runtime8.jsxs)("div", { className: "h-full w-full flex flex-col p-4 bg-gray-900 text-white", children: [(0, import_jsx_runtime8.jsxs)("div", { className: "flex-1 flex gap-4", children: [(0, import_jsx_runtime8.jsxs)("div", { className: "flex-1", children: [(0, import_jsx_runtime8.jsx)("h3", { className: "text-lg font-semibold mb-3", children: "Sources" }), (0, import_jsx_runtime8.jsx)("div", { className: "grid grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4", children: state.availableSources.map((source) => {
70264
70324
  if (!source.sourceName) {
70265
70325
  return null;
70266
70326
  }
70267
70327
  const sourceName = source.sourceName;
70268
70328
  const isActive = state.activeSource === sourceName;
70269
70329
  const previewUrl = state.sourcePreviews?.[sourceName];
70270
- return (0, import_jsx_runtime9.jsxs)("div", { className: `
70330
+ return (0, import_jsx_runtime8.jsxs)("div", { className: `
70271
70331
  relative border-2 rounded-lg overflow-hidden
70272
70332
  ${isActive ? "border-green-500" : "border-gray-600"}
70273
- `, children: [(0, import_jsx_runtime9.jsxs)("div", { className: "aspect-video bg-gray-800 relative", children: [previewUrl ? (0, import_jsx_runtime9.jsx)("img", { src: previewUrl, alt: `${sourceName} preview`, className: "w-full h-full object-cover" }) : (0, import_jsx_runtime9.jsx)("div", { className: "flex items-center justify-center h-full text-gray-500", children: "Loading..." }), isActive && (0, import_jsx_runtime9.jsx)("div", { className: "absolute top-2 right-2 bg-green-500 text-white px-2 py-1 rounded text-xs font-bold", children: "ACTIVE" })] }), (0, import_jsx_runtime9.jsxs)("div", { className: "p-3", children: [(0, import_jsx_runtime9.jsx)("h4", { className: "font-medium mb-2", children: sourceName }), (0, import_jsx_runtime9.jsx)("div", { className: "flex items-center justify-end", children: !isActive && (0, import_jsx_runtime9.jsx)("button", { onClick: () => handleSwitch(sourceName), className: "px-3 py-1 bg-blue-600 hover:bg-blue-700 rounded text-sm transition", children: "Make Active" }) })] })] }, sourceName);
70274
- }) })] }), (0, import_jsx_runtime9.jsxs)("div", { className: "w-96", children: [(0, import_jsx_runtime9.jsx)("h3", { className: "text-lg font-semibold mb-3", children: "Output" }), (0, import_jsx_runtime9.jsxs)("div", { className: "border-2 border-blue-500 rounded-lg overflow-hidden", children: [(0, import_jsx_runtime9.jsx)("div", { className: "aspect-video bg-gray-800", children: state.outputPreview ? (0, import_jsx_runtime9.jsx)("img", { src: state.outputPreview, alt: "Output preview", className: "w-full h-full object-cover" }) : (0, import_jsx_runtime9.jsx)("div", { className: "flex items-center justify-center h-full text-gray-500", children: "No output" }) }), (0, import_jsx_runtime9.jsx)("div", { className: "p-3 bg-gray-800", children: (0, import_jsx_runtime9.jsxs)("p", { className: "text-sm text-gray-400", children: ["Active Source:", " ", (0, import_jsx_runtime9.jsx)("span", { className: "font-semibold text-white", children: state.activeSource || "None" })] }) })] })] })] }), state.formatWarnings && state.formatWarnings.length > 0 && (0, import_jsx_runtime9.jsxs)("div", { className: "mt-4 bg-yellow-900/50 border border-yellow-600 rounded-lg p-3", children: [(0, import_jsx_runtime9.jsxs)("h4", { className: "text-yellow-400 font-semibold mb-2 flex items-center gap-2", children: [(0, import_jsx_runtime9.jsx)("span", { children: "\u26A0\uFE0F" }), "Format Warnings"] }), (0, import_jsx_runtime9.jsx)("div", { className: "space-y-1 max-h-32 overflow-y-auto", children: state.formatWarnings.map((warning, idx) => (0, import_jsx_runtime9.jsxs)("div", { className: "text-sm text-yellow-200", children: ["\u2022 ", warning] }, idx)) })] })] });
70333
+ `, children: [(0, import_jsx_runtime8.jsxs)("div", { className: "aspect-video bg-gray-800 relative", children: [previewUrl ? (0, import_jsx_runtime8.jsx)("img", { src: previewUrl, alt: `${sourceName} preview`, className: "w-full h-full object-cover" }) : (0, import_jsx_runtime8.jsx)("div", { className: "flex items-center justify-center h-full text-gray-500", children: "Loading..." }), isActive && (0, import_jsx_runtime8.jsx)("div", { className: "absolute top-2 right-2 bg-green-500 text-white px-2 py-1 rounded text-xs font-bold", children: "ACTIVE" })] }), (0, import_jsx_runtime8.jsxs)("div", { className: "p-3", children: [(0, import_jsx_runtime8.jsx)("h4", { className: "font-medium mb-2", children: sourceName }), (0, import_jsx_runtime8.jsx)("div", { className: "flex items-center justify-end", children: !isActive && (0, import_jsx_runtime8.jsx)("button", { onClick: () => handleSwitch(sourceName), className: "px-3 py-1 bg-blue-600 hover:bg-blue-700 rounded text-sm transition", children: "Make Active" }) })] })] }, sourceName);
70334
+ }) })] }), (0, import_jsx_runtime8.jsxs)("div", { className: "w-96 flex flex-col gap-4", children: [(0, import_jsx_runtime8.jsxs)("div", { children: [(0, import_jsx_runtime8.jsx)("h3", { className: "text-lg font-semibold mb-3", children: "Output" }), (0, import_jsx_runtime8.jsxs)("div", { className: "border-2 border-blue-500 rounded-lg overflow-hidden", children: [(0, import_jsx_runtime8.jsx)("div", { className: "aspect-video bg-gray-800", children: state.outputPreview ? (0, import_jsx_runtime8.jsx)("img", { src: state.outputPreview, alt: "Output preview", className: "w-full h-full object-cover" }) : (0, import_jsx_runtime8.jsx)("div", { className: "flex items-center justify-center h-full text-gray-500", children: "No output" }) }), (0, import_jsx_runtime8.jsx)("div", { className: "p-3 bg-gray-800", children: (0, import_jsx_runtime8.jsxs)("p", { className: "text-sm text-gray-400", children: ["Active Source:", " ", (0, import_jsx_runtime8.jsx)("span", { className: "font-semibold text-white", children: state.activeSource || "None" })] }) })] })] }), (0, import_jsx_runtime8.jsxs)("div", { children: [(0, import_jsx_runtime8.jsx)("h3", { className: "text-lg font-semibold mb-3", children: "Priority Order" }), (0, import_jsx_runtime8.jsx)("div", { className: "space-y-2", children: (state.sourcePriority || []).map((source, index3) => (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center justify-between bg-gray-800 p-2 rounded", children: [(0, import_jsx_runtime8.jsxs)("span", { className: "text-sm", children: [index3 + 1, ": ", source] }), (0, import_jsx_runtime8.jsxs)("div", { className: "flex gap-1", children: [index3 > 0 && (0, import_jsx_runtime8.jsx)("button", { onClick: () => {
70335
+ const newOrder = [...state.sourcePriority || []];
70336
+ [newOrder[index3], newOrder[index3 - 1]] = [
70337
+ newOrder[index3 - 1],
70338
+ newOrder[index3]
70339
+ ];
70340
+ handlePriorityChange(newOrder);
70341
+ }, className: "px-2 py-1 bg-gray-700 hover:bg-gray-600 rounded text-xs", title: "Move up", children: "\u2191" }), index3 < (state.sourcePriority?.length || 0) - 1 && (0, import_jsx_runtime8.jsx)("button", { onClick: () => {
70342
+ const newOrder = [...state.sourcePriority || []];
70343
+ [newOrder[index3], newOrder[index3 + 1]] = [
70344
+ newOrder[index3 + 1],
70345
+ newOrder[index3]
70346
+ ];
70347
+ handlePriorityChange(newOrder);
70348
+ }, className: "px-2 py-1 bg-gray-700 hover:bg-gray-600 rounded text-xs", title: "Move down", children: "\u2193" })] })] }, source)) })] })] })] }), state.formatWarnings && state.formatWarnings.length > 0 && (0, import_jsx_runtime8.jsxs)("div", { className: "mt-4 bg-yellow-900/50 border border-yellow-600 rounded-lg p-3", children: [(0, import_jsx_runtime8.jsxs)("h4", { className: "text-yellow-400 font-semibold mb-2 flex items-center gap-2", children: [(0, import_jsx_runtime8.jsx)("span", { children: "\u26A0\uFE0F" }), "Format Warnings"] }), (0, import_jsx_runtime8.jsx)("div", { className: "space-y-1 max-h-32 overflow-y-auto", children: state.formatWarnings.map((warning, idx) => (0, import_jsx_runtime8.jsxs)("div", { className: "text-sm text-yellow-200", children: ["\u2022 ", warning] }, idx)) })] })] });
70349
+ }
70350
+
70351
+ // build/client/processor.hardSourceSwitch/source-selection.js
70352
+ var import_jsx_runtime9 = __toESM(require_jsx_runtime());
70353
+ var import_react9 = __toESM(require_react());
70354
+ function OrderInput(props) {
70355
+ const { onChanged } = props;
70356
+ const [value, setValue] = (0, import_react9.useState)(props.defaultValue ?? []);
70357
+ (0, import_react9.useEffect)(() => {
70358
+ onChanged(value);
70359
+ }, [value, onChanged]);
70360
+ if (value.length == 0) {
70361
+ return (0, import_jsx_runtime9.jsx)("p", { className: "node-editor-helper-text", children: "Sources will appear here when subscriptions have been added to this node" });
70362
+ } else {
70363
+ return (0, import_jsx_runtime9.jsx)("div", { id: props.id, children: (0, import_jsx_runtime9.jsx)("ul", { children: value.map((v, ix2) => {
70364
+ return (0, import_jsx_runtime9.jsxs)("li", { className: "flex", children: [(0, import_jsx_runtime9.jsx)("span", { className: "node-editor-label flex-grow", children: v }), ix2 == 0 ? (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, {}) : (0, import_jsx_runtime9.jsx)("svg", { onClick: moveUp(ix2), xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", strokeWidth: 1.5, className: "w-4 h-6 shrink cursor-pointer stroke-gray-700 dark:stroke-gray-50", children: (0, import_jsx_runtime9.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8.25 6.75L12 3m0 0l3.75 3.75M12 3v18" }) }), ix2 == value.length - 1 ? (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, {}) : (0, import_jsx_runtime9.jsx)("svg", { onClick: moveDown(ix2), xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", strokeWidth: 1.5, className: "w-4 h-6 shrink cursor-pointer stroke-gray-700 dark:stroke-gray-50", children: (0, import_jsx_runtime9.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15.75 17.25L12 21m0 0l-3.75-3.75M12 21V3" }) })] }, v);
70365
+ }) }) });
70366
+ }
70367
+ function moveUp(ix2) {
70368
+ return () => {
70369
+ const nv2 = [...value];
70370
+ nv2[ix2] = value[ix2 - 1];
70371
+ nv2[ix2 - 1] = value[ix2];
70372
+ setValue(nv2);
70373
+ };
70374
+ }
70375
+ function moveDown(ix2) {
70376
+ return () => {
70377
+ const nv2 = [...value];
70378
+ nv2[ix2 + 1] = value[ix2];
70379
+ nv2[ix2] = value[ix2 + 1];
70380
+ setValue(nv2);
70381
+ };
70382
+ }
70275
70383
  }
70384
+ var source_selection_default = OrderInput;
70276
70385
 
70277
70386
  // build/client/processor.hardSourceSwitch/info.js
70278
70387
  function info_default7({ defineComponent, Av: Av2, validation: { Z: Z3, SourceName } }) {
70388
+ function configFromSubscription(cfg, sub) {
70389
+ if (!cfg.sourcePriority) {
70390
+ cfg.sourcePriority = [];
70391
+ }
70392
+ const potentiallyNewSources = sub.expectedStreams.map((s) => s.sourceName).filter((s) => !!s);
70393
+ potentiallyNewSources.forEach((s) => {
70394
+ if (!cfg.sourcePriority.includes(s)) {
70395
+ cfg.sourcePriority.push(s);
70396
+ }
70397
+ });
70398
+ }
70399
+ function missingSubscriptions(config, subscriptions) {
70400
+ if (!config.sourcePriority) {
70401
+ config.sourcePriority = [];
70402
+ }
70403
+ const allSourceNames = subscriptions.flatMap((s) => s.expectedStreams).map((s) => s.sourceName).filter((s) => !!s);
70404
+ config.sourcePriority = config.sourcePriority.filter((s) => allSourceNames.includes(s));
70405
+ }
70279
70406
  return defineComponent({
70280
70407
  identifier: "processor.hardSourceSwitch",
70281
70408
  category: "processor",
@@ -70311,15 +70438,35 @@ function info_default7({ defineComponent, Av: Av2, validation: { Z: Z3, SourceNa
70311
70438
  display: (desc) => {
70312
70439
  return {
70313
70440
  activeSource: desc.config.activeSource || "(auto)",
70314
- outputSource: desc.config.outputSource
70441
+ outputSource: desc.config.outputSource,
70442
+ fallback: desc.config.fallbackFilePath ? "MP4 File" : "None"
70315
70443
  };
70316
70444
  },
70445
+ designtime: {
70446
+ uiEvents: {
70447
+ onSubscriptionAdded: function(sub) {
70448
+ configFromSubscription(this.config, sub);
70449
+ },
70450
+ onSubscriptionRemoved: function() {
70451
+ missingSubscriptions(this.config, this.subscriptions);
70452
+ },
70453
+ onNodeUpdated: function() {
70454
+ this.subscriptions.forEach((s) => configFromSubscription(this.config, s));
70455
+ missingSubscriptions(this.config, this.subscriptions);
70456
+ },
70457
+ onSubscriptionUpdated: function(sub) {
70458
+ configFromSubscription(this.config, sub);
70459
+ missingSubscriptions(this.config, this.subscriptions);
70460
+ }
70461
+ }
70462
+ },
70317
70463
  runtime: {
70318
70464
  initialState: () => ({
70319
70465
  activeSource: "",
70320
70466
  availableSources: [],
70321
70467
  sourcePreviews: {},
70322
- formatWarnings: []
70468
+ formatWarnings: [],
70469
+ sourcePriority: []
70323
70470
  }),
70324
70471
  handleEvent: (ev2, state) => {
70325
70472
  const evType = ev2.type;
@@ -70358,6 +70505,8 @@ function info_default7({ defineComponent, Av: Av2, validation: { Z: Z3, SourceNa
70358
70505
  const newWarnings = [ev2.message, ...currentWarnings].slice(0, 10);
70359
70506
  return { ...state, formatWarnings: newWarnings };
70360
70507
  }
70508
+ case "priority-order-changed":
70509
+ return { ...state, sourcePriority: ev2.sourcePriority };
70361
70510
  case "error":
70362
70511
  case "automatic-failover":
70363
70512
  return state;
@@ -70365,8 +70514,8 @@ function info_default7({ defineComponent, Av: Av2, validation: { Z: Z3, SourceNa
70365
70514
  assertUnreachable3(evType);
70366
70515
  }
70367
70516
  },
70368
- inline: InlineView4,
70369
- summary: InlineView4,
70517
+ inline: InlineView3,
70518
+ summary: InlineView3,
70370
70519
  fullscreen: FullscreenView
70371
70520
  },
70372
70521
  extraValidation: function(ctx) {
@@ -70417,6 +70566,23 @@ function info_default7({ defineComponent, Av: Av2, validation: { Z: Z3, SourceNa
70417
70566
  optional: true
70418
70567
  }
70419
70568
  },
70569
+ fallbackFilePath: {
70570
+ help: "Optional MP4 file to use as fallback",
70571
+ advanced: true,
70572
+ hint: {
70573
+ type: "text",
70574
+ optional: true,
70575
+ envOverride: true
70576
+ }
70577
+ },
70578
+ sourcePriority: {
70579
+ help: "The priority order in which the sources will be chosen when available",
70580
+ hint: {
70581
+ type: "custom",
70582
+ component: source_selection_default,
70583
+ defaultValue: []
70584
+ }
70585
+ },
70420
70586
  notes: {
70421
70587
  help: "Optional notes",
70422
70588
  hint: {
@@ -70478,9 +70644,9 @@ function info_default8({ defineComponent, validation: { Z: Z3 } }) {
70478
70644
 
70479
70645
  // build/client/util.agent/summary-view.js
70480
70646
  var import_jsx_runtime10 = __toESM(require_jsx_runtime());
70481
- var import_react8 = __toESM(require_react());
70647
+ var import_react10 = __toESM(require_react());
70482
70648
  function SummaryView4({ state, config, sendCommand }) {
70483
- const [showDetailedActions, setShowDetailedActions] = (0, import_react8.useState)(false);
70649
+ const [showDetailedActions, setShowDetailedActions] = (0, import_react10.useState)(false);
70484
70650
  const getStatusColor = (status, isRunning) => {
70485
70651
  if (!isRunning)
70486
70652
  return "text-gray-500 dark:text-gray-400";
@@ -70552,7 +70718,7 @@ var summary_view_default3 = SummaryView4;
70552
70718
 
70553
70719
  // build/client/util.agent/inline-view.js
70554
70720
  var import_jsx_runtime11 = __toESM(require_jsx_runtime());
70555
- function InlineView5({ state, config }) {
70721
+ function InlineView4({ state, config }) {
70556
70722
  const recentDecision = state.recentActions.find((action) => {
70557
70723
  if (action.type === "analysis" && action.result && typeof action.result === "object") {
70558
70724
  const result = action.result;
@@ -70598,16 +70764,16 @@ function InlineView5({ state, config }) {
70598
70764
  };
70599
70765
  return (0, import_jsx_runtime11.jsx)("div", { id: `agent-${config.id}`, className: "p-3 space-y-2", children: (0, import_jsx_runtime11.jsxs)("div", { className: "w-80 grid grid-cols-[min-content,1fr] gap-x-3 gap-y-1 text-sm", children: [(0, import_jsx_runtime11.jsx)("div", { className: "font-medium", children: "Status:" }), (0, import_jsx_runtime11.jsxs)("div", { className: `flex items-center gap-2 ${getStatusColor(state.status, state.isRunning)}`, children: [(0, import_jsx_runtime11.jsx)("span", { children: getStatusIcon(state.status, state.isRunning) }), (0, import_jsx_runtime11.jsx)("span", { className: "capitalize", children: state.isRunning ? state.status : "stopped" })] }), (0, import_jsx_runtime11.jsx)("div", { className: "font-medium", children: "Cycles:" }), (0, import_jsx_runtime11.jsxs)("div", { className: "text-slate-700 dark:text-slate-300", children: [state.cyclesThisMinute, "/min \u2022 ", state.totalCycles, " total"] }), (0, import_jsx_runtime11.jsx)("div", { className: "font-medium", children: "Goal:" }), (0, import_jsx_runtime11.jsx)("div", { className: "text-slate-700 dark:text-slate-300 truncate", title: config.goal, children: config.goal }), recentDecision && (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [(0, import_jsx_runtime11.jsx)("div", { className: "font-medium", children: "Recent:" }), (0, import_jsx_runtime11.jsx)("div", { className: "text-slate-700 dark:text-slate-300 truncate", title: recentDecision.result && typeof recentDecision.result === "object" ? recentDecision.result.structured_response?.decision : recentDecision.description, children: recentDecision.result && typeof recentDecision.result === "object" ? recentDecision.result.structured_response?.decision : recentDecision.description })] }), (0, import_jsx_runtime11.jsx)("div", { className: "font-medium", children: "Components:" }), (0, import_jsx_runtime11.jsxs)("div", { className: "text-slate-700 dark:text-slate-300", children: [state.discoveredComponents.length, " discovered"] }), state.lastError && (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [(0, import_jsx_runtime11.jsx)("div", { className: "font-medium text-red-600", children: "Error:" }), (0, import_jsx_runtime11.jsx)("div", { className: "text-red-600 dark:text-red-400 truncate text-xs", title: state.lastError, children: state.lastError })] })] }) });
70600
70766
  }
70601
- var inline_view_default4 = InlineView5;
70767
+ var inline_view_default3 = InlineView4;
70602
70768
 
70603
70769
  // build/client/util.agent/fullscreen-view.js
70604
70770
  var import_jsx_runtime12 = __toESM(require_jsx_runtime());
70605
70771
  var React2 = __toESM(require_react());
70606
- var import_react9 = __toESM(require_react());
70772
+ var import_react11 = __toESM(require_react());
70607
70773
  function FullscreenView2({ state, config, sendCommand, urls }) {
70608
- const [memoryData, setMemoryData] = (0, import_react9.useState)({});
70609
- const [loading, setLoading] = (0, import_react9.useState)(false);
70610
- const [activeTab, setActiveTab] = (0, import_react9.useState)("status");
70774
+ const [memoryData, setMemoryData] = (0, import_react11.useState)({});
70775
+ const [loading, setLoading] = (0, import_react11.useState)(false);
70776
+ const [activeTab, setActiveTab] = (0, import_react11.useState)("status");
70611
70777
  const fetchMemoryData = async () => {
70612
70778
  setLoading(true);
70613
70779
  try {
@@ -70716,7 +70882,7 @@ function info_default9({ defineComponent, validation: { Z: Z3 } }) {
70716
70882
  },
70717
70883
  runtime: {
70718
70884
  summary: summary_view_default3,
70719
- inline: inline_view_default4,
70885
+ inline: inline_view_default3,
70720
70886
  fullscreen: fullscreen_view_default,
70721
70887
  initialState: () => ({
70722
70888
  status: "analyzing",
@@ -70840,16 +71006,16 @@ function assertUnreachable4(_) {
70840
71006
 
70841
71007
  // build/client/util.aiChat/summary-view.js
70842
71008
  var import_jsx_runtime13 = __toESM(require_jsx_runtime());
70843
- var import_react10 = __toESM(require_react());
71009
+ var import_react12 = __toESM(require_react());
70844
71010
  function SummaryView5({ state, config: _config, sendCommand }) {
70845
- const [inputMessage, setInputMessage] = (0, import_react10.useState)("");
70846
- const [isSubmitting, setIsSubmitting] = (0, import_react10.useState)(false);
70847
- const messagesEndRef = (0, import_react10.useRef)(null);
70848
- const inputRef = (0, import_react10.useRef)(null);
70849
- (0, import_react10.useEffect)(() => {
71011
+ const [inputMessage, setInputMessage] = (0, import_react12.useState)("");
71012
+ const [isSubmitting, setIsSubmitting] = (0, import_react12.useState)(false);
71013
+ const messagesEndRef = (0, import_react12.useRef)(null);
71014
+ const inputRef = (0, import_react12.useRef)(null);
71015
+ (0, import_react12.useEffect)(() => {
70850
71016
  messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
70851
71017
  }, [state.messages]);
70852
- (0, import_react10.useEffect)(() => {
71018
+ (0, import_react12.useEffect)(() => {
70853
71019
  inputRef.current?.focus();
70854
71020
  }, []);
70855
71021
  const handleSendMessage = () => {
@@ -70975,7 +71141,7 @@ function assertUnreachable5(_) {
70975
71141
 
70976
71142
  // build/client/util.timestamps/inline-view.js
70977
71143
  var import_jsx_runtime14 = __toESM(require_jsx_runtime());
70978
- var import_react11 = __toESM(require_react());
71144
+ var import_react13 = __toESM(require_react());
70979
71145
 
70980
71146
  // ../../node_modules/@kurkle/color/dist/color.esm.js
70981
71147
  function round2(v) {
@@ -85448,10 +85614,10 @@ Chart.register(...registerables);
85448
85614
  var auto_default = Chart;
85449
85615
 
85450
85616
  // build/client/util.timestamps/inline-view.js
85451
- function InlineView6({ state, config: _2 }) {
85452
- const chartContainer = (0, import_react11.useRef)(null);
85453
- const [chartControl, setChartControl] = (0, import_react11.useState)(void 0);
85454
- (0, import_react11.useEffect)(() => {
85617
+ function InlineView5({ state, config: _2 }) {
85618
+ const chartContainer = (0, import_react13.useRef)(null);
85619
+ const [chartControl, setChartControl] = (0, import_react13.useState)(void 0);
85620
+ (0, import_react13.useEffect)(() => {
85455
85621
  if (!chartContainer.current)
85456
85622
  return;
85457
85623
  if (state.timestamps.length < 2)
@@ -85513,7 +85679,7 @@ function InlineView6({ state, config: _2 }) {
85513
85679
  chart.update();
85514
85680
  }, 100);
85515
85681
  }, [chartContainer]);
85516
- (0, import_react11.useEffect)(() => {
85682
+ (0, import_react13.useEffect)(() => {
85517
85683
  if (!chartControl)
85518
85684
  return;
85519
85685
  chartControl.data = {
@@ -85540,7 +85706,7 @@ function InlineView6({ state, config: _2 }) {
85540
85706
  }
85541
85707
  return (0, import_jsx_runtime14.jsx)("div", { className: "util-timestamp", children: (0, import_jsx_runtime14.jsx)("div", { className: "bg-gray-50 dark:bg-gray-700 rounded", style: { width: "360px", height: "200px", padding: "10px" }, children: (0, import_jsx_runtime14.jsx)("canvas", { className: "bg-gray-50 dark:bg-gray-700 rounded", ref: chartContainer }) }) });
85542
85708
  }
85543
- var inline_view_default5 = InlineView6;
85709
+ var inline_view_default4 = InlineView5;
85544
85710
 
85545
85711
  // build/client/util.timestamps/info.js
85546
85712
  function info_default11(R) {
@@ -85585,7 +85751,7 @@ function info_default11(R) {
85585
85751
  }
85586
85752
  return { ...state };
85587
85753
  },
85588
- inline: inline_view_default5
85754
+ inline: inline_view_default4
85589
85755
  },
85590
85756
  configForm: {
85591
85757
  form: {}