@documentation-robotics/cli 0.1.0 → 0.1.7
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/LICENSE +21 -0
- package/README.md +466 -693
- package/dist/analysis/data-model-analyzer.js +189 -0
- package/dist/analysis/data-model-analyzer.js.map +7 -0
- package/dist/analysis/index.js +3 -0
- package/dist/analysis/index.js.map +7 -0
- package/dist/analysis/relationship-classifier.js +181 -0
- package/dist/analysis/relationship-classifier.js.map +7 -0
- package/dist/analyzers/base-analyzer.js +1 -0
- package/dist/analyzers/base-analyzer.js.map +7 -0
- package/dist/analyzers/call-graph-utils.js +39 -0
- package/dist/analyzers/call-graph-utils.js.map +7 -0
- package/dist/analyzers/cbm-analyzer.js +1205 -0
- package/dist/analyzers/cbm-analyzer.js.map +7 -0
- package/dist/analyzers/heuristic-utils.js +55 -0
- package/dist/analyzers/heuristic-utils.js.map +7 -0
- package/dist/analyzers/mapping-loader.js +146 -0
- package/dist/analyzers/mapping-loader.js.map +7 -0
- package/dist/analyzers/registry.js +124 -0
- package/dist/analyzers/registry.js.map +7 -0
- package/dist/analyzers/session-state.js +176 -0
- package/dist/analyzers/session-state.js.map +7 -0
- package/dist/analyzers/stdio-client.js +208 -0
- package/dist/analyzers/stdio-client.js.map +7 -0
- package/dist/analyzers/types.js +15 -0
- package/dist/analyzers/types.js.map +7 -0
- package/dist/analyzers/verify-engine.js +209 -0
- package/dist/analyzers/verify-engine.js.map +7 -0
- package/dist/analyzers/verify-ignore.js +130 -0
- package/dist/analyzers/verify-ignore.js.map +7 -0
- package/dist/analyzers/version.js +8 -0
- package/dist/analyzers/version.js.map +7 -0
- package/dist/audit/ai/runner.js +41 -0
- package/dist/audit/ai/runner.js.map +7 -0
- package/dist/audit/differential-analyzer.js +183 -0
- package/dist/audit/differential-analyzer.js.map +7 -0
- package/dist/audit/index.js +32 -0
- package/dist/audit/index.js.map +7 -0
- package/dist/audit/nodes/ai/evaluator.js +49 -0
- package/dist/audit/nodes/ai/evaluator.js.map +7 -0
- package/dist/audit/nodes/ai/parser.js +55 -0
- package/dist/audit/nodes/ai/parser.js.map +7 -0
- package/dist/audit/nodes/ai/prompts.js +103 -0
- package/dist/audit/nodes/ai/prompts.js.map +7 -0
- package/dist/audit/nodes/analysis/node-completeness-checker.js +32 -0
- package/dist/audit/nodes/analysis/node-completeness-checker.js.map +7 -0
- package/dist/audit/nodes/analysis/node-definition-analyzer.js +47 -0
- package/dist/audit/nodes/analysis/node-definition-analyzer.js.map +7 -0
- package/dist/audit/nodes/analysis/node-overlap-detector.js +79 -0
- package/dist/audit/nodes/analysis/node-overlap-detector.js.map +7 -0
- package/dist/audit/nodes/model/orchestrator.js +82 -0
- package/dist/audit/nodes/model/orchestrator.js.map +7 -0
- package/dist/audit/nodes/spec/loader.js +116 -0
- package/dist/audit/nodes/spec/loader.js.map +7 -0
- package/dist/audit/nodes/spec/orchestrator.js +68 -0
- package/dist/audit/nodes/spec/orchestrator.js.map +7 -0
- package/dist/audit/nodes/types.js +1 -0
- package/dist/audit/nodes/types.js.map +7 -0
- package/dist/audit/pipeline/index.js +5 -0
- package/dist/audit/pipeline/index.js.map +7 -0
- package/dist/audit/pipeline/pipeline-orchestrator.js +218 -0
- package/dist/audit/pipeline/pipeline-orchestrator.js.map +7 -0
- package/dist/audit/relationships/ai/evaluator.js +235 -0
- package/dist/audit/relationships/ai/evaluator.js.map +7 -0
- package/dist/audit/relationships/ai/parser.js +197 -0
- package/dist/audit/relationships/ai/parser.js.map +7 -0
- package/dist/audit/relationships/ai/prompts.js +274 -0
- package/dist/audit/relationships/ai/prompts.js.map +7 -0
- package/dist/audit/relationships/analysis/balance-assessor.js +115 -0
- package/dist/audit/relationships/analysis/balance-assessor.js.map +7 -0
- package/dist/audit/relationships/analysis/coverage-analyzer.js +99 -0
- package/dist/audit/relationships/analysis/coverage-analyzer.js.map +7 -0
- package/dist/audit/relationships/analysis/duplicate-detector.js +95 -0
- package/dist/audit/relationships/analysis/duplicate-detector.js.map +7 -0
- package/dist/audit/relationships/analysis/gap-analyzer.js +99 -0
- package/dist/audit/relationships/analysis/gap-analyzer.js.map +7 -0
- package/dist/audit/relationships/analysis/layer-templates.js +294 -0
- package/dist/audit/relationships/analysis/layer-templates.js.map +7 -0
- package/dist/audit/relationships/graph/connectivity.js +129 -0
- package/dist/audit/relationships/graph/connectivity.js.map +7 -0
- package/dist/audit/relationships/graph/relationship-graph.js +179 -0
- package/dist/audit/relationships/graph/relationship-graph.js.map +7 -0
- package/dist/audit/relationships/model/balance-assessor.js +49 -0
- package/dist/audit/relationships/model/balance-assessor.js.map +7 -0
- package/dist/audit/relationships/model/coverage-analyzer.js +34 -0
- package/dist/audit/relationships/model/coverage-analyzer.js.map +7 -0
- package/dist/audit/relationships/model/duplicate-detector.js +68 -0
- package/dist/audit/relationships/model/duplicate-detector.js.map +7 -0
- package/dist/audit/relationships/model/gap-analyzer.js +41 -0
- package/dist/audit/relationships/model/gap-analyzer.js.map +7 -0
- package/dist/audit/relationships/model/orchestrator.js +126 -0
- package/dist/audit/relationships/model/orchestrator.js.map +7 -0
- package/dist/audit/relationships/spec/orchestrator.js +157 -0
- package/dist/audit/relationships/spec/orchestrator.js.map +7 -0
- package/dist/audit/reports/index.js +5 -0
- package/dist/audit/reports/index.js.map +7 -0
- package/dist/audit/reports/report-generator.js +118 -0
- package/dist/audit/reports/report-generator.js.map +7 -0
- package/dist/audit/snapshot-storage.js +163 -0
- package/dist/audit/snapshot-storage.js.map +7 -0
- package/dist/audit/types.js +21 -0
- package/dist/audit/types.js.map +7 -0
- package/dist/cli.js +223 -92
- package/dist/cli.js.map +3 -3
- package/dist/coding-agents/agents/claude-code.js +147 -0
- package/dist/coding-agents/agents/claude-code.js.map +7 -0
- package/dist/coding-agents/agents/index.js +5 -0
- package/dist/coding-agents/agents/index.js.map +7 -0
- package/dist/coding-agents/agents/types.js +1 -0
- package/dist/coding-agents/agents/types.js.map +7 -0
- package/dist/coding-agents/base-chat-client.js +45 -0
- package/dist/coding-agents/base-chat-client.js.map +7 -0
- package/dist/coding-agents/chat-utils.js +23 -0
- package/dist/coding-agents/chat-utils.js.map +7 -0
- package/dist/coding-agents/claude-code-client.js +246 -0
- package/dist/coding-agents/claude-code-client.js.map +7 -0
- package/dist/coding-agents/copilot-client.js +209 -0
- package/dist/coding-agents/copilot-client.js.map +7 -0
- package/dist/commands/add.js +95 -33
- package/dist/commands/add.js.map +2 -2
- package/dist/commands/analyzer.js +511 -0
- package/dist/commands/analyzer.js.map +7 -0
- package/dist/commands/audit-diff.js +49 -0
- package/dist/commands/audit-diff.js.map +7 -0
- package/dist/commands/audit-snapshots.js +62 -0
- package/dist/commands/audit-snapshots.js.map +7 -0
- package/dist/commands/audit.js +81 -0
- package/dist/commands/audit.js.map +7 -0
- package/dist/commands/catalog.js +248 -0
- package/dist/commands/catalog.js.map +7 -0
- package/dist/commands/changeset.js +577 -66
- package/dist/commands/changeset.js.map +2 -2
- package/dist/commands/chat.js +106 -83
- package/dist/commands/chat.js.map +2 -2
- package/dist/commands/claude.js +74 -0
- package/dist/commands/claude.js.map +7 -0
- package/dist/commands/conformance.js +71 -68
- package/dist/commands/conformance.js.map +2 -2
- package/dist/commands/copilot.js +75 -0
- package/dist/commands/copilot.js.map +7 -0
- package/dist/commands/delete.js +125 -11
- package/dist/commands/delete.js.map +3 -3
- package/dist/commands/discover-logic.js +44 -0
- package/dist/commands/discover-logic.js.map +7 -0
- package/dist/commands/docs.js +87 -0
- package/dist/commands/docs.js.map +7 -0
- package/dist/commands/element.js +14 -20
- package/dist/commands/element.js.map +2 -2
- package/dist/commands/export.js +13 -3
- package/dist/commands/export.js.map +2 -2
- package/dist/commands/import.js +51 -0
- package/dist/commands/import.js.map +7 -0
- package/dist/commands/info.js +30 -24
- package/dist/commands/info.js.map +2 -2
- package/dist/commands/init.js +27 -11
- package/dist/commands/init.js.map +2 -2
- package/dist/commands/list.js +63 -13
- package/dist/commands/list.js.map +3 -3
- package/dist/commands/relationship.js +225 -37
- package/dist/commands/relationship.js.map +2 -2
- package/dist/commands/report.js +54 -0
- package/dist/commands/report.js.map +7 -0
- package/dist/commands/reports.js +45 -0
- package/dist/commands/reports.js.map +7 -0
- package/dist/commands/schema.js +135 -0
- package/dist/commands/schema.js.map +7 -0
- package/dist/commands/search.js +40 -12
- package/dist/commands/search.js.map +2 -2
- package/dist/commands/show.js +58 -27
- package/dist/commands/show.js.map +2 -2
- package/dist/commands/stats.js +35 -0
- package/dist/commands/stats.js.map +7 -0
- package/dist/commands/trace.js +39 -16
- package/dist/commands/trace.js.map +2 -2
- package/dist/commands/update.js +141 -14
- package/dist/commands/update.js.map +2 -2
- package/dist/commands/upgrade.js +210 -46
- package/dist/commands/upgrade.js.map +3 -3
- package/dist/commands/validate.js +142 -23
- package/dist/commands/validate.js.map +3 -3
- package/dist/commands/version.js +8 -12
- package/dist/commands/version.js.map +2 -2
- package/dist/commands/visualize.js +162 -25
- package/dist/commands/visualize.js.map +2 -2
- package/dist/core/base-snapshot-manager.js +84 -0
- package/dist/core/base-snapshot-manager.js.map +7 -0
- package/dist/core/changeset-exporter.js +305 -0
- package/dist/core/changeset-exporter.js.map +7 -0
- package/dist/core/changeset-validator.js +41 -0
- package/dist/core/changeset-validator.js.map +7 -0
- package/dist/core/changeset.js +88 -173
- package/dist/core/changeset.js.map +2 -2
- package/dist/core/dependency-tracker.js +4 -2
- package/dist/core/dependency-tracker.js.map +2 -2
- package/dist/core/element.js +98 -27
- package/dist/core/element.js.map +2 -2
- package/dist/core/golden-copy-cache.js +290 -0
- package/dist/core/golden-copy-cache.js.map +7 -0
- package/dist/core/graph-model.js +266 -0
- package/dist/core/graph-model.js.map +7 -0
- package/dist/core/layer.js +159 -16
- package/dist/core/layer.js.map +2 -2
- package/dist/core/layers.js +32 -0
- package/dist/core/layers.js.map +7 -0
- package/dist/core/manifest.js +32 -11
- package/dist/core/manifest.js.map +2 -2
- package/dist/core/migration-registry.js +56 -1
- package/dist/core/migration-registry.js.map +2 -2
- package/dist/core/model.js +424 -217
- package/dist/core/model.js.map +3 -3
- package/dist/core/mutation-handler.js +179 -0
- package/dist/core/mutation-handler.js.map +7 -0
- package/dist/core/reference-registry.js +29 -21
- package/dist/core/reference-registry.js.map +2 -2
- package/dist/core/relationship-catalog.js +189 -0
- package/dist/core/relationship-catalog.js.map +7 -0
- package/dist/core/relationship-registry.js.map +2 -2
- package/dist/core/relationships.js.map +1 -1
- package/dist/core/report-data-model.js +285 -0
- package/dist/core/report-data-model.js.map +7 -0
- package/dist/core/spec-data-service.js +185 -0
- package/dist/core/spec-data-service.js.map +7 -0
- package/dist/core/spec-loader-types.js +1 -0
- package/dist/core/spec-loader-types.js.map +7 -0
- package/dist/core/spec-loader.js +234 -0
- package/dist/core/spec-loader.js.map +7 -0
- package/dist/core/staged-changeset-storage.js +282 -0
- package/dist/core/staged-changeset-storage.js.map +7 -0
- package/dist/core/staging-area.js +1002 -0
- package/dist/core/staging-area.js.map +7 -0
- package/dist/core/stats-collector.js +169 -0
- package/dist/core/stats-collector.js.map +7 -0
- package/dist/core/virtual-projection.js +443 -0
- package/dist/core/virtual-projection.js.map +7 -0
- package/dist/export/archimate-exporter.js +99 -60
- package/dist/export/archimate-exporter.js.map +2 -2
- package/dist/export/audit-formatters.js +479 -0
- package/dist/export/audit-formatters.js.map +7 -0
- package/dist/export/diff-formatters.js +99 -0
- package/dist/export/diff-formatters.js.map +7 -0
- package/dist/export/export-manager.js.map +2 -2
- package/dist/export/graphml-exporter.js +44 -27
- package/dist/export/graphml-exporter.js.map +2 -2
- package/dist/export/index.js +4 -0
- package/dist/export/index.js.map +2 -2
- package/dist/export/json-schema-exporter.js +55 -42
- package/dist/export/json-schema-exporter.js.map +2 -2
- package/dist/export/markdown-exporter.js +92 -70
- package/dist/export/markdown-exporter.js.map +2 -2
- package/dist/export/markdown-generator.js +248 -0
- package/dist/export/markdown-generator.js.map +7 -0
- package/dist/export/markdown-utils.js +30 -0
- package/dist/export/markdown-utils.js.map +7 -0
- package/dist/export/mermaid-markdown-exporter.js +37 -0
- package/dist/export/mermaid-markdown-exporter.js.map +7 -0
- package/dist/export/openapi-exporter.js +119 -71
- package/dist/export/openapi-exporter.js.map +2 -2
- package/dist/export/plantuml-exporter.js +104 -39
- package/dist/export/plantuml-exporter.js.map +2 -2
- package/dist/export/report-formatters.js +111 -0
- package/dist/export/report-formatters.js.map +7 -0
- package/dist/export/stats-formatters.js +98 -0
- package/dist/export/stats-formatters.js.map +7 -0
- package/dist/export/types.js +2 -14
- package/dist/export/types.js.map +2 -2
- package/dist/export/verify-formatters.js +153 -0
- package/dist/export/verify-formatters.js.map +7 -0
- package/dist/generated/compiled-validators.js +17 -0
- package/dist/generated/compiled-validators.js.map +7 -0
- package/dist/generated/index.js +31 -0
- package/dist/generated/index.js.map +7 -0
- package/dist/generated/layer-registry.js +190 -0
- package/dist/generated/layer-registry.js.map +7 -0
- package/dist/generated/layer-types.js +7 -0
- package/dist/generated/layer-types.js.map +7 -0
- package/dist/generated/node-types.js +1719 -0
- package/dist/generated/node-types.js.map +7 -0
- package/dist/generated/relationship-index.js +14552 -0
- package/dist/generated/relationship-index.js.map +7 -0
- package/dist/import/archimate-importer.js +166 -0
- package/dist/import/archimate-importer.js.map +7 -0
- package/dist/import/index.js +47 -0
- package/dist/import/index.js.map +7 -0
- package/dist/import/openapi-importer.js +143 -0
- package/dist/import/openapi-importer.js.map +7 -0
- package/dist/import/types.js +1 -0
- package/dist/import/types.js.map +7 -0
- package/dist/integrations/base-manager.js +311 -0
- package/dist/integrations/base-manager.js.map +7 -0
- package/dist/integrations/claude-manager.js +360 -0
- package/dist/integrations/claude-manager.js.map +7 -0
- package/dist/integrations/claude_code/agents/dr-advisor.md +253 -0
- package/dist/integrations/claude_code/agents/dr-architect.md +278 -0
- package/dist/integrations/claude_code/agents/dr-extractor.md +286 -0
- package/dist/integrations/claude_code/commands/dr-changeset.md +657 -0
- package/dist/integrations/claude_code/commands/dr-design.md +373 -0
- package/dist/integrations/claude_code/commands/dr-info.md +132 -0
- package/dist/integrations/claude_code/commands/dr-init.md +251 -0
- package/dist/integrations/claude_code/commands/dr-map.md +936 -0
- package/dist/integrations/claude_code/commands/dr-model.md +493 -0
- package/dist/integrations/claude_code/commands/dr-relate.md +814 -0
- package/dist/integrations/claude_code/commands/dr-sync.md +279 -0
- package/dist/integrations/claude_code/commands/dr-validate.md +654 -0
- package/dist/integrations/claude_code/commands/dr-verify.md +559 -0
- package/dist/integrations/claude_code/docs/END_TO_END_WALKTHROUGH.md +903 -0
- package/dist/integrations/claude_code/docs/QUICK_START.md +271 -0
- package/dist/integrations/claude_code/docs/README.md +347 -0
- package/dist/integrations/claude_code/skills/dr_01_motivation_layer/SKILL.md +550 -0
- package/dist/integrations/claude_code/skills/dr_02_business_layer/SKILL.md +620 -0
- package/dist/integrations/claude_code/skills/dr_03_security_layer/SKILL.md +642 -0
- package/dist/integrations/claude_code/skills/dr_04_application_layer/SKILL.md +911 -0
- package/dist/integrations/claude_code/skills/dr_05_technology_layer/SKILL.md +836 -0
- package/dist/integrations/claude_code/skills/dr_06_api_layer/SKILL.md +933 -0
- package/dist/integrations/claude_code/skills/dr_07_data_model_layer/SKILL.md +210 -0
- package/dist/integrations/claude_code/skills/dr_08_dataset_layer/SKILL.md +319 -0
- package/dist/integrations/claude_code/skills/dr_09_ux_layer/SKILL.md +319 -0
- package/dist/integrations/claude_code/skills/dr_10_navigation_layer/SKILL.md +318 -0
- package/dist/integrations/claude_code/skills/dr_11_apm_layer/SKILL.md +273 -0
- package/dist/integrations/claude_code/skills/dr_12_testing_layer/SKILL.md +273 -0
- package/dist/integrations/claude_code/skills/dr_changeset_reviewer/SKILL.md +187 -0
- package/dist/integrations/claude_code/skills/dr_codebase_memory/SKILL.md +590 -0
- package/dist/integrations/claude_code/skills/dr_engineering_guide/SKILL.md +295 -0
- package/dist/integrations/copilot-manager.js +328 -0
- package/dist/integrations/copilot-manager.js.map +7 -0
- package/dist/integrations/github_copilot/agents/dr-advisor.md +243 -0
- package/dist/integrations/github_copilot/agents/dr-architect.md +1567 -0
- package/dist/integrations/github_copilot/skills/dr_01_motivation_layer/SKILL.md +491 -0
- package/dist/integrations/github_copilot/skills/dr_02_business_layer/SKILL.md +539 -0
- package/dist/integrations/github_copilot/skills/dr_03_security_layer/SKILL.md +667 -0
- package/dist/integrations/github_copilot/skills/dr_04_application_layer/SKILL.md +670 -0
- package/dist/integrations/github_copilot/skills/dr_05_technology_layer/SKILL.md +660 -0
- package/dist/integrations/github_copilot/skills/dr_06_api_layer/SKILL.md +855 -0
- package/dist/integrations/github_copilot/skills/dr_07_data_model_layer/SKILL.md +171 -0
- package/dist/integrations/github_copilot/skills/dr_08_dataset_layer/SKILL.md +216 -0
- package/dist/integrations/github_copilot/skills/dr_09_ux_layer/SKILL.md +230 -0
- package/dist/integrations/github_copilot/skills/dr_10_navigation_layer/SKILL.md +228 -0
- package/dist/integrations/github_copilot/skills/dr_11_apm_layer/SKILL.md +234 -0
- package/dist/integrations/github_copilot/skills/dr_12_testing_layer/SKILL.md +230 -0
- package/dist/integrations/github_copilot/skills/dr_changeset_reviewer/SKILL.md +187 -0
- package/dist/integrations/hash-utils.js +51 -0
- package/dist/integrations/hash-utils.js.map +7 -0
- package/dist/integrations/types.js +16 -0
- package/dist/integrations/types.js.map +7 -0
- package/dist/reports/model-layer-report-generator.js +278 -0
- package/dist/reports/model-layer-report-generator.js.map +7 -0
- package/dist/reports/model-report-data.js +57 -0
- package/dist/reports/model-report-data.js.map +7 -0
- package/dist/reports/model-report-orchestrator.js +103 -0
- package/dist/reports/model-report-orchestrator.js.map +7 -0
- package/dist/schemas/bundled/analyzers/cbm.json +595 -0
- package/dist/schemas/bundled/analyzers/manifest.json +9 -0
- package/dist/schemas/bundled/api.json +3411 -0
- package/dist/schemas/bundled/apm.json +2371 -0
- package/dist/schemas/bundled/application.json +1253 -0
- package/dist/schemas/bundled/base.json +1622 -0
- package/dist/schemas/bundled/business.json +1279 -0
- package/dist/schemas/bundled/data-model.json +1298 -0
- package/dist/schemas/bundled/data-store.json +2025 -0
- package/dist/schemas/bundled/manifest.json +93 -0
- package/dist/schemas/bundled/motivation.json +1360 -0
- package/dist/schemas/bundled/navigation.json +1874 -0
- package/dist/schemas/bundled/security.json +3488 -0
- package/dist/schemas/bundled/technology.json +2067 -0
- package/dist/schemas/bundled/testing.json +3120 -0
- package/dist/schemas/bundled/ux.json +3592 -0
- package/dist/server/schemas.js +202 -0
- package/dist/server/schemas.js.map +7 -0
- package/dist/server/server.js +1336 -252
- package/dist/server/server.js.map +3 -3
- package/dist/server/telemetry-middleware.js +22 -15
- package/dist/server/telemetry-middleware.js.map +2 -2
- package/dist/server-entry.js +65 -0
- package/dist/server-entry.js.map +7 -0
- package/dist/telemetry/config.js +89 -0
- package/dist/telemetry/config.js.map +7 -0
- package/dist/telemetry/console-interceptor.js.map +1 -1
- package/dist/telemetry/detect.js +24 -0
- package/dist/telemetry/detect.js.map +7 -0
- package/dist/telemetry/fetch-otlp-exporter.js +112 -0
- package/dist/telemetry/fetch-otlp-exporter.js.map +7 -0
- package/dist/telemetry/index.js +153 -3
- package/dist/telemetry/index.js.map +2 -2
- package/dist/telemetry/resilient-exporter.js +22 -8
- package/dist/telemetry/resilient-exporter.js.map +2 -2
- package/dist/telemetry/resilient-log-exporter.js +17 -8
- package/dist/telemetry/resilient-log-exporter.js.map +2 -2
- package/dist/telemetry/test-instrumentation.js.map +2 -2
- package/dist/types/index.js +84 -0
- package/dist/types/index.js.map +3 -3
- package/dist/types/source-reference.js +1 -0
- package/dist/types/source-reference.js.map +7 -0
- package/dist/utils/chat-logger.js +292 -0
- package/dist/utils/chat-logger.js.map +7 -0
- package/dist/utils/claude-stream.js +8 -0
- package/dist/utils/claude-stream.js.map +7 -0
- package/dist/utils/date-utils.js +7 -0
- package/dist/utils/date-utils.js.map +7 -0
- package/dist/utils/element-utils.js.map +1 -1
- package/dist/utils/errors.js +88 -15
- package/dist/utils/errors.js.map +3 -3
- package/dist/utils/export-python-annotations.js +82 -0
- package/dist/utils/export-python-annotations.js.map +7 -0
- package/dist/utils/file-io.js +7 -2
- package/dist/utils/file-io.js.map +2 -2
- package/dist/utils/file-lock.js +156 -0
- package/dist/utils/file-lock.js.map +7 -0
- package/dist/utils/id-generator.js +18 -0
- package/dist/utils/id-generator.js.map +7 -0
- package/dist/utils/layer-name-formatter.js +16 -0
- package/dist/utils/layer-name-formatter.js.map +7 -0
- package/dist/utils/markdown-anchor.js +7 -0
- package/dist/utils/markdown-anchor.js.map +7 -0
- package/dist/utils/markdown-link.js +12 -0
- package/dist/utils/markdown-link.js.map +7 -0
- package/dist/utils/markdown-table.js +17 -0
- package/dist/utils/markdown-table.js.map +7 -0
- package/dist/utils/mermaid-utils.js +11 -0
- package/dist/utils/mermaid-utils.js.map +7 -0
- package/dist/utils/project-paths.js.map +2 -2
- package/dist/utils/source-reference.js +52 -0
- package/dist/utils/source-reference.js.map +7 -0
- package/dist/utils/spec-installer.js +40 -53
- package/dist/utils/spec-installer.js.map +2 -2
- package/dist/utils/spec-version.js +5 -1
- package/dist/utils/spec-version.js.map +2 -2
- package/dist/utils/string-utils.js +12 -0
- package/dist/utils/string-utils.js.map +7 -0
- package/dist/utils/table-formatting.js +19 -0
- package/dist/utils/table-formatting.js.map +7 -0
- package/dist/validators/index.js +4 -0
- package/dist/validators/index.js.map +2 -2
- package/dist/validators/naming-validator.js +20 -23
- package/dist/validators/naming-validator.js.map +2 -2
- package/dist/validators/reference-validator.js +23 -38
- package/dist/validators/reference-validator.js.map +2 -2
- package/dist/validators/relationship-schema-validator.js +243 -0
- package/dist/validators/relationship-schema-validator.js.map +7 -0
- package/dist/validators/schema-validator.js +168 -68
- package/dist/validators/schema-validator.js.map +2 -2
- package/dist/validators/semantic-validator.js +36 -60
- package/dist/validators/semantic-validator.js.map +2 -2
- package/dist/validators/types.js.map +2 -2
- package/dist/validators/validation-formatter.js +159 -0
- package/dist/validators/validation-formatter.js.map +7 -0
- package/dist/validators/validator.js +24 -38
- package/dist/validators/validator.js.map +2 -2
- package/dist/viewer/README.md +139 -0
- package/dist/viewer/assets/main-CY0Xufuj.css +1 -0
- package/dist/viewer/assets/main-DtgErnwF.js +81 -0
- package/dist/viewer/assets/vendor-CxKvDp2x.js +17 -0
- package/dist/viewer/favicon.svg +11 -0
- package/dist/viewer/fonts/inter/Inter-Black.woff2 +0 -0
- package/dist/viewer/fonts/inter/Inter-Bold.woff2 +0 -0
- package/dist/viewer/fonts/inter/Inter-ExtraBold.woff2 +0 -0
- package/dist/viewer/fonts/inter/Inter-Light.woff2 +0 -0
- package/dist/viewer/fonts/inter/Inter-Medium.woff2 +0 -0
- package/dist/viewer/fonts/inter/Inter-Regular.woff2 +0 -0
- package/dist/viewer/fonts/inter/Inter-SemiBold.woff2 +0 -0
- package/dist/viewer/fonts/jetbrains-mono/JetBrainsMono-Medium.woff2 +0 -0
- package/dist/viewer/fonts/jetbrains-mono/JetBrainsMono-Regular.woff2 +0 -0
- package/dist/viewer/fonts/jetbrains-mono/JetBrainsMono-SemiBold.woff2 +0 -0
- package/dist/viewer/index.html +15 -0
- package/dist/viewer/manifest.json +99 -0
- package/dist/viewer/version.json +1 -0
- package/package.json +42 -16
- package/PYTHON_CLI_PARITY.md +0 -265
- package/PYTHON_CLI_STRUCTURE_UPDATE.md +0 -246
- package/biome.json +0 -42
- package/bunfig.toml +0 -3
- package/dist/ai/claude-client.js +0 -71
- package/dist/ai/claude-client.js.map +0 -7
- package/dist/ai/context-provider.js +0 -129
- package/dist/ai/context-provider.js.map +0 -7
- package/dist/ai/tools.js +0 -231
- package/dist/ai/tools.js.map +0 -7
- package/dist/commands/migrate.js +0 -36
- package/dist/commands/migrate.js.map +0 -7
- package/dist/commands/project.js +0 -74
- package/dist/commands/project.js.map +0 -7
- package/dist/core/active-changeset.js +0 -52
- package/dist/core/active-changeset.js.map +0 -7
- package/dist/core/projection-engine.js +0 -288
- package/dist/core/projection-engine.js.map +0 -7
- package/dist/schemas/bundled/01-motivation-layer.schema.json +0 -942
- package/dist/schemas/bundled/02-business-layer.schema.json +0 -1293
- package/dist/schemas/bundled/03-security-layer.schema.json +0 -2177
- package/dist/schemas/bundled/04-application-layer.schema.json +0 -1328
- package/dist/schemas/bundled/05-technology-layer.schema.json +0 -1465
- package/dist/schemas/bundled/06-api-layer.schema.json +0 -1743
- package/dist/schemas/bundled/07-data-model-layer.schema.json +0 -1253
- package/dist/schemas/bundled/08-datastore-layer.schema.json +0 -892
- package/dist/schemas/bundled/09-ux-layer.schema.json +0 -1506
- package/dist/schemas/bundled/10-navigation-layer.schema.json +0 -843
- package/dist/schemas/bundled/11-apm-observability-layer.schema.json +0 -1430
- package/dist/schemas/bundled/12-testing-layer.schema.json +0 -1091
- package/dist/schemas/bundled/common/layer-extensions.schema.json +0 -266
- package/dist/schemas/bundled/common/predicates.schema.json +0 -493
- package/dist/schemas/bundled/common/relationships.schema.json +0 -791
- package/dist/schemas/bundled/common/source-references.schema.json +0 -71
- package/dist/schemas/bundled/link-registry.json +0 -1839
- package/dist/schemas/bundled/link-registry.schema.json +0 -339
- package/dist/schemas/bundled/relationship-catalog.json +0 -1302
- package/dist/schemas/bundled/relationship-type.schema.json +0 -221
- package/dist/utils/model-path.js +0 -22
- package/dist/utils/model-path.js.map +0 -7
- package/docs/TEST-INSTRUMENTATION.md +0 -405
- package/docs/telemetry.md +0 -427
- package/test-debug.js +0 -33
- package/test-special.mjs +0 -46
- package/test_runner.ts +0 -7
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/server/telemetry-middleware.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * OpenTelemetry middleware for Hono server\n * Instruments HTTP requests with spans and semantic attributes\n */\n\nimport type { Context, Next } from
|
|
5
|
-
"mappings": "AASA,MAAM,qBAAgE;AActE,eAAsB,oBAAoB,GAAY,MAAU;
|
|
4
|
+
"sourcesContent": ["/**\n * OpenTelemetry middleware for Hono server\n * Instruments HTTP requests with spans and semantic attributes\n */\n\nimport type { Context, Next } from \"hono\";\n\n// Conditional imports based on telemetry flag\ndeclare const TELEMETRY_ENABLED: boolean | undefined;\nconst isTelemetryEnabled = typeof TELEMETRY_ENABLED !== \"undefined\" ? TELEMETRY_ENABLED : false;\n\n/**\n * Hono middleware that creates a span for each HTTP request\n * Captures HTTP semantic attributes according to OpenTelemetry conventions:\n * - http.method: HTTP request method\n * - http.route: HTTP route pattern\n * - http.status_code: HTTP response status code\n * - http.url: Full request URL\n * - http.user_agent: User agent string\n *\n * Also emits logs at request start and completion per SigNoz integration guide\n * for request lifecycle tracking.\n */\nexport async function telemetryMiddleware(c: Context, next: Next): Promise<void> {\n const method = c.req.method;\n const path = c.req.path;\n const url = c.req.url;\n const isDebug = process.env.DEBUG || process.env.VERBOSE;\n\n // Log ALL incoming requests for debugging\n if (isDebug) {\n console.log(`[HTTP] ${method} ${path} (full URL: ${url})`);\n }\n\n if (!isTelemetryEnabled) {\n if (isDebug) {\n console.log(`[Telemetry] Skipping span creation - TELEMETRY_ENABLED is false`);\n }\n return next();\n }\n\n // Dynamic import for tree-shaking\n const { startActiveSpan } = await import(\"../telemetry/index.js\");\n\n const route = c.req.routePath || path; // Use route pattern if available\n\n if (isDebug) {\n console.log(`[Telemetry] Creating active span for http.server.request`);\n }\n\n // Use startActiveSpan for proper context propagation and automatic span management\n return await startActiveSpan(\n \"http.server.request\",\n async (span) => {\n const requestStartTime = Date.now();\n\n // Set initial attributes\n span.setAttributes({\n \"http.method\": method,\n \"http.route\": route,\n \"http.url\": url,\n \"http.target\": path,\n \"http.user_agent\": c.req.header(\"user-agent\") || \"\",\n \"http.scheme\": new URL(url).protocol.replace(\":\", \"\"),\n });\n\n if (isDebug) {\n console.log(`[Telemetry] Active span created successfully`);\n }\n\n try {\n // Process the request\n await next();\n\n // Add response attributes after request is processed\n const statusCode = c.res.status;\n const durationMs = Date.now() - requestStartTime;\n\n span.setAttribute(\"http.status_code\", statusCode);\n span.setAttribute(\"http.duration_ms\", durationMs);\n\n // Set span status based on HTTP status code\n if (statusCode >= 500) {\n span.setStatus({ code: 2, message: \"Server Error\" }); // ERROR\n } else if (statusCode >= 400) {\n span.setStatus({ code: 2, message: \"Client Error\" }); // ERROR\n } else {\n span.setStatus({ code: 1 }); // OK\n }\n } catch (error) {\n // Record exception in span\n span.recordException(error as Error);\n span.setStatus({ code: 2, message: (error as Error).message }); // ERROR\n throw error;\n }\n // Span is automatically ended when this async function completes\n },\n {\n \"http.method\": method,\n \"http.route\": route,\n }\n );\n}\n"],
|
|
5
|
+
"mappings": "AASA,MAAM,qBAAgE;AActE,eAAsB,oBAAoB,GAAY,MAAU;AAC9D,QAAM,SAAS,EAAE,IAAI,QACf,OAAO,EAAE,IAAI,MACb,MAAM,EAAE,IAAI,KACZ,UAAU,QAAQ,IAAI,SAAS,QAAQ,IAAI;AAGjD,SAAI,WACF,QAAQ,IAAI,UAAU,MAAM,IAAI,IAAI,eAAe,GAAG,GAAG,GAIrD,WACF,QAAQ,IAAI,iEAAiE,GAExE,KAAI;AAIb,QAAM,EAAE,gBAAe,IAAK,MAAM,OAAO,uBAAuB,GAE1D,QAAQ,EAAE,IAAI,aAAa;AAEjC,SAAI,WACF,QAAQ,IAAI,0DAA0D,GAIjE,MAAM,gBACX,uBACA,OAAO,SAAQ;AACb,UAAM,mBAAmB,KAAK,IAAG;AAGjC,SAAK,cAAc;MACjB,eAAe;MACf,cAAc;MACd,YAAY;MACZ,eAAe;MACf,mBAAmB,EAAE,IAAI,OAAO,YAAY,KAAK;MACjD,eAAe,IAAI,IAAI,GAAG,EAAE,SAAS,QAAQ,KAAK,EAAE;KACrD,GAEG,WACF,QAAQ,IAAI,8CAA8C;AAG5D,QAAI;AAEF,YAAM,KAAI;AAGV,YAAM,aAAa,EAAE,IAAI,QACnB,aAAa,KAAK,IAAG,IAAK;AAEhC,WAAK,aAAa,oBAAoB,UAAU,GAChD,KAAK,aAAa,oBAAoB,UAAU,GAG5C,cAAc,MAChB,KAAK,UAAU,EAAE,MAAM,GAAG,SAAS,eAAc,CAAE,IAC1C,cAAc,MACvB,KAAK,UAAU,EAAE,MAAM,GAAG,SAAS,eAAc,CAAE,IAEnD,KAAK,UAAU,EAAE,MAAM,EAAC,CAAE;IAE9B,SAAS,OAAO;AAEd,iBAAK,gBAAgB,KAAc,GACnC,KAAK,UAAU,EAAE,MAAM,GAAG,SAAU,MAAgB,QAAO,CAAE,GACvD;IACR;EAEF,GACA;IACE,eAAe;IACf,cAAc;GACf;AAEL;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Model } from "./core/model.js";
|
|
2
|
+
import { VisualizationServer } from "./server/server.js";
|
|
3
|
+
import { getErrorMessage } from "./utils/errors.js";
|
|
4
|
+
const port = parseInt(process.env.DR_VISUALIZE_PORT || "8080", 10), projectPath = process.env.DR_PROJECT_PATH || process.cwd(), authEnabled = process.env.DR_AUTH_ENABLED !== "false", authToken = process.env.DR_AUTH_TOKEN && process.env.DR_AUTH_TOKEN.length > 0 ? process.env.DR_AUTH_TOKEN : void 0, withDanger = process.env.DR_WITH_DANGER === "true", viewerPath = process.env.DR_VIEWER_PATH, isTelemetryEnabled = !1;
|
|
5
|
+
let serverInstance = null, isShuttingDown = !1;
|
|
6
|
+
async function main() {
|
|
7
|
+
try {
|
|
8
|
+
if (isTelemetryEnabled)
|
|
9
|
+
try {
|
|
10
|
+
const { initTelemetry } = await import("./telemetry/index.js");
|
|
11
|
+
await initTelemetry();
|
|
12
|
+
const { loadOTLPConfig } = await import("./telemetry/config.js"), otlpConfig = await loadOTLPConfig();
|
|
13
|
+
if (process.env.DEBUG || process.env.VERBOSE) {
|
|
14
|
+
console.log("[Telemetry] SDK initialized in server subprocess"), console.log(`[Telemetry] OTLP traces endpoint: ${otlpConfig.endpoint}`), console.log(`[Telemetry] OTLP logs endpoint: ${otlpConfig.logsEndpoint}`), console.log(`[Telemetry] Service name: ${otlpConfig.serviceName}`);
|
|
15
|
+
const isBun = typeof globalThis.Bun < "u";
|
|
16
|
+
console.log(isBun ? "[Telemetry] Runtime: Bun (using fetch-based OTLP exporter)" : "[Telemetry] Runtime: Node.js (using http-based OTLP exporter)");
|
|
17
|
+
}
|
|
18
|
+
} catch (error) {
|
|
19
|
+
console.error("[Telemetry] Failed to initialize telemetry:", error), console.error("[Telemetry] Server will continue without telemetry");
|
|
20
|
+
}
|
|
21
|
+
else (process.env.DEBUG || process.env.VERBOSE) && console.log("[Telemetry] TELEMETRY_ENABLED is false - telemetry disabled");
|
|
22
|
+
const model = await Model.load(projectPath, { lazyLoad: !1 }), server = new VisualizationServer(model, {
|
|
23
|
+
authEnabled,
|
|
24
|
+
authToken,
|
|
25
|
+
withDanger,
|
|
26
|
+
viewerPath
|
|
27
|
+
});
|
|
28
|
+
serverInstance = server, await server.start(port), authEnabled && console.log(`TOKEN:${server.getAuthToken()}`), setupShutdownHandlers();
|
|
29
|
+
} catch (error) {
|
|
30
|
+
const message = getErrorMessage(error);
|
|
31
|
+
console.error(`Error: ${message}`), error instanceof Error && console.error(`Stack: ${error.stack}`), await gracefulShutdown(1);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
async function gracefulShutdown(exitCode = 0) {
|
|
35
|
+
if (!isShuttingDown) {
|
|
36
|
+
isShuttingDown = !0;
|
|
37
|
+
try {
|
|
38
|
+
if (serverInstance && (serverInstance.stop(), serverInstance = null), isTelemetryEnabled) {
|
|
39
|
+
console.log("[Telemetry] Shutting down telemetry and flushing spans...");
|
|
40
|
+
const { shutdownTelemetry } = await import("./telemetry/index.js");
|
|
41
|
+
await shutdownTelemetry(), console.log("[Telemetry] Telemetry shutdown complete");
|
|
42
|
+
} else
|
|
43
|
+
process.env.DEBUG && console.log("[Telemetry] Telemetry is disabled (TELEMETRY_ENABLED=false at build time)");
|
|
44
|
+
} catch (error) {
|
|
45
|
+
process.env.DEBUG && console.error("Error during shutdown:", error);
|
|
46
|
+
} finally {
|
|
47
|
+
process.exit(exitCode);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function setupShutdownHandlers() {
|
|
52
|
+
process.on("SIGINT", async () => {
|
|
53
|
+
console.log(`
|
|
54
|
+
[SIGINT] Shutting down visualization server...`), await gracefulShutdown(0);
|
|
55
|
+
}), process.on("SIGTERM", async () => {
|
|
56
|
+
console.log(`
|
|
57
|
+
[SIGTERM] Shutting down visualization server...`), await gracefulShutdown(0);
|
|
58
|
+
}), process.on("uncaughtException", async (error) => {
|
|
59
|
+
console.error("Uncaught exception:", error), await gracefulShutdown(1);
|
|
60
|
+
}), process.on("unhandledRejection", async (reason) => {
|
|
61
|
+
console.error("Unhandled rejection:", reason), await gracefulShutdown(1);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
main();
|
|
65
|
+
//# sourceMappingURL=server-entry.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/server-entry.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Visualization Server Entry Point\n * This is a Bun-specific entry point for running the visualization server\n * It receives configuration via environment variables and starts the server\n */\n\nimport { Model } from \"./core/model.js\";\nimport { VisualizationServer } from \"./server/server.js\";\nimport { getErrorMessage } from \"./utils/errors.js\";\n\n// Get configuration from environment variables\nconst port = parseInt(process.env.DR_VISUALIZE_PORT || \"8080\", 10);\nconst projectPath = process.env.DR_PROJECT_PATH || process.cwd();\nconst authEnabled = process.env.DR_AUTH_ENABLED !== \"false\";\n// Only pass authToken if it's a non-empty string, otherwise let server generate one\nconst authToken =\n process.env.DR_AUTH_TOKEN && process.env.DR_AUTH_TOKEN.length > 0\n ? process.env.DR_AUTH_TOKEN\n : undefined;\nconst withDanger = process.env.DR_WITH_DANGER === \"true\";\nconst viewerPath = process.env.DR_VIEWER_PATH;\n\n// Conditional telemetry import based on compile-time flag\ndeclare const TELEMETRY_ENABLED: boolean | undefined;\nconst isTelemetryEnabled = typeof TELEMETRY_ENABLED !== \"undefined\" ? TELEMETRY_ENABLED : false;\n\nlet serverInstance: VisualizationServer | null = null;\nlet isShuttingDown = false;\n\nasync function main() {\n try {\n // CRITICAL: Initialize telemetry SDK in subprocess\n // Without this, no spans will be created or exported even though TELEMETRY_ENABLED=true\n if (isTelemetryEnabled) {\n try {\n const { initTelemetry } = await import(\"./telemetry/index.js\");\n await initTelemetry();\n\n // Load and display actual OTLP configuration\n const { loadOTLPConfig } = await import(\"./telemetry/config.js\");\n const otlpConfig = await loadOTLPConfig();\n\n if (process.env.DEBUG || process.env.VERBOSE) {\n console.log(`[Telemetry] SDK initialized in server subprocess`);\n console.log(`[Telemetry] OTLP traces endpoint: ${otlpConfig.endpoint}`);\n console.log(`[Telemetry] OTLP logs endpoint: ${otlpConfig.logsEndpoint}`);\n console.log(`[Telemetry] Service name: ${otlpConfig.serviceName}`);\n\n // Runtime detection and compatibility info\n const isBun = typeof (globalThis as any).Bun !== \"undefined\";\n if (isBun) {\n console.log(`[Telemetry] Runtime: Bun (using fetch-based OTLP exporter)`);\n } else {\n console.log(`[Telemetry] Runtime: Node.js (using http-based OTLP exporter)`);\n }\n }\n } catch (error) {\n // Log telemetry initialization errors but don't fail the server\n console.error(\"[Telemetry] Failed to initialize telemetry:\", error);\n console.error(\"[Telemetry] Server will continue without telemetry\");\n }\n } else if (process.env.DEBUG || process.env.VERBOSE) {\n console.log(`[Telemetry] TELEMETRY_ENABLED is false - telemetry disabled`);\n }\n\n // Load model with full content\n const model = await Model.load(projectPath, { lazyLoad: false });\n\n // Create and start server\n const server = new VisualizationServer(model, {\n authEnabled,\n authToken,\n withDanger,\n viewerPath,\n });\n serverInstance = server; // Store for signal handlers\n await server.start(port);\n\n // Output token for parent process to read\n if (authEnabled) {\n console.log(`TOKEN:${server.getAuthToken()}`);\n }\n\n // Setup graceful shutdown handlers\n setupShutdownHandlers();\n } catch (error) {\n const message = getErrorMessage(error);\n console.error(`Error: ${message}`);\n if (error instanceof Error) {\n console.error(`Stack: ${error.stack}`);\n }\n await gracefulShutdown(1);\n }\n}\n\n/**\n * Gracefully shutdown the server and flush telemetry\n */\nasync function gracefulShutdown(exitCode: number = 0): Promise<void> {\n if (isShuttingDown) {\n return; // Prevent multiple shutdown attempts\n }\n isShuttingDown = true;\n\n try {\n // Stop the visualization server\n if (serverInstance) {\n serverInstance.stop();\n serverInstance = null;\n }\n\n // Flush telemetry spans before exit\n if (isTelemetryEnabled) {\n console.log(\"[Telemetry] Shutting down telemetry and flushing spans...\");\n const { shutdownTelemetry } = await import(\"./telemetry/index.js\");\n await shutdownTelemetry();\n console.log(\"[Telemetry] Telemetry shutdown complete\");\n } else {\n if (process.env.DEBUG) {\n console.log(\"[Telemetry] Telemetry is disabled (TELEMETRY_ENABLED=false at build time)\");\n }\n }\n } catch (error) {\n // Don't block shutdown on errors\n if (process.env.DEBUG) {\n console.error(\"Error during shutdown:\", error);\n }\n } finally {\n process.exit(exitCode);\n }\n}\n\n/**\n * Setup handlers for graceful shutdown on signals\n */\nfunction setupShutdownHandlers(): void {\n // Handle Ctrl-C (SIGINT)\n process.on(\"SIGINT\", async () => {\n console.log(\"\\n[SIGINT] Shutting down visualization server...\");\n await gracefulShutdown(0);\n });\n\n // Handle termination signal (SIGTERM)\n process.on(\"SIGTERM\", async () => {\n console.log(\"\\n[SIGTERM] Shutting down visualization server...\");\n await gracefulShutdown(0);\n });\n\n // Handle uncaught exceptions\n process.on(\"uncaughtException\", async (error) => {\n console.error(\"Uncaught exception:\", error);\n await gracefulShutdown(1);\n });\n\n // Handle unhandled promise rejections\n process.on(\"unhandledRejection\", async (reason) => {\n console.error(\"Unhandled rejection:\", reason);\n await gracefulShutdown(1);\n });\n}\n\nmain();\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { readFile } from "node:fs/promises";
|
|
4
|
+
import { parse } from "yaml";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
const CONFIG_FILENAME = ".dr-config.yaml";
|
|
7
|
+
async function loadOTLPConfig() {
|
|
8
|
+
const defaults = {
|
|
9
|
+
endpoint: "http://localhost:4318/v1/traces",
|
|
10
|
+
logsEndpoint: "http://localhost:4318/v1/logs",
|
|
11
|
+
serviceName: "dr-cli",
|
|
12
|
+
isExplicitlyConfigured: !1
|
|
13
|
+
};
|
|
14
|
+
let fileConfig = {};
|
|
15
|
+
const configPath = process.env.DR_CONFIG_PATH ?? join(homedir(), CONFIG_FILENAME);
|
|
16
|
+
if (existsSync(configPath))
|
|
17
|
+
try {
|
|
18
|
+
const content = await readFile(configPath, "utf-8");
|
|
19
|
+
fileConfig = parse(content);
|
|
20
|
+
} catch (error) {
|
|
21
|
+
if (error instanceof Error) {
|
|
22
|
+
const errorMsg = error.message;
|
|
23
|
+
errorMsg.includes("EACCES") || errorMsg.includes("permission denied") ? (process.stderr.write(`Error: Cannot read config file ${configPath} - permission denied
|
|
24
|
+
`), process.stderr.write(`Suggestions:
|
|
25
|
+
`), process.stderr.write(` \u2022 Check file permissions with: ls -l ${configPath}
|
|
26
|
+
`), process.stderr.write(` \u2022 Ensure you have read access to the file
|
|
27
|
+
`), process.stderr.write(` \u2022 Try: chmod 644 ${configPath}
|
|
28
|
+
`)) : errorMsg.includes("YAMLException") || error.name === "YAMLException" || errorMsg.includes("bad indentation") || errorMsg.includes("unexpected") ? (process.stderr.write(`Error: Invalid YAML syntax in ${configPath}
|
|
29
|
+
`), process.stderr.write(`Details: ${errorMsg}
|
|
30
|
+
`), process.stderr.write(`Suggestions:
|
|
31
|
+
`), process.stderr.write(` \u2022 Validate your YAML syntax at https://www.yamllint.com/
|
|
32
|
+
`), process.stderr.write(` \u2022 Check for proper indentation (use spaces, not tabs)
|
|
33
|
+
`), process.stderr.write(` \u2022 Verify colons have spaces after them
|
|
34
|
+
`)) : (process.stderr.write(`Error: Failed to load config file ${configPath}
|
|
35
|
+
`), process.stderr.write(`Details: ${errorMsg}
|
|
36
|
+
`), process.stderr.write(`Suggestions:
|
|
37
|
+
`), process.stderr.write(` \u2022 Verify the file is valid UTF-8 encoded text
|
|
38
|
+
`), process.stderr.write(` \u2022 Check if the file system is accessible
|
|
39
|
+
`), process.stderr.write(` \u2022 Try recreating the file if it may be corrupted
|
|
40
|
+
`)), process.stderr.write(`Using default OTLP configuration due to config file error
|
|
41
|
+
`);
|
|
42
|
+
} else
|
|
43
|
+
process.stderr.write(`Warning: Failed to parse ${configPath}, using defaults
|
|
44
|
+
`);
|
|
45
|
+
}
|
|
46
|
+
const otlp = fileConfig?.telemetry?.otlp, getEnvVar = (value) => value !== void 0 && value.trim().length > 0 ? value : void 0, getValidUrl = (url, fieldName = "URL") => {
|
|
47
|
+
if (!url)
|
|
48
|
+
return;
|
|
49
|
+
const trimmed = url.trim();
|
|
50
|
+
if (trimmed.length !== 0)
|
|
51
|
+
try {
|
|
52
|
+
const parsedUrl = new URL(trimmed);
|
|
53
|
+
if (parsedUrl.protocol !== "http:" && parsedUrl.protocol !== "https:") {
|
|
54
|
+
const protocolMsg = parsedUrl.protocol === "" || parsedUrl.protocol === ":" ? "URL must include http:// or https:// scheme" : `Invalid protocol "${parsedUrl.protocol}" (expected http or https)`;
|
|
55
|
+
process.stderr.write(`Error: ${protocolMsg} in ${fieldName}
|
|
56
|
+
`), process.stderr.write(` Provided: ${trimmed}
|
|
57
|
+
`), process.stderr.write(` Expected: URL must start with http:// or https://
|
|
58
|
+
`), process.stderr.write(` Using fallback configuration for this field
|
|
59
|
+
`);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
return trimmed;
|
|
63
|
+
} catch (error) {
|
|
64
|
+
process.stderr.write(`Error: Invalid URL in ${fieldName}: "${trimmed}"
|
|
65
|
+
`), error instanceof Error && process.stderr.write(` Reason: ${error.message}
|
|
66
|
+
`), process.stderr.write(`Suggestions:
|
|
67
|
+
`), process.stderr.write(` \u2022 Ensure URL starts with http:// or https://
|
|
68
|
+
`), process.stderr.write(` \u2022 Check for typos in hostname
|
|
69
|
+
`), process.stderr.write(` \u2022 Verify port number if specified (e.g., :4318)
|
|
70
|
+
`), process.stderr.write(` \u2022 Example: http://localhost:4318/v1/traces
|
|
71
|
+
`), process.stderr.write(` Using fallback configuration for this field
|
|
72
|
+
`);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
}, explicitEndpoint = getValidUrl(getEnvVar(process.env.DR_OTLP_ENDPOINT), "DR_OTLP_ENDPOINT") ?? getValidUrl(otlp?.endpoint, "telemetry.otlp.endpoint") ?? getValidUrl(getEnvVar(process.env.OTEL_EXPORTER_OTLP_ENDPOINT), "OTEL_EXPORTER_OTLP_ENDPOINT"), explicitLogsEndpoint = getValidUrl(getEnvVar(process.env.DR_OTLP_LOGS_ENDPOINT), "DR_OTLP_LOGS_ENDPOINT") ?? getValidUrl(otlp?.logs_endpoint, "telemetry.otlp.logs_endpoint") ?? getValidUrl(getEnvVar(process.env.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT), "OTEL_EXPORTER_OTLP_LOGS_ENDPOINT");
|
|
76
|
+
return {
|
|
77
|
+
endpoint: explicitEndpoint ?? defaults.endpoint,
|
|
78
|
+
logsEndpoint: explicitLogsEndpoint ?? defaults.logsEndpoint,
|
|
79
|
+
serviceName: getEnvVar(process.env.DR_OTLP_SERVICE_NAME) ?? otlp?.service_name ?? getEnvVar(process.env.OTEL_SERVICE_NAME) ?? defaults.serviceName,
|
|
80
|
+
// True only when at least one endpoint was explicitly provided. Without this,
|
|
81
|
+
// TELEMETRY_ENABLED=true (build-time) would try to connect to localhost:4318
|
|
82
|
+
// even when no collector is running, causing a hang at shutdown.
|
|
83
|
+
isExplicitlyConfigured: !!(explicitEndpoint || explicitLogsEndpoint)
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
export {
|
|
87
|
+
loadOTLPConfig
|
|
88
|
+
};
|
|
89
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/telemetry/config.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * OTLP Configuration Loader\n *\n * Loads and merges OTLP configuration from multiple sources with the following precedence:\n * 1. DR-specific env vars: DR_OTLP_ENDPOINT, DR_OTLP_LOGS_ENDPOINT, DR_OTLP_SERVICE_NAME (highest)\n * 2. ~/.dr-config.yaml file configuration\n * 3. Standard OTEL env vars: OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_LOGS_ENDPOINT,\n * OTEL_SERVICE_NAME \u2014 treated as a low-priority fallback so that ambient OTEL env vars set\n * by a parent process (e.g. Claude Code) do not silently override the DR config file.\n * 4. Hard-coded defaults (lowest priority)\n *\n * Why DR-specific env vars are highest: the standard OTEL_* vars are commonly set in developer\n * environments by other OTEL-instrumented tools (IDEs, shell profiles, CI). When dr runs as a\n * subprocess it inherits those vars and would silently misdirect spans. DR_OTLP_* vars are\n * unambiguously for dr and always win.\n *\n * Configuration file format (~/.dr-config.yaml):\n * ```yaml\n * telemetry:\n * otlp:\n * endpoint: 'http://localhost:4318/v1/traces'\n * logs_endpoint: 'http://localhost:4318/v1/logs'\n * service_name: 'dr-cli'\n * ```\n */\n\nimport { homedir } from \"node:os\";\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { parse } from \"yaml\";\nimport { join } from \"node:path\";\n\n/**\n * Configuration structure parsed from ~/.dr-config.yaml\n */\ninterface DRConfig {\n telemetry?: {\n otlp?: {\n endpoint?: string;\n logs_endpoint?: string;\n service_name?: string;\n };\n };\n}\n\n/**\n * Resolved OTLP configuration with all required fields\n */\nexport interface OTLPConfig {\n endpoint: string;\n logsEndpoint: string;\n serviceName: string;\n /** True only when an endpoint was explicitly set via env var or config file. */\n isExplicitlyConfigured: boolean;\n}\n\nconst CONFIG_FILENAME = \".dr-config.yaml\";\n\n/**\n * Load OTLP configuration from multiple sources.\n *\n * Configuration precedence (each field resolved independently):\n * 1. Environment variables (OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_LOGS_ENDPOINT, OTEL_SERVICE_NAME)\n * 2. File configuration (~/.dr-config.yaml)\n * 3. Hard-coded defaults\n *\n * All endpoint URLs are validated. Invalid URLs are treated as not set and fall back to next priority.\n *\n * @returns Resolved OTLP configuration with all required fields\n *\n * @example\n * ```typescript\n * const config = await loadOTLPConfig();\n * console.log(config.endpoint); // 'http://localhost:4318/v1/traces' (or from env/file)\n * ```\n */\nexport async function loadOTLPConfig(): Promise<OTLPConfig> {\n // Hard-coded defaults (Priority 3)\n const defaults: OTLPConfig = {\n endpoint: \"http://localhost:4318/v1/traces\",\n logsEndpoint: \"http://localhost:4318/v1/logs\",\n serviceName: \"dr-cli\",\n isExplicitlyConfigured: false,\n };\n\n // Load file configuration (Priority 2)\n let fileConfig: DRConfig = {};\n // Support DR_CONFIG_PATH override for testing; default to ~/.dr-config.yaml\n const configPath = process.env.DR_CONFIG_PATH ?? join(homedir(), CONFIG_FILENAME);\n\n if (existsSync(configPath)) {\n try {\n const content = await readFile(configPath, \"utf-8\");\n fileConfig = parse(content) as DRConfig;\n } catch (error) {\n // Provide specific error messages based on error type\n if (error instanceof Error) {\n const errorMsg = error.message;\n\n // File permission errors\n if (errorMsg.includes(\"EACCES\") || errorMsg.includes(\"permission denied\")) {\n process.stderr.write(\n `Error: Cannot read config file ${configPath} - permission denied\\n`\n );\n process.stderr.write(\"Suggestions:\\n\");\n process.stderr.write(` \u2022 Check file permissions with: ls -l ${configPath}\\n`);\n process.stderr.write(\" \u2022 Ensure you have read access to the file\\n\");\n process.stderr.write(` \u2022 Try: chmod 644 ${configPath}\\n`);\n }\n // YAML parse errors\n else if (\n errorMsg.includes(\"YAMLException\") ||\n error.name === \"YAMLException\" ||\n errorMsg.includes(\"bad indentation\") ||\n errorMsg.includes(\"unexpected\")\n ) {\n process.stderr.write(`Error: Invalid YAML syntax in ${configPath}\\n`);\n process.stderr.write(`Details: ${errorMsg}\\n`);\n process.stderr.write(\"Suggestions:\\n\");\n process.stderr.write(\" \u2022 Validate your YAML syntax at https://www.yamllint.com/\\n\");\n process.stderr.write(\" \u2022 Check for proper indentation (use spaces, not tabs)\\n\");\n process.stderr.write(\" \u2022 Verify colons have spaces after them\\n\");\n }\n // File encoding or other I/O errors\n else {\n process.stderr.write(`Error: Failed to load config file ${configPath}\\n`);\n process.stderr.write(`Details: ${errorMsg}\\n`);\n process.stderr.write(\"Suggestions:\\n\");\n process.stderr.write(\" \u2022 Verify the file is valid UTF-8 encoded text\\n\");\n process.stderr.write(\" \u2022 Check if the file system is accessible\\n\");\n process.stderr.write(\" \u2022 Try recreating the file if it may be corrupted\\n\");\n }\n process.stderr.write(`Using default OTLP configuration due to config file error\\n`);\n } else {\n process.stderr.write(`Warning: Failed to parse ${configPath}, using defaults\\n`);\n }\n }\n }\n\n const otlp = fileConfig?.telemetry?.otlp;\n\n // Helper to check if env var is effectively set (not empty after trim)\n const getEnvVar = (value: string | undefined) => {\n return value !== undefined && value.trim().length > 0 ? value : undefined;\n };\n\n // Helper to validate URL and return if valid, undefined if invalid\n const getValidUrl = (url: string | undefined, fieldName: string = \"URL\") => {\n if (!url) return undefined;\n const trimmed = url.trim();\n if (trimmed.length === 0) return undefined;\n\n try {\n const parsedUrl = new URL(trimmed);\n\n // Only accept http and https protocols\n if (parsedUrl.protocol !== \"http:\" && parsedUrl.protocol !== \"https:\") {\n const protocolMsg =\n parsedUrl.protocol === \"\" || parsedUrl.protocol === \":\"\n ? \"URL must include http:// or https:// scheme\"\n : `Invalid protocol \"${parsedUrl.protocol}\" (expected http or https)`;\n process.stderr.write(`Error: ${protocolMsg} in ${fieldName}\\n`);\n process.stderr.write(` Provided: ${trimmed}\\n`);\n process.stderr.write(` Expected: URL must start with http:// or https://\\n`);\n process.stderr.write(` Using fallback configuration for this field\\n`);\n return undefined;\n }\n\n return trimmed;\n } catch (error) {\n process.stderr.write(`Error: Invalid URL in ${fieldName}: \"${trimmed}\"\\n`);\n if (error instanceof Error) {\n process.stderr.write(` Reason: ${error.message}\\n`);\n }\n process.stderr.write(\"Suggestions:\\n\");\n process.stderr.write(\" \u2022 Ensure URL starts with http:// or https://\\n\");\n process.stderr.write(\" \u2022 Check for typos in hostname\\n\");\n process.stderr.write(\" \u2022 Verify port number if specified (e.g., :4318)\\n\");\n process.stderr.write(\" \u2022 Example: http://localhost:4318/v1/traces\\n\");\n process.stderr.write(` Using fallback configuration for this field\\n`);\n return undefined;\n }\n };\n\n // Resolve each field using the 4-level precedence chain:\n // 1. DR-specific env vars (unambiguously for dr, never set by other tools)\n // 2. ~/.dr-config.yaml (explicit user config for dr)\n // 3. Standard OTEL env vars (low-priority fallback; may be set by parent processes)\n // 4. Hard-coded defaults\n //\n // Standard OTEL env vars are intentionally below the config file. When dr runs as a\n // subprocess of another OTEL-instrumented tool (e.g. Claude Code), it inherits those\n // env vars and would otherwise silently redirect spans to the wrong collector.\n const explicitEndpoint =\n getValidUrl(getEnvVar(process.env.DR_OTLP_ENDPOINT), \"DR_OTLP_ENDPOINT\") ??\n getValidUrl(otlp?.endpoint, \"telemetry.otlp.endpoint\") ??\n getValidUrl(getEnvVar(process.env.OTEL_EXPORTER_OTLP_ENDPOINT), \"OTEL_EXPORTER_OTLP_ENDPOINT\");\n\n const explicitLogsEndpoint =\n getValidUrl(getEnvVar(process.env.DR_OTLP_LOGS_ENDPOINT), \"DR_OTLP_LOGS_ENDPOINT\") ??\n getValidUrl(otlp?.logs_endpoint, \"telemetry.otlp.logs_endpoint\") ??\n getValidUrl(getEnvVar(process.env.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT), \"OTEL_EXPORTER_OTLP_LOGS_ENDPOINT\");\n\n return {\n endpoint: explicitEndpoint ?? defaults.endpoint,\n logsEndpoint: explicitLogsEndpoint ?? defaults.logsEndpoint,\n serviceName:\n getEnvVar(process.env.DR_OTLP_SERVICE_NAME) ??\n otlp?.service_name ??\n getEnvVar(process.env.OTEL_SERVICE_NAME) ??\n defaults.serviceName,\n // True only when at least one endpoint was explicitly provided. Without this,\n // TELEMETRY_ENABLED=true (build-time) would try to connect to localhost:4318\n // even when no collector is running, causing a hang at shutdown.\n isExplicitlyConfigured: !!(explicitEndpoint || explicitLogsEndpoint),\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/telemetry/console-interceptor.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Console method interceptor for OpenTelemetry log emission.\n *\n * Wraps console.log, console.error, console.warn, and console.debug to emit\n * OpenTelemetry log records while preserving original console behavior.\n *\n * Log records inherit trace context from active spans and include stack traces\n * for errors. This module is only active when TELEMETRY_ENABLED is true.\n *\n * Pattern: All telemetry function calls must be directly guarded by\n * `if (TELEMETRY_ENABLED)` checks in calling code to enable tree-shaking\n * and zero-cost abstractions in production builds.\n */\n\n// Fallback for runtime environments where TELEMETRY_ENABLED is not defined by esbuild\ndeclare const TELEMETRY_ENABLED: boolean | undefined;\nconst isTelemetryEnabled = typeof TELEMETRY_ENABLED !==
|
|
4
|
+
"sourcesContent": ["/**\n * Console method interceptor for OpenTelemetry log emission.\n *\n * Wraps console.log, console.error, console.warn, and console.debug to emit\n * OpenTelemetry log records while preserving original console behavior.\n *\n * Log records inherit trace context from active spans and include stack traces\n * for errors. This module is only active when TELEMETRY_ENABLED is true.\n *\n * Pattern: All telemetry function calls must be directly guarded by\n * `if (TELEMETRY_ENABLED)` checks in calling code to enable tree-shaking\n * and zero-cost abstractions in production builds.\n */\n\n// Fallback for runtime environments where TELEMETRY_ENABLED is not defined by esbuild\ndeclare const TELEMETRY_ENABLED: boolean | undefined;\nconst isTelemetryEnabled = typeof TELEMETRY_ENABLED !== \"undefined\" ? TELEMETRY_ENABLED : false;\n\n// Store original console methods before any wrapping\nconst originalConsole = {\n log: console.log,\n error: console.error,\n warn: console.warn,\n debug: console.debug,\n};\n\n/**\n * Format console arguments into a single string.\n * Converts objects to JSON representation for readability in logs.\n */\nfunction formatArgs(args: any[]): string {\n return args\n .map((arg) => {\n if (typeof arg === \"object\" && arg !== null) {\n try {\n return JSON.stringify(arg);\n } catch {\n return String(arg);\n }\n }\n return String(arg);\n })\n .join(\" \");\n}\n\n/**\n * Extract error stack trace and message from console arguments.\n * Returns attributes suitable for log record enrichment.\n */\nfunction extractStackTrace(args: any[]): Record<string, string> {\n const errorArg = args.find((arg) => arg instanceof Error);\n if (errorArg) {\n return {\n \"error.message\": errorArg.message,\n \"error.stack\": errorArg.stack || \"\",\n };\n }\n return {};\n}\n\n/**\n * Install console interceptor to emit OpenTelemetry log records.\n *\n * Maps console methods to OpenTelemetry severity levels:\n * - console.debug() \u2192 DEBUG\n * - console.log() \u2192 INFO\n * - console.warn() \u2192 WARN\n * - console.error() \u2192 ERROR\n *\n * Each log record includes the active trace and span identifiers\n * from the current OpenTelemetry context (if available).\n *\n * Original console behavior is preserved - all console output still appears.\n *\n * No-op when TELEMETRY_ENABLED is false.\n */\nexport async function installConsoleInterceptor(): Promise<void> {\n if (!isTelemetryEnabled) return;\n\n const [{ SeverityNumber }, { emitLog }] = await Promise.all([\n import(\"@opentelemetry/api-logs\"),\n import(\"./index.js\"),\n ]);\n\n console.log = (...args: any[]): void => {\n emitLog(SeverityNumber.INFO, formatArgs(args));\n originalConsole.log.apply(console, args);\n };\n\n console.error = (...args: any[]): void => {\n const attrs = extractStackTrace(args);\n emitLog(SeverityNumber.ERROR, formatArgs(args), attrs);\n originalConsole.error.apply(console, args);\n };\n\n console.warn = (...args: any[]): void => {\n emitLog(SeverityNumber.WARN, formatArgs(args));\n originalConsole.warn.apply(console, args);\n };\n\n console.debug = (...args: any[]): void => {\n emitLog(SeverityNumber.DEBUG, formatArgs(args));\n originalConsole.debug.apply(console, args);\n };\n}\n\n/**\n * Uninstall console interceptor and restore original console methods.\n *\n * Useful for testing to prevent state pollution between tests.\n * Safe to call when telemetry is disabled (no-op).\n */\nexport function uninstallConsoleInterceptor(): void {\n console.log = originalConsole.log;\n console.error = originalConsole.error;\n console.warn = originalConsole.warn;\n console.debug = originalConsole.debug;\n}\n"],
|
|
5
5
|
"mappings": "AAgBA,MAAM,qBAAgE,IAGhE,kBAAkB;EACtB,KAAK,QAAQ;EACb,OAAO,QAAQ;EACf,MAAM,QAAQ;EACd,OAAO,QAAQ;;AAOjB,SAAS,WAAW,MAAW;AAC7B,SAAO,KACJ,IAAI,CAAC,QAAO;AACX,QAAI,OAAO,OAAQ,YAAY,QAAQ;AACrC,UAAI;AACF,eAAO,KAAK,UAAU,GAAG;MAC3B,QAAQ;AACN,eAAO,OAAO,GAAG;MACnB;AAEF,WAAO,OAAO,GAAG;EACnB,CAAC,EACA,KAAK,GAAG;AACb;AAMA,SAAS,kBAAkB,MAAW;AACpC,QAAM,WAAW,KAAK,KAAK,CAAC,QAAQ,eAAe,KAAK;AACxD,SAAI,WACK;IACL,iBAAiB,SAAS;IAC1B,eAAe,SAAS,SAAS;MAG9B,CAAA;AACT;AAkBA,eAAsB,4BAAyB;AA4B/C;AAQM,SAAU,8BAA2B;AACzC,UAAQ,MAAM,gBAAgB,KAC9B,QAAQ,QAAQ,gBAAgB,OAChC,QAAQ,OAAO,gBAAgB,MAC/B,QAAQ,QAAQ,gBAAgB;AAClC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { parse } from "yaml";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { homedir } from "node:os";
|
|
6
|
+
function isTelemetryBuiltIn() {
|
|
7
|
+
return !1;
|
|
8
|
+
}
|
|
9
|
+
async function isTelemetryConfigured() {
|
|
10
|
+
const configPath = process.env.DR_CONFIG_PATH ?? join(homedir(), ".dr-config.yaml");
|
|
11
|
+
if (!existsSync(configPath))
|
|
12
|
+
return !1;
|
|
13
|
+
try {
|
|
14
|
+
const content = await readFile(configPath, "utf-8");
|
|
15
|
+
return !!parse(content)?.telemetry?.otlp?.endpoint;
|
|
16
|
+
} catch {
|
|
17
|
+
return !1;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export {
|
|
21
|
+
isTelemetryBuiltIn,
|
|
22
|
+
isTelemetryConfigured
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=detect.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/telemetry/detect.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Telemetry Detection\n *\n * Determines if the CLI was built with telemetry (OTLP sender) enabled\n * and if telemetry is configured via ~/.dr-config.yaml.\n * This is a build-time constant that gets dead-code eliminated in production builds.\n */\n\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { parse } from \"yaml\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\n\n// Declare TELEMETRY_ENABLED as a build-time constant (substituted by esbuild)\ndeclare const TELEMETRY_ENABLED: boolean;\n\n/**\n * Check if the CLI was built with telemetry enabled\n * @returns true if telemetry is enabled, false otherwise\n */\nexport function isTelemetryBuiltIn(): boolean {\n return typeof TELEMETRY_ENABLED !== \"undefined\" ? TELEMETRY_ENABLED : false;\n}\n\n/**\n * Check if telemetry is configured via ~/.dr-config.yaml\n * @returns true if config file exists with telemetry.otlp section, false otherwise\n */\nexport async function isTelemetryConfigured(): Promise<boolean> {\n const configPath = process.env.DR_CONFIG_PATH ?? join(homedir(), \".dr-config.yaml\");\n\n if (!existsSync(configPath)) {\n return false;\n }\n\n try {\n const content = await readFile(configPath, \"utf-8\");\n const config = parse(content) as any;\n\n // Check if config has telemetry.otlp.endpoint (minimum required)\n return !!(config?.telemetry?.otlp?.endpoint);\n } catch {\n return false;\n }\n}\n"],
|
|
5
|
+
"mappings": "AAQA,SAAS,kBAAkB;AAC3B,SAAS,gBAAgB;AACzB,SAAS,aAAa;AACtB,SAAS,YAAY;AACrB,SAAS,eAAe;AASlB,SAAU,qBAAkB;AAChC,SAAkD;AACpD;AAMA,eAAsB,wBAAqB;AACzC,QAAM,aAAa,QAAQ,IAAI,kBAAkB,KAAK,QAAO,GAAI,iBAAiB;AAElF,MAAI,CAAC,WAAW,UAAU;AACxB,WAAO;AAGT,MAAI;AACF,UAAM,UAAU,MAAM,SAAS,YAAY,OAAO;AAIlD,WAAO,CAAC,CAHO,MAAM,OAAO,GAGV,WAAW,MAAM;EACrC,QAAQ;AACN,WAAO;EACT;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { ExportResultCode } from "@opentelemetry/core";
|
|
2
|
+
import { getErrorMessage } from "../utils/errors.js";
|
|
3
|
+
class FetchOTLPExporter {
|
|
4
|
+
url;
|
|
5
|
+
debug;
|
|
6
|
+
timeoutMs;
|
|
7
|
+
constructor(config) {
|
|
8
|
+
this.url = config?.url || "http://localhost:4318/v1/traces", this.timeoutMs = config?.timeoutMillis ?? 1e4, this.debug = process.env.DR_TELEMETRY_DEBUG === "1" || process.env.DEBUG === "1" || process.env.VERBOSE === "1", this.debug && process.stderr.write(`[TELEMETRY] Fetch-based trace exporter initialized: ${this.url}
|
|
9
|
+
`);
|
|
10
|
+
}
|
|
11
|
+
export(spans, resultCallback) {
|
|
12
|
+
this.debug && process.stderr.write(`[TELEMETRY] Exporting ${spans.length} span(s) to ${this.url}
|
|
13
|
+
`);
|
|
14
|
+
const payload = this.convertSpansToOTLP(spans), controller = new AbortController(), timeoutId = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
15
|
+
fetch(this.url, {
|
|
16
|
+
method: "POST",
|
|
17
|
+
headers: {
|
|
18
|
+
"Content-Type": "application/json"
|
|
19
|
+
},
|
|
20
|
+
body: JSON.stringify(payload),
|
|
21
|
+
signal: controller.signal
|
|
22
|
+
}).then(async (response) => {
|
|
23
|
+
if (clearTimeout(timeoutId), response.ok)
|
|
24
|
+
this.debug && process.stderr.write(`[TELEMETRY] Export SUCCESS - ${spans.length} span(s) sent
|
|
25
|
+
`), resultCallback({ code: ExportResultCode.SUCCESS });
|
|
26
|
+
else {
|
|
27
|
+
const errorText = await response.text();
|
|
28
|
+
this.debug && process.stderr.write(`[TELEMETRY] Export FAILED - HTTP ${response.status}: ${errorText}
|
|
29
|
+
`), resultCallback({
|
|
30
|
+
code: ExportResultCode.FAILED,
|
|
31
|
+
error: new Error(`HTTP ${response.status}: ${errorText}`)
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}).catch((error) => {
|
|
35
|
+
if (clearTimeout(timeoutId), this.debug) {
|
|
36
|
+
const errorMsg = getErrorMessage(error);
|
|
37
|
+
process.stderr.write(`[TELEMETRY] Export FAILED - ${errorMsg}
|
|
38
|
+
`);
|
|
39
|
+
}
|
|
40
|
+
resultCallback({
|
|
41
|
+
code: ExportResultCode.FAILED,
|
|
42
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
async forceFlush() {
|
|
47
|
+
}
|
|
48
|
+
async shutdown() {
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Convert OpenTelemetry spans to OTLP JSON format.
|
|
52
|
+
* Simplified version that covers the essential fields.
|
|
53
|
+
*/
|
|
54
|
+
convertSpansToOTLP(spans) {
|
|
55
|
+
return {
|
|
56
|
+
resourceSpans: [
|
|
57
|
+
{
|
|
58
|
+
resource: {
|
|
59
|
+
attributes: this.convertAttributes(spans[0]?.resource?.attributes || {})
|
|
60
|
+
},
|
|
61
|
+
scopeSpans: [
|
|
62
|
+
{
|
|
63
|
+
scope: {
|
|
64
|
+
name: spans[0]?.instrumentationLibrary?.name || "unknown",
|
|
65
|
+
version: spans[0]?.instrumentationLibrary?.version || ""
|
|
66
|
+
},
|
|
67
|
+
spans: spans.map((span) => ({
|
|
68
|
+
traceId: span.spanContext().traceId,
|
|
69
|
+
spanId: span.spanContext().spanId,
|
|
70
|
+
parentSpanId: span.parentSpanId || void 0,
|
|
71
|
+
name: span.name,
|
|
72
|
+
kind: span.kind,
|
|
73
|
+
startTimeUnixNano: String(span.startTime[0] * 1e9 + span.startTime[1]),
|
|
74
|
+
endTimeUnixNano: String(span.endTime[0] * 1e9 + span.endTime[1]),
|
|
75
|
+
attributes: this.convertAttributes(span.attributes),
|
|
76
|
+
status: span.status,
|
|
77
|
+
events: span.events.map((event) => ({
|
|
78
|
+
timeUnixNano: String(event.time[0] * 1e9 + event.time[1]),
|
|
79
|
+
name: event.name,
|
|
80
|
+
attributes: this.convertAttributes(event.attributes || {})
|
|
81
|
+
}))
|
|
82
|
+
}))
|
|
83
|
+
}
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
]
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Convert attributes to OTLP format.
|
|
91
|
+
*/
|
|
92
|
+
convertAttributes(attrs) {
|
|
93
|
+
return attrs ? Object.entries(attrs).map(([key, value]) => ({
|
|
94
|
+
key,
|
|
95
|
+
value: this.convertValue(value)
|
|
96
|
+
})) : [];
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Convert attribute value to OTLP format.
|
|
100
|
+
*/
|
|
101
|
+
convertValue(value) {
|
|
102
|
+
return typeof value == "string" ? { stringValue: value } : typeof value == "number" ? Number.isInteger(value) ? { intValue: String(value) } : { doubleValue: value } : typeof value == "boolean" ? { boolValue: value } : Array.isArray(value) ? {
|
|
103
|
+
arrayValue: {
|
|
104
|
+
values: value.map((v) => this.convertValue(v))
|
|
105
|
+
}
|
|
106
|
+
} : { stringValue: String(value) };
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
export {
|
|
110
|
+
FetchOTLPExporter
|
|
111
|
+
};
|
|
112
|
+
//# sourceMappingURL=fetch-otlp-exporter.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/telemetry/fetch-otlp-exporter.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Fetch-based OTLP exporter for Bun compatibility.\n * Uses native fetch API instead of Node.js http module.\n */\n\nimport type { SpanExporter, ReadableSpan } from \"@opentelemetry/sdk-trace-base\";\nimport type { ExportResult } from \"@opentelemetry/core\";\nimport { ExportResultCode } from \"@opentelemetry/core\";\nimport { getErrorMessage } from \"../utils/errors.js\";\n\n/**\n * OTLP exporter using fetch API for Bun compatibility.\n * Bun's http module has compatibility issues with the standard OTLP exporter,\n * so we use fetch which is natively supported by Bun.\n */\nexport class FetchOTLPExporter implements SpanExporter {\n private readonly url: string;\n private readonly debug: boolean;\n private readonly timeoutMs: number;\n\n constructor(config?: { url?: string; timeoutMillis?: number }) {\n this.url = config?.url || \"http://localhost:4318/v1/traces\";\n this.timeoutMs = config?.timeoutMillis ?? 10000;\n this.debug =\n process.env.DR_TELEMETRY_DEBUG === \"1\" ||\n process.env.DEBUG === \"1\" ||\n process.env.VERBOSE === \"1\";\n\n if (this.debug) {\n process.stderr.write(`[TELEMETRY] Fetch-based trace exporter initialized: ${this.url}\\n`);\n }\n }\n\n export(spans: ReadableSpan[], resultCallback: (result: ExportResult) => void): void {\n if (this.debug) {\n process.stderr.write(`[TELEMETRY] Exporting ${spans.length} span(s) to ${this.url}\\n`);\n }\n\n // Convert spans to OTLP JSON format\n const payload = this.convertSpansToOTLP(spans);\n\n // Use AbortController for timeout\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeoutMs);\n\n fetch(this.url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(payload),\n signal: controller.signal,\n })\n .then(async (response) => {\n clearTimeout(timeoutId);\n\n if (response.ok) {\n if (this.debug) {\n process.stderr.write(`[TELEMETRY] Export SUCCESS - ${spans.length} span(s) sent\\n`);\n }\n resultCallback({ code: ExportResultCode.SUCCESS });\n } else {\n const errorText = await response.text();\n if (this.debug) {\n process.stderr.write(\n `[TELEMETRY] Export FAILED - HTTP ${response.status}: ${errorText}\\n`\n );\n }\n resultCallback({\n code: ExportResultCode.FAILED,\n error: new Error(`HTTP ${response.status}: ${errorText}`),\n });\n }\n })\n .catch((error) => {\n clearTimeout(timeoutId);\n if (this.debug) {\n const errorMsg = getErrorMessage(error);\n process.stderr.write(`[TELEMETRY] Export FAILED - ${errorMsg}\\n`);\n }\n resultCallback({\n code: ExportResultCode.FAILED,\n error: error instanceof Error ? error : new Error(String(error)),\n });\n });\n }\n\n async forceFlush(): Promise<void> {\n // No-op for fetch-based exporter (no buffering)\n }\n\n async shutdown(): Promise<void> {\n // No-op for fetch-based exporter (no persistent connections)\n }\n\n /**\n * Convert OpenTelemetry spans to OTLP JSON format.\n * Simplified version that covers the essential fields.\n */\n private convertSpansToOTLP(spans: ReadableSpan[]): any {\n return {\n resourceSpans: [\n {\n resource: {\n attributes: this.convertAttributes(spans[0]?.resource?.attributes || {}),\n },\n scopeSpans: [\n {\n scope: {\n name: spans[0]?.instrumentationLibrary?.name || \"unknown\",\n version: spans[0]?.instrumentationLibrary?.version || \"\",\n },\n spans: spans.map((span) => ({\n traceId: span.spanContext().traceId,\n spanId: span.spanContext().spanId,\n parentSpanId: span.parentSpanId || undefined,\n name: span.name,\n kind: span.kind,\n startTimeUnixNano: String(span.startTime[0] * 1e9 + span.startTime[1]),\n endTimeUnixNano: String(span.endTime[0] * 1e9 + span.endTime[1]),\n attributes: this.convertAttributes(span.attributes),\n status: span.status,\n events: span.events.map((event) => ({\n timeUnixNano: String(event.time[0] * 1e9 + event.time[1]),\n name: event.name,\n attributes: this.convertAttributes(event.attributes || {}),\n })),\n })),\n },\n ],\n },\n ],\n };\n }\n\n /**\n * Convert attributes to OTLP format.\n */\n private convertAttributes(attrs: any): any[] {\n if (!attrs) return [];\n return Object.entries(attrs).map(([key, value]) => ({\n key,\n value: this.convertValue(value),\n }));\n }\n\n /**\n * Convert attribute value to OTLP format.\n */\n private convertValue(value: any): any {\n if (typeof value === \"string\") {\n return { stringValue: value };\n } else if (typeof value === \"number\") {\n if (Number.isInteger(value)) {\n return { intValue: String(value) };\n } else {\n return { doubleValue: value };\n }\n } else if (typeof value === \"boolean\") {\n return { boolValue: value };\n } else if (Array.isArray(value)) {\n return {\n arrayValue: {\n values: value.map((v) => this.convertValue(v)),\n },\n };\n } else {\n return { stringValue: String(value) };\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/telemetry/index.js
CHANGED
|
@@ -1,12 +1,88 @@
|
|
|
1
|
+
import { SeverityNumber } from "@opentelemetry/api-logs";
|
|
1
2
|
const isTelemetryEnabled = !1;
|
|
2
|
-
let sdk = null, tracer = null, loggerProvider = null, logger = null, cachedContext = null, cachedTrace = null;
|
|
3
|
+
let sdk = null, tracer = null, loggerProvider = null, logger = null, spanProcessor = null, cachedContext = null, cachedTrace = null;
|
|
3
4
|
async function initTelemetry() {
|
|
5
|
+
if (isTelemetryEnabled) {
|
|
6
|
+
const { loadOTLPConfig } = await import("./config.js"), otlpConfig = await loadOTLPConfig();
|
|
7
|
+
if (!otlpConfig.isExplicitlyConfigured)
|
|
8
|
+
return;
|
|
9
|
+
const [{ NodeSDK }, { BatchSpanProcessor }, { SimpleLogRecordProcessor }, otelApi, { Resource }, { LoggerProvider }, { ResilientOTLPExporter }, { ResilientLogExporter }] = await Promise.all([
|
|
10
|
+
import("@opentelemetry/sdk-node"),
|
|
11
|
+
import("@opentelemetry/sdk-trace-base"),
|
|
12
|
+
import("@opentelemetry/sdk-logs"),
|
|
13
|
+
import("@opentelemetry/api"),
|
|
14
|
+
import("@opentelemetry/resources"),
|
|
15
|
+
import("@opentelemetry/sdk-logs"),
|
|
16
|
+
import("./resilient-exporter.js"),
|
|
17
|
+
import("./resilient-log-exporter.js")
|
|
18
|
+
]), { trace, context } = otelApi;
|
|
19
|
+
cachedTrace = trace, cachedContext = context, process.env.DR_TELEMETRY_DEBUG && (process.stderr.write(`[TELEMETRY] Configuration loaded:
|
|
20
|
+
`), process.stderr.write(` - Traces endpoint: ${otlpConfig.endpoint}
|
|
21
|
+
`), process.stderr.write(` - Logs endpoint: ${otlpConfig.logsEndpoint}
|
|
22
|
+
`), process.stderr.write(` - Service name: ${otlpConfig.serviceName}
|
|
23
|
+
`));
|
|
24
|
+
const cliVersion = "0.1.7";
|
|
25
|
+
let projectName = "unknown";
|
|
26
|
+
try {
|
|
27
|
+
const [{ readFileSync, existsSync }, { parse }] = await Promise.all([
|
|
28
|
+
import("fs"),
|
|
29
|
+
import("yaml")
|
|
30
|
+
]), possiblePaths = [
|
|
31
|
+
`${process.cwd()}/documentation-robotics/model/manifest.yaml`,
|
|
32
|
+
`${process.cwd()}/model/manifest.yaml`
|
|
33
|
+
];
|
|
34
|
+
for (const manifestPath of possiblePaths)
|
|
35
|
+
try {
|
|
36
|
+
if (existsSync(manifestPath)) {
|
|
37
|
+
const content = readFileSync(manifestPath, "utf-8");
|
|
38
|
+
projectName = parse(content).project?.name || "unknown";
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
} catch {
|
|
42
|
+
}
|
|
43
|
+
} catch {
|
|
44
|
+
}
|
|
45
|
+
const resource = new Resource({
|
|
46
|
+
"service.name": otlpConfig.serviceName,
|
|
47
|
+
"service.version": cliVersion,
|
|
48
|
+
"dr.project.name": projectName
|
|
49
|
+
}), traceExporter = new ResilientOTLPExporter({
|
|
50
|
+
url: otlpConfig.endpoint,
|
|
51
|
+
timeoutMillis: 1e4
|
|
52
|
+
// 10s timeout for network requests (serialization + network latency)
|
|
53
|
+
});
|
|
54
|
+
spanProcessor = new BatchSpanProcessor(traceExporter, {
|
|
55
|
+
maxExportBatchSize: 32,
|
|
56
|
+
maxQueueSize: 64,
|
|
57
|
+
scheduledDelayMillis: 100,
|
|
58
|
+
// Short delay for CLI
|
|
59
|
+
exportTimeoutMillis: 5e3
|
|
60
|
+
});
|
|
61
|
+
const nodeSdk = new NodeSDK({
|
|
62
|
+
resource,
|
|
63
|
+
spanProcessor
|
|
64
|
+
});
|
|
65
|
+
nodeSdk.start(), sdk = nodeSdk, tracer = trace.getTracer("dr-cli", cliVersion), (process.env.DR_TELEMETRY_DEBUG || process.env.DEBUG || process.env.VERBOSE) && (process.stderr.write(`[TELEMETRY] SDK initialized successfully
|
|
66
|
+
`), process.stderr.write(`[TELEMETRY] Tracer initialized: ${tracer !== null}
|
|
67
|
+
`));
|
|
68
|
+
const logExporter = new ResilientLogExporter({
|
|
69
|
+
url: otlpConfig.logsEndpoint,
|
|
70
|
+
timeoutMillis: 1e4
|
|
71
|
+
// 10s timeout for network requests (serialization + network latency)
|
|
72
|
+
});
|
|
73
|
+
loggerProvider = new LoggerProvider({
|
|
74
|
+
resource
|
|
75
|
+
}), loggerProvider.addLogRecordProcessor(new SimpleLogRecordProcessor(logExporter)), logger = loggerProvider.getLogger("dr-cli", cliVersion);
|
|
76
|
+
}
|
|
4
77
|
}
|
|
5
78
|
function startSpan(name, attributes) {
|
|
6
|
-
return null
|
|
79
|
+
return isTelemetryEnabled && tracer && cachedContext ? tracer.startSpan(name, { attributes }, cachedContext.active()) : ((process.env.DR_TELEMETRY_DEBUG || process.env.DEBUG || process.env.VERBOSE) && (isTelemetryEnabled ? tracer ? cachedContext || process.stderr.write(`[TELEMETRY] startSpan('${name}'): skipped - cachedContext is null
|
|
80
|
+
`) : process.stderr.write(`[TELEMETRY] startSpan('${name}'): skipped - tracer is null (initTelemetry not called?)
|
|
81
|
+
`) : process.stderr.write(`[TELEMETRY] startSpan('${name}'): skipped - isTelemetryEnabled=false
|
|
82
|
+
`)), null);
|
|
7
83
|
}
|
|
8
84
|
async function startActiveSpan(name, fn, attributes) {
|
|
9
|
-
{
|
|
85
|
+
if (!isTelemetryEnabled || !tracer) {
|
|
10
86
|
const noopSpan = {
|
|
11
87
|
end: () => {
|
|
12
88
|
},
|
|
@@ -38,15 +114,89 @@ async function startActiveSpan(name, fn, attributes) {
|
|
|
38
114
|
});
|
|
39
115
|
}
|
|
40
116
|
function endSpan(span) {
|
|
117
|
+
isTelemetryEnabled && span && span.end();
|
|
118
|
+
}
|
|
119
|
+
function getActiveSpan() {
|
|
120
|
+
return isTelemetryEnabled && cachedTrace ? cachedTrace.getActiveSpan?.() ?? null : null;
|
|
41
121
|
}
|
|
42
122
|
function emitLog(severity, message, attributes) {
|
|
123
|
+
if (!isTelemetryEnabled || !logger || !cachedTrace)
|
|
124
|
+
return;
|
|
125
|
+
const context = cachedTrace.getActiveSpan()?.spanContext(), severityText = {
|
|
126
|
+
0: "UNSPECIFIED",
|
|
127
|
+
1: "TRACE",
|
|
128
|
+
2: "TRACE2",
|
|
129
|
+
3: "TRACE3",
|
|
130
|
+
4: "TRACE4",
|
|
131
|
+
5: "DEBUG",
|
|
132
|
+
6: "DEBUG2",
|
|
133
|
+
7: "DEBUG3",
|
|
134
|
+
8: "DEBUG4",
|
|
135
|
+
9: "INFO",
|
|
136
|
+
10: "INFO2",
|
|
137
|
+
11: "INFO3",
|
|
138
|
+
12: "INFO4",
|
|
139
|
+
13: "WARN",
|
|
140
|
+
14: "WARN2",
|
|
141
|
+
15: "WARN3",
|
|
142
|
+
16: "WARN4",
|
|
143
|
+
17: "ERROR",
|
|
144
|
+
18: "ERROR2",
|
|
145
|
+
19: "ERROR3",
|
|
146
|
+
20: "ERROR4",
|
|
147
|
+
21: "FATAL",
|
|
148
|
+
22: "FATAL2",
|
|
149
|
+
23: "FATAL3",
|
|
150
|
+
24: "FATAL4"
|
|
151
|
+
}[severity] || "UNSPECIFIED";
|
|
152
|
+
logger.emit({
|
|
153
|
+
severityNumber: severity,
|
|
154
|
+
severityText,
|
|
155
|
+
body: message,
|
|
156
|
+
attributes: {
|
|
157
|
+
...attributes,
|
|
158
|
+
...context && {
|
|
159
|
+
"trace.id": context.traceId,
|
|
160
|
+
"span.id": context.spanId
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
async function flushTelemetry() {
|
|
166
|
+
if (isTelemetryEnabled && spanProcessor)
|
|
167
|
+
try {
|
|
168
|
+
await spanProcessor.forceFlush();
|
|
169
|
+
} catch {
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
function setSpanAttribute(span, key, value) {
|
|
173
|
+
if (span && typeof span.setAttribute == "function")
|
|
174
|
+
try {
|
|
175
|
+
span.setAttribute(key, value);
|
|
176
|
+
} catch {
|
|
177
|
+
}
|
|
43
178
|
}
|
|
44
179
|
async function shutdownTelemetry() {
|
|
180
|
+
if (isTelemetryEnabled) {
|
|
181
|
+
try {
|
|
182
|
+
spanProcessor && await spanProcessor.forceFlush(), await sdk?.shutdown();
|
|
183
|
+
} catch {
|
|
184
|
+
}
|
|
185
|
+
try {
|
|
186
|
+
await loggerProvider?.shutdown();
|
|
187
|
+
} catch {
|
|
188
|
+
}
|
|
189
|
+
}
|
|
45
190
|
}
|
|
46
191
|
export {
|
|
192
|
+
SeverityNumber,
|
|
47
193
|
emitLog,
|
|
48
194
|
endSpan,
|
|
195
|
+
flushTelemetry,
|
|
196
|
+
getActiveSpan,
|
|
49
197
|
initTelemetry,
|
|
198
|
+
isTelemetryEnabled,
|
|
199
|
+
setSpanAttribute,
|
|
50
200
|
shutdownTelemetry,
|
|
51
201
|
startActiveSpan,
|
|
52
202
|
startSpan
|