@bian-womp/spark-graph 0.1.15 → 0.1.17
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/lib/cjs/index.cjs +264 -72
- package/lib/cjs/index.cjs.map +1 -1
- package/lib/cjs/src/builder/GraphBuilder.d.ts.map +1 -1
- package/lib/cjs/src/builder/Registry.d.ts +3 -3
- package/lib/cjs/src/builder/Registry.d.ts.map +1 -1
- package/lib/cjs/src/core/types.d.ts +7 -1
- package/lib/cjs/src/core/types.d.ts.map +1 -1
- package/lib/cjs/src/examples/async.d.ts.map +1 -1
- package/lib/cjs/src/examples/engine.d.ts.map +1 -1
- package/lib/cjs/src/examples/progress.d.ts.map +1 -1
- package/lib/cjs/src/examples/shared.d.ts +2 -6
- package/lib/cjs/src/examples/shared.d.ts.map +1 -1
- package/lib/cjs/src/examples/simple.d.ts.map +1 -1
- package/lib/cjs/src/index.d.ts +3 -1
- package/lib/cjs/src/index.d.ts.map +1 -1
- package/lib/cjs/src/misc/base.d.ts +7 -0
- package/lib/cjs/src/misc/base.d.ts.map +1 -0
- package/lib/cjs/src/plugins/composite.d.ts.map +1 -1
- package/lib/cjs/src/runtime/GraphRuntime.d.ts +1 -0
- package/lib/cjs/src/runtime/GraphRuntime.d.ts.map +1 -1
- package/lib/esm/index.js +263 -73
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/src/builder/GraphBuilder.d.ts.map +1 -1
- package/lib/esm/src/builder/Registry.d.ts +3 -3
- package/lib/esm/src/builder/Registry.d.ts.map +1 -1
- package/lib/esm/src/core/types.d.ts +7 -1
- package/lib/esm/src/core/types.d.ts.map +1 -1
- package/lib/esm/src/examples/async.d.ts.map +1 -1
- package/lib/esm/src/examples/engine.d.ts.map +1 -1
- package/lib/esm/src/examples/progress.d.ts.map +1 -1
- package/lib/esm/src/examples/shared.d.ts +2 -6
- package/lib/esm/src/examples/shared.d.ts.map +1 -1
- package/lib/esm/src/examples/simple.d.ts.map +1 -1
- package/lib/esm/src/index.d.ts +3 -1
- package/lib/esm/src/index.d.ts.map +1 -1
- package/lib/esm/src/misc/base.d.ts +7 -0
- package/lib/esm/src/misc/base.d.ts.map +1 -0
- package/lib/esm/src/plugins/composite.d.ts.map +1 -1
- package/lib/esm/src/runtime/GraphRuntime.d.ts +1 -0
- package/lib/esm/src/runtime/GraphRuntime.d.ts.map +1 -1
- package/package.json +1 -1
package/lib/cjs/index.cjs
CHANGED
|
@@ -372,6 +372,15 @@ class Registry {
|
|
|
372
372
|
}
|
|
373
373
|
}
|
|
374
374
|
|
|
375
|
+
function typed(typeId, value) {
|
|
376
|
+
return { __spark_type: typeId, __spark_value: value };
|
|
377
|
+
}
|
|
378
|
+
function isTypedOutput(v) {
|
|
379
|
+
return (!!v &&
|
|
380
|
+
typeof v === "object" &&
|
|
381
|
+
Object.prototype.hasOwnProperty.call(v, "__spark_type"));
|
|
382
|
+
}
|
|
383
|
+
|
|
375
384
|
class GraphRuntime {
|
|
376
385
|
constructor() {
|
|
377
386
|
this.nodes = new Map();
|
|
@@ -435,25 +444,19 @@ class GraphRuntime {
|
|
|
435
444
|
srcDeclared = srcDesc.outputs[e.source.handle];
|
|
436
445
|
}
|
|
437
446
|
}
|
|
438
|
-
if (!effectiveTypeId)
|
|
439
|
-
effectiveTypeId = srcDeclared
|
|
447
|
+
if (!effectiveTypeId) {
|
|
448
|
+
effectiveTypeId = Array.isArray(srcDeclared)
|
|
449
|
+
? srcDeclared[0]
|
|
450
|
+
: srcDeclared;
|
|
451
|
+
}
|
|
440
452
|
if (dstNode) {
|
|
441
453
|
const dstDesc = registry.nodes.get(dstNode.typeId);
|
|
442
454
|
if (dstDesc) {
|
|
443
455
|
dstDeclared = dstDesc.inputs[e.target.handle];
|
|
444
456
|
}
|
|
445
457
|
}
|
|
446
|
-
// Attach convert
|
|
447
|
-
|
|
448
|
-
let convertAsync = undefined;
|
|
449
|
-
if (srcDeclared && dstDeclared && srcDeclared !== dstDeclared) {
|
|
450
|
-
const fn = registry.getCoercion(srcDeclared, dstDeclared);
|
|
451
|
-
if (fn)
|
|
452
|
-
convert = convert ?? fn;
|
|
453
|
-
const afn = registry.getAsyncCoercion(srcDeclared, dstDeclared);
|
|
454
|
-
if (afn)
|
|
455
|
-
convertAsync = convertAsync ?? afn;
|
|
456
|
-
}
|
|
458
|
+
// Attach dynamic convert/convertAsync aware of union sources and typed outputs
|
|
459
|
+
const { convert, convertAsync } = GraphRuntime.buildEdgeConverters(srcDeclared, dstDeclared, registry);
|
|
457
460
|
return {
|
|
458
461
|
id: e.id,
|
|
459
462
|
source: { ...e.source },
|
|
@@ -461,6 +464,9 @@ class GraphRuntime {
|
|
|
461
464
|
typeId: effectiveTypeId ?? "untyped",
|
|
462
465
|
convert,
|
|
463
466
|
convertAsync,
|
|
467
|
+
srcUnionTypes: Array.isArray(srcDeclared)
|
|
468
|
+
? [...srcDeclared]
|
|
469
|
+
: undefined,
|
|
464
470
|
stats: { runs: 0, inFlight: false, progress: 0 },
|
|
465
471
|
};
|
|
466
472
|
});
|
|
@@ -537,6 +543,59 @@ class GraphRuntime {
|
|
|
537
543
|
const node = this.nodes.get(nodeId);
|
|
538
544
|
return node?.outputs[output];
|
|
539
545
|
}
|
|
546
|
+
static buildEdgeConverters(srcDeclared, dstDeclared, registry) {
|
|
547
|
+
let convert;
|
|
548
|
+
let convertAsync;
|
|
549
|
+
if (dstDeclared && srcDeclared) {
|
|
550
|
+
if (Array.isArray(srcDeclared)) {
|
|
551
|
+
const srcTypes = srcDeclared;
|
|
552
|
+
const anyAsync = srcTypes.some((s) => {
|
|
553
|
+
const res = registry.resolveCoercion(s, dstDeclared);
|
|
554
|
+
return res?.kind === "async";
|
|
555
|
+
});
|
|
556
|
+
if (anyAsync) {
|
|
557
|
+
convertAsync = async (v, signal) => {
|
|
558
|
+
if (!isTypedOutput(v))
|
|
559
|
+
throw new Error(`Typed output required for union source; allowed: ${srcTypes.join("|")}`);
|
|
560
|
+
const typeId = String(v.__spark_type);
|
|
561
|
+
if (!srcTypes.includes(typeId))
|
|
562
|
+
throw new Error(`Invalid typed output ${typeId}; allowed: ${srcTypes.join("|")}`);
|
|
563
|
+
const payload = v.__spark_value;
|
|
564
|
+
const res = registry.resolveCoercion(typeId, dstDeclared);
|
|
565
|
+
if (!res)
|
|
566
|
+
return payload;
|
|
567
|
+
if (res.kind === "async")
|
|
568
|
+
return await res.convertAsync(payload, signal);
|
|
569
|
+
return res.convert(payload);
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
else {
|
|
573
|
+
convert = (v) => {
|
|
574
|
+
if (!isTypedOutput(v))
|
|
575
|
+
throw new Error(`Typed output required for union source; allowed: ${srcTypes.join("|")}`);
|
|
576
|
+
const typeId = String(v.__spark_type);
|
|
577
|
+
if (!srcTypes.includes(typeId))
|
|
578
|
+
throw new Error(`Invalid typed output ${typeId}; allowed: ${srcTypes.join("|")}`);
|
|
579
|
+
const payload = v.__spark_value;
|
|
580
|
+
const res = registry.resolveCoercion(typeId, dstDeclared);
|
|
581
|
+
if (!res)
|
|
582
|
+
return payload;
|
|
583
|
+
if (res.kind === "async")
|
|
584
|
+
throw new Error("Async coercion required but convert used");
|
|
585
|
+
return res.convert(payload);
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
else {
|
|
590
|
+
const res = registry.resolveCoercion(srcDeclared, dstDeclared);
|
|
591
|
+
if (res?.kind === "async")
|
|
592
|
+
convertAsync = res.convertAsync;
|
|
593
|
+
else if (res?.kind === "sync")
|
|
594
|
+
convert = res.convert;
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
return { convert, convertAsync };
|
|
598
|
+
}
|
|
540
599
|
scheduleInputsChanged(nodeId) {
|
|
541
600
|
const node = this.nodes.get(nodeId);
|
|
542
601
|
if (!node)
|
|
@@ -708,10 +767,27 @@ class GraphRuntime {
|
|
|
708
767
|
handle: srcHandle,
|
|
709
768
|
value,
|
|
710
769
|
io: "output",
|
|
770
|
+
runtimeTypeId: isTypedOutput(value)
|
|
771
|
+
? String(value.__spark_type)
|
|
772
|
+
: undefined,
|
|
711
773
|
});
|
|
712
774
|
// fan-out along all edges from this output
|
|
713
775
|
const outEdges = this.edges.filter((e) => e.source.nodeId === srcNodeId && e.source.handle === srcHandle);
|
|
714
776
|
for (const e of outEdges) {
|
|
777
|
+
// If source declares a union for this handle, require typed output
|
|
778
|
+
const isUnion = Array.isArray(e.srcUnionTypes);
|
|
779
|
+
const isTyped = isTypedOutput(value);
|
|
780
|
+
if (isUnion && !isTyped) {
|
|
781
|
+
const err = new Error(`Output ${srcNodeId}.${srcHandle} requires typed value for union output (allowed: ${e.srcUnionTypes.join("|")})`);
|
|
782
|
+
this.emit("error", {
|
|
783
|
+
kind: "edge-convert",
|
|
784
|
+
edgeId: e.id,
|
|
785
|
+
source: { nodeId: e.source.nodeId, handle: e.source.handle },
|
|
786
|
+
target: { nodeId: e.target.nodeId, handle: e.target.handle },
|
|
787
|
+
err,
|
|
788
|
+
});
|
|
789
|
+
continue;
|
|
790
|
+
}
|
|
715
791
|
// Clone per edge to isolate conversions from mutating the shared source value
|
|
716
792
|
let nextVal = structuredClone(value);
|
|
717
793
|
const applyToTarget = (v) => {
|
|
@@ -725,6 +801,7 @@ class GraphRuntime {
|
|
|
725
801
|
handle: e.target.handle,
|
|
726
802
|
value: v,
|
|
727
803
|
io: "input",
|
|
804
|
+
runtimeTypeId: isTypedOutput(v) ? String(v.__spark_type) : undefined,
|
|
728
805
|
});
|
|
729
806
|
if (!this.paused && this.allInboundHaveValue(e.target.nodeId))
|
|
730
807
|
this.scheduleInputsChanged(e.target.nodeId);
|
|
@@ -743,7 +820,7 @@ class GraphRuntime {
|
|
|
743
820
|
e.stats.inFlight = true;
|
|
744
821
|
e.stats.progress = 0;
|
|
745
822
|
const sig = controller.signal;
|
|
746
|
-
// Fire async conversion
|
|
823
|
+
// Fire async conversion using edge's convertAsync (dynamic union aware)
|
|
747
824
|
void e
|
|
748
825
|
.convertAsync(nextVal, sig)
|
|
749
826
|
.then((v) => {
|
|
@@ -1020,24 +1097,18 @@ class GraphRuntime {
|
|
|
1020
1097
|
srcDeclared = srcDesc.outputs[e.source.handle];
|
|
1021
1098
|
}
|
|
1022
1099
|
}
|
|
1023
|
-
if (!effectiveTypeId)
|
|
1024
|
-
effectiveTypeId = srcDeclared
|
|
1100
|
+
if (!effectiveTypeId) {
|
|
1101
|
+
effectiveTypeId = Array.isArray(srcDeclared)
|
|
1102
|
+
? srcDeclared[0]
|
|
1103
|
+
: srcDeclared;
|
|
1104
|
+
}
|
|
1025
1105
|
if (dstNode) {
|
|
1026
1106
|
const dstDesc = registry.nodes.get(dstNode.typeId);
|
|
1027
1107
|
if (dstDesc) {
|
|
1028
1108
|
dstDeclared = dstDesc.inputs[e.target.handle];
|
|
1029
1109
|
}
|
|
1030
1110
|
}
|
|
1031
|
-
|
|
1032
|
-
let convertAsync = undefined;
|
|
1033
|
-
if (srcDeclared && dstDeclared && srcDeclared !== dstDeclared) {
|
|
1034
|
-
const fn = registry.getCoercion(srcDeclared, dstDeclared);
|
|
1035
|
-
if (fn)
|
|
1036
|
-
convert = convert ?? fn;
|
|
1037
|
-
const afn = registry.getAsyncCoercion(srcDeclared, dstDeclared);
|
|
1038
|
-
if (afn)
|
|
1039
|
-
convertAsync = convertAsync ?? afn;
|
|
1040
|
-
}
|
|
1111
|
+
const { convert, convertAsync } = GraphRuntime.buildEdgeConverters(srcDeclared, dstDeclared, registry);
|
|
1041
1112
|
return {
|
|
1042
1113
|
id: e.id,
|
|
1043
1114
|
source: { ...e.source },
|
|
@@ -1178,12 +1249,30 @@ class GraphBuilder {
|
|
|
1178
1249
|
message: `Edge ${e.id} target node missing`,
|
|
1179
1250
|
data: { edgeId: e.id },
|
|
1180
1251
|
});
|
|
1181
|
-
//
|
|
1252
|
+
// Infer edge type when missing. For union sources, prefer target input type if available.
|
|
1182
1253
|
let effectiveTypeId = e.typeId;
|
|
1183
|
-
|
|
1254
|
+
let _srcDeclared;
|
|
1255
|
+
let _dstDeclared;
|
|
1256
|
+
if (srcNode) {
|
|
1184
1257
|
const srcType = this.registry.nodes.get(srcNode.typeId);
|
|
1185
|
-
if (srcType)
|
|
1186
|
-
|
|
1258
|
+
if (srcType)
|
|
1259
|
+
_srcDeclared = srcType.outputs[e.source.handle];
|
|
1260
|
+
}
|
|
1261
|
+
if (dstNode) {
|
|
1262
|
+
const dstType = this.registry.nodes.get(dstNode.typeId);
|
|
1263
|
+
if (dstType)
|
|
1264
|
+
_dstDeclared = dstType.inputs[e.target.handle];
|
|
1265
|
+
}
|
|
1266
|
+
if (!effectiveTypeId) {
|
|
1267
|
+
if (Array.isArray(_srcDeclared) && _dstDeclared) {
|
|
1268
|
+
// When source is a union and target input type is known, adopt the input type
|
|
1269
|
+
// so validation checks are performed against the target, not an arbitrary variant.
|
|
1270
|
+
effectiveTypeId = _dstDeclared;
|
|
1271
|
+
}
|
|
1272
|
+
else if (_srcDeclared) {
|
|
1273
|
+
effectiveTypeId = Array.isArray(_srcDeclared)
|
|
1274
|
+
? _srcDeclared[0]
|
|
1275
|
+
: _srcDeclared;
|
|
1187
1276
|
}
|
|
1188
1277
|
}
|
|
1189
1278
|
const type = effectiveTypeId
|
|
@@ -1213,22 +1302,29 @@ class GraphBuilder {
|
|
|
1213
1302
|
}
|
|
1214
1303
|
if (srcType) {
|
|
1215
1304
|
const declared = srcType.outputs[e.source.handle];
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
declared
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1305
|
+
const declaredArr = Array.isArray(declared)
|
|
1306
|
+
? declared
|
|
1307
|
+
: declared
|
|
1308
|
+
? [declared]
|
|
1309
|
+
: [];
|
|
1310
|
+
if (declaredArr.length > 0 && effectiveTypeId) {
|
|
1311
|
+
for (const s of declaredArr) {
|
|
1312
|
+
if (s !== effectiveTypeId &&
|
|
1313
|
+
!this.registry.canCoerce(s, effectiveTypeId)) {
|
|
1314
|
+
issues.push({
|
|
1315
|
+
level: "error",
|
|
1316
|
+
code: "TYPE_MISMATCH_OUTPUT",
|
|
1317
|
+
message: `Edge ${e.id} type ${effectiveTypeId} mismatches source output ${srcNode.typeId}.${e.source.handle} (${s}) and no coercion exists`,
|
|
1318
|
+
data: {
|
|
1319
|
+
edgeId: e.id,
|
|
1320
|
+
nodeId: srcNode.nodeId,
|
|
1321
|
+
output: e.source.handle,
|
|
1322
|
+
declared: s,
|
|
1323
|
+
effectiveTypeId,
|
|
1324
|
+
},
|
|
1325
|
+
});
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1232
1328
|
}
|
|
1233
1329
|
}
|
|
1234
1330
|
}
|
|
@@ -1247,23 +1343,52 @@ class GraphBuilder {
|
|
|
1247
1343
|
});
|
|
1248
1344
|
}
|
|
1249
1345
|
if (dstType) {
|
|
1250
|
-
const
|
|
1251
|
-
if (
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1346
|
+
const declaredIn = dstType.inputs[e.target.handle];
|
|
1347
|
+
if (declaredIn && effectiveTypeId) {
|
|
1348
|
+
// If source is a union, ensure each variant can reach declaredIn
|
|
1349
|
+
if (srcNode) {
|
|
1350
|
+
const srcType = this.registry.nodes.get(srcNode.typeId);
|
|
1351
|
+
const srcDeclared = srcType?.outputs[e.source.handle];
|
|
1352
|
+
const srcArr = Array.isArray(srcDeclared)
|
|
1353
|
+
? srcDeclared
|
|
1354
|
+
: srcDeclared
|
|
1355
|
+
? [srcDeclared]
|
|
1356
|
+
: effectiveTypeId
|
|
1357
|
+
? [effectiveTypeId]
|
|
1358
|
+
: [];
|
|
1359
|
+
for (const s of srcArr) {
|
|
1360
|
+
if (s !== declaredIn &&
|
|
1361
|
+
!this.registry.canCoerce(s, declaredIn)) {
|
|
1362
|
+
issues.push({
|
|
1363
|
+
level: "error",
|
|
1364
|
+
code: "TYPE_MISMATCH_INPUT",
|
|
1365
|
+
message: `Edge ${e.id} output type ${s} not convertible to target input ${dstNode.typeId}.${e.target.handle} (${declaredIn})`,
|
|
1366
|
+
data: {
|
|
1367
|
+
edgeId: e.id,
|
|
1368
|
+
nodeId: dstNode.nodeId,
|
|
1369
|
+
input: e.target.handle,
|
|
1370
|
+
declared: declaredIn,
|
|
1371
|
+
effectiveTypeId: s,
|
|
1372
|
+
},
|
|
1373
|
+
});
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
else if (declaredIn !== effectiveTypeId &&
|
|
1378
|
+
!this.registry.canCoerce(effectiveTypeId, declaredIn)) {
|
|
1379
|
+
issues.push({
|
|
1380
|
+
level: "error",
|
|
1381
|
+
code: "TYPE_MISMATCH_INPUT",
|
|
1382
|
+
message: `Edge ${e.id} type ${effectiveTypeId} mismatches target input ${dstNode.typeId}.${e.target.handle} (${declaredIn}) and no coercion exists`,
|
|
1383
|
+
data: {
|
|
1384
|
+
edgeId: e.id,
|
|
1385
|
+
nodeId: dstNode.nodeId,
|
|
1386
|
+
input: e.target.handle,
|
|
1387
|
+
declared: declaredIn,
|
|
1388
|
+
effectiveTypeId,
|
|
1389
|
+
},
|
|
1390
|
+
});
|
|
1391
|
+
}
|
|
1267
1392
|
}
|
|
1268
1393
|
}
|
|
1269
1394
|
}
|
|
@@ -1304,7 +1429,8 @@ class GraphBuilder {
|
|
|
1304
1429
|
? this.registry.nodes.get(innerNode.typeId)
|
|
1305
1430
|
: undefined;
|
|
1306
1431
|
const typeId = innerDesc ? innerDesc.outputs[map.handle] : undefined;
|
|
1307
|
-
|
|
1432
|
+
const single = Array.isArray(typeId) ? typeId[0] : typeId;
|
|
1433
|
+
outputTypes[outerOut] = single ?? "untyped";
|
|
1308
1434
|
}
|
|
1309
1435
|
return {
|
|
1310
1436
|
id: nodeTypeId,
|
|
@@ -1576,10 +1702,16 @@ const CompositeCategory = (registry) => ({
|
|
|
1576
1702
|
onInputsChanged: (inputs, ctx) => {
|
|
1577
1703
|
if (!inner)
|
|
1578
1704
|
return;
|
|
1579
|
-
// map outer
|
|
1705
|
+
// map outer inputs => batch per inner node to avoid extra runs
|
|
1706
|
+
const grouped = {};
|
|
1580
1707
|
for (const [inHandle, map] of Object.entries(impl.exposure.inputs)) {
|
|
1581
|
-
if (inHandle in inputs)
|
|
1582
|
-
|
|
1708
|
+
if (inHandle in inputs) {
|
|
1709
|
+
const nodeMap = (grouped[map.nodeId] = grouped[map.nodeId] || {});
|
|
1710
|
+
nodeMap[map.handle] = inputs[inHandle];
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1713
|
+
for (const [nodeId, map] of Object.entries(grouped)) {
|
|
1714
|
+
inner.setInputs(nodeId, map);
|
|
1583
1715
|
}
|
|
1584
1716
|
// pull inner exposed outputs and emit
|
|
1585
1717
|
for (const [outHandle, map] of Object.entries(impl.exposure.outputs)) {
|
|
@@ -1622,6 +1754,25 @@ const lcg = (seed) => {
|
|
|
1622
1754
|
let s = seed >>> 0 || 1;
|
|
1623
1755
|
return () => (s = (s * 1664525 + 1013904223) >>> 0) / 0xffffffff;
|
|
1624
1756
|
};
|
|
1757
|
+
// JSON helpers
|
|
1758
|
+
const isPlainObject = (v) => {
|
|
1759
|
+
if (v === null || typeof v !== "object")
|
|
1760
|
+
return false;
|
|
1761
|
+
const proto = Object.getPrototypeOf(v);
|
|
1762
|
+
return proto === Object.prototype || proto === null;
|
|
1763
|
+
};
|
|
1764
|
+
const isJson = (v) => {
|
|
1765
|
+
if (v === null)
|
|
1766
|
+
return true;
|
|
1767
|
+
const t = typeof v;
|
|
1768
|
+
if (t === "string" || t === "number" || t === "boolean")
|
|
1769
|
+
return true;
|
|
1770
|
+
if (Array.isArray(v))
|
|
1771
|
+
return v.every(isJson);
|
|
1772
|
+
if (isPlainObject(v))
|
|
1773
|
+
return Object.values(v).every(isJson);
|
|
1774
|
+
return false;
|
|
1775
|
+
};
|
|
1625
1776
|
function setupBasicGraphRegistry() {
|
|
1626
1777
|
const registry = new Registry();
|
|
1627
1778
|
registry.categories.register(ComputeCategory);
|
|
@@ -1637,6 +1788,11 @@ function setupBasicGraphRegistry() {
|
|
|
1637
1788
|
id: "base.string",
|
|
1638
1789
|
validate: (v) => typeof v === "string",
|
|
1639
1790
|
}, { withArray: true, arrayPickFirstDefined: true });
|
|
1791
|
+
// Generic object value (JSON-compatible; object/array/primitive/null)
|
|
1792
|
+
registry.registerType({
|
|
1793
|
+
id: "base.object",
|
|
1794
|
+
validate: (v) => isJson(v),
|
|
1795
|
+
}, { withArray: true, arrayPickFirstDefined: true });
|
|
1640
1796
|
registry.registerType({
|
|
1641
1797
|
id: "base.vec3",
|
|
1642
1798
|
validate: (v) => Array.isArray(v) &&
|
|
@@ -1647,18 +1803,52 @@ function setupBasicGraphRegistry() {
|
|
|
1647
1803
|
registry.registerCoercion("base.float", "base.vec3", (v) => {
|
|
1648
1804
|
return [Number(v) || 0, 0, 0];
|
|
1649
1805
|
});
|
|
1650
|
-
|
|
1651
|
-
registry.registerAsyncCoercion("base.vec3", "base.float", async (value, signal) => {
|
|
1652
|
-
if (signal.aborted)
|
|
1653
|
-
throw new DOMException("Aborted", "AbortError");
|
|
1806
|
+
registry.registerCoercion("base.vec3", "base.float", (value) => {
|
|
1654
1807
|
const v = value;
|
|
1655
|
-
await new Promise((r) => setTimeout(r, 1000));
|
|
1656
1808
|
return Math.hypot(Number(v[0] ?? 0), Number(v[1] ?? 0), Number(v[2] ?? 0));
|
|
1657
1809
|
});
|
|
1658
1810
|
registry.registerCoercion("base.bool", "base.float", (v) => (v ? 1 : 0));
|
|
1659
1811
|
registry.registerCoercion("base.float", "base.bool", (v) => !!v);
|
|
1660
1812
|
registry.registerCoercion("base.float", "base.string", (v) => String(v));
|
|
1661
1813
|
registry.registerCoercion("base.string", "base.float", (v) => Number(v));
|
|
1814
|
+
// Object <-> String
|
|
1815
|
+
registry.registerCoercion("base.string", "base.object", (v) => {
|
|
1816
|
+
try {
|
|
1817
|
+
return JSON.parse(String(v));
|
|
1818
|
+
}
|
|
1819
|
+
catch {
|
|
1820
|
+
return undefined;
|
|
1821
|
+
}
|
|
1822
|
+
});
|
|
1823
|
+
registry.registerCoercion("base.object", "base.string", (v) => {
|
|
1824
|
+
try {
|
|
1825
|
+
return JSON.stringify(v);
|
|
1826
|
+
}
|
|
1827
|
+
catch {
|
|
1828
|
+
return String(v);
|
|
1829
|
+
}
|
|
1830
|
+
});
|
|
1831
|
+
registry.registerCoercion("base.vec3", "base.json", (v) => {
|
|
1832
|
+
try {
|
|
1833
|
+
return v ? JSON.stringify(v) : undefined;
|
|
1834
|
+
}
|
|
1835
|
+
catch {
|
|
1836
|
+
return undefined;
|
|
1837
|
+
}
|
|
1838
|
+
});
|
|
1839
|
+
registry.registerCoercion("base.json", "base.vec3", (v) => {
|
|
1840
|
+
try {
|
|
1841
|
+
const result = JSON.parse(v);
|
|
1842
|
+
if (result.length === 3 &&
|
|
1843
|
+
result.every((x) => typeof x === "number")) {
|
|
1844
|
+
return result;
|
|
1845
|
+
}
|
|
1846
|
+
return undefined;
|
|
1847
|
+
}
|
|
1848
|
+
catch {
|
|
1849
|
+
return undefined;
|
|
1850
|
+
}
|
|
1851
|
+
});
|
|
1662
1852
|
// Enums: Math Operation
|
|
1663
1853
|
registry.registerEnum({
|
|
1664
1854
|
id: "base.enum:math.operation",
|
|
@@ -2204,6 +2394,8 @@ exports.createSimpleGraphDef = createSimpleGraphDef;
|
|
|
2204
2394
|
exports.createSimpleGraphRegistry = createSimpleGraphRegistry;
|
|
2205
2395
|
exports.createValidationGraphDef = createValidationGraphDef;
|
|
2206
2396
|
exports.createValidationGraphRegistry = createValidationGraphRegistry;
|
|
2397
|
+
exports.isTypedOutput = isTypedOutput;
|
|
2207
2398
|
exports.registerDelayNode = registerDelayNode;
|
|
2208
2399
|
exports.registerProgressNodes = registerProgressNodes;
|
|
2400
|
+
exports.typed = typed;
|
|
2209
2401
|
//# sourceMappingURL=index.cjs.map
|