@principal-ai/principal-view-core 0.5.16 → 0.5.17

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/index.d.ts CHANGED
@@ -18,6 +18,8 @@ export { CanvasConverter } from './utils/CanvasConverter';
18
18
  export type { ReactFlowNode, ReactFlowEdge } from './utils/CanvasConverter';
19
19
  export { EventValidator, createValidatedEmitter, EventValidationError } from './telemetry/event-validator';
20
20
  export type { ValidationResult } from './telemetry/event-validator';
21
+ export { analyzeCoverage } from './telemetry/coverage';
22
+ export type { CoverageMetrics, NodeCoverage, CanvasNode as CoverageCanvasNode } from './telemetry/coverage';
21
23
  export { generateTypes, TypeScriptGenerator, generatorRegistry } from './codegen/type-generator';
22
24
  export type { CodegenOptions, CodegenResult, CodeGenerator } from './codegen/type-generator';
23
25
  export { traceToCanvas, traceToCanvasJson } from './utils/TraceToCanvas';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,cAAc,SAAS,CAAC;AAGxB,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,YAAY,EACV,4BAA4B,EAC5B,6BAA6B,GAC9B,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EAAE,0BAA0B,EAAE,MAAM,sCAAsC,CAAC;AAGlF,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACpE,YAAY,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAG1D,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAGxD,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAG5E,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAC3G,YAAY,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAGpE,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AACjG,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAG7F,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AACzE,YAAY,EACV,SAAS,EACT,WAAW,EACX,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,YAAY,EACV,aAAa,EACb,aAAa,EACb,eAAe,EACf,YAAY,EACZ,oBAAoB,EACpB,iBAAiB,EACjB,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,YAAY,EACV,mBAAmB,EACnB,eAAe,EACf,mBAAmB,EACnB,iBAAiB,EACjB,UAAU,EACV,eAAe,EACf,WAAW,EACX,WAAW,EACX,YAAY,EACZ,UAAU,EACV,eAAe,EACf,eAAe,EACf,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,eAAe,EACf,0BAA0B,GAC3B,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,YAAY,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AACxF,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AACtF,YAAY,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAG1D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAGrF,YAAY,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AAC9E,OAAO,EAAE,yBAAyB,EAAE,MAAM,sCAAsC,CAAC;AAGjF,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,cAAc,SAAS,CAAC;AAGxB,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,YAAY,EACV,4BAA4B,EAC5B,6BAA6B,GAC9B,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EAAE,0BAA0B,EAAE,MAAM,sCAAsC,CAAC;AAGlF,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACpE,YAAY,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAG1D,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAGxD,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAG5E,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAC3G,YAAY,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAGpE,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,UAAU,IAAI,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAG5G,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AACjG,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAG7F,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AACzE,YAAY,EACV,SAAS,EACT,WAAW,EACX,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,YAAY,EACV,aAAa,EACb,aAAa,EACb,eAAe,EACf,YAAY,EACZ,oBAAoB,EACpB,iBAAiB,EACjB,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,YAAY,EACV,mBAAmB,EACnB,eAAe,EACf,mBAAmB,EACnB,iBAAiB,EACjB,UAAU,EACV,eAAe,EACf,WAAW,EACX,WAAW,EACX,YAAY,EACZ,UAAU,EACV,eAAe,EACf,eAAe,EACf,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,eAAe,EACf,0BAA0B,GAC3B,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,YAAY,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AACxF,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AACtF,YAAY,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAG1D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAGrF,YAAY,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AAC9E,OAAO,EAAE,yBAAyB,EAAE,MAAM,sCAAsC,CAAC;AAGjF,cAAc,SAAS,CAAC"}
package/dist/index.js CHANGED
@@ -20,6 +20,8 @@ export * from './types/canvas';
20
20
  export { CanvasConverter } from './utils/CanvasConverter';
21
21
  // Export telemetry event validation
22
22
  export { EventValidator, createValidatedEmitter, EventValidationError } from './telemetry/event-validator';
