Flowfile 0.3.9__py3-none-any.whl → 0.5.1__py3-none-any.whl

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 (201) hide show
  1. flowfile/__init__.py +8 -1
  2. flowfile/api.py +1 -3
  3. flowfile/web/static/assets/{CloudConnectionManager-c97c25f8.js → CloudConnectionManager-0dfba9f2.js} +2 -2
  4. flowfile/web/static/assets/{CloudStorageReader-f1ff509e.js → CloudStorageReader-d5b1b6c9.js} +11 -78
  5. flowfile/web/static/assets/{CloudStorageWriter-034f8b78.js → CloudStorageWriter-00d87aad.js} +12 -79
  6. flowfile/web/static/assets/{CloudStorageWriter-49c9a4b2.css → CloudStorageWriter-b0ee067f.css} +24 -24
  7. flowfile/web/static/assets/ColumnSelector-4685e75d.js +83 -0
  8. flowfile/web/static/assets/ColumnSelector-47996a16.css +10 -0
  9. flowfile/web/static/assets/ContextMenu-23e909da.js +41 -0
  10. flowfile/web/static/assets/{SettingsSection-9c836ecc.css → ContextMenu-4c74eef1.css} +0 -21
  11. flowfile/web/static/assets/ContextMenu-63cfa99b.css +26 -0
  12. flowfile/web/static/assets/ContextMenu-70ae0c79.js +41 -0
  13. flowfile/web/static/assets/ContextMenu-c13f91d0.css +26 -0
  14. flowfile/web/static/assets/ContextMenu-f149cf7c.js +41 -0
  15. flowfile/web/static/assets/{CrossJoin-41efa4cb.css → CrossJoin-1119d18e.css} +18 -18
  16. flowfile/web/static/assets/{CrossJoin-9e156ebe.js → CrossJoin-702a3edd.js} +14 -84
  17. flowfile/web/static/assets/CustomNode-74a37f74.css +32 -0
  18. flowfile/web/static/assets/CustomNode-b1519993.js +211 -0
  19. flowfile/web/static/assets/{DatabaseConnectionSettings-d5c625b3.js → DatabaseConnectionSettings-6f3e4ea5.js} +3 -3
  20. flowfile/web/static/assets/{DatabaseManager-265adc5e.js → DatabaseManager-cf5ef661.js} +2 -2
  21. flowfile/web/static/assets/{DatabaseReader-f50c6558.css → DatabaseReader-ae61773c.css} +0 -27
  22. flowfile/web/static/assets/{DatabaseReader-0b10551e.js → DatabaseReader-d38c7295.js} +14 -114
  23. flowfile/web/static/assets/{DatabaseWriter-c17c6916.js → DatabaseWriter-b04ef46a.js} +13 -74
  24. flowfile/web/static/assets/{ExploreData-5bdae813.css → ExploreData-2d0cf4db.css} +8 -14
  25. flowfile/web/static/assets/ExploreData-5fa10ed8.js +192 -0
  26. flowfile/web/static/assets/{ExternalSource-3a66556c.js → ExternalSource-d39af878.js} +8 -79
  27. flowfile/web/static/assets/{Filter-91ad87e7.js → Filter-9b6d08db.js} +12 -85
  28. flowfile/web/static/assets/{Filter-a9d08ba1.css → Filter-f62091b3.css} +3 -3
  29. flowfile/web/static/assets/{Formula-3c395ab1.js → Formula-6b04fb1d.js} +20 -87
  30. flowfile/web/static/assets/{Formula-29f19d21.css → Formula-bb96803d.css} +4 -4
  31. flowfile/web/static/assets/{FuzzyMatch-6857de82.css → FuzzyMatch-1010f966.css} +42 -42
  32. flowfile/web/static/assets/{FuzzyMatch-2df0d230.js → FuzzyMatch-999521f4.js} +16 -87
  33. flowfile/web/static/assets/{GraphSolver-d285877f.js → GraphSolver-17dd2198.js} +13 -159
  34. flowfile/web/static/assets/GraphSolver-f0cb7bfb.css +22 -0
  35. flowfile/web/static/assets/{GroupBy-0bd1cc6b.js → GroupBy-6b039e18.js} +12 -75
  36. flowfile/web/static/assets/{Unique-b5615727.css → GroupBy-b9505323.css} +8 -8
  37. flowfile/web/static/assets/{Join-5a78a203.js → Join-24d0f113.js} +15 -85
  38. flowfile/web/static/assets/{Join-f45eff22.css → Join-fd79b451.css} +20 -20
  39. flowfile/web/static/assets/{ManualInput-a71b52c6.css → ManualInput-3246a08d.css} +20 -20
  40. flowfile/web/static/assets/{ManualInput-93aef9d6.js → ManualInput-34639209.js} +11 -82
  41. flowfile/web/static/assets/MultiSelect-0e8724a3.js +5 -0
  42. flowfile/web/static/assets/MultiSelect.vue_vue_type_script_setup_true_lang-b0e538c2.js +63 -0
  43. flowfile/web/static/assets/NumericInput-3d63a470.js +5 -0
  44. flowfile/web/static/assets/NumericInput.vue_vue_type_script_setup_true_lang-e0edeccc.js +35 -0
  45. flowfile/web/static/assets/Output-283fe388.css +37 -0
  46. flowfile/web/static/assets/{Output-411ecaee.js → Output-edea9802.js} +62 -273
  47. flowfile/web/static/assets/{Pivot-89db4b04.js → Pivot-61d19301.js} +14 -138
  48. flowfile/web/static/assets/Pivot-cf333e3d.css +22 -0
  49. flowfile/web/static/assets/PivotValidation-891ddfb0.css +13 -0
  50. flowfile/web/static/assets/PivotValidation-c46cd420.css +13 -0
  51. flowfile/web/static/assets/PivotValidation-de9f43fe.js +61 -0
  52. flowfile/web/static/assets/PivotValidation-f97fec5b.js +61 -0
  53. flowfile/web/static/assets/{PolarsCode-a9f974f8.js → PolarsCode-bc3c9984.js} +13 -80
  54. flowfile/web/static/assets/Read-64a3f259.js +218 -0
  55. flowfile/web/static/assets/Read-e808b239.css +62 -0
  56. flowfile/web/static/assets/RecordCount-3d5039be.js +53 -0
  57. flowfile/web/static/assets/{RecordId-55ae7d36.js → RecordId-597510e0.js} +8 -80
  58. flowfile/web/static/assets/SQLQueryComponent-36cef432.css +27 -0
  59. flowfile/web/static/assets/SQLQueryComponent-df51adbe.js +38 -0
  60. flowfile/web/static/assets/{Sample-b4a18476.js → Sample-4be0a507.js} +8 -77
  61. flowfile/web/static/assets/{SecretManager-b066d13a.js → SecretManager-4839be57.js} +2 -2
  62. flowfile/web/static/assets/{Select-727688dc.js → Select-9b72f201.js} +11 -85
  63. flowfile/web/static/assets/SettingsSection-2e4d03c4.css +21 -0
  64. flowfile/web/static/assets/SettingsSection-5c696bee.css +20 -0
  65. flowfile/web/static/assets/SettingsSection-71e6b7e3.css +21 -0
  66. flowfile/web/static/assets/SettingsSection-7ded385d.js +45 -0
  67. flowfile/web/static/assets/{SettingsSection-695ac487.js → SettingsSection-e1e9c953.js} +2 -40
  68. flowfile/web/static/assets/SettingsSection-f0f75a42.js +53 -0
  69. flowfile/web/static/assets/SingleSelect-6c777aac.js +5 -0
  70. flowfile/web/static/assets/SingleSelect.vue_vue_type_script_setup_true_lang-33e3ff9b.js +62 -0
  71. flowfile/web/static/assets/SliderInput-7cb93e62.js +40 -0
  72. flowfile/web/static/assets/SliderInput-b8fb6a8c.css +4 -0
  73. flowfile/web/static/assets/{GroupBy-ab1ea74b.css → Sort-3643d625.css} +8 -8
  74. flowfile/web/static/assets/{Sort-be3339a8.js → Sort-6cbde21a.js} +12 -97
  75. flowfile/web/static/assets/TextInput-d9a40c11.js +5 -0
  76. flowfile/web/static/assets/TextInput.vue_vue_type_script_setup_true_lang-5896c375.js +32 -0
  77. flowfile/web/static/assets/{TextToRows-c92d1ec2.css → TextToRows-5d2c1190.css} +9 -9
  78. flowfile/web/static/assets/{TextToRows-7b8998da.js → TextToRows-c4fcbf4d.js} +14 -83
  79. flowfile/web/static/assets/ToggleSwitch-4ef91d19.js +5 -0
  80. flowfile/web/static/assets/ToggleSwitch.vue_vue_type_script_setup_true_lang-38478c20.js +31 -0
  81. flowfile/web/static/assets/{UnavailableFields-8b0cb48e.js → UnavailableFields-a03f512c.js} +2 -2
  82. flowfile/web/static/assets/{Union-8d9ac7f9.css → Union-af6c3d9b.css} +6 -6
  83. flowfile/web/static/assets/Union-bfe9b996.js +77 -0
  84. flowfile/web/static/assets/{Unique-af5a80b4.js → Unique-5d023a27.js} +23 -104
  85. flowfile/web/static/assets/{Sort-7ccfa0fe.css → Unique-f9fb0809.css} +8 -8
  86. flowfile/web/static/assets/Unpivot-1e422df3.css +30 -0
  87. flowfile/web/static/assets/{Unpivot-5195d411.js → Unpivot-91cc5354.js} +12 -166
  88. flowfile/web/static/assets/UnpivotValidation-0d240eeb.css +13 -0
  89. flowfile/web/static/assets/UnpivotValidation-7ee2de44.js +51 -0
  90. flowfile/web/static/assets/{ExploreData-18a4fe52.js → VueGraphicWalker-e51b9924.js} +4 -264
  91. flowfile/web/static/assets/VueGraphicWalker-ed5ab88b.css +6 -0
  92. flowfile/web/static/assets/{api-cb00cce6.js → api-c1bad5ca.js} +1 -1
  93. flowfile/web/static/assets/{api-023d1733.js → api-cf1221f0.js} +1 -1
  94. flowfile/web/static/assets/{designer-2197d782.css → designer-8da3ba3a.css} +859 -201
  95. flowfile/web/static/assets/{designer-6c322d8e.js → designer-9633482a.js} +2297 -733
  96. flowfile/web/static/assets/{documentation-4d1fafe1.js → documentation-ca400224.js} +1 -1
  97. flowfile/web/static/assets/{dropDown-0b46dd77.js → dropDown-614b998d.js} +1 -1
  98. flowfile/web/static/assets/{fullEditor-ec4e4f95.js → fullEditor-f7971590.js} +2 -2
  99. flowfile/web/static/assets/{genericNodeSettings-def5879b.js → genericNodeSettings-4fe5f36b.js} +3 -3
  100. flowfile/web/static/assets/{index-681a3ed0.css → index-50508d4d.css} +8 -0
  101. flowfile/web/static/assets/{index-683fc198.js → index-5429bbf8.js} +208 -31
  102. flowfile/web/static/assets/nodeInput-5d0d6b79.js +41 -0
  103. flowfile/web/static/assets/outputCsv-076b85ab.js +86 -0
  104. flowfile/web/static/assets/{Output-48f81019.css → outputCsv-9cc59e0b.css} +0 -143
  105. flowfile/web/static/assets/outputExcel-0fd17dbe.js +56 -0
  106. flowfile/web/static/assets/outputExcel-b41305c0.css +102 -0
  107. flowfile/web/static/assets/outputParquet-b61e0847.js +31 -0
  108. flowfile/web/static/assets/outputParquet-cf8cf3f2.css +4 -0
  109. flowfile/web/static/assets/readCsv-a8bb8b61.js +179 -0
  110. flowfile/web/static/assets/readCsv-c767cb37.css +52 -0
  111. flowfile/web/static/assets/readExcel-67b4aee0.js +201 -0
  112. flowfile/web/static/assets/readExcel-806d2826.css +64 -0
  113. flowfile/web/static/assets/readParquet-48c81530.css +19 -0
  114. flowfile/web/static/assets/readParquet-92ce1dbc.js +23 -0
  115. flowfile/web/static/assets/{secretApi-baceb6f9.js → secretApi-68435402.js} +1 -1
  116. flowfile/web/static/assets/{selectDynamic-de91449a.js → selectDynamic-92e25ee3.js} +7 -7
  117. flowfile/web/static/assets/{selectDynamic-b062bc9b.css → selectDynamic-aa913ff4.css} +16 -16
  118. flowfile/web/static/assets/user-defined-icon-0ae16c90.png +0 -0
  119. flowfile/web/static/assets/{vue-codemirror.esm-dc5e3348.js → vue-codemirror.esm-41b0e0d7.js} +65 -36
  120. flowfile/web/static/assets/{vue-content-loader.es-ba94b82f.js → vue-content-loader.es-2c8e608f.js} +1 -1
  121. flowfile/web/static/index.html +2 -2
  122. {flowfile-0.3.9.dist-info → flowfile-0.5.1.dist-info}/METADATA +5 -3
  123. {flowfile-0.3.9.dist-info → flowfile-0.5.1.dist-info}/RECORD +191 -121
  124. {flowfile-0.3.9.dist-info → flowfile-0.5.1.dist-info}/WHEEL +1 -1
  125. {flowfile-0.3.9.dist-info → flowfile-0.5.1.dist-info}/entry_points.txt +1 -0
  126. flowfile_core/__init__.py +3 -0
  127. flowfile_core/configs/flow_logger.py +5 -13
  128. flowfile_core/configs/node_store/__init__.py +30 -0
  129. flowfile_core/configs/node_store/nodes.py +383 -99
  130. flowfile_core/configs/node_store/user_defined_node_registry.py +193 -0
  131. flowfile_core/configs/settings.py +2 -1
  132. flowfile_core/database/connection.py +5 -21
  133. flowfile_core/fileExplorer/funcs.py +239 -121
  134. flowfile_core/flowfile/analytics/analytics_processor.py +1 -0
  135. flowfile_core/flowfile/code_generator/code_generator.py +62 -64
  136. flowfile_core/flowfile/flow_data_engine/create/funcs.py +73 -56
  137. flowfile_core/flowfile/flow_data_engine/flow_data_engine.py +77 -86
  138. flowfile_core/flowfile/flow_data_engine/flow_file_column/interface.py +4 -0
  139. flowfile_core/flowfile/flow_data_engine/flow_file_column/main.py +19 -34
  140. flowfile_core/flowfile/flow_data_engine/flow_file_column/type_registry.py +36 -0
  141. flowfile_core/flowfile/flow_data_engine/fuzzy_matching/prepare_for_fuzzy_match.py +23 -23
  142. flowfile_core/flowfile/flow_data_engine/join/utils.py +1 -1
  143. flowfile_core/flowfile/flow_data_engine/join/verify_integrity.py +9 -4
  144. flowfile_core/flowfile/flow_data_engine/subprocess_operations/subprocess_operations.py +212 -86
  145. flowfile_core/flowfile/flow_data_engine/utils.py +2 -0
  146. flowfile_core/flowfile/flow_graph.py +240 -54
  147. flowfile_core/flowfile/flow_node/flow_node.py +48 -13
  148. flowfile_core/flowfile/flow_node/models.py +2 -1
  149. flowfile_core/flowfile/handler.py +24 -5
  150. flowfile_core/flowfile/manage/compatibility_enhancements.py +404 -41
  151. flowfile_core/flowfile/manage/io_flowfile.py +394 -0
  152. flowfile_core/flowfile/node_designer/__init__.py +47 -0
  153. flowfile_core/flowfile/node_designer/_type_registry.py +197 -0
  154. flowfile_core/flowfile/node_designer/custom_node.py +371 -0
  155. flowfile_core/flowfile/node_designer/ui_components.py +277 -0
  156. flowfile_core/flowfile/schema_callbacks.py +17 -10
  157. flowfile_core/flowfile/setting_generator/settings.py +15 -10
  158. flowfile_core/main.py +5 -1
  159. flowfile_core/routes/routes.py +73 -30
  160. flowfile_core/routes/user_defined_components.py +55 -0
  161. flowfile_core/schemas/cloud_storage_schemas.py +0 -2
  162. flowfile_core/schemas/input_schema.py +228 -65
  163. flowfile_core/schemas/output_model.py +5 -2
  164. flowfile_core/schemas/schemas.py +153 -35
  165. flowfile_core/schemas/transform_schema.py +1083 -412
  166. flowfile_core/schemas/yaml_types.py +103 -0
  167. flowfile_core/types.py +156 -0
  168. flowfile_core/utils/validate_setup.py +3 -1
  169. flowfile_frame/__init__.py +3 -1
  170. flowfile_frame/flow_frame.py +31 -24
  171. flowfile_frame/flow_frame_methods.py +12 -9
  172. flowfile_worker/__init__.py +9 -35
  173. flowfile_worker/create/__init__.py +3 -21
  174. flowfile_worker/create/funcs.py +68 -56
  175. flowfile_worker/create/models.py +130 -62
  176. flowfile_worker/main.py +5 -2
  177. flowfile_worker/routes.py +52 -13
  178. shared/__init__.py +15 -0
  179. shared/storage_config.py +258 -0
  180. tools/migrate/README.md +56 -0
  181. tools/migrate/__init__.py +12 -0
  182. tools/migrate/__main__.py +131 -0
  183. tools/migrate/legacy_schemas.py +621 -0
  184. tools/migrate/migrate.py +598 -0
  185. tools/migrate/tests/__init__.py +0 -0
  186. tools/migrate/tests/conftest.py +23 -0
  187. tools/migrate/tests/test_migrate.py +627 -0
  188. tools/migrate/tests/test_migration_e2e.py +1010 -0
  189. tools/migrate/tests/test_node_migrations.py +813 -0
  190. flowfile/web/static/assets/GraphSolver-17fd26db.css +0 -68
  191. flowfile/web/static/assets/Pivot-f415e85f.css +0 -35
  192. flowfile/web/static/assets/Read-80dc1675.css +0 -197
  193. flowfile/web/static/assets/Read-c3b1929c.js +0 -701
  194. flowfile/web/static/assets/RecordCount-4e95f98e.js +0 -122
  195. flowfile/web/static/assets/Union-89fd73dc.js +0 -146
  196. flowfile/web/static/assets/Unpivot-246e9bbd.css +0 -77
  197. flowfile/web/static/assets/nodeTitle-a16db7c3.js +0 -227
  198. flowfile/web/static/assets/nodeTitle-f4b12bcb.css +0 -134
  199. flowfile_core/flowfile/manage/open_flowfile.py +0 -135
  200. {flowfile-0.3.9.dist-info → flowfile-0.5.1.dist-info/licenses}/LICENSE +0 -0
  201. /flowfile_core/flowfile/manage/manage_flowfile.py → /tools/__init__.py +0 -0
