@bian-womp/spark-graph 0.3.90 → 0.3.92

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