@saptools/service-flow 0.1.63 → 0.1.65
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 +6 -0
- package/dist/{chunk-EGBTHN7J.js → chunk-OONNRIDL.js} +84 -24
- package/dist/chunk-OONNRIDL.js.map +1 -0
- package/dist/cli.js +78 -2
- package/dist/cli.js.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/linker/002-call-evidence.ts +2 -4
- package/src/linker/cross-repo-linker.ts +1 -1
- package/src/linker/dynamic-edge-resolver.ts +15 -12
- package/src/linker/service-resolver.ts +3 -1
- package/src/parsers/service-binding-parser-helpers.ts +2 -1
- package/src/parsers/symbol-parser.ts +106 -1
- package/src/trace/001-dynamic-identity.ts +8 -6
- package/src/utils/001-placeholders.ts +30 -0
- package/src/utils/redaction.ts +44 -4
- package/dist/chunk-EGBTHN7J.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.65
|
|
4
|
+
|
|
5
|
+
- Captured event-subscription handler references from `.on('Event', handlerRef)` as resolvable symbol-call facts using the existing import-binding-aware machinery for relative imports, package imports, namespace members, same-file symbols, and static accessors.
|
|
6
|
+
- Covered bare identifiers, `Class.member` references, and one level of single-argument wrapper-call unwrapping; inline callbacks, multi-argument wrappers, nested wrappers, and other unsupported expressions remain unrepresented and fail closed.
|
|
7
|
+
- Kept the SQLite schema, event-registration and outbound-call facts, linkers, trace engine, renderers, and output shapes unchanged.
|
|
8
|
+
|
|
3
9
|
## 0.1.63
|
|
4
10
|
|
|
5
11
|
- Stopped recording CAP runtime lifecycle activity on the `cds` facade (`bootstrap`, `loaded`, `connect`, `serving`, `served`, `listening`, and `shutdown`) and supported-receiver `on('error')` hooks as asynchronous domain-event facts or derived event edges, while preserving custom facade events, lifecycle-named service events, domain messaging events, error emissions, and synthetic event-registration symbols.
|
|
@@ -1637,11 +1637,40 @@ function readExports(repoPath, filePath, seen, context) {
|
|
|
1637
1637
|
|
|
1638
1638
|
// src/utils/redaction.ts
|
|
1639
1639
|
var SENSITIVE = /authorization|cookie|token|secret|password|key|credential/i;
|
|
1640
|
+
var SENSITIVE_KEYWORD = /authorization|cookie|token|secret|password|key|credential/gi;
|
|
1641
|
+
function isWhitespace(value) {
|
|
1642
|
+
return value !== void 0 && /\s/u.test(value);
|
|
1643
|
+
}
|
|
1644
|
+
function redactionSpan(text, start, keyword) {
|
|
1645
|
+
let cursor = start + keyword.length;
|
|
1646
|
+
while (isWhitespace(text[cursor])) cursor += 1;
|
|
1647
|
+
if (text[cursor] !== ":" && text[cursor] !== "=") return void 0;
|
|
1648
|
+
cursor += 1;
|
|
1649
|
+
while (isWhitespace(text[cursor])) cursor += 1;
|
|
1650
|
+
const candidateQuote = text[cursor];
|
|
1651
|
+
const quote = candidateQuote === "'" || candidateQuote === '"' || candidateQuote === "`" ? candidateQuote : void 0;
|
|
1652
|
+
if (quote !== void 0) cursor += 1;
|
|
1653
|
+
const valueStart = cursor;
|
|
1654
|
+
while (cursor < text.length && !/[,'"`}\s]/u.test(text[cursor] ?? "")) cursor += 1;
|
|
1655
|
+
if (cursor === valueStart) return void 0;
|
|
1656
|
+
if (quote !== void 0) {
|
|
1657
|
+
if (text[cursor] !== quote) return void 0;
|
|
1658
|
+
cursor += 1;
|
|
1659
|
+
}
|
|
1660
|
+
return { start, end: cursor, keyword };
|
|
1661
|
+
}
|
|
1640
1662
|
function redactText(text) {
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1663
|
+
let cursor = 0;
|
|
1664
|
+
let output = "";
|
|
1665
|
+
for (const match of text.matchAll(SENSITIVE_KEYWORD)) {
|
|
1666
|
+
const start = match.index ?? 0;
|
|
1667
|
+
if (start < cursor) continue;
|
|
1668
|
+
const span = redactionSpan(text, start, match[0]);
|
|
1669
|
+
if (span === void 0) continue;
|
|
1670
|
+
output += text.slice(cursor, span.start) + `${span.keyword}: [REDACTED]`;
|
|
1671
|
+
cursor = span.end;
|
|
1672
|
+
}
|
|
1673
|
+
return output + text.slice(cursor);
|
|
1645
1674
|
}
|
|
1646
1675
|
function redactValue(value) {
|
|
1647
1676
|
if (Array.isArray(value)) return value.map(redactValue);
|
|
@@ -1665,6 +1694,31 @@ import ts5 from "typescript";
|
|
|
1665
1694
|
import fs7 from "fs/promises";
|
|
1666
1695
|
import path8 from "path";
|
|
1667
1696
|
import ts4 from "typescript";
|
|
1697
|
+
|
|
1698
|
+
// src/utils/001-placeholders.ts
|
|
1699
|
+
function scanPlaceholders(value) {
|
|
1700
|
+
const input = value ?? "";
|
|
1701
|
+
const spans = [];
|
|
1702
|
+
let cursor = 0;
|
|
1703
|
+
while (cursor < input.length) {
|
|
1704
|
+
const start = input.indexOf("${", cursor);
|
|
1705
|
+
if (start < 0) break;
|
|
1706
|
+
const closingBrace = input.indexOf("}", start + 2);
|
|
1707
|
+
if (closingBrace < 0) break;
|
|
1708
|
+
spans.push({
|
|
1709
|
+
start,
|
|
1710
|
+
end: closingBrace + 1,
|
|
1711
|
+
key: input.slice(start + 2, closingBrace)
|
|
1712
|
+
});
|
|
1713
|
+
cursor = closingBrace + 1;
|
|
1714
|
+
}
|
|
1715
|
+
return spans;
|
|
1716
|
+
}
|
|
1717
|
+
function extractPlaceholderKeys(value) {
|
|
1718
|
+
return scanPlaceholders(value).map((span) => span.key.trim()).filter(Boolean);
|
|
1719
|
+
}
|
|
1720
|
+
|
|
1721
|
+
// src/parsers/service-binding-parser-helpers.ts
|
|
1668
1722
|
function lineOf3(sf, node) {
|
|
1669
1723
|
return sf.getLineAndCharacterOfPosition(node.getStart(sf)).line + 1;
|
|
1670
1724
|
}
|
|
@@ -1675,7 +1729,7 @@ function stringValue2(node) {
|
|
|
1675
1729
|
return node.getText();
|
|
1676
1730
|
}
|
|
1677
1731
|
function placeholders(value) {
|
|
1678
|
-
return
|
|
1732
|
+
return extractPlaceholderKeys(value);
|
|
1679
1733
|
}
|
|
1680
1734
|
function connectFactFromCall(call) {
|
|
1681
1735
|
const expr = call.expression;
|
|
@@ -4152,12 +4206,11 @@ function serviceOperationCall(node, aliases) {
|
|
|
4152
4206
|
}
|
|
4153
4207
|
|
|
4154
4208
|
// src/linker/dynamic-edge-resolver.ts
|
|
4155
|
-
var PLACEHOLDER = /\$\{([^}]*)\}/g;
|
|
4156
4209
|
function applyVariables(template, vars) {
|
|
4157
4210
|
return substituteVariables(template, vars).effective;
|
|
4158
4211
|
}
|
|
4159
4212
|
function extractPlaceholders(template) {
|
|
4160
|
-
return
|
|
4213
|
+
return extractPlaceholderKeys(template);
|
|
4161
4214
|
}
|
|
4162
4215
|
function matchRuntimeTemplate(template, concrete) {
|
|
4163
4216
|
if (!template || !concrete) return void 0;
|
|
@@ -4180,10 +4233,15 @@ function substituteVariables(template, vars) {
|
|
|
4180
4233
|
const placeholders3 = [...new Set(extractPlaceholders(template))];
|
|
4181
4234
|
const supplied = placeholders3.filter((key) => Object.hasOwn(vars, key));
|
|
4182
4235
|
const missing = placeholders3.filter((key) => !Object.hasOwn(vars, key));
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
|
|
4236
|
+
let lastIndex = 0;
|
|
4237
|
+
let effective = "";
|
|
4238
|
+
for (const span of scanPlaceholders(template)) {
|
|
4239
|
+
const trimmed = span.key.trim();
|
|
4240
|
+
const replacement = Object.hasOwn(vars, trimmed) ? vars[trimmed] ?? "" : `\${${trimmed}}`;
|
|
4241
|
+
effective += template.slice(lastIndex, span.start) + replacement;
|
|
4242
|
+
lastIndex = span.end;
|
|
4243
|
+
}
|
|
4244
|
+
effective += template.slice(lastIndex);
|
|
4187
4245
|
return {
|
|
4188
4246
|
original: template,
|
|
4189
4247
|
effective,
|
|
@@ -4196,10 +4254,10 @@ function substituteVariables(template, vars) {
|
|
|
4196
4254
|
function runtimeTemplatePattern(template) {
|
|
4197
4255
|
let pattern = "";
|
|
4198
4256
|
let lastIndex = 0;
|
|
4199
|
-
for (const
|
|
4200
|
-
pattern += escapeRegex(template.slice(lastIndex,
|
|
4257
|
+
for (const span of scanPlaceholders(template)) {
|
|
4258
|
+
pattern += escapeRegex(template.slice(lastIndex, span.start));
|
|
4201
4259
|
pattern += "([^/]+?)";
|
|
4202
|
-
lastIndex =
|
|
4260
|
+
lastIndex = span.end;
|
|
4203
4261
|
}
|
|
4204
4262
|
return `${pattern}${escapeRegex(template.slice(lastIndex))}`;
|
|
4205
4263
|
}
|
|
@@ -5187,7 +5245,7 @@ function operationMatches(candidate, operationPath) {
|
|
|
5187
5245
|
return candidate.operationPath === names.path || candidate.operationPath === names.simplePath || candidate.operationName === names.name || candidate.operationName === names.simpleName;
|
|
5188
5246
|
}
|
|
5189
5247
|
function resolveOperation(db, signals, workspaceId) {
|
|
5190
|
-
const missing = [signals.servicePath, signals.alias, signals.destination, signals.operationPath].flatMap(
|
|
5248
|
+
const missing = [signals.servicePath, signals.alias, signals.destination, signals.operationPath].flatMap(extractPlaceholderKeys);
|
|
5191
5249
|
if (missing.length > 0)
|
|
5192
5250
|
return {
|
|
5193
5251
|
status: "dynamic",
|
|
@@ -5533,7 +5591,7 @@ function compactCandidateScores(candidates2) {
|
|
|
5533
5591
|
}));
|
|
5534
5592
|
}
|
|
5535
5593
|
function placeholderKeys(values) {
|
|
5536
|
-
const keys = values.flatMap(
|
|
5594
|
+
const keys = values.flatMap(extractPlaceholderKeys);
|
|
5537
5595
|
return [...new Set(keys)].sort();
|
|
5538
5596
|
}
|
|
5539
5597
|
function parseJson(value) {
|
|
@@ -5811,7 +5869,7 @@ function insertCallEdge(db, workspaceId, call, vars, generation) {
|
|
|
5811
5869
|
}
|
|
5812
5870
|
if (isRemoteEntityCall) {
|
|
5813
5871
|
const target = buildRemoteQueryTarget({ queryEntity: intent.entitySegment ?? call.query_entity, servicePath, serviceAlias: call.alias, serviceAliasExpr: call.aliasExpr, destination: destination ? applyVariables(destination, vars) : void 0, isDynamic, parserWarning: evidence.parserWarning });
|
|
5814
|
-
const entityKind = callType
|
|
5872
|
+
const entityKind = callType;
|
|
5815
5873
|
db.prepare("INSERT INTO graph_edges(workspace_id,edge_type,status,from_kind,from_id,to_kind,to_id,confidence,evidence_json,is_dynamic,generation) VALUES(?,?,?,?,?,?,?,?,?,?,?)").run(workspaceId, "HANDLER_ACCESSES_REMOTE_ENTITY", "terminal", "call", String(call.id), target.toKind, target.toId, Number(call.confidence ?? 0.5), JSON.stringify({ ...evidence, ...target.evidence, remoteEntityAccess: entityKind }), 0, generation);
|
|
5816
5874
|
return { status: "terminal", callType };
|
|
5817
5875
|
}
|
|
@@ -6515,17 +6573,18 @@ function proposalForIdentity(candidate, template, identity, sourceKind, npmPacka
|
|
|
6515
6573
|
}];
|
|
6516
6574
|
}
|
|
6517
6575
|
function matchIdentityTemplate(template, identity, npmPackage) {
|
|
6518
|
-
const matches2 =
|
|
6519
|
-
|
|
6520
|
-
|
|
6521
|
-
const
|
|
6576
|
+
const matches2 = scanPlaceholders(template);
|
|
6577
|
+
const matchSpan = matches2[0];
|
|
6578
|
+
if (matches2.length !== 1 || !matchSpan?.key) return void 0;
|
|
6579
|
+
const placeholder = template.slice(matchSpan.start, matchSpan.end);
|
|
6580
|
+
const sentinel = "dynamic_placeholder_token";
|
|
6522
6581
|
const normalizedTemplate = normalizeIdentity(template.replace(placeholder, sentinel));
|
|
6523
6582
|
const [prefix, suffix, extra] = normalizedTemplate.split(sentinel);
|
|
6524
6583
|
if (!prefix || !suffix || extra !== void 0) return void 0;
|
|
6525
6584
|
const normalizedIdentity = normalizeIdentity(identity, npmPackage);
|
|
6526
6585
|
const match = new RegExp(`^${escapeRegex2(prefix)}([a-z0-9]+)${escapeRegex2(suffix)}$`).exec(normalizedIdentity);
|
|
6527
6586
|
if (!match?.[1]) return void 0;
|
|
6528
|
-
return { key:
|
|
6587
|
+
return { key: matchSpan.key.trim(), value: match[1], normalizedIdentity };
|
|
6529
6588
|
}
|
|
6530
6589
|
function competingIdentityKeys(proposals) {
|
|
6531
6590
|
const owners = /* @__PURE__ */ new Map();
|
|
@@ -6630,7 +6689,7 @@ function routeImplementationEvidence(db, operationId) {
|
|
|
6630
6689
|
}
|
|
6631
6690
|
function normalizeIdentity(value, npmPackage = false) {
|
|
6632
6691
|
const unscoped = npmPackage && /^@[^/]+\/[^/]+$/.test(value) ? value.slice(value.indexOf("/") + 1) : value;
|
|
6633
|
-
return unscoped.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
6692
|
+
return unscoped.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|(?<!_)_+$/g, "");
|
|
6634
6693
|
}
|
|
6635
6694
|
function stringValue7(value) {
|
|
6636
6695
|
return typeof value === "string" ? value : void 0;
|
|
@@ -8955,6 +9014,7 @@ export {
|
|
|
8955
9014
|
normalizeODataOperationInvocationPath,
|
|
8956
9015
|
classifyODataPathIntent,
|
|
8957
9016
|
parseServiceBindings,
|
|
9017
|
+
classifyOutboundCallsInSource,
|
|
8958
9018
|
containsSupportedOutboundCall,
|
|
8959
9019
|
parseOutboundCalls,
|
|
8960
9020
|
applyVariables,
|
|
@@ -8967,4 +9027,4 @@ export {
|
|
|
8967
9027
|
selectorRepoAmbiguousDiagnostic,
|
|
8968
9028
|
trace
|
|
8969
9029
|
};
|
|
8970
|
-
//# sourceMappingURL=chunk-
|
|
9030
|
+
//# sourceMappingURL=chunk-OONNRIDL.js.map
|