@@ -1,10 +1,48 @@
1
- from typing import Optional, List, Dict, Tuple, Any, Literal, Annotated
2
- from pydantic import BaseModel, field_validator, ConfigDict, Field, StringConstraints
1
+ from typing import Optional, List, Dict, Tuple, Any, Literal, ClassVar
2
+ from pydantic import BaseModel, field_validator, ConfigDict, Field, ValidationInfo, field_serializer
3
3
  from flowfile_core.flowfile.utils import create_unique_id
4
4
  from flowfile_core.configs.settings import OFFLOAD_TO_WORKER
5
+ from flowfile_core.schemas import input_schema
5
6
  ExecutionModeLiteral = Literal['Development', 'Performance']
6
7
  ExecutionLocationsLiteral = Literal['local', 'remote']
7
8
 
9
+ # Type literals for classifying nodes.
10
+ NodeTypeLiteral = Literal['input', 'output', 'process']
11
+ TransformTypeLiteral = Literal['narrow', 'wide', 'other']
12
+ _custom_node_store_cache = None
13
+
14
+ NODE_TYPE_TO_SETTINGS_CLASS = {
15
+ 'manual_input': input_schema.NodeManualInput,
16
+ 'filter': input_schema.NodeFilter,
17
+ 'formula': input_schema.NodeFormula,
18
+ 'select': input_schema.NodeSelect,
19
+ 'sort': input_schema.NodeSort,
20
+ 'record_id': input_schema.NodeRecordId,
21
+ 'sample': input_schema.NodeSample,
22
+ 'unique': input_schema.NodeUnique,
23
+ 'group_by': input_schema.NodeGroupBy,
24
+ 'pivot': input_schema.NodePivot,
25
+ 'unpivot': input_schema.NodeUnpivot,
26
+ 'text_to_rows': input_schema.NodeTextToRows,
27
+ 'graph_solver': input_schema.NodeGraphSolver,
28
+ 'polars_code': input_schema.NodePolarsCode,
29
+ 'join': input_schema.NodeJoin,
30
+ 'cross_join': input_schema.NodeCrossJoin,
31
+ 'fuzzy_match': input_schema.NodeFuzzyMatch,
32
+ 'record_count': input_schema.NodeRecordCount,
33
+ 'explore_data': input_schema.NodeExploreData,
34
+ 'union': input_schema.NodeUnion,
35
+ 'output': input_schema.NodeOutput,
36
+ 'read': input_schema.NodeRead,
37
+ 'database_reader': input_schema.NodeDatabaseReader,
38
+ 'database_writer': input_schema.NodeDatabaseWriter,
39
+ 'cloud_storage_reader': input_schema.NodeCloudStorageReader,
40
+ 'cloud_storage_writer': input_schema.NodeCloudStorageWriter,
41
+ 'external_source': input_schema.NodeExternalSource,
42
+ 'promise': input_schema.NodePromise,
43
+ 'user_defined': input_schema.UserDefinedNode,
44
+ }
45
+
8
46
 
