@bian-womp/spark-graph 0.3.49 → 0.3.51

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 (173) hide show
  1. package/lib/cjs/index.cjs +129 -108
  2. package/lib/cjs/index.cjs.map +1 -1
  3. package/lib/cjs/src/core/types.d.ts +1 -0
  4. package/lib/cjs/src/core/types.d.ts.map +1 -1
  5. package/lib/cjs/src/runtime/GraphRuntime.d.ts +7 -2
  6. package/lib/cjs/src/runtime/GraphRuntime.d.ts.map +1 -1
  7. package/lib/cjs/src/runtime/LocalEngine.d.ts.map +1 -1
  8. package/lib/cjs/src/runtime/components/EdgePropagator.d.ts.map +1 -1
  9. package/lib/cjs/src/runtime/components/NodeExecutor.d.ts +8 -4
  10. package/lib/cjs/src/runtime/components/NodeExecutor.d.ts.map +1 -1
  11. package/lib/cjs/src/runtime/components/interfaces.d.ts +5 -1
  12. package/lib/cjs/src/runtime/components/interfaces.d.ts.map +1 -1
  13. package/lib/cjs/src/runtime/components/types.d.ts +1 -0
  14. package/lib/cjs/src/runtime/components/types.d.ts.map +1 -1
  15. package/lib/esm/index.js +129 -108
  16. package/lib/esm/index.js.map +1 -1
  17. package/lib/esm/src/core/types.d.ts +1 -0
  18. package/lib/esm/src/core/types.d.ts.map +1 -1
  19. package/lib/esm/src/runtime/GraphRuntime.d.ts +7 -2
  20. package/lib/esm/src/runtime/GraphRuntime.d.ts.map +1 -1
  21. package/lib/esm/src/runtime/LocalEngine.d.ts.map +1 -1
  22. package/lib/esm/src/runtime/components/EdgePropagator.d.ts.map +1 -1
  23. package/lib/esm/src/runtime/components/NodeExecutor.d.ts +8 -4
  24. package/lib/esm/src/runtime/components/NodeExecutor.d.ts.map +1 -1
  25. package/lib/esm/src/runtime/components/interfaces.d.ts +5 -1
  26. package/lib/esm/src/runtime/components/interfaces.d.ts.map +1 -1
  27. package/lib/esm/src/runtime/components/types.d.ts +1 -0
  28. package/lib/esm/src/runtime/components/types.d.ts.map +1 -1
  29. package/package.json +2 -2
  30. package/lib/src/builder/GraphBuilder.d.ts +0 -43
  31. package/lib/src/builder/GraphBuilder.d.ts.map +0 -1
  32. package/lib/src/builder/GraphBuilder.js +0 -284
  33. package/lib/src/builder/GraphBuilder.js.map +0 -1
  34. package/lib/src/builder/Registry.d.ts +0 -93
  35. package/lib/src/builder/Registry.d.ts.map +0 -1
  36. package/lib/src/builder/Registry.js +0 -393
  37. package/lib/src/builder/Registry.js.map +0 -1
  38. package/lib/src/core/categories.d.ts +0 -22
  39. package/lib/src/core/categories.d.ts.map +0 -1
  40. package/lib/src/core/categories.js +0 -2
  41. package/lib/src/core/categories.js.map +0 -1
  42. package/lib/src/core/order.d.ts +0 -7
  43. package/lib/src/core/order.d.ts.map +0 -1
  44. package/lib/src/core/order.js +0 -66
  45. package/lib/src/core/order.js.map +0 -1
  46. package/lib/src/core/type-utils.d.ts +0 -29
  47. package/lib/src/core/type-utils.d.ts.map +0 -1
  48. package/lib/src/core/type-utils.js +0 -97
  49. package/lib/src/core/type-utils.js.map +0 -1
  50. package/lib/src/core/types.d.ts +0 -92
  51. package/lib/src/core/types.d.ts.map +0 -1
  52. package/lib/src/core/types.js +0 -2
  53. package/lib/src/core/types.js.map +0 -1
  54. package/lib/src/examples/arrays.d.ts +0 -5
  55. package/lib/src/examples/arrays.d.ts.map +0 -1
  56. package/lib/src/examples/arrays.js +0 -49
  57. package/lib/src/examples/arrays.js.map +0 -1
  58. package/lib/src/examples/async.d.ts +0 -5
  59. package/lib/src/examples/async.d.ts.map +0 -1
  60. package/lib/src/examples/async.js +0 -91
  61. package/lib/src/examples/async.js.map +0 -1
  62. package/lib/src/examples/progress.d.ts +0 -5
  63. package/lib/src/examples/progress.d.ts.map +0 -1
  64. package/lib/src/examples/progress.js +0 -51
  65. package/lib/src/examples/progress.js.map +0 -1
  66. package/lib/src/examples/run.d.ts +0 -2
  67. package/lib/src/examples/run.d.ts.map +0 -1
  68. package/lib/src/examples/run.js +0 -32
  69. package/lib/src/examples/run.js.map +0 -1
  70. package/lib/src/examples/runMode.d.ts +0 -2
  71. package/lib/src/examples/runMode.d.ts.map +0 -1
  72. package/lib/src/examples/runMode.js +0 -223
  73. package/lib/src/examples/runMode.js.map +0 -1
  74. package/lib/src/examples/shared.d.ts +0 -5
  75. package/lib/src/examples/shared.d.ts.map +0 -1
  76. package/lib/src/examples/shared.js +0 -49
  77. package/lib/src/examples/shared.js.map +0 -1
  78. package/lib/src/examples/simple.d.ts +0 -5
  79. package/lib/src/examples/simple.d.ts.map +0 -1
  80. package/lib/src/examples/simple.js +0 -79
  81. package/lib/src/examples/simple.js.map +0 -1
  82. package/lib/src/examples/snapshot.d.ts +0 -4
  83. package/lib/src/examples/snapshot.d.ts.map +0 -1
  84. package/lib/src/examples/snapshot.js +0 -58
  85. package/lib/src/examples/snapshot.js.map +0 -1
  86. package/lib/src/examples/validation.d.ts +0 -5
  87. package/lib/src/examples/validation.d.ts.map +0 -1
  88. package/lib/src/examples/validation.js +0 -105
  89. package/lib/src/examples/validation.js.map +0 -1
  90. package/lib/src/index.d.ts +0 -27
  91. package/lib/src/index.d.ts.map +0 -1
  92. package/lib/src/index.js +0 -19
  93. package/lib/src/index.js.map +0 -1
  94. package/lib/src/misc/base.d.ts +0 -51
  95. package/lib/src/misc/base.d.ts.map +0 -1
  96. package/lib/src/misc/base.js +0 -1122
  97. package/lib/src/misc/base.js.map +0 -1
  98. package/lib/src/misc/utils/json.d.ts +0 -22
  99. package/lib/src/misc/utils/json.d.ts.map +0 -1
  100. package/lib/src/misc/utils/json.js +0 -239
  101. package/lib/src/misc/utils/json.js.map +0 -1
  102. package/lib/src/misc/utils/merge.d.ts +0 -51
  103. package/lib/src/misc/utils/merge.d.ts.map +0 -1
  104. package/lib/src/misc/utils/merge.js +0 -600
  105. package/lib/src/misc/utils/merge.js.map +0 -1
  106. package/lib/src/plugins/composite.d.ts +0 -22
  107. package/lib/src/plugins/composite.d.ts.map +0 -1
  108. package/lib/src/plugins/composite.js +0 -59
  109. package/lib/src/plugins/composite.js.map +0 -1
  110. package/lib/src/plugins/compute.d.ts +0 -5
  111. package/lib/src/plugins/compute.d.ts.map +0 -1
  112. package/lib/src/plugins/compute.js +0 -39
  113. package/lib/src/plugins/compute.js.map +0 -1
  114. package/lib/src/runtime/Engine.d.ts +0 -28
  115. package/lib/src/runtime/Engine.d.ts.map +0 -1
  116. package/lib/src/runtime/Engine.js +0 -2
  117. package/lib/src/runtime/Engine.js.map +0 -1
  118. package/lib/src/runtime/GraphLifecycleApi.d.ts +0 -46
  119. package/lib/src/runtime/GraphLifecycleApi.d.ts.map +0 -1
  120. package/lib/src/runtime/GraphLifecycleApi.js +0 -2
  121. package/lib/src/runtime/GraphLifecycleApi.js.map +0 -1
  122. package/lib/src/runtime/GraphRuntime.d.ts +0 -94
  123. package/lib/src/runtime/GraphRuntime.d.ts.map +0 -1
  124. package/lib/src/runtime/GraphRuntime.js +0 -729
  125. package/lib/src/runtime/GraphRuntime.js.map +0 -1
  126. package/lib/src/runtime/LocalEngine.d.ts +0 -45
  127. package/lib/src/runtime/LocalEngine.d.ts.map +0 -1
  128. package/lib/src/runtime/LocalEngine.js +0 -89
  129. package/lib/src/runtime/LocalEngine.js.map +0 -1
  130. package/lib/src/runtime/components/EdgePropagator.d.ts +0 -101
  131. package/lib/src/runtime/components/EdgePropagator.d.ts.map +0 -1
  132. package/lib/src/runtime/components/EdgePropagator.js +0 -372
  133. package/lib/src/runtime/components/EdgePropagator.js.map +0 -1
  134. package/lib/src/runtime/components/EventEmitter.d.ts +0 -12
  135. package/lib/src/runtime/components/EventEmitter.d.ts.map +0 -1
  136. package/lib/src/runtime/components/EventEmitter.js +0 -33
  137. package/lib/src/runtime/components/EventEmitter.js.map +0 -1
  138. package/lib/src/runtime/components/Graph.d.ts +0 -211
  139. package/lib/src/runtime/components/Graph.d.ts.map +0 -1
  140. package/lib/src/runtime/components/Graph.js +0 -468
  141. package/lib/src/runtime/components/Graph.js.map +0 -1
  142. package/lib/src/runtime/components/HandleResolver.d.ts +0 -36
  143. package/lib/src/runtime/components/HandleResolver.d.ts.map +0 -1
  144. package/lib/src/runtime/components/HandleResolver.js +0 -231
  145. package/lib/src/runtime/components/HandleResolver.js.map +0 -1
  146. package/lib/src/runtime/components/NodeExecutor.d.ts +0 -110
  147. package/lib/src/runtime/components/NodeExecutor.d.ts.map +0 -1
  148. package/lib/src/runtime/components/NodeExecutor.js +0 -659
  149. package/lib/src/runtime/components/NodeExecutor.js.map +0 -1
  150. package/lib/src/runtime/components/RunContextManager.d.ts +0 -86
  151. package/lib/src/runtime/components/RunContextManager.d.ts.map +0 -1
  152. package/lib/src/runtime/components/RunContextManager.js +0 -302
  153. package/lib/src/runtime/components/RunContextManager.js.map +0 -1
  154. package/lib/src/runtime/components/RuntimeValidatorManager.d.ts +0 -31
  155. package/lib/src/runtime/components/RuntimeValidatorManager.d.ts.map +0 -1
  156. package/lib/src/runtime/components/RuntimeValidatorManager.js +0 -55
  157. package/lib/src/runtime/components/RuntimeValidatorManager.js.map +0 -1
  158. package/lib/src/runtime/components/graph-utils.d.ts +0 -33
  159. package/lib/src/runtime/components/graph-utils.d.ts.map +0 -1
  160. package/lib/src/runtime/components/graph-utils.js +0 -292
  161. package/lib/src/runtime/components/graph-utils.js.map +0 -1
  162. package/lib/src/runtime/components/interfaces.d.ts +0 -54
  163. package/lib/src/runtime/components/interfaces.d.ts.map +0 -1
  164. package/lib/src/runtime/components/interfaces.js +0 -2
  165. package/lib/src/runtime/components/interfaces.js.map +0 -1
  166. package/lib/src/runtime/components/types.d.ts +0 -55
  167. package/lib/src/runtime/components/types.d.ts.map +0 -1
  168. package/lib/src/runtime/components/types.js +0 -2
  169. package/lib/src/runtime/components/types.js.map +0 -1
  170. package/lib/src/runtime/utils.d.ts +0 -67
  171. package/lib/src/runtime/utils.d.ts.map +0 -1
  172. package/lib/src/runtime/utils.js +0 -137
  173. package/lib/src/runtime/utils.js.map +0 -1
