@bian-womp/spark-graph 0.3.82 → 0.3.83
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 +201 -20
- package/lib/cjs/index.cjs.map +1 -1
- package/lib/cjs/src/index.d.ts +1 -1
- package/lib/cjs/src/index.d.ts.map +1 -1
- package/lib/cjs/src/misc/utils/LevelLogger.d.ts +85 -1
- package/lib/cjs/src/misc/utils/LevelLogger.d.ts.map +1 -1
- package/lib/cjs/src/runtime/components/NodeExecutor.d.ts.map +1 -1
- package/lib/esm/index.js +201 -20
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/src/index.d.ts +1 -1
- package/lib/esm/src/index.d.ts.map +1 -1
- package/lib/esm/src/misc/utils/LevelLogger.d.ts +85 -1
- package/lib/esm/src/misc/utils/LevelLogger.d.ts.map +1 -1
- package/lib/esm/src/runtime/components/NodeExecutor.d.ts.map +1 -1
- package/package.json +2 -2
package/lib/cjs/index.cjs
CHANGED
|
@@ -1438,9 +1438,52 @@ function stringifySceneAndOps(obj) {
|
|
|
1438
1438
|
/**
|
|
1439
1439
|
* A reusable logger class that supports configurable log levels and prefixes.
|
|
1440
1440
|
* Can be instantiated with a default log level and optionally override per call.
|
|
1441
|
+
*
|
|
1442
|
+
* Dynamic log-level rules:
|
|
1443
|
+
* - Rules are configured once via `LevelLogger.setDynamicLevelRules(raw)`.
|
|
1444
|
+
* - Rules can also be configured per logger instance via `setInstanceDynamicLevelRules(raw)`.
|
|
1445
|
+
* - Rules are compiled into a static runtime-friendly structure for fast matching.
|
|
1446
|
+
* - On every log call, logger resolves dynamic level by rule match:
|
|
1447
|
+
* `overrideLevel` > instance rule > global rule > logger default.
|
|
1448
|
+
*
|
|
1449
|
+
* Rule format (raw):
|
|
1450
|
+
* [
|
|
1451
|
+
* {
|
|
1452
|
+
* "name": "optional label",
|
|
1453
|
+
* "enabled": true,
|
|
1454
|
+
* "setLevel": "debug",
|
|
1455
|
+
* "when": {
|
|
1456
|
+
* "prefix": { "startsWith": ["[node:scene.importAsset"] },
|
|
1457
|
+
* "message": { "startsWith": ["computeAssetSyncStatus"] }
|
|
1458
|
+
* }
|
|
1459
|
+
* }
|
|
1460
|
+
* ]
|
|
1461
|
+
*
|
|
1462
|
+
* Matching semantics:
|
|
1463
|
+
* - Rules are evaluated in order; first match wins.
|
|
1464
|
+
* - `prefix` and `message` conditions are AND-ed when both exist.
|
|
1465
|
+
* - Within each operator list (`startsWith`, `contains`, etc.), values are OR-ed.
|
|
1466
|
+
* - If multiple operators are defined in one block, all operators must pass.
|
|
1467
|
+
* - `not` negates an additional matcher block.
|
|
1468
|
+
* - String matching is case-insensitive; regex is used as provided.
|
|
1469
|
+
*
|
|
1470
|
+
* Priority strategy (fixed):
|
|
1471
|
+
* - `overrideLevel` > first matching instance rule > first matching global rule > logger default.
|
|
1441
1472
|
*/
|
|
1442
1473
|
class LevelLogger {
|
|
1474
|
+
/**
|
|
1475
|
+
* Updates static dynamic level rules from raw settings input.
|
|
1476
|
+
* Accepts either:
|
|
1477
|
+
* - a JSON string containing an array of rules
|
|
1478
|
+
* - an in-memory array of rules
|
|
1479
|
+
*
|
|
1480
|
+
* Invalid rules are ignored; parse errors clear rules and warn.
|
|
1481
|
+
*/
|
|
1482
|
+
static setDynamicLevelRules(raw) {
|
|
1483
|
+
LevelLogger.compiledDynamicLevelRules = LevelLogger.compileDynamicLevelRulesFromRaw(raw);
|
|
1484
|
+
}
|
|
1443
1485
|
constructor(defaultLevel = "info", prefix = "") {
|
|
1486
|
+
this.compiledInstanceDynamicLevelRules = [];
|
|
1444
1487
|
this.defaultLevel = defaultLevel;
|
|
1445
1488
|
this.prefix = prefix;
|
|
1446
1489
|
}
|
|
@@ -1471,29 +1514,179 @@ class LevelLogger {
|
|
|
1471
1514
|
getLevelValue() {
|
|
1472
1515
|
return LevelLogger.levelValues[this.defaultLevel];
|
|
1473
1516
|
}
|
|
1517
|
+
/**
|
|
1518
|
+
* Sets per-instance dynamic rules. These are evaluated along with global rules
|
|
1519
|
+
* using the active priority preset.
|
|
1520
|
+
*/
|
|
1521
|
+
setInstanceDynamicLevelRules(raw) {
|
|
1522
|
+
this.compiledInstanceDynamicLevelRules = LevelLogger.compileDynamicLevelRulesFromRaw(raw);
|
|
1523
|
+
}
|
|
1524
|
+
static isRecord(value) {
|
|
1525
|
+
return value !== null && typeof value === "object";
|
|
1526
|
+
}
|
|
1527
|
+
static isLogLevel(value) {
|
|
1528
|
+
return typeof value === "string" && value in LevelLogger.levelValues;
|
|
1529
|
+
}
|
|
1530
|
+
static normalizeStringArray(input) {
|
|
1531
|
+
if (typeof input === "string")
|
|
1532
|
+
return [input];
|
|
1533
|
+
if (!Array.isArray(input))
|
|
1534
|
+
return [];
|
|
1535
|
+
return input.filter((v) => typeof v === "string");
|
|
1536
|
+
}
|
|
1537
|
+
static compileRegexArray(input) {
|
|
1538
|
+
const patterns = LevelLogger.normalizeStringArray(input);
|
|
1539
|
+
const compiled = [];
|
|
1540
|
+
for (const pattern of patterns) {
|
|
1541
|
+
try {
|
|
1542
|
+
compiled.push(new RegExp(pattern));
|
|
1543
|
+
}
|
|
1544
|
+
catch (err) {
|
|
1545
|
+
console.warn(`[LevelLogger] Invalid regex in dynamic level rule: ${pattern}`, err);
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
return compiled;
|
|
1549
|
+
}
|
|
1550
|
+
static compileMatchRule(input) {
|
|
1551
|
+
if (!LevelLogger.isRecord(input))
|
|
1552
|
+
return undefined;
|
|
1553
|
+
const equals = LevelLogger.normalizeStringArray(input.equals).map((v) => v.toLowerCase());
|
|
1554
|
+
const startsWith = LevelLogger.normalizeStringArray(input.startsWith).map((v) => v.toLowerCase());
|
|
1555
|
+
const contains = LevelLogger.normalizeStringArray(input.contains).map((v) => v.toLowerCase());
|
|
1556
|
+
const regex = LevelLogger.compileRegexArray(input.regex);
|
|
1557
|
+
let not;
|
|
1558
|
+
if (LevelLogger.isRecord(input.not)) {
|
|
1559
|
+
not = {
|
|
1560
|
+
equals: LevelLogger.normalizeStringArray(input.not.equals).map((v) => v.toLowerCase()),
|
|
1561
|
+
startsWith: LevelLogger.normalizeStringArray(input.not.startsWith).map((v) => v.toLowerCase()),
|
|
1562
|
+
contains: LevelLogger.normalizeStringArray(input.not.contains).map((v) => v.toLowerCase()),
|
|
1563
|
+
regex: LevelLogger.compileRegexArray(input.not.regex),
|
|
1564
|
+
};
|
|
1565
|
+
}
|
|
1566
|
+
if (!equals.length && !startsWith.length && !contains.length && !regex.length && !not)
|
|
1567
|
+
return undefined;
|
|
1568
|
+
return { equals, startsWith, contains, regex, not };
|
|
1569
|
+
}
|
|
1570
|
+
static compileDynamicLevelRules(raw) {
|
|
1571
|
+
if (!Array.isArray(raw)) {
|
|
1572
|
+
console.warn("[LevelLogger] Dynamic level rules must be an array. Ignoring value.");
|
|
1573
|
+
return [];
|
|
1574
|
+
}
|
|
1575
|
+
const compiled = [];
|
|
1576
|
+
for (const item of raw) {
|
|
1577
|
+
if (!LevelLogger.isRecord(item))
|
|
1578
|
+
continue;
|
|
1579
|
+
if (item.enabled === false)
|
|
1580
|
+
continue;
|
|
1581
|
+
if (!LevelLogger.isLogLevel(item.setLevel))
|
|
1582
|
+
continue;
|
|
1583
|
+
let when;
|
|
1584
|
+
if (LevelLogger.isRecord(item.when)) {
|
|
1585
|
+
const prefix = LevelLogger.compileMatchRule(item.when.prefix);
|
|
1586
|
+
const message = LevelLogger.compileMatchRule(item.when.message);
|
|
1587
|
+
if (prefix || message)
|
|
1588
|
+
when = { prefix, message };
|
|
1589
|
+
}
|
|
1590
|
+
compiled.push({
|
|
1591
|
+
name: typeof item.name === "string" ? item.name : undefined,
|
|
1592
|
+
setLevel: item.setLevel,
|
|
1593
|
+
when,
|
|
1594
|
+
});
|
|
1595
|
+
}
|
|
1596
|
+
return compiled;
|
|
1597
|
+
}
|
|
1598
|
+
static compileDynamicLevelRulesFromRaw(raw) {
|
|
1599
|
+
if (raw === undefined || raw === null || raw === "")
|
|
1600
|
+
return [];
|
|
1601
|
+
let parsed = raw;
|
|
1602
|
+
if (typeof raw === "string") {
|
|
1603
|
+
try {
|
|
1604
|
+
parsed = JSON.parse(raw);
|
|
1605
|
+
}
|
|
1606
|
+
catch (err) {
|
|
1607
|
+
console.warn("[LevelLogger] Failed to parse dynamic level rules JSON:", err);
|
|
1608
|
+
return [];
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
return LevelLogger.compileDynamicLevelRules(parsed);
|
|
1612
|
+
}
|
|
1613
|
+
static matchesCompiledMatchRule(rule, value, valueLower) {
|
|
1614
|
+
if (!rule)
|
|
1615
|
+
return true;
|
|
1616
|
+
const lower = valueLower ?? value.toLowerCase();
|
|
1617
|
+
if (rule.equals.length > 0 && !rule.equals.some((candidate) => lower === candidate))
|
|
1618
|
+
return false;
|
|
1619
|
+
if (rule.startsWith.length > 0 && !rule.startsWith.some((candidate) => lower.startsWith(candidate)))
|
|
1620
|
+
return false;
|
|
1621
|
+
if (rule.contains.length > 0 && !rule.contains.some((candidate) => lower.includes(candidate)))
|
|
1622
|
+
return false;
|
|
1623
|
+
if (rule.regex.length > 0 && !rule.regex.some((re) => re.test(value)))
|
|
1624
|
+
return false;
|
|
1625
|
+
if (rule.not) {
|
|
1626
|
+
const notMatches = (rule.not.equals.length > 0 && rule.not.equals.some((candidate) => lower === candidate)) ||
|
|
1627
|
+
(rule.not.startsWith.length > 0 && rule.not.startsWith.some((candidate) => lower.startsWith(candidate))) ||
|
|
1628
|
+
(rule.not.contains.length > 0 && rule.not.contains.some((candidate) => lower.includes(candidate))) ||
|
|
1629
|
+
(rule.not.regex.length > 0 && rule.not.regex.some((re) => re.test(value)));
|
|
1630
|
+
if (notMatches)
|
|
1631
|
+
return false;
|
|
1632
|
+
}
|
|
1633
|
+
return true;
|
|
1634
|
+
}
|
|
1635
|
+
static resolveDynamicLevelFromRules(prefix, message, rules) {
|
|
1636
|
+
const prefixLower = prefix.toLowerCase();
|
|
1637
|
+
const messageLower = message.toLowerCase();
|
|
1638
|
+
for (const rule of rules) {
|
|
1639
|
+
const prefixMatch = LevelLogger.matchesCompiledMatchRule(rule.when?.prefix, prefix, prefixLower);
|
|
1640
|
+
if (!prefixMatch)
|
|
1641
|
+
continue;
|
|
1642
|
+
const messageMatch = LevelLogger.matchesCompiledMatchRule(rule.when?.message, message, messageLower);
|
|
1643
|
+
if (!messageMatch)
|
|
1644
|
+
continue;
|
|
1645
|
+
return rule.setLevel;
|
|
1646
|
+
}
|
|
1647
|
+
return undefined;
|
|
1648
|
+
}
|
|
1649
|
+
static resolveDynamicLevel(prefix, message) {
|
|
1650
|
+
return LevelLogger.resolveDynamicLevelFromRules(prefix, message, LevelLogger.compiledDynamicLevelRules);
|
|
1651
|
+
}
|
|
1652
|
+
resolveEffectiveLevel(message, overrideLevel) {
|
|
1653
|
+
if (overrideLevel)
|
|
1654
|
+
return overrideLevel;
|
|
1655
|
+
const instanceDynamic = LevelLogger.resolveDynamicLevelFromRules(this.prefix, message, this.compiledInstanceDynamicLevelRules);
|
|
1656
|
+
const globalDynamic = LevelLogger.resolveDynamicLevel(this.prefix, message);
|
|
1657
|
+
return instanceDynamic ?? globalDynamic ?? this.defaultLevel;
|
|
1658
|
+
}
|
|
1474
1659
|
/**
|
|
1475
1660
|
* Logs a debug message
|
|
1476
1661
|
*/
|
|
1477
1662
|
debug(message, context, overrideLevel) {
|
|
1478
|
-
this.
|
|
1663
|
+
this._log("debug", message, context, overrideLevel);
|
|
1479
1664
|
}
|
|
1480
1665
|
/**
|
|
1481
1666
|
* Logs an info message
|
|
1482
1667
|
*/
|
|
1483
1668
|
info(message, context, overrideLevel) {
|
|
1484
|
-
this.
|
|
1669
|
+
this._log("info", message, context, overrideLevel);
|
|
1485
1670
|
}
|
|
1486
1671
|
/**
|
|
1487
1672
|
* Logs a warning message
|
|
1488
1673
|
*/
|
|
1489
1674
|
warn(message, context, overrideLevel) {
|
|
1490
|
-
this.
|
|
1675
|
+
this._log("warn", message, context, overrideLevel);
|
|
1491
1676
|
}
|
|
1492
1677
|
/**
|
|
1493
1678
|
* Logs an error message
|
|
1494
1679
|
*/
|
|
1495
1680
|
error(message, context, overrideLevel) {
|
|
1496
|
-
this.
|
|
1681
|
+
this._log("error", message, context, overrideLevel);
|
|
1682
|
+
}
|
|
1683
|
+
/**
|
|
1684
|
+
* Logs a message at the specified level
|
|
1685
|
+
*/
|
|
1686
|
+
log(level, message, context, overrideLevel) {
|
|
1687
|
+
if (level === "silent")
|
|
1688
|
+
return;
|
|
1689
|
+
this._log(level, message, context, overrideLevel);
|
|
1497
1690
|
}
|
|
1498
1691
|
/**
|
|
1499
1692
|
* Tries to parse a string as JSON and format it nicely if it's fully JSON
|
|
@@ -1560,8 +1753,8 @@ class LevelLogger {
|
|
|
1560
1753
|
/**
|
|
1561
1754
|
* Core logging method that respects the log level and applies prefix
|
|
1562
1755
|
*/
|
|
1563
|
-
|
|
1564
|
-
const effectiveLevel =
|
|
1756
|
+
_log(requestedLevel, message, context, overrideLevel) {
|
|
1757
|
+
const effectiveLevel = this.resolveEffectiveLevel(message, overrideLevel);
|
|
1565
1758
|
// Silent level suppresses all logs
|
|
1566
1759
|
if (effectiveLevel === "silent") {
|
|
1567
1760
|
return;
|
|
@@ -1654,6 +1847,7 @@ class LevelLogger {
|
|
|
1654
1847
|
}
|
|
1655
1848
|
}
|
|
1656
1849
|
}
|
|
1850
|
+
LevelLogger.compiledDynamicLevelRules = [];
|
|
1657
1851
|
/**
|
|
1658
1852
|
* Maps log levels to numeric values for comparison
|
|
1659
1853
|
*/
|
|
@@ -3001,20 +3195,7 @@ class NodeExecutor {
|
|
|
3001
3195
|
const nodeLogLevel = node?.logLevel ?? "info";
|
|
3002
3196
|
const logger = new LevelLogger(nodeLogLevel, `[node:${formatNodeRef(this.graph, nodeId)}:${runId}]`);
|
|
3003
3197
|
const log = (level, message, context) => {
|
|
3004
|
-
|
|
3005
|
-
case "debug":
|
|
3006
|
-
logger.debug(message, context);
|
|
3007
|
-
break;
|
|
3008
|
-
case "info":
|
|
3009
|
-
logger.info(message, context);
|
|
3010
|
-
break;
|
|
3011
|
-
case "warn":
|
|
3012
|
-
logger.warn(message, context);
|
|
3013
|
-
break;
|
|
3014
|
-
case "error":
|
|
3015
|
-
logger.error(message, context);
|
|
3016
|
-
break;
|
|
3017
|
-
}
|
|
3198
|
+
logger.log(level, message, context);
|
|
3018
3199
|
};
|
|
3019
3200
|
return {
|
|
3020
3201
|
nodeId,
|