@norskvideo/norsk-studio 1.0.0

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 (263) hide show
  1. package/README.md +58 -0
  2. package/bin/info.ts.template +23 -0
  3. package/bin/studio-bundle +23 -0
  4. package/bin/studio-editor +3 -0
  5. package/bin/studio-runner +3 -0
  6. package/bin/studio-wrap-infos +44 -0
  7. package/lib/client/comms.d.ts +26 -0
  8. package/lib/client/comms.js +114 -0
  9. package/lib/client/comms.js.map +1 -0
  10. package/lib/client/componentevents.d.ts +12 -0
  11. package/lib/client/componentevents.js +41 -0
  12. package/lib/client/componentevents.js.map +1 -0
  13. package/lib/client/console.d.ts +19 -0
  14. package/lib/client/console.js +42 -0
  15. package/lib/client/console.js.map +1 -0
  16. package/lib/client/controls.d.ts +23 -0
  17. package/lib/client/controls.js +80 -0
  18. package/lib/client/controls.js.map +1 -0
  19. package/lib/client/creator.d.ts +45 -0
  20. package/lib/client/creator.js +276 -0
  21. package/lib/client/creator.js.map +1 -0
  22. package/lib/client/jsx/connection-editor.d.ts +11 -0
  23. package/lib/client/jsx/connection-editor.js +198 -0
  24. package/lib/client/jsx/connection-editor.js.map +1 -0
  25. package/lib/client/jsx/connection.d.ts +7 -0
  26. package/lib/client/jsx/connection.js +33 -0
  27. package/lib/client/jsx/connection.js.map +1 -0
  28. package/lib/client/jsx/console-log.d.ts +11 -0
  29. package/lib/client/jsx/console-log.js +17 -0
  30. package/lib/client/jsx/console-log.js.map +1 -0
  31. package/lib/client/jsx/console.d.ts +20 -0
  32. package/lib/client/jsx/console.js +30 -0
  33. package/lib/client/jsx/console.js.map +1 -0
  34. package/lib/client/jsx/node-editor.d.ts +23 -0
  35. package/lib/client/jsx/node-editor.js +442 -0
  36. package/lib/client/jsx/node-editor.js.map +1 -0
  37. package/lib/client/jsx/node.d.ts +25 -0
  38. package/lib/client/jsx/node.js +244 -0
  39. package/lib/client/jsx/node.js.map +1 -0
  40. package/lib/client/jsx/selected-connection.d.ts +21 -0
  41. package/lib/client/jsx/selected-connection.js +110 -0
  42. package/lib/client/jsx/selected-connection.js.map +1 -0
  43. package/lib/client/jsx/selected-node.d.ts +24 -0
  44. package/lib/client/jsx/selected-node.js +75 -0
  45. package/lib/client/jsx/selected-node.js.map +1 -0
  46. package/lib/client/jsx/selected.d.ts +24 -0
  47. package/lib/client/jsx/selected.js +15 -0
  48. package/lib/client/jsx/selected.js.map +1 -0
  49. package/lib/client/jsx/selectfilename.d.ts +7 -0
  50. package/lib/client/jsx/selectfilename.js +17 -0
  51. package/lib/client/jsx/selectfilename.js.map +1 -0
  52. package/lib/client/jsx/toolbox.d.ts +14 -0
  53. package/lib/client/jsx/toolbox.js +45 -0
  54. package/lib/client/jsx/toolbox.js.map +1 -0
  55. package/lib/client/library.d.ts +12 -0
  56. package/lib/client/library.js +53 -0
  57. package/lib/client/library.js.map +1 -0
  58. package/lib/client/modal.d.ts +21 -0
  59. package/lib/client/modal.js +34 -0
  60. package/lib/client/modal.js.map +1 -0
  61. package/lib/client/rete/connection.d.ts +20 -0
  62. package/lib/client/rete/connection.js +27 -0
  63. package/lib/client/rete/connection.js.map +1 -0
  64. package/lib/client/rete/node.d.ts +28 -0
  65. package/lib/client/rete/node.js +78 -0
  66. package/lib/client/rete/node.js.map +1 -0
  67. package/lib/client/rete/selector.d.ts +10 -0
  68. package/lib/client/rete/selector.js +22 -0
  69. package/lib/client/rete/selector.js.map +1 -0
  70. package/lib/client/rete.d.ts +81 -0
  71. package/lib/client/rete.js +384 -0
  72. package/lib/client/rete.js.map +1 -0
  73. package/lib/client/session-view.d.ts +7 -0
  74. package/lib/client/session-view.js +132 -0
  75. package/lib/client/session-view.js.map +1 -0
  76. package/lib/client/session.d.ts +70 -0
  77. package/lib/client/session.js +185 -0
  78. package/lib/client/session.js.map +1 -0
  79. package/lib/client/tools.d.ts +22 -0
  80. package/lib/client/tools.js +311 -0
  81. package/lib/client/tools.js.map +1 -0
  82. package/lib/extension/base-nodes.d.ts +55 -0
  83. package/lib/extension/base-nodes.js +120 -0
  84. package/lib/extension/base-nodes.js.map +1 -0
  85. package/lib/extension/built-ins.d.ts +4 -0
  86. package/lib/extension/built-ins.js +52 -0
  87. package/lib/extension/built-ins.js.map +1 -0
  88. package/lib/extension/client-system.d.ts +5 -0
  89. package/lib/extension/client-system.js +3 -0
  90. package/lib/extension/client-system.js.map +1 -0
  91. package/lib/extension/client-types.d.ts +245 -0
  92. package/lib/extension/client-types.js +87 -0
  93. package/lib/extension/client-types.js.map +1 -0
  94. package/lib/extension/common.d.ts +34 -0
  95. package/lib/extension/common.js +45 -0
  96. package/lib/extension/common.js.map +1 -0
  97. package/lib/extension/registration.d.ts +7 -0
  98. package/lib/extension/registration.js +62 -0
  99. package/lib/extension/registration.js.map +1 -0
  100. package/lib/extension/runtime-system.d.ts +9 -0
  101. package/lib/extension/runtime-system.js +3 -0
  102. package/lib/extension/runtime-system.js.map +1 -0
  103. package/lib/extension/runtime-types.d.ts +91 -0
  104. package/lib/extension/runtime-types.js +318 -0
  105. package/lib/extension/runtime-types.js.map +1 -0
  106. package/lib/extension/validation.d.ts +16 -0
  107. package/lib/extension/validation.js +50 -0
  108. package/lib/extension/validation.js.map +1 -0
  109. package/lib/library/test.d.ts +2 -0
  110. package/lib/library/test.js +11 -0
  111. package/lib/library/test.js.map +1 -0
  112. package/lib/runtime/document.d.ts +62 -0
  113. package/lib/runtime/document.js +322 -0
  114. package/lib/runtime/document.js.map +1 -0
  115. package/lib/runtime/execution.d.ts +48 -0
  116. package/lib/runtime/execution.js +327 -0
  117. package/lib/runtime/execution.js.map +1 -0
  118. package/lib/runtime/norsk-comms.d.ts +24 -0
  119. package/lib/runtime/norsk-comms.js +71 -0
  120. package/lib/runtime/norsk-comms.js.map +1 -0
  121. package/lib/runtime/system.d.ts +30 -0
  122. package/lib/runtime/system.js +83 -0
  123. package/lib/runtime/system.js.map +1 -0
  124. package/lib/server/config.d.ts +19 -0
  125. package/lib/server/config.js +26 -0
  126. package/lib/server/config.js.map +1 -0
  127. package/lib/server/index.d.ts +1 -0
  128. package/lib/server/index.js +310 -0
  129. package/lib/server/index.js.map +1 -0
  130. package/lib/server/logging.d.ts +6 -0
  131. package/lib/server/logging.js +96 -0
  132. package/lib/server/logging.js.map +1 -0
  133. package/lib/server/medialive.d.ts +1 -0
  134. package/lib/server/medialive.js +34 -0
  135. package/lib/server/medialive.js.map +1 -0
  136. package/lib/server/runner.d.ts +1 -0
  137. package/lib/server/runner.js +137 -0
  138. package/lib/server/runner.js.map +1 -0
  139. package/lib/server/session-registration.d.ts +5 -0
  140. package/lib/server/session-registration.js +18 -0
  141. package/lib/server/session-registration.js.map +1 -0
  142. package/lib/server/session.d.ts +117 -0
  143. package/lib/server/session.js +364 -0
  144. package/lib/server/session.js.map +1 -0
  145. package/lib/shared/client-msg.d.ts +13 -0
  146. package/lib/shared/client-msg.js +3 -0
  147. package/lib/shared/client-msg.js.map +1 -0
  148. package/lib/shared/config.d.ts +7 -0
  149. package/lib/shared/config.js +60 -0
  150. package/lib/shared/config.js.map +1 -0
  151. package/lib/shared/document.d.ts +164 -0
  152. package/lib/shared/document.js +496 -0
  153. package/lib/shared/document.js.map +1 -0
  154. package/lib/shared/names.d.ts +3 -0
  155. package/lib/shared/names.js +8 -0
  156. package/lib/shared/names.js.map +1 -0
  157. package/lib/shared/norsk.d.ts +21 -0
  158. package/lib/shared/norsk.js +3 -0
  159. package/lib/shared/norsk.js.map +1 -0
  160. package/lib/shared/server-msg.d.ts +69 -0
  161. package/lib/shared/server-msg.js +3 -0
  162. package/lib/shared/server-msg.js.map +1 -0
  163. package/lib/shared/util.d.ts +7 -0
  164. package/lib/shared/util.js +63 -0
  165. package/lib/shared/util.js.map +1 -0
  166. package/lib/test/_util/builder.d.ts +46 -0
  167. package/lib/test/_util/builder.js +200 -0
  168. package/lib/test/_util/builder.js.map +1 -0
  169. package/lib/test/_util/callback_app.d.ts +13 -0
  170. package/lib/test/_util/callback_app.js +25 -0
  171. package/lib/test/_util/callback_app.js.map +1 -0
  172. package/lib/test/_util/driver.d.ts +16 -0
  173. package/lib/test/_util/driver.js +89 -0
  174. package/lib/test/_util/driver.js.map +1 -0
  175. package/lib/test/_util/fake-norsk.d.ts +14 -0
  176. package/lib/test/_util/fake-norsk.js +19 -0
  177. package/lib/test/_util/fake-norsk.js.map +1 -0
  178. package/lib/test/_util/ffmpeg.d.ts +80 -0
  179. package/lib/test/_util/ffmpeg.js +266 -0
  180. package/lib/test/_util/ffmpeg.js.map +1 -0
  181. package/lib/test/_util/manual-driver.d.ts +42 -0
  182. package/lib/test/_util/manual-driver.js +206 -0
  183. package/lib/test/_util/manual-driver.js.map +1 -0
  184. package/lib/test/_util/runtime.d.ts +81 -0
  185. package/lib/test/_util/runtime.js +194 -0
  186. package/lib/test/_util/runtime.js.map +1 -0
  187. package/lib/test/_util/server.d.ts +8 -0
  188. package/lib/test/_util/server.js +33 -0
  189. package/lib/test/_util/server.js.map +1 -0
  190. package/lib/test/_util/sinks.d.ts +35 -0
  191. package/lib/test/_util/sinks.js +200 -0
  192. package/lib/test/_util/sinks.js.map +1 -0
  193. package/lib/test/_util/sources.d.ts +18 -0
  194. package/lib/test/_util/sources.js +113 -0
  195. package/lib/test/_util/sources.js.map +1 -0
  196. package/lib/test/_util/test-infos-views.d.ts +9 -0
  197. package/lib/test/_util/test-infos-views.js +46 -0
  198. package/lib/test/_util/test-infos-views.js.map +1 -0
  199. package/lib/test/_util/test-infos.d.ts +44 -0
  200. package/lib/test/_util/test-infos.js +202 -0
  201. package/lib/test/_util/test-infos.js.map +1 -0
  202. package/lib/test/client-designview.d.ts +1 -0
  203. package/lib/test/client-designview.js +258 -0
  204. package/lib/test/client-designview.js.map +1 -0
  205. package/lib/test/client-liveview.d.ts +1 -0
  206. package/lib/test/client-liveview.js +413 -0
  207. package/lib/test/client-liveview.js.map +1 -0
  208. package/lib/test/client-session.d.ts +1 -0
  209. package/lib/test/client-session.js +205 -0
  210. package/lib/test/client-session.js.map +1 -0
  211. package/lib/test/client-ui.d.ts +1 -0
  212. package/lib/test/client-ui.js +74 -0
  213. package/lib/test/client-ui.js.map +1 -0
  214. package/lib/test/document-execution.d.ts +1 -0
  215. package/lib/test/document-execution.js +162 -0
  216. package/lib/test/document-execution.js.map +1 -0
  217. package/lib/test/document-loading.d.ts +1 -0
  218. package/lib/test/document-loading.js +420 -0
  219. package/lib/test/document-loading.js.map +1 -0
  220. package/lib/test/runtime-comms.d.ts +1 -0
  221. package/lib/test/runtime-comms.js +321 -0
  222. package/lib/test/runtime-comms.js.map +1 -0
  223. package/lib/test/subscriptions.d.ts +1 -0
  224. package/lib/test/subscriptions.js +334 -0
  225. package/lib/test/subscriptions.js.map +1 -0
  226. package/package.json +112 -0
  227. package/static/98_slides.html +61 -0
  228. package/static/Norsk-Favicon-150x150.png +0 -0
  229. package/static/Norsk-Favicon.png +0 -0
  230. package/static/Norsk-Logo-Dark-Background.png +0 -0
  231. package/static/Norsk.png +0 -0
  232. package/static/ShortStack.woff2 +0 -0
  233. package/static/bonnie-green.png +0 -0
  234. package/static/button.svg +67 -0
  235. package/static/doodle.css +174 -0
  236. package/static/flowbite.min.css +1 -0
  237. package/static/flowbite.min.js +2 -0
  238. package/static/font.css +20 -0
  239. package/static/jese-leos.png +0 -0
  240. package/static/joseph-mcfall.png +0 -0
  241. package/static/michael-gough.png +0 -0
  242. package/static/news-embedded.html +106 -0
  243. package/static/overlay-score.html +210 -0
  244. package/static/overlay-ui.html +918 -0
  245. package/static/react-dom.development.js +29869 -0
  246. package/static/react.development.js +3342 -0
  247. package/static/robert-brown.png +0 -0
  248. package/static/roberta-casas.png +0 -0
  249. package/static/style-dark.css +2467 -0
  250. package/static/style.css +7252 -0
  251. package/static/tailwind.css +31 -0
  252. package/static/team1.png +0 -0
  253. package/static/team2.png +0 -0
  254. package/static/videoFrame.html +73 -0
  255. package/static/webrtc.js +430 -0
  256. package/tailwind-theme.js +66 -0
  257. package/tailwind.config.js +11 -0
  258. package/ui/bypass-esbuild.js +24 -0
  259. package/ui/index.html +189 -0
  260. package/ui/index.js +229180 -0
  261. package/ui/studio.css +31 -0
  262. package/ui/test.html +95 -0
  263. package/ui/view.html +23 -0
@@ -0,0 +1,164 @@
1
+ import Library from "../client/library";
2
+ import EventHandler from "eventhandler";
3
+ import type { BaseConfig, GlobalValidation, Media, NodeInfo, SubscriptionAcceptInfo, SubscriptionProduceInfo } from "../extension/client-types";
4
+ export type NodeDescriptionId = string;
5
+ export type CompileIssueContext = {
6
+ nodeId?: string;
7
+ subscriptionSourceId?: string;
8
+ } & {
9
+ [k: string]: unknown;
10
+ };
11
+ export type CompileIssue = {
12
+ message: string;
13
+ context: CompileIssueContext;
14
+ };
15
+ export type CompileWarning = CompileIssue;
16
+ export type CompileError = CompileIssue;
17
+ export type NodeEvent = {
18
+ id: string;
19
+ node: NodeDescription<BaseConfig>;
20
+ };
21
+ export type SubscriptionEvent = {
22
+ subscription: NodeSubscriptionDescription<BaseConfig>;
23
+ destination: NodeDescription<BaseConfig>;
24
+ source: NodeDescription<BaseConfig>;
25
+ };
26
+ export type NodeEventHandler = (e: NodeEvent) => void;
27
+ export type SubscriptionEventHandler = (e: SubscriptionEvent) => void;
28
+ export interface TopLevelContext {
29
+ addWarning: (warning: CompileWarning, ctx?: CompileIssueContext) => void;
30
+ addError: (error: CompileError, ctx?: CompileIssueContext) => void;
31
+ }
32
+ export declare class DefaultNodeValidationContext implements NodeValidationContext<BaseConfig> {
33
+ top: TopLevelContext;
34
+ document: DocumentDescription;
35
+ node: NodeDescription<BaseConfig>;
36
+ get config(): BaseConfig;
37
+ get subscriptions(): NodeSubscriptionDescription<BaseConfig>[];
38
+ constructor(top: TopLevelContext, node: NodeDescription<BaseConfig>, document: DocumentDescription);
39
+ videoInputs(): NodeSubscriptionDescription<BaseConfig>[];
40
+ audioInputs(): NodeSubscriptionDescription<BaseConfig>[];
41
+ requireVideo(count: number): void;
42
+ requireAudio(count: number): void;
43
+ run(): void;
44
+ runDefaultSubscriptionValidation(): void;
45
+ addWarning(message: string, ctx?: CompileIssueContext): void;
46
+ addError(message: string, ctx?: CompileIssueContext): void;
47
+ }
48
+ export declare function runGlobalValidationForRow(globalRule: GlobalValidation<BaseConfig>, currentValue: unknown | unknown[], node: NodeDescription<BaseConfig>, top: DocumentDescription): boolean | undefined;
49
+ export interface NodeValidationContext<Config extends BaseConfig> {
50
+ config: Config;
51
+ subscriptions: NodeSubscriptionDescription<Config>[];
52
+ document: DocumentDescription;
53
+ runDefaultSubscriptionValidation: () => void;
54
+ addWarning: (message: string) => void;
55
+ addError: (message: string) => void;
56
+ videoInputs(): NodeSubscriptionDescription<Config>[];
57
+ audioInputs(): NodeSubscriptionDescription<Config>[];
58
+ requireVideo(count: number): void;
59
+ requireAudio(count: number): void;
60
+ }
61
+ export declare class DocumentDescription {
62
+ nodes: {
63
+ [key: NodeDescriptionId]: NodeDescription<BaseConfig>;
64
+ };
65
+ errors: CompileError[];
66
+ warnings: CompileWarning[];
67
+ layout?: {
68
+ [id: string]: {
69
+ x: number;
70
+ y: number;
71
+ };
72
+ };
73
+ globalConfig?: {
74
+ [key: PropertyKey]: unknown;
75
+ };
76
+ library: Library;
77
+ events: EventHandler;
78
+ constructor(library: Library, yaml?: YamlDocument);
79
+ forEachNode(f: (n: NodeDescription<BaseConfig>) => void): void;
80
+ addNode(type: string): NodeDescription<BaseConfig>;
81
+ removeNode(id: string): void;
82
+ findNode(id: string): NodeDescription<BaseConfig> | undefined;
83
+ getNode(id: string): NodeDescription<BaseConfig>;
84
+ toYaml(): YamlDocument;
85
+ onNodeRemoved(h: NodeEventHandler): void;
86
+ onNodeAdded(h: NodeEventHandler): void;
87
+ onNodeUpdated(h: NodeEventHandler): void;
88
+ onSubscriptionAdded(h: SubscriptionEventHandler): void;
89
+ onSubscriptionUpdated(h: SubscriptionEventHandler): void;
90
+ onSubscriptionRemoved(h: SubscriptionEventHandler): void;
91
+ handleNodeUpdate({ id, node }: {
92
+ id: string;
93
+ node: NodeDescription<BaseConfig>;
94
+ }): void;
95
+ handleNodeRemoved(_: NodeEvent): void;
96
+ }
97
+ export declare class NodeDescription<Config extends BaseConfig> {
98
+ get id(): NodeDescriptionId;
99
+ get type(): string;
100
+ get config(): Config;
101
+ set id(id: NodeDescriptionId);
102
+ set config(cfg: Config);
103
+ info: NodeInfo<Config>;
104
+ yaml: YamlNode;
105
+ subscribers: NodeDescriptionId[];
106
+ subscriptions: NodeSubscriptionDescription<Config>[];
107
+ document: DocumentDescription;
108
+ toYaml(): YamlNode;
109
+ constructor(document: DocumentDescription, yaml: YamlNode, info: NodeInfo<Config>);
110
+ removeSubscription(sourceId: string): void;
111
+ addSubscription<SConfig extends BaseConfig>(source: NodeDescription<SConfig>): void;
112
+ }
113
+ export declare class NodeSubscriptionDescription<Config extends BaseConfig> {
114
+ get source(): NodeDescriptionId;
115
+ set source(id: NodeDescriptionId);
116
+ get streams(): SubscriptionConfiguration;
117
+ set streams(config: SubscriptionConfiguration);
118
+ yaml: YamlSubscription;
119
+ node: NodeDescription<Config>;
120
+ document: DocumentDescription;
121
+ constructor(document: DocumentDescription, node: NodeDescription<Config>, yaml: YamlSubscription);
122
+ }
123
+ export type SubscriptionConfiguration = {
124
+ type: 'take-first-stream';
125
+ select: Media[];
126
+ } | {
127
+ type: 'take-all-streams';
128
+ select: Media[];
129
+ } | {
130
+ type: 'take-specific-streams';
131
+ select: Media[];
132
+ filter: string[];
133
+ } | {
134
+ type: 'take-specific-stream';
135
+ select: Media[];
136
+ filter: string;
137
+ };
138
+ export declare const SubscriptionTypeInfo: {
139
+ [k in SubscriptionConfiguration["type"]]: string;
140
+ };
141
+ export declare const SubscriptionTypeDescription: {
142
+ [k in SubscriptionConfiguration["type"]]: string;
143
+ };
144
+ export type YamlDocument = {
145
+ app?: string;
146
+ nodes?: YamlNode[];
147
+ __globalConfig?: Record<PropertyKey, unknown>;
148
+ __layout?: {
149
+ id: string;
150
+ x: number;
151
+ y: number;
152
+ }[];
153
+ };
154
+ export type YamlNode = {
155
+ config?: Partial<BaseConfig> & Record<PropertyKey, unknown>;
156
+ type?: string;
157
+ subscriptions?: YamlSubscription[];
158
+ subscriptionValidation?: string;
159
+ };
160
+ export type YamlSubscription = {
161
+ source?: string;
162
+ streams?: Partial<SubscriptionConfiguration>;
163
+ };
164
+ export declare function buildSubscription<SC extends BaseConfig>(sourceInfo: SubscriptionProduceInfo<SC>, currentSubscriptions: NodeSubscriptionDescription<SC>[], currentCfg: SC, dest: SubscriptionAcceptInfo): SubscriptionConfiguration | undefined;
@@ -0,0 +1,496 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.buildSubscription = exports.SubscriptionTypeDescription = exports.SubscriptionTypeInfo = exports.NodeSubscriptionDescription = exports.NodeDescription = exports.DocumentDescription = exports.runGlobalValidationForRow = exports.DefaultNodeValidationContext = void 0;
7
+ const eventhandler_1 = __importDefault(require("eventhandler"));
8
+ const intersect_1 = __importDefault(require("intersect"));
9
+ const util_1 = require("./util");
10
+ class DefaultNodeValidationContext {
11
+ top;
12
+ document;
13
+ node;
14
+ get config() {
15
+ return this.node.config;
16
+ }
17
+ get subscriptions() { return this.node.subscriptions; }
18
+ constructor(top, node, document) {
19
+ this.top = top;
20
+ this.node = node;
21
+ this.document = document;
22
+ }
23
+ videoInputs() {
24
+ return this.subscriptions.filter((s) => s.streams.select.includes("video"));
25
+ }
26
+ audioInputs() {
27
+ return this.subscriptions.filter((s) => s.streams.select.includes("audio"));
28
+ }
29
+ requireVideo(count) {
30
+ const video = this.subscriptions.filter((s) => s.streams.select.includes("video"));
31
+ if (video.length < count) {
32
+ this.addError(`${count} input video stream(s) required`);
33
+ }
34
+ }
35
+ requireAudio(count) {
36
+ const audio = this.subscriptions.filter((s) => s.streams.select.includes("video"));
37
+ if (audio.length < count) {
38
+ this.addError(`${count} input audio stream(s) required`);
39
+ }
40
+ }
41
+ run() {
42
+ if (this.node.info.validation) {
43
+ this.node.info.validation(this);
44
+ }
45
+ else {
46
+ this.runDefaultSubscriptionValidation();
47
+ }
48
+ if (this.node.info.extraValidation) {
49
+ this.node.info.extraValidation(this);
50
+ }
51
+ for (const [k, v] of Object.entries(this.node.info.configForm.form)) {
52
+ const entry = v;
53
+ const hintType = entry.hint.type;
54
+ switch (hintType) {
55
+ case "custom":
56
+ case "text":
57
+ case "numeric":
58
+ case 'list':
59
+ case 'form-list':
60
+ case "form-item":
61
+ case "multiselect":
62
+ if (entry.hint.validation) {
63
+ const result = entry.hint.validation.safeParse(this.node.config[k]);
64
+ if (!result.success) {
65
+ this.addError(`Validation failure on node form row ${this.node.id}:${k} - ${result.error.message}`);
66
+ }
67
+ }
68
+ break;
69
+ case "boolean":
70
+ case "select":
71
+ break;
72
+ default:
73
+ (0, util_1.assertUnreachable)(hintType);
74
+ }
75
+ switch (hintType) {
76
+ case "text":
77
+ case "numeric":
78
+ case 'list':
79
+ case "custom":
80
+ if (entry.hint.global) {
81
+ const globalRule = entry.hint.global;
82
+ const result = runGlobalValidationForRow(globalRule, this.node.config[k], this.node, this.document);
83
+ if (result == true)
84
+ break;
85
+ else {
86
+ if (globalRule.constraint == "custom") {
87
+ this.addError(globalRule.message, { nodeId: this.node.id });
88
+ }
89
+ else {
90
+ this.addError(`${k} must be unique`, { nodeId: this.node.id });
91
+ }
92
+ }
93
+ }
94
+ break;
95
+ case 'form-list':
96
+ case "form-item":
97
+ case "multiselect":
98
+ case "boolean":
99
+ case "select":
100
+ break;
101
+ default:
102
+ (0, util_1.assertUnreachable)(hintType);
103
+ }
104
+ }
105
+ }
106
+ runDefaultSubscriptionValidation() {
107
+ const accepts = this.node.info.subscription.accepts;
108
+ const acceptType = accepts?.type;
109
+ switch (acceptType) {
110
+ case undefined:
111
+ return;
112
+ case "multi-stream":
113
+ return;
114
+ case "single-stream":
115
+ accepts?.media.forEach((m) => {
116
+ const matching = this.subscriptions.flatMap((s) => {
117
+ switch (s.streams.type) {
118
+ case "take-all-streams":
119
+ this.addError("Invalid selector (take-all-streams) present on single-stream subscription");
120
+ return [];
121
+ case "take-specific-streams":
122
+ this.addError("Invalid selector (take-specific streams) present on single-stream subscription");
123
+ return [];
124
+ case "take-first-stream":
125
+ if (s.streams.select.includes(m))
126
+ return [s];
127
+ return [];
128
+ case "take-specific-stream":
129
+ if (s.streams.select.includes(m))
130
+ return [s];
131
+ return [];
132
+ }
133
+ });
134
+ if (matching.length > 1) {
135
+ this.addError("Node only accepts a single stream, but subscribes to multiple " + m + " streams");
136
+ }
137
+ });
138
+ break;
139
+ default:
140
+ (0, util_1.assertUnreachable)(acceptType);
141
+ }
142
+ }
143
+ addWarning(message, ctx) {
144
+ this.top.addWarning({
145
+ message,
146
+ context: {
147
+ nodeId: ctx?.nodeId ?? this.node.id,
148
+ subscriptionSourceId: ctx?.subscriptionSourceId
149
+ }
150
+ });
151
+ }
152
+ addError(message, ctx) {
153
+ this.top.addError({
154
+ message,
155
+ context: {
156
+ nodeId: ctx?.nodeId ?? this.node.id,
157
+ subscriptionSourceId: ctx?.subscriptionSourceId
158
+ }
159
+ });
160
+ }
161
+ }
162
+ exports.DefaultNodeValidationContext = DefaultNodeValidationContext;
163
+ function runGlobalValidationForRow(globalRule, currentValue, node, top) {
164
+ const globalConstraint = globalRule.constraint;
165
+ switch (globalConstraint) {
166
+ case "custom": {
167
+ return globalRule.validate(node.config, top);
168
+ }
169
+ case "unique": {
170
+ if (globalRule.include && !globalRule.include(node.config, top)) {
171
+ return undefined;
172
+ }
173
+ const matching = Object.values(top.nodes).flatMap((n) => {
174
+ if (n.id == node.id)
175
+ return undefined;
176
+ return Object.entries(n.info.configForm.form).flatMap(([k, v]) => {
177
+ const innerEntry = v;
178
+ const innerIntType = innerEntry.hint.type;
179
+ switch (innerIntType) {
180
+ case "text":
181
+ case "numeric":
182
+ case "custom":
183
+ if (innerEntry.hint.global?.constraint == "unique" && innerEntry.hint.global.key == globalRule.key) {
184
+ if (innerEntry.hint.global.include && !innerEntry.hint.global.include(n.config[k], top))
185
+ return undefined;
186
+ return [n.config[k]];
187
+ }
188
+ return undefined;
189
+ case 'list':
190
+ if (innerEntry.hint.global?.constraint == "unique" && innerEntry.hint.global.key == globalRule.key) {
191
+ if (innerEntry.hint.global.include && !innerEntry.hint.global.include(n.config[k], top))
192
+ return undefined;
193
+ return n.config[k];
194
+ }
195
+ return undefined;
196
+ case 'form-list':
197
+ case "form-item":
198
+ case "multiselect":
199
+ case "boolean":
200
+ case "select":
201
+ return undefined;
202
+ default:
203
+ (0, util_1.assertUnreachable)(innerIntType);
204
+ }
205
+ });
206
+ }).filter((v) => v !== undefined);
207
+ if (currentValue instanceof Array) {
208
+ if (matching.some((m) => currentValue.includes(m))) {
209
+ return false;
210
+ }
211
+ }
212
+ else {
213
+ if (matching.some((m) => m == currentValue)) {
214
+ return false;
215
+ }
216
+ }
217
+ return true;
218
+ }
219
+ default:
220
+ (0, util_1.assertUnreachable)(globalConstraint);
221
+ }
222
+ }
223
+ exports.runGlobalValidationForRow = runGlobalValidationForRow;
224
+ class DocumentDescription {
225
+ nodes = {};
226
+ errors;
227
+ warnings;
228
+ layout;
229
+ globalConfig;
230
+ library;
231
+ events;
232
+ constructor(library, yaml) {
233
+ this.errors = [];
234
+ this.warnings = [];
235
+ this.layout = undefined;
236
+ this.library = library;
237
+ this.events = new eventhandler_1.default();
238
+ if (yaml) {
239
+ if (yaml.__layout) {
240
+ this.layout = {};
241
+ for (const l of yaml.__layout) {
242
+ this.layout[l.id] = l;
243
+ }
244
+ }
245
+ this.globalConfig = { ...yaml.__globalConfig };
246
+ if (yaml.nodes) {
247
+ for (const node of yaml.nodes) {
248
+ const info = library.find(node.type ?? 'undefined');
249
+ if (!info) {
250
+ console.error("Failed to load node into document as type is missing", node.config?.id, node.type);
251
+ }
252
+ else if (!node.config?.id) {
253
+ console.error("Missing id on node", node.config?.id, node.type);
254
+ }
255
+ else {
256
+ this.nodes[node.config.id] = new NodeDescription(this, node, info);
257
+ }
258
+ }
259
+ }
260
+ }
261
+ this.onNodeUpdated(this.handleNodeUpdate.bind(this));
262
+ this.onNodeRemoved(this.handleNodeRemoved.bind(this));
263
+ this.forEachNode((n) => {
264
+ n.subscriptions.forEach((s) => {
265
+ this.getNode(s.source).subscribers.push(n.id);
266
+ });
267
+ });
268
+ }
269
+ forEachNode(f) {
270
+ Object.values(this.nodes).forEach(f);
271
+ }
272
+ addNode(type) {
273
+ const info = this.library.find(type);
274
+ if (!info) {
275
+ throw new Error("Failed to find type for addition to document: " + type);
276
+ }
277
+ const node = new NodeDescription(this, { type, config: { id: '', displayName: '' }, subscriptions: [] }, info);
278
+ this.nodes[node.id] = node;
279
+ this.events.emit('onNodeAdded', { id: "", node });
280
+ return node;
281
+ }
282
+ removeNode(id) {
283
+ const existing = this.nodes[id];
284
+ if (existing) {
285
+ existing.subscriptions.forEach((s) => {
286
+ existing.removeSubscription(s.source);
287
+ });
288
+ existing.subscribers.forEach((s) => {
289
+ const subscriber = this.getNode(s);
290
+ subscriber.removeSubscription(id);
291
+ });
292
+ delete this.nodes[id];
293
+ this.events.emit('onNodeRemoved', { id, node: existing });
294
+ }
295
+ }
296
+ findNode(id) {
297
+ return this.nodes[id];
298
+ }
299
+ getNode(id) {
300
+ const node = this.findNode(id);
301
+ if (!node)
302
+ throw new Error("Missing node");
303
+ return node;
304
+ }
305
+ toYaml() {
306
+ return {
307
+ __layout: this.layout ? Object.entries(this.layout).map(([k, v]) => ({ id: k, x: v.x, y: v.y })) : [],
308
+ __globalConfig: this.globalConfig,
309
+ nodes: Object.entries(this.nodes).map(([_id, node]) => node.toYaml()),
310
+ };
311
+ }
312
+ onNodeRemoved(h) {
313
+ this.events.on('onNodeRemoved', h);
314
+ }
315
+ onNodeAdded(h) {
316
+ this.events.on('onNodeAdded', h);
317
+ }
318
+ onNodeUpdated(h) {
319
+ this.events.on('onNodeUpdated', h);
320
+ }
321
+ onSubscriptionAdded(h) {
322
+ this.events.on('onSubscriptionAdded', h);
323
+ }
324
+ onSubscriptionUpdated(h) {
325
+ this.events.on('onSubscriptionUpdated', h);
326
+ }
327
+ onSubscriptionRemoved(h) {
328
+ this.events.on('onSubscriptionRemoved', h);
329
+ }
330
+ handleNodeUpdate({ id, node }) {
331
+ if (id != node.id) {
332
+ delete this.nodes[id];
333
+ this.nodes[node.id] = node;
334
+ this.forEachNode((n) => {
335
+ n.subscriptions.forEach((s) => {
336
+ if (s.source == id) {
337
+ s.source = node.id;
338
+ }
339
+ });
340
+ n.subscribers = n.subscribers.map((s) => {
341
+ if (s == id) {
342
+ return node.id;
343
+ }
344
+ return s;
345
+ });
346
+ });
347
+ }
348
+ }
349
+ handleNodeRemoved(_) {
350
+ }
351
+ }
352
+ exports.DocumentDescription = DocumentDescription;
353
+ class NodeDescription {
354
+ get id() { return this.yaml.config?.id ?? ''; }
355
+ get type() { return this.yaml.type; }
356
+ get config() { return this.yaml.config; }
357
+ set id(id) {
358
+ const oldId = this.id;
359
+ if (this.yaml.config) {
360
+ this.yaml.config.id = id;
361
+ this.document.events.emit('onNodeUpdated', { id: oldId, node: this });
362
+ }
363
+ else {
364
+ console.warn("Failed to update id of node because config wasn't set yet");
365
+ }
366
+ }
367
+ set config(cfg) {
368
+ const oldId = this.id;
369
+ this.yaml.config = cfg;
370
+ this.document.events.emit('onNodeUpdated', { id: oldId, node: this });
371
+ }
372
+ info;
373
+ yaml;
374
+ subscribers = [];
375
+ subscriptions = [];
376
+ document;
377
+ toYaml() {
378
+ return this.yaml;
379
+ }
380
+ constructor(document, yaml, info) {
381
+ this.info = info;
382
+ this.yaml = yaml;
383
+ this.yaml.subscriptions = this.yaml.subscriptions ?? [];
384
+ this.document = document;
385
+ for (const sub of yaml.subscriptions ?? []) {
386
+ this.subscriptions.push(new NodeSubscriptionDescription(this.document, this, sub));
387
+ }
388
+ }
389
+ removeSubscription(sourceId) {
390
+ const sourceNode = this.document.findNode(sourceId);
391
+ if (sourceNode) {
392
+ sourceNode.subscribers = sourceNode.subscribers.filter((s) => s != this.id);
393
+ }
394
+ const existing = this.subscriptions.find((s) => s.source == sourceId);
395
+ if (existing) {
396
+ this.subscriptions = this.subscriptions.filter((s) => s.source != sourceId);
397
+ this.yaml.subscriptions = this.subscriptions.map((s) => s.yaml);
398
+ this.document.events.emit('onSubscriptionRemoved', { subscription: existing, source: sourceNode, destination: this });
399
+ }
400
+ }
401
+ addSubscription(source) {
402
+ if (!source.info.subscription.produces) {
403
+ console.error("Attempt to add subscription to node that doesn't produce data", source);
404
+ return;
405
+ }
406
+ if (!this.info.subscription.accepts) {
407
+ console.error("Attempt to add subscription from node that doesn't accept data", this);
408
+ return;
409
+ }
410
+ const streams = buildSubscription(source.info.subscription.produces, source.subscriptions, source.config, this.info.subscription.accepts);
411
+ if (!streams) {
412
+ console.error("Unable to find appropriate subscription between nodes?", source, this);
413
+ return;
414
+ }
415
+ source.subscribers.push(this.id);
416
+ const yaml = {
417
+ source: source.id,
418
+ streams
419
+ };
420
+ const subscription = new NodeSubscriptionDescription(this.document, this, yaml);
421
+ this.yaml.subscriptions?.push(yaml);
422
+ this.subscriptions.push(subscription);
423
+ this.document.events.emit('onSubscriptionAdded', { subscription, source, destination: this });
424
+ }
425
+ }
426
+ exports.NodeDescription = NodeDescription;
427
+ class NodeSubscriptionDescription {
428
+ get source() { return this.yaml.source ?? 'unknown'; }
429
+ set source(id) {
430
+ this.yaml.source = id;
431
+ this.document.events.emit('onSubscriptionUpdated', { subscription: this, source: this.node, destination: this.document.nodes[this.source] });
432
+ }
433
+ get streams() { return this.yaml.streams; }
434
+ set streams(config) {
435
+ this.yaml.streams = config;
436
+ this.document.events.emit('onSubscriptionUpdated', { subscription: this, source: this.node, destination: this.document.nodes[this.source] });
437
+ }
438
+ yaml;
439
+ node;
440
+ document;
441
+ constructor(document, node, yaml) {
442
+ this.node = node;
443
+ this.yaml = yaml;
444
+ this.document = document;
445
+ }
446
+ }
447
+ exports.NodeSubscriptionDescription = NodeSubscriptionDescription;
448
+ exports.SubscriptionTypeInfo = {
449
+ 'take-all-streams': "All",
450
+ 'take-first-stream': "First Found",
451
+ 'take-specific-stream': "Specified Stream Only",
452
+ 'take-specific-streams': "Specified Streams Only",
453
+ };
454
+ exports.SubscriptionTypeDescription = {
455
+ 'take-all-streams': "Every stream from this source will be subscribed to",
456
+ 'take-first-stream': "If multiple streams are available, only the first matching stream will be subscribed to",
457
+ 'take-specific-stream': "Only the one specified stream (below) will be subscribed to",
458
+ 'take-specific-streams': "Only the specified streams (below) will be subscribed to",
459
+ };
460
+ function buildSubscription(sourceInfo, currentSubscriptions, currentCfg, dest) {
461
+ const sourceType = sourceInfo.type;
462
+ const destType = dest.type;
463
+ switch (sourceType) {
464
+ case 'single-stream':
465
+ switch (destType) {
466
+ case "single-stream":
467
+ return { type: 'take-first-stream', select: (0, intersect_1.default)(dest.media, sourceInfo.media) };
468
+ case "multi-stream":
469
+ return { type: 'take-first-stream', select: (0, intersect_1.default)(dest.media, sourceInfo.media) };
470
+ default:
471
+ return (0, util_1.assertUnreachable)(destType);
472
+ }
473
+ case "multi-stream":
474
+ switch (destType) {
475
+ case "single-stream":
476
+ return { type: 'take-first-stream', select: (0, intersect_1.default)(dest.media, sourceInfo.media) };
477
+ case "multi-stream":
478
+ return { type: 'take-all-streams', select: (0, intersect_1.default)(dest.media, sourceInfo.media) };
479
+ default:
480
+ return (0, util_1.assertUnreachable)(destType);
481
+ }
482
+ case "fixed-list":
483
+ switch (destType) {
484
+ case "single-stream":
485
+ return { type: 'take-specific-stream', select: (0, intersect_1.default)(dest.media, sourceInfo.possibleMedia), filter: sourceInfo.keys(currentCfg, currentSubscriptions)[0].key };
486
+ case "multi-stream":
487
+ return { type: 'take-specific-streams', select: (0, intersect_1.default)(dest.media, sourceInfo.possibleMedia), filter: sourceInfo.keys(currentCfg, currentSubscriptions).map((s) => s.key) };
488
+ default:
489
+ return (0, util_1.assertUnreachable)(destType);
490
+ }
491
+ default:
492
+ (0, util_1.assertUnreachable)(sourceType);
493
+ }
494
+ }
495
+ exports.buildSubscription = buildSubscription;
496
+ //# sourceMappingURL=document.js.map