@corva/ui 3.54.0-21 → 3.54.0-22

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.
@@ -11,9 +11,10 @@ import { randomUUID } from 'crypto';
11
11
  import { Resource } from '@opentelemetry/resources';
12
12
  import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions';
13
13
  import { readFile } from 'fs/promises';
14
- import { join as join$1, dirname } from 'path';
14
+ import { join as join$1, dirname, resolve } from 'path';
15
15
  import { fileURLToPath } from 'url';
16
16
  import { z } from 'zod';
17
+ import { readFileSync } from 'fs';
17
18
 
18
19
  const LOG_SYMBOLS = {
19
20
  success: '✓',
@@ -227,7 +228,7 @@ const validateDsn = (dsn) => {
227
228
 
228
229
  const MCP_SERVER_VERSION = '1.1.0';
229
230
 
230
- var version = "3.54.0-21";
231
+ var version = "3.54.0-22";
231
232
 
232
233
  const CORVA_UI_VERSION = version;
233
234
 
@@ -268,16 +269,24 @@ const createMetricsClient = (meter) => {
268
269
  recordToolEmptyResult: toolName => {
269
270
  emptyResultCounter.add(1, { 'gen_ai.tool.name': toolName });
270
271
  },
271
- recordSession: (clientName, clientVersion) => {
272
+ recordSession: (clientName, clientVersion, projectIdentity) => {
272
273
  sessionCounter.add(1, {
273
274
  'mcp.client.name': clientName || UNKNOWN_CLIENT_ATTR,
274
275
  'mcp.client.version': clientVersion || UNKNOWN_CLIENT_ATTR,
276
+ ...(projectIdentity?.appKey ? { 'corva.app.key': projectIdentity.appKey } : {}),
277
+ ...(projectIdentity?.packageName
278
+ ? { 'corva.package.name': projectIdentity.packageName }
279
+ : {}),
275
280
  });
276
281
  },
277
- recordSessionEnd: (durationMs, toolCount, clientName, clientVersion) => {
282
+ recordSessionEnd: (durationMs, toolCount, clientName, clientVersion, projectIdentity) => {
278
283
  const attrs = {
279
284
  'mcp.client.name': clientName || UNKNOWN_CLIENT_ATTR,
280
285
  'mcp.client.version': clientVersion || UNKNOWN_CLIENT_ATTR,
286
+ ...(projectIdentity?.appKey ? { 'corva.app.key': projectIdentity.appKey } : {}),
287
+ ...(projectIdentity?.packageName
288
+ ? { 'corva.package.name': projectIdentity.packageName }
289
+ : {}),
281
290
  };
282
291
  sessionDuration.record(durationMs, attrs);
283
292
  sessionToolCount.record(toolCount, attrs);
@@ -375,6 +384,12 @@ const recordInitSpan = (tracer, attrs) => {
375
384
  if (attrs.networkTransport) {
376
385
  span.setAttribute('network.transport', attrs.networkTransport);
377
386
  }
387
+ if (attrs.appKey) {
388
+ span.setAttribute('corva.app.key', attrs.appKey);
389
+ }
390
+ if (attrs.packageName) {
391
+ span.setAttribute('corva.package.name', attrs.packageName);
392
+ }
378
393
  }
379
394
  finally {
380
395
  span.end();
@@ -94844,7 +94859,7 @@ const formatBytes = (bytes) => {
94844
94859
  return `${mb.toFixed(1)} MB`;
94845
94860
  };
94846
94861
  const formatConfigSource = (source) => source === 'local' ? 'Local file' : 'Remote endpoint';
94847
- const handleGetDiagnostics = (stats, telemetry) => {
94862
+ const handleGetDiagnostics = (stats, telemetry, identity) => {
94848
94863
  const { heapUsed, heapTotal, rss } = process.memoryUsage();
94849
94864
  const uptimeMs = Date.now() - stats.startTime;
94850
94865
  let text = h1('MCP Server Diagnostics');
@@ -94877,11 +94892,82 @@ const handleGetDiagnostics = (stats, telemetry) => {
94877
94892
  else {
94878
94893
  text += `${bold('Status')}: Disabled\n`;
94879
94894
  }
94895
+ text += h2('Project Identity');
94896
+ text += `${bold('App key')}: ${identity?.appKey ?? 'N/A'}\n`;
94897
+ text += `${bold('Package name')}: ${identity?.packageName ?? 'N/A'}\n`;
94880
94898
  return {
94881
94899
  response: createToolResponse(text),
94882
94900
  };
94883
94901
  };
94884
94902
 
94903
+ const readJsonField = (filePath, ...keys) => {
94904
+ try {
94905
+ let value = JSON.parse(readFileSync(filePath, 'utf-8'));
94906
+ for (const key of keys) {
94907
+ if (value && typeof value === 'object') {
94908
+ value = value[key];
94909
+ }
94910
+ else {
94911
+ return null;
94912
+ }
94913
+ }
94914
+ return typeof value === 'string' && value ? value : null;
94915
+ }
94916
+ catch {
94917
+ return null;
94918
+ }
94919
+ };
94920
+ const findUpJsonField = (startDir, fileName, ...keys) => {
94921
+ let dir = resolve(startDir);
94922
+ for (;;) {
94923
+ const value = readJsonField(join$1(dir, fileName), ...keys);
94924
+ if (value) {
94925
+ return value;
94926
+ }
94927
+ const parent = dirname(dir);
94928
+ if (parent === dir) {
94929
+ return null;
94930
+ }
94931
+ dir = parent;
94932
+ }
94933
+ };
94934
+ const getProjectIdentityAttrs = (identity) => {
94935
+ const attrs = {};
94936
+ if (identity?.appKey) {
94937
+ attrs['corva.app.key'] = identity.appKey;
94938
+ }
94939
+ if (identity?.packageName) {
94940
+ attrs['corva.package.name'] = identity.packageName;
94941
+ }
94942
+ return attrs;
94943
+ };
94944
+ const resolveProjectIdentity = async (server, logger) => {
94945
+ const empty = { appKey: null, packageName: null };
94946
+ try {
94947
+ const capabilities = server.getClientCapabilities();
94948
+ if (!capabilities?.roots) {
94949
+ return empty;
94950
+ }
94951
+ const { roots } = await server.listRoots();
94952
+ if (!roots.length) {
94953
+ return empty;
94954
+ }
94955
+ const rootPath = fileURLToPath(roots[0].uri);
94956
+ const appKey = findUpJsonField(rootPath, 'manifest.json', 'application', 'key');
94957
+ const packageName = findUpJsonField(rootPath, 'package.json', 'name');
94958
+ if (appKey) {
94959
+ logger.info(`Consuming app: ${appKey}`);
94960
+ }
94961
+ if (packageName) {
94962
+ logger.info(`Consuming package: ${packageName}`);
94963
+ }
94964
+ return { appKey, packageName };
94965
+ }
94966
+ catch {
94967
+ return empty;
94968
+ }
94969
+ };
94970
+
94885
94971
  class CorvaUiMcpServer {
94886
94972
  server;
94887
94973
  mcpLogger;
@@ -94894,6 +94980,8 @@ class CorvaUiMcpServer {
94894
94980
  telemetryInitPromise = null;
94895
94981
  shutdownRequested = false;
94896
94982
  pendingInitData = null;
94983
+ projectIdentity = null;
94984
+ identityPromise = null;
94897
94985
  constructor() {
94898
94986
  const baseLogger = createLogger({ prefix: '[CorvaUI MCP]' });
94899
94987
  this.mcpLogger = createMcpNotificationLogger(baseLogger, () => this.isConnected ? this.server : null);
@@ -94926,7 +95014,16 @@ class CorvaUiMcpServer {
94926
95014
  if (clientInfo?.name) {
94927
95015
  this.mcpLogger.info(`Client connected: ${clientInfo.name}${clientInfo.version ? ` v${clientInfo.version}` : ''}`);
94928
95016
  }
94929
- this.flushPendingInitData();
95017
+ this.identityPromise = resolveProjectIdentity(this.server.server, this.mcpLogger)
95018
+ .then(identity => {
95019
+ this.projectIdentity = identity;
95020
+ })
95021
+ .catch(error => {
95022
+ this.mcpLogger.error('Failed to resolve project identity', error);
95023
+ })
95024
+ .finally(() => {
95025
+ this.flushPendingInitData();
95026
+ });
94930
95027
  };
94931
95028
  }
94932
95029
  flushPendingInitData() {
@@ -94979,6 +95076,7 @@ class CorvaUiMcpServer {
94979
95076
  extraAttrs: {
94980
95077
  ...serializedResult.extraAttrs,
94981
95078
  ...getSpanAttributes?.(result),
95079
+ ...getProjectIdentityAttrs(this.projectIdentity),
94982
95080
  },
94983
95081
  });
94984
95082
  this.telemetry.metrics.recordToolInvocation(toolName, ms);
@@ -95010,7 +95108,10 @@ class CorvaUiMcpServer {
95010
95108
  protocolVersion: MCP_PROTOCOL_VERSION,
95011
95109
  networkTransport: MCP_NETWORK_TRANSPORT,
95012
95110
  parentContext,
95013
- extraAttrs: serializedError.extraAttrs,
95111
+ extraAttrs: {
95112
+ ...serializedError.extraAttrs,
95113
+ ...getProjectIdentityAttrs(this.projectIdentity),
95114
+ },
95014
95115
  });
95015
95116
  this.telemetry.metrics.recordToolInvocation(toolName, ms);
95016
95117
  this.telemetry.metrics.recordToolError(toolName, serializedError.errorType);
@@ -95150,7 +95251,7 @@ class CorvaUiMcpServer {
95150
95251
  }, (extra) => {
95151
95252
  const parentContext = extractContextFromMeta(extra?._meta);
95152
95253
  try {
95153
- return this.executeToolWithObservability(diagnosticsToolName, {}, () => handleGetDiagnostics(this.getStats(), this.getTelemetryStatus()), () => 'ok', { parentContext });
95254
+ return this.executeToolWithObservability(diagnosticsToolName, {}, () => handleGetDiagnostics(this.getStats(), this.getTelemetryStatus(), this.projectIdentity), () => 'ok', { parentContext });
95154
95255
  }
95155
95256
  catch (error) {
95156
95257
  return createErrorResponse(`Error: ${error instanceof Error ? error.message : String(error)}`);
@@ -95185,10 +95286,13 @@ class CorvaUiMcpServer {
95185
95286
  if (this.telemetryInitPromise) {
95186
95287
  await withTimeout(this.telemetryInitPromise, TELEMETRY_INIT_TIMEOUT_MS);
95187
95288
  }
95289
+ if (this.identityPromise) {
95290
+ await withTimeout(this.identityPromise, TELEMETRY_INIT_TIMEOUT_MS);
95291
+ }
95188
95292
  if (this.telemetry.isEnabled()) {
95189
95293
  const sessionDurationMs = Date.now() - this.startTime;
95190
95294
  const clientInfo = this.server.server.getClientVersion();
95191
- this.telemetry.metrics.recordSessionEnd(sessionDurationMs, this.requestCount, clientInfo?.name, clientInfo?.version);
95295
+ this.telemetry.metrics.recordSessionEnd(sessionDurationMs, this.requestCount, clientInfo?.name, clientInfo?.version, this.projectIdentity);
95192
95296
  }
95193
95297
  if (this.transport) {
95194
95298
  await this.server.close();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@corva/ui",
3
- "version": "3.54.0-21",
3
+ "version": "3.54.0-22",
4
4
  "license": "SEE LICENSE IN LICENSE",
5
5
  "description": "Shared components/utils for Corva ui projects",
6
6
  "keywords": [