9
47
  def get_global_execution_location() -> ExecutionLocationsLiteral:
10
48
  """
@@ -18,6 +56,25 @@ def get_global_execution_location() -> ExecutionLocationsLiteral:
18
56
  return "local"
19
57
 
20
58
 
59
+ def _get_custom_node_store():
60
+ """Lazy load CUSTOM_NODE_STORE once and cache it."""
61
+ global _custom_node_store_cache
62
+ if _custom_node_store_cache is None:
63
+ from flowfile_core.configs.node_store import CUSTOM_NODE_STORE
64
+ _custom_node_store_cache = CUSTOM_NODE_STORE
65
+ return _custom_node_store_cache
66
+
67
+
68
+ def get_settings_class_for_node_type(node_type: str):
69
+ """Get the settings class for a node type, supporting both standard and user-defined nodes."""
70
+ model_class = NODE_TYPE_TO_SETTINGS_CLASS.get(node_type)
71
+ if model_class is None:
72
+ if node_type in _get_custom_node_store():
73
+ return input_schema.UserDefinedNode
74
+ return None
75
+ return model_class
76
+
77
+
21
78
  def is_valid_execution_location_in_current_global_settings(execution_location: ExecutionLocationsLiteral) -> bool:
22
79
  return not (get_global_execution_location() == "local" and execution_location == "remote")
23
80
 
@@ -114,6 +171,60 @@ class RawLogInput(BaseModel):
114
171
  extra: Optional[dict] = None
115
172
 
116
173
 
174
+ class FlowfileSettings(BaseModel):
175
+ """Settings for flowfile serialization (YAML/JSON).
176
+
177
+ Excludes runtime state fields like is_running, is_canceled, modified_on.
178
+ """
179
+ description: Optional[str] = None
180
+ execution_mode: ExecutionModeLiteral = 'Performance'
181
+ execution_location: ExecutionLocationsLiteral = 'local'
182
+ auto_save: bool = False
183
+ show_detailed_progress: bool = True
184
+
185
+
186
+ class FlowfileNode(BaseModel):
187
+ """Node representation for flowfile serialization (YAML/JSON)."""
188
+ id: int
189
+ type: str
190
+ is_start_node: bool = False
191
+ description: Optional[str] = ''
192
+ x_position: Optional[int] = 0
193
+ y_position: Optional[int] = 0
194
+ left_input_id: Optional[int] = None
195
+ right_input_id: Optional[int] = None
196
+ input_ids: Optional[List[int]] = Field(default_factory=list)
197
+ outputs: Optional[List[int]] = Field(default_factory=list)
198
+ setting_input: Optional[Any] = None
199
+
200
+ _setting_input_exclude: ClassVar[set] = {
201
+ 'flow_id', 'node_id', 'pos_x', 'pos_y', 'is_setup',
202
+ 'description', 'user_id', 'is_flow_output', 'is_user_defined',
203
+ 'depending_on_id', 'depending_on_ids'
204
+ }
205
+
206
+ @field_serializer('setting_input')
207
+ def serialize_setting_input(self, value, _info):
208
+ if value is None:
209
+ return None
210
+ if isinstance(value, input_schema.NodePromise):
211
+ return None
212
+ if hasattr(value, 'to_yaml_dict'):
213
+ return value.to_yaml_dict()
214
+ if hasattr(value, 'to_yaml_dict'):
215
+ return value.to_yaml_dict()
216
+ return value.model_dump(exclude=self._setting_input_exclude)
217
+
218
+
219
+ class FlowfileData(BaseModel):
220
+ """Root model for flowfile serialization (YAML/JSON)."""
221
+ flowfile_version: str
222
+ flowfile_id: int
223
+ flowfile_name: str
224
+ flowfile_settings: FlowfileSettings
225
+ nodes: List[FlowfileNode]
226
+
227
+
117
228
  class NodeTemplate(BaseModel):
118
229
  """
