@saptools/service-flow 0.1.24 → 0.1.25

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 CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.25
4
+
5
+ - Make class-instance symbol-call indexing conservative so only same-file and relatively imported helper classes are traced, while built-in collection, date, URL, error, typed-array, promise, and abort-controller instances are ignored.
6
+ - Persist identifier and one-level destructured object parameter metadata for executable symbols, including class methods, so contextual service-client binding propagation can map helper arguments to callee receiver names.
7
+ - Propagate contextual service bindings through positional helper arguments and destructured object helper parameters with auditable caller and callee evidence.
8
+ - Refine unresolved operation diagnostics when indexed candidates exist but service context is absent or the resolution score is below threshold.
9
+
3
10
  ## 0.1.24
4
11
 
5
12
  - Add conservative class instance method symbol-call resolution for same-file and relatively imported helper classes, with auditable class-instance evidence.
@@ -1767,13 +1767,21 @@ function insertCallEdge(db, workspaceId, call, vars, generation) {
1767
1767
  }
1768
1768
  const edgeType = callType === "local_db_query" ? "HANDLER_RUNS_DB_QUERY" : callType === "external_http" ? "HANDLER_CALLS_EXTERNAL_HTTP" : callType === "async_emit" ? "HANDLER_EMITS_EVENT" : callType === "async_subscribe" ? "EVENT_CONSUMED_BY_HANDLER" : resolution.status === "dynamic" ? "DYNAMIC_EDGE_CANDIDATE" : "UNRESOLVED_EDGE";
1769
1769
  const status = edgeType === "DYNAMIC_EDGE_CANDIDATE" ? "dynamic" : resolution.status === "ambiguous" ? "ambiguous" : edgeType === "UNRESOLVED_EDGE" ? "unresolved" : "terminal";
1770
- 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"));
1770
+ const unresolvedReason = status === "terminal" ? null : String(call.unresolved_reason ?? unresolvedOperationReason(resolution));
1771
1771
  const targetKind = callType === "local_db_query" ? "db_entity" : callType.startsWith("async_") ? "event" : "external";
1772
1772
  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);
1773
1773
  const graphLevelDynamic = edgeType === "DYNAMIC_EDGE_CANDIDATE" && resolution.status === "dynamic";
1774
1774
  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);
1775
1775
  return { status, callType };
1776
1776
  }
