@particle-academy/fancy-flow 0.29.1 → 0.31.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.
package/dist/engine.cjs CHANGED
@@ -3,6 +3,21 @@
3
3
  // src/registry/registry.ts
4
4
  var kinds = /* @__PURE__ */ new Map();
5
5
  var aliases = /* @__PURE__ */ new Map();
6
+ var listeners = /* @__PURE__ */ new Set();
7
+ function registerNodeKind(definition) {
8
+ kinds.set(definition.name, definition);
9
+ for (const alias of definition.aliases ?? []) aliases.set(alias, definition.name);
10
+ notify();
11
+ return () => {
12
+ if (kinds.get(definition.name) === definition) {
13
+ kinds.delete(definition.name);
14
+ for (const alias of definition.aliases ?? []) {
15
+ if (aliases.get(alias) === definition.name) aliases.delete(alias);
16
+ }
17
+ notify();
18
+ }
19
+ };
20
+ }
6
21
  function resolveKindId(id) {
7
22
  if (kinds.has(id)) return id;
8
23
  const canonical = aliases.get(id);
@@ -15,6 +30,104 @@ function getNodeKind(name) {
15
30
  function kindIds(kind) {
16
31
  return [kind.name, ...kind.aliases ?? []];
17
32
  }
33
+ function listNodeKinds(category) {
34
+ const all = Array.from(kinds.values());
35
+ return category ? all.filter((k) => k.category === category) : all;
36
+ }
37
+ function notify() {
38
+ for (const l of listeners) l();
39
+ }
40
+ function defaultConfigFor(kind) {
41
+ const fromKind = kind.defaultConfig ? { ...kind.defaultConfig } : {};
42
+ for (const field of kind.configSchema ?? []) {
43
+ if (fromKind[field.key] !== void 0) continue;
44
+ if ("default" in field && field.default !== void 0) {
45
+ fromKind[field.key] = field.default;
46
+ }
47
+ }
48
+ return fromKind;
49
+ }
50
+ function validateConfig(kind, config) {
51
+ const issues = [];
52
+ for (const field of kind.configSchema ?? []) {
53
+ const value = config[field.key];
54
+ if (field.required && (value === void 0 || value === null || value === "")) {
55
+ issues.push({ key: field.key, message: `${field.label} is required` });
56
+ continue;
57
+ }
58
+ if (value === void 0 || value === null) continue;
59
+ const issue = validateField(field, value);
60
+ if (issue) issues.push({ key: field.key, message: issue });
61
+ }
62
+ return issues;
63
+ }
64
+ function validateField(field, value) {
65
+ switch (field.type) {
66
+ case "text":
67
+ case "textarea":
68
+ case "expression":
69
+ case "credential":
70
+ return typeof value === "string" ? null : `${field.label} must be a string`;
71
+ case "number": {
72
+ if (typeof value !== "number" || !Number.isFinite(value)) return `${field.label} must be a number`;
73
+ if (field.min !== void 0 && value < field.min) return `${field.label} must be >= ${field.min}`;
74
+ if (field.max !== void 0 && value > field.max) return `${field.label} must be <= ${field.max}`;
75
+ return null;
76
+ }
77
+ case "switch":
78
+ return typeof value === "boolean" ? null : `${field.label} must be a boolean`;
79
+ case "select": {
80
+ const allowed = field.options.map((o) => o.value);
81
+ return allowed.includes(String(value)) ? null : `${field.label} must be one of ${allowed.join(", ")}`;
82
+ }
83
+ case "json":
84
+ return null;
85
+ // permissive — just JSON-shaped
86
+ case "repeater": {
87
+ if (!Array.isArray(value)) return `${field.label} must be a list`;
88
+ if (field.minItems !== void 0 && value.length < field.minItems) {
89
+ return `${field.label} needs at least ${field.minItems}`;
90
+ }
91
+ if (field.maxItems !== void 0 && value.length > field.maxItems) {
92
+ return `${field.label} allows at most ${field.maxItems}`;
93
+ }
94
+ for (let i = 0; i < value.length; i++) {
95
+ const row = value[i];
96
+ if (!row || typeof row !== "object" || Array.isArray(row)) {
97
+ return `${field.label} item ${i + 1} must be an object`;
98
+ }
99
+ for (const sub of field.fields) {
100
+ const cell = row[sub.key];
101
+ if (sub.required && (cell === void 0 || cell === null || cell === "")) {
102
+ return `${field.label} item ${i + 1}: ${sub.label} is required`;
103
+ }
104
+ if (cell === void 0 || cell === null) continue;
105
+ const issue = validateField(sub, cell);
106
+ if (issue) return `${field.label} item ${i + 1}: ${issue}`;
107
+ }
108
+ }
109
+ return null;
110
+ }
111
+ case "keyvalue": {
112
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
113
+ return `${field.label} must be a key/value map`;
114
+ }
115
+ const allowed = field.valueOptions?.map((o) => o.value);
116
+ for (const [k, v] of Object.entries(value)) {
117
+ if (typeof v !== "string") return `${field.label}: "${k}" must be a string`;
118
+ if (allowed && !allowed.includes(v)) {
119
+ return `${field.label}: "${k}" must be one of ${allowed.join(", ")}`;
120
+ }
121
+ }
122
+ return null;
123
+ }
124
+ case "document":
125
+ return null;
126
+ // opaque to fancy-flow — the host's editor owns its shape
127
+ default:
128
+ return null;
129
+ }
130
+ }
18
131
 
19
132
  // src/registry/ports.ts
20
133
  function resolvePortSpec(spec, config) {
@@ -771,13 +884,20 @@ exports.PAUSE_PREFIX = PAUSE_PREFIX;
771
884
  exports.checkCapabilities = checkCapabilities;
772
885
  exports.checkRuntimeSupport = checkRuntimeSupport;
773
886
  exports.decodePause = decodePause;
887
+ exports.defaultConfigFor = defaultConfigFor;
774
888
  exports.encodePause = encodePause;
889
+ exports.getNodeKind = getNodeKind;
775
890
  exports.isPause = isPause;
891
+ exports.kindIds = kindIds;
892
+ exports.listNodeKinds = listNodeKinds;
776
893
  exports.pauseForHuman = pauseForHuman;
894
+ exports.registerNodeKind = registerNodeKind;
895
+ exports.resolveKindId = resolveKindId;
777
896
  exports.runCohort = runCohort;
778
897
  exports.runFixtures = runFixtures;
779
898
  exports.runFlow = runFlow;
780
899
  exports.satisfiesRange = satisfiesRange;
900
+ exports.validateConfig = validateConfig;
781
901
  exports.validateFixtureFile = validateFixtureFile;
782
902
  exports.validateNodeManifest = validateNodeManifest;
783
903
  //# sourceMappingURL=engine.cjs.map