119
230
  Defines the template for a node type, specifying its UI and functional characteristics.
@@ -135,56 +246,60 @@ class NodeTemplate(BaseModel):
135
246
  output: int
136
247
  image: str
137
248
  multi: bool = False
249
+ node_type: NodeTypeLiteral
250
+ transform_type: TransformTypeLiteral
138
251
  node_group: str
139
252
  prod_ready: bool = True
140
253
  can_be_start: bool = False
254
+ drawer_title: str = "Node title"
255
+ drawer_intro: str = "Drawer into"
256
+ custom_node: Optional[bool] = False
141
257
 
142
258
 
143
259
  class NodeInformation(BaseModel):
144
260
  """
145
261
  Stores the state and configuration of a specific node instance within a flow.
146
-
147
- Attributes:
148
- id (Optional[int]): The unique ID of the node instance.
149
- type (Optional[str]): The type of the node (e.g., 'join', 'filter').
150
- is_setup (Optional[bool]): Whether the node has been configured.
151
- description (Optional[str]): A user-provided description.
152
- x_position (Optional[int]): The x-coordinate on the canvas.
153
- y_position (Optional[int]): The y-coordinate on the canvas.
154
- left_input_id (Optional[int]): The ID of the node connected to the left input.
155
- right_input_id (Optional[int]): The ID of the node connected to the right input.
156
- input_ids (Optional[List[int]]): A list of IDs for main input nodes.
157
- outputs (Optional[List[int]]): A list of IDs for nodes this node outputs to.
158
- setting_input (Optional[Any]): The specific settings for this node instance.
159
262
  """