23
+ // Export telemetry coverage analysis
24
+ export { analyzeCoverage } from './telemetry/coverage';
23
25
  // Export code generation
24
26
  export { generateTypes, TypeScriptGenerator, generatorRegistry } from './codegen/type-generator';
25
27
  // Export trace-to-canvas conversion
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,mBAAmB;AACnB,cAAc,SAAS,CAAC;AAExB,sBAAsB;AACtB,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAGlD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAMlE,iBAAiB;AACjB,OAAO,EAAE,0BAA0B,EAAE,MAAM,sCAAsC,CAAC;AAElF,iDAAiD;AACjD,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAGpE,wBAAwB;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,oCAAoC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAG1D,oCAAoC;AACpC,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAG3G,yBAAyB;AACzB,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAGjG,oCAAoC;AACpC,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAQzE,qDAAqD;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAYlD,gCAAgC;AAChC,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAqB9D,+DAA+D;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAGtF,mCAAmC;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAK5D,OAAO,EAAE,yBAAyB,EAAE,MAAM,sCAAsC,CAAC;AAEjF,sBAAsB;AACtB,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,mBAAmB;AACnB,cAAc,SAAS,CAAC;AAExB,sBAAsB;AACtB,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAGlD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAMlE,iBAAiB;AACjB,OAAO,EAAE,0BAA0B,EAAE,MAAM,sCAAsC,CAAC;AAElF,iDAAiD;AACjD,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAGpE,wBAAwB;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,oCAAoC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAG1D,oCAAoC;AACpC,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAG3G,qCAAqC;AACrC,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAGvD,yBAAyB;AACzB,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAGjG,oCAAoC;AACpC,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAQzE,qDAAqD;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAYlD,gCAAgC;AAChC,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAqB9D,+DAA+D;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAGtF,mCAAmC;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAK5D,OAAO,EAAE,yBAAyB,EAAE,MAAM,sCAAsC,CAAC;AAEjF,sBAAsB;AACtB,cAAc,SAAS,CAAC"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Telemetry Coverage Analysis
3
+ *
4
+ * Measures observability coverage by analyzing which canvas nodes have
5
+ * OpenTelemetry instrumentation in their source files.
6
+ */
7
+ export interface CanvasNode {
8
+ id: string;
9
+ text?: string;
10
+ anchors?: Array<{
11
+ path?: string;
12
+ }>;
13
+ [key: string]: any;
14
+ }
15
+ export interface Canvas {
16
+ nodes?: CanvasNode[];
17
+ [key: string]: any;
18
+ }
19
+ export interface NodeCoverage {
20
+ nodeId: string;
21
+ filePaths: string[];
22
+ hasInstrumentation: boolean;
23
+ instrumentedFiles: string[];
24
+ missingFiles: string[];
25
+ }
26
+ export interface CoverageMetrics {
27
+ totalNodes: number;
28
+ nodesWithFiles: number;
29
+ nodesWithInstrumentation: number;
30
+ coveragePercentage: number;
31
+ nodeCoverage: NodeCoverage[];
32
+ canvasFiles: string[];
33
+ }
34
+ /**
35
+ * Generate telemetry coverage report from canvas files
36
+ */
37
+ export declare function analyzeCoverage(rootDir: string): Promise<CoverageMetrics>;
38
+ //# sourceMappingURL=coverage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coverage.d.ts","sourceRoot":"","sources":["../../src/telemetry/coverage.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,MAAM;IACrB,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC;IACrB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,wBAAwB,EAAE,MAAM,CAAC;IACjC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,YAAY,EAAE,YAAY,EAAE,CAAC;IAC7B,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAmFD;;GAEG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAqC/E"}
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Telemetry Coverage Analysis
3
+ *
4
+ * Measures observability coverage by analyzing which canvas nodes have
5
+ * OpenTelemetry instrumentation in their source files.
6
+ */
7
+ import { readFile, access } from 'fs/promises';
8
+ import { resolve } from 'path';
9
+ import { glob } from 'glob';
10
+ /**
11
+ * Extract file paths from a canvas node anchors (REQUIRED)
12
+ */
13
+ function extractFilePaths(node) {
14
+ const paths = [];
15
+ if (node.anchors) {
16
+ for (const anchor of node.anchors) {
17
+ if (anchor.path) {
18
+ paths.push(anchor.path);
19
+ }
20
+ }
21
+ }
22
+ return paths;
23
+ }
24
+ /**
25
+ * Check if a file has OpenTelemetry instrumentation
26
+ */
27
+ async function hasInstrumentation(filePath) {
28
+ try {
29
+ const content = await readFile(filePath, 'utf-8');
30
+ const hasOtelImport = content.includes('@opentelemetry/api');
31
+ const hasTracer = /getTracer|startSpan|addEvent/.test(content);
32
+ const hasTestOtel = /['"]\.\.?\/.*test\/otel-setup['"]/.test(content);
33
+ return hasOtelImport || hasTracer || hasTestOtel;
34
+ }
35
+ catch {
36
+ return false;
37
+ }
38
+ }
39
+ /**
40
+ * Check if file exists
41
+ */
42
+ async function fileExists(filePath) {
43
+ try {
44
+ await access(filePath);
45
+ return true;
46
+ }
47
+ catch {
48
+ return false;
49
+ }
50
+ }
51
+ /**
52
+ * Analyze coverage for a single canvas node
53
+ */
54
+ async function analyzeNodeCoverage(node, rootDir) {
55
+ const filePaths = extractFilePaths(node);
56
+ const instrumentedFiles = [];
57
+ const missingFiles = [];
58
+ for (const path of filePaths) {
59
+ const fullPath = resolve(rootDir, path);
60
+ const exists = await fileExists(fullPath);
61
+ if (!exists) {
62
+ missingFiles.push(path);
63
+ continue;
64
+ }
65
+ const instrumented = await hasInstrumentation(fullPath);
66
+ if (instrumented) {
67
+ instrumentedFiles.push(path);
68
+ }
69
+ }
70
+ return {
71
+ nodeId: node.id,
72
+ filePaths,
73
+ hasInstrumentation: instrumentedFiles.length > 0,
74
+ instrumentedFiles,
75
+ missingFiles
76
+ };
77
+ }
78
+ /**
79
+ * Generate telemetry coverage report from canvas files
80
+ */
81
+ export async function analyzeCoverage(rootDir) {
82
+ const canvasFiles = await glob('**/*.otel.canvas', {
83
+ cwd: rootDir,
84
+ absolute: true,
85
+ dot: true,
86
+ ignore: ['**/node_modules/**']
87
+ });
88
+ const allNodeCoverage = [];
89
+ for (const canvasFile of canvasFiles) {
90
+ const content = await readFile(canvasFile, 'utf-8');
91
+ const canvas = JSON.parse(content);
92
+ if (!canvas.nodes || canvas.nodes.length === 0) {
93
+ continue;
94
+ }
95
+ for (const node of canvas.nodes) {
96
+ const coverage = await analyzeNodeCoverage(node, rootDir);
97
+ allNodeCoverage.push(coverage);
98
+ }
99
+ }
100
+ const nodesWithFiles = allNodeCoverage.filter(n => n.filePaths.length > 0);
101
+ const nodesWithInstrumentation = allNodeCoverage.filter(n => n.hasInstrumentation);
102
+ return {
103
+ totalNodes: allNodeCoverage.length,
104
+ nodesWithFiles: nodesWithFiles.length,
105
+ nodesWithInstrumentation: nodesWithInstrumentation.length,
106
+ coveragePercentage: nodesWithFiles.length > 0
107
+ ? (nodesWithInstrumentation.length / nodesWithFiles.length) * 100
108
+ : 0,
109
+ nodeCoverage: allNodeCoverage,
110
+ canvasFiles: canvasFiles.map(f => f.replace(rootDir + '/', ''))
111
+ };
112
+ }
113
+ //# sourceMappingURL=coverage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coverage.js","sourceRoot":"","sources":["../../src/telemetry/coverage.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@principal-ai/principal-view-core",
3
- "version": "0.5.16",
3
+ "version": "0.5.17",
4
4
  "description": "Core logic and types for graph-based principal view framework",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
package/src/index.ts CHANGED
@@ -38,6 +38,10 @@ export type { ReactFlowNode, ReactFlowEdge } from './utils/CanvasConverter';
38
38
  export { EventValidator, createValidatedEmitter, EventValidationError } from './telemetry/event-validator';
39
39
  export type { ValidationResult } from './telemetry/event-validator';
40
40
 
41
+ // Export telemetry coverage analysis
42
+ export { analyzeCoverage } from './telemetry/coverage';
43
+ export type { CoverageMetrics, NodeCoverage, CanvasNode as CoverageCanvasNode } from './telemetry/coverage';
44
+
41
45
  // Export code generation
42
46
  export { generateTypes, TypeScriptGenerator, generatorRegistry } from './codegen/type-generator';
43
47
  export type { CodegenOptions, CodegenResult, CodeGenerator } from './codegen/type-generator';
@@ -0,0 +1,162 @@
1
+ /**
2
+ * Telemetry Coverage Analysis
3
+ *
4
+ * Measures observability coverage by analyzing which canvas nodes have
5
+ * OpenTelemetry instrumentation in their source files.
6
+ */
7
+
8
+ import { readFile, access } from 'fs/promises';
9
+ import { resolve } from 'path';
10
+ import { glob } from 'glob';
11
+
12
+ export interface CanvasNode {
13
+ id: string;
14
+ text?: string;
15
+ anchors?: Array<{ path?: string }>;
16
+ [key: string]: any;
17
+ }
18
+
19
+ export interface Canvas {
20
+ nodes?: CanvasNode[];
21
+ [key: string]: any;
22
+ }
23
+
24
+ export interface NodeCoverage {
25
+ nodeId: string;
26
+ filePaths: string[];
27
+ hasInstrumentation: boolean;
28
+ instrumentedFiles: string[];
29
+ missingFiles: string[];
30
+ }
31
+
32
+ export interface CoverageMetrics {
33
+ totalNodes: number;
34
+ nodesWithFiles: number;
35
+ nodesWithInstrumentation: number;
36
+ coveragePercentage: number;
37
+ nodeCoverage: NodeCoverage[];
38
+ canvasFiles: string[];
39
+ }
40
+
41
+ /**
42
+ * Extract file paths from a canvas node anchors (REQUIRED)
43
+ */
44
+ function extractFilePaths(node: CanvasNode): string[] {
45
+ const paths: string[] = [];
46
+
47
+ if (node.anchors) {
48
+ for (const anchor of node.anchors) {
49
+ if (anchor.path) {
50
+ paths.push(anchor.path);
51
+ }
52
+ }
53
+ }
54
+
55
+ return paths;
56
+ }
57
+
58
+ /**
59
+ * Check if a file has OpenTelemetry instrumentation
60
+ */
61
+ async function hasInstrumentation(filePath: string): Promise<boolean> {
62
+ try {
63
+ const content = await readFile(filePath, 'utf-8');
64
+
65
+ const hasOtelImport = content.includes('@opentelemetry/api');
66
+ const hasTracer = /getTracer|startSpan|addEvent/.test(content);
67
+ const hasTestOtel = /['"]\.\.?\/.*test\/otel-setup['"]/.test(content);
68
+
69
+ return hasOtelImport || hasTracer || hasTestOtel;
70
+ } catch {
71
+ return false;
72
+ }
73
+ }
74
+
75
+ /**
76
+ * Check if file exists
77
+ */
78
+ async function fileExists(filePath: string): Promise<boolean> {
79
+ try {
80
+ await access(filePath);
81
+ return true;
82
+ } catch {
83
+ return false;
84
+ }
85
+ }
86
+
87
+ /**
88
+ * Analyze coverage for a single canvas node
89
+ */
90
+ async function analyzeNodeCoverage(
91
+ node: CanvasNode,
92
+ rootDir: string
93
+ ): Promise<NodeCoverage> {
94
+ const filePaths = extractFilePaths(node);
95
+ const instrumentedFiles: string[] = [];
96
+ const missingFiles: string[] = [];
97
+
98
+ for (const path of filePaths) {
99
+ const fullPath = resolve(rootDir, path);
100
+ const exists = await fileExists(fullPath);
101
+
102
+ if (!exists) {
103
+ missingFiles.push(path);
104
+ continue;
105
+ }
106
+
107
+ const instrumented = await hasInstrumentation(fullPath);
108
+ if (instrumented) {
109
+ instrumentedFiles.push(path);
110
+ }
111
+ }
112
+
113
+ return {
114
+ nodeId: node.id,
115
+ filePaths,
116
+ hasInstrumentation: instrumentedFiles.length > 0,
117
+ instrumentedFiles,
118
+ missingFiles
119
+ };
120
+ }
121
+
122
+ /**
123
+ * Generate telemetry coverage report from canvas files
124
+ */
125
+ export async function analyzeCoverage(rootDir: string): Promise<CoverageMetrics> {
126
+ const canvasFiles = await glob('**/*.otel.canvas', {
127
+ cwd: rootDir,
128
+ absolute: true,
129
+ dot: true,
130
+ ignore: ['**/node_modules/**']
131
+ });
132
+
133
+ const allNodeCoverage: NodeCoverage[] = [];
134
+
135
+ for (const canvasFile of canvasFiles) {
136
+ const content = await readFile(canvasFile, 'utf-8');
137
+ const canvas: Canvas = JSON.parse(content);
138
+
139
+ if (!canvas.nodes || canvas.nodes.length === 0) {
140
+ continue;
141
+ }
142
+
143
+ for (const node of canvas.nodes) {
144
+ const coverage = await analyzeNodeCoverage(node, rootDir);
145
+ allNodeCoverage.push(coverage);
146
+ }
147
+ }
148
+
149
+ const nodesWithFiles = allNodeCoverage.filter(n => n.filePaths.length > 0);
150
+ const nodesWithInstrumentation = allNodeCoverage.filter(n => n.hasInstrumentation);
151
+
152
+ return {
153
+ totalNodes: allNodeCoverage.length,
154
+ nodesWithFiles: nodesWithFiles.length,
155
+ nodesWithInstrumentation: nodesWithInstrumentation.length,
156
+ coveragePercentage: nodesWithFiles.length > 0
157
+ ? (nodesWithInstrumentation.length / nodesWithFiles.length) * 100
158
+ : 0,
159
+ nodeCoverage: allNodeCoverage,
160
+ canvasFiles: canvasFiles.map(f => f.replace(rootDir + '/', ''))
161
+ };
162
+ }
@@ -9,6 +9,8 @@ import {
9
9
  markTestFailed,
10
10
  setSpanAttribute,
11
11
  exportSpans,
12
+ log,
13
+ recordLog,
12
14
  } from '../../test/otel-setup';
13
15
 
14
16
  describe('GraphConverter', () => {
@@ -24,11 +26,25 @@ describe('GraphConverter', () => {
24
26
  });
25
27
 
26
28
  try {
29
+ // TRACE log at test start (automatically correlated with testSpan)
30
+ log('TRACE', 'Entering test case for simple config conversion', {
31
+ 'service.name': 'graph-converter-service',
32
+ 'service.version': '1.0.0',
33
+ });
34
+
27
35
  // Setup - record as event
28
36
  addEvent(testSpan, 'setup.started', {
29
37
  description: 'Creating test configuration with 2 nodes and 1 edge',
30
38
  });
31
39
 
40
+ // INFO log during setup
41
+ log('INFO', 'Initializing test configuration', {
42
+ 'service.name': 'graph-converter-service',
43
+ }, {
44
+ 'config.nodeCount': 2,
45
+ 'config.edgeCount': 1,
46
+ });
47
+
32
48
  const config: PathBasedGraphConfiguration = {
33
49
  metadata: {
34
50
  name: 'Test Config',
@@ -70,6 +86,15 @@ describe('GraphConverter', () => {
70
86
  'config.edges': 1,
71
87
  });
72
88
 
89
+ // DEBUG log with structured data after setup
90
+ log('DEBUG', {
91
+ phase: 'setup-complete',
92
+ nodeTypes: Object.keys(config.nodeTypes),
93
+ edgeTypes: Object.keys(config.edgeTypes),
94
+ }, {
95
+ 'service.name': 'graph-converter-service',
96
+ });
97
+
73
98
  // Execution - record as event
74
99
  // Note: execution happens in GraphConverter.ts, not the test file
75
100
  addEvent(testSpan, 'execution.started', {
@@ -78,8 +103,25 @@ describe('GraphConverter', () => {
78
103
  'code.lineno': 15,
79
104
  });
80
105
 
106
+ // INFO log before conversion
107
+ log('INFO', 'Starting graph conversion process', {
108
+ 'service.name': 'graph-converter-service',
109
+ }, {
110
+ 'operation': 'configToGraph',
111
+ 'inputSize.bytes': JSON.stringify(config).length,
112
+ });
113
+
81
114
  const result = GraphConverter.configToGraph(config);
82
115
 
116
+ // DEBUG log after conversion with result details
117
+ log('DEBUG', 'Conversion completed successfully', {
118
+ 'service.name': 'graph-converter-service',
119
+ }, {
120
+ 'output.nodeCount': result.nodes.length,
121
+ 'output.edgeCount': result.edges.length,
122
+ 'processingTime.ms': 5,
123
+ });
124
+
83
125
  addEvent(testSpan, 'execution.complete', {
84
126
  'result.nodes.count': result.nodes.length,
85
127
  'result.edges.count': result.edges.length,
@@ -92,6 +134,13 @@ describe('GraphConverter', () => {
92
134
  assertions: 'Verifying nodes and edges structure',
93
135
  });
94
136
 
137
+ // INFO log at assertion phase
138
+ log('INFO', 'Running assertions on converted graph', {
139
+ 'service.name': 'graph-converter-service',
140
+ }, {
141
+ 'totalAssertions': 11,
142
+ });
143
+
95
144
  expect(result.nodes).toHaveLength(2);
96
145
  expect(result.edges).toHaveLength(1);
97
146
 
@@ -116,8 +165,24 @@ describe('GraphConverter', () => {
116
165
  'assertions.failed': 0,
117
166
  });
118
167
 
168
+ // INFO log on successful test completion
169
+ log('INFO', 'All assertions passed - test successful', {
170
+ 'service.name': 'graph-converter-service',
171
+ }, {
172
+ 'test.status': 'passed',
173
+ 'test.duration.ms': Date.now() - testSpan.startTime,
174
+ });
175
+
119
176
  markTestPassed(testSpan);
120
177
  } catch (error) {
178
+ // ERROR log on failure
179
+ log('ERROR', `Test failed: ${(error as Error).message}`, {
180
+ 'service.name': 'graph-converter-service',
181
+ }, {
182
+ 'test.status': 'failed',
183
+ 'error.type': (error as Error).name,
184
+ });
185
+
121
186
  addEvent(testSpan, 'test.failed', {
122
187
  error: (error as Error).message,
123
188
  });
@@ -125,6 +190,20 @@ describe('GraphConverter', () => {
125
190
  throw error;
126
191
  } finally {
127
192
  endSpan(testSpan);
193
+
194
+ // Uncorrelated log after span ends (simulating cleanup/background task)
195
+ recordLog({
196
+ severity: 'DEBUG',
197
+ body: 'Test cleanup completed',
198
+ resource: {
199
+ 'service.name': 'test-cleanup-service',
200
+ 'cleanup.type': 'post-test',
201
+ },
202
+ attributes: {
203
+ 'test.name': 'should convert simple config to nodes and edges',
204
+ },
205
+ // No traceId/spanId - this is an uncorrelated log
206
+ });
128
207
  }
129
208
  });
130
209