@saptools/service-flow 0.1.19 → 0.1.20
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/CHANGELOG.md +7 -0
- package/README.md +3 -3
- package/TECHNICAL-NOTE.md +7 -0
- package/dist/{chunk-YG66SHAR.js → chunk-EKLZJJW7.js} +102 -13
- package/dist/chunk-EKLZJJW7.js.map +1 -0
- package/dist/cli.js +28 -7
- package/dist/cli.js.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-YG66SHAR.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.20
|
|
4
|
+
|
|
5
|
+
- Preserve service-binding evidence when helpers return connected clients inside object properties and callers destructure or create simple transaction aliases.
|
|
6
|
+
- Track full template-expression placeholder keys such as `${domainInfo.serviceName}`, `${domainInfo.shortName?.toLowerCase()}`, and `${items[0].service}` for runtime `--var` substitution without evaluating JavaScript.
|
|
7
|
+
- Render unresolved remote actions with unknown or dynamic paths as semantic targets instead of numeric call ids, with parser evidence for shorthand `path` identifiers.
|
|
8
|
+
- Expand strict doctor aggregates for normalized OData invocation ambiguity and remote-action unresolved target quality.
|
|
9
|
+
|
|
3
10
|
## 0.1.19
|
|
4
11
|
|
|
5
12
|
- Normalize balanced top-level OData action/function invocation paths before remote operation resolution, including namespace-qualified invocation lookup, while preserving raw and normalized evidence.
|
package/README.md
CHANGED
|
@@ -54,7 +54,7 @@ npm install @saptools/service-flow
|
|
|
54
54
|
|
|
55
55
|
### Correctness notes
|
|
56
56
|
|
|
57
|
-
- Runtime `--var` values are considered only for dynamic, ambiguous, or unresolved **remote** graph edges whose alias, destination, service path, or operation path expressions contain supplied placeholders. Local database, external HTTP, event, and already resolved static edges keep their persisted status, target, reason, and confidence. Partial substitutions remain dynamic and report the missing placeholder names.
|
|
57
|
+
- Runtime `--var` values are considered only for dynamic, ambiguous, or unresolved **remote** graph edges whose alias, destination, service path, or operation path expressions contain supplied placeholders. Placeholder keys are the full trimmed expression inside `${...}`, so keys such as `domainInfo.serviceName`, `domainInfo.shortName?.toLowerCase()`, and `items[0].service` can be supplied literally without JavaScript evaluation. Local database, external HTTP, event, and already resolved static edges keep their persisted status, target, reason, and confidence. Partial substitutions remain dynamic and report the missing placeholder names.
|
|
58
58
|
- `trace` and `graph` both accept repeatable `--var key=value` options. Effective substitutions are rendered in trace evidence without mutating the persisted graph. Confidence values are bounded to `[0, 1]`.
|
|
59
59
|
- Repository selectors on list, trace, graph, and inspect commands narrow scope. Unknown selectors return empty machine-readable diagnostics instead of falling back to the whole workspace.
|
|
60
60
|
- Helper-package dependency edges prefer exact indexed package names. Duplicate package-name candidates are persisted as ambiguous evidence rather than silently selecting one repository.
|
|
@@ -310,7 +310,7 @@ service-flow trace --workspace /path/to/workspace --repo facade-service --operat
|
|
|
310
310
|
|
|
311
311
|
When a concrete target exists after variable substitution, the trace shows both the parameterized evidence and the resolved match. When it does not, `service-flow` keeps the edge as a dynamic candidate or unresolved edge so the missing link remains visible.
|
|
312
312
|
|
|
313
|
-
Service-binding evidence keeps these fields distinct: service alias, alias expression, destination expression, service-path expression, operation-path expression, and runtime placeholders. This is important for common CAP helpers such as `cds.connect.to(`remote_${code}`, { credentials: { destination: `remote_${code}`, path: `/${entityType}ProcessService` } })`, where the alias is not the service path.
|
|
313
|
+
Service-binding evidence keeps these fields distinct: service alias, alias expression, destination expression, service-path expression, operation-path expression, and runtime placeholders. Helpers that return concrete connected clients inside object properties are followed through destructuring and simple transaction aliases while preserving helper-chain evidence. This is important for common CAP helpers such as `cds.connect.to(`remote_${code}`, { credentials: { destination: `remote_${code}`, path: `/${entityType}ProcessService` } })`, where the alias is not the service path.
|
|
314
314
|
|
|
315
315
|
By default, production traces should be built from production source files. Keep generated credentials and local state out of git, and use explicit fixture/test workspaces when validating test-only mocked service clients so they do not pollute production graph interpretation.
|
|
316
316
|
|
|
@@ -411,7 +411,7 @@ Run `service-flow index` after source, CDS, package metadata, or helper-package
|
|
|
411
411
|
<summary><b>Why is an expected call unresolved?</b></summary>
|
|
412
412
|
|
|
413
413
|
Check `service-flow doctor`, then inspect the facts with `service-flow list services`, `service-flow list operations`, and `service-flow list calls`. Dynamic destinations may need `--var key=value`, and custom wrappers may need new parser support.
|
|
414
|
-
Default doctor output is intended to focus on actionable indexing or trace-impacting issues; use `--strict` when you need exhaustive model-shape diagnostics for entity-only or extension-heavy CDS models.
|
|
414
|
+
Default doctor output is intended to focus on actionable indexing or trace-impacting issues; use `--strict` when you need exhaustive model-shape diagnostics for entity-only or extension-heavy CDS models. Strict mode also reports normalized OData invocation ambiguity and remote-action target quality, including whether unresolved unknown/dynamic paths are semantic instead of numeric call ids.
|
|
415
415
|
|
|
416
416
|
</details>
|
|
417
417
|
|
package/TECHNICAL-NOTE.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Service Flow Resolution Notes
|
|
2
2
|
|
|
3
|
+
## 0.1.20 helper object clients, expression placeholders, and remote-action target notes
|
|
4
|
+
|
|
5
|
+
- Helper-return binding analysis now follows concrete `cds.connect.to(...)` clients returned through object shorthand or explicit properties. Callers that destructure those properties, rename them, or assign a simple `.tx()` transaction alias keep helper-chain evidence including caller variable, returned property, helper source, destination expression, service-path expression, and placeholders. Arbitrary object returns are ignored.
|
|
6
|
+
- Template placeholders use the full trimmed expression inside `${...}` as the runtime key. Examples include `domain`, `domainInfo.serviceName`, `domainInfo.shortName?.toLowerCase()`, and `items[0].service`. Runtime `--var` substitution matches these keys literally and does not execute or partially evaluate JavaScript. Missing expression keys keep edges dynamic.
|
|
7
|
+
- Remote action calls that do not expose a static path now use semantic unresolved targets such as `Remote action: unknown path` or `Remote action: dynamic path`; shorthand `path` properties retain `operationPathExpression` and `dynamic_operation_path_identifier` parser evidence.
|
|
8
|
+
- Strict doctor reports normalized OData invocation totals by resolved/dynamic/ambiguous/unresolved status and remote-action target quality, including numeric unresolved targets and semantic unknown/dynamic target counts.
|
|
9
|
+
|
|
3
10
|
## 0.1.19 remote invocation and query notes
|
|
4
11
|
|
|
5
12
|
- Remote action/function paths are scanned for a balanced top-level OData invocation suffix. Single-segment operation imports like `/readConfig(...)` normalize to `/readConfig`; namespace-qualified operation imports keep the qualified request segment for evidence and can resolve against the indexed simple CDS operation when service signals are strong. Navigation/property paths like `/Orders(id='123')/items` are left unchanged. Graph evidence keeps both `rawOperationPath` and `normalizedOperationPath` when normalization occurs.
|
|
@@ -590,8 +590,14 @@ function literalText(expr) {
|
|
|
590
590
|
return void 0;
|
|
591
591
|
}
|
|
592
592
|
function objectPropertyText(object, key) {
|
|
593
|
-
const prop = object.properties.find(
|
|
594
|
-
|
|
593
|
+
const prop = object.properties.find(
|
|
594
|
+
(property) => ts4.isPropertyAssignment(property) && nameOfProperty(property.name) === key || ts4.isShorthandPropertyAssignment(property) && property.name.text === key
|
|
595
|
+
);
|
|
596
|
+
if (!prop) return void 0;
|
|
597
|
+
return ts4.isShorthandPropertyAssignment(prop) ? prop.name.text : prop.initializer.getText();
|
|
598
|
+
}
|
|
599
|
+
function objectPropertyIsShorthand(object, key) {
|
|
600
|
+
return object.properties.some((property) => ts4.isShorthandPropertyAssignment(property) && property.name.text === key);
|
|
595
601
|
}
|
|
596
602
|
function nameOfProperty(name) {
|
|
597
603
|
if (ts4.isIdentifier(name) || ts4.isStringLiteral(name) || ts4.isNumericLiteral(name)) return name.text;
|
|
@@ -655,7 +661,8 @@ function classifyOutboundCallsInSource(source, filePath) {
|
|
|
655
661
|
const receiver = expr.expression.text;
|
|
656
662
|
const query = objectPropertyText(objectArg, "query");
|
|
657
663
|
const op = objectPropertyText(objectArg, "path") ?? objectPropertyText(objectArg, "event");
|
|
658
|
-
|
|
664
|
+
const shorthandPath = objectPropertyIsShorthand(objectArg, "path");
|
|
665
|
+
add(node, { callType: query ? "remote_query" : "remote_action", serviceVariableName: receiver, method: stripQuotes(objectPropertyText(objectArg, "method") ?? "POST"), operationPathExpr: op && !shorthandPath ? `/${stripQuotes(op).replace(/^\//, "")}` : void 0, queryEntity: query ? extractQueryEntity(query) : void 0, payloadSummary: summarizeExpression(objectArg.getText(source)), confidence: op || query ? 0.8 : 0.4, unresolvedReason: !query && shorthandPath ? "dynamic_operation_path_identifier" : void 0 }, { receiver, classifier: "service_client_send_object", operationPathExpression: shorthandPath ? op : void 0, parserWarning: shorthandPath ? "dynamic_operation_path_identifier" : void 0 });
|
|
659
666
|
}
|
|
660
667
|
} else if (ts4.isPropertyAccessExpression(expr) && ["emit", "publish", "on"].includes(expr.name.text)) {
|
|
661
668
|
const receiver = receiverName(expr.expression);
|
|
@@ -750,7 +757,7 @@ function stringValue(node) {
|
|
|
750
757
|
return node.getText();
|
|
751
758
|
}
|
|
752
759
|
function placeholders(value) {
|
|
753
|
-
return [...(value ?? "").matchAll(/\$\{
|
|
760
|
+
return [...(value ?? "").matchAll(/\$\{([^}]*)\}/g)].map((m) => (m[1] ?? "").trim()).filter(Boolean);
|
|
754
761
|
}
|
|
755
762
|
function connectFactFromCall(call) {
|
|
756
763
|
const expr = call.expression;
|
|
@@ -889,6 +896,33 @@ async function importsFor(repoPath, filePath, sf) {
|
|
|
889
896
|
}
|
|
890
897
|
return imports;
|
|
891
898
|
}
|
|
899
|
+
function collectReturnedObjectBindings(fn) {
|
|
900
|
+
const bindings = /* @__PURE__ */ new Map();
|
|
901
|
+
const returns = /* @__PURE__ */ new Map();
|
|
902
|
+
function visit(node) {
|
|
903
|
+
if (ts5.isVariableDeclaration(node) && ts5.isIdentifier(node.name) && node.initializer) {
|
|
904
|
+
const fact = findConnectInExpression(node.initializer);
|
|
905
|
+
if (fact) bindings.set(node.name.text, fact);
|
|
906
|
+
}
|
|
907
|
+
if (ts5.isReturnStatement(node) && node.expression && ts5.isObjectLiteralExpression(node.expression)) {
|
|
908
|
+
for (const prop of node.expression.properties) {
|
|
909
|
+
if (ts5.isShorthandPropertyAssignment(prop)) returns.set(prop.name.text, prop.name.text);
|
|
910
|
+
if (ts5.isPropertyAssignment(prop) && ts5.isIdentifier(prop.initializer)) {
|
|
911
|
+
const propertyName = ts5.isIdentifier(prop.name) || ts5.isStringLiteralLike(prop.name) ? prop.name.text : void 0;
|
|
912
|
+
if (propertyName) returns.set(propertyName, prop.initializer.text);
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
ts5.forEachChild(node, visit);
|
|
917
|
+
}
|
|
918
|
+
visit(fn);
|
|
919
|
+
const out = /* @__PURE__ */ new Map();
|
|
920
|
+
for (const [propertyName, variableName] of returns) {
|
|
921
|
+
const fact = bindings.get(variableName);
|
|
922
|
+
if (fact) out.set(propertyName, fact);
|
|
923
|
+
}
|
|
924
|
+
return out;
|
|
925
|
+
}
|
|
892
926
|
function exportedLocalNames(sf) {
|
|
893
927
|
const exports = /* @__PURE__ */ new Map();
|
|
894
928
|
for (const stmt of sf.statements) {
|
|
@@ -924,6 +958,8 @@ async function helperBindings(repoPath, filePath) {
|
|
|
924
958
|
if (!fact) ts5.forEachChild(node, visit);
|
|
925
959
|
});
|
|
926
960
|
if (fact) factsByLocal.set(stmt.name.text, { ...fact, sourceLine: lineOf4(sf, stmt) });
|
|
961
|
+
for (const [returnedProperty, objectFact] of collectReturnedObjectBindings(stmt))
|
|
962
|
+
factsByLocal.set(`${stmt.name.text}#${returnedProperty}`, { ...objectFact, returnedProperty, sourceLine: lineOf4(sf, stmt) });
|
|
927
963
|
}
|
|
928
964
|
if (ts5.isVariableStatement(stmt))
|
|
929
965
|
for (const decl of stmt.declarationList.declarations) {
|
|
@@ -946,6 +982,14 @@ async function helperBindings(repoPath, filePath) {
|
|
|
946
982
|
sourceLine: fact.sourceLine
|
|
947
983
|
});
|
|
948
984
|
}
|
|
985
|
+
for (const [key, fact] of factsByLocal) {
|
|
986
|
+
const [localName, returnedProperty] = key.split("#");
|
|
987
|
+
if (!returnedProperty) continue;
|
|
988
|
+
for (const [exportedName, exportedLocal] of exportedLocals) {
|
|
989
|
+
if (exportedLocal !== localName) continue;
|
|
990
|
+
out.push({ ...fact, exportedName, returnedProperty, sourceFile: normalizePath(filePath), sourceLine: fact.sourceLine });
|
|
991
|
+
}
|
|
992
|
+
}
|
|
949
993
|
return out;
|
|
950
994
|
}
|
|
951
995
|
async function parseServiceBindings(repoPath, filePath) {
|
|
@@ -956,6 +1000,14 @@ async function parseServiceBindings(repoPath, filePath) {
|
|
|
956
1000
|
const imports = await importsFor(repoPath, filePath, sf);
|
|
957
1001
|
const helperCache = /* @__PURE__ */ new Map();
|
|
958
1002
|
const classHelpers = collectClassHelpers(sourceFileAst);
|
|
1003
|
+
const localObjectHelpers = /* @__PURE__ */ new Map();
|
|
1004
|
+
for (const stmt of sourceFileAst.statements) {
|
|
1005
|
+
if (!ts5.isFunctionDeclaration(stmt) || !stmt.name) continue;
|
|
1006
|
+
const rows2 = [];
|
|
1007
|
+
for (const [returnedProperty, fact] of collectReturnedObjectBindings(stmt))
|
|
1008
|
+
rows2.push({ ...fact, exportedName: stmt.name.text, returnedProperty, sourceFile: normalizePath(filePath), sourceLine: lineOf4(sourceFileAst, stmt) });
|
|
1009
|
+
if (rows2.length > 0) localObjectHelpers.set(stmt.name.text, rows2);
|
|
1010
|
+
}
|
|
959
1011
|
async function importedHelper(localName) {
|
|
960
1012
|
const imp = imports.find((i) => i.localName === localName && i.sourceFile);
|
|
961
1013
|
if (!imp?.sourceFile) return void 0;
|
|
@@ -1005,6 +1057,37 @@ async function parseServiceBindings(repoPath, filePath) {
|
|
|
1005
1057
|
});
|
|
1006
1058
|
}
|
|
1007
1059
|
}
|
|
1060
|
+
async function helperForCall(call) {
|
|
1061
|
+
if (!ts5.isIdentifier(call.expression)) return void 0;
|
|
1062
|
+
const local = localObjectHelpers.get(call.expression.text)?.[0];
|
|
1063
|
+
if (local) return { helper: local };
|
|
1064
|
+
const resolved = await importedHelper(call.expression.text);
|
|
1065
|
+
return resolved ? { helper: resolved.helper, imp: resolved.imp } : void 0;
|
|
1066
|
+
}
|
|
1067
|
+
async function recordDestructuredHelper(decl) {
|
|
1068
|
+
if (!ts5.isObjectBindingPattern(decl.name) || !decl.initializer) return;
|
|
1069
|
+
const call = unwrapCall(decl.initializer);
|
|
1070
|
+
if (!call) return;
|
|
1071
|
+
const resolved = await helperForCall(call);
|
|
1072
|
+
if (!resolved) return;
|
|
1073
|
+
for (const el of decl.name.elements) {
|
|
1074
|
+
if (!ts5.isIdentifier(el.name)) continue;
|
|
1075
|
+
const propertyName = el.propertyName && ts5.isIdentifier(el.propertyName) ? el.propertyName.text : el.name.text;
|
|
1076
|
+
if (resolved.helper.returnedProperty !== propertyName) continue;
|
|
1077
|
+
out.push({
|
|
1078
|
+
variableName: el.name.text,
|
|
1079
|
+
alias: resolved.helper.alias,
|
|
1080
|
+
aliasExpr: resolved.helper.aliasExpr,
|
|
1081
|
+
destinationExpr: resolved.helper.destinationExpr,
|
|
1082
|
+
servicePathExpr: resolved.helper.servicePathExpr,
|
|
1083
|
+
isDynamic: resolved.helper.isDynamic,
|
|
1084
|
+
placeholders: resolved.helper.placeholders,
|
|
1085
|
+
sourceFile: normalizePath(filePath),
|
|
1086
|
+
sourceLine: lineOf4(sourceFileAst, decl),
|
|
1087
|
+
helperChain: [{ callerVariable: el.name.text, helperFunction: call.expression.getText(sourceFileAst), returnedProperty: propertyName, importSource: resolved.imp?.sourceFile, helperSourceFile: resolved.helper.sourceFile, helperSourceLine: resolved.helper.sourceLine }]
|
|
1088
|
+
});
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1008
1091
|
function recordDestructuredClassHelper(decl) {
|
|
1009
1092
|
if (!ts5.isObjectBindingPattern(decl.name) || !decl.initializer) return;
|
|
1010
1093
|
const call = unwrapCall(decl.initializer);
|
|
@@ -1044,8 +1127,14 @@ async function parseServiceBindings(repoPath, filePath) {
|
|
|
1044
1127
|
}
|
|
1045
1128
|
collectDeclarations(sourceFileAst);
|
|
1046
1129
|
for (const decl of declarations) {
|
|
1130
|
+
await recordDestructuredHelper(decl);
|
|
1047
1131
|
recordDestructuredClassHelper(decl);
|
|
1048
1132
|
await recordVariable(decl);
|
|
1133
|
+
if (ts5.isIdentifier(decl.name) && decl.initializer && ts5.isCallExpression(decl.initializer) && ts5.isPropertyAccessExpression(decl.initializer.expression) && decl.initializer.expression.name.text === "tx" && ts5.isIdentifier(decl.initializer.expression.expression)) {
|
|
1134
|
+
const sourceName = decl.initializer.expression.expression.text;
|
|
1135
|
+
const existing = out.find((row) => row.variableName === sourceName && row.sourceFile === normalizePath(filePath));
|
|
1136
|
+
if (existing) out.push({ ...existing, variableName: decl.name.text, sourceLine: lineOf4(sourceFileAst, decl), helperChain: [...existing.helperChain ?? [], { callerVariable: decl.name.text, aliasOf: sourceName, aliasKind: "transaction" }] });
|
|
1137
|
+
}
|
|
1049
1138
|
}
|
|
1050
1139
|
return out;
|
|
1051
1140
|
}
|
|
@@ -1106,22 +1195,22 @@ function collectClassHelpers(sf) {
|
|
|
1106
1195
|
}
|
|
1107
1196
|
|
|
1108
1197
|
// src/linker/dynamic-edge-resolver.ts
|
|
1109
|
-
var PLACEHOLDER = /\$\{
|
|
1198
|
+
var PLACEHOLDER = /\$\{([^}]*)\}/g;
|
|
1110
1199
|
function applyVariables(template, vars) {
|
|
1111
1200
|
return substituteVariables(template, vars).effective;
|
|
1112
1201
|
}
|
|
1113
1202
|
function extractPlaceholders(template) {
|
|
1114
|
-
return [...(template ?? "").matchAll(PLACEHOLDER)].map((m) => m[1] ?? "").filter(Boolean);
|
|
1203
|
+
return [...(template ?? "").matchAll(PLACEHOLDER)].map((m) => (m[1] ?? "").trim()).filter(Boolean);
|
|
1115
1204
|
}
|
|
1116
1205
|
function substituteVariables(template, vars) {
|
|
1117
1206
|
if (!template) return { placeholders: [], missing: [], supplied: [], changed: false };
|
|
1118
1207
|
const placeholders2 = [...new Set(extractPlaceholders(template))];
|
|
1119
1208
|
const supplied = placeholders2.filter((key) => Object.hasOwn(vars, key));
|
|
1120
1209
|
const missing = placeholders2.filter((key) => !Object.hasOwn(vars, key));
|
|
1121
|
-
const effective = template.replace(
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
);
|
|
1210
|
+
const effective = template.replace(PLACEHOLDER, (_m, key) => {
|
|
1211
|
+
const trimmed = key.trim();
|
|
1212
|
+
return Object.hasOwn(vars, trimmed) ? vars[trimmed] ?? "" : `\${${trimmed}}`;
|
|
1213
|
+
});
|
|
1125
1214
|
return {
|
|
1126
1215
|
original: template,
|
|
1127
1216
|
effective,
|
|
@@ -1230,7 +1319,7 @@ function operationMatches(candidate, operationPath) {
|
|
|
1230
1319
|
return candidate.operationPath === names.path || candidate.operationPath === names.simplePath || candidate.operationName === names.name || candidate.operationName === names.simpleName;
|
|
1231
1320
|
}
|
|
1232
1321
|
function resolveOperation(db, signals, workspaceId) {
|
|
1233
|
-
const missing = [signals.servicePath, signals.alias, signals.destination, signals.operationPath].flatMap((value) => [...(value ?? "").matchAll(/\$\{
|
|
1322
|
+
const missing = [signals.servicePath, signals.alias, signals.destination, signals.operationPath].flatMap((value) => [...(value ?? "").matchAll(/\$\{([^}]*)\}/g)].map((match) => (match[1] ?? "").trim())).filter(Boolean);
|
|
1234
1323
|
if (missing.length > 0)
|
|
1235
1324
|
return {
|
|
1236
1325
|
status: "dynamic",
|
|
@@ -1475,7 +1564,7 @@ function insertCallEdge(db, workspaceId, call, vars, generation) {
|
|
|
1475
1564
|
const status = edgeType === "DYNAMIC_EDGE_CANDIDATE" ? "dynamic" : resolution.status === "ambiguous" ? "ambiguous" : edgeType === "UNRESOLVED_EDGE" ? "unresolved" : "terminal";
|
|
1476
1565
|
const unresolvedReason = status === "terminal" ? null : String(call.unresolved_reason ?? (resolution.status === "ambiguous" ? "Ambiguous operation candidates require a strong service signal" : resolution.status === "dynamic" ? `Dynamic target requires runtime variable overrides: ${(resolution.reasons.length ? resolution.reasons : ["missing runtime variables"]).join(", ")}` : "No indexed target operation matched"));
|
|
1477
1566
|
const targetKind = callType === "local_db_query" ? "db_entity" : callType.startsWith("async_") ? "event" : "external";
|
|
1478
|
-
const targetId = callType === "local_db_query" ? String(call.query_entity ?? "unknown") : String(call.event_name_expr ?? op ?? call.id);
|
|
1567
|
+
const targetId = callType === "local_db_query" ? String(call.query_entity ?? "unknown") : callType === "remote_action" ? op ? `Remote action: ${op}` : call.unresolved_reason === "dynamic_operation_path_identifier" ? "Remote action: dynamic path" : "Remote action: unknown path" : String(call.event_name_expr ?? op ?? call.id);
|
|
1479
1568
|
const graphLevelDynamic = edgeType === "DYNAMIC_EDGE_CANDIDATE" && resolution.status === "dynamic";
|
|
1480
1569
|
db.prepare("INSERT INTO graph_edges(workspace_id,edge_type,status,from_kind,from_id,to_kind,to_id,confidence,evidence_json,is_dynamic,unresolved_reason,generation) VALUES(?,?,?,?,?,?,?,?,?,?,?,?)").run(workspaceId, edgeType, status, "call", String(call.id), targetKind, targetId, Number(call.confidence ?? 0.2), JSON.stringify(evidence), graphLevelDynamic ? 1 : 0, unresolvedReason, generation);
|
|
1481
1570
|
return { status, callType };
|
|
@@ -2132,4 +2221,4 @@ export {
|
|
|
2132
2221
|
linkWorkspace,
|
|
2133
2222
|
trace
|
|
2134
2223
|
};
|
|
2135
|
-
//# sourceMappingURL=chunk-
|
|
2224
|
+
//# sourceMappingURL=chunk-EKLZJJW7.js.map
|