@@ -1,1122 +0,0 @@
1
- import { GraphBuilder } from "../builder/GraphBuilder";
2
- import { Registry } from "../builder/Registry";
3
- import { ComputeCategory } from "../plugins/compute";
4
- // Helpers
5
- const asArray = (v) => Array.isArray(v) ? v : [Number(v)];
6
- const broadcast = (a, b) => {
7
- const aa = asArray(a);
8
- const bb = asArray(b);
9
- if (aa.length === bb.length)
10
- return [aa, bb];
11
- if (aa.length === 1)
12
- return [new Array(bb.length).fill(aa[0]), bb];
13
- if (bb.length === 1)
14
- return [aa, new Array(aa.length).fill(bb[0])];
15
- const len = Math.max(aa.length, bb.length);
16
- return [new Array(len).fill(aa[0] ?? 0), new Array(len).fill(bb[0] ?? 0)];
17
- };
18
- const asBoolArray = (v) => Array.isArray(v) ? v.map((x) => Boolean(x)) : [Boolean(v)];
19
- const broadcastBool = (a, b) => {
20
- const aa = asBoolArray(a);
21
- const bb = asBoolArray(b);
22
- if (aa.length === bb.length)
23
- return [aa, bb];
24
- if (aa.length === 1)
25
- return [new Array(bb.length).fill(aa[0]), bb];
26
- if (bb.length === 1)
27
- return [aa, new Array(aa.length).fill(bb[0])];
28
- const len = Math.max(aa.length, bb.length);
29
- return [
30
- new Array(len).fill(aa[0] ?? false),
31
- new Array(len).fill(bb[0] ?? false),
32
- ];
33
- };
34
- const clamp = (x, min, max) => Math.min(max, Math.max(min, x));
35
- const lerp = (a, b, t) => a + (b - a) * t;
36
- const lcg = (seed) => {
37
- let s = seed >>> 0 || 1;
38
- return () => (s = (s * 1664525 + 1013904223) >>> 0) / 0xffffffff;
39
- };
40
- // JSON Pointer helpers (RFC 6901 subset)
41
- function jsonPointerGet(obj, pointer) {
42
- if (!pointer || pointer === "/")
43
- return obj;
44
- if (!pointer.startsWith("/"))
45
- return undefined;
46
- const parts = pointer
47
- .split("/")
48
- .slice(1)
49
- .map((p) => p.replace(/~1/g, "/").replace(/~0/g, "~"));
50
- let cur = obj;
51
- for (const key of parts) {
52
- if (cur === undefined || cur === null)
53
- return undefined;
54
- cur = cur[key];
55
- }
56
- return cur;
57
- }
58
- function jsonPointerSet(obj, pointer, value) {
59
- if (!pointer || pointer === "/")
60
- return value;
61
- if (!pointer.startsWith("/"))
62
- return obj;
63
- const parts = pointer
64
- .split("/")
65
- .slice(1)
66
- .map((p) => p.replace(/~1/g, "/").replace(/~0/g, "~"));
67
- const root = structuredClone(obj);
68
- let cur = root;
69
- for (let i = 0; i < parts.length; i++) {
70
- const key = parts[i];
71
- if (i === parts.length - 1) {
72
- if (Array.isArray(cur) && key === "-")
73
- cur.push(value);
74
- else
75
- cur[key] = value;
76
- }
77
- else {
78
- const next = cur[key];
79
- if (next === undefined || next === null) {
80
- // create container heuristically
81
- const nextKey = parts[i + 1];
82
- cur[key] =
83
- typeof nextKey === "string" && /^[0-9]+$/.test(nextKey) ? [] : {};
84
- }
85
- cur = cur[key];
86
- }
87
- }
88
- return root;
89
- }
90
- function jsonPointerRemove(obj, pointer) {
91
- if (!pointer || pointer === "/")
92
- return undefined;
93
- if (!pointer.startsWith("/"))
94
- return obj;
95
- const parts = pointer
96
- .split("/")
97
- .slice(1)
98
- .map((p) => p.replace(/~1/g, "/").replace(/~0/g, "~"));
99
- const root = structuredClone(obj);
100
- let cur = root;
101
- for (let i = 0; i < parts.length - 1; i++) {
102
- const key = parts[i];
103
- if (cur === undefined || cur === null)
104
- return root;
105
- cur = cur[key];
106
- }
107
- const last = parts[parts.length - 1];
108
- if (Array.isArray(cur)) {
109
- const idx = last === "-" ? cur.length - 1 : Number(last);
110
- if (Number.isFinite(idx))
111
- cur.splice(idx, 1);
112
- }
113
- else if (cur && typeof cur === "object") {
114
- delete cur[last];
115
- }
116
- return root;
117
- }
118
- function deepMerge(a, b) {
119
- if (Array.isArray(a) && Array.isArray(b))
120
- return [...a, ...b];
121
- if (isPlainObject(a) && isPlainObject(b)) {
122
- const out = { ...a };
123
- for (const [k, v] of Object.entries(b)) {
124
- out[k] = k in out ? deepMerge(out[k], v) : v;
125
- }
126
- return out;
127
- }
128
- return b;
129
- }
130
- // JSON helpers
131
- const isPlainObject = (v) => {
132
- if (v === null || typeof v !== "object")
133
- return false;
134
- const proto = Object.getPrototypeOf(v);
135
- return proto === Object.prototype || proto === null;
136
- };
137
- const isJson = (v) => {
138
- if (v === null)
139
- return true;
140
- const t = typeof v;
141
- if (t === "string" || t === "number" || t === "boolean")
142
- return true;
143
- if (Array.isArray(v))
144
- return v.every(isJson);
145
- if (isPlainObject(v))
146
- return Object.values(v).every(isJson);
147
- return false;
148
- };
149
- // Export operation constants for use in examples and tests
150
- export const BaseMathOperation = {
151
- Add: 0,
152
- Subtract: 1,
153
- Multiply: 2,
154
- Divide: 3,
155
- Min: 4,
156
- Max: 5,
157
- Modulo: 6,
158
- Power: 7,
159
- Round: 8,
160
- Floor: 9,
161
- Ceil: 10,
162
- Abs: 11,
163
- Sum: 12,
164
- Avg: 13,
165
- MinAll: 14,
166
- MaxAll: 15,
167
- Sin: 16,
168
- Cos: 17,
169
- Tan: 18,
170
- Asin: 19,
171
- Acos: 20,
172
- Atan: 21,
173
- Sqrt: 22,
174
- Exp: 23,
175
- Log: 24,
176
- };
177
- export const BaseCompareOperation = {
178
- LessThan: 0,
179
- LessThanOrEqual: 1,
180
- GreaterThan: 2,
181
- GreaterThanOrEqual: 3,
182
- Equal: 4,
183
- NotEqual: 5,
184
- };
185
- export const BaseLogicOperation = {
186
- Not: 0,
187
- And: 1,
188
- Or: 2,
189
- Xor: 3,
190
- };
191
- export function setupBasicGraphRegistry(id) {
192
- const registry = new Registry(id);
193
- registry.categories.register(ComputeCategory);
194
- registry.registerType({
195
- id: "base.float",
196
- validate: (v) => typeof v === "number" && !Number.isNaN(v),
197
- bakeTarget: { nodeTypeId: "base.input.number", inputHandle: "Value" },
198
- }, { withArray: true, arrayPickFirstDefined: true });
199
- registry.registerType({
200
- id: "base.bool",
201
- validate: (v) => typeof v === "boolean",
202
- bakeTarget: { nodeTypeId: "base.input.bool", inputHandle: "Value" },
203
- }, { withArray: true, arrayPickFirstDefined: true });
204
- registry.registerType({
205
- id: "base.string",
206
- validate: (v) => typeof v === "string",
207
- bakeTarget: { nodeTypeId: "base.input.string", inputHandle: "Value" },
208
- }, { withArray: true, arrayPickFirstDefined: true });
209
- // Generic object value (JSON-compatible; object/array/primitive/null)
210
- registry.registerType({
211
- id: "base.object",
212
- validate: (v) => isJson(v),
213
- bakeTarget: { nodeTypeId: "base.input.object", inputHandle: "Value" },
214
- }, { withArray: false });
215
- registry.registerType({
216
- id: "base.vec3",
217
- validate: (v) => Array.isArray(v) &&
218
- v.length === 3 &&
219
- v.every((x) => typeof x === "number"),
220
- bakeTarget: { nodeTypeId: "base.input.vec3", inputHandle: "Value" },
221
- }, { withArray: true, arrayPickFirstDefined: true });
222
- // float -> vec3 : map x to [x,0,0]
223
- registry.registerCoercion("base.float", "base.vec3", (v) => {
224
- return [Number(v) || 0, 0, 0];
225
- });
226
- registry.registerCoercion("base.vec3", "base.float", (value) => {
227
- const v = value;
228
- return Math.hypot(Number(v[0] ?? 0), Number(v[1] ?? 0), Number(v[2] ?? 0));
229
- });
230
- registry.registerCoercion("base.bool", "base.float", (v) => (v ? 1 : 0));
231
- registry.registerCoercion("base.float", "base.bool", (v) => !!v);
232
- registry.registerCoercion("base.float", "base.string", (v) => String(v));
233
- registry.registerCoercion("base.string", "base.float", (v) => Number(v));
234
- // Object <-> String
235
- registry.registerCoercion("base.string", "base.object", (v) => {
236
- return v;
237
- });
238
- registry.registerCoercion("base.object", "base.string", (v) => {
239
- if (typeof v === "string")
240
- return v;
241
- return undefined;
242
- });
243
- registry.registerCoercion("base.bool", "base.object", (v) => {
244
- return v;
245
- });
246
- registry.registerCoercion("base.object", "base.bool", (v) => {
247
- if (typeof v === "boolean")
248
- return v;
249
- return undefined;
250
- });
251
- registry.registerCoercion("base.float", "base.object", (v) => {
252
- return v;
253
- });
254
- registry.registerCoercion("base.object", "base.float", (v) => {
255
- if (typeof v === "number")
256
- return v;
257
- return undefined;
258
- });
259
- registry.registerCoercion("base.vec3", "base.object", (v) => {
260
- return v;
261
- });
262
- registry.registerCoercion("base.object", "base.vec3", (v) => {
263
- try {
264
- if (Array.isArray(v) &&
265
- v.length === 3 &&
266
- v.every((x) => typeof x === "number")) {
267
- return v;
268
- }
269
- return undefined;
270
- }
271
- catch {
272
- return undefined;
273
- }
274
- });
275
- // Enums: Math Operation
276
- registry.registerEnum({
277
- id: "enum:base.math.operation",
278
- options: Object.entries(BaseMathOperation).map(([label, value]) => ({
279
- value,
280
- label,
281
- })),
282
- });
283
- // Enums: Compare Operation
284
- registry.registerEnum({
285
- id: "enum:base.compare.operation",
286
- options: Object.entries(BaseCompareOperation).map(([label, value]) => ({
287
- value,
288
- label,
289
- })),
290
- });
291
- // Enums: Logic Operation
292
- registry.registerEnum({
293
- id: "enum:base.logic.operation",
294
- options: Object.entries(BaseLogicOperation).map(([label, value]) => ({
295
- value,
296
- label,
297
- })),
298
- });
299
- // Number
300
- registry.registerNode({
301
- id: "base.input.number",
302
- categoryId: "compute",
303
- inputs: { Value: "base.float" },
304
- outputs: { Result: "base.float" },
305
- policy: { autoRun: true },
306
- impl: (ins) => ({ Result: Number(ins.Value) }),
307
- });
308
- registry.registerNode({
309
- id: "base.input.string",
310
- categoryId: "compute",
311
- inputs: { Value: "base.string" },
312
- outputs: { Result: "base.string" },
313
- policy: { autoRun: true },
314
- impl: (ins) => ({ Result: String(ins.Value) }),
315
- });
316
- registry.registerNode({
317
- id: "base.input.bool",
318
- categoryId: "compute",
319
- inputs: { Value: "base.bool" },
320
- outputs: { Result: "base.bool" },
321
- policy: { autoRun: true },
322
- impl: (ins) => ({ Result: Boolean(ins.Value) }),
323
- });
324
- registry.registerNode({
325
- id: "base.input.object",
326
- categoryId: "compute",
327
- inputs: { Value: "base.object" },
328
- outputs: { Result: "base.object" },
329
- policy: { autoRun: true },
330
- impl: (ins) => ({ Result: ins.Value }),
331
- });
332
- registry.registerNode({
333
- id: "base.input.vec3",
334
- categoryId: "compute",
335
- inputs: { Value: "base.vec3" },
336
- outputs: { Result: "base.vec3" },
337
- policy: { autoRun: true },
338
- impl: (ins) => ({ Result: ins.Value }),
339
- });
340
- // JSON parser node: base.stringToObject
341
- registry.registerNode({
342
- id: "base.string.toObject",
343
- categoryId: "compute",
344
- inputs: { Text: "base.string" },
345
- outputs: { Object: "base.object" },
346
- impl: (ins) => {
347
- const t = ins.Text ?? "";
348
- try {
349
- const obj = JSON.parse(t);
350
- return { Object: obj };
351
- }
352
- catch {
353
- return { Object: undefined };
354
- }
355
- },
356
- });
357
- registry.registerNode({
358
- id: "base.object.toString",
359
- categoryId: "compute",
360
- inputs: { Object: "base.object" },
361
- outputs: { Text: "base.string" },
362
- impl: (ins) => {
363
- return { Text: JSON.stringify(ins.Object) };
364
- },
365
- });
366
- // Clamp
367
- registry.registerNode({
368
- id: "base.clamp",
369
- categoryId: "compute",
370
- inputs: { Value: "base.float[]", Min: "base.float", Max: "base.float" },
371
- outputs: { Value: "base.float[]" },
372
- impl: (ins) => {
373
- const vals = asArray(ins.Value);
374
- const min = Number(ins.Min ?? 0);
375
- const max = Number(ins.Max ?? 1);
376
- return { Value: vals.map((v) => clamp(Number(v), min, max)) };
377
- },
378
- });
379
- // Interpolate (lerp)
380
- registry.registerNode({
381
- id: "base.interpolate",
382
- categoryId: "compute",
383
- inputs: {
384
- ValueA: "base.float[]",
385
- ValueB: "base.float[]",
386
- Factor: "base.float",
387
- },
388
- outputs: { Value: "base.float[]" },
389
- inputDefaults: {
390
- Factor: 0.5,
391
- },
392
- impl: (ins) => {
393
- const [a, b] = broadcast(ins.ValueA, ins.ValueB);
394
- const t = Number(ins.Factor ?? 0);
395
- const len = Math.max(a.length, b.length);
396
- const out = new Array(len)
397
- .fill(0)
398
- .map((_, i) => lerp(Number(a[i] ?? 0), Number(b[i] ?? 0), t));
399
- return { Value: out };
400
- },
401
- });
402
- // Map Range (linear)
403
- registry.registerNode({
404
- id: "base.mapRange",
405
- categoryId: "compute",
406
- inputs: {
407
- Mode: "base.string",
408
- Clamp: "base.bool",
409
- Value: "base.float[]",
410
- FromMin: "base.float",
411
- FromMax: "base.float",
412
- ToMin: "base.float",
413
- ToMax: "base.float",
414
- },
415
- outputs: { Value: "base.float[]" },
416
- impl: (ins) => {
417
- const vals = asArray(ins.Value);
418
- const fromMin = Number(ins.FromMin ?? 0);
419
- const fromMax = Number(ins.FromMax ?? 1);
420
- const toMin = Number(ins.ToMin ?? 0);
421
- const toMax = Number(ins.ToMax ?? 1);
422
- const doClamp = Boolean(ins.Clamp);
423
- const out = vals.map((v) => {
424
- const t = (Number(v) - fromMin) / (fromMax - fromMin || 1);
425
- const r = toMin + t * (toMax - toMin);
426
- return doClamp
427
- ? clamp(r, Math.min(toMin, toMax), Math.max(toMin, toMax))
428
- : r;
429
- });
430
- return { Value: out };
431
- },
432
- });
433
- // Math (subset) - scalar version for simple examples
434
- registry.registerNode({
435
- id: "base.math",
436
- categoryId: "compute",
437
- inputs: {
438
- Operation: "enum:base.math.operation",
439
- A: "base.float[]",
440
- B: "base.float[]",
441
- },
442
- outputs: { Result: "base.float[]" },
443
- // Registry-level defaults: Add by default, A=[1], B=[1]
444
- inputDefaults: { Operation: 0, A: [1], B: [1] },
445
- impl: (ins) => {
446
- const a = asArray(ins.A ?? []);
447
- const b = asArray(ins.B ?? []);
448
- const op = Number(ins.Operation ?? BaseMathOperation.Add);
449
- const unaryByOp = {
450
- [BaseMathOperation.Round]: (x) => Math.round(x),
451
- [BaseMathOperation.Floor]: (x) => Math.floor(x),
452
- [BaseMathOperation.Ceil]: (x) => Math.ceil(x),
453
- [BaseMathOperation.Abs]: (x) => Math.abs(x),
454
- [BaseMathOperation.Sin]: (x) => Math.sin(x),
455
- [BaseMathOperation.Cos]: (x) => Math.cos(x),
456
- [BaseMathOperation.Tan]: (x) => Math.tan(x),
457
- [BaseMathOperation.Asin]: (x) => Math.asin(x),
458
- [BaseMathOperation.Acos]: (x) => Math.acos(x),
459
- [BaseMathOperation.Atan]: (x) => Math.atan(x),
460
- [BaseMathOperation.Sqrt]: (x) => Math.sqrt(x),
461
- [BaseMathOperation.Exp]: (x) => Math.exp(x),
462
- [BaseMathOperation.Log]: (x) => Math.log(x),
463
- };
464
- if (unaryByOp[op])
465
- return { Result: a.map((x) => unaryByOp[op](Number(x))) };
466
- const aggregateByOp = {
467
- [BaseMathOperation.Sum]: (arr) => arr.reduce((s, x) => s + Number(x || 0), 0),
468
- [BaseMathOperation.Avg]: (arr) => {
469
- const sum = arr.reduce((s, x) => s + Number(x || 0), 0);
470
- return arr.length ? sum / arr.length : 0;
471
- },
472
- [BaseMathOperation.MinAll]: (arr) => arr.length ? Math.min(...arr.map((x) => Number(x))) : 0,
473
- [BaseMathOperation.MaxAll]: (arr) => arr.length ? Math.max(...arr.map((x) => Number(x))) : 0,
474
- };
475
- if (aggregateByOp[op] !== undefined)
476
- return { Result: [aggregateByOp[op](a)] };
477
- const binaryByOp = {
478
- [BaseMathOperation.Add]: (x, y) => x + y,
479
- [BaseMathOperation.Subtract]: (x, y) => x - y,
480
- [BaseMathOperation.Multiply]: (x, y) => x * y,
481
- [BaseMathOperation.Divide]: (x, y) => x / (y || 1),
482
- [BaseMathOperation.Min]: (x, y) => Math.min(x, y),
483
- [BaseMathOperation.Max]: (x, y) => Math.max(x, y),
484
- [BaseMathOperation.Modulo]: (x, y) => (y ? x % y : 0),
485
- [BaseMathOperation.Power]: (x, y) => Math.pow(x, y),
486
- };
487
- const fn = binaryByOp[op] || binaryByOp[BaseMathOperation.Add];
488
- const len = Math.max(a.length, b.length);
489
- const out = new Array(len).fill(0).map((_, i) => {
490
- const ax = a.length === 1 && len > 1 ? a[0] : a[i] ?? 0;
491
- const bx = b.length === 1 && len > 1 ? b[0] : b[i] ?? 0;
492
- return fn(Number(ax), Number(bx));
493
- });
494
- return { Result: out };
495
- },
496
- });
497
- // Compare
498
- registry.registerNode({
499
- id: "base.compare",
500
- categoryId: "compute",
501
- inputs: {
502
- Operation: "enum:base.compare.operation",
503
- A: "base.float[]",
504
- B: "base.float[]",
505
- },
506
- outputs: { Result: "base.bool[]" },
507
- impl: (ins) => {
508
- const [a, b] = broadcast(ins.A, ins.B);
509
- const op = Number(ins.Operation ?? BaseCompareOperation.Equal);
510
- const compareByOp = {
511
- [BaseCompareOperation.LessThan]: (x, y) => x < y,
512
- [BaseCompareOperation.LessThanOrEqual]: (x, y) => x <= y,
513
- [BaseCompareOperation.GreaterThan]: (x, y) => x > y,
514
- [BaseCompareOperation.GreaterThanOrEqual]: (x, y) => x >= y,
515
- [BaseCompareOperation.Equal]: (x, y) => x === y,
516
- [BaseCompareOperation.NotEqual]: (x, y) => x !== y,
517
- };
518
- const fn = compareByOp[op] || compareByOp[BaseCompareOperation.Equal];
519
- return { Result: a.map((x, i) => fn(Number(x), Number(b[i] ?? 0))) };
520
- },
521
- });
522
- // Logic
523
- registry.registerNode({
524
- id: "base.logic",
525
- categoryId: "compute",
526
- inputs: {
527
- Operation: "enum:base.logic.operation",
528
- A: "base.bool[]",
529
- B: "base.bool[]",
530
- },
531
- outputs: { Result: "base.bool[]" },
532
- inputDefaults: { Operation: BaseLogicOperation.Not },
533
- impl: (ins) => {
534
- const op = Number(ins.Operation ?? BaseLogicOperation.Not);
535
- if (op === BaseLogicOperation.Not) {
536
- const a = asBoolArray(ins.A ?? []);
537
- return { Result: a.map((x) => !x) };
538
- }
539
- const [a, b] = broadcastBool(ins.A ?? [], ins.B ?? []);
540
- const logicByOp = {
541
- [BaseLogicOperation.And]: (x, y) => x && y,
542
- [BaseLogicOperation.Or]: (x, y) => x || y,
543
- [BaseLogicOperation.Xor]: (x, y) => Boolean(x ? !y : y),
544
- };
545
- const fn = logicByOp[op] || logicByOp[BaseLogicOperation.And];
546
- return {
547
- Result: a.map((x, i) => fn(Boolean(x), Boolean(b[i] ?? false))),
548
- };
549
- },
550
- });
551
- // Strings
552
- registry.registerNode({
553
- id: "base.string.length",
554
- categoryId: "compute",
555
- inputs: { Text: "base.string" },
556
- outputs: { Length: "base.float" },
557
- impl: (ins) => ({
558
- Length: String(ins.Text || "").length,
559
- }),
560
- });
561
- registry.registerNode({
562
- id: "base.string.op",
563
- categoryId: "compute",
564
- inputs: { Op: "base.string", Text: "base.string" },
565
- outputs: { Text: "base.string" },
566
- impl: (ins) => {
567
- const op = String(ins.Op || "trim").toLowerCase();
568
- const t = String(ins.Text || "");
569
- if (op === "lower")
570
- return { Text: t.toLowerCase() };
571
- if (op === "upper")
572
- return { Text: t.toUpperCase() };
573
- return { Text: t.trim() };
574
- },
575
- });
576
- registry.registerNode({
577
- id: "base.string.split",
578
- categoryId: "compute",
579
- inputs: { Text: "base.string", Sep: "base.string" },
580
- outputs: { Parts: "base.string[]" },
581
- impl: (ins) => {
582
- const t = String(ins.Text || "");
583
- const sep = String(ins.Sep || ",");
584
- return { Parts: t.split(sep) };
585
- },
586
- });
587
- registry.registerNode({
588
- id: "base.string.join",
589
- categoryId: "compute",
590
- inputs: { Parts: "base.string[]", Sep: "base.string" },
591
- outputs: { Text: "base.string" },
592
- impl: (ins) => {
593
- const parts = Array.isArray(ins.Parts) ? ins.Parts.map(String) : [];
594
- const sep = String(ins.Sep || "");
595
- return { Text: parts.join(sep) };
596
- },
597
- });
598
- registry.registerNode({
599
- id: "base.string.replace",
600
- categoryId: "compute",
601
- inputs: {
602
- Text: "base.string",
603
- Search: "base.string",
604
- Replace: "base.string",
605
- },
606
- outputs: { Text: "base.string" },
607
- impl: (ins) => {
608
- const t = String(ins.Text || "");
609
- const s = String(ins.Search || "");
610
- const r = String(ins.Replace || "");
611
- return { Text: t.split(s).join(r) };
612
- },
613
- });
614
- // Arrays (carried as base.object)
615
- registry.registerNode({
616
- id: "base.array.length",
617
- categoryId: "compute",
618
- inputs: { Items: "base.object" },
619
- outputs: { Length: "base.float" },
620
- impl: (ins) => ({
621
- Length: Array.isArray(ins.Items) ? ins.Items.length : 0,
622
- }),
623
- });
624
- registry.registerNode({
625
- id: "base.array.slice",
626
- categoryId: "compute",
627
- inputs: { Items: "base.object", Start: "base.float", End: "base.float" },
628
- outputs: { Result: "base.object" },
629
- impl: (ins) => {
630
- const arr = Array.isArray(ins.Items) ? ins.Items : [];
631
- const s = Math.trunc(Number(ins.Start ?? 0));
632
- const e = Number.isFinite(Number(ins.End))
633
- ? Math.trunc(Number(ins.End))
634
- : undefined;
635
- return { Result: arr.slice(s, e) };
636
- },
637
- });
638
- // Compose array from dynamic item inputs
639
- registry.registerNode({
640
- id: "base.array.compose",
641
- categoryId: "compute",
642
- inputs: { Length: "base.float" },
643
- outputs: { Items: "base.object" },
644
- resolveHandles: ({ inputs }) => {
645
- const maxLen = 64;
646
- const raw = inputs?.Length ?? 0;
647
- const n = Math.max(0, Math.min(maxLen, Math.trunc(Number(raw ?? 0))));
648
- if (!Number.isFinite(n))
649
- return { inputs: {} };
650
- const dyn = {};
651
- for (let i = 0; i < n; i++)
652
- dyn[`Item${i}`] = { typeId: "base.object" };
653
- return { inputs: dyn };
654
- },
655
- inputDefaults: { Length: 0 },
656
- impl: (ins) => {
657
- const length = Math.max(0, Math.trunc(Number(ins.Length ?? 0)));
658
- if (!Number.isFinite(length))
659
- return { Items: [] };
660
- return { Items: Array.from({ length }, (_, i) => ins[`Item${i}`]) };
661
- },
662
- });
663
- // Decompose array into dynamic item outputs
664
- registry.registerNode({
665
- id: "base.array.decompose",
666
- categoryId: "compute",
667
- inputs: { Items: "base.object" },
668
- outputs: {},
669
- resolveHandles: ({ inputs }) => {
670
- const maxLen = 64;
671
- const arr = Array.isArray(inputs?.Items) ? inputs?.Items : [];
672
- const n = Math.max(0, Math.min(maxLen, arr.length));
673
- const dyn = {};
674
- for (let i = 0; i < n; i++)
675
- dyn[`Item${i}`] = "base.object";
676
- return { outputs: dyn };
677
- },
678
- impl: (ins) => {
679
- const arr = Array.isArray(ins.Items) ? ins.Items : [];
680
- const out = {};
681
- const n = Math.max(0, Math.min(64, arr.length));
682
- for (let i = 0; i < n; i++)
683
- out[`Item${i}`] = arr[i];
684
- return out;
685
- },
686
- });
687
- // Select
688
- registry.registerNode({
689
- id: "base.select",
690
- categoryId: "compute",
691
- inputs: { Cond: "base.bool", Then: "base.object", Else: "base.object" },
692
- outputs: { Result: "base.object" },
693
- impl: (ins) => ({
694
- Result: ins.Cond ? ins.Then : ins.Else,
695
- }),
696
- });
697
- // Combine XYZ
698
- registry.registerNode({
699
- id: "base.compareXYZ",
700
- categoryId: "compute",
701
- inputs: { X: "base.float[]", Y: "base.float[]", Z: "base.float[]" },
702
- outputs: { XYZ: "base.vec3[]" },
703
- impl: (ins) => {
704
- const [x, y] = broadcast(ins.X, ins.Y);
705
- const [xx, z] = broadcast(x, ins.Z);
706
- const len = Math.max(xx.length, z.length);
707
- const out = new Array(len)
708
- .fill(0)
709
- .map((_, i) => [Number(xx[i] ?? 0), Number(y[i] ?? 0), Number(z[i] ?? 0)]);
710
- return { XYZ: out };
711
- },
712
- });
713
- // Separate XYZ
714
- registry.registerNode({
715
- id: "base.separateXYZ",
716
- categoryId: "compute",
717
- inputs: { XYZ: "base.vec3[]" },
718
- outputs: { X: "base.float[]", Y: "base.float[]", Z: "base.float[]" },
719
- impl: (ins) => {
720
- const arr = ins.XYZ ?? [];
721
- const X = arr.map((v) => Number(v?.[0] ?? 0));
722
- const Y = arr.map((v) => Number(v?.[1] ?? 0));
723
- const Z = arr.map((v) => Number(v?.[2] ?? 0));
724
- return { X, Y, Z };
725
- },
726
- });
727
- // Indices
728
- registry.registerNode({
729
- id: "base.indices",
730
- categoryId: "compute",
731
- inputs: { Domain: "base.float" },
732
- outputs: { Indices: "base.float[]" },
733
- impl: (ins) => {
734
- const n = Math.trunc(ins.Domain);
735
- return { Indices: Array.from({ length: n }, (_, i) => i) };
736
- },
737
- });
738
- // Random Numbers
739
- registry.registerNode({
740
- id: "base.randomNumbers",
741
- categoryId: "compute",
742
- inputs: {
743
- Domain: "base.float",
744
- Min: "base.float",
745
- Max: "base.float",
746
- Seed: "base.float",
747
- },
748
- outputs: { Values: "base.float[]" },
749
- impl: (ins) => {
750
- const len = Math.trunc(ins.Domain);
751
- const min = Number(ins.Min ?? 0);
752
- const max = Number(ins.Max ?? 1);
753
- const rng = lcg(Number(ins.Seed ?? 1));
754
- const out = Array.from({ length: len }, () => min + rng() * (max - min));
755
- return { Values: out };
756
- },
757
- });
758
- // Random Vectors
759
- registry.registerNode({
760
- id: "base.randomXYZs",
761
- categoryId: "compute",
762
- inputs: {
763
- Domain: "base.float",
764
- Min: "base.vec3",
765
- Max: "base.vec3",
766
- Seed: "base.float",
767
- },
768
- outputs: { Values: "base.vec3[]" },
769
- // Registry-level defaults for convenience
770
- inputDefaults: { Domain: 10, Min: [0, 0, 0], Max: [1, 1, 1], Seed: 1 },
771
- impl: (ins) => {
772
- const len = Math.trunc(ins.Domain);
773
- const min = ins.Min ?? [0, 0, 0];
774
- const max = ins.Max ?? [1, 1, 1];
775
- const rng = lcg(Number(ins.Seed ?? 1));
776
- const out = Array.from({ length: len }, () => [
777
- min[0] + rng() * (max[0] - min[0]),
778
- min[1] + rng() * (max[1] - min[1]),
779
- min[2] + rng() * (max[2] - min[2]),
780
- ]);
781
- return { Values: out };
782
- },
783
- });
784
- // Timer
785
- registry.registerNode({
786
- id: "base.timer",
787
- categoryId: "compute",
788
- inputs: {
789
- Enabled: "base.bool",
790
- IntervalMs: "base.float",
791
- Immediate: "base.bool",
792
- },
793
- outputs: { Now: "base.float", Count: "base.float" },
794
- inputDefaults: { Enabled: true, IntervalMs: 1000, Immediate: true },
795
- impl: (ins, ctx) => {
796
- const enabled = Boolean(ins.Enabled);
797
- const intervalMs = Math.max(1, Math.trunc(Number(ins.IntervalMs ?? 1000)));
798
- const immediate = Boolean(ins.Immediate);
799
- const stop = () => {
800
- const id = ctx.state.timerId;
801
- if (id !== undefined) {
802
- clearInterval(id);
803
- ctx.setState({ timerId: undefined });
804
- }
805
- };
806
- if (!enabled) {
807
- stop();
808
- return;
809
- }
810
- // restart timer with new settings
811
- stop();
812
- let count = 0;
813
- if (immediate) {
814
- ctx.emit("Now", Date.now());
815
- ctx.emit("Count", count);
816
- count += 1;
817
- }
818
- const id = setInterval(() => {
819
- ctx.emit("Now", Date.now());
820
- ctx.emit("Count", count);
821
- count += 1;
822
- }, intervalMs);
823
- ctx.setState({ timerId: id });
824
- },
825
- lifecycle: {
826
- dispose: (ctx) => {
827
- const id = ctx.state.timerId;
828
- if (id !== undefined) {
829
- clearInterval(id);
830
- ctx.setState({ timerId: undefined });
831
- }
832
- },
833
- },
834
- });
835
- // ------------------------- JSON/object utilities -------------------------
836
- registry.registerNode({
837
- id: "base.object.get",
838
- categoryId: "compute",
839
- inputs: { Object: "base.object", Pointers: "base.string[]" },
840
- outputs: { Values: "base.object" },
841
- impl: (ins) => {
842
- const obj = ins.Object;
843
- const pointers = (ins.Pointers || []).map(String);
844
- const out = {};
845
- for (const p of pointers)
846
- out[p] = jsonPointerGet(obj, p);
847
- return { Values: out };
848
- },
849
- });
850
- registry.registerNode({
851
- id: "base.object.set",
852
- categoryId: "compute",
853
- inputs: {
854
- Object: "base.object",
855
- Pointers: "base.string[]",
856
- NewValues: "base.object",
857
- },
858
- outputs: { Result: "base.object" },
859
- impl: (ins) => {
860
- const pointers = (ins.Pointers || []).map(String);
861
- const values = (ins.NewValues || []).map(String);
862
- let cur = structuredClone(ins.Object);
863
- for (let i = 0; i < pointers.length; i++) {
864
- const p = pointers[i];
865
- const raw = values[i];
866
- let val = raw;
867
- if (typeof raw === "string") {
868
- try {
869
- val = JSON.parse(raw);
870
- }
871
- catch {
872
- /* keep as string */
873
- }
874
- }
875
- cur = jsonPointerSet(cur, p, val);
876
- }
877
- return { Result: cur };
878
- },
879
- });
880
- registry.registerNode({
881
- id: "base.object.remove",
882
- categoryId: "compute",
883
- inputs: { Object: "base.object", Pointers: "base.string[]" },
884
- outputs: { Result: "base.object" },
885
- impl: (ins) => {
886
- const pointers = (ins.Pointers || []).map(String);
887
- let cur = structuredClone(ins.Object);
888
- for (const p of pointers)
889
- cur = jsonPointerRemove(cur, p);
890
- return { Result: cur };
891
- },
892
- });
893
- registry.registerNode({
894
- id: "base.object.merge",
895
- categoryId: "compute",
896
- inputs: { A: "base.object", B: "base.object" },
897
- outputs: { Result: "base.object" },
898
- impl: (ins) => ({
899
- Result: deepMerge(ins.A, ins.B),
900
- }),
901
- });
902
- registry.registerNode({
903
- id: "base.object.keys",
904
- categoryId: "compute",
905
- inputs: { Object: "base.object" },
906
- outputs: { Keys: "base.string[]" },
907
- impl: (ins) => {
908
- const obj = ins.Object;
909
- const keys = isPlainObject(obj)
910
- ? Object.keys(obj)
911
- : Array.isArray(obj)
912
- ? Object.keys(obj)
913
- : [];
914
- return { Keys: keys };
915
- },
916
- });
917
- registry.registerNode({
918
- id: "base.object.values",
919
- categoryId: "compute",
920
- inputs: { Object: "base.object" },
921
- outputs: { Values: "base.object" },
922
- impl: (ins) => {
923
- const obj = ins.Object;
924
- const vals = isPlainObject(obj)
925
- ? Object.values(obj)
926
- : Array.isArray(obj)
927
- ? Object.values(obj)
928
- : [];
929
- return { Values: vals };
930
- },
931
- });
932
- registry.registerNode({
933
- id: "base.object.patch",
934
- categoryId: "compute",
935
- inputs: { Object: "base.object", Ops: "base.object" },
936
- outputs: { Result: "base.object" },
937
- impl: (ins) => {
938
- const root = structuredClone(ins.Object);
939
- const opsRaw = ins.Ops;
940
- const ops = Array.isArray(opsRaw)
941
- ? opsRaw
942
- : opsRaw
943
- ? [opsRaw]
944
- : [];
945
- let cur = root;
946
- for (const op of ops) {
947
- if (!op || typeof op !== "object")
948
- continue;
949
- const kind = String(op.op || "");
950
- const path = String(op.path || "");
951
- if (kind === "add" || kind === "replace") {
952
- cur = jsonPointerSet(cur, path, op.value);
953
- }
954
- else if (kind === "remove") {
955
- cur = jsonPointerRemove(cur, path);
956
- }
957
- else if (kind === "test") {
958
- const got = jsonPointerGet(cur, path);
959
- const expected = op.value;
960
- const ok = JSON.stringify(got) === JSON.stringify(expected);
961
- if (!ok)
962
- throw new Error(`objectPatch test failed at ${path}`);
963
- }
964
- }
965
- return { Result: cur };
966
- },
967
- });
968
- registry.registerNode({
969
- id: "base.array.concat",
970
- categoryId: "compute",
971
- inputs: { A: "base.object", B: "base.object" },
972
- outputs: { Result: "base.object" },
973
- impl: (ins) => {
974
- const a = Array.isArray(ins.A) ? ins.A : [];
975
- const b = Array.isArray(ins.B) ? ins.B : [];
976
- return { Result: [...a, ...b] };
977
- },
978
- });
979
- registry.registerNode({
980
- id: "base.array.flatten",
981
- categoryId: "compute",
982
- inputs: { Objects: "base.object" },
983
- outputs: { Result: "base.object" },
984
- impl: (ins) => {
985
- const arr = Array.isArray(ins.Objects) ? ins.Objects : [];
986
- const out = [];
987
- for (const v of arr) {
988
- if (Array.isArray(v))
989
- out.push(...v);
990
- else
991
- out.push(v);
992
- }
993
- return { Result: out };
994
- },
995
- });
996
- registry.registerNode({
997
- id: "base.array.sortBy",
998
- categoryId: "compute",
999
- inputs: { Objects: "base.object", Pointers: "base.string[]" },
1000
- outputs: { Result: "base.object" },
1001
- impl: (ins) => {
1002
- const arr = Array.isArray(ins.Objects) ? ins.Objects : [];
1003
- const pointers = (ins.Pointers || []).map(String);
1004
- const out = [...arr].sort((a, b) => {
1005
- for (const p of pointers) {
1006
- const av = jsonPointerGet(a, p);
1007
- const bv = jsonPointerGet(b, p);
1008
- if (av === bv)
1009
- continue;
1010
- if (av === undefined)
1011
- return 1;
1012
- if (bv === undefined)
1013
- return -1;
1014
- if (av < bv)
1015
- return -1;
1016
- if (av > bv)
1017
- return 1;
1018
- }
1019
- return 0;
1020
- });
1021
- return { Result: out };
1022
- },
1023
- });
1024
- return registry;
1025
- }
1026
- export function registerDelayNode(registry) {
1027
- registry.registerNode({
1028
- id: "async.delay",
1029
- categoryId: "compute",
1030
- inputs: { Value: "base.float", DelayMs: "base.float" },
1031
- outputs: { Output: "base.float" },
1032
- impl: async (ins, ctx) => {
1033
- const ms = Number(ins.DelayMs ?? 200);
1034
- const valueRaw = ins.Value;
1035
- if (valueRaw === undefined ||
1036
- valueRaw === null ||
1037
- Number.isNaN(Number(valueRaw))) {
1038
- return; // wait until x is present to avoid NaN emissions
1039
- }
1040
- await new Promise((resolve, reject) => {
1041
- const id = setTimeout(resolve, ms);
1042
- const onAbort = () => {
1043
- clearTimeout(id);
1044
- reject(new DOMException("Aborted", "AbortError"));
1045
- };
1046
- if (ctx.abortSignal.aborted)
1047
- return onAbort();
1048
- ctx.abortSignal.addEventListener("abort", onAbort, { once: true });
1049
- });
1050
- return { Output: Number(valueRaw) };
1051
- },
1052
- });
1053
- }
1054
- function sleepWithAbort(ms, signal) {
1055
- return new Promise((resolve, reject) => {
1056
- const id = setTimeout(() => {
1057
- cleanup();
1058
- resolve();
1059
- }, ms);
1060
- const onAbort = () => {
1061
- clearTimeout(id);
1062
- cleanup();
1063
- reject(new DOMException("Aborted", "AbortError"));
1064
- };
1065
- const cleanup = () => {
1066
- signal.removeEventListener("abort", onAbort);
1067
- };
1068
- if (signal.aborted)
1069
- return onAbort();
1070
- signal.addEventListener("abort", onAbort);
1071
- });
1072
- }
1073
- export function registerProgressNodes(registry) {
1074
- registry.registerNode({
1075
- id: "async.progress",
1076
- categoryId: "compute",
1077
- inputs: {
1078
- Steps: "base.float",
1079
- DelayMs: "base.float",
1080
- ShouldError: "base.bool",
1081
- },
1082
- outputs: { Done: "base.string" },
1083
- impl: async (ins, ctx) => {
1084
- const steps = Math.max(1, Math.trunc(Number(ins.Steps ?? 10)));
1085
- const delayMs = Math.max(0, Math.trunc(Number(ins.DelayMs ?? 50)));
1086
- const shouldError = Boolean(ins.ShouldError);
1087
- for (let i = 0; i < steps; i++) {
1088
- ctx.reportProgress?.(i / steps);
1089
- await sleepWithAbort(delayMs, ctx.abortSignal);
1090
- if (shouldError && i >= Math.floor(steps * 0.7)) {
1091
- ctx.reportProgress?.(i / steps);
1092
- throw new Error("progressWorker: simulated failure at 70% progress");
1093
- }
1094
- }
1095
- ctx.reportProgress?.(1);
1096
- return { Done: `Completed ${steps} steps` };
1097
- },
1098
- });
1099
- }
1100
- export function createRuntime(registry, def, opts) {
1101
- const builder = new GraphBuilder(registry);
1102
- const report = builder.validate(def);
1103
- if (!report.ok)
1104
- throw new Error("Validation failed: " +
1105
- report.issues.map((i) => `${i.code}:${i.message}`).join(", "));
1106
- return builder.build(def, opts);
1107
- }
1108
- export function generateId(prefix, used = new Set()) {
1109
- let id;
1110
- let attempts = 0;
1111
- do {
1112
- id = `${prefix}${Math.random().toString(36).slice(2, 8)}`;
1113
- attempts++;
1114
- if (attempts > 1000) {
1115
- id = `${prefix}${Date.now().toString(36)}${Math.random()
1116
- .toString(36)
1117
- .slice(2, 4)}`;
1118
- }
1119
- } while (used.has(id));
1120
- return id;
1121
- }
1122
- //# sourceMappingURL=base.js.map