160
263
  id: Optional[int] = None
161
264
  type: Optional[str] = None
162
265
  is_setup: Optional[bool] = None
266
+ is_start_node: bool = False
163
267
  description: Optional[str] = ''
164
268
  x_position: Optional[int] = 0
165
269
  y_position: Optional[int] = 0
166
270
  left_input_id: Optional[int] = None
167
271
  right_input_id: Optional[int] = None
168
- input_ids: Optional[List[int]] = [-1]
169
- outputs: Optional[List[int]] = [-1]
272
+ input_ids: Optional[List[int]] = Field(default_factory=list)
273
+ outputs: Optional[List[int]] = Field(default_factory=list)
170
274
  setting_input: Optional[Any] = None
171
275
 
172
276
  @property
173
277
  def data(self) -> Any:
174
- """
175
- Property to access the node's specific settings.
176
- :return: The settings of the node.
177
- """
178
278
  return self.setting_input
179
279
 
180
280
  @property
181
281
  def main_input_ids(self) -> Optional[List[int]]:
182
- """
183
- Property to access the main input node IDs.
184
- :return: A list of main input node IDs.
185
- """
186
282
  return self.input_ids
187
283
 
284
+ @field_validator('setting_input', mode='before')
285
+ @classmethod
286
+ def validate_setting_input(cls, v, info: ValidationInfo):
287
+ if v is None:
288
+ return None
289
+ if isinstance(v, BaseModel):
290
+ return v
291
+
292
+ node_type = info.data.get('type')
293
+ model_class = get_settings_class_for_node_type(node_type)
294
+
295
+ if model_class is None:
296
+ raise ValueError(f"Unknown node type: {node_type}")
297
+
298
+ if isinstance(v, model_class):
299
+ return v
300
+
301
+ return model_class.model_validate(v)
302
+
188
303
 
