@ryanstark24/sfgraph-core 1.4.0 → 1.6.0
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/dist/analyze/apex-platform.d.ts +23 -0
- package/dist/analyze/apex-platform.d.ts.map +1 -0
- package/dist/analyze/apex-platform.js +112 -0
- package/dist/analyze/apex-platform.js.map +1 -0
- package/dist/analyze/audit-graph.d.ts +34 -10
- package/dist/analyze/audit-graph.d.ts.map +1 -1
- package/dist/analyze/audit-graph.js +360 -39
- package/dist/analyze/audit-graph.js.map +1 -1
- package/dist/analyze/component-scope.d.ts +82 -0
- package/dist/analyze/component-scope.d.ts.map +1 -0
- package/dist/analyze/component-scope.js +207 -0
- package/dist/analyze/component-scope.js.map +1 -0
- package/dist/analyze/containment.d.ts +91 -0
- package/dist/analyze/containment.d.ts.map +1 -0
- package/dist/analyze/containment.js +175 -0
- package/dist/analyze/containment.js.map +1 -0
- package/dist/analyze/cross-org.d.ts +35 -0
- package/dist/analyze/cross-org.d.ts.map +1 -1
- package/dist/analyze/cross-org.js +102 -3
- package/dist/analyze/cross-org.js.map +1 -1
- package/dist/analyze/dead-code.d.ts +99 -3
- package/dist/analyze/dead-code.d.ts.map +1 -1
- package/dist/analyze/dead-code.js +282 -10
- package/dist/analyze/dead-code.js.map +1 -1
- package/dist/analyze/dependencies.d.ts +20 -1
- package/dist/analyze/dependencies.d.ts.map +1 -1
- package/dist/analyze/dependencies.js +96 -12
- package/dist/analyze/dependencies.js.map +1 -1
- package/dist/analyze/dependents.d.ts +111 -1
- package/dist/analyze/dependents.d.ts.map +1 -1
- package/dist/analyze/dependents.js +282 -20
- package/dist/analyze/dependents.js.map +1 -1
- package/dist/analyze/deployment-manifest/generate.d.ts +24 -0
- package/dist/analyze/deployment-manifest/generate.d.ts.map +1 -1
- package/dist/analyze/deployment-manifest/generate.js +40 -12
- package/dist/analyze/deployment-manifest/generate.js.map +1 -1
- package/dist/analyze/deployment-manifest/member-name-formatters.d.ts.map +1 -1
- package/dist/analyze/deployment-manifest/member-name-formatters.js +1 -0
- package/dist/analyze/deployment-manifest/member-name-formatters.js.map +1 -1
- package/dist/analyze/deployment-manifest/member-types.d.ts.map +1 -1
- package/dist/analyze/deployment-manifest/member-types.js +2 -0
- package/dist/analyze/deployment-manifest/member-types.js.map +1 -1
- package/dist/analyze/diff-seeds.d.ts +33 -0
- package/dist/analyze/diff-seeds.d.ts.map +1 -0
- package/dist/analyze/diff-seeds.js +299 -0
- package/dist/analyze/diff-seeds.js.map +1 -0
- package/dist/analyze/edge-filters.d.ts +25 -0
- package/dist/analyze/edge-filters.d.ts.map +1 -1
- package/dist/analyze/edge-filters.js +78 -2
- package/dist/analyze/edge-filters.js.map +1 -1
- package/dist/analyze/field-scope.d.ts +25 -0
- package/dist/analyze/field-scope.d.ts.map +1 -0
- package/dist/analyze/field-scope.js +94 -0
- package/dist/analyze/field-scope.js.map +1 -0
- package/dist/analyze/find-nodes.d.ts +48 -12
- package/dist/analyze/find-nodes.d.ts.map +1 -1
- package/dist/analyze/find-nodes.js +323 -12
- package/dist/analyze/find-nodes.js.map +1 -1
- package/dist/analyze/findings.d.ts.map +1 -1
- package/dist/analyze/findings.js +14 -0
- package/dist/analyze/findings.js.map +1 -1
- package/dist/analyze/git-diff.d.ts +27 -1
- package/dist/analyze/git-diff.d.ts.map +1 -1
- package/dist/analyze/git-diff.js +198 -26
- package/dist/analyze/git-diff.js.map +1 -1
- package/dist/analyze/governor.d.ts +25 -4
- package/dist/analyze/governor.d.ts.map +1 -1
- package/dist/analyze/governor.js +82 -18
- package/dist/analyze/governor.js.map +1 -1
- package/dist/analyze/index.d.ts +6 -0
- package/dist/analyze/index.d.ts.map +1 -1
- package/dist/analyze/index.js +6 -0
- package/dist/analyze/index.js.map +1 -1
- package/dist/analyze/path-to-qname.d.ts +9 -0
- package/dist/analyze/path-to-qname.d.ts.map +1 -1
- package/dist/analyze/path-to-qname.js +58 -15
- package/dist/analyze/path-to-qname.js.map +1 -1
- package/dist/analyze/populate.d.ts +40 -0
- package/dist/analyze/populate.d.ts.map +1 -1
- package/dist/analyze/populate.js +148 -48
- package/dist/analyze/populate.js.map +1 -1
- package/dist/analyze/pseudo-endpoints.d.ts +67 -0
- package/dist/analyze/pseudo-endpoints.d.ts.map +1 -0
- package/dist/analyze/pseudo-endpoints.js +78 -0
- package/dist/analyze/pseudo-endpoints.js.map +1 -0
- package/dist/analyze/security.d.ts +2 -0
- package/dist/analyze/security.d.ts.map +1 -1
- package/dist/analyze/security.js +44 -15
- package/dist/analyze/security.js.map +1 -1
- package/dist/analyze/test-coverage.d.ts +48 -0
- package/dist/analyze/test-coverage.d.ts.map +1 -1
- package/dist/analyze/test-coverage.js +72 -1
- package/dist/analyze/test-coverage.js.map +1 -1
- package/dist/analyze/wip-changed-files.d.ts +88 -0
- package/dist/analyze/wip-changed-files.d.ts.map +1 -0
- package/dist/analyze/wip-changed-files.js +422 -0
- package/dist/analyze/wip-changed-files.js.map +1 -0
- package/dist/analyze/wip-impact.d.ts +59 -0
- package/dist/analyze/wip-impact.d.ts.map +1 -1
- package/dist/analyze/wip-impact.js +199 -126
- package/dist/analyze/wip-impact.js.map +1 -1
- package/dist/domain/apex-platform.d.ts +10 -0
- package/dist/domain/apex-platform.d.ts.map +1 -0
- package/dist/domain/apex-platform.js +231 -0
- package/dist/domain/apex-platform.js.map +1 -0
- package/dist/domain/index.d.ts +2 -0
- package/dist/domain/index.d.ts.map +1 -1
- package/dist/domain/index.js +2 -0
- package/dist/domain/index.js.map +1 -1
- package/dist/domain/rel-types.d.ts +7 -0
- package/dist/domain/rel-types.d.ts.map +1 -1
- package/dist/domain/rel-types.js +7 -0
- package/dist/domain/rel-types.js.map +1 -1
- package/dist/domain/standard-sobjects.d.ts +20 -0
- package/dist/domain/standard-sobjects.d.ts.map +1 -0
- package/dist/domain/standard-sobjects.js +183 -0
- package/dist/domain/standard-sobjects.js.map +1 -0
- package/dist/embedding/cache.d.ts +41 -0
- package/dist/embedding/cache.d.ts.map +1 -0
- package/dist/embedding/cache.js +69 -0
- package/dist/embedding/cache.js.map +1 -0
- package/dist/embedding/embed.d.ts +59 -0
- package/dist/embedding/embed.d.ts.map +1 -1
- package/dist/embedding/embed.js +193 -28
- package/dist/embedding/embed.js.map +1 -1
- package/dist/embedding/index.d.ts +7 -0
- package/dist/embedding/index.d.ts.map +1 -1
- package/dist/embedding/index.js +4 -0
- package/dist/embedding/index.js.map +1 -1
- package/dist/embedding/pool.d.ts +66 -6
- package/dist/embedding/pool.d.ts.map +1 -1
- package/dist/embedding/pool.js +156 -6
- package/dist/embedding/pool.js.map +1 -1
- package/dist/embedding/queue.d.ts +166 -9
- package/dist/embedding/queue.d.ts.map +1 -1
- package/dist/embedding/queue.js +397 -39
- package/dist/embedding/queue.js.map +1 -1
- package/dist/embedding/tokenize.d.ts +18 -0
- package/dist/embedding/tokenize.d.ts.map +1 -0
- package/dist/embedding/tokenize.js +43 -0
- package/dist/embedding/tokenize.js.map +1 -0
- package/dist/embedding/worker.d.ts +0 -5
- package/dist/embedding/worker.d.ts.map +1 -1
- package/dist/embedding/worker.js +27 -4
- package/dist/embedding/worker.js.map +1 -1
- package/dist/extractors/filesystem/index.d.ts +21 -1
- package/dist/extractors/filesystem/index.d.ts.map +1 -1
- package/dist/extractors/filesystem/index.js +195 -38
- package/dist/extractors/filesystem/index.js.map +1 -1
- package/dist/extractors/filesystem/vlocity-datapacks.d.ts +27 -0
- package/dist/extractors/filesystem/vlocity-datapacks.d.ts.map +1 -0
- package/dist/extractors/filesystem/vlocity-datapacks.js +201 -0
- package/dist/extractors/filesystem/vlocity-datapacks.js.map +1 -0
- package/dist/extractors/interfaces/metadata-source.d.ts +29 -0
- package/dist/extractors/interfaces/metadata-source.d.ts.map +1 -1
- package/dist/extractors/live-org/bulk-retrieve.d.ts +37 -1
- package/dist/extractors/live-org/bulk-retrieve.d.ts.map +1 -1
- package/dist/extractors/live-org/bulk-retrieve.js +233 -50
- package/dist/extractors/live-org/bulk-retrieve.js.map +1 -1
- package/dist/extractors/live-org/capabilities.d.ts +15 -0
- package/dist/extractors/live-org/capabilities.d.ts.map +1 -1
- package/dist/extractors/live-org/capabilities.js +54 -9
- package/dist/extractors/live-org/capabilities.js.map +1 -1
- package/dist/extractors/live-org/extractors/apex.d.ts +12 -2
- package/dist/extractors/live-org/extractors/apex.d.ts.map +1 -1
- package/dist/extractors/live-org/extractors/apex.js +151 -80
- package/dist/extractors/live-org/extractors/apex.js.map +1 -1
- package/dist/extractors/live-org/extractors/custom-settings.d.ts +2 -1
- package/dist/extractors/live-org/extractors/custom-settings.d.ts.map +1 -1
- package/dist/extractors/live-org/extractors/custom-settings.js +19 -9
- package/dist/extractors/live-org/extractors/custom-settings.js.map +1 -1
- package/dist/extractors/live-org/extractors/flow.d.ts +2 -1
- package/dist/extractors/live-org/extractors/flow.d.ts.map +1 -1
- package/dist/extractors/live-org/extractors/flow.js +12 -3
- package/dist/extractors/live-org/extractors/flow.js.map +1 -1
- package/dist/extractors/live-org/extractors/generic-metadata.d.ts +23 -3
- package/dist/extractors/live-org/extractors/generic-metadata.d.ts.map +1 -1
- package/dist/extractors/live-org/extractors/generic-metadata.js +110 -25
- package/dist/extractors/live-org/extractors/generic-metadata.js.map +1 -1
- package/dist/extractors/live-org/extractors/integration.d.ts +2 -1
- package/dist/extractors/live-org/extractors/integration.d.ts.map +1 -1
- package/dist/extractors/live-org/extractors/integration.js +14 -5
- package/dist/extractors/live-org/extractors/integration.js.map +1 -1
- package/dist/extractors/live-org/extractors/lwc.d.ts +2 -1
- package/dist/extractors/live-org/extractors/lwc.d.ts.map +1 -1
- package/dist/extractors/live-org/extractors/lwc.js +14 -6
- package/dist/extractors/live-org/extractors/lwc.js.map +1 -1
- package/dist/extractors/live-org/extractors/object.d.ts +2 -11
- package/dist/extractors/live-org/extractors/object.d.ts.map +1 -1
- package/dist/extractors/live-org/extractors/object.js +127 -226
- package/dist/extractors/live-org/extractors/object.js.map +1 -1
- package/dist/extractors/live-org/extractors/omnistudio.d.ts +3 -0
- package/dist/extractors/live-org/extractors/omnistudio.d.ts.map +1 -1
- package/dist/extractors/live-org/extractors/omnistudio.js +57 -22
- package/dist/extractors/live-org/extractors/omnistudio.js.map +1 -1
- package/dist/extractors/live-org/extractors/security.d.ts +12 -1
- package/dist/extractors/live-org/extractors/security.d.ts.map +1 -1
- package/dist/extractors/live-org/extractors/security.js +29 -7
- package/dist/extractors/live-org/extractors/security.js.map +1 -1
- package/dist/extractors/live-org/rate-limit.d.ts +7 -1
- package/dist/extractors/live-org/rate-limit.d.ts.map +1 -1
- package/dist/extractors/live-org/rate-limit.js +53 -10
- package/dist/extractors/live-org/rate-limit.js.map +1 -1
- package/dist/extractors/live-org/retry.d.ts +136 -0
- package/dist/extractors/live-org/retry.d.ts.map +1 -0
- package/dist/extractors/live-org/retry.js +416 -0
- package/dist/extractors/live-org/retry.js.map +1 -0
- package/dist/extractors/live-org/vlocity/runner.d.ts +2 -1
- package/dist/extractors/live-org/vlocity/runner.d.ts.map +1 -1
- package/dist/extractors/live-org/vlocity/runner.js +95 -67
- package/dist/extractors/live-org/vlocity/runner.js.map +1 -1
- package/dist/extractors/vlocity-shared/row.d.ts +19 -0
- package/dist/extractors/vlocity-shared/row.d.ts.map +1 -0
- package/dist/extractors/vlocity-shared/row.js +69 -0
- package/dist/extractors/vlocity-shared/row.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/ingest/delta.d.ts +70 -0
- package/dist/ingest/delta.d.ts.map +1 -0
- package/dist/ingest/delta.js +534 -0
- package/dist/ingest/delta.js.map +1 -0
- package/dist/ingest/detect-deletions-guard.d.ts +34 -0
- package/dist/ingest/detect-deletions-guard.d.ts.map +1 -1
- package/dist/ingest/detect-deletions-guard.js +59 -0
- package/dist/ingest/detect-deletions-guard.js.map +1 -1
- package/dist/ingest/index.d.ts +8 -1
- package/dist/ingest/index.d.ts.map +1 -1
- package/dist/ingest/index.js +4 -0
- package/dist/ingest/index.js.map +1 -1
- package/dist/ingest/live-ingest.d.ts +171 -7
- package/dist/ingest/live-ingest.d.ts.map +1 -1
- package/dist/ingest/live-ingest.js +1014 -249
- package/dist/ingest/live-ingest.js.map +1 -1
- package/dist/ingest/lock.d.ts +47 -0
- package/dist/ingest/lock.d.ts.map +1 -0
- package/dist/ingest/lock.js +222 -0
- package/dist/ingest/lock.js.map +1 -0
- package/dist/ingest/member-rows.d.ts +88 -0
- package/dist/ingest/member-rows.d.ts.map +1 -0
- package/dist/ingest/member-rows.js +152 -0
- package/dist/ingest/member-rows.js.map +1 -0
- package/dist/ingest/offline-org.d.ts +8 -0
- package/dist/ingest/offline-org.d.ts.map +1 -0
- package/dist/ingest/offline-org.js +41 -0
- package/dist/ingest/offline-org.js.map +1 -0
- package/dist/ingest/parse-member.d.ts +53 -0
- package/dist/ingest/parse-member.d.ts.map +1 -0
- package/dist/ingest/parse-member.js +276 -0
- package/dist/ingest/parse-member.js.map +1 -0
- package/dist/ingest/parse-pool.d.ts +139 -0
- package/dist/ingest/parse-pool.d.ts.map +1 -0
- package/dist/ingest/parse-pool.js +593 -0
- package/dist/ingest/parse-pool.js.map +1 -0
- package/dist/ingest/parse-worker.d.ts +3 -0
- package/dist/ingest/parse-worker.d.ts.map +1 -0
- package/dist/ingest/parse-worker.js +100 -0
- package/dist/ingest/parse-worker.js.map +1 -0
- package/dist/ingest/profile.d.ts +27 -0
- package/dist/ingest/profile.d.ts.map +1 -0
- package/dist/ingest/profile.js +48 -0
- package/dist/ingest/profile.js.map +1 -0
- package/dist/ingest/resolver-gates.d.ts +12 -0
- package/dist/ingest/resolver-gates.d.ts.map +1 -0
- package/dist/ingest/resolver-gates.js +53 -0
- package/dist/ingest/resolver-gates.js.map +1 -0
- package/dist/parsers/apex/arity-resolver.d.ts +16 -3
- package/dist/parsers/apex/arity-resolver.d.ts.map +1 -1
- package/dist/parsers/apex/arity-resolver.js +31 -2
- package/dist/parsers/apex/arity-resolver.js.map +1 -1
- package/dist/parsers/apex/ast-extractor.d.ts +4 -0
- package/dist/parsers/apex/ast-extractor.d.ts.map +1 -1
- package/dist/parsers/apex/ast-extractor.js +96 -29
- package/dist/parsers/apex/ast-extractor.js.map +1 -1
- package/dist/parsers/apex/class-refs.d.ts +78 -0
- package/dist/parsers/apex/class-refs.d.ts.map +1 -0
- package/dist/parsers/apex/class-refs.js +465 -0
- package/dist/parsers/apex/class-refs.js.map +1 -0
- package/dist/parsers/apex/class.d.ts +158 -0
- package/dist/parsers/apex/class.d.ts.map +1 -1
- package/dist/parsers/apex/class.js +1025 -183
- package/dist/parsers/apex/class.js.map +1 -1
- package/dist/parsers/apex/dynamic-soql.d.ts +52 -0
- package/dist/parsers/apex/dynamic-soql.d.ts.map +1 -0
- package/dist/parsers/apex/dynamic-soql.js +427 -0
- package/dist/parsers/apex/dynamic-soql.js.map +1 -0
- package/dist/parsers/apex/field-access.d.ts +65 -0
- package/dist/parsers/apex/field-access.d.ts.map +1 -0
- package/dist/parsers/apex/field-access.js +438 -0
- package/dist/parsers/apex/field-access.js.map +1 -0
- package/dist/parsers/apex/interface-ref-resolver.d.ts +32 -0
- package/dist/parsers/apex/interface-ref-resolver.d.ts.map +1 -0
- package/dist/parsers/apex/interface-ref-resolver.js +64 -0
- package/dist/parsers/apex/interface-ref-resolver.js.map +1 -0
- package/dist/parsers/apex/name-refs.d.ts +83 -0
- package/dist/parsers/apex/name-refs.d.ts.map +1 -0
- package/dist/parsers/apex/name-refs.js +465 -0
- package/dist/parsers/apex/name-refs.js.map +1 -0
- package/dist/parsers/apex/page-refs.d.ts +11 -0
- package/dist/parsers/apex/page-refs.d.ts.map +1 -0
- package/dist/parsers/apex/page-refs.js +34 -0
- package/dist/parsers/apex/page-refs.js.map +1 -0
- package/dist/parsers/apex/ref-resolver.d.ts +58 -0
- package/dist/parsers/apex/ref-resolver.d.ts.map +1 -0
- package/dist/parsers/apex/ref-resolver.js +348 -0
- package/dist/parsers/apex/ref-resolver.js.map +1 -0
- package/dist/parsers/apex/soql-fields.d.ts +75 -0
- package/dist/parsers/apex/soql-fields.d.ts.map +1 -0
- package/dist/parsers/apex/soql-fields.js +338 -0
- package/dist/parsers/apex/soql-fields.js.map +1 -0
- package/dist/parsers/apex/trigger.d.ts.map +1 -1
- package/dist/parsers/apex/trigger.js +90 -2
- package/dist/parsers/apex/trigger.js.map +1 -1
- package/dist/parsers/apex/vlocity-calls.d.ts +25 -0
- package/dist/parsers/apex/vlocity-calls.d.ts.map +1 -0
- package/dist/parsers/apex/vlocity-calls.js +225 -0
- package/dist/parsers/apex/vlocity-calls.js.map +1 -0
- package/dist/parsers/aura/bundle.d.ts +39 -0
- package/dist/parsers/aura/bundle.d.ts.map +1 -0
- package/dist/parsers/aura/bundle.js +269 -0
- package/dist/parsers/aura/bundle.js.map +1 -0
- package/dist/parsers/aura/embed-resolver.d.ts +17 -0
- package/dist/parsers/aura/embed-resolver.d.ts.map +1 -0
- package/dist/parsers/aura/embed-resolver.js +58 -0
- package/dist/parsers/aura/embed-resolver.js.map +1 -0
- package/dist/parsers/aura/index.d.ts +4 -0
- package/dist/parsers/aura/index.d.ts.map +1 -0
- package/dist/parsers/aura/index.js +6 -0
- package/dist/parsers/aura/index.js.map +1 -0
- package/dist/parsers/common.d.ts +9 -0
- package/dist/parsers/common.d.ts.map +1 -1
- package/dist/parsers/common.js +17 -0
- package/dist/parsers/common.js.map +1 -1
- package/dist/parsers/cross-flavor-resolver.js +8 -2
- package/dist/parsers/cross-flavor-resolver.js.map +1 -1
- package/dist/parsers/flow/invocable-resolver.d.ts.map +1 -1
- package/dist/parsers/flow/invocable-resolver.js +2 -0
- package/dist/parsers/flow/invocable-resolver.js.map +1 -1
- package/dist/parsers/flow/parser.d.ts +9 -0
- package/dist/parsers/flow/parser.d.ts.map +1 -1
- package/dist/parsers/flow/parser.js +327 -2
- package/dist/parsers/flow/parser.js.map +1 -1
- package/dist/parsers/flow/relationship-resolver.d.ts +34 -0
- package/dist/parsers/flow/relationship-resolver.d.ts.map +1 -0
- package/dist/parsers/flow/relationship-resolver.js +199 -0
- package/dist/parsers/flow/relationship-resolver.js.map +1 -0
- package/dist/parsers/generic/opaque-node-parser.d.ts +5 -1
- package/dist/parsers/generic/opaque-node-parser.d.ts.map +1 -1
- package/dist/parsers/generic/opaque-node-parser.js +37 -5
- package/dist/parsers/generic/opaque-node-parser.js.map +1 -1
- package/dist/parsers/generic/reflection-walker.d.ts +7 -0
- package/dist/parsers/generic/reflection-walker.d.ts.map +1 -1
- package/dist/parsers/generic/reflection-walker.js +37 -10
- package/dist/parsers/generic/reflection-walker.js.map +1 -1
- package/dist/parsers/hash-salts.d.ts +72 -0
- package/dist/parsers/hash-salts.d.ts.map +1 -0
- package/dist/parsers/hash-salts.js +91 -0
- package/dist/parsers/hash-salts.js.map +1 -0
- package/dist/parsers/index.d.ts +2 -0
- package/dist/parsers/index.d.ts.map +1 -1
- package/dist/parsers/index.js +2 -0
- package/dist/parsers/index.js.map +1 -1
- package/dist/parsers/lwc/bundle.d.ts +1 -0
- package/dist/parsers/lwc/bundle.d.ts.map +1 -1
- package/dist/parsers/lwc/bundle.js +37 -2
- package/dist/parsers/lwc/bundle.js.map +1 -1
- package/dist/parsers/lwc/field-key-resolver.d.ts +32 -0
- package/dist/parsers/lwc/field-key-resolver.d.ts.map +1 -0
- package/dist/parsers/lwc/field-key-resolver.js +92 -0
- package/dist/parsers/lwc/field-key-resolver.js.map +1 -0
- package/dist/parsers/lwc/html-visitor.d.ts +1 -1
- package/dist/parsers/lwc/html-visitor.d.ts.map +1 -1
- package/dist/parsers/lwc/html-visitor.js +78 -1
- package/dist/parsers/lwc/html-visitor.js.map +1 -1
- package/dist/parsers/lwc/js-visitor.d.ts +16 -0
- package/dist/parsers/lwc/js-visitor.d.ts.map +1 -1
- package/dist/parsers/lwc/js-visitor.js +348 -10
- package/dist/parsers/lwc/js-visitor.js.map +1 -1
- package/dist/parsers/lwc/omnidef.d.ts +10 -0
- package/dist/parsers/lwc/omnidef.d.ts.map +1 -0
- package/dist/parsers/lwc/omnidef.js +127 -0
- package/dist/parsers/lwc/omnidef.js.map +1 -0
- package/dist/parsers/lwc/xml-meta.d.ts.map +1 -1
- package/dist/parsers/lwc/xml-meta.js +16 -1
- package/dist/parsers/lwc/xml-meta.js.map +1 -1
- package/dist/parsers/object/formula-hop-resolver.d.ts +33 -0
- package/dist/parsers/object/formula-hop-resolver.d.ts.map +1 -0
- package/dist/parsers/object/formula-hop-resolver.js +60 -0
- package/dist/parsers/object/formula-hop-resolver.js.map +1 -0
- package/dist/parsers/object/formula-refs.d.ts +40 -0
- package/dist/parsers/object/formula-refs.d.ts.map +1 -0
- package/dist/parsers/object/formula-refs.js +129 -0
- package/dist/parsers/object/formula-refs.js.map +1 -0
- package/dist/parsers/object/object.d.ts +3 -0
- package/dist/parsers/object/object.d.ts.map +1 -1
- package/dist/parsers/object/object.js +53 -52
- package/dist/parsers/object/object.js.map +1 -1
- package/dist/parsers/omnistudio/data-transform.d.ts.map +1 -1
- package/dist/parsers/omnistudio/data-transform.js +2 -2
- package/dist/parsers/omnistudio/data-transform.js.map +1 -1
- package/dist/parsers/omnistudio/integration-procedure.d.ts.map +1 -1
- package/dist/parsers/omnistudio/integration-procedure.js +4 -5
- package/dist/parsers/omnistudio/integration-procedure.js.map +1 -1
- package/dist/parsers/omnistudio/overlap-detector.d.ts.map +1 -1
- package/dist/parsers/omnistudio/overlap-detector.js +27 -2
- package/dist/parsers/omnistudio/overlap-detector.js.map +1 -1
- package/dist/parsers/omnistudio/process.d.ts.map +1 -1
- package/dist/parsers/omnistudio/process.js +4 -5
- package/dist/parsers/omnistudio/process.js.map +1 -1
- package/dist/parsers/omnistudio/remote-refs.d.ts +11 -0
- package/dist/parsers/omnistudio/remote-refs.d.ts.map +1 -0
- package/dist/parsers/omnistudio/remote-refs.js +17 -0
- package/dist/parsers/omnistudio/remote-refs.js.map +1 -0
- package/dist/parsers/omnistudio/ui-card.d.ts.map +1 -1
- package/dist/parsers/omnistudio/ui-card.js +4 -5
- package/dist/parsers/omnistudio/ui-card.js.map +1 -1
- package/dist/parsers/resolver-prune.d.ts +14 -0
- package/dist/parsers/resolver-prune.d.ts.map +1 -0
- package/dist/parsers/resolver-prune.js +29 -0
- package/dist/parsers/resolver-prune.js.map +1 -0
- package/dist/parsers/rules/_engine.d.ts.map +1 -1
- package/dist/parsers/rules/_engine.js +4 -0
- package/dist/parsers/rules/_engine.js.map +1 -1
- package/dist/parsers/rules/_engine.ts +3 -0
- package/dist/parsers/rules/_loader.d.ts +8 -0
- package/dist/parsers/rules/_loader.d.ts.map +1 -1
- package/dist/parsers/rules/_loader.js +17 -0
- package/dist/parsers/rules/_loader.js.map +1 -1
- package/dist/parsers/rules/_loader.ts +19 -0
- package/dist/parsers/rules/_schema.d.ts +12 -12
- package/dist/parsers/rules/_selectors.d.ts +1 -0
- package/dist/parsers/rules/_selectors.d.ts.map +1 -1
- package/dist/parsers/rules/_selectors.js +6 -0
- package/dist/parsers/rules/_selectors.js.map +1 -1
- package/dist/parsers/rules/_selectors.ts +6 -0
- package/dist/parsers/rules/apex-component.yml +49 -4
- package/dist/parsers/rules/apex-page.yml +49 -4
- package/dist/parsers/rules/approval-process.yml +25 -5
- package/dist/parsers/rules/custom-metadata-type.yml +7 -7
- package/dist/parsers/rules/custom-tab.yml +41 -0
- package/dist/parsers/rules/lightning-page.yml +4 -2
- package/dist/parsers/rules/workflow.yml +30 -10
- package/dist/parsers/vf/refs.d.ts +39 -0
- package/dist/parsers/vf/refs.d.ts.map +1 -0
- package/dist/parsers/vf/refs.js +152 -0
- package/dist/parsers/vf/refs.js.map +1 -0
- package/dist/parsers/vlocity/apex-resolver.d.ts +21 -0
- package/dist/parsers/vlocity/apex-resolver.d.ts.map +1 -0
- package/dist/parsers/vlocity/apex-resolver.js +115 -0
- package/dist/parsers/vlocity/apex-resolver.js.map +1 -0
- package/dist/parsers/vlocity/common.d.ts +56 -1
- package/dist/parsers/vlocity/common.d.ts.map +1 -1
- package/dist/parsers/vlocity/common.js +275 -7
- package/dist/parsers/vlocity/common.js.map +1 -1
- package/dist/parsers/vlocity/data-raptor.d.ts +9 -0
- package/dist/parsers/vlocity/data-raptor.d.ts.map +1 -1
- package/dist/parsers/vlocity/data-raptor.js +133 -31
- package/dist/parsers/vlocity/data-raptor.js.map +1 -1
- package/dist/parsers/vlocity/datapack-refs.d.ts +22 -0
- package/dist/parsers/vlocity/datapack-refs.d.ts.map +1 -0
- package/dist/parsers/vlocity/datapack-refs.js +126 -0
- package/dist/parsers/vlocity/datapack-refs.js.map +1 -0
- package/dist/parsers/vlocity/dr-relationship-resolver.d.ts +26 -0
- package/dist/parsers/vlocity/dr-relationship-resolver.d.ts.map +1 -0
- package/dist/parsers/vlocity/dr-relationship-resolver.js +137 -0
- package/dist/parsers/vlocity/dr-relationship-resolver.js.map +1 -0
- package/dist/parsers/vlocity/integration-procedure.d.ts.map +1 -1
- package/dist/parsers/vlocity/integration-procedure.js +15 -48
- package/dist/parsers/vlocity/integration-procedure.js.map +1 -1
- package/dist/parsers/vlocity/name-match-resolver.d.ts +21 -0
- package/dist/parsers/vlocity/name-match-resolver.d.ts.map +1 -0
- package/dist/parsers/vlocity/name-match-resolver.js +97 -0
- package/dist/parsers/vlocity/name-match-resolver.js.map +1 -0
- package/dist/parsers/vlocity/omni-script.d.ts.map +1 -1
- package/dist/parsers/vlocity/omni-script.js +18 -32
- package/dist/parsers/vlocity/omni-script.js.map +1 -1
- package/dist/parsers/vlocity/vlocity-card.d.ts.map +1 -1
- package/dist/parsers/vlocity/vlocity-card.js +30 -36
- package/dist/parsers/vlocity/vlocity-card.js.map +1 -1
- package/dist/render/mermaid/dependency-graph.d.ts.map +1 -1
- package/dist/render/mermaid/dependency-graph.js +13 -1
- package/dist/render/mermaid/dependency-graph.js.map +1 -1
- package/dist/render/mermaid/diff.d.ts.map +1 -1
- package/dist/render/mermaid/diff.js +4 -2
- package/dist/render/mermaid/diff.js.map +1 -1
- package/dist/render/mermaid/shared.d.ts +7 -0
- package/dist/render/mermaid/shared.d.ts.map +1 -1
- package/dist/render/mermaid/shared.js +15 -6
- package/dist/render/mermaid/shared.js.map +1 -1
- package/dist/storage/index.d.ts +3 -3
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +2 -2
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/interfaces.d.ts +155 -1
- package/dist/storage/interfaces.d.ts.map +1 -1
- package/dist/storage/sqlite/graph-store.d.ts +352 -3
- package/dist/storage/sqlite/graph-store.d.ts.map +1 -1
- package/dist/storage/sqlite/graph-store.js +1683 -74
- package/dist/storage/sqlite/graph-store.js.map +1 -1
- package/dist/storage/sqlite/migrations.d.ts +11 -0
- package/dist/storage/sqlite/migrations.d.ts.map +1 -1
- package/dist/storage/sqlite/migrations.js +226 -11
- package/dist/storage/sqlite/migrations.js.map +1 -1
- package/dist/storage/sqlite/snapshot-store.d.ts +79 -3
- package/dist/storage/sqlite/snapshot-store.d.ts.map +1 -1
- package/dist/storage/sqlite/snapshot-store.js +500 -100
- package/dist/storage/sqlite/snapshot-store.js.map +1 -1
- package/dist/storage/sqlite/snapshot-versions.d.ts +51 -0
- package/dist/storage/sqlite/snapshot-versions.d.ts.map +1 -0
- package/dist/storage/sqlite/snapshot-versions.js +209 -0
- package/dist/storage/sqlite/snapshot-versions.js.map +1 -0
- package/dist/storage/sqlite/vector-store.d.ts +12 -0
- package/dist/storage/sqlite/vector-store.d.ts.map +1 -1
- package/dist/storage/sqlite/vector-store.js +57 -14
- package/dist/storage/sqlite/vector-store.js.map +1 -1
- package/dist/util/process-owner.d.ts +35 -0
- package/dist/util/process-owner.d.ts.map +1 -0
- package/dist/util/process-owner.js +87 -0
- package/dist/util/process-owner.js.map +1 -0
- package/dist/util/worker-heap-cap.d.ts +10 -0
- package/dist/util/worker-heap-cap.d.ts.map +1 -0
- package/dist/util/worker-heap-cap.js +65 -0
- package/dist/util/worker-heap-cap.js.map +1 -0
- package/package.json +6 -7
- package/dist/analyze/__tests__/audit-graph.test.d.ts +0 -2
- package/dist/analyze/__tests__/audit-graph.test.d.ts.map +0 -1
- package/dist/analyze/__tests__/audit-graph.test.js +0 -201
- package/dist/analyze/__tests__/audit-graph.test.js.map +0 -1
- package/dist/analyze/__tests__/cross-org-two-store.test.d.ts +0 -2
- package/dist/analyze/__tests__/cross-org-two-store.test.d.ts.map +0 -1
- package/dist/analyze/__tests__/cross-org-two-store.test.js +0 -68
- package/dist/analyze/__tests__/cross-org-two-store.test.js.map +0 -1
- package/dist/analyze/__tests__/dead-code-confidence.test.d.ts +0 -2
- package/dist/analyze/__tests__/dead-code-confidence.test.d.ts.map +0 -1
- package/dist/analyze/__tests__/dead-code-confidence.test.js +0 -66
- package/dist/analyze/__tests__/dead-code-confidence.test.js.map +0 -1
- package/dist/analyze/__tests__/deployment-manifest.test.d.ts +0 -2
- package/dist/analyze/__tests__/deployment-manifest.test.d.ts.map +0 -1
- package/dist/analyze/__tests__/deployment-manifest.test.js +0 -66
- package/dist/analyze/__tests__/deployment-manifest.test.js.map +0 -1
- package/dist/analyze/__tests__/edge-filters.test.d.ts +0 -2
- package/dist/analyze/__tests__/edge-filters.test.d.ts.map +0 -1
- package/dist/analyze/__tests__/edge-filters.test.js +0 -66
- package/dist/analyze/__tests__/edge-filters.test.js.map +0 -1
- package/dist/analyze/__tests__/find-nodes.test.d.ts +0 -2
- package/dist/analyze/__tests__/find-nodes.test.d.ts.map +0 -1
- package/dist/analyze/__tests__/find-nodes.test.js +0 -129
- package/dist/analyze/__tests__/find-nodes.test.js.map +0 -1
- package/dist/analyze/__tests__/findings.test.d.ts +0 -2
- package/dist/analyze/__tests__/findings.test.d.ts.map +0 -1
- package/dist/analyze/__tests__/findings.test.js +0 -100
- package/dist/analyze/__tests__/findings.test.js.map +0 -1
- package/dist/analyze/__tests__/governor-risks-detection.test.d.ts +0 -2
- package/dist/analyze/__tests__/governor-risks-detection.test.d.ts.map +0 -1
- package/dist/analyze/__tests__/governor-risks-detection.test.js +0 -160
- package/dist/analyze/__tests__/governor-risks-detection.test.js.map +0 -1
- package/dist/analyze/__tests__/populate.test.d.ts +0 -2
- package/dist/analyze/__tests__/populate.test.d.ts.map +0 -1
- package/dist/analyze/__tests__/populate.test.js +0 -129
- package/dist/analyze/__tests__/populate.test.js.map +0 -1
- package/dist/analyze/__tests__/security-fls-filter.test.d.ts +0 -2
- package/dist/analyze/__tests__/security-fls-filter.test.d.ts.map +0 -1
- package/dist/analyze/__tests__/security-fls-filter.test.js +0 -23
- package/dist/analyze/__tests__/security-fls-filter.test.js.map +0 -1
- package/dist/analyze/__tests__/traversal-caps.test.d.ts +0 -2
- package/dist/analyze/__tests__/traversal-caps.test.d.ts.map +0 -1
- package/dist/analyze/__tests__/traversal-caps.test.js +0 -129
- package/dist/analyze/__tests__/traversal-caps.test.js.map +0 -1
- package/dist/analyze/__tests__/wip-impact.test.d.ts +0 -2
- package/dist/analyze/__tests__/wip-impact.test.d.ts.map +0 -1
- package/dist/analyze/__tests__/wip-impact.test.js +0 -134
- package/dist/analyze/__tests__/wip-impact.test.js.map +0 -1
- package/dist/embedding/__tests__/embed.test.d.ts +0 -2
- package/dist/embedding/__tests__/embed.test.d.ts.map +0 -1
- package/dist/embedding/__tests__/embed.test.js +0 -72
- package/dist/embedding/__tests__/embed.test.js.map +0 -1
- package/dist/embedding/__tests__/queue.test.d.ts +0 -2
- package/dist/embedding/__tests__/queue.test.d.ts.map +0 -1
- package/dist/embedding/__tests__/queue.test.js +0 -64
- package/dist/embedding/__tests__/queue.test.js.map +0 -1
- package/dist/extractors/__tests__/network-egress.test.d.ts +0 -2
- package/dist/extractors/__tests__/network-egress.test.d.ts.map +0 -1
- package/dist/extractors/__tests__/network-egress.test.js +0 -32
- package/dist/extractors/__tests__/network-egress.test.js.map +0 -1
- package/dist/extractors/filesystem/__tests__/filesystem.test.d.ts +0 -2
- package/dist/extractors/filesystem/__tests__/filesystem.test.d.ts.map +0 -1
- package/dist/extractors/filesystem/__tests__/filesystem.test.js +0 -96
- package/dist/extractors/filesystem/__tests__/filesystem.test.js.map +0 -1
- package/dist/extractors/live-org/__tests__/_jsforce-mock.d.ts +0 -38
- package/dist/extractors/live-org/__tests__/_jsforce-mock.d.ts.map +0 -1
- package/dist/extractors/live-org/__tests__/_jsforce-mock.js +0 -96
- package/dist/extractors/live-org/__tests__/_jsforce-mock.js.map +0 -1
- package/dist/extractors/live-org/__tests__/auth.test.d.ts +0 -2
- package/dist/extractors/live-org/__tests__/auth.test.d.ts.map +0 -1
- package/dist/extractors/live-org/__tests__/auth.test.js +0 -85
- package/dist/extractors/live-org/__tests__/auth.test.js.map +0 -1
- package/dist/extractors/live-org/__tests__/bulk-retrieve.test.d.ts +0 -2
- package/dist/extractors/live-org/__tests__/bulk-retrieve.test.d.ts.map +0 -1
- package/dist/extractors/live-org/__tests__/bulk-retrieve.test.js +0 -150
- package/dist/extractors/live-org/__tests__/bulk-retrieve.test.js.map +0 -1
- package/dist/extractors/live-org/__tests__/capabilities.test.d.ts +0 -2
- package/dist/extractors/live-org/__tests__/capabilities.test.d.ts.map +0 -1
- package/dist/extractors/live-org/__tests__/capabilities.test.js +0 -54
- package/dist/extractors/live-org/__tests__/capabilities.test.js.map +0 -1
- package/dist/extractors/live-org/__tests__/custom-settings.test.d.ts +0 -2
- package/dist/extractors/live-org/__tests__/custom-settings.test.d.ts.map +0 -1
- package/dist/extractors/live-org/__tests__/custom-settings.test.js +0 -79
- package/dist/extractors/live-org/__tests__/custom-settings.test.js.map +0 -1
- package/dist/extractors/live-org/__tests__/discovery.test.d.ts +0 -2
- package/dist/extractors/live-org/__tests__/discovery.test.d.ts.map +0 -1
- package/dist/extractors/live-org/__tests__/discovery.test.js +0 -55
- package/dist/extractors/live-org/__tests__/discovery.test.js.map +0 -1
- package/dist/extractors/live-org/__tests__/dispatch.test.d.ts +0 -2
- package/dist/extractors/live-org/__tests__/dispatch.test.d.ts.map +0 -1
- package/dist/extractors/live-org/__tests__/dispatch.test.js +0 -68
- package/dist/extractors/live-org/__tests__/dispatch.test.js.map +0 -1
- package/dist/extractors/live-org/__tests__/extractor-enrichment.test.d.ts +0 -2
- package/dist/extractors/live-org/__tests__/extractor-enrichment.test.d.ts.map +0 -1
- package/dist/extractors/live-org/__tests__/extractor-enrichment.test.js +0 -374
- package/dist/extractors/live-org/__tests__/extractor-enrichment.test.js.map +0 -1
- package/dist/extractors/live-org/__tests__/liveness.test.d.ts +0 -2
- package/dist/extractors/live-org/__tests__/liveness.test.d.ts.map +0 -1
- package/dist/extractors/live-org/__tests__/liveness.test.js +0 -148
- package/dist/extractors/live-org/__tests__/liveness.test.js.map +0 -1
- package/dist/extractors/live-org/__tests__/mcd-baseline.test.d.ts +0 -2
- package/dist/extractors/live-org/__tests__/mcd-baseline.test.d.ts.map +0 -1
- package/dist/extractors/live-org/__tests__/mcd-baseline.test.js +0 -177
- package/dist/extractors/live-org/__tests__/mcd-baseline.test.js.map +0 -1
- package/dist/extractors/live-org/__tests__/metadata-read-batch.test.d.ts +0 -2
- package/dist/extractors/live-org/__tests__/metadata-read-batch.test.d.ts.map +0 -1
- package/dist/extractors/live-org/__tests__/metadata-read-batch.test.js +0 -75
- package/dist/extractors/live-org/__tests__/metadata-read-batch.test.js.map +0 -1
- package/dist/extractors/live-org/__tests__/omnistudio-retrieve.test.d.ts +0 -2
- package/dist/extractors/live-org/__tests__/omnistudio-retrieve.test.d.ts.map +0 -1
- package/dist/extractors/live-org/__tests__/omnistudio-retrieve.test.js +0 -135
- package/dist/extractors/live-org/__tests__/omnistudio-retrieve.test.js.map +0 -1
- package/dist/extractors/live-org/__tests__/pools.test.d.ts +0 -2
- package/dist/extractors/live-org/__tests__/pools.test.d.ts.map +0 -1
- package/dist/extractors/live-org/__tests__/pools.test.js +0 -78
- package/dist/extractors/live-org/__tests__/pools.test.js.map +0 -1
- package/dist/extractors/live-org/__tests__/rate-limit.test.d.ts +0 -2
- package/dist/extractors/live-org/__tests__/rate-limit.test.d.ts.map +0 -1
- package/dist/extractors/live-org/__tests__/rate-limit.test.js +0 -73
- package/dist/extractors/live-org/__tests__/rate-limit.test.js.map +0 -1
- package/dist/extractors/live-org/__tests__/read-only-proxy.test.d.ts +0 -2
- package/dist/extractors/live-org/__tests__/read-only-proxy.test.d.ts.map +0 -1
- package/dist/extractors/live-org/__tests__/read-only-proxy.test.js +0 -376
- package/dist/extractors/live-org/__tests__/read-only-proxy.test.js.map +0 -1
- package/dist/extractors/live-org/__tests__/soql-rebatch.test.d.ts +0 -2
- package/dist/extractors/live-org/__tests__/soql-rebatch.test.d.ts.map +0 -1
- package/dist/extractors/live-org/__tests__/soql-rebatch.test.js +0 -118
- package/dist/extractors/live-org/__tests__/soql-rebatch.test.js.map +0 -1
- package/dist/extractors/live-org/__tests__/source-member.test.d.ts +0 -2
- package/dist/extractors/live-org/__tests__/source-member.test.d.ts.map +0 -1
- package/dist/extractors/live-org/__tests__/source-member.test.js +0 -84
- package/dist/extractors/live-org/__tests__/source-member.test.js.map +0 -1
- package/dist/extractors/live-org/__tests__/stop-waiting.test.d.ts +0 -2
- package/dist/extractors/live-org/__tests__/stop-waiting.test.d.ts.map +0 -1
- package/dist/extractors/live-org/__tests__/stop-waiting.test.js +0 -243
- package/dist/extractors/live-org/__tests__/stop-waiting.test.js.map +0 -1
- package/dist/extractors/live-org/__tests__/vlocity-runner.test.d.ts +0 -2
- package/dist/extractors/live-org/__tests__/vlocity-runner.test.d.ts.map +0 -1
- package/dist/extractors/live-org/__tests__/vlocity-runner.test.js +0 -115
- package/dist/extractors/live-org/__tests__/vlocity-runner.test.js.map +0 -1
- package/dist/extractors/live-org/__tests__/watchdog-budgets.test.d.ts +0 -2
- package/dist/extractors/live-org/__tests__/watchdog-budgets.test.d.ts.map +0 -1
- package/dist/extractors/live-org/__tests__/watchdog-budgets.test.js +0 -40
- package/dist/extractors/live-org/__tests__/watchdog-budgets.test.js.map +0 -1
- package/dist/extractors/live-org/__tests__/wedge-isolation.test.d.ts +0 -2
- package/dist/extractors/live-org/__tests__/wedge-isolation.test.d.ts.map +0 -1
- package/dist/extractors/live-org/__tests__/wedge-isolation.test.js +0 -270
- package/dist/extractors/live-org/__tests__/wedge-isolation.test.js.map +0 -1
- package/dist/extractors/live-org/extractors/__tests__/apex.test.d.ts +0 -2
- package/dist/extractors/live-org/extractors/__tests__/apex.test.d.ts.map +0 -1
- package/dist/extractors/live-org/extractors/__tests__/apex.test.js +0 -73
- package/dist/extractors/live-org/extractors/__tests__/apex.test.js.map +0 -1
- package/dist/extractors/live-org/extractors/__tests__/lwc.parallel.test.d.ts +0 -2
- package/dist/extractors/live-org/extractors/__tests__/lwc.parallel.test.d.ts.map +0 -1
- package/dist/extractors/live-org/extractors/__tests__/lwc.parallel.test.js +0 -183
- package/dist/extractors/live-org/extractors/__tests__/lwc.parallel.test.js.map +0 -1
- package/dist/ingest/__tests__/config-values.test.d.ts +0 -2
- package/dist/ingest/__tests__/config-values.test.d.ts.map +0 -1
- package/dist/ingest/__tests__/config-values.test.js +0 -65
- package/dist/ingest/__tests__/config-values.test.js.map +0 -1
- package/dist/ingest/__tests__/full-sync-deletion.test.d.ts +0 -2
- package/dist/ingest/__tests__/full-sync-deletion.test.d.ts.map +0 -1
- package/dist/ingest/__tests__/full-sync-deletion.test.js +0 -207
- package/dist/ingest/__tests__/full-sync-deletion.test.js.map +0 -1
- package/dist/ingest/__tests__/incremental-deletion.test.d.ts +0 -2
- package/dist/ingest/__tests__/incremental-deletion.test.d.ts.map +0 -1
- package/dist/ingest/__tests__/incremental-deletion.test.js +0 -92
- package/dist/ingest/__tests__/incremental-deletion.test.js.map +0 -1
- package/dist/ingest/__tests__/live-ingest.detect-deletions-guard.test.d.ts +0 -10
- package/dist/ingest/__tests__/live-ingest.detect-deletions-guard.test.d.ts.map +0 -1
- package/dist/ingest/__tests__/live-ingest.detect-deletions-guard.test.js +0 -251
- package/dist/ingest/__tests__/live-ingest.detect-deletions-guard.test.js.map +0 -1
- package/dist/ingest/__tests__/live-ingest.test.d.ts +0 -2
- package/dist/ingest/__tests__/live-ingest.test.d.ts.map +0 -1
- package/dist/ingest/__tests__/live-ingest.test.js +0 -155
- package/dist/ingest/__tests__/live-ingest.test.js.map +0 -1
- package/dist/ingest/__tests__/multi-org-orchestrator.test.d.ts +0 -2
- package/dist/ingest/__tests__/multi-org-orchestrator.test.d.ts.map +0 -1
- package/dist/ingest/__tests__/multi-org-orchestrator.test.js +0 -108
- package/dist/ingest/__tests__/multi-org-orchestrator.test.js.map +0 -1
- package/dist/ingest/__tests__/parser-dispatch.test.d.ts +0 -2
- package/dist/ingest/__tests__/parser-dispatch.test.d.ts.map +0 -1
- package/dist/ingest/__tests__/parser-dispatch.test.js +0 -55
- package/dist/ingest/__tests__/parser-dispatch.test.js.map +0 -1
- package/dist/ingest/__tests__/read-only-wrapping.test.d.ts +0 -2
- package/dist/ingest/__tests__/read-only-wrapping.test.d.ts.map +0 -1
- package/dist/ingest/__tests__/read-only-wrapping.test.js +0 -62
- package/dist/ingest/__tests__/read-only-wrapping.test.js.map +0 -1
- package/dist/ingest/__tests__/vlocity-dispatch-integration.test.d.ts +0 -2
- package/dist/ingest/__tests__/vlocity-dispatch-integration.test.d.ts.map +0 -1
- package/dist/ingest/__tests__/vlocity-dispatch-integration.test.js +0 -134
- package/dist/ingest/__tests__/vlocity-dispatch-integration.test.js.map +0 -1
- package/dist/parsers/__tests__/_harness.d.ts +0 -13
- package/dist/parsers/__tests__/_harness.d.ts.map +0 -1
- package/dist/parsers/__tests__/_harness.js +0 -84
- package/dist/parsers/__tests__/_harness.js.map +0 -1
- package/dist/parsers/__tests__/apex.golden.test.d.ts +0 -2
- package/dist/parsers/__tests__/apex.golden.test.d.ts.map +0 -1
- package/dist/parsers/__tests__/apex.golden.test.js +0 -28
- package/dist/parsers/__tests__/apex.golden.test.js.map +0 -1
- package/dist/parsers/__tests__/cross-flavor.test.d.ts +0 -2
- package/dist/parsers/__tests__/cross-flavor.test.d.ts.map +0 -1
- package/dist/parsers/__tests__/cross-flavor.test.js +0 -56
- package/dist/parsers/__tests__/cross-flavor.test.js.map +0 -1
- package/dist/parsers/__tests__/datatransform-structured.test.d.ts +0 -2
- package/dist/parsers/__tests__/datatransform-structured.test.d.ts.map +0 -1
- package/dist/parsers/__tests__/datatransform-structured.test.js +0 -147
- package/dist/parsers/__tests__/datatransform-structured.test.js.map +0 -1
- package/dist/parsers/__tests__/edge-provenance.test.d.ts +0 -2
- package/dist/parsers/__tests__/edge-provenance.test.d.ts.map +0 -1
- package/dist/parsers/__tests__/edge-provenance.test.js +0 -47
- package/dist/parsers/__tests__/edge-provenance.test.js.map +0 -1
- package/dist/parsers/__tests__/flow.golden.test.d.ts +0 -2
- package/dist/parsers/__tests__/flow.golden.test.d.ts.map +0 -1
- package/dist/parsers/__tests__/flow.golden.test.js +0 -17
- package/dist/parsers/__tests__/flow.golden.test.js.map +0 -1
- package/dist/parsers/__tests__/integration.golden.test.d.ts +0 -2
- package/dist/parsers/__tests__/integration.golden.test.d.ts.map +0 -1
- package/dist/parsers/__tests__/integration.golden.test.js +0 -31
- package/dist/parsers/__tests__/integration.golden.test.js.map +0 -1
- package/dist/parsers/__tests__/long-tail.golden.test.d.ts +0 -2
- package/dist/parsers/__tests__/long-tail.golden.test.d.ts.map +0 -1
- package/dist/parsers/__tests__/long-tail.golden.test.js +0 -115
- package/dist/parsers/__tests__/long-tail.golden.test.js.map +0 -1
- package/dist/parsers/__tests__/lwc-bindings.test.d.ts +0 -2
- package/dist/parsers/__tests__/lwc-bindings.test.d.ts.map +0 -1
- package/dist/parsers/__tests__/lwc-bindings.test.js +0 -149
- package/dist/parsers/__tests__/lwc-bindings.test.js.map +0 -1
- package/dist/parsers/__tests__/lwc.golden.test.d.ts +0 -2
- package/dist/parsers/__tests__/lwc.golden.test.d.ts.map +0 -1
- package/dist/parsers/__tests__/lwc.golden.test.js +0 -16
- package/dist/parsers/__tests__/lwc.golden.test.js.map +0 -1
- package/dist/parsers/__tests__/mcd-gap-fills.test.d.ts +0 -2
- package/dist/parsers/__tests__/mcd-gap-fills.test.d.ts.map +0 -1
- package/dist/parsers/__tests__/mcd-gap-fills.test.js +0 -75
- package/dist/parsers/__tests__/mcd-gap-fills.test.js.map +0 -1
- package/dist/parsers/__tests__/object-inline-fields.test.d.ts +0 -2
- package/dist/parsers/__tests__/object-inline-fields.test.d.ts.map +0 -1
- package/dist/parsers/__tests__/object-inline-fields.test.js +0 -115
- package/dist/parsers/__tests__/object-inline-fields.test.js.map +0 -1
- package/dist/parsers/__tests__/object.golden.test.d.ts +0 -2
- package/dist/parsers/__tests__/object.golden.test.d.ts.map +0 -1
- package/dist/parsers/__tests__/object.golden.test.js +0 -33
- package/dist/parsers/__tests__/object.golden.test.js.map +0 -1
- package/dist/parsers/__tests__/omnistudio-overlap.test.d.ts +0 -2
- package/dist/parsers/__tests__/omnistudio-overlap.test.d.ts.map +0 -1
- package/dist/parsers/__tests__/omnistudio-overlap.test.js +0 -163
- package/dist/parsers/__tests__/omnistudio-overlap.test.js.map +0 -1
- package/dist/parsers/__tests__/omnistudio.golden.test.d.ts +0 -2
- package/dist/parsers/__tests__/omnistudio.golden.test.d.ts.map +0 -1
- package/dist/parsers/__tests__/omnistudio.golden.test.js +0 -53
- package/dist/parsers/__tests__/omnistudio.golden.test.js.map +0 -1
- package/dist/parsers/__tests__/reflection-walker.test.d.ts +0 -2
- package/dist/parsers/__tests__/reflection-walker.test.d.ts.map +0 -1
- package/dist/parsers/__tests__/reflection-walker.test.js +0 -162
- package/dist/parsers/__tests__/reflection-walker.test.js.map +0 -1
- package/dist/parsers/__tests__/registry.test.d.ts +0 -2
- package/dist/parsers/__tests__/registry.test.d.ts.map +0 -1
- package/dist/parsers/__tests__/registry.test.js +0 -23
- package/dist/parsers/__tests__/registry.test.js.map +0 -1
- package/dist/parsers/__tests__/security.golden.test.d.ts +0 -2
- package/dist/parsers/__tests__/security.golden.test.d.ts.map +0 -1
- package/dist/parsers/__tests__/security.golden.test.js +0 -31
- package/dist/parsers/__tests__/security.golden.test.js.map +0 -1
- package/dist/parsers/__tests__/vlocity.golden.test.d.ts +0 -2
- package/dist/parsers/__tests__/vlocity.golden.test.d.ts.map +0 -1
- package/dist/parsers/__tests__/vlocity.golden.test.js +0 -105
- package/dist/parsers/__tests__/vlocity.golden.test.js.map +0 -1
- package/dist/parsers/__tests__/worker-pool.test.d.ts +0 -2
- package/dist/parsers/__tests__/worker-pool.test.d.ts.map +0 -1
- package/dist/parsers/__tests__/worker-pool.test.js +0 -48
- package/dist/parsers/__tests__/worker-pool.test.js.map +0 -1
- package/dist/parsers/apex/__tests__/arity-resolver.test.d.ts +0 -2
- package/dist/parsers/apex/__tests__/arity-resolver.test.d.ts.map +0 -1
- package/dist/parsers/apex/__tests__/arity-resolver.test.js +0 -135
- package/dist/parsers/apex/__tests__/arity-resolver.test.js.map +0 -1
- package/dist/parsers/apex/__tests__/ast-extractor.test.d.ts +0 -2
- package/dist/parsers/apex/__tests__/ast-extractor.test.d.ts.map +0 -1
- package/dist/parsers/apex/__tests__/ast-extractor.test.js +0 -206
- package/dist/parsers/apex/__tests__/ast-extractor.test.js.map +0 -1
- package/dist/parsers/apex/__tests__/empty-body.test.d.ts +0 -2
- package/dist/parsers/apex/__tests__/empty-body.test.d.ts.map +0 -1
- package/dist/parsers/apex/__tests__/empty-body.test.js +0 -40
- package/dist/parsers/apex/__tests__/empty-body.test.js.map +0 -1
- package/dist/parsers/apex/__tests__/is-test-attribute.test.d.ts +0 -2
- package/dist/parsers/apex/__tests__/is-test-attribute.test.d.ts.map +0 -1
- package/dist/parsers/apex/__tests__/is-test-attribute.test.js +0 -56
- package/dist/parsers/apex/__tests__/is-test-attribute.test.js.map +0 -1
- package/dist/parsers/apex/__tests__/regex-arg-count.test.d.ts +0 -2
- package/dist/parsers/apex/__tests__/regex-arg-count.test.d.ts.map +0 -1
- package/dist/parsers/apex/__tests__/regex-arg-count.test.js +0 -82
- package/dist/parsers/apex/__tests__/regex-arg-count.test.js.map +0 -1
- package/dist/parsers/apex/__tests__/regex-inloop.test.d.ts +0 -2
- package/dist/parsers/apex/__tests__/regex-inloop.test.d.ts.map +0 -1
- package/dist/parsers/apex/__tests__/regex-inloop.test.js +0 -70
- package/dist/parsers/apex/__tests__/regex-inloop.test.js.map +0 -1
- package/dist/parsers/flow/__tests__/invocable-resolver.test.d.ts +0 -2
- package/dist/parsers/flow/__tests__/invocable-resolver.test.d.ts.map +0 -1
- package/dist/parsers/flow/__tests__/invocable-resolver.test.js +0 -91
- package/dist/parsers/flow/__tests__/invocable-resolver.test.js.map +0 -1
- package/dist/parsers/rules/__tests__/applies-to.test.d.ts +0 -2
- package/dist/parsers/rules/__tests__/applies-to.test.d.ts.map +0 -1
- package/dist/parsers/rules/__tests__/applies-to.test.js +0 -31
- package/dist/parsers/rules/__tests__/applies-to.test.js.map +0 -1
- package/dist/parsers/rules/__tests__/applies-to.test.ts +0 -40
- package/dist/parsers/rules/__tests__/engine.test.d.ts +0 -2
- package/dist/parsers/rules/__tests__/engine.test.d.ts.map +0 -1
- package/dist/parsers/rules/__tests__/engine.test.js +0 -127
- package/dist/parsers/rules/__tests__/engine.test.js.map +0 -1
- package/dist/parsers/rules/__tests__/engine.test.ts +0 -138
- package/dist/parsers/rules/__tests__/loader.test.d.ts +0 -2
- package/dist/parsers/rules/__tests__/loader.test.d.ts.map +0 -1
- package/dist/parsers/rules/__tests__/loader.test.js +0 -31
- package/dist/parsers/rules/__tests__/loader.test.js.map +0 -1
- package/dist/parsers/rules/__tests__/loader.test.ts +0 -37
- package/dist/parsers/rules/__tests__/schema.test.d.ts +0 -2
- package/dist/parsers/rules/__tests__/schema.test.d.ts.map +0 -1
- package/dist/parsers/rules/__tests__/schema.test.js +0 -33
- package/dist/parsers/rules/__tests__/schema.test.js.map +0 -1
- package/dist/parsers/rules/__tests__/schema.test.ts +0 -37
- package/dist/parsers/rules/__tests__/selectors.test.d.ts +0 -2
- package/dist/parsers/rules/__tests__/selectors.test.d.ts.map +0 -1
- package/dist/parsers/rules/__tests__/selectors.test.js +0 -51
- package/dist/parsers/rules/__tests__/selectors.test.js.map +0 -1
- package/dist/parsers/rules/__tests__/selectors.test.ts +0 -62
- package/dist/render/__tests__/sarif.test.d.ts +0 -2
- package/dist/render/__tests__/sarif.test.d.ts.map +0 -1
- package/dist/render/__tests__/sarif.test.js +0 -126
- package/dist/render/__tests__/sarif.test.js.map +0 -1
- package/dist/render/mermaid/__tests__/mermaid.test.d.ts +0 -2
- package/dist/render/mermaid/__tests__/mermaid.test.d.ts.map +0 -1
- package/dist/render/mermaid/__tests__/mermaid.test.js +0 -74
- package/dist/render/mermaid/__tests__/mermaid.test.js.map +0 -1
- package/dist/storage/__tests__/analysis-tables-migration.test.d.ts +0 -2
- package/dist/storage/__tests__/analysis-tables-migration.test.d.ts.map +0 -1
- package/dist/storage/__tests__/analysis-tables-migration.test.js +0 -44
- package/dist/storage/__tests__/analysis-tables-migration.test.js.map +0 -1
- package/dist/storage/__tests__/graph-store.test.d.ts +0 -2
- package/dist/storage/__tests__/graph-store.test.d.ts.map +0 -1
- package/dist/storage/__tests__/graph-store.test.js +0 -145
- package/dist/storage/__tests__/graph-store.test.js.map +0 -1
- package/dist/storage/__tests__/identifier.test.d.ts +0 -2
- package/dist/storage/__tests__/identifier.test.d.ts.map +0 -1
- package/dist/storage/__tests__/identifier.test.js +0 -35
- package/dist/storage/__tests__/identifier.test.js.map +0 -1
- package/dist/storage/__tests__/load-better-sqlite3.test.d.ts +0 -2
- package/dist/storage/__tests__/load-better-sqlite3.test.d.ts.map +0 -1
- package/dist/storage/__tests__/load-better-sqlite3.test.js +0 -65
- package/dist/storage/__tests__/load-better-sqlite3.test.js.map +0 -1
- package/dist/storage/__tests__/migrations.test.d.ts +0 -2
- package/dist/storage/__tests__/migrations.test.d.ts.map +0 -1
- package/dist/storage/__tests__/migrations.test.js +0 -93
- package/dist/storage/__tests__/migrations.test.js.map +0 -1
- package/dist/storage/__tests__/perf-50k.test.d.ts +0 -2
- package/dist/storage/__tests__/perf-50k.test.d.ts.map +0 -1
- package/dist/storage/__tests__/perf-50k.test.js +0 -67
- package/dist/storage/__tests__/perf-50k.test.js.map +0 -1
- package/dist/storage/__tests__/rename-stability.test.d.ts +0 -2
- package/dist/storage/__tests__/rename-stability.test.d.ts.map +0 -1
- package/dist/storage/__tests__/rename-stability.test.js +0 -135
- package/dist/storage/__tests__/rename-stability.test.js.map +0 -1
- package/dist/storage/__tests__/snapshot-store.test.d.ts +0 -2
- package/dist/storage/__tests__/snapshot-store.test.d.ts.map +0 -1
- package/dist/storage/__tests__/snapshot-store.test.js +0 -117
- package/dist/storage/__tests__/snapshot-store.test.js.map +0 -1
- package/dist/storage/__tests__/snippets.test.d.ts +0 -2
- package/dist/storage/__tests__/snippets.test.d.ts.map +0 -1
- package/dist/storage/__tests__/snippets.test.js +0 -88
- package/dist/storage/__tests__/snippets.test.js.map +0 -1
- package/dist/storage/__tests__/sync-generation.test.d.ts +0 -2
- package/dist/storage/__tests__/sync-generation.test.d.ts.map +0 -1
- package/dist/storage/__tests__/sync-generation.test.js +0 -159
- package/dist/storage/__tests__/sync-generation.test.js.map +0 -1
- package/dist/storage/__tests__/vector-store-load-failure.test.d.ts +0 -2
- package/dist/storage/__tests__/vector-store-load-failure.test.d.ts.map +0 -1
- package/dist/storage/__tests__/vector-store-load-failure.test.js +0 -42
- package/dist/storage/__tests__/vector-store-load-failure.test.js.map +0 -1
- package/dist/storage/__tests__/vector-store.test.d.ts +0 -2
- package/dist/storage/__tests__/vector-store.test.d.ts.map +0 -1
- package/dist/storage/__tests__/vector-store.test.js +0 -87
- package/dist/storage/__tests__/vector-store.test.js.map +0 -1
- package/dist/telemetry/__tests__/event-schema.test.d.ts +0 -2
- package/dist/telemetry/__tests__/event-schema.test.d.ts.map +0 -1
- package/dist/telemetry/__tests__/event-schema.test.js +0 -56
- package/dist/telemetry/__tests__/event-schema.test.js.map +0 -1
- package/dist/telemetry/__tests__/machine-id.test.d.ts +0 -2
- package/dist/telemetry/__tests__/machine-id.test.d.ts.map +0 -1
- package/dist/telemetry/__tests__/machine-id.test.js +0 -33
- package/dist/telemetry/__tests__/machine-id.test.js.map +0 -1
- package/dist/telemetry/__tests__/pipeline.test.d.ts +0 -2
- package/dist/telemetry/__tests__/pipeline.test.d.ts.map +0 -1
- package/dist/telemetry/__tests__/pipeline.test.js +0 -68
- package/dist/telemetry/__tests__/pipeline.test.js.map +0 -1
- package/dist/telemetry/__tests__/sanitizer.test.d.ts +0 -2
- package/dist/telemetry/__tests__/sanitizer.test.d.ts.map +0 -1
- package/dist/telemetry/__tests__/sanitizer.test.js +0 -143
- package/dist/telemetry/__tests__/sanitizer.test.js.map +0 -1
|
@@ -1,21 +1,41 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
1
2
|
import { asQualifiedName } from "@ryanstark24/sfgraph-shared";
|
|
2
3
|
import { resolveApexMethodArity } from "../parsers/apex/arity-resolver.js";
|
|
4
|
+
import { retargetApexInterfaceRefs } from "../parsers/apex/interface-ref-resolver.js";
|
|
5
|
+
import { resolveAuraEmbeds } from "../parsers/aura/embed-resolver.js";
|
|
3
6
|
import { resolveCrossFlavor } from "../parsers/cross-flavor-resolver.js";
|
|
4
7
|
import { resolveFlowApexMethods } from "../parsers/flow/invocable-resolver.js";
|
|
5
|
-
import {
|
|
8
|
+
import { resolveFormulaRelationshipHops } from "../parsers/object/formula-hop-resolver.js";
|
|
6
9
|
// Ensure all parsers are registered before we look them up.
|
|
7
10
|
import "../parsers/index.js";
|
|
8
11
|
import { auditDanglingEdges } from "../analyze/audit-graph.js";
|
|
9
12
|
import { populateAnalysisTables } from "../analyze/populate.js";
|
|
10
|
-
import {
|
|
13
|
+
import { REL_TYPES } from "../domain/rel-types.js";
|
|
14
|
+
import { EmbeddingCache, EmbeddingPool, EmbeddingQueue, defaultEmbeddingWorkerUrl, hashEmbedText, } from "../embedding/index.js";
|
|
15
|
+
import { tokenizeIdentifier } from "../embedding/tokenize.js";
|
|
11
16
|
import { resolveOrg } from "../extractors/live-org/auth.js";
|
|
12
17
|
import { bulkRetrieve } from "../extractors/live-org/bulk-retrieve.js";
|
|
13
18
|
import { probeCapabilities } from "../extractors/live-org/capabilities.js";
|
|
14
19
|
import { startLivenessProbe } from "../extractors/live-org/liveness.js";
|
|
15
20
|
import { dataPool, metadataPool, toolingPool } from "../extractors/live-org/rate-limit.js";
|
|
16
21
|
import { iterChanges } from "../extractors/live-org/source-member.js";
|
|
22
|
+
// SourceMember MemberType -> the node LABEL the parsers actually store under,
|
|
23
|
+
// for the (rare) types whose label differs from the member type. The LWC parser
|
|
24
|
+
// labels nodes "LWC", not "LightningComponentBundle", so an obsolete-LWC delete
|
|
25
|
+
// keyed by the raw member type was a silent no-op. METADATA_CATEGORY is NOT
|
|
26
|
+
// usable here: its LWC/AURA values ARE the member-type strings, not the labels.
|
|
27
|
+
const MEMBER_TYPE_TO_NODE_LABEL = {
|
|
28
|
+
LightningComponentBundle: "LWC",
|
|
29
|
+
AuraDefinitionBundle: "AuraComponent",
|
|
30
|
+
};
|
|
17
31
|
import { loadAllRules } from "../parsers/rules/_loader.js";
|
|
18
|
-
import { evaluateDeletionGuard, resolveMaxDropRatio } from "./detect-deletions-guard.js";
|
|
32
|
+
import { evaluateDeletionGuard, isSkipProtected, resolveMaxDropRatio, skipProtection, } from "./detect-deletions-guard.js";
|
|
33
|
+
import { hasGoodPriorOwned, isParseFailureOnly, isQuarantinedFor, isQuarantinedRow, memberContentHash, memberFailureStamp, memberRowsGeneration, ownedQnames, quarantinedOutcome, } from "./member-rows.js";
|
|
34
|
+
import { OFFLINE_CAPS } from "./offline-org.js";
|
|
35
|
+
import { parseMember } from "./parse-member.js";
|
|
36
|
+
import { parsePool, resolveParseWorkers, } from "./parse-pool.js";
|
|
37
|
+
export { adaptParserInput } from "./parse-member.js";
|
|
38
|
+
import { createIngestProfiler } from "./profile.js";
|
|
19
39
|
const NOOP_LOG = {
|
|
20
40
|
debug: () => { },
|
|
21
41
|
info: () => { },
|
|
@@ -25,23 +45,56 @@ const NOOP_LOG = {
|
|
|
25
45
|
/** Print a consolidated end-of-run summary of metadata types that were
|
|
26
46
|
* skipped during ingest, grouped by failure category, with a targeted
|
|
27
47
|
* remediation block per category. */
|
|
28
|
-
|
|
48
|
+
/**
|
|
49
|
+
* Entries of the previous skip report at `path` (same org) whose label a
|
|
50
|
+
* scoped run did NOT re-run. Missing / malformed / other-org report: none.
|
|
51
|
+
* A `discovery` only-label re-runs every generic:* source (bulkRetrieve), so
|
|
52
|
+
* their entries are not carried either (review N3).
|
|
53
|
+
*/
|
|
54
|
+
export function carriedOverSkips(path, orgId, reRun) {
|
|
55
|
+
try {
|
|
56
|
+
if (!existsSync(path))
|
|
57
|
+
return [];
|
|
58
|
+
const prev = JSON.parse(readFileSync(path, "utf8"));
|
|
59
|
+
if (prev.orgId !== undefined && prev.orgId !== orgId)
|
|
60
|
+
return [];
|
|
61
|
+
return (prev.skips ?? []).filter((s) => s &&
|
|
62
|
+
typeof s.label === "string" &&
|
|
63
|
+
!reRun.has(s.label) &&
|
|
64
|
+
!(reRun.has("discovery") && s.label.startsWith("generic:")));
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return [];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/** A skip reason without a leading "<label>: " — source errors already name
|
|
71
|
+
* their source, which the summary bullet prints anyway. */
|
|
72
|
+
function bulletReason(s) {
|
|
73
|
+
return s.reason.startsWith(`${s.label}: `) ? s.reason.slice(s.label.length + 2) : s.reason;
|
|
74
|
+
}
|
|
75
|
+
export function printSkipSummary(report, orgAlias) {
|
|
29
76
|
const byCategory = new Map();
|
|
30
77
|
for (const s of report.skips) {
|
|
31
78
|
const arr = byCategory.get(s.category) ?? [];
|
|
32
79
|
arr.push({ label: s.label, reason: s.reason });
|
|
33
80
|
byCategory.set(s.category, arr);
|
|
34
81
|
}
|
|
35
|
-
const
|
|
82
|
+
const unreadableCount = byCategory.get("unreadable")?.length ?? 0;
|
|
83
|
+
const total = report.skips.length - unreadableCount;
|
|
36
84
|
console.log("");
|
|
37
|
-
|
|
38
|
-
|
|
85
|
+
if (total > 0) {
|
|
86
|
+
console.log(`⚠ ${total} metadata ${total === 1 ? "type was" : "types were"} skipped during this ingest.`);
|
|
87
|
+
console.log(" The rest of the graph completed successfully — these types are simply absent.");
|
|
88
|
+
}
|
|
89
|
+
if (unreadableCount > 0) {
|
|
90
|
+
console.log(`⚠ ${unreadableCount} metadata ${unreadableCount === 1 ? "type (or some of its members)" : "types (or some of their members)"} could not be read: the org refused them (unreadable — see below).`);
|
|
91
|
+
}
|
|
39
92
|
if (byCategory.has("insufficient_access")) {
|
|
40
93
|
const list = byCategory.get("insufficient_access") ?? [];
|
|
41
94
|
console.log("");
|
|
42
95
|
console.log(` Insufficient access (${list.length}):`);
|
|
43
96
|
for (const s of list)
|
|
44
|
-
console.log(` • ${s.label}: ${s
|
|
97
|
+
console.log(` • ${s.label}: ${bulletReason(s)}`);
|
|
45
98
|
console.log("");
|
|
46
99
|
console.log(" How to fix permanently:");
|
|
47
100
|
console.log(" 1. Have an admin assign your user a permission set with:");
|
|
@@ -78,66 +131,47 @@ function printSkipSummary(report, orgAlias) {
|
|
|
78
131
|
console.log("");
|
|
79
132
|
console.log(` Network errors (${list.length}):`);
|
|
80
133
|
for (const s of list)
|
|
81
|
-
console.log(` • ${s.label}: ${s
|
|
134
|
+
console.log(` • ${s.label}: ${bulletReason(s)}`);
|
|
82
135
|
console.log(" How to fix: check connectivity to your org and re-run.");
|
|
83
136
|
}
|
|
137
|
+
if (byCategory.has("unreadable")) {
|
|
138
|
+
const list = byCategory.get("unreadable") ?? [];
|
|
139
|
+
console.log("");
|
|
140
|
+
console.log(` Unreadable (org refused; re-run with --retry-skipped to try again) (${list.length}):`);
|
|
141
|
+
for (const s of list)
|
|
142
|
+
console.log(` • ${s.label}: ${bulletReason(s)}`);
|
|
143
|
+
console.log(" The org rejected these reads as invalid, or returned the same error on");
|
|
144
|
+
console.log(" repeated reads, so they were not auto-retried in this run. To try again:");
|
|
145
|
+
console.log(` sfgraph ingest --org ${orgAlias} --retry-skipped`);
|
|
146
|
+
}
|
|
84
147
|
if (byCategory.has("unknown")) {
|
|
85
148
|
const list = byCategory.get("unknown") ?? [];
|
|
86
149
|
console.log("");
|
|
87
150
|
console.log(` Other (${list.length}):`);
|
|
88
151
|
for (const s of list)
|
|
89
|
-
console.log(` • ${s.label}: ${s
|
|
152
|
+
console.log(` • ${s.label}: ${bulletReason(s)}`);
|
|
90
153
|
}
|
|
91
154
|
console.log("");
|
|
92
155
|
}
|
|
93
|
-
/** Live-org Apex extractor wraps body in a `{body, metaXml}` JSON envelope
|
|
94
|
-
* so we can forward Tooling-row ApiVersion/Status to the parser. Filesystem
|
|
95
|
-
* extractor still passes raw body. Detect by trying JSON.parse — if it
|
|
96
|
-
* yields an object with `body`, unwrap; otherwise treat as raw body. */
|
|
97
|
-
function unwrapApexEnvelope(content) {
|
|
98
|
-
if (!content)
|
|
99
|
-
return { body: "" };
|
|
100
|
-
if (content[0] !== "{")
|
|
101
|
-
return { body: content };
|
|
102
|
-
try {
|
|
103
|
-
const parsed = JSON.parse(content);
|
|
104
|
-
if (parsed && typeof parsed === "object" && typeof parsed.body === "string") {
|
|
105
|
-
const out = { body: parsed.body };
|
|
106
|
-
if (typeof parsed.metaXml === "string")
|
|
107
|
-
out.metaXml = parsed.metaXml;
|
|
108
|
-
return out;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
catch {
|
|
112
|
-
/* fallthrough — raw body */
|
|
113
|
-
}
|
|
114
|
-
return { body: content };
|
|
115
|
-
}
|
|
116
|
-
/** Maps the Vlocity runner's emitted memberType (the bare VlocityDataPackType)
|
|
117
|
-
* to the parser-registry key the four rich Vlocity parsers register under.
|
|
118
|
-
* Only these four DataPack types have dedicated parsers; the other ~44 fall
|
|
119
|
-
* through to the opaque node parser (node-only, by design). */
|
|
120
|
-
const VLOCITY_MEMBER_TO_PARSER = {
|
|
121
|
-
DataRaptor: "VlocityDataRaptor",
|
|
122
|
-
VlocityDataRaptor: "VlocityDataRaptor",
|
|
123
|
-
IntegrationProcedure: "VlocityIntegrationProcedure",
|
|
124
|
-
VlocityIntegrationProcedure: "VlocityIntegrationProcedure",
|
|
125
|
-
OmniScript: "VlocityOmniScript",
|
|
126
|
-
VlocityOmniScript: "VlocityOmniScript",
|
|
127
|
-
VlocityCard: "VlocityCard",
|
|
128
|
-
};
|
|
129
156
|
/**
|
|
130
157
|
* Build the text embedded for a node's semantic vector. Beyond the
|
|
131
158
|
* label/qname/description baseline, this folds in CONFIG VALUES so
|
|
132
159
|
* `find_similar` matches on what a config artifact actually resolves to —
|
|
133
160
|
* a Custom Metadata record's field values, a Custom Label's text, a Custom
|
|
134
161
|
* Setting's rows. Without this, searching "endpoint for product push" can't
|
|
135
|
-
* reach `
|
|
162
|
+
* reach `Endpoint_Url.ProductPush_Acme` because only its name was embedded.
|
|
136
163
|
* Exported for tests.
|
|
137
164
|
*/
|
|
138
165
|
export function buildEmbedText(label, qname, attributes) {
|
|
139
166
|
const a = attributes ?? {};
|
|
140
167
|
const parts = [`${label}: ${qname}`];
|
|
168
|
+
// Word-split the identifier so semantic search matches on word boundaries
|
|
169
|
+
// (`account controller` → AccountController, `customer tier` → Customer_Tier__c).
|
|
170
|
+
// Only the name part after the label prefix; skip if it adds nothing.
|
|
171
|
+
const namePart = qname.includes(":") ? qname.slice(qname.indexOf(":") + 1) : qname;
|
|
172
|
+
const words = tokenizeIdentifier(namePart);
|
|
173
|
+
if (words && words !== namePart.toLowerCase())
|
|
174
|
+
parts.push(words);
|
|
141
175
|
if (typeof a.description === "string" && a.description)
|
|
142
176
|
parts.push(a.description);
|
|
143
177
|
// Custom Metadata record field values: [{field,value}] | {field:value} | object.
|
|
@@ -173,6 +207,20 @@ export function buildEmbedText(label, qname, attributes) {
|
|
|
173
207
|
}
|
|
174
208
|
}
|
|
175
209
|
}
|
|
210
|
+
// Structural attributes that make automation findable by WHAT it acts on:
|
|
211
|
+
// a trigger's object + DML events ("on Account before insert"), a Flow's
|
|
212
|
+
// process type ("AutoLaunchedFlow"/"Flow"). Gated by label — CustomField (and
|
|
213
|
+
// other nodes) also carry an `object` attribute (their parent SObject), and
|
|
214
|
+
// appending "on Account" to every field was pure noise in the embedding.
|
|
215
|
+
if (label === "ApexTrigger" && typeof a.object === "string" && a.object) {
|
|
216
|
+
const ev = Array.isArray(a.events)
|
|
217
|
+
? a.events.filter((x) => typeof x === "string").join(" ")
|
|
218
|
+
: "";
|
|
219
|
+
parts.push(`on ${a.object}${ev ? ` ${ev}` : ""}`);
|
|
220
|
+
}
|
|
221
|
+
if (label === "Flow" && typeof a.processType === "string" && a.processType) {
|
|
222
|
+
parts.push(a.processType);
|
|
223
|
+
}
|
|
176
224
|
return parts.join("\n");
|
|
177
225
|
}
|
|
178
226
|
function stringifyConfigVal(v) {
|
|
@@ -188,134 +236,6 @@ function stringifyConfigVal(v) {
|
|
|
188
236
|
}
|
|
189
237
|
return String(v);
|
|
190
238
|
}
|
|
191
|
-
/** Exported for tests — maps a RawMember to the registered parser's input shape. */
|
|
192
|
-
export function adaptParserInput(ref, content) {
|
|
193
|
-
switch (ref.memberType) {
|
|
194
|
-
case "ApexClass": {
|
|
195
|
-
const { body, metaXml } = unwrapApexEnvelope(content);
|
|
196
|
-
return {
|
|
197
|
-
type: "ApexClass",
|
|
198
|
-
input: { className: ref.memberName, body, ...(metaXml ? { metaXml } : {}) },
|
|
199
|
-
};
|
|
200
|
-
}
|
|
201
|
-
case "ApexTrigger": {
|
|
202
|
-
const { body, metaXml } = unwrapApexEnvelope(content);
|
|
203
|
-
return {
|
|
204
|
-
type: "ApexTrigger",
|
|
205
|
-
input: { triggerName: ref.memberName, body, ...(metaXml ? { metaXml } : {}) },
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
case "LightningComponentBundle": {
|
|
209
|
-
try {
|
|
210
|
-
const parsed = JSON.parse(content || "{}");
|
|
211
|
-
return {
|
|
212
|
-
type: "LightningComponentBundle",
|
|
213
|
-
input: { bundleName: parsed.bundleName ?? ref.memberName, files: parsed.files ?? {} },
|
|
214
|
-
};
|
|
215
|
-
}
|
|
216
|
-
catch {
|
|
217
|
-
return null;
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
case "Flow":
|
|
221
|
-
return { type: "Flow", input: { fullName: ref.memberName, xml: content } };
|
|
222
|
-
case "CustomObject":
|
|
223
|
-
return { type: "CustomObject", input: { apiName: ref.memberName, objectXml: content } };
|
|
224
|
-
case "Profile":
|
|
225
|
-
return { type: "Profile", input: { name: ref.memberName, xml: content } };
|
|
226
|
-
case "PermissionSet":
|
|
227
|
-
return { type: "PermissionSet", input: { name: ref.memberName, xml: content } };
|
|
228
|
-
case "SharingRules":
|
|
229
|
-
return { type: "SharingRules", input: { object: ref.memberName, xml: content } };
|
|
230
|
-
case "NamedCredential":
|
|
231
|
-
return { type: "NamedCredential", input: { name: ref.memberName, xml: content } };
|
|
232
|
-
case "ExternalServiceRegistration":
|
|
233
|
-
return { type: "ExternalServiceRegistration", input: { name: ref.memberName, xml: content } };
|
|
234
|
-
case "OmniProcess":
|
|
235
|
-
case "OmniUiCard":
|
|
236
|
-
case "OmniDataTransform":
|
|
237
|
-
case "OmniIntegrationProcedure": {
|
|
238
|
-
let metadata = content;
|
|
239
|
-
try {
|
|
240
|
-
metadata = JSON.parse(content);
|
|
241
|
-
}
|
|
242
|
-
catch {
|
|
243
|
-
/* keep raw */
|
|
244
|
-
}
|
|
245
|
-
return { type: ref.memberType, input: { name: ref.memberName, metadata } };
|
|
246
|
-
}
|
|
247
|
-
// The Vlocity runner emits the bare VlocityDataPackType as memberType
|
|
248
|
-
// ("DataRaptor", "IntegrationProcedure", "OmniScript", "VlocityCard"),
|
|
249
|
-
// but the four rich parsers register under "Vlocity"-prefixed type names
|
|
250
|
-
// ("VlocityDataRaptor", …). Without this mapping the runner's members
|
|
251
|
-
// never matched a case here and fell through to the opaque fallback —
|
|
252
|
-
// shallow nodes with zero DR_/IP_/OS_ edges. Only "VlocityCard" happened
|
|
253
|
-
// to align on both sides, which is why a real ingest produced VC edges
|
|
254
|
-
// but no DataRaptor/IP/OmniScript lineage. The golden tests call the
|
|
255
|
-
// parsers directly, so this runner→dispatch seam was never covered.
|
|
256
|
-
// The legacy "Vlocity*"-prefixed keys are kept too in case any caller
|
|
257
|
-
// (or a future filesystem source) emits them.
|
|
258
|
-
case "DataRaptor":
|
|
259
|
-
case "VlocityDataRaptor":
|
|
260
|
-
case "IntegrationProcedure":
|
|
261
|
-
case "VlocityIntegrationProcedure":
|
|
262
|
-
case "OmniScript":
|
|
263
|
-
case "VlocityOmniScript":
|
|
264
|
-
case "VlocityCard": {
|
|
265
|
-
let datapack = content;
|
|
266
|
-
try {
|
|
267
|
-
datapack = JSON.parse(content);
|
|
268
|
-
}
|
|
269
|
-
catch {
|
|
270
|
-
/* keep raw */
|
|
271
|
-
}
|
|
272
|
-
return {
|
|
273
|
-
type: VLOCITY_MEMBER_TO_PARSER[ref.memberType] ?? ref.memberType,
|
|
274
|
-
input: { name: ref.memberName, datapack },
|
|
275
|
-
};
|
|
276
|
-
}
|
|
277
|
-
default: {
|
|
278
|
-
// Long-tail metadata types: route to a registered parser when one
|
|
279
|
-
// exists (the 21 rule-based YAML parsers register under their raw
|
|
280
|
-
// metadata type name, e.g. "Layout", "Dashboard"), otherwise fall
|
|
281
|
-
// back to the opaque node parser so the member still becomes a
|
|
282
|
-
// graph node. Before this fallback every generic-extractor member
|
|
283
|
-
// was silently dropped here — extracted, logged as ✓, and never
|
|
284
|
-
// merged — which left grant/reference edges dangling (e.g. 59k
|
|
285
|
-
// GRANTS_TAB_ACCESS edges pointing at CustomTab nodes that were
|
|
286
|
-
// never created).
|
|
287
|
-
if (parserRegistry.for(ref.memberType)) {
|
|
288
|
-
return { type: ref.memberType, input: genericRuleInput(ref.memberName, content) };
|
|
289
|
-
}
|
|
290
|
-
return {
|
|
291
|
-
type: "OpaqueMetadata",
|
|
292
|
-
input: { metadataType: ref.memberType, name: ref.memberName, raw: content },
|
|
293
|
-
};
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
/**
|
|
298
|
-
* Build the `{ name, xml, ...siblings }` input shape the rule-based parsers'
|
|
299
|
-
* `xml-string` coercion expects. Filesystem sources hand us raw XML; the
|
|
300
|
-
* live generic extractor hands us the JSON-serialized `metadata.read()`
|
|
301
|
-
* object — whose keys mirror the parsed XML root, so they can be promoted
|
|
302
|
-
* to sibling keys directly (coerceInput merges siblings into the record).
|
|
303
|
-
*/
|
|
304
|
-
function genericRuleInput(name, content) {
|
|
305
|
-
const s = (content ?? "").trimStart();
|
|
306
|
-
if (s.startsWith("<"))
|
|
307
|
-
return { name, xml: content };
|
|
308
|
-
let parsed = {};
|
|
309
|
-
try {
|
|
310
|
-
const j = JSON.parse(s);
|
|
311
|
-
if (j && typeof j === "object" && !Array.isArray(j))
|
|
312
|
-
parsed = j;
|
|
313
|
-
}
|
|
314
|
-
catch {
|
|
315
|
-
/* not JSON — leave record empty; the node still gets name + label */
|
|
316
|
-
}
|
|
317
|
-
return { xml: "", ...parsed, name };
|
|
318
|
-
}
|
|
319
239
|
export async function liveIngest(opts) {
|
|
320
240
|
const logger = opts.logger ?? NOOP_LOG;
|
|
321
241
|
// Load declarative rule parsers (idempotent).
|
|
@@ -352,28 +272,40 @@ export async function liveIngest(opts) {
|
|
|
352
272
|
catch (e) {
|
|
353
273
|
logger.warn("live-ingest: markSyncStarted failed", { err: e.message });
|
|
354
274
|
}
|
|
275
|
+
// Opt-in profiling (SFGRAPH_INGEST_PROFILE=<file>); no-op otherwise.
|
|
276
|
+
// Created before the try so the finally can flush on failure too.
|
|
277
|
+
const profiler = createIngestProfiler();
|
|
278
|
+
// Embedding resources, owned here so the finally can release them on any path.
|
|
279
|
+
let embedQueue = null;
|
|
280
|
+
let ownedEmbedder = null;
|
|
281
|
+
let embedCache = null;
|
|
355
282
|
// W1.5-08: the rest of the ingest runs inside this try so a thrown
|
|
356
283
|
// exception still flips `sync_in_progress` back to 0 via markSyncFailed.
|
|
357
284
|
// Per-resolver try/catch isolation inside bulkRetrieve / live-ingest is
|
|
358
285
|
// preserved — this wrapper only catches exceptions that escape *all* of
|
|
359
286
|
// those inner handlers (i.e. genuinely fatal failures).
|
|
360
287
|
try {
|
|
361
|
-
const caps = await probeCapabilities(resolved.conn);
|
|
288
|
+
const caps = opts.metadataSource ? OFFLINE_CAPS : await probeCapabilities(resolved.conn);
|
|
362
289
|
logger.info("live-ingest: probed capabilities", { caps });
|
|
363
290
|
// Discovery is also invoked implicitly inside bulkRetrieve, but logging the
|
|
364
291
|
// type-count up-front gives operators a quick coverage signal.
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
292
|
+
if (!opts.metadataSource) {
|
|
293
|
+
try {
|
|
294
|
+
const { discoverMetadataTypes } = await import("../extractors/live-org/discovery.js");
|
|
295
|
+
const discovered = await discoverMetadataTypes(resolved.conn, apiVersion);
|
|
296
|
+
logger.info("live-ingest: discovered metadata types", { count: discovered.length });
|
|
297
|
+
}
|
|
298
|
+
catch (e) {
|
|
299
|
+
logger.warn("live-ingest: metadata.describe failed", { err: e.message });
|
|
300
|
+
}
|
|
372
301
|
}
|
|
373
302
|
const existing = graph.getOrg(resolved.orgId);
|
|
374
303
|
const requestedMode = opts.mode ?? "auto";
|
|
375
304
|
let mode;
|
|
376
|
-
if (
|
|
305
|
+
if (opts.metadataSource) {
|
|
306
|
+
mode = "full";
|
|
307
|
+
}
|
|
308
|
+
else if (requestedMode === "auto") {
|
|
377
309
|
mode = existing?.lastSyncedAt && caps.sourceTracking ? "incremental" : "full";
|
|
378
310
|
}
|
|
379
311
|
else {
|
|
@@ -390,6 +322,11 @@ export async function liveIngest(opts) {
|
|
|
390
322
|
let membersProcessed = 0;
|
|
391
323
|
let parseErrors = 0;
|
|
392
324
|
let deletions = 0;
|
|
325
|
+
// Incremental detects changed/added members but cannot fetch their content
|
|
326
|
+
// yet, so it skips them. If we then advanced the watermark past them, the
|
|
327
|
+
// next incremental would start AFTER those changes and never see them —
|
|
328
|
+
// silent permanent data loss. Track the count so we can HOLD the watermark.
|
|
329
|
+
let incrementalUnfetched = 0;
|
|
393
330
|
// Set in the full-sync branch if the bulkRetrieve stream itself throws.
|
|
394
331
|
// Detect-deletions reads it post-fan-out to bail out instead of mass-
|
|
395
332
|
// wiping nodes that were never visited due to the abort.
|
|
@@ -410,18 +347,125 @@ export async function liveIngest(opts) {
|
|
|
410
347
|
// the legacy `${label}: ${reason}` strings from skipReport.skips into the
|
|
411
348
|
// final LiveIngestResult.warnings array. See bulk-retrieve.ts WedgeCoordinator.
|
|
412
349
|
const wedgeWarnings = [];
|
|
350
|
+
// Task 10 rebuild fast path. On a full ingest into an org whose graph is
|
|
351
|
+
// empty at start, run the fan-out inside the store's bulk-load window:
|
|
352
|
+
// deferred secondary indexes, synchronous=OFF, one transaction per 2,000
|
|
353
|
+
// members, and no per-member delete probes for keys not yet written (the
|
|
354
|
+
// store tracks what this run wrote, so repeats are still reconciled and
|
|
355
|
+
// the graph is identical to the slow path). SFGRAPH_DISABLE_FASTPATH=1
|
|
356
|
+
// forces the per-member path (used by the same-output test and gate).
|
|
357
|
+
const fastPathDisabled = process.env.SFGRAPH_DISABLE_FASTPATH === "1";
|
|
358
|
+
const graphEmptyAtStart = !fastPathDisabled &&
|
|
359
|
+
mode === "full" &&
|
|
360
|
+
opts.rebuild !== false &&
|
|
361
|
+
typeof graph.beginBulk === "function" &&
|
|
362
|
+
typeof graph.endBulk === "function" &&
|
|
363
|
+
typeof graph.isOrgEmpty === "function" &&
|
|
364
|
+
graph.isOrgEmpty(resolved.orgId);
|
|
365
|
+
// A vector store on its own connection would hit SQLITE_BUSY behind the
|
|
366
|
+
// held bulk transaction, so keep per-member commits in that case.
|
|
367
|
+
const vectorDb = opts.vectorStore?.db;
|
|
368
|
+
const graphDb = graph.db;
|
|
369
|
+
const sharedConnection = vectorDb === undefined || vectorDb === graphDb;
|
|
370
|
+
// Every other full ingest (a normal sync, a delta's merge) writes into a
|
|
371
|
+
// graph that MCP servers may be reading, so the bulk window's relaxed
|
|
372
|
+
// pragmas and dropped indexes are not an option. It still groups members
|
|
373
|
+
// into plain transactions (store.beginBatch: BEGIN IMMEDIATE, committed
|
|
374
|
+
// only between members, at most ~200 ms each), which removes most of the
|
|
375
|
+
// per-member commit cost. Same SQLITE_BUSY rule as the bulk window: a
|
|
376
|
+
// vector store on its own connection keeps per-member commits.
|
|
377
|
+
const batchWrites = !fastPathDisabled &&
|
|
378
|
+
!graphEmptyAtStart &&
|
|
379
|
+
mode === "full" &&
|
|
380
|
+
sharedConnection &&
|
|
381
|
+
typeof graph.beginBatch === "function" &&
|
|
382
|
+
typeof graph.endBatch === "function";
|
|
383
|
+
let bulkOpen = false;
|
|
384
|
+
let batchOpen = false;
|
|
385
|
+
let bulkFailure = null;
|
|
386
|
+
const openBulk = () => {
|
|
387
|
+
if (graphEmptyAtStart && !bulkOpen) {
|
|
388
|
+
graph.beginBulk?.({
|
|
389
|
+
freshOrgId: resolved.orgId,
|
|
390
|
+
...(sharedConnection ? {} : { batchTransactions: false }),
|
|
391
|
+
});
|
|
392
|
+
bulkOpen = true;
|
|
393
|
+
}
|
|
394
|
+
else if (batchWrites && !batchOpen) {
|
|
395
|
+
try {
|
|
396
|
+
graph.beginBatch?.();
|
|
397
|
+
batchOpen = true;
|
|
398
|
+
}
|
|
399
|
+
catch (e) {
|
|
400
|
+
// e.g. the caller holds a transaction: keep per-member commits.
|
|
401
|
+
logger.debug("live-ingest: write batching unavailable", { err: e.message });
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
const closeBulk = () => {
|
|
406
|
+
if (batchOpen) {
|
|
407
|
+
batchOpen = false;
|
|
408
|
+
graph.endBatch?.();
|
|
409
|
+
}
|
|
410
|
+
if (!bulkOpen)
|
|
411
|
+
return;
|
|
412
|
+
bulkOpen = false;
|
|
413
|
+
graph.endBulk?.();
|
|
414
|
+
};
|
|
413
415
|
const parseCtxBase = {
|
|
414
416
|
orgId: resolved.orgId,
|
|
415
417
|
parseTimestamp: new Date(now).toISOString(),
|
|
416
418
|
namespace: null,
|
|
417
419
|
logger,
|
|
418
420
|
};
|
|
419
|
-
|
|
420
|
-
|
|
421
|
+
// Task 11a: embeddings run off the graph-ready path. Inference happens in
|
|
422
|
+
// a worker thread (compiled builds) or an injected embedder, with up to 4
|
|
423
|
+
// batches in flight to keep it fed. The queue is HELD until graph ready:
|
|
424
|
+
// texts buffer (bounded by backpressure, which still forces batches out)
|
|
425
|
+
// and no inference competes for CPU with the graph build — measured, an
|
|
426
|
+
// overlapping worker slowed fan-out by ~45%. A persistent text → vector
|
|
427
|
+
// cache makes --rebuild skip the model for unchanged texts. The org is flagged `embeddings_pending` until every
|
|
428
|
+
// vector is written, so find_similar can fall back to text search and the
|
|
429
|
+
// next ingest can fill whatever a no-wait / failed run left behind. The
|
|
430
|
+
// flag is set lazily, when the queue first has real vector work (a text
|
|
431
|
+
// past the unchanged check at dispatch, or live work abandoned), so a
|
|
432
|
+
// re-sync with nothing to embed keeps find_similar's vector leg on.
|
|
433
|
+
let embedError = null;
|
|
434
|
+
let wasEmbeddingsPending = false;
|
|
435
|
+
if (opts.vectorStore) {
|
|
436
|
+
const workerUrl = opts.embedder ? null : defaultEmbeddingWorkerUrl();
|
|
437
|
+
ownedEmbedder = opts.embedder ? null : workerUrl ? new EmbeddingPool({ workerUrl }) : null;
|
|
438
|
+
const embedder = opts.embedder ?? ownedEmbedder;
|
|
439
|
+
if (opts.embeddingCacheFile) {
|
|
440
|
+
try {
|
|
441
|
+
embedCache = EmbeddingCache.open(opts.embeddingCacheFile);
|
|
442
|
+
}
|
|
443
|
+
catch (e) {
|
|
444
|
+
logger.warn("live-ingest: embedding cache unavailable", { err: e.message });
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
wasEmbeddingsPending = graph.getEmbeddingStatus?.(resolved.orgId)?.pending ?? false;
|
|
448
|
+
const maxPendingChars = Number.parseInt(process.env.SFGRAPH_EMBED_MAX_PENDING_CHARS ?? "", 10);
|
|
449
|
+
embedQueue = new EmbeddingQueue({
|
|
421
450
|
vectorStore: opts.vectorStore,
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
451
|
+
hold: true,
|
|
452
|
+
...(maxPendingChars > 0 ? { maxPendingChars } : {}),
|
|
453
|
+
onWork: () => {
|
|
454
|
+
if (!wasEmbeddingsPending)
|
|
455
|
+
graph.setEmbeddingsPending?.(resolved.orgId, true);
|
|
456
|
+
},
|
|
457
|
+
onCacheError: (err) => {
|
|
458
|
+
logger.warn("live-ingest: embedding cache write failed", { err: err.message });
|
|
459
|
+
},
|
|
460
|
+
...(embedder ? { embed: (t) => embedder.embed(t), maxInFlight: 4 } : {}),
|
|
461
|
+
...(embedCache ? { cache: embedCache } : {}),
|
|
462
|
+
onError: (err) => {
|
|
463
|
+
if (!embedError)
|
|
464
|
+
embedError = err;
|
|
465
|
+
logger.warn("live-ingest: embedding batch failed", { err: err.message });
|
|
466
|
+
},
|
|
467
|
+
});
|
|
468
|
+
}
|
|
425
469
|
const handleParsed = (parsed) => {
|
|
426
470
|
if (parsed.nodes.length) {
|
|
427
471
|
graph.mergeNodes(parsed.nodes);
|
|
@@ -437,8 +481,29 @@ export async function liveIngest(opts) {
|
|
|
437
481
|
bucket.add(qn);
|
|
438
482
|
}
|
|
439
483
|
}
|
|
440
|
-
|
|
441
|
-
|
|
484
|
+
// A parser's ParseResult is the COMPLETE authoritative outgoing-edge set
|
|
485
|
+
// for the member it parsed, so reconcile: prune any prior outgoing edge
|
|
486
|
+
// from these sources that the member no longer emits (fixes "immortal
|
|
487
|
+
// edges" — a SOQL/DML/CALLS that lingered after the code dropped it on a
|
|
488
|
+
// non-rebuild re-sync). Resolver post-passes (arity / overlap / reflection)
|
|
489
|
+
// re-add their cross-cutting edges afterward, so this is safe.
|
|
490
|
+
// N-5: a method the member still emits but that now has NO outgoing
|
|
491
|
+
// edge (its only call was removed) is not a source in `parsed.edges`,
|
|
492
|
+
// so it is named explicitly and its stale edges are pruned too.
|
|
493
|
+
const methodSrcs = [];
|
|
494
|
+
for (const n of parsed.nodes) {
|
|
495
|
+
if (n.label === "ApexMethod" || n.label === "TestMethod") {
|
|
496
|
+
methodSrcs.push(String(n.qualifiedName));
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
if (parsed.edges.length || methodSrcs.length) {
|
|
500
|
+
graph.mergeEdges(parsed.edges, {
|
|
501
|
+
reconcileSources: true,
|
|
502
|
+
...(methodSrcs.length
|
|
503
|
+
? { reconcileExtraSrcs: { orgId: resolved.orgId, qnames: methodSrcs } }
|
|
504
|
+
: {}),
|
|
505
|
+
});
|
|
506
|
+
}
|
|
442
507
|
if (parsed.snippets?.length) {
|
|
443
508
|
graph.transaction(() => {
|
|
444
509
|
for (const s of parsed.snippets ?? []) {
|
|
@@ -446,52 +511,117 @@ export async function liveIngest(opts) {
|
|
|
446
511
|
}
|
|
447
512
|
});
|
|
448
513
|
}
|
|
449
|
-
|
|
514
|
+
// Fold the stored source snippet into the search text for code nodes so
|
|
515
|
+
// search matches on what the code DOES, not just its name/attrs. (The
|
|
516
|
+
// snippet text lives in parsed.snippets, not on the node.) Bounded to a
|
|
517
|
+
// few KB — MiniLM truncates to its token window anyway, and we keep the
|
|
518
|
+
// structured buildEmbedText prefix first so identity stays dominant. The
|
|
519
|
+
// SAME text feeds both the vector index and the FTS keyword index; FTS is
|
|
520
|
+
// populated regardless of embedQueue so it works as the embedder-down
|
|
521
|
+
// fallback leg of hybrid search.
|
|
522
|
+
if (parsed.nodes.length) {
|
|
523
|
+
const snippetByQname = new Map();
|
|
524
|
+
for (const s of parsed.snippets ?? []) {
|
|
525
|
+
snippetByQname.set(String(s.qualifiedName), s.sourceText);
|
|
526
|
+
}
|
|
450
527
|
for (const n of parsed.nodes) {
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
528
|
+
const qn = String(n.qualifiedName);
|
|
529
|
+
let text = buildEmbedText(n.label, qn, n.attributes);
|
|
530
|
+
const snippet = snippetByQname.get(qn);
|
|
531
|
+
if (snippet)
|
|
532
|
+
text += `\n${snippet.slice(0, 4000)}`;
|
|
533
|
+
graph.upsertNodeFts(n.orgId, n.qualifiedName, n.label, text);
|
|
534
|
+
if (embedQueue) {
|
|
535
|
+
embedQueue.push({ qname: qn, text, orgId: String(n.orgId), label: n.label });
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
};
|
|
540
|
+
// Purge a deleted node's vector so it stops surfacing as a phantom
|
|
541
|
+
// find_similar hit. The vec0 table lives in the VectorStore (not the graph
|
|
542
|
+
// store); feature-detect since lightweight sinks may not implement delete.
|
|
543
|
+
const purgeNodeVector = (qname) => {
|
|
544
|
+
const sink = opts.vectorStore;
|
|
545
|
+
if (sink && typeof sink.deleteNodeVector === "function") {
|
|
546
|
+
try {
|
|
547
|
+
sink.deleteNodeVector(resolved.orgId, qname);
|
|
548
|
+
}
|
|
549
|
+
catch (e) {
|
|
550
|
+
logger.warn("live-ingest: vector purge failed", {
|
|
551
|
+
qname: String(qname),
|
|
552
|
+
err: e.message,
|
|
456
553
|
});
|
|
457
554
|
}
|
|
458
555
|
}
|
|
459
556
|
};
|
|
460
557
|
const debugProcess = process.env.SFGRAPH_DEBUG_INGEST === "1";
|
|
461
|
-
|
|
558
|
+
// Per-member timings, filled by applyMember (parse vs. store write) and
|
|
559
|
+
// consumed by the member loop. Reset on every call. These are shared
|
|
560
|
+
// closure state: applyMember must NOT be called concurrently.
|
|
561
|
+
let lastParseMs = 0;
|
|
562
|
+
let lastWriteMs = 0;
|
|
563
|
+
// Apply one member's parse outcome to the graph (or delete an obsolete
|
|
564
|
+
// member). Always on the main thread, in member order: the parse may have
|
|
565
|
+
// run in a worker (parsePool), the writes never do.
|
|
566
|
+
const applyMember = (ref, outcome) => {
|
|
462
567
|
const qnameForLog = `${ref.memberType}:${ref.memberName}`;
|
|
568
|
+
lastParseMs = 0;
|
|
569
|
+
lastWriteMs = 0;
|
|
463
570
|
if (ref.obsolete) {
|
|
464
|
-
// Build the
|
|
465
|
-
|
|
571
|
+
// Build the qname with the node's LABEL, not the raw SourceMember type:
|
|
572
|
+
// e.g. LightningComponentBundle is stored as `LWC:<name>`, so the old
|
|
573
|
+
// `${memberType}:${name}` never matched and LWC deletes were silent
|
|
574
|
+
// no-ops. Fall back to memberType when no mapping exists.
|
|
575
|
+
const label = MEMBER_TYPE_TO_NODE_LABEL[ref.memberType] ?? ref.memberType;
|
|
576
|
+
const qname = asQualifiedName(`${label}:${ref.memberName}`);
|
|
466
577
|
if (debugProcess)
|
|
467
578
|
console.log(`ingest: [trace] delete ← ${qnameForLog}`);
|
|
579
|
+
// Cascade to contained children (a class/trigger owns ApexMethod /
|
|
580
|
+
// TestMethod nodes via CONTAINS_METHOD). Deleting only the parent left
|
|
581
|
+
// the method nodes — and their edges/snippets/vectors — orphaned.
|
|
582
|
+
for (const e of graph.listEdgesFrom(resolved.orgId, qname, REL_TYPES.CONTAINS_METHOD)) {
|
|
583
|
+
const child = e.dstQualifiedName;
|
|
584
|
+
graph.deleteEdgesFor(resolved.orgId, child);
|
|
585
|
+
graph.deleteNode(resolved.orgId, child);
|
|
586
|
+
purgeNodeVector(child);
|
|
587
|
+
}
|
|
468
588
|
graph.deleteEdgesFor(resolved.orgId, qname);
|
|
469
589
|
graph.deleteNode(resolved.orgId, qname);
|
|
590
|
+
purgeNodeVector(qname);
|
|
470
591
|
if (debugProcess)
|
|
471
592
|
console.log(`ingest: [trace] delete ✓ ${qnameForLog}`);
|
|
472
593
|
deletions += 1;
|
|
473
594
|
return;
|
|
474
595
|
}
|
|
475
|
-
|
|
476
|
-
if (
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
if (!parser)
|
|
596
|
+
// Building the parser input threw: surfaces to the member loop's catch.
|
|
597
|
+
if (outcome.kind === "error" && outcome.phase === "adapt")
|
|
598
|
+
throw new Error(outcome.message);
|
|
599
|
+
if (outcome.kind === "skip")
|
|
480
600
|
return;
|
|
601
|
+
// Emitted when the result is applied (in member order); the parse itself
|
|
602
|
+
// may have run earlier in a worker.
|
|
603
|
+
if (debugProcess)
|
|
604
|
+
console.log(`ingest: [trace] parse ← ${qnameForLog}`);
|
|
605
|
+
lastParseMs = outcome.parseMs;
|
|
481
606
|
try {
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
const result = await parser.parse(adapted.input, ctx);
|
|
607
|
+
if (outcome.kind === "error") {
|
|
608
|
+
const err = new Error(outcome.message);
|
|
609
|
+
if (outcome.stack)
|
|
610
|
+
err.stack = outcome.stack;
|
|
611
|
+
throw err;
|
|
612
|
+
}
|
|
613
|
+
const result = outcome.result;
|
|
490
614
|
if (debugProcess)
|
|
491
615
|
console.log(`ingest: [trace] parse ✓ ${qnameForLog} (nodes=${result.nodes.length} edges=${result.edges.length})`);
|
|
492
616
|
if (debugProcess)
|
|
493
617
|
console.log(`ingest: [trace] graph-merge ← ${qnameForLog}`);
|
|
494
|
-
|
|
618
|
+
const tWrite = performance.now();
|
|
619
|
+
try {
|
|
620
|
+
handleParsed(result);
|
|
621
|
+
}
|
|
622
|
+
finally {
|
|
623
|
+
lastWriteMs = performance.now() - tWrite;
|
|
624
|
+
}
|
|
495
625
|
if (debugProcess)
|
|
496
626
|
console.log(`ingest: [trace] graph-merge ✓ ${qnameForLog}`);
|
|
497
627
|
membersProcessed += 1;
|
|
@@ -508,13 +638,161 @@ export async function liveIngest(opts) {
|
|
|
508
638
|
}
|
|
509
639
|
}
|
|
510
640
|
};
|
|
641
|
+
// Task 11c: member rows (delta ingest's record of what each member owns)
|
|
642
|
+
// and the ghost sweep, on a full ingest of a metadataSource. The rows are
|
|
643
|
+
// cleared now and rewritten only once the ingest completes, so an
|
|
644
|
+
// interrupted run leaves no rows and the next delta falls back to a full
|
|
645
|
+
// rebuild. The ghost sweep deletes what a member owned last run that no
|
|
646
|
+
// member owns now (a deleted / renamed file), before the resolvers run.
|
|
647
|
+
if (opts.delta && (!opts.metadataSource || mode !== "full")) {
|
|
648
|
+
throw new Error("liveIngest: delta hooks need a metadataSource and mode 'full'");
|
|
649
|
+
}
|
|
650
|
+
const deltaHooks = opts.delta;
|
|
651
|
+
const priorRows = !deltaHooks &&
|
|
652
|
+
opts.metadataSource &&
|
|
653
|
+
mode === "full" &&
|
|
654
|
+
graph.listMemberRows &&
|
|
655
|
+
graph.replaceMemberRows
|
|
656
|
+
? graph.listMemberRows(resolved.orgId)
|
|
657
|
+
: null;
|
|
658
|
+
if (priorRows && priorRows.length > 0)
|
|
659
|
+
graph.clearMemberRows?.(resolved.orgId);
|
|
660
|
+
const memberRows = priorRows ? new Map() : null;
|
|
661
|
+
const priorRowByKey = new Map((priorRows ?? []).map((r) => [r.key, r]));
|
|
662
|
+
const keptPrior = [];
|
|
663
|
+
// T15 N5-1: members quarantined by earlier runs (workers kept failing on
|
|
664
|
+
// that exact content) are not parsed again until their content changes.
|
|
665
|
+
const quarantinedKeys = new Set((priorRows ?? []).filter((r) => isQuarantinedRow(r)).map((r) => r.key));
|
|
666
|
+
const quarantinePreset = (m) => quarantinedKeys.has(m.ref.sourceUri) &&
|
|
667
|
+
isQuarantinedFor(priorRowByKey.get(m.ref.sourceUri), memberContentHash(m.content))
|
|
668
|
+
? quarantinedOutcome()
|
|
669
|
+
: undefined;
|
|
670
|
+
const recordMemberRow = (member, outcome, errored) => {
|
|
671
|
+
if (!memberRows)
|
|
672
|
+
return;
|
|
673
|
+
const key = member.ref.sourceUri;
|
|
674
|
+
const prior = priorRowByKey.get(key);
|
|
675
|
+
const owned = outcome.kind === "parsed" ? ownedQnames(outcome.result) : [];
|
|
676
|
+
if (errored || (isParseFailureOnly(owned) && hasGoodPriorOwned(prior))) {
|
|
677
|
+
// Keep what it owned (its nodes are not re-emitted, nor swept). A
|
|
678
|
+
// member that parsed to ParseError only (N2-1) or whose parse threw
|
|
679
|
+
// records the hash of its broken content and is skipped until it
|
|
680
|
+
// changes; one whose merge failed is retried by every delta.
|
|
681
|
+
if (hasGoodPriorOwned(prior))
|
|
682
|
+
keptPrior.push(key);
|
|
683
|
+
memberRows.set(key, {
|
|
684
|
+
key,
|
|
685
|
+
...memberFailureStamp(member, outcome, errored, prior),
|
|
686
|
+
owned: [...new Set([...(prior?.owned ?? []), ...owned])],
|
|
687
|
+
});
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
690
|
+
memberRows.set(key, {
|
|
691
|
+
key,
|
|
692
|
+
fingerprint: member.fingerprint ?? "",
|
|
693
|
+
hash: memberContentHash(member.content),
|
|
694
|
+
owned,
|
|
695
|
+
});
|
|
696
|
+
};
|
|
697
|
+
const finishMemberRows = () => {
|
|
698
|
+
if (!memberRows || !priorRows)
|
|
699
|
+
return;
|
|
700
|
+
if (streamAborted) {
|
|
701
|
+
memberRows.clear();
|
|
702
|
+
return;
|
|
703
|
+
}
|
|
704
|
+
if (priorRows.length === 0)
|
|
705
|
+
return;
|
|
706
|
+
// Members the source indexed but could not load (unreadable, malformed)
|
|
707
|
+
// keep their previous graph and row (retried by the next delta).
|
|
708
|
+
const unloaded = opts.metadataSource?.unloadedKeys?.();
|
|
709
|
+
if (unloaded) {
|
|
710
|
+
for (const r of priorRows) {
|
|
711
|
+
if (!unloaded.has(r.key) || memberRows.has(r.key))
|
|
712
|
+
continue;
|
|
713
|
+
memberRows.set(r.key, { ...r, fingerprint: "" });
|
|
714
|
+
keptPrior.push(r.key);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
if (keptPrior.length > 0) {
|
|
718
|
+
wedgeWarnings.push(`wedge:ingest:kept-prior:members=${keptPrior.length}`);
|
|
719
|
+
logger.warn("live-ingest: unreadable / unparseable members keep their previous graph", {
|
|
720
|
+
members: keptPrior.slice(0, 20),
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
if (memberRows.size === 0) {
|
|
724
|
+
// Same guard as detect-deletions' empty-stream refusal: a source that
|
|
725
|
+
// yielded no members at all (wrong path, unreadable tree) must not
|
|
726
|
+
// wipe the graph. No rows are written, so the next delta rebuilds.
|
|
727
|
+
wedgeWarnings.push(`wedge:ghost-sweep:refuse:reason=empty-stream:priorMembers=${priorRows.length}`);
|
|
728
|
+
logger.warn("live-ingest: ghost sweep refused (the source yielded no members)", {
|
|
729
|
+
priorMembers: priorRows.length,
|
|
730
|
+
});
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
733
|
+
// Qnames match case-insensitively (the store's NOCASE): `ApexClass:Util`
|
|
734
|
+
// re-emitted as `ApexClass:UTIL` is the same node, not a ghost.
|
|
735
|
+
const ownedNow = new Set();
|
|
736
|
+
for (const r of memberRows.values())
|
|
737
|
+
for (const q of r.owned)
|
|
738
|
+
ownedNow.add(q.toLowerCase());
|
|
739
|
+
const ghosts = [];
|
|
740
|
+
for (const r of priorRows) {
|
|
741
|
+
for (const q of r.owned)
|
|
742
|
+
if (!ownedNow.has(q.toLowerCase()))
|
|
743
|
+
ghosts.push(q);
|
|
744
|
+
}
|
|
745
|
+
if (ghosts.length === 0)
|
|
746
|
+
return;
|
|
747
|
+
let removed = 0;
|
|
748
|
+
graph.transaction(() => {
|
|
749
|
+
graph.deleteEdgesFrom?.(resolved.orgId, ghosts);
|
|
750
|
+
graph.deleteReflectionEdges?.(resolved.orgId, { dsts: ghosts });
|
|
751
|
+
for (const q of new Set(ghosts)) {
|
|
752
|
+
const qn = asQualifiedName(q);
|
|
753
|
+
if (!graph.getNode(resolved.orgId, qn))
|
|
754
|
+
continue;
|
|
755
|
+
graph.deleteNode(resolved.orgId, qn);
|
|
756
|
+
purgeNodeVector(qn);
|
|
757
|
+
removed += 1;
|
|
758
|
+
}
|
|
759
|
+
});
|
|
760
|
+
deletions += removed;
|
|
761
|
+
if (removed > 0)
|
|
762
|
+
logger.info("live-ingest: ghost sweep removed nodes of vanished members", { removed });
|
|
763
|
+
};
|
|
764
|
+
// Serial parse + apply (incremental deletions).
|
|
765
|
+
const processOne = async (ref, content) => {
|
|
766
|
+
const outcome = ref.obsolete
|
|
767
|
+
? { kind: "skip", parseMs: 0 }
|
|
768
|
+
: await parseMember(ref, content, parseCtxBase, logger);
|
|
769
|
+
applyMember(ref, outcome);
|
|
770
|
+
};
|
|
511
771
|
if (mode === "incremental") {
|
|
512
772
|
const sinceIso = existing?.lastSyncedAt
|
|
513
773
|
? new Date(existing.lastSyncedAt).toISOString()
|
|
514
774
|
: new Date(now - 24 * 3600 * 1000).toISOString();
|
|
775
|
+
// Incremental applies DELETIONS (obsolete members need no content) but
|
|
776
|
+
// does NOT re-parse changed/added members: their content is not fetched
|
|
777
|
+
// here, and calling processOne(ref, "") would overwrite real node
|
|
778
|
+
// attributes with empty-parse garbage and emit no edges — actively
|
|
779
|
+
// degrading the graph. Until per-member content fetch lands, changed
|
|
780
|
+
// members are counted and the user is told to run a full ingest to
|
|
781
|
+
// refresh them. (Deletions are still valuable and safe.)
|
|
782
|
+
let changedNotApplied = 0;
|
|
515
783
|
for await (const ref of iterChanges(resolved.conn, resolved.orgId, sinceIso)) {
|
|
516
|
-
|
|
517
|
-
|
|
784
|
+
if (ref.obsolete) {
|
|
785
|
+
await processOne(ref, "");
|
|
786
|
+
}
|
|
787
|
+
else {
|
|
788
|
+
changedNotApplied += 1;
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
incrementalUnfetched = changedNotApplied;
|
|
792
|
+
if (changedNotApplied > 0) {
|
|
793
|
+
const msg = `incremental: ${changedNotApplied} changed/added member(s) detected but NOT refreshed (content fetch not implemented for incremental). The sync watermark is being HELD so the next run re-detects them. Run \`sfgraph ingest --org ${resolved.alias} --rebuild\` (or --mode full) to capture them.`;
|
|
794
|
+
logger.warn(msg);
|
|
795
|
+
wedgeWarnings.push(`incremental:contentNotFetched:count=${changedNotApplied}`);
|
|
518
796
|
}
|
|
519
797
|
}
|
|
520
798
|
else {
|
|
@@ -537,7 +815,8 @@ export async function liveIngest(opts) {
|
|
|
537
815
|
// different edge tables rather than competing for the same row, but
|
|
538
816
|
// the pre-fan-out ordering preserves the "parsed wins" guarantee for
|
|
539
817
|
// the (rare) case where a parser does emit REFERENCES.
|
|
540
|
-
|
|
818
|
+
openBulk();
|
|
819
|
+
if (!opts.disableMcdBaseline && !opts.metadataSource) {
|
|
541
820
|
try {
|
|
542
821
|
const { runMcdBaseline } = await import("../extractors/live-org/extractors/mcd-baseline.js");
|
|
543
822
|
const mcdCtx = {
|
|
@@ -614,7 +893,7 @@ export async function liveIngest(opts) {
|
|
|
614
893
|
// benefit. The probe's job is observability, not control flow.
|
|
615
894
|
// Disable via SFGRAPH_NO_LIVENESS_PROBE=1 for hermetic test runs
|
|
616
895
|
// where the mock connection has no identity() implementation.
|
|
617
|
-
if (process.env.SFGRAPH_NO_LIVENESS_PROBE !== "1") {
|
|
896
|
+
if (process.env.SFGRAPH_NO_LIVENESS_PROBE !== "1" && !opts.metadataSource) {
|
|
618
897
|
livenessProbe = startLivenessProbe(resolved.conn);
|
|
619
898
|
}
|
|
620
899
|
// Wall-clock heartbeat — always on. Without this, silent phases (where
|
|
@@ -667,6 +946,17 @@ export async function liveIngest(opts) {
|
|
|
667
946
|
console.error(`ingest: [debug] received ${sig} after ${Math.round((Date.now() - fanOutStart) / 1000)}s — processed=${progressCount} lastSource=${lastMemberLabel}`);
|
|
668
947
|
console.error(new Error(`signal:${sig}`).stack);
|
|
669
948
|
process.exitCode = 130;
|
|
949
|
+
// rel-08: a breadcrumb only — never swallow the signal. Drop the
|
|
950
|
+
// debug handlers; if nothing else handles it (an embedding host
|
|
951
|
+
// or the CLI would), re-raise so the default action terminates.
|
|
952
|
+
// Review minor 12: on the library path the default action kills
|
|
953
|
+
// the process without the finally blocks, so the ingest lock file
|
|
954
|
+
// and sync_in_progress stay behind; the next run reclaims both
|
|
955
|
+
// through the dead-owner (stale pid) check (rel-02).
|
|
956
|
+
for (const h of installedSignalHandlers.splice(0))
|
|
957
|
+
process.off(h.sig, h.fn);
|
|
958
|
+
if (process.listenerCount(sig) === 0)
|
|
959
|
+
process.kill(process.pid, sig);
|
|
670
960
|
};
|
|
671
961
|
const onUsr2 = () => {
|
|
672
962
|
const mem = process.memoryUsage();
|
|
@@ -679,21 +969,65 @@ export async function liveIngest(opts) {
|
|
|
679
969
|
process.on(h.sig, h.fn);
|
|
680
970
|
}
|
|
681
971
|
try {
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
972
|
+
const memberStream = deltaHooks
|
|
973
|
+
? deltaHooks.members
|
|
974
|
+
: opts.metadataSource
|
|
975
|
+
? opts.metadataSource.iter()
|
|
976
|
+
: bulkRetrieve(resolved.conn, caps, resolved.orgId, {
|
|
977
|
+
skipReport,
|
|
978
|
+
warnings: wedgeWarnings,
|
|
979
|
+
...(opts.onlyLabels ? { onlyLabels: opts.onlyLabels } : {}),
|
|
980
|
+
...(opts.explicitOnlyLabels ? { explicitOnlyLabels: true } : {}),
|
|
981
|
+
// The bulk-retrieve flag name follows the same convention as
|
|
982
|
+
// the bulk-retrieve's other opts; semantically it's "do the
|
|
983
|
+
// retrieve()" which is now on by default. Caller-side disable
|
|
984
|
+
// routes through this same boolean inverted.
|
|
985
|
+
...(opts.disableOmnistudioRetrieve ? {} : { enableOmnistudioRetrieve: true }),
|
|
986
|
+
// jsforce attaches the version it negotiated on conn.version; fall
|
|
987
|
+
// back to a sensible recent release if absent (mocks, etc.)
|
|
988
|
+
apiVersion: resolved.conn.version ?? "60.0",
|
|
989
|
+
});
|
|
990
|
+
const tFanout = performance.now();
|
|
991
|
+
// Task 11b: parse in worker threads (SFGRAPH_PARSE_WORKERS, default
|
|
992
|
+
// min(4, availableParallelism - 1); 0 = main thread), apply in member
|
|
993
|
+
// order here.
|
|
994
|
+
const parseStats = opts.parsePool?.stats ?? {
|
|
995
|
+
workers: 0,
|
|
996
|
+
pooled: 0,
|
|
997
|
+
inProcess: 0,
|
|
998
|
+
fallbacks: 0,
|
|
999
|
+
crashes: 0,
|
|
1000
|
+
oomFallbacks: 0,
|
|
1001
|
+
};
|
|
1002
|
+
const parsed = parsePool(memberStream, {
|
|
1003
|
+
orgId: parseCtxBase.orgId,
|
|
1004
|
+
parseTimestamp: parseCtxBase.parseTimestamp,
|
|
1005
|
+
logger,
|
|
1006
|
+
workers: opts.parsePool?.workers ?? resolveParseWorkers(),
|
|
1007
|
+
...(opts.parsePool?.workerUrl !== undefined
|
|
1008
|
+
? { workerUrl: opts.parsePool.workerUrl }
|
|
1009
|
+
: {}),
|
|
1010
|
+
...(opts.parsePool?.minMembers !== undefined
|
|
1011
|
+
? { minMembers: opts.parsePool.minMembers }
|
|
1012
|
+
: {}),
|
|
1013
|
+
stats: parseStats,
|
|
1014
|
+
...(quarantinedKeys.size > 0 ? { preset: quarantinePreset } : {}),
|
|
1015
|
+
});
|
|
1016
|
+
for await (const { member, outcome } of parsed) {
|
|
1017
|
+
const errorsBefore = parseErrors;
|
|
1018
|
+
if (batchOpen)
|
|
1019
|
+
graph.batchMemberStart?.();
|
|
695
1020
|
try {
|
|
696
|
-
|
|
1021
|
+
applyMember(member.ref, outcome);
|
|
1022
|
+
if (profiler.enabled) {
|
|
1023
|
+
profiler.member({
|
|
1024
|
+
qname: `${member.ref.memberType}:${member.ref.memberName}`,
|
|
1025
|
+
label: member.ref.memberType,
|
|
1026
|
+
bytes: member.content.length,
|
|
1027
|
+
parseMs: lastParseMs,
|
|
1028
|
+
writeMs: lastWriteMs,
|
|
1029
|
+
});
|
|
1030
|
+
}
|
|
697
1031
|
}
|
|
698
1032
|
catch (e) {
|
|
699
1033
|
parseErrors += 1;
|
|
@@ -702,6 +1036,33 @@ export async function liveIngest(opts) {
|
|
|
702
1036
|
error: e.message,
|
|
703
1037
|
});
|
|
704
1038
|
}
|
|
1039
|
+
// Task 11c: member rows (what each member owns) for delta ingest.
|
|
1040
|
+
const errored = outcome.kind === "error" || parseErrors > errorsBefore;
|
|
1041
|
+
if (deltaHooks)
|
|
1042
|
+
deltaHooks.onMember(member, outcome, errored);
|
|
1043
|
+
else if (memberRows && member.fingerprint !== undefined) {
|
|
1044
|
+
recordMemberRow(member, outcome, errored);
|
|
1045
|
+
}
|
|
1046
|
+
if (bulkOpen || batchOpen) {
|
|
1047
|
+
// Outside the per-member catch: if SQLite rolled back the bulk
|
|
1048
|
+
// transaction (SQLITE_FULL / IOERR / NOMEM), up to 2,000 earlier
|
|
1049
|
+
// members are gone, so the ingest must fail, not count one error.
|
|
1050
|
+
// The same holds for a live-graph batch.
|
|
1051
|
+
try {
|
|
1052
|
+
if (bulkOpen)
|
|
1053
|
+
graph.bulkMemberDone?.();
|
|
1054
|
+
else
|
|
1055
|
+
graph.batchMemberDone?.();
|
|
1056
|
+
}
|
|
1057
|
+
catch (e) {
|
|
1058
|
+
bulkFailure = e;
|
|
1059
|
+
break;
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
// Backpressure: past the queued-text bound, wait for forced
|
|
1063
|
+
// batches to drain (the only inference during fan-out).
|
|
1064
|
+
if (embedQueue?.overCapacity)
|
|
1065
|
+
await embedQueue.waitForCapacity();
|
|
705
1066
|
progressCount += 1;
|
|
706
1067
|
lastActivityAt = Date.now();
|
|
707
1068
|
lastMemberLabel = `${member.ref.memberType}:${member.ref.memberName}`;
|
|
@@ -719,6 +1080,9 @@ export async function liveIngest(opts) {
|
|
|
719
1080
|
gs.checkpoint();
|
|
720
1081
|
}
|
|
721
1082
|
}
|
|
1083
|
+
profiler.phase("fanout", performance.now() - tFanout);
|
|
1084
|
+
// Always printed (serial too) so bench runs can record the counts.
|
|
1085
|
+
console.log(`ingest: parse pool: ${parseStats.workers} workers, ${parseStats.pooled} parsed in workers, ${parseStats.inProcess} on main (${parseStats.fallbacks} fallbacks, ${parseStats.crashes} worker crashes, ${parseStats.oomFallbacks ?? 0} heap-cap re-parses)`);
|
|
722
1086
|
console.log(`ingest: fan-out complete (${progressCount} members in ${Math.round((Date.now() - fanOutStart) / 1000)}s)`);
|
|
723
1087
|
const gs = graph;
|
|
724
1088
|
if (typeof gs.checkpoint === "function")
|
|
@@ -731,6 +1095,8 @@ export async function liveIngest(opts) {
|
|
|
731
1095
|
logger.warn("live-ingest: bulkRetrieve stream aborted", {
|
|
732
1096
|
error: e.message,
|
|
733
1097
|
});
|
|
1098
|
+
// Never a silent partial ingest: the abort is in the result's warnings.
|
|
1099
|
+
wedgeWarnings.push(`stream:aborted:${String(e.message).slice(0, 200)}`);
|
|
734
1100
|
}
|
|
735
1101
|
}
|
|
736
1102
|
finally {
|
|
@@ -741,6 +1107,31 @@ export async function liveIngest(opts) {
|
|
|
741
1107
|
livenessProbe?.stop();
|
|
742
1108
|
for (const h of installedSignalHandlers)
|
|
743
1109
|
process.off(h.sig, h.fn);
|
|
1110
|
+
// Commit the last bulk batch and rebuild the deferred indexes before
|
|
1111
|
+
// any post-pass reads the graph.
|
|
1112
|
+
const tEndBulk = performance.now();
|
|
1113
|
+
closeBulk();
|
|
1114
|
+
if (graphEmptyAtStart)
|
|
1115
|
+
profiler.phase("endBulk", performance.now() - tEndBulk);
|
|
1116
|
+
}
|
|
1117
|
+
if (bulkFailure)
|
|
1118
|
+
throw bulkFailure;
|
|
1119
|
+
if (deltaHooks) {
|
|
1120
|
+
// A partial stream must not be finalized as a delta: fail, keeping
|
|
1121
|
+
// the pending marker, so the next delta replays it.
|
|
1122
|
+
if (streamAborted)
|
|
1123
|
+
throw new Error("delta: member stream aborted");
|
|
1124
|
+
deltaHooks.afterMerge();
|
|
1125
|
+
}
|
|
1126
|
+
else if (memberRows) {
|
|
1127
|
+
finishMemberRows();
|
|
1128
|
+
}
|
|
1129
|
+
// A scoped run (auto-retry pass, --retry-skipped, --only) re-ran only
|
|
1130
|
+
// `onlyLabels`: carry the previous report's entries for every OTHER
|
|
1131
|
+
// label forward, so unreadable / insufficient_access entries it did
|
|
1132
|
+
// not touch stay in the report, the summary and the warnings (I2).
|
|
1133
|
+
if (opts.onlyLabels && opts.skipReportPath) {
|
|
1134
|
+
skipReport.skips.push(...carriedOverSkips(opts.skipReportPath, resolved.orgId, opts.onlyLabels));
|
|
744
1135
|
}
|
|
745
1136
|
// End-of-run skip summary. Grouped by category so the remediation is
|
|
746
1137
|
// targeted to the specific class of failure.
|
|
@@ -762,19 +1153,16 @@ export async function liveIngest(opts) {
|
|
|
762
1153
|
}
|
|
763
1154
|
}
|
|
764
1155
|
}
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
await embedQueue.drain();
|
|
768
|
-
}
|
|
769
|
-
catch (e) {
|
|
770
|
-
logger.warn("live-ingest: embed drain failed", { err: e.message });
|
|
771
|
-
}
|
|
772
|
-
}
|
|
1156
|
+
// Mark the end of input (the held queue still runs nothing until graph ready).
|
|
1157
|
+
embedQueue?.startDrain();
|
|
773
1158
|
// Full-sync deletion detection: compute previously-known minus touched and
|
|
774
1159
|
// delete the difference. Skipped on incremental (SourceMember handles it),
|
|
775
1160
|
// skipped if any parse error occurred this run (avoid mass-wipe on
|
|
776
1161
|
// transient SF errors).
|
|
777
|
-
|
|
1162
|
+
// Fast path: an org that was empty at start has no stale qnames — every
|
|
1163
|
+
// persisted node was touched by this run — so the sweep (and its
|
|
1164
|
+
// deleteEdgesFor calls) would be a no-op; skip it.
|
|
1165
|
+
if (opts.detectDeletions && !opts.metadataSource && mode === "full" && !graphEmptyAtStart) {
|
|
778
1166
|
if (streamAborted) {
|
|
779
1167
|
logger.warn("live-ingest: detect-deletions skipped because bulkRetrieve stream aborted — touchedQnames is incomplete and a full deletion sweep would wrongly wipe untouched-but-still-present nodes");
|
|
780
1168
|
}
|
|
@@ -790,7 +1178,18 @@ export async function liveIngest(opts) {
|
|
|
790
1178
|
// compounds with the W1.5-01/02 wedge cascade). Now we evaluate the
|
|
791
1179
|
// guard per label and refuse when the implied drop is suspicious.
|
|
792
1180
|
const maxDropRatio = resolveMaxDropRatio(process.env.SFGRAPH_DETECT_DELETIONS_MAX_DROP_RATIO);
|
|
793
|
-
|
|
1181
|
+
// Task 11c: a node from a source this run skipped (or carried a
|
|
1182
|
+
// skip for) is never "stale" — the source touched nothing.
|
|
1183
|
+
const protection = skipProtection(skipReport.skips);
|
|
1184
|
+
if (protection.refuseAll) {
|
|
1185
|
+
const warning = `wedge:detect-deletions:refuse:label=*:reason=skipped-source:skips=${protection.unknownLabels.join(",")}`;
|
|
1186
|
+
wedgeWarnings.push(warning);
|
|
1187
|
+
logger.warn("live-ingest: detect-deletions refused (a skipped source has no type mapping)", {
|
|
1188
|
+
skips: protection.unknownLabels,
|
|
1189
|
+
});
|
|
1190
|
+
}
|
|
1191
|
+
const labels = protection.refuseAll ? [] : graph.listAllLabels();
|
|
1192
|
+
let protectedCount = 0;
|
|
794
1193
|
for (const label of labels) {
|
|
795
1194
|
const priorCount = graph.countNodesByLabel(resolved.orgId, label);
|
|
796
1195
|
const touchedCount = touchedQnamesByLabel.get(label)?.size ?? 0;
|
|
@@ -818,8 +1217,13 @@ export async function liveIngest(opts) {
|
|
|
818
1217
|
const q = String(node.qualifiedName);
|
|
819
1218
|
if (touchedSet?.has(q))
|
|
820
1219
|
continue;
|
|
1220
|
+
if (isSkipProtected(protection, node)) {
|
|
1221
|
+
protectedCount += 1;
|
|
1222
|
+
continue;
|
|
1223
|
+
}
|
|
821
1224
|
graph.deleteEdgesFor(resolved.orgId, asQualifiedName(q));
|
|
822
1225
|
graph.deleteNode(resolved.orgId, asQualifiedName(q));
|
|
1226
|
+
purgeNodeVector(asQualifiedName(q));
|
|
823
1227
|
deletions += 1;
|
|
824
1228
|
labelDeletions += 1;
|
|
825
1229
|
}
|
|
@@ -830,12 +1234,50 @@ export async function liveIngest(opts) {
|
|
|
830
1234
|
});
|
|
831
1235
|
}
|
|
832
1236
|
}
|
|
1237
|
+
if (protectedCount > 0) {
|
|
1238
|
+
logger.info("live-ingest: detect-deletions kept nodes of skipped sources", {
|
|
1239
|
+
count: protectedCount,
|
|
1240
|
+
});
|
|
1241
|
+
}
|
|
833
1242
|
}
|
|
834
1243
|
catch (e) {
|
|
835
1244
|
logger.warn("live-ingest: detect-deletions failed", { err: e.message });
|
|
836
1245
|
}
|
|
837
1246
|
}
|
|
838
1247
|
}
|
|
1248
|
+
// Backfill: an earlier run returned before its vectors were all written
|
|
1249
|
+
// (--no-wait-embeddings, a worker crash, a kill). Every embedded text is
|
|
1250
|
+
// also stored verbatim as the node's FTS body, so re-queue the docs this
|
|
1251
|
+
// run did not touch whose stored vector is missing or stale.
|
|
1252
|
+
let backfilled = 0;
|
|
1253
|
+
if (embedQueue && wasEmbeddingsPending && graph.listFtsDocs) {
|
|
1254
|
+
const sink = opts.vectorStore;
|
|
1255
|
+
try {
|
|
1256
|
+
for (const doc of graph.listFtsDocs(resolved.orgId)) {
|
|
1257
|
+
if (touchedQnames.has(doc.qname))
|
|
1258
|
+
continue;
|
|
1259
|
+
const stored = sink?.getContentHash?.(resolved.orgId, asQualifiedName(doc.qname));
|
|
1260
|
+
if (stored && stored === hashEmbedText(doc.body))
|
|
1261
|
+
continue;
|
|
1262
|
+
embedQueue.push({
|
|
1263
|
+
qname: doc.qname,
|
|
1264
|
+
text: doc.body,
|
|
1265
|
+
orgId: String(resolved.orgId),
|
|
1266
|
+
label: doc.label,
|
|
1267
|
+
});
|
|
1268
|
+
backfilled += 1;
|
|
1269
|
+
if (embedQueue.overCapacity)
|
|
1270
|
+
await embedQueue.waitForCapacity();
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
catch (e) {
|
|
1274
|
+
logger.warn("live-ingest: embedding backfill failed", { err: e.message });
|
|
1275
|
+
}
|
|
1276
|
+
if (backfilled > 0) {
|
|
1277
|
+
logger.info("live-ingest: re-queued pending embeddings", { backfilled });
|
|
1278
|
+
}
|
|
1279
|
+
embedQueue.startDrain();
|
|
1280
|
+
}
|
|
839
1281
|
// -----------------------------------------------------------------------
|
|
840
1282
|
// Post-merge resolver passes. Each step is isolated in try/catch so a
|
|
841
1283
|
// single resolver bug never breaks ingest — it just reports zero work done.
|
|
@@ -843,14 +1285,30 @@ export async function liveIngest(opts) {
|
|
|
843
1285
|
let crossFlavorEdges = 0;
|
|
844
1286
|
let arityResolved = 0;
|
|
845
1287
|
let flowMethodsResolved = 0;
|
|
1288
|
+
let vlocityApexResult;
|
|
1289
|
+
let drRelationshipsResult;
|
|
846
1290
|
let danglingEdges = 0;
|
|
847
1291
|
let overlapResult = { matched: 0, diverged: 0, empty: 0, annotated: 0 };
|
|
848
1292
|
let reflectionEdges = 0;
|
|
1293
|
+
// T15 I-2: post-merge steps that threw. A full ingest only warns; a delta
|
|
1294
|
+
// must not finalize (see below).
|
|
1295
|
+
const postFailures = [];
|
|
849
1296
|
// Synth a ParseContext for post-passes that need to mint edges/nodes.
|
|
850
1297
|
const postCtx = {
|
|
851
1298
|
...parseCtxBase,
|
|
852
1299
|
sourceUri: "post-merge://resolver",
|
|
853
1300
|
};
|
|
1301
|
+
// review I4: re-target Aura `<c:name>` embeds at the bundles that exist.
|
|
1302
|
+
try {
|
|
1303
|
+
const auraEmbeds = resolveAuraEmbeds(graph, resolved.orgId);
|
|
1304
|
+
if (auraEmbeds.retargeted > 0) {
|
|
1305
|
+
logger.info("live-ingest: aura embed resolver re-targeted embeds", { ...auraEmbeds });
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
catch (e) {
|
|
1309
|
+
postFailures.push("aura embed resolver");
|
|
1310
|
+
logger.warn("live-ingest: aura embed resolver failed", { err: e.message });
|
|
1311
|
+
}
|
|
854
1312
|
if (!opts.disableCrossFlavor) {
|
|
855
1313
|
try {
|
|
856
1314
|
crossFlavorEdges = resolveCrossFlavor(graph, {
|
|
@@ -865,6 +1323,7 @@ export async function liveIngest(opts) {
|
|
|
865
1323
|
}
|
|
866
1324
|
}
|
|
867
1325
|
catch (e) {
|
|
1326
|
+
postFailures.push("cross-flavor resolver");
|
|
868
1327
|
logger.warn("live-ingest: cross-flavor resolver failed", { err: e.message });
|
|
869
1328
|
}
|
|
870
1329
|
}
|
|
@@ -889,12 +1348,14 @@ export async function liveIngest(opts) {
|
|
|
889
1348
|
}
|
|
890
1349
|
}
|
|
891
1350
|
catch (e) {
|
|
1351
|
+
postFailures.push("omnistudio overlap detector");
|
|
892
1352
|
logger.warn("live-ingest: omnistudio overlap detector failed", {
|
|
893
1353
|
err: e.message,
|
|
894
1354
|
});
|
|
895
1355
|
}
|
|
896
1356
|
}
|
|
897
1357
|
if (!opts.disableFlowInvocableResolve) {
|
|
1358
|
+
const tPhase = performance.now();
|
|
898
1359
|
try {
|
|
899
1360
|
const flowResult = resolveFlowApexMethods(graph, resolved.orgId, postCtx);
|
|
900
1361
|
flowMethodsResolved = flowResult.resolved;
|
|
@@ -908,14 +1369,134 @@ export async function liveIngest(opts) {
|
|
|
908
1369
|
}
|
|
909
1370
|
}
|
|
910
1371
|
catch (e) {
|
|
1372
|
+
postFailures.push("flow→apex resolver");
|
|
911
1373
|
logger.warn("live-ingest: flow→apex resolver failed", { err: e.message });
|
|
912
1374
|
}
|
|
1375
|
+
profiler.phase("resolver:flow-apex", performance.now() - tPhase);
|
|
1376
|
+
}
|
|
1377
|
+
if (!opts.disableVlocityApexResolve) {
|
|
1378
|
+
const tPhase = performance.now();
|
|
1379
|
+
try {
|
|
1380
|
+
const { resolveVlocityApex } = await import("../parsers/vlocity/apex-resolver.js");
|
|
1381
|
+
vlocityApexResult = resolveVlocityApex(graph, resolved.orgId, postCtx);
|
|
1382
|
+
if (vlocityApexResult.scanned > 0)
|
|
1383
|
+
logger.info("live-ingest: vlocity→apex resolver", vlocityApexResult);
|
|
1384
|
+
}
|
|
1385
|
+
catch (e) {
|
|
1386
|
+
postFailures.push("vlocity-apex-resolver");
|
|
1387
|
+
logger.warn(`vlocity-apex-resolver:failed:${e.message}`);
|
|
1388
|
+
wedgeWarnings.push(`vlocity-apex-resolver:failed:${e.message}`);
|
|
1389
|
+
}
|
|
1390
|
+
profiler.phase("resolver:vlocity-apex", performance.now() - tPhase);
|
|
1391
|
+
}
|
|
1392
|
+
if (!opts.disableDrRelationshipResolve) {
|
|
1393
|
+
const tPhase = performance.now();
|
|
1394
|
+
try {
|
|
1395
|
+
const { resolveDataRaptorRelationships } = await import("../parsers/vlocity/dr-relationship-resolver.js");
|
|
1396
|
+
drRelationshipsResult = resolveDataRaptorRelationships(graph, resolved.orgId, postCtx);
|
|
1397
|
+
if (drRelationshipsResult.scanned > 0)
|
|
1398
|
+
logger.info("live-ingest: dataraptor relationship-path resolver", drRelationshipsResult);
|
|
1399
|
+
}
|
|
1400
|
+
catch (e) {
|
|
1401
|
+
postFailures.push("dr-relationship-resolver");
|
|
1402
|
+
logger.warn(`dr-relationship-resolver:failed:${e.message}`);
|
|
1403
|
+
wedgeWarnings.push(`dr-relationship-resolver:failed:${e.message}`);
|
|
1404
|
+
}
|
|
1405
|
+
profiler.phase("resolver:dr-relationship", performance.now() - tPhase);
|
|
1406
|
+
}
|
|
1407
|
+
if (!opts.disableFlowRelationshipResolve) {
|
|
1408
|
+
const tPhase = performance.now();
|
|
1409
|
+
try {
|
|
1410
|
+
const { resolveFlowRelationshipPaths } = await import("../parsers/flow/relationship-resolver.js");
|
|
1411
|
+
const fr = resolveFlowRelationshipPaths(graph, resolved.orgId, postCtx);
|
|
1412
|
+
if (fr.scanned > 0)
|
|
1413
|
+
logger.info("live-ingest: flow relationship-path resolver", { ...fr });
|
|
1414
|
+
}
|
|
1415
|
+
catch (e) {
|
|
1416
|
+
postFailures.push("flow-relationship-resolver");
|
|
1417
|
+
logger.warn(`flow-relationship-resolver:failed:${e.message}`);
|
|
1418
|
+
wedgeWarnings.push(`flow-relationship-resolver:failed:${e.message}`);
|
|
1419
|
+
}
|
|
1420
|
+
profiler.phase("resolver:flow-relationship", performance.now() - tPhase);
|
|
1421
|
+
}
|
|
1422
|
+
if (!opts.disableLwcFieldKeyResolve) {
|
|
1423
|
+
const tPhase = performance.now();
|
|
1424
|
+
try {
|
|
1425
|
+
const { resolveLwcFieldKeys } = await import("../parsers/lwc/field-key-resolver.js");
|
|
1426
|
+
const r = resolveLwcFieldKeys(graph, resolved.orgId, postCtx);
|
|
1427
|
+
if (r.scanned > 0)
|
|
1428
|
+
logger.info("live-ingest: lwc field-key resolver", { ...r });
|
|
1429
|
+
}
|
|
1430
|
+
catch (e) {
|
|
1431
|
+
postFailures.push("lwc-field-key-resolver");
|
|
1432
|
+
logger.warn(`lwc-field-key-resolver:failed:${e.message}`);
|
|
1433
|
+
wedgeWarnings.push(`lwc-field-key-resolver:failed:${e.message}`);
|
|
1434
|
+
}
|
|
1435
|
+
profiler.phase("resolver:lwc-field-key", performance.now() - tPhase);
|
|
1436
|
+
}
|
|
1437
|
+
if (!opts.disableVlocityNameMatchResolve) {
|
|
1438
|
+
const tPhase = performance.now();
|
|
1439
|
+
try {
|
|
1440
|
+
const { resolveVlocityNameMatches } = await import("../parsers/vlocity/name-match-resolver.js");
|
|
1441
|
+
const nm = resolveVlocityNameMatches(graph, resolved.orgId, postCtx);
|
|
1442
|
+
if (nm.scanned > 0)
|
|
1443
|
+
logger.info("live-ingest: vlocity name-match resolver", { ...nm });
|
|
1444
|
+
}
|
|
1445
|
+
catch (e) {
|
|
1446
|
+
postFailures.push("vlocity-name-match-resolver");
|
|
1447
|
+
logger.warn(`vlocity-name-match-resolver:failed:${e.message}`);
|
|
1448
|
+
wedgeWarnings.push(`vlocity-name-match-resolver:failed:${e.message}`);
|
|
1449
|
+
}
|
|
1450
|
+
profiler.phase("resolver:vlocity-name-match", performance.now() - tPhase);
|
|
1451
|
+
}
|
|
1452
|
+
if (!opts.disableApexRefResolve) {
|
|
1453
|
+
const tPhase = performance.now();
|
|
1454
|
+
try {
|
|
1455
|
+
const { resolveApexReferences } = await import("../parsers/apex/ref-resolver.js");
|
|
1456
|
+
const { apexRefNoWorkResult } = await import("./resolver-gates.js");
|
|
1457
|
+
// Skip its whole-graph reads when it provably has no input and no
|
|
1458
|
+
// earlier output to prune (same result object it would return).
|
|
1459
|
+
const ar = apexRefNoWorkResult(graph, resolved.orgId) ??
|
|
1460
|
+
resolveApexReferences(graph, resolved.orgId, postCtx);
|
|
1461
|
+
if (ar.edgesEmitted > 0 || ar.pathsUnresolved > 0 || ar.dynamicSoqlFieldsSkipped > 0)
|
|
1462
|
+
logger.info("live-ingest: apex ref resolver", { ...ar });
|
|
1463
|
+
}
|
|
1464
|
+
catch (e) {
|
|
1465
|
+
postFailures.push("apex-ref-resolver");
|
|
1466
|
+
logger.warn(`apex-ref-resolver:failed:${e.message}`);
|
|
1467
|
+
wedgeWarnings.push(`apex-ref-resolver:failed:${e.message}`);
|
|
1468
|
+
}
|
|
1469
|
+
profiler.phase("resolver:apex-ref", performance.now() - tPhase);
|
|
1470
|
+
}
|
|
1471
|
+
// `ApexClass:X` references to an interface X (no class X): move them onto
|
|
1472
|
+
// `ApexInterface:X`. Before arity, which then sees interface method calls
|
|
1473
|
+
// under their real owner.
|
|
1474
|
+
let interfaceRefsRetargeted = 0;
|
|
1475
|
+
if (!opts.disableInterfaceRetarget) {
|
|
1476
|
+
const tPhase = performance.now();
|
|
1477
|
+
try {
|
|
1478
|
+
const names = deltaHooks?.retargetInterfaceNames();
|
|
1479
|
+
interfaceRefsRetargeted = retargetApexInterfaceRefs(graph, resolved.orgId, names ? { interfaceNames: names } : {});
|
|
1480
|
+
if (interfaceRefsRetargeted > 0) {
|
|
1481
|
+
logger.info("live-ingest: apex interface references retargeted", {
|
|
1482
|
+
interfaceRefsRetargeted,
|
|
1483
|
+
});
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
catch (e) {
|
|
1487
|
+
postFailures.push("apex interface retarget");
|
|
1488
|
+
logger.warn("live-ingest: apex interface retarget failed", { err: e.message });
|
|
1489
|
+
}
|
|
1490
|
+
profiler.phase("resolver:interface-retarget", performance.now() - tPhase);
|
|
913
1491
|
}
|
|
914
1492
|
if (!opts.disableArityResolve) {
|
|
1493
|
+
const tPhase = performance.now();
|
|
915
1494
|
try {
|
|
1495
|
+
const scope = deltaHooks?.arityScope();
|
|
916
1496
|
const arityResult = resolveApexMethodArity(graph, {
|
|
917
1497
|
orgId: resolved.orgId,
|
|
918
1498
|
ctx: postCtx,
|
|
1499
|
+
...(scope ? { scope } : {}),
|
|
919
1500
|
});
|
|
920
1501
|
arityResolved = arityResult.resolved;
|
|
921
1502
|
if (arityResult.scanned > 0) {
|
|
@@ -929,18 +1510,39 @@ export async function liveIngest(opts) {
|
|
|
929
1510
|
}
|
|
930
1511
|
}
|
|
931
1512
|
catch (e) {
|
|
1513
|
+
postFailures.push("apex arity resolver");
|
|
932
1514
|
logger.warn("live-ingest: apex arity resolver failed", { err: e.message });
|
|
933
1515
|
}
|
|
1516
|
+
profiler.phase("resolver:arity", performance.now() - tPhase);
|
|
1517
|
+
}
|
|
1518
|
+
// A formula's second-hop field guess moves onto the CustomField that
|
|
1519
|
+
// declares that relationshipName.
|
|
1520
|
+
if (!opts.disableFormulaHopResolve) {
|
|
1521
|
+
const tPhase = performance.now();
|
|
1522
|
+
try {
|
|
1523
|
+
const sources = deltaHooks?.hopSources();
|
|
1524
|
+
const hop = resolveFormulaRelationshipHops(graph, resolved.orgId, sources ? { sources } : {});
|
|
1525
|
+
if (hop.moved > 0)
|
|
1526
|
+
logger.info("live-ingest: formula relationship hops resolved", { ...hop });
|
|
1527
|
+
}
|
|
1528
|
+
catch (e) {
|
|
1529
|
+
postFailures.push("formula hop resolver");
|
|
1530
|
+
logger.warn("live-ingest: formula hop resolver failed", { err: e.message });
|
|
1531
|
+
}
|
|
1532
|
+
profiler.phase("resolver:formula-hop", performance.now() - tPhase);
|
|
934
1533
|
}
|
|
935
1534
|
// Reflection walker: runs BEFORE the dangling-edge audit so any
|
|
936
1535
|
// REFERENCES edges it emits are validated by the audit alongside
|
|
937
1536
|
// parser-emitted edges. Default on; disable via disableReflectionWalker.
|
|
938
1537
|
if (!opts.disableReflectionWalker) {
|
|
1538
|
+
const tPhase = performance.now();
|
|
939
1539
|
try {
|
|
940
1540
|
const { walkBlobsForReferences } = await import("../parsers/generic/reflection-walker.js");
|
|
1541
|
+
const sourceQnames = deltaHooks?.reflectionSources();
|
|
941
1542
|
const reflectionResult = walkBlobsForReferences(graph, {
|
|
942
1543
|
orgId: resolved.orgId,
|
|
943
1544
|
ctx: postCtx,
|
|
1545
|
+
...(sourceQnames ? { sourceQnames } : {}),
|
|
944
1546
|
});
|
|
945
1547
|
reflectionEdges = reflectionResult.edgesEmitted;
|
|
946
1548
|
if (reflectionEdges > 0) {
|
|
@@ -953,12 +1555,16 @@ export async function liveIngest(opts) {
|
|
|
953
1555
|
}
|
|
954
1556
|
}
|
|
955
1557
|
catch (e) {
|
|
1558
|
+
postFailures.push("reflection walker");
|
|
956
1559
|
logger.warn("live-ingest: reflection walker failed", {
|
|
957
1560
|
err: e.message,
|
|
958
1561
|
});
|
|
959
1562
|
}
|
|
1563
|
+
profiler.phase("resolver:reflection", performance.now() - tPhase);
|
|
960
1564
|
}
|
|
961
|
-
|
|
1565
|
+
// The audit only reports (it changes nothing): a delta skips it.
|
|
1566
|
+
if (!opts.disableAudit && !deltaHooks) {
|
|
1567
|
+
const tPhase = performance.now();
|
|
962
1568
|
try {
|
|
963
1569
|
const auditResult = auditDanglingEdges(graph, resolved.orgId, { sampleSize: 25 });
|
|
964
1570
|
danglingEdges = auditResult.danglingCount;
|
|
@@ -974,29 +1580,151 @@ export async function liveIngest(opts) {
|
|
|
974
1580
|
}
|
|
975
1581
|
}
|
|
976
1582
|
catch (e) {
|
|
1583
|
+
postFailures.push("graph audit");
|
|
977
1584
|
logger.warn("live-ingest: graph audit failed", { err: e.message });
|
|
978
1585
|
}
|
|
1586
|
+
profiler.phase("audit", performance.now() - tPhase);
|
|
979
1587
|
}
|
|
980
1588
|
const completedIso = new Date().toISOString();
|
|
1589
|
+
// N4: when incremental skipped changed members it couldn't fetch, do NOT
|
|
1590
|
+
// advance the watermark past them — hold it at the prior value so the next
|
|
1591
|
+
// incremental re-detects (and keeps warning about) those changes instead of
|
|
1592
|
+
// stepping over them forever. generation still increments / in-progress
|
|
1593
|
+
// still clears (markSyncComplete does both regardless of the timestamp).
|
|
1594
|
+
const holdWatermark = incrementalUnfetched > 0 && existing?.lastSyncedAt != null;
|
|
1595
|
+
const watermarkIso = holdWatermark
|
|
1596
|
+
? new Date(existing.lastSyncedAt).toISOString()
|
|
1597
|
+
: completedIso;
|
|
1598
|
+
// N-1: the held queue has not dispatched yet, so its lazy `onWork` flag
|
|
1599
|
+
// may not be set. Make `embeddings_pending` durable BEFORE the sync is
|
|
1600
|
+
// marked complete: a crash between here and the drain must leave the
|
|
1601
|
+
// next ingest knowing vectors are missing (it backfills them).
|
|
1602
|
+
if (embedQueue && !wasEmbeddingsPending && embedQueue.hasVectorWork()) {
|
|
1603
|
+
try {
|
|
1604
|
+
graph.setEmbeddingsPending?.(resolved.orgId, true);
|
|
1605
|
+
}
|
|
1606
|
+
catch (e) {
|
|
1607
|
+
logger.warn("live-ingest: setEmbeddingsPending failed", { err: e.message });
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
const populate = async () => {
|
|
1611
|
+
if (!opts.analysisDb)
|
|
1612
|
+
return;
|
|
1613
|
+
const tDead = performance.now();
|
|
1614
|
+
try {
|
|
1615
|
+
await populateAnalysisTables(graph, resolved.orgId, opts.analysisDb);
|
|
1616
|
+
}
|
|
1617
|
+
catch (e) {
|
|
1618
|
+
postFailures.push("populate analysis tables");
|
|
1619
|
+
logger.warn("live-ingest: populate analysis tables failed", {
|
|
1620
|
+
err: e.message,
|
|
1621
|
+
});
|
|
1622
|
+
}
|
|
1623
|
+
profiler.phase("deadcode", performance.now() - tDead);
|
|
1624
|
+
};
|
|
1625
|
+
// T15 I-2: a delta whose resolver or dead-code pass failed is not a clean
|
|
1626
|
+
// sync. Populate runs before the sync is marked complete, and any failure
|
|
1627
|
+
// throws here: the pending marker and member rows stay as they were, so the
|
|
1628
|
+
// next delta replays the touched members with every resolver at full scope
|
|
1629
|
+
// (the outer catch marks the sync failed; the generation does not move).
|
|
1630
|
+
if (deltaHooks) {
|
|
1631
|
+
await populate();
|
|
1632
|
+
if (postFailures.length > 0) {
|
|
1633
|
+
throw new Error(`delta: post-merge step(s) failed (${postFailures.join(", ")}); not finalized, the next delta re-derives at full scope`);
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
981
1636
|
try {
|
|
982
1637
|
// W1.5-08: markSyncComplete subsumes the old touchSync — it updates
|
|
983
1638
|
// last_synced_at AND increments sync_generation AND clears the
|
|
984
1639
|
// in-progress flag, atomically in one transaction.
|
|
985
|
-
graph.markSyncComplete(resolved.orgId,
|
|
1640
|
+
graph.markSyncComplete(resolved.orgId, watermarkIso);
|
|
986
1641
|
}
|
|
987
1642
|
catch (e) {
|
|
988
1643
|
logger.warn("live-ingest: markSyncComplete failed", { err: e.message });
|
|
989
1644
|
}
|
|
990
|
-
|
|
1645
|
+
opts.onPhase?.("sync-complete");
|
|
1646
|
+
if (!deltaHooks)
|
|
1647
|
+
await populate();
|
|
1648
|
+
// Task 11c: the ingest is complete; record what each member owns.
|
|
1649
|
+
if (deltaHooks)
|
|
1650
|
+
deltaHooks.finalize();
|
|
1651
|
+
else if (memberRows && !streamAborted) {
|
|
991
1652
|
try {
|
|
992
|
-
|
|
1653
|
+
graph.replaceMemberRows?.(resolved.orgId, [...memberRows.values()], memberRowsGeneration());
|
|
993
1654
|
}
|
|
994
1655
|
catch (e) {
|
|
995
|
-
logger.warn("live-ingest:
|
|
996
|
-
err: e.message,
|
|
997
|
-
});
|
|
1656
|
+
logger.warn("live-ingest: member rows write failed", { err: e.message });
|
|
998
1657
|
}
|
|
999
1658
|
}
|
|
1659
|
+
// T15 N5-1: surface members skipped after repeated parse-worker failures.
|
|
1660
|
+
const parseQuarantined = deltaHooks
|
|
1661
|
+
? (deltaHooks.quarantinedCount?.() ?? 0)
|
|
1662
|
+
: memberRows
|
|
1663
|
+
? [...memberRows.values()].filter((r) => isQuarantinedRow(r)).length
|
|
1664
|
+
: 0;
|
|
1665
|
+
if (parseQuarantined > 0) {
|
|
1666
|
+
logger.warn("live-ingest: members skipped after repeated parse-worker failures (until their content changes)", { count: parseQuarantined });
|
|
1667
|
+
}
|
|
1668
|
+
// Graph ready: merges, resolvers and the dead-code cache are done. Only
|
|
1669
|
+
// embeddings may still be in flight.
|
|
1670
|
+
const graphReadyMs = Date.now() - startedAt;
|
|
1671
|
+
console.log(`graph ready in ${(graphReadyMs / 1000).toFixed(1)}s`);
|
|
1672
|
+
profiler.phase("graph-ready", graphReadyMs, true);
|
|
1673
|
+
let embeddings;
|
|
1674
|
+
if (embedQueue) {
|
|
1675
|
+
const q = embedQueue;
|
|
1676
|
+
let pendingLeft = 0;
|
|
1677
|
+
if (opts.waitEmbeddings === false) {
|
|
1678
|
+
// Cache hits are cheap: write them before returning, so a warm no-wait
|
|
1679
|
+
// run still completes its vectors. Only model work is deferred.
|
|
1680
|
+
try {
|
|
1681
|
+
q.flushCached();
|
|
1682
|
+
}
|
|
1683
|
+
catch (e) {
|
|
1684
|
+
// Items may have been dropped mid-flush: keep the flag set.
|
|
1685
|
+
if (!embedError)
|
|
1686
|
+
embedError = e;
|
|
1687
|
+
logger.warn("live-ingest: cached vector flush failed", { err: e.message });
|
|
1688
|
+
}
|
|
1689
|
+
pendingLeft = q.abandon() + q.stats.failed;
|
|
1690
|
+
const err = embedError;
|
|
1691
|
+
if (pendingLeft > 0 || err) {
|
|
1692
|
+
console.log(`embeddings deferred: ${pendingLeft} texts pending (cached vectors written: ${q.stats.cached}); find_similar uses text search until an ingest that waits for embeddings fills them`);
|
|
1693
|
+
}
|
|
1694
|
+
else {
|
|
1695
|
+
graph.setEmbeddingsPending?.(resolved.orgId, false);
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
else {
|
|
1699
|
+
try {
|
|
1700
|
+
// drain() releases the held queue.
|
|
1701
|
+
await q.drain();
|
|
1702
|
+
}
|
|
1703
|
+
catch (e) {
|
|
1704
|
+
if (!embedError)
|
|
1705
|
+
embedError = e;
|
|
1706
|
+
}
|
|
1707
|
+
const doneMs = Date.now() - startedAt;
|
|
1708
|
+
const err = embedError;
|
|
1709
|
+
if (err) {
|
|
1710
|
+
pendingLeft = q.stats.failed;
|
|
1711
|
+
console.error(`embeddings failed: ${err.message} — ${q.stats.failed} texts left unembedded; they will be filled on the next ingest`);
|
|
1712
|
+
}
|
|
1713
|
+
else {
|
|
1714
|
+
graph.setEmbeddingsPending?.(resolved.orgId, false);
|
|
1715
|
+
console.log(`embeddings done in ${(doneMs / 1000).toFixed(1)}s (cached ${q.stats.cached} / computed ${q.stats.computed})`);
|
|
1716
|
+
}
|
|
1717
|
+
profiler.phase("embeddings", doneMs, true);
|
|
1718
|
+
}
|
|
1719
|
+
const err = embedError;
|
|
1720
|
+
embeddings = {
|
|
1721
|
+
...q.stats,
|
|
1722
|
+
pending: pendingLeft,
|
|
1723
|
+
backfilled,
|
|
1724
|
+
doneMs: Date.now() - startedAt,
|
|
1725
|
+
...(err ? { error: err.message } : {}),
|
|
1726
|
+
};
|
|
1727
|
+
}
|
|
1000
1728
|
if (opts.snapshotStore) {
|
|
1001
1729
|
try {
|
|
1002
1730
|
opts.snapshotStore.prune(resolved.orgId, opts.snapshotRetentionDays ?? 30);
|
|
@@ -1015,7 +1743,11 @@ export async function liveIngest(opts) {
|
|
|
1015
1743
|
durationMs: Date.now() - startedAt,
|
|
1016
1744
|
crossFlavorEdges,
|
|
1017
1745
|
arityResolved,
|
|
1746
|
+
parseQuarantined,
|
|
1747
|
+
interfaceRefsRetargeted,
|
|
1018
1748
|
flowMethodsResolved,
|
|
1749
|
+
vlocityApex: vlocityApexResult,
|
|
1750
|
+
drRelationships: drRelationshipsResult,
|
|
1019
1751
|
danglingEdges,
|
|
1020
1752
|
reflectionEdges,
|
|
1021
1753
|
overlap: overlapResult,
|
|
@@ -1026,9 +1758,27 @@ export async function liveIngest(opts) {
|
|
|
1026
1758
|
// with Phase 1's structured-warnings refactor (W1-01).
|
|
1027
1759
|
...wedgeWarnings,
|
|
1028
1760
|
],
|
|
1761
|
+
graphReadyMs,
|
|
1762
|
+
...(streamAborted ? { streamAborted: true } : {}),
|
|
1763
|
+
...(embeddings ? { embeddings } : {}),
|
|
1029
1764
|
};
|
|
1030
1765
|
}
|
|
1031
1766
|
catch (e) {
|
|
1767
|
+
embedQueue?.abandon();
|
|
1768
|
+
// Never leave a bulk window (open transaction, dropped indexes) or a
|
|
1769
|
+
// batch window (open transaction) behind.
|
|
1770
|
+
try {
|
|
1771
|
+
graph.endBatch?.();
|
|
1772
|
+
}
|
|
1773
|
+
catch {
|
|
1774
|
+
/* best-effort */
|
|
1775
|
+
}
|
|
1776
|
+
try {
|
|
1777
|
+
graph.endBulk?.();
|
|
1778
|
+
}
|
|
1779
|
+
catch {
|
|
1780
|
+
/* best-effort */
|
|
1781
|
+
}
|
|
1032
1782
|
// W1.5-08: ingest threw before reaching markSyncComplete. Flip
|
|
1033
1783
|
// sync_in_progress back to 0 (and clear sync_started_at) so concurrent
|
|
1034
1784
|
// MCP readers don't see an orphaned in_progress flag forever. Generation
|
|
@@ -1045,5 +1795,20 @@ export async function liveIngest(opts) {
|
|
|
1045
1795
|
}
|
|
1046
1796
|
throw e;
|
|
1047
1797
|
}
|
|
1798
|
+
finally {
|
|
1799
|
+
profiler.close();
|
|
1800
|
+
try {
|
|
1801
|
+
await ownedEmbedder?.close();
|
|
1802
|
+
}
|
|
1803
|
+
catch {
|
|
1804
|
+
/* best-effort */
|
|
1805
|
+
}
|
|
1806
|
+
try {
|
|
1807
|
+
embedCache?.close();
|
|
1808
|
+
}
|
|
1809
|
+
catch {
|
|
1810
|
+
/* best-effort */
|
|
1811
|
+
}
|
|
1812
|
+
}
|
|
1048
1813
|
}
|
|
1049
1814
|
//# sourceMappingURL=live-ingest.js.map
|