1777
+ function unresolvedOperationReason(resolution) {
1778
+ if (resolution.status === "dynamic") return `Dynamic target requires runtime variable overrides: ${(resolution.reasons.length ? resolution.reasons : ["missing runtime variables"]).join(", ")}`;
1779
+ if (resolution.candidates.length === 0) return "No indexed target operation matched";
1780
+ if (resolution.reasons.includes("operation_path_only_has_no_strong_target_signal")) return "Operation candidates found but no strong service signal is available";
1781
+ if (resolution.reasons.includes("candidate_score_below_resolution_threshold")) return "Operation candidates found but resolution score is below threshold";
1782
+ if (resolution.status === "ambiguous") return "Ambiguous operation candidates require a strong service signal";
1783
+ return "Operation candidates found but resolution could not select a target";
1784
+ }
1777
1785
  function parseJson(value) {
1778
1786
  if (!value) return void 0;
1779
1787
  try {
@@ -2269,6 +2277,21 @@ function knownBindingsForCalls(db, calls) {
2269
2277
  }
2270
2278
  return map;
2271
2279
  }
2280
+ function knownBindingsForScope(db, repoId, symbolIds, files) {
2281
+ const map = /* @__PURE__ */ new Map();
2282
+ if (repoId === void 0) return map;
2283
+ const rows2 = db.prepare("SELECT id,variable_name variableName,alias,alias_expr aliasExpr,destination_expr destinationExpr,service_path_expr servicePathExpr,source_file sourceFile,source_line sourceLine FROM service_bindings WHERE repo_id=?").all(repoId);
2284
+ for (const row of rows2) {
2285
+ if (!row.variableName) continue;
2286
+ if (files && !files.has(String(row.sourceFile))) continue;
2287
+ if (symbolIds && symbolIds.size > 0) {
2288
+ const owner = db.prepare("SELECT id FROM symbols WHERE id IN (" + [...symbolIds].map(() => "?").join(",") + ") AND source_file=? AND start_line<=? AND end_line>=? LIMIT 1").get(...symbolIds, row.sourceFile, row.sourceLine, row.sourceLine);
2289
+ if (!owner) continue;
2290
+ }
2291
+ map.set(row.variableName, { ...row, bindingId: Number(row.id), source: "local_service_binding", calleeReceiver: row.variableName });
2292
+ }
2293
+ return map;
2294
+ }
2272
2295
  function contextForSymbolCall(db, symbolCall, callerBindings) {
2273
2296
  const next = /* @__PURE__ */ new Map();
2274
2297
  if (callerBindings.size === 0) return next;
@@ -2276,19 +2299,23 @@ function contextForSymbolCall(db, symbolCall, callerBindings) {
2276
2299
  const callee = db.prepare("SELECT evidence_json evidenceJson FROM symbols WHERE id=?").get(symbolCall.callee_symbol_id);
2277
2300
  const calleeEvidence = parseEvidence(callee?.evidenceJson);
2278
2301
  const params = Array.isArray(calleeEvidence.parameters) ? calleeEvidence.parameters.filter((item) => typeof item === "string") : [];
2302
+ const parameterBindings = Array.isArray(calleeEvidence.parameterBindings) ? calleeEvidence.parameterBindings.filter((item) => Boolean(item && typeof item === "object" && !Array.isArray(item))) : [];
2279
2303
  const args = Array.isArray(callEvidence2.callArguments) ? callEvidence2.callArguments : [];
2280
2304
  args.forEach((arg, index) => {
2281
- const param = params[index];
2282
- if (!param) return;
2305
+ const paramBinding = parameterBindings.find((binding) => binding.index === index);
2306
+ const param = paramBinding?.kind === "identifier" && typeof paramBinding.name === "string" ? paramBinding.name : params[index];
2283
2307
  if (arg.kind === "identifier" && typeof arg.name === "string") {
2284
2308
  const binding = callerBindings.get(arg.name);
2285
- if (binding) next.set(param, { ...binding, source: "local_symbol_argument", callerArgument: arg.name, calleeParameter: param, calleeReceiver: param });
2309
+ if (binding && param) next.set(param, { ...binding, source: "local_symbol_argument", callerArgument: arg.name, calleeParameter: param, calleeReceiver: param });
2286
2310
  }
2287
2311
  if (arg.kind === "object_literal" && Array.isArray(arg.properties)) {
2288
2312
  for (const prop of arg.properties) {
2289
2313
  if (typeof prop.property !== "string" || typeof prop.argument !== "string") continue;
2290
2314
  const binding = callerBindings.get(prop.argument);
2291
- if (binding) next.set(`${param}.${prop.property}`, { ...binding, source: "local_symbol_object_argument", callerProperty: prop.property, callerArgument: prop.argument, calleeParameter: param, calleeReceiver: `${param}.${prop.property}` });
2315
+ if (!binding) continue;
2316
+ const destructured = paramBinding?.kind === "object_pattern" && Array.isArray(paramBinding.properties) ? paramBinding.properties.find((item) => item.property === prop.property && typeof item.local === "string") : void 0;
2317
+ if (destructured && typeof destructured.local === "string") next.set(destructured.local, { ...binding, source: "local_symbol_destructured_object_argument", callerProperty: prop.property, callerArgument: prop.argument, calleeParameter: String(index), calleeReceiver: destructured.local });
2318
+ else if (param) next.set(`${param}.${prop.property}`, { ...binding, source: "local_symbol_object_argument", callerProperty: prop.property, callerArgument: prop.argument, calleeParameter: param, calleeReceiver: `${param}.${prop.property}` });
2292
2319
  }
2293
2320
  }
2294
2321
  });
@@ -2370,7 +2397,7 @@ function trace(db, start, options) {
2370
2397
  const filtered = calls.filter(
2371
2398
  (c) => (!current.symbolIds || current.symbolIds.has(Number(c.source_symbol_id))) && (!current.files || current.files.has(String(c.source_file))) && includeCall(String(c.call_type), options)
2372
2399
  );
2373
- const callerBindings = new Map([...current.context ?? /* @__PURE__ */ new Map(), ...knownBindingsForCalls(db, filtered)]);
2400
+ const callerBindings = new Map([...current.context ?? /* @__PURE__ */ new Map(), ...knownBindingsForScope(db, current.repoId, current.symbolIds, current.files), ...knownBindingsForCalls(db, filtered)]);
2374
2401
  if (current.symbolIds && current.symbolIds.size > 0 && current.depth < maxDepth) {
2375
2402
  const symbolRows = db.prepare(`SELECT sc.*,s.repo_id calleeRepoId,s.source_file calleeFile FROM symbol_calls sc LEFT JOIN symbols s ON s.id=sc.callee_symbol_id WHERE sc.caller_symbol_id IN (${[...current.symbolIds].map(() => "?").join(",")}) ORDER BY sc.source_file,sc.source_line`).all(...current.symbolIds);
2376
2403
  for (const symbolCall of symbolRows) {
@@ -2503,4 +2530,4 @@ export {
2503
2530
  linkWorkspace,
2504
2531
  trace
2505
2532
  };
2506
- //# sourceMappingURL=chunk-RXJNPONU.js.map
2533
+ //# sourceMappingURL=chunk-HS746OHV.js.map