weavatrix 0.2.13 → 0.2.14
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/README.md +83 -39
- package/SECURITY.md +2 -2
- package/docs/releases/v0.2.14.md +93 -0
- package/package.json +2 -2
- package/skill/SKILL.md +57 -38
- package/src/analysis/architecture/contract-graph.js +119 -0
- package/src/analysis/architecture/contract-schema.js +110 -0
- package/src/analysis/architecture/contract-storage.js +35 -0
- package/src/analysis/architecture/contract-verification.js +168 -0
- package/src/analysis/architecture-contract.js +16 -343
- package/src/analysis/change-classification/diff-parser.js +103 -0
- package/src/analysis/change-classification/options.js +40 -0
- package/src/analysis/change-classification/symbol-classifier.js +177 -0
- package/src/analysis/change-classification.js +120 -519
- package/src/analysis/dead-code-review/policy.js +23 -0
- package/src/analysis/dead-code-review.js +9 -19
- package/src/analysis/dep-check.js +10 -57
- package/src/analysis/dep-rules.js +10 -303
- package/src/analysis/dependency/scoped-dependencies.js +40 -0
- package/src/analysis/endpoints/common.js +62 -0
- package/src/analysis/endpoints/extract.js +107 -0
- package/src/analysis/endpoints/inventory.js +84 -0
- package/src/analysis/endpoints/mounts.js +129 -0
- package/src/analysis/endpoints-java.js +80 -3
- package/src/analysis/endpoints.js +3 -448
- package/src/analysis/git-history/analytics.js +177 -0
- package/src/analysis/git-history/collector.js +109 -0
- package/src/analysis/git-history/options.js +68 -0
- package/src/analysis/git-history.js +128 -577
- package/src/analysis/health-capabilities.js +82 -0
- package/src/analysis/http-contracts/analysis.js +169 -0
- package/src/analysis/http-contracts/client-call-detection.js +81 -0
- package/src/analysis/http-contracts/client-call-parser.js +255 -0
- package/src/analysis/http-contracts/graph-context.js +143 -0
- package/src/analysis/http-contracts/matching.js +61 -0
- package/src/analysis/http-contracts/shared.js +86 -0
- package/src/analysis/http-contracts.js +6 -822
- package/src/analysis/internal-audit/dependency-health.js +111 -0
- package/src/analysis/internal-audit/python-manifests.js +65 -0
- package/src/analysis/internal-audit/repo-files.js +55 -0
- package/src/analysis/internal-audit/supply-chain.js +132 -0
- package/src/analysis/internal-audit.collect.js +5 -106
- package/src/analysis/internal-audit.run.js +113 -200
- package/src/analysis/jvm-dependency-evidence.js +69 -0
- package/src/analysis/source-correctness/retry-patterns.js +93 -0
- package/src/analysis/source-correctness.js +225 -0
- package/src/analysis/structure/dependency-graph.js +156 -0
- package/src/analysis/structure/findings.js +142 -0
- package/src/graph/builder/go-receiver-resolution.js +112 -0
- package/src/graph/builder/js/queries.js +48 -0
- package/src/graph/builder/lang-go.js +89 -4
- package/src/graph/builder/lang-js.js +4 -44
- package/src/graph/builder/pass2-resolution.js +68 -0
- package/src/graph/freshness-probe.js +2 -1
- package/src/graph/incremental-refresh.js +3 -2
- package/src/graph/internal-builder.build.js +22 -183
- package/src/graph/internal-builder.pass2.js +161 -0
- package/src/graph/internal-builder.resolvers.js +2 -105
- package/src/graph/resolvers/rust.js +117 -0
- package/src/mcp/actions/advisories.mjs +18 -0
- package/src/mcp/actions/graph-lifecycle.mjs +148 -0
- package/src/mcp/actions/graph-sync.mjs +195 -0
- package/src/mcp/actions/hosted-architecture.mjs +57 -0
- package/src/mcp/architecture-bootstrap.mjs +168 -0
- package/src/mcp/architecture-starter.mjs +234 -0
- package/src/mcp/catalog.mjs +20 -6
- package/src/mcp/evidence/bun-lock-graph.mjs +209 -0
- package/src/mcp/evidence/package-graph-common.mjs +115 -0
- package/src/mcp/evidence/package-lock-graph.mjs +92 -0
- package/src/mcp/evidence-snapshot.package-graph.mjs +5 -474
- package/src/mcp/graph/context-core.mjs +111 -0
- package/src/mcp/graph/context-seeds.mjs +208 -0
- package/src/mcp/graph/context-state.mjs +86 -0
- package/src/mcp/graph/tools-core.mjs +143 -0
- package/src/mcp/graph/tools-query.mjs +223 -0
- package/src/mcp/graph-context.mjs +4 -496
- package/src/mcp/health/audit-format.mjs +172 -0
- package/src/mcp/health/audit.mjs +171 -0
- package/src/mcp/health/dead-code.mjs +110 -0
- package/src/mcp/health/duplicates.mjs +83 -0
- package/src/mcp/health/endpoints.mjs +42 -0
- package/src/mcp/health/structure.mjs +219 -0
- package/src/mcp/runtime-version.mjs +32 -0
- package/src/mcp/server/auto-refresh.mjs +66 -0
- package/src/mcp/server/runtime-config.mjs +43 -0
- package/src/mcp/server/shutdown.mjs +40 -0
- package/src/mcp/sync/evidence-architecture.mjs +54 -0
- package/src/mcp/sync/evidence-common.mjs +88 -0
- package/src/mcp/sync/evidence-duplicates.mjs +100 -0
- package/src/mcp/sync/evidence-health.mjs +56 -0
- package/src/mcp/sync/evidence-packages.mjs +95 -0
- package/src/mcp/sync/payload-common.mjs +97 -0
- package/src/mcp/sync/payload-v2.mjs +53 -0
- package/src/mcp/sync/payload-v3.mjs +79 -0
- package/src/mcp/sync-evidence.mjs +7 -402
- package/src/mcp/sync-payload.mjs +10 -244
- package/src/mcp/tools-actions.mjs +18 -414
- package/src/mcp/tools-architecture.mjs +18 -70
- package/src/mcp/tools-context.mjs +56 -15
- package/src/mcp/tools-endpoints.mjs +4 -1
- package/src/mcp/tools-graph.mjs +17 -331
- package/src/mcp/tools-health.mjs +24 -705
- package/src/mcp-server.mjs +35 -146
- package/src/precision/lsp-client/constants.js +12 -0
- package/src/precision/lsp-client/environment.js +20 -0
- package/src/precision/lsp-client/errors.js +15 -0
- package/src/precision/lsp-client/lifecycle.js +127 -0
- package/src/precision/lsp-client/message-parser.js +81 -0
- package/src/precision/lsp-client/protocol.js +212 -0
- package/src/precision/lsp-client/registry.js +58 -0
- package/src/precision/lsp-client/repo-uri.js +60 -0
- package/src/precision/lsp-client/stdio-client.js +151 -0
- package/src/precision/lsp-client.js +10 -682
- package/src/precision/lsp-overlay/build.js +238 -0
- package/src/precision/lsp-overlay/contract.js +61 -0
- package/src/precision/lsp-overlay/reference-results.js +108 -0
- package/src/precision/lsp-overlay/semantic-inputs.js +62 -0
- package/src/precision/lsp-overlay/source-session.js +134 -0
- package/src/precision/lsp-overlay/store.js +150 -0
- package/src/precision/lsp-overlay/target-index.js +147 -0
- package/src/precision/lsp-overlay/target-query.js +55 -0
- package/src/precision/lsp-overlay.js +11 -868
- package/src/precision/typescript-lsp-provider.js +12 -682
- package/src/precision/typescript-provider/client.js +69 -0
- package/src/precision/typescript-provider/discovery.js +124 -0
- package/src/precision/typescript-provider/project-host.js +249 -0
- package/src/precision/typescript-provider/project-safety.js +161 -0
- package/src/precision/typescript-provider/reference-usage.js +53 -0
- package/src/version.js +7 -0
- package/docs/releases/v0.2.13.md +0 -48
package/src/mcp/sync-payload.mjs
CHANGED
|
@@ -1,245 +1,14 @@
|
|
|
1
|
-
// Versioned, explicit wire schema for sync_graph. Never forward graph.json wholesale
|
|
2
|
-
// cache file and may contain future fields or attacker-injected data that are not safe to upload.
|
|
1
|
+
// Versioned, explicit wire schema for sync_graph. Never forward graph.json wholesale.
|
|
3
2
|
import {sanitizeEvidenceSnapshot} from './sync-evidence.mjs';
|
|
4
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
MAX_SYNC_EXTERNAL_IMPORTS, MAX_SYNC_LINKS, MAX_SYNC_NODES, assertArrayLimit,
|
|
5
|
+
} from './sync/payload-common.mjs';
|
|
6
|
+
import {sanitizeExternalImport, sanitizeLink, sanitizeNode} from './sync/payload-v2.mjs';
|
|
7
|
+
import {sanitizeExternalImportV3, sanitizeLinkV3, sanitizeNodeV3} from './sync/payload-v3.mjs';
|
|
5
8
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
export const MAX_SYNC_BODY_BYTES = 8 * 1024 * 1024;
|
|
10
|
-
export const MAX_SYNC_NODES = 25_000;
|
|
11
|
-
export const MAX_SYNC_LINKS = 100_000;
|
|
12
|
-
export const MAX_SYNC_EXTERNAL_IMPORTS = 50_000;
|
|
13
|
-
|
|
14
|
-
function metadataString(value, max = 4096) {
|
|
15
|
-
return typeof value === 'string' && value.length > 0 && value.length <= max && !CONTROL_CHARS.test(value)
|
|
16
|
-
? value
|
|
17
|
-
: undefined;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// graph.json is derived data and may be edited independently of the repository. Never trust a path
|
|
21
|
-
// merely because it occupies an allowlisted field: sync only accepts canonical-looking repo-relative
|
|
22
|
-
// paths, on every host OS. Graph IDs append `#symbol@line`, so validate their file portion separately
|
|
23
|
-
// while preserving the complete ID on the wire.
|
|
24
|
-
function repoRelativePathString(value, max = 4096) {
|
|
25
|
-
const path = metadataString(value, max);
|
|
26
|
-
if (!path) return undefined;
|
|
27
|
-
if (/^(?:[a-z][a-z0-9+.-]*:|[\\/])/i.test(path)) return undefined; // URI, drive path, POSIX or UNC absolute
|
|
28
|
-
const segments = path.split(/[\\/]/);
|
|
29
|
-
if (segments.some((segment) => segment === '.' || segment === '..')) return undefined;
|
|
30
|
-
return path;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function graphIdString(value) {
|
|
34
|
-
const id = metadataString(value);
|
|
35
|
-
if (!id) return undefined;
|
|
36
|
-
const hash = id.indexOf('#');
|
|
37
|
-
const file = hash < 0 ? id : id.slice(0, hash);
|
|
38
|
-
return repoRelativePathString(file) ? id : undefined;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Optional display metadata is still attacker-controlled graph data. Keep useful labels/import
|
|
42
|
-
// specifiers, but never let an absolute host path hide inside one of those free-text fields.
|
|
43
|
-
function privacySafeText(value, max = 4096) {
|
|
44
|
-
const text = metadataString(value, max);
|
|
45
|
-
if (!text) return undefined;
|
|
46
|
-
return ABSOLUTE_PATH_FRAGMENT.test(text) ? undefined : text;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function repoPathV3(value, max = 4096) {
|
|
50
|
-
const path = repoRelativePathString(value, max);
|
|
51
|
-
return path ? path.replace(/\\/g, '/') : undefined;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function graphIdV3(value) {
|
|
55
|
-
const id = metadataString(value);
|
|
56
|
-
if (!id) return undefined;
|
|
57
|
-
const hash = id.indexOf('#');
|
|
58
|
-
const file = hash < 0 ? id : id.slice(0, hash);
|
|
59
|
-
const safeFile = repoPathV3(file);
|
|
60
|
-
if (!safeFile) return undefined;
|
|
61
|
-
if (hash < 0) return safeFile;
|
|
62
|
-
const suffix = id.slice(hash);
|
|
63
|
-
// Builder IDs are `#symbol@line` (optionally with a short collision suffix). A symbol suffix
|
|
64
|
-
// never needs a path separator or whitespace; rejecting both closes an otherwise opaque channel.
|
|
65
|
-
if (suffix.length > 512 || !/^#[^\\/\s\u0000-\u001f\u007f]{1,511}$/u.test(suffix)) return undefined;
|
|
66
|
-
return `${safeFile}${suffix}`;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function safeToken(value, max = 256) {
|
|
70
|
-
const token = metadataString(value, max);
|
|
71
|
-
if (!token || !/^[\p{L}\p{N}_.:@+\-#$<>()\[\],]+$/u.test(token)) return undefined;
|
|
72
|
-
return token;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function packageName(value) {
|
|
76
|
-
const name = metadataString(value, 256);
|
|
77
|
-
return name && /^(?:@[a-z0-9._-]+\/)?[a-z0-9][a-z0-9._-]*$/i.test(name) ? name : undefined;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function externalSpecifier(value) {
|
|
81
|
-
const spec = metadataString(value, 512);
|
|
82
|
-
if (!spec || ABSOLUTE_PATH_FRAGMENT.test(spec) || /^(?:[a-z]:[\\/]|[\\/]|\.\.?[\\/])/i.test(spec)) return undefined;
|
|
83
|
-
return /^[a-z0-9@][a-z0-9@._:/+\-]*$/i.test(spec) ? spec : undefined;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function finiteNumber(value) {
|
|
87
|
-
return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function setIf(out, key, value) {
|
|
91
|
-
if (value !== undefined) out[key] = value;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const COMPLEXITY_NUMBERS = [
|
|
95
|
-
'startLine', 'endLine', 'loc', 'params', 'objectFields', 'branches', 'cyclomatic',
|
|
96
|
-
'loops', 'maxLoopDepth', 'returns', 'awaits', 'callCount', 'externalCalls',
|
|
97
|
-
'asyncBoundaries', 'allocations', 'objectLiterals', 'spreadCopies', 'sorts',
|
|
98
|
-
'linearOps', 'allocationsInLoops', 'copiesInLoops', 'linearOpsInLoops',
|
|
99
|
-
'sortsInLoops', 'recursionInLoops', 'timeRank', 'timeScore', 'memoryRank', 'memoryScore',
|
|
100
|
-
];
|
|
101
|
-
|
|
102
|
-
function sanitizeComplexity(value) {
|
|
103
|
-
if (!value || typeof value !== 'object' || Array.isArray(value)) return undefined;
|
|
104
|
-
const out = {};
|
|
105
|
-
for (const key of COMPLEXITY_NUMBERS) setIf(out, key, finiteNumber(value[key]));
|
|
106
|
-
if (typeof value.recursion === 'boolean') out.recursion = value.recursion;
|
|
107
|
-
for (const key of ['family', 'scope', 'complexityScope', 'confidence']) {
|
|
108
|
-
setIf(out, key, metadataString(value[key], 32));
|
|
109
|
-
}
|
|
110
|
-
return Object.keys(out).length ? out : undefined;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function sanitizeNode(value) {
|
|
114
|
-
if (!value || typeof value !== 'object' || Array.isArray(value)) return null;
|
|
115
|
-
const id = graphIdString(value.id);
|
|
116
|
-
if (!id) return null;
|
|
117
|
-
const out = {id};
|
|
118
|
-
setIf(out, 'label', metadataString(value.label, 1024));
|
|
119
|
-
setIf(out, 'file_type', metadataString(value.file_type, 32));
|
|
120
|
-
setIf(out, 'source_file', repoRelativePathString(value.source_file));
|
|
121
|
-
const sourceLocation = metadataString(value.source_location, 32);
|
|
122
|
-
const sourceEnd = metadataString(value.source_end, 32);
|
|
123
|
-
if (sourceLocation && /^L\d+$/.test(sourceLocation)) out.source_location = sourceLocation;
|
|
124
|
-
if (sourceEnd && /^L\d+$/.test(sourceEnd)) out.source_end = sourceEnd;
|
|
125
|
-
const community = finiteNumber(value.community);
|
|
126
|
-
if (community !== undefined && Number.isInteger(community) && community >= 0) out.community = community;
|
|
127
|
-
if (typeof value.exported === 'boolean') out.exported = value.exported;
|
|
128
|
-
if (typeof value.decorated === 'boolean') out.decorated = value.decorated;
|
|
129
|
-
setIf(out, 'complexity', sanitizeComplexity(value.complexity));
|
|
130
|
-
return out;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function sanitizeLink(value) {
|
|
134
|
-
if (!value || typeof value !== 'object' || Array.isArray(value)) return null;
|
|
135
|
-
const source = graphIdString(value.source);
|
|
136
|
-
const target = graphIdString(value.target);
|
|
137
|
-
if (!source || !target) return null;
|
|
138
|
-
const out = {source, target};
|
|
139
|
-
setIf(out, 'relation', metadataString(value.relation, 32));
|
|
140
|
-
setIf(out, 'confidence', metadataString(value.confidence, 32));
|
|
141
|
-
if (value.typeOnly === true) out.typeOnly = true;
|
|
142
|
-
if (value.compileOnly === true) out.compileOnly = true;
|
|
143
|
-
const line = finiteNumber(value.line);
|
|
144
|
-
if (line !== undefined && Number.isInteger(line) && line >= 0) out.line = line;
|
|
145
|
-
setIf(out, 'specifier', metadataString(value.specifier));
|
|
146
|
-
return out;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
function sanitizeExternalImport(value) {
|
|
150
|
-
if (!value || typeof value !== 'object' || Array.isArray(value)) return null;
|
|
151
|
-
const file = repoRelativePathString(value.file);
|
|
152
|
-
if (!file) return null;
|
|
153
|
-
const out = {file};
|
|
154
|
-
for (const key of ['spec', 'target']) setIf(out, key, metadataString(value[key]));
|
|
155
|
-
for (const key of ['pkg', 'kind', 'ecosystem']) setIf(out, key, metadataString(value[key], 256));
|
|
156
|
-
const line = finiteNumber(value.line);
|
|
157
|
-
if (line !== undefined && Number.isInteger(line) && line >= 0) out.line = line;
|
|
158
|
-
for (const key of ['builtin', 'dynamic', 'unresolved']) {
|
|
159
|
-
if (typeof value[key] === 'boolean') out[key] = value[key];
|
|
160
|
-
}
|
|
161
|
-
return out;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
function sanitizeNodeV3(value) {
|
|
165
|
-
const out = sanitizeNode(value);
|
|
166
|
-
if (!out) return null;
|
|
167
|
-
const id = graphIdV3(value.id);
|
|
168
|
-
if (!id) return null;
|
|
169
|
-
const sourceFile = value.source_file == null ? undefined : repoPathV3(value.source_file);
|
|
170
|
-
if (value.source_file != null && !sourceFile) return null;
|
|
171
|
-
const hash = id.indexOf('#');
|
|
172
|
-
const idFile = hash < 0 ? id : id.slice(0, hash);
|
|
173
|
-
if (sourceFile && idFile !== sourceFile) return null;
|
|
174
|
-
out.id = id;
|
|
175
|
-
const label = privacySafeText(value.label, 1024);
|
|
176
|
-
if (label) out.label = label;
|
|
177
|
-
else delete out.label;
|
|
178
|
-
const fileType = safeToken(value.file_type, 32);
|
|
179
|
-
if (fileType) out.file_type = fileType;
|
|
180
|
-
else delete out.file_type;
|
|
181
|
-
if (sourceFile) out.source_file = sourceFile;
|
|
182
|
-
else delete out.source_file;
|
|
183
|
-
for (const key of ['symbol_kind', 'symbol_space', 'member_of', 'visibility']) setIf(out, key, safeToken(value[key], 128));
|
|
184
|
-
if (out.complexity) {
|
|
185
|
-
for (const key of ['family', 'scope', 'complexityScope', 'confidence']) {
|
|
186
|
-
const safe = safeToken(value.complexity?.[key], 32);
|
|
187
|
-
if (safe) out.complexity[key] = safe;
|
|
188
|
-
else delete out.complexity[key];
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
return out;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
function sanitizeLinkV3(value) {
|
|
195
|
-
const out = sanitizeLink(value);
|
|
196
|
-
if (!out) return null;
|
|
197
|
-
const source = graphIdV3(value.source);
|
|
198
|
-
const target = graphIdV3(value.target);
|
|
199
|
-
if (!source || !target) return null;
|
|
200
|
-
out.source = source;
|
|
201
|
-
out.target = target;
|
|
202
|
-
for (const key of ['relation', 'confidence']) {
|
|
203
|
-
const safe = safeToken(value[key], 32);
|
|
204
|
-
if (safe) out[key] = safe;
|
|
205
|
-
else delete out[key];
|
|
206
|
-
}
|
|
207
|
-
const provenance = edgeProvenance(value);
|
|
208
|
-
if (provenance !== 'UNKNOWN') out.provenance = provenance;
|
|
209
|
-
const specifier = privacySafeText(value.specifier, 1024);
|
|
210
|
-
if (specifier) out.specifier = specifier;
|
|
211
|
-
else delete out.specifier;
|
|
212
|
-
return out;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
function sanitizeExternalImportV3(value) {
|
|
216
|
-
const out = sanitizeExternalImport(value);
|
|
217
|
-
if (!out) return null;
|
|
218
|
-
const file = repoPathV3(value.file);
|
|
219
|
-
if (!file) return null;
|
|
220
|
-
out.file = file;
|
|
221
|
-
setIf(out, 'spec', externalSpecifier(value.spec));
|
|
222
|
-
if (!externalSpecifier(value.spec)) delete out.spec;
|
|
223
|
-
setIf(out, 'pkg', packageName(value.pkg));
|
|
224
|
-
if (!packageName(value.pkg)) delete out.pkg;
|
|
225
|
-
for (const key of ['kind', 'ecosystem']) {
|
|
226
|
-
const safe = safeToken(value[key], 64);
|
|
227
|
-
if (safe) out[key] = safe;
|
|
228
|
-
else delete out[key];
|
|
229
|
-
}
|
|
230
|
-
if (value.target != null) {
|
|
231
|
-
const target = repoPathV3(value.target);
|
|
232
|
-
if (target) out.target = target;
|
|
233
|
-
else delete out.target;
|
|
234
|
-
}
|
|
235
|
-
if (value.typeOnly === true) out.typeOnly = true;
|
|
236
|
-
return out;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
function assertArrayLimit(raw, key, limit) {
|
|
240
|
-
const count = Array.isArray(raw[key]) ? raw[key].length : 0;
|
|
241
|
-
if (count > limit) throw new Error(`${key} has ${count} entries; maximum is ${limit}`);
|
|
242
|
-
}
|
|
9
|
+
export {
|
|
10
|
+
MAX_SYNC_BODY_BYTES, MAX_SYNC_EXTERNAL_IMPORTS, MAX_SYNC_LINKS, MAX_SYNC_NODES,
|
|
11
|
+
} from './sync/payload-common.mjs';
|
|
243
12
|
|
|
244
13
|
export function createSyncPayload(raw) {
|
|
245
14
|
if (!raw || typeof raw !== 'object' || Array.isArray(raw) || raw.repoBoundaryV !== 1) {
|
|
@@ -251,8 +20,7 @@ export function createSyncPayload(raw) {
|
|
|
251
20
|
const nodes = Array.isArray(raw.nodes) ? raw.nodes.map(sanitizeNode).filter(Boolean) : [];
|
|
252
21
|
const links = Array.isArray(raw.links) ? raw.links.map(sanitizeLink).filter(Boolean) : [];
|
|
253
22
|
const externalImports = Array.isArray(raw.externalImports)
|
|
254
|
-
? raw.externalImports.map(sanitizeExternalImport).filter(Boolean)
|
|
255
|
-
: [];
|
|
23
|
+
? raw.externalImports.map(sanitizeExternalImport).filter(Boolean) : [];
|
|
256
24
|
return {
|
|
257
25
|
syncPayloadV: 2,
|
|
258
26
|
repoBoundaryV: 1,
|
|
@@ -266,8 +34,6 @@ export function createSyncPayload(raw) {
|
|
|
266
34
|
}
|
|
267
35
|
|
|
268
36
|
export function createSyncPayloadV3(raw, evidence) {
|
|
269
|
-
// Reuse the v2 schema gates, but construct v3 arrays independently so the stricter path/identity
|
|
270
|
-
// rules cannot change graph-only compatibility for existing endpoints.
|
|
271
37
|
const base = createSyncPayload(raw);
|
|
272
38
|
if (!Number.isInteger(raw.edgeProvenanceV) || raw.edgeProvenanceV < 1) {
|
|
273
39
|
throw new Error('graph predates edge provenance metadata');
|