189
304
  class FlowInformation(BaseModel):
190
305
  """
@@ -215,6 +330,19 @@ class FlowInformation(BaseModel):
215
330
  return str(v) if v is not None else ''
216
331
 
217
332
 
333
+ class NodeConnection(BaseModel):
334
+ """
335
+ Represents a connection between two nodes in the flow.
336
+
337
+ Attributes:
338
+ from_node_id (int): The ID of the source node.
339
+ to_node_id (int): The ID of the target node.
340
+ """
341
+ model_config = ConfigDict(frozen=True)
342
+ from_node_id: int
343
+ to_node_id: int
344
+
345
+
218
346
  class NodeInput(NodeTemplate):
219
347
  """
220
348
  Represents a node as it is received from the frontend, including position.
@@ -261,11 +389,6 @@ class VueFlowInput(BaseModel):
261
389
  node_inputs: List[NodeInput]
262
390
 
263
391
 
264
- # Type literals for classifying nodes.
265
- NodeTypeLiteral = Literal['input', 'output', 'process']
266
- TransformTypeLiteral = Literal['narrow', 'wide', 'other']
267
-
268
-
269
392
  class NodeDefault(BaseModel):
270
393
  """
271
394
  Defines default properties for a node type.
@@ -280,8 +403,3 @@ class NodeDefault(BaseModel):
280
403
  node_type: NodeTypeLiteral
281
404
  transform_type: TransformTypeLiteral
282
405
  has_default_settings: Optional[Any] = None
283
-
284
-
285
- # Define SecretRef here if not in a common location
286
- SecretRef = Annotated[str, StringConstraints(min_length=1, max_length=100),
287
- Field(description="An ID referencing an encrypted secret.")]