@foresthubai/workflow-core 0.4.4 → 0.4.5

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 (287) hide show
  1. package/dist/api/deployment.d.ts +26 -19
  2. package/dist/api/deployment.d.ts.map +1 -1
  3. package/dist/api/engine.d.ts +26 -26
  4. package/dist/api/engine.d.ts.map +1 -1
  5. package/dist/api/index.d.ts.map +1 -1
  6. package/dist/api/index.js +2 -0
  7. package/dist/api/index.js.map +1 -1
  8. package/dist/api/workflow.d.ts +10 -10
  9. package/dist/api/workflow.d.ts.map +1 -1
  10. package/dist/channel/Channel.d.ts.map +1 -1
  11. package/dist/channel/Channel.js +2 -0
  12. package/dist/channel/Channel.js.map +1 -1
  13. package/dist/channel/ChannelDefinition.d.ts.map +1 -1
  14. package/dist/channel/ChannelDefinition.js +2 -0
  15. package/dist/channel/ChannelDefinition.js.map +1 -1
  16. package/dist/channel/index.d.ts.map +1 -1
  17. package/dist/channel/index.js +2 -0
  18. package/dist/channel/index.js.map +1 -1
  19. package/dist/channel/serialization.d.ts.map +1 -1
  20. package/dist/channel/serialization.js +2 -0
  21. package/dist/channel/serialization.js.map +1 -1
  22. package/dist/deploy/index.d.ts +1 -1
  23. package/dist/deploy/index.d.ts.map +1 -1
  24. package/dist/deploy/index.js +2 -0
  25. package/dist/deploy/index.js.map +1 -1
  26. package/dist/deploy/inputs.d.ts.map +1 -1
  27. package/dist/deploy/inputs.js +2 -10
  28. package/dist/deploy/inputs.js.map +1 -1
  29. package/dist/deploy/requirements.d.ts.map +1 -1
  30. package/dist/deploy/requirements.js +2 -0
  31. package/dist/deploy/requirements.js.map +1 -1
  32. package/dist/deploy/spec.d.ts +2 -7
  33. package/dist/deploy/spec.d.ts.map +1 -1
  34. package/dist/deploy/spec.js +32 -23
  35. package/dist/deploy/spec.js.map +1 -1
  36. package/dist/diagnostics/__fixtures__/diagnosticFixtures.d.ts.map +1 -1
  37. package/dist/diagnostics/__fixtures__/diagnosticFixtures.js +2 -0
  38. package/dist/diagnostics/__fixtures__/diagnosticFixtures.js.map +1 -1
  39. package/dist/diagnostics/diagnostics.d.ts.map +1 -1
  40. package/dist/diagnostics/diagnostics.js +2 -0
  41. package/dist/diagnostics/diagnostics.js.map +1 -1
  42. package/dist/diagnostics/index.d.ts.map +1 -1
  43. package/dist/diagnostics/index.js +2 -0
  44. package/dist/diagnostics/index.js.map +1 -1
  45. package/dist/edge/Edge.d.ts.map +1 -1
  46. package/dist/edge/Edge.js +2 -0
  47. package/dist/edge/Edge.js.map +1 -1
  48. package/dist/edge/EdgeDefinition.d.ts.map +1 -1
  49. package/dist/edge/EdgeDefinition.js +2 -0
  50. package/dist/edge/EdgeDefinition.js.map +1 -1
  51. package/dist/edge/EdgeType.d.ts.map +1 -1
  52. package/dist/edge/EdgeType.js +2 -0
  53. package/dist/edge/EdgeType.js.map +1 -1
  54. package/dist/edge/index.d.ts.map +1 -1
  55. package/dist/edge/index.js +2 -2
  56. package/dist/edge/index.js.map +1 -1
  57. package/dist/edge/serialization.d.ts.map +1 -1
  58. package/dist/edge/serialization.js +2 -0
  59. package/dist/edge/serialization.js.map +1 -1
  60. package/dist/expression/index.d.ts.map +1 -1
  61. package/dist/expression/index.js +2 -0
  62. package/dist/expression/index.js.map +1 -1
  63. package/dist/expression/parser.d.ts.map +1 -1
  64. package/dist/expression/parser.js +2 -0
  65. package/dist/expression/parser.js.map +1 -1
  66. package/dist/expression/types.d.ts.map +1 -1
  67. package/dist/expression/types.js +2 -0
  68. package/dist/expression/types.js.map +1 -1
  69. package/dist/function/FunctionDeclaration.d.ts.map +1 -1
  70. package/dist/function/FunctionDeclaration.js +2 -0
  71. package/dist/function/FunctionDeclaration.js.map +1 -1
  72. package/dist/function/index.d.ts.map +1 -1
  73. package/dist/function/index.js +2 -0
  74. package/dist/function/index.js.map +1 -1
  75. package/dist/function/serialization.d.ts.map +1 -1
  76. package/dist/function/serialization.js +2 -0
  77. package/dist/function/serialization.js.map +1 -1
  78. package/dist/id/index.d.ts.map +1 -1
  79. package/dist/id/index.js +2 -0
  80. package/dist/id/index.js.map +1 -1
  81. package/dist/index.d.ts.map +1 -1
  82. package/dist/index.js +2 -0
  83. package/dist/index.js.map +1 -1
  84. package/dist/memory/Memory.d.ts.map +1 -1
  85. package/dist/memory/Memory.js +2 -0
  86. package/dist/memory/Memory.js.map +1 -1
  87. package/dist/memory/MemoryDefinition.d.ts.map +1 -1
  88. package/dist/memory/MemoryDefinition.js +2 -0
  89. package/dist/memory/MemoryDefinition.js.map +1 -1
  90. package/dist/memory/MemoryFileDefinition.d.ts.map +1 -1
  91. package/dist/memory/MemoryFileDefinition.js +2 -0
  92. package/dist/memory/MemoryFileDefinition.js.map +1 -1
  93. package/dist/memory/MemoryRegistry.d.ts.map +1 -1
  94. package/dist/memory/MemoryRegistry.js +2 -0
  95. package/dist/memory/MemoryRegistry.js.map +1 -1
  96. package/dist/memory/VectorDatabaseDefinition.d.ts.map +1 -1
  97. package/dist/memory/VectorDatabaseDefinition.js +2 -0
  98. package/dist/memory/VectorDatabaseDefinition.js.map +1 -1
  99. package/dist/memory/index.d.ts.map +1 -1
  100. package/dist/memory/index.js +2 -0
  101. package/dist/memory/index.js.map +1 -1
  102. package/dist/memory/serialization.d.ts.map +1 -1
  103. package/dist/memory/serialization.js +2 -0
  104. package/dist/memory/serialization.js.map +1 -1
  105. package/dist/migration/index.d.ts.map +1 -1
  106. package/dist/migration/index.js +2 -0
  107. package/dist/migration/index.js.map +1 -1
  108. package/dist/migration/migrate.d.ts.map +1 -1
  109. package/dist/migration/migrate.js +2 -0
  110. package/dist/migration/migrate.js.map +1 -1
  111. package/dist/migration/migrations.d.ts.map +1 -1
  112. package/dist/migration/migrations.js +2 -0
  113. package/dist/migration/migrations.js.map +1 -1
  114. package/dist/migration/version.d.ts.map +1 -1
  115. package/dist/migration/version.js +2 -0
  116. package/dist/migration/version.js.map +1 -1
  117. package/dist/model/LLMModelDefinition.d.ts.map +1 -1
  118. package/dist/model/LLMModelDefinition.js +2 -0
  119. package/dist/model/LLMModelDefinition.js.map +1 -1
  120. package/dist/model/Model.d.ts.map +1 -1
  121. package/dist/model/Model.js +2 -13
  122. package/dist/model/Model.js.map +1 -1
  123. package/dist/model/ModelDefinition.d.ts.map +1 -1
  124. package/dist/model/ModelDefinition.js +2 -0
  125. package/dist/model/ModelDefinition.js.map +1 -1
  126. package/dist/model/ModelRegistry.d.ts.map +1 -1
  127. package/dist/model/ModelRegistry.js +2 -0
  128. package/dist/model/ModelRegistry.js.map +1 -1
  129. package/dist/model/index.d.ts.map +1 -1
  130. package/dist/model/index.js +2 -0
  131. package/dist/model/index.js.map +1 -1
  132. package/dist/model/serialization.d.ts.map +1 -1
  133. package/dist/model/serialization.js +2 -0
  134. package/dist/model/serialization.js.map +1 -1
  135. package/dist/node/AgentNode.d.ts.map +1 -1
  136. package/dist/node/AgentNode.js +2 -0
  137. package/dist/node/AgentNode.js.map +1 -1
  138. package/dist/node/DataNode.d.ts.map +1 -1
  139. package/dist/node/DataNode.js +2 -0
  140. package/dist/node/DataNode.js.map +1 -1
  141. package/dist/node/FunctionNode.d.ts.map +1 -1
  142. package/dist/node/FunctionNode.js +2 -0
  143. package/dist/node/FunctionNode.js.map +1 -1
  144. package/dist/node/InputNode.d.ts.map +1 -1
  145. package/dist/node/InputNode.js +2 -0
  146. package/dist/node/InputNode.js.map +1 -1
  147. package/dist/node/LogicNode.d.ts.map +1 -1
  148. package/dist/node/LogicNode.js +2 -0
  149. package/dist/node/LogicNode.js.map +1 -1
  150. package/dist/node/MqttNode.d.ts.map +1 -1
  151. package/dist/node/MqttNode.js +2 -0
  152. package/dist/node/MqttNode.js.map +1 -1
  153. package/dist/node/Node.d.ts.map +1 -1
  154. package/dist/node/Node.js +2 -7
  155. package/dist/node/Node.js.map +1 -1
  156. package/dist/node/NodeDefinition.d.ts.map +1 -1
  157. package/dist/node/NodeDefinition.js +2 -0
  158. package/dist/node/NodeDefinition.js.map +1 -1
  159. package/dist/node/NodeRegistry.d.ts.map +1 -1
  160. package/dist/node/NodeRegistry.js +2 -0
  161. package/dist/node/NodeRegistry.js.map +1 -1
  162. package/dist/node/OutputNode.d.ts.map +1 -1
  163. package/dist/node/OutputNode.js +2 -0
  164. package/dist/node/OutputNode.js.map +1 -1
  165. package/dist/node/ToolNode.d.ts.map +1 -1
  166. package/dist/node/ToolNode.js +2 -0
  167. package/dist/node/ToolNode.js.map +1 -1
  168. package/dist/node/TriggerNode.d.ts.map +1 -1
  169. package/dist/node/TriggerNode.js +2 -0
  170. package/dist/node/TriggerNode.js.map +1 -1
  171. package/dist/node/constants.d.ts.map +1 -1
  172. package/dist/node/constants.js +2 -0
  173. package/dist/node/constants.js.map +1 -1
  174. package/dist/node/index.d.ts.map +1 -1
  175. package/dist/node/index.js +2 -0
  176. package/dist/node/index.js.map +1 -1
  177. package/dist/node/methods.d.ts.map +1 -1
  178. package/dist/node/methods.js +2 -0
  179. package/dist/node/methods.js.map +1 -1
  180. package/dist/node/serialization.d.ts.map +1 -1
  181. package/dist/node/serialization.js +33 -13
  182. package/dist/node/serialization.js.map +1 -1
  183. package/dist/parameter/OutputParameter.d.ts.map +1 -1
  184. package/dist/parameter/OutputParameter.js +2 -0
  185. package/dist/parameter/OutputParameter.js.map +1 -1
  186. package/dist/parameter/Parameter.d.ts.map +1 -1
  187. package/dist/parameter/Parameter.js +2 -0
  188. package/dist/parameter/Parameter.js.map +1 -1
  189. package/dist/parameter/index.d.ts.map +1 -1
  190. package/dist/parameter/index.js +2 -0
  191. package/dist/parameter/index.js.map +1 -1
  192. package/dist/variable/Variable.d.ts.map +1 -1
  193. package/dist/variable/Variable.js +2 -0
  194. package/dist/variable/Variable.js.map +1 -1
  195. package/dist/variable/index.d.ts.map +1 -1
  196. package/dist/variable/index.js +2 -3
  197. package/dist/variable/index.js.map +1 -1
  198. package/dist/variable/operations.d.ts.map +1 -1
  199. package/dist/variable/operations.js +2 -0
  200. package/dist/variable/operations.js.map +1 -1
  201. package/dist/workflow/Workflow.d.ts.map +1 -1
  202. package/dist/workflow/Workflow.js +2 -0
  203. package/dist/workflow/Workflow.js.map +1 -1
  204. package/dist/workflow/index.d.ts.map +1 -1
  205. package/dist/workflow/index.js +2 -0
  206. package/dist/workflow/index.js.map +1 -1
  207. package/dist/workflow/serialization.d.ts.map +1 -1
  208. package/dist/workflow/serialization.js +2 -4
  209. package/dist/workflow/serialization.js.map +1 -1
  210. package/package.json +1 -1
  211. package/src/api/deployment.ts +26 -19
  212. package/src/api/engine.ts +26 -26
  213. package/src/api/index.ts +3 -0
  214. package/src/api/workflow.ts +10 -10
  215. package/src/channel/Channel.ts +3 -0
  216. package/src/channel/ChannelDefinition.ts +3 -0
  217. package/src/channel/index.ts +3 -0
  218. package/src/channel/serialization.ts +3 -0
  219. package/src/deploy/index.ts +4 -1
  220. package/src/deploy/inputs.ts +3 -0
  221. package/src/deploy/requirements.test.ts +3 -0
  222. package/src/deploy/requirements.ts +3 -0
  223. package/src/deploy/spec.test.ts +7 -6
  224. package/src/deploy/spec.ts +46 -28
  225. package/src/diagnostics/__fixtures__/diagnosticFixtures.ts +3 -0
  226. package/src/diagnostics/diagnostics.test.ts +3 -0
  227. package/src/diagnostics/diagnostics.ts +3 -0
  228. package/src/diagnostics/index.ts +3 -0
  229. package/src/edge/Edge.ts +3 -0
  230. package/src/edge/EdgeDefinition.ts +3 -0
  231. package/src/edge/EdgeType.ts +3 -0
  232. package/src/edge/index.ts +3 -0
  233. package/src/edge/serialization.ts +3 -0
  234. package/src/expression/index.ts +3 -0
  235. package/src/expression/parser.ts +3 -0
  236. package/src/expression/types.ts +3 -0
  237. package/src/function/FunctionDeclaration.ts +3 -0
  238. package/src/function/index.ts +3 -0
  239. package/src/function/serialization.ts +3 -0
  240. package/src/globals.d.ts +3 -0
  241. package/src/id/index.ts +3 -0
  242. package/src/index.ts +3 -0
  243. package/src/memory/Memory.ts +3 -0
  244. package/src/memory/MemoryDefinition.ts +3 -0
  245. package/src/memory/MemoryFileDefinition.ts +3 -0
  246. package/src/memory/MemoryRegistry.ts +3 -0
  247. package/src/memory/VectorDatabaseDefinition.ts +3 -0
  248. package/src/memory/index.ts +3 -0
  249. package/src/memory/serialization.ts +3 -0
  250. package/src/migration/index.ts +3 -0
  251. package/src/migration/migrate.test.ts +3 -0
  252. package/src/migration/migrate.ts +3 -0
  253. package/src/migration/migrations.ts +3 -0
  254. package/src/migration/version.ts +3 -0
  255. package/src/model/LLMModelDefinition.ts +3 -0
  256. package/src/model/Model.ts +3 -0
  257. package/src/model/ModelDefinition.ts +3 -0
  258. package/src/model/ModelRegistry.ts +3 -0
  259. package/src/model/index.ts +3 -0
  260. package/src/model/serialization.ts +3 -0
  261. package/src/node/AgentNode.ts +3 -0
  262. package/src/node/DataNode.ts +3 -0
  263. package/src/node/FunctionNode.ts +3 -0
  264. package/src/node/InputNode.ts +3 -0
  265. package/src/node/LogicNode.ts +3 -0
  266. package/src/node/MqttNode.ts +3 -0
  267. package/src/node/Node.ts +3 -0
  268. package/src/node/NodeDefinition.ts +3 -0
  269. package/src/node/NodeRegistry.ts +3 -0
  270. package/src/node/OutputNode.ts +3 -0
  271. package/src/node/ToolNode.ts +3 -0
  272. package/src/node/TriggerNode.ts +3 -0
  273. package/src/node/constants.ts +3 -0
  274. package/src/node/index.ts +3 -0
  275. package/src/node/methods.ts +3 -0
  276. package/src/node/serialization.test.ts +51 -0
  277. package/src/node/serialization.ts +34 -13
  278. package/src/parameter/OutputParameter.ts +3 -0
  279. package/src/parameter/Parameter.ts +3 -0
  280. package/src/parameter/index.ts +3 -0
  281. package/src/variable/Variable.ts +3 -0
  282. package/src/variable/index.ts +3 -0
  283. package/src/variable/operations.ts +3 -0
  284. package/src/workflow/Workflow.ts +3 -0
  285. package/src/workflow/index.ts +3 -0
  286. package/src/workflow/serialization.test.ts +3 -0
  287. package/src/workflow/serialization.ts +3 -0
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import jsep from "jsep";
2
5
  import type { DataType } from "../api";
3
6
  import { ResolvedExpr } from "./types";
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import type { NodeOutput } from "../node";
2
5
  import type { DataType, Expression } from "../api";
3
6
  import type { Variable } from "../variable";
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import type { Expression, Schemas } from "../api";
2
5
  import type { ApiVariable } from "../variable";
3
6
  import type { DataType } from "../parameter";
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  export type { OutputAssignment, FunctionDeclaration, FunctionInfo } from "./FunctionDeclaration";
2
5
  export { toFunctionInfo } from "./FunctionDeclaration";
3
6
  export { serialize, deserialize } from "./serialization";
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import type { Expression } from "../api";
2
5
  import type { FunctionDeclaration, FunctionInfo } from "./FunctionDeclaration";
3
6
  import { toFunctionInfo } from "./FunctionDeclaration";
package/src/globals.d.ts CHANGED
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  /**
2
5
  * This package drops the `DOM` lib (see tsconfig.json) to stay headless, so the
3
6
  * Web Crypto `crypto` global is untyped. It exists at runtime everywhere we run
package/src/id/index.ts CHANGED
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  /**
2
5
  * Centralized UID creation for every entity in a workflow — nodes, edges,
3
6
  * channels, memory, models, declared variables, function arguments, and
package/src/index.ts CHANGED
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import { deserialize } from "./workflow/serialization";
2
5
  import { validateWorkflowState, type ValidationResult } from "./diagnostics/diagnostics";
3
6
  import type { ApiWorkflow } from "./workflow/Workflow";
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import type { Schemas } from "../api";
2
5
 
3
6
  export type MemoryType = "MemoryFile" | "VectorDatabase";
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import type { Parameter } from "../parameter";
2
5
  import type { MemoryType } from "./Memory";
3
6
 
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import type { MemoryDefinition } from "./MemoryDefinition";
2
5
 
3
6
  /**
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import type { MemoryType } from "./Memory";
2
5
  import type { MemoryDefinition } from "./MemoryDefinition";
3
6
  import { MemoryFileDefinition } from "./MemoryFileDefinition";
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import type { MemoryDefinition } from "./MemoryDefinition";
2
5
 
3
6
  /**
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  export type { MemoryType, Memory, MemoryRef } from "./Memory";
2
5
  export { ALL_MEMORY_TYPES } from "./Memory";
3
6
  export type { MemoryDefinition } from "./MemoryDefinition";
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import type { Schemas } from "../api";
2
5
  import type { Memory } from "./Memory";
3
6
 
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  export { CURRENT_SCHEMA_VERSION, BASELINE_SCHEMA_VERSION } from "./version";
2
5
  export { migrate, readSchemaVersion } from "./migrate";
3
6
  export { MIGRATIONS } from "./migrations";
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import { describe, it, expect } from "vitest";
2
5
  import { migrate, readSchemaVersion } from "./migrate";
3
6
  import { CURRENT_SCHEMA_VERSION } from "./version";
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import type { ApiWorkflow } from "../workflow/Workflow";
2
5
  import { MIGRATIONS, type Migration } from "./migrations";
3
6
  import { BASELINE_SCHEMA_VERSION, CURRENT_SCHEMA_VERSION } from "./version";
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  /**
2
5
  * A single-step upgrade of the persisted workflow format, from `from` to
3
6
  * `from + 1`. Operates on the raw parsed document, never the domain types.
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  /**
2
5
  * Persisted-format version this build reads and writes. A plain monotonic
3
6
  * integer, decoupled from the contract/package semver. Bump only when the
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import type { ModelDefinition } from "./ModelDefinition";
2
5
 
3
6
  /**
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  // Domain Model — covers two distinct things that share a picker:
2
5
  // 1. The STATIC catalog (ModelInfo[]): the set of models the llmproxy already
3
6
  // supports. Supplied to the editor as data (props), not declared per-workflow.
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import type { Parameter } from "../parameter";
2
5
  import type { ModelType } from "./Model";
3
6
 
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import type { ModelType } from "./Model";
2
5
  import type { ModelDefinition } from "./ModelDefinition";
3
6
  import { LLMModelDefinition } from "./LLMModelDefinition";
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  export type { ModelType, Model, ModelCapability, ModelInfo } from "./Model";
2
5
  export { ALL_MODEL_TYPES } from "./Model";
3
6
  export type { ModelDefinition } from "./ModelDefinition";
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import type { Schemas } from "../api";
2
5
  import type { Model, ModelCapability } from "./Model";
3
6
 
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import { NodeBase } from "./Node";
2
5
  import { OutputBinding, OutputDeclaration } from "../parameter";
3
6
  import type { Schemas } from "../api";
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import { NodeBase } from "./Node";
2
5
  import type { Expression, Reference } from "../api";
3
6
  import { NodeCategory } from "./constants";
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import { NodeBase } from "./Node";
2
5
  import type { Expression } from "../api";
3
6
  import type { FunctionInfo } from "../function";
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import { NodeBase } from "./Node";
2
5
  import type { Expression } from "../api";
3
6
  import { OutputBinding } from "../parameter";
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import { NodeBase } from "./Node";
2
5
  import type { Expression } from "../api";
3
6
  import { NodeCategory } from "./constants";
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import { NodeBase } from "./Node";
2
5
  import type { Expression } from "../api";
3
6
  import { OutputBinding } from "../parameter";
package/src/node/Node.ts CHANGED
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  // Domain Node — the base shape every node variant builds on. NodeBase is the
2
5
  // generic, untyped-parameters shape used wherever a node is handled generically
3
6
  // (e.g. React Flow nodes); NodeData is the discriminated union over the
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import { NodeType } from "./Node";
2
5
  import { NodeCategory, NodeTag } from "./constants";
3
6
  import { OutputParameter, Parameter } from "../parameter";
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import { ReadPinNodeDefinition, SerialReadNodeDefinition, RetrieverNodeDefinition, WebFetchNodeDefinition } from "./InputNode";
2
5
  import { AgentNodeDefinition } from "./AgentNode";
3
6
  import {
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import { NodeBase } from "./Node";
2
5
  import type { Expression } from "../api";
3
6
  import { NodeCategory, NodeTag } from "./constants";
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import { NodeBase } from "./Node";
2
5
  import { NodeCategory } from "./constants";
3
6
  import { NodeDefinition } from "./NodeDefinition";
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import { NodeBase } from "./Node";
2
5
  import type { Reference } from "../api";
3
6
  import { OutputBinding } from "../parameter";
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  export enum NodeCategory {
2
5
  Input = "Input",
3
6
  Output = "Output",
package/src/node/index.ts CHANGED
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  // Base domain node types
2
5
  export type {
3
6
  NodeOutput,
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import { NodeData, NodeOutput } from "./Node";
2
5
  import type { OutputBinding, OutputDeclaration } from "../parameter";
3
6
  import { PortDefinitions } from "./NodeDefinition";
@@ -0,0 +1,51 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
4
+ import { describe, it, expect } from "vitest";
5
+ import { serialize, deserialize } from "./serialization";
6
+ import type { Node } from "./Node";
7
+
8
+ // Drafts save on purpose: a required-but-unset argument must serialize as
9
+ // ABSENT — never as `undefined`, `""`, or (worst) `null` in the JSON file.
10
+
11
+ function makeNode(type: string, args: Record<string, unknown>): Node {
12
+ return { id: "n1", type, position: { x: 0, y: 0 }, arguments: args } as unknown as Node;
13
+ }
14
+
15
+ describe("serialize: draft (incomplete) nodes", () => {
16
+ it("omits a required-but-unset argument entirely", () => {
17
+ const api = serialize(makeNode("ReadPin", {}), false);
18
+ expect("arguments" in api && api.arguments && "pinReference" in api.arguments).toBe(false);
19
+ });
20
+
21
+ it("emits no null/undefined values in the JSON form", () => {
22
+ const api = serialize(makeNode("OnThreshold", {}), false);
23
+ const json = JSON.parse(JSON.stringify(api)) as { arguments?: Record<string, unknown> };
24
+ expect(Object.values(json.arguments ?? {})).not.toContain(null);
25
+ expect(json).toEqual({ id: "n1", type: "OnThreshold", position: { x: 0, y: 0 }, arguments: {} });
26
+ });
27
+
28
+ it("unset MqttPublish qos stays absent instead of NaN→null", () => {
29
+ const api = serialize(makeNode("MqttPublish", { channelReference: "ch1" }), false);
30
+ const json = JSON.parse(JSON.stringify(api)) as { arguments: Record<string, unknown> };
31
+ expect("qos" in json.arguments).toBe(false);
32
+ });
33
+ });
34
+
35
+ describe("serialize: complete nodes", () => {
36
+ it("keeps configured required arguments", () => {
37
+ const api = serialize(makeNode("Delay", { delayMs: 250 }), false);
38
+ expect(api).toMatchObject({ arguments: { delayMs: 250 } });
39
+ });
40
+
41
+ it("maps MqttPublish qos from domain string to wire number", () => {
42
+ const api = serialize(makeNode("MqttPublish", { channelReference: "ch1", qos: "2" }), false);
43
+ expect(api).toMatchObject({ arguments: { qos: 2 } });
44
+ });
45
+
46
+ it("round-trips a configured node through deserialize", () => {
47
+ const node = makeNode("Ticker", { intervalValue: 5, intervalUnit: "seconds" });
48
+ const back = deserialize(serialize(node, false));
49
+ expect(back.arguments).toMatchObject({ intervalValue: 5, intervalUnit: "seconds" });
50
+ });
51
+ });
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import type { Schemas } from "../api";
2
5
  import type { NodeData, Node } from "./Node";
3
6
  import type { Expression } from "../api";
@@ -17,6 +20,17 @@ export type ApiNode = Schemas["Node"];
17
20
  */
18
21
  export type ResolveFunctionInfo = (functionId: string) => FunctionInfo | undefined;
19
22
 
23
+ /**
24
+ * A required wire field the workflow may not have yet: drafts save on purpose,
25
+ * and deserialize mirrors this with `??` fallbacks. serialize() emits such a
26
+ * field as absent (see the undefined-prune there); validate / check-schema /
27
+ * deploy are the strictness gates. This is the one deliberate spot where the
28
+ * api's "required" is relaxed — use it instead of `!` assertions.
29
+ */
30
+ function draft<T>(value: T | undefined): T {
31
+ return value as T;
32
+ }
33
+
20
34
  /**
21
35
  * Serialize a domain Node to the strict API format (Schemas["Node"]).
22
36
  * Strips hidden parameters (those whose activationRules are not met). The
@@ -39,6 +53,12 @@ export function serialize(node: Node, isToolInput: boolean): ApiNode {
39
53
  if (def) {
40
54
  pruneArguments(result.arguments, def.parameters, isToolInput);
41
55
  }
56
+ // Required-but-unset draft arguments (see draft()) are emitted as absent,
57
+ // so the in-memory node matches its JSON form.
58
+ const args = result.arguments as Record<string, unknown>;
59
+ for (const key of Object.keys(args)) {
60
+ if (args[key] === undefined) delete args[key];
61
+ }
42
62
  }
43
63
 
44
64
  return result;
@@ -52,7 +72,7 @@ function serializeNodeData(data: NodeData, position: { x: number; y: number }, i
52
72
  type: data.type,
53
73
  position: position,
54
74
  arguments: {
55
- pinReference: data.arguments.pinReference!,
75
+ pinReference: draft(data.arguments.pinReference),
56
76
  signalType: data.arguments.signalType,
57
77
  output: data.arguments.output,
58
78
  toolDescription: data.arguments.toolDescription,
@@ -64,7 +84,7 @@ function serializeNodeData(data: NodeData, position: { x: number; y: number }, i
64
84
  type: data.type,
65
85
  position: position,
66
86
  arguments: {
67
- portReference: data.arguments.portReference!,
87
+ portReference: draft(data.arguments.portReference),
68
88
  ...(data.arguments.prompt !== undefined ? { prompt: data.arguments.prompt } : {}),
69
89
  output: data.arguments.output,
70
90
  },
@@ -75,7 +95,7 @@ function serializeNodeData(data: NodeData, position: { x: number; y: number }, i
75
95
  type: data.type,
76
96
  position: position,
77
97
  arguments: {
78
- pinReference: data.arguments.pinReference!,
98
+ pinReference: draft(data.arguments.pinReference),
79
99
  signalType: data.arguments.signalType,
80
100
  value: data.arguments.value,
81
101
  },
@@ -86,7 +106,7 @@ function serializeNodeData(data: NodeData, position: { x: number; y: number }, i
86
106
  type: data.type,
87
107
  position: position,
88
108
  arguments: {
89
- portReference: data.arguments.portReference!,
109
+ portReference: draft(data.arguments.portReference),
90
110
  value: data.arguments.value,
91
111
  },
92
112
  };
@@ -138,7 +158,7 @@ function serializeNodeData(data: NodeData, position: { x: number; y: number }, i
138
158
  type: data.type,
139
159
  position: position,
140
160
  arguments: {
141
- pinReference: data.arguments.pinReference!,
161
+ pinReference: draft(data.arguments.pinReference),
142
162
  edge: data.arguments.edge,
143
163
  },
144
164
  };
@@ -148,7 +168,7 @@ function serializeNodeData(data: NodeData, position: { x: number; y: number }, i
148
168
  type: data.type,
149
169
  position: position,
150
170
  arguments: {
151
- portReference: data.arguments.portReference!,
171
+ portReference: draft(data.arguments.portReference),
152
172
  output: data.arguments.output,
153
173
  },
154
174
  };
@@ -158,8 +178,8 @@ function serializeNodeData(data: NodeData, position: { x: number; y: number }, i
158
178
  type: data.type,
159
179
  position: position,
160
180
  arguments: {
161
- variable: data.arguments.variable!,
162
- threshold: data.arguments.threshold!,
181
+ variable: draft(data.arguments.variable),
182
+ threshold: draft(data.arguments.threshold),
163
183
  direction: data.arguments.direction,
164
184
  deadband: data.arguments.deadband,
165
185
  output: data.arguments.output,
@@ -171,7 +191,7 @@ function serializeNodeData(data: NodeData, position: { x: number; y: number }, i
171
191
  type: data.type,
172
192
  position: position,
173
193
  arguments: {
174
- delayMs: data.arguments.delayMs!,
194
+ delayMs: draft(data.arguments.delayMs),
175
195
  },
176
196
  };
177
197
  case "Ticker":
@@ -180,7 +200,7 @@ function serializeNodeData(data: NodeData, position: { x: number; y: number }, i
180
200
  type: data.type,
181
201
  position: position,
182
202
  arguments: {
183
- intervalValue: data.arguments.intervalValue!,
203
+ intervalValue: draft(data.arguments.intervalValue),
184
204
  intervalUnit: data.arguments.intervalUnit,
185
205
  },
186
206
  };
@@ -210,7 +230,7 @@ function serializeNodeData(data: NodeData, position: { x: number; y: number }, i
210
230
  position: position,
211
231
  arguments: {
212
232
  memoryReference: data.arguments.memoryReference,
213
- topK: data.arguments.topK!,
233
+ topK: draft(data.arguments.topK),
214
234
  query: data.arguments.query,
215
235
  output: data.arguments.output,
216
236
  toolDescription: data.arguments.toolDescription,
@@ -265,7 +285,7 @@ function serializeNodeData(data: NodeData, position: { x: number; y: number }, i
265
285
  type: data.type,
266
286
  position: position,
267
287
  arguments: {
268
- variable: data.arguments.variable!,
288
+ variable: draft(data.arguments.variable),
269
289
  value: data.arguments.value,
270
290
  },
271
291
  };
@@ -278,7 +298,8 @@ function serializeNodeData(data: NodeData, position: { x: number; y: number }, i
278
298
  channelReference: data.arguments.channelReference ?? "",
279
299
  dataType: data.arguments.dataType,
280
300
  value: data.arguments.value,
281
- qos: Number(data.arguments.qos) as 0 | 1 | 2,
301
+ // Unset stays unset — Number(undefined) is NaN, which stringifies to null.
302
+ qos: draft(data.arguments.qos === undefined ? undefined : (Number(data.arguments.qos) as 0 | 1 | 2)),
282
303
  retain: data.arguments.retain,
283
304
  },
284
305
  };
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import type { Reference } from "../api";
2
5
  import { DataType, FromArgs, unwrapFromArgs } from "./Parameter";
3
6
 
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import type { Expression, Reference } from "../api";
2
5
  import type { ChannelType } from "../channel";
3
6
  import type { MemoryType } from "../memory";
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  export type {
2
5
  DataType,
3
6
  FromArgs,
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import type { Schemas } from "../api";
2
5
  import type { DataType } from "../api";
3
6
 
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  // Public surface of the variable module. The discriminated-union types live in
2
5
  // ./Variable; the key/lookup/uid helpers and availability computation live in
3
6
  // ./operations. This file is a barrel only. Mirrors channel/memory/model.
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import type { NodeOutput } from "../node";
2
5
  import type { Reference } from "../api";
3
6
  import type { ApiVariable } from "./Variable";
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import type { Channel } from "../channel";
2
5
  import type { Memory } from "../memory";
3
6
  import type { Model } from "../model";
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  export type { ApiWorkflow, Workflow, Canvas } from "./Workflow";
2
5
  export { MAIN_CANVAS_ID } from "./Workflow";
3
6
  export { serialize, deserialize, computeVariablesFromNodes } from "./serialization";
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  import { describe, it, expect } from "vitest";
2
5
  import { serialize, deserialize, computeVariablesFromNodes, buildCanvasVariables } from "./serialization";
3
6
  import { MAIN_CANVAS_ID, type Workflow, type Canvas } from "./Workflow";
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
1
4
  // Pure conversion between the api format (Schemas["Workflow"])
2
5
  // and the domain shape (Workflow).
3
6
  // Two producers feed serialize: the editor reads its live stores into