@topolo/sdk 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -3321,7 +3321,7 @@ var TopoloOAuth = class {
3321
3321
  };
3322
3322
 
3323
3323
  // src/widget-validation.ts
3324
- var CONTRACT_VERSION = "2.0.0";
3324
+ var CONTRACT_VERSION = "3.0.0";
3325
3325
  var WIDGET_TYPES = ["stats", "chart", "activity", "notifications", "actions"];
3326
3326
  var CONTEXTS = ["personal", "organization", "workspace", "resource"];
3327
3327
  var SIZES = ["compact", "medium", "wide", "full"];
@@ -3332,6 +3332,9 @@ var AGGREGATIONS = ["last", "sum", "average", "minimum", "maximum", "count", "di
3332
3332
  var CHART_TYPES = ["line", "bar", "area", "pie", "donut"];
3333
3333
  var SEVERITIES = ["info", "warning", "error", "success"];
3334
3334
  var RECOVERY_MODES = ["not_applicable", "retry", "compensating_action"];
3335
+ var VISUALIZATION_FAMILIES = ["number", "line", "area", "bar", "donut", "table", "funnel", "timeline", "actions"];
3336
+ var WORKSPACE_SELECTOR_MODES = ["none", "optional", "required"];
3337
+ var DIMENSION_VALUE_TYPES = ["string", "number", "boolean", "date", "datetime"];
3335
3338
  var SEMVER = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
3336
3339
  function validateTopoloWidgetResponse(response) {
3337
3340
  const errors = [];
@@ -3382,6 +3385,7 @@ function validateWidget(value, path, errors) {
3382
3385
  validateActions(value.controls, `${path}.controls`, errors);
3383
3386
  validateLocalization(value.localization, `${path}.localization`, errors);
3384
3387
  validateAccessibility(value.accessibility, `${path}.accessibility`, errors);
3388
+ validateContribution(value.contribution, `${path}.contribution`, value, errors);
3385
3389
  switch (value.type) {
3386
3390
  case "stats":
3387
3391
  validateMetrics(value.metrics, `${path}.metrics`, errors, requiresContent(value));
@@ -3519,6 +3523,208 @@ function validateAccessibility(value, path, errors) {
3519
3523
  nonEmptyString(value.label, `${path}.label`, errors);
3520
3524
  optionalNonEmptyString(value.description, `${path}.description`, errors);
3521
3525
  }
3526
+ function validateContribution(value, path, widget, errors) {
3527
+ if (!recordValue(value, path, errors)) return;
3528
+ nonEmptyString(value.summary, `${path}.summary`, errors);
3529
+ if (recordValue(value.identity, `${path}.identity`, errors)) {
3530
+ exactValue(value.identity.iconSource, "catalog", `${path}.identity.iconSource`, errors);
3531
+ }
3532
+ if (recordValue(value.workspaceSelector, `${path}.workspaceSelector`, errors)) {
3533
+ enumValue(value.workspaceSelector.mode, WORKSPACE_SELECTOR_MODES, `${path}.workspaceSelector.mode`, errors);
3534
+ nonEmptyString(value.workspaceSelector.resourceType, `${path}.workspaceSelector.resourceType`, errors);
3535
+ nonEmptyString(value.workspaceSelector.label, `${path}.workspaceSelector.label`, errors);
3536
+ booleanValue(value.workspaceSelector.supportsMultiple, `${path}.workspaceSelector.supportsMultiple`, errors);
3537
+ if (value.workspaceSelector.mode === "required" && requiresContent(widget) && isRecord5(widget.resource) && typeof widget.resource.resourceId !== "string") {
3538
+ errors.push(`${path}.workspaceSelector requires a bound resourceId for ready or stale data`);
3539
+ }
3540
+ }
3541
+ const metricKeys = validateMetricDefinitions(value.metricDefinitions, `${path}.metricDefinitions`, errors);
3542
+ const seriesKeys = validateSeriesDefinitions(value.seriesDefinitions, `${path}.seriesDefinitions`, metricKeys, errors);
3543
+ const dimensionKeys = validateDimensionDefinitions(value.dimensions, `${path}.dimensions`, errors);
3544
+ const lifecycleKeys = validateLifecycleStages(value.lifecycleStages, `${path}.lifecycleStages`, errors);
3545
+ const eventKeys = validateEventDefinitions(value.events, `${path}.events`, errors);
3546
+ const actionKeys = widgetActionKeys(widget);
3547
+ validateDatasets(value.datasets, `${path}.datasets`, {
3548
+ metricKeys,
3549
+ seriesKeys,
3550
+ dimensionKeys,
3551
+ eventKeys,
3552
+ actionKeys
3553
+ }, errors);
3554
+ enumArray(
3555
+ value.compatibleVisualizations,
3556
+ VISUALIZATION_FAMILIES,
3557
+ `${path}.compatibleVisualizations`,
3558
+ errors,
3559
+ true
3560
+ );
3561
+ enumValue(value.defaultVisualization, VISUALIZATION_FAMILIES, `${path}.defaultVisualization`, errors);
3562
+ if (typeof value.defaultVisualization === "string" && Array.isArray(value.compatibleVisualizations) && !value.compatibleVisualizations.includes(value.defaultVisualization)) {
3563
+ errors.push(`${path}.defaultVisualization must be included in compatibleVisualizations`);
3564
+ }
3565
+ if (Array.isArray(value.compatibleVisualizations)) {
3566
+ for (const family of value.compatibleVisualizations) {
3567
+ if (family === "number" && metricKeys.size === 0) errors.push(`${path}.compatibleVisualizations number requires a metric definition`);
3568
+ if ((family === "line" || family === "area") && seriesKeys.size === 0) errors.push(`${path}.compatibleVisualizations ${family} requires a series definition`);
3569
+ if (family === "donut" && (metricKeys.size === 0 || dimensionKeys.size === 0)) errors.push(`${path}.compatibleVisualizations donut requires metric and dimension definitions`);
3570
+ if (family === "funnel" && lifecycleKeys.size < 2) errors.push(`${path}.compatibleVisualizations funnel requires at least two lifecycle stages`);
3571
+ if (family === "timeline" && eventKeys.size === 0) errors.push(`${path}.compatibleVisualizations timeline requires an event definition`);
3572
+ if (family === "actions" && actionKeys.size === 0) errors.push(`${path}.compatibleVisualizations actions requires a published action`);
3573
+ if (family === "bar" && metricKeys.size === 0 && seriesKeys.size === 0) errors.push(`${path}.compatibleVisualizations bar requires a metric or series definition`);
3574
+ }
3575
+ }
3576
+ validateRuntimeSemantics(widget, path, { metricKeys, seriesKeys, dimensionKeys }, errors);
3577
+ }
3578
+ function validateMetricDefinitions(value, path, errors) {
3579
+ const keys = /* @__PURE__ */ new Set();
3580
+ if (!arrayValue(value, path, errors)) return keys;
3581
+ value.forEach((definition, index) => {
3582
+ const itemPath = `${path}[${index}]`;
3583
+ if (!recordValue(definition, itemPath, errors)) return;
3584
+ nonEmptyString(definition.key, `${itemPath}.key`, errors);
3585
+ nonEmptyString(definition.label, `${itemPath}.label`, errors);
3586
+ nonEmptyString(definition.description, `${itemPath}.description`, errors);
3587
+ nonEmptyString(definition.unit, `${itemPath}.unit`, errors);
3588
+ enumValue(definition.semantic, SEMANTICS, `${itemPath}.semantic`, errors);
3589
+ enumValue(definition.aggregation, AGGREGATIONS, `${itemPath}.aggregation`, errors);
3590
+ addUniqueKey(definition.key, itemPath, keys, errors);
3591
+ });
3592
+ return keys;
3593
+ }
3594
+ function validateSeriesDefinitions(value, path, metricKeys, errors) {
3595
+ const keys = /* @__PURE__ */ new Set();
3596
+ if (!arrayValue(value, path, errors)) return keys;
3597
+ value.forEach((definition, index) => {
3598
+ const itemPath = `${path}[${index}]`;
3599
+ if (!recordValue(definition, itemPath, errors)) return;
3600
+ nonEmptyString(definition.key, `${itemPath}.key`, errors);
3601
+ nonEmptyString(definition.label, `${itemPath}.label`, errors);
3602
+ nonEmptyString(definition.metricKey, `${itemPath}.metricKey`, errors);
3603
+ nonEmptyString(definition.unit, `${itemPath}.unit`, errors);
3604
+ addUniqueKey(definition.key, itemPath, keys, errors);
3605
+ if (typeof definition.metricKey === "string" && !metricKeys.has(definition.metricKey)) {
3606
+ errors.push(`${itemPath}.metricKey must reference a declared metric definition`);
3607
+ }
3608
+ });
3609
+ return keys;
3610
+ }
3611
+ function validateDimensionDefinitions(value, path, errors) {
3612
+ const keys = /* @__PURE__ */ new Set();
3613
+ if (!arrayValue(value, path, errors)) return keys;
3614
+ value.forEach((definition, index) => {
3615
+ const itemPath = `${path}[${index}]`;
3616
+ if (!recordValue(definition, itemPath, errors)) return;
3617
+ nonEmptyString(definition.key, `${itemPath}.key`, errors);
3618
+ nonEmptyString(definition.label, `${itemPath}.label`, errors);
3619
+ nonEmptyString(definition.description, `${itemPath}.description`, errors);
3620
+ enumValue(definition.valueType, DIMENSION_VALUE_TYPES, `${itemPath}.valueType`, errors);
3621
+ addUniqueKey(definition.key, itemPath, keys, errors);
3622
+ });
3623
+ return keys;
3624
+ }
3625
+ function validateLifecycleStages(value, path, errors) {
3626
+ const keys = /* @__PURE__ */ new Set();
3627
+ const orders = /* @__PURE__ */ new Set();
3628
+ if (!arrayValue(value, path, errors)) return keys;
3629
+ value.forEach((stage, index) => {
3630
+ const itemPath = `${path}[${index}]`;
3631
+ if (!recordValue(stage, itemPath, errors)) return;
3632
+ nonEmptyString(stage.key, `${itemPath}.key`, errors);
3633
+ nonEmptyString(stage.label, `${itemPath}.label`, errors);
3634
+ nonNegativeInteger(stage.order, `${itemPath}.order`, errors);
3635
+ booleanValue(stage.terminal, `${itemPath}.terminal`, errors);
3636
+ addUniqueKey(stage.key, itemPath, keys, errors);
3637
+ if (typeof stage.order === "number") {
3638
+ if (orders.has(stage.order)) errors.push(`${itemPath}.order must be unique`);
3639
+ orders.add(stage.order);
3640
+ }
3641
+ });
3642
+ return keys;
3643
+ }
3644
+ function validateEventDefinitions(value, path, errors) {
3645
+ const keys = /* @__PURE__ */ new Set();
3646
+ if (!arrayValue(value, path, errors)) return keys;
3647
+ value.forEach((event, index) => {
3648
+ const itemPath = `${path}[${index}]`;
3649
+ if (!recordValue(event, itemPath, errors)) return;
3650
+ nonEmptyString(event.key, `${itemPath}.key`, errors);
3651
+ nonEmptyString(event.label, `${itemPath}.label`, errors);
3652
+ nonEmptyString(event.description, `${itemPath}.description`, errors);
3653
+ addUniqueKey(event.key, itemPath, keys, errors);
3654
+ });
3655
+ return keys;
3656
+ }
3657
+ function validateDatasets(value, path, references, errors) {
3658
+ const ids = /* @__PURE__ */ new Set();
3659
+ if (!arrayValue(value, path, errors, true)) return;
3660
+ value.forEach((dataset, index) => {
3661
+ const itemPath = `${path}[${index}]`;
3662
+ if (!recordValue(dataset, itemPath, errors)) return;
3663
+ nonEmptyString(dataset.id, `${itemPath}.id`, errors);
3664
+ nonEmptyString(dataset.label, `${itemPath}.label`, errors);
3665
+ nonEmptyString(dataset.description, `${itemPath}.description`, errors);
3666
+ nonEmptyString(dataset.grain, `${itemPath}.grain`, errors);
3667
+ addUniqueKey(dataset.id, itemPath, ids, errors);
3668
+ const fields = ["metricKeys", "seriesKeys", "dimensionKeys", "eventKeys", "actionIds"];
3669
+ for (const field of fields) stringArray2(dataset[field], `${itemPath}.${field}`, errors);
3670
+ const totalReferences = fields.reduce((total, field) => total + (Array.isArray(dataset[field]) ? dataset[field].length : 0), 0);
3671
+ if (totalReferences === 0) errors.push(`${itemPath} must reference at least one declared metric, series, dimension, event, or action`);
3672
+ validateReferences(dataset.metricKeys, references.metricKeys, `${itemPath}.metricKeys`, errors);
3673
+ validateReferences(dataset.seriesKeys, references.seriesKeys, `${itemPath}.seriesKeys`, errors);
3674
+ validateReferences(dataset.dimensionKeys, references.dimensionKeys, `${itemPath}.dimensionKeys`, errors);
3675
+ validateReferences(dataset.eventKeys, references.eventKeys, `${itemPath}.eventKeys`, errors);
3676
+ validateReferences(dataset.actionIds, references.actionKeys, `${itemPath}.actionIds`, errors);
3677
+ });
3678
+ }
3679
+ function validateReferences(value, known, path, errors) {
3680
+ if (!Array.isArray(value)) return;
3681
+ for (const reference of value) {
3682
+ if (typeof reference === "string" && !known.has(reference)) errors.push(`${path} references undeclared key ${reference}`);
3683
+ }
3684
+ }
3685
+ function widgetActionKeys(widget) {
3686
+ const keys = /* @__PURE__ */ new Set();
3687
+ for (const collection of [widget.controls, widget.actions]) {
3688
+ if (!Array.isArray(collection)) continue;
3689
+ for (const action of collection) if (isRecord5(action) && typeof action.id === "string") keys.add(action.id);
3690
+ }
3691
+ return keys;
3692
+ }
3693
+ function validateRuntimeSemantics(widget, contributionPath, declared, errors) {
3694
+ const metrics = Array.isArray(widget.metrics) ? widget.metrics : [];
3695
+ for (const metric of metrics) {
3696
+ if (!isRecord5(metric) || typeof metric.key !== "string") continue;
3697
+ if (!declared.metricKeys.has(metric.key)) errors.push(`${contributionPath}.metricDefinitions is missing runtime metric ${metric.key}`);
3698
+ validateRuntimeDimensions(metric.dimensions, declared.dimensionKeys, contributionPath, errors);
3699
+ if (isRecord5(metric.series)) {
3700
+ if (typeof metric.series.id === "string" && !declared.seriesKeys.has(metric.series.id)) errors.push(`${contributionPath}.seriesDefinitions is missing runtime series ${metric.series.id}`);
3701
+ validateSeriesDimensions(metric.series, declared.dimensionKeys, contributionPath, errors);
3702
+ }
3703
+ }
3704
+ const series = Array.isArray(widget.series) ? widget.series : [];
3705
+ for (const item of series) {
3706
+ if (!isRecord5(item)) continue;
3707
+ if (typeof item.id === "string" && !declared.seriesKeys.has(item.id)) errors.push(`${contributionPath}.seriesDefinitions is missing runtime series ${item.id}`);
3708
+ validateSeriesDimensions(item, declared.dimensionKeys, contributionPath, errors);
3709
+ }
3710
+ }
3711
+ function validateSeriesDimensions(series, known, path, errors) {
3712
+ if (!Array.isArray(series.points)) return;
3713
+ for (const point of series.points) if (isRecord5(point)) validateRuntimeDimensions(point.dimensions, known, path, errors);
3714
+ }
3715
+ function validateRuntimeDimensions(value, known, path, errors) {
3716
+ if (!Array.isArray(value)) return;
3717
+ for (const dimension of value) {
3718
+ if (isRecord5(dimension) && typeof dimension.key === "string" && !known.has(dimension.key)) {
3719
+ errors.push(`${path}.dimensions is missing runtime dimension ${dimension.key}`);
3720
+ }
3721
+ }
3722
+ }
3723
+ function addUniqueKey(value, path, keys, errors) {
3724
+ if (typeof value !== "string" || value.trim().length === 0) return;
3725
+ if (keys.has(value)) errors.push(`${path}.key must be unique`);
3726
+ keys.add(value);
3727
+ }
3522
3728
  function validateMetrics(value, path, errors, requireOne) {
3523
3729
  if (!arrayValue(value, path, errors, requireOne)) return;
3524
3730
  value.forEach((metric, index) => {
@@ -3686,7 +3892,7 @@ function isRecord5(value) {
3686
3892
  // src/widgets.ts
3687
3893
  var TOPOLO_WIDGET_ENDPOINT = "/api/widget";
3688
3894
  var TOPOLO_WIDGET_REFRESH_INTERVAL_MS = 6e4;
3689
- var TOPOLO_WIDGET_CONTRACT_VERSION = "2.0.0";
3895
+ var TOPOLO_WIDGET_CONTRACT_VERSION = "3.0.0";
3690
3896
  function defineTopoloStatsWidget(widget) {
3691
3897
  return { ...widget, type: "stats" };
3692
3898
  }
package/dist/index.d.cts CHANGED
@@ -1257,7 +1257,7 @@ declare function validateTopoloWidgetResponse(response: unknown): TopoloWidgetVa
1257
1257
 
1258
1258
  declare const TOPOLO_WIDGET_ENDPOINT = "/api/widget";
1259
1259
  declare const TOPOLO_WIDGET_REFRESH_INTERVAL_MS = 60000;
1260
- declare const TOPOLO_WIDGET_CONTRACT_VERSION: "2.0.0";
1260
+ declare const TOPOLO_WIDGET_CONTRACT_VERSION: "3.0.0";
1261
1261
  type TopoloWidgetType = "stats" | "chart" | "activity" | "notifications" | "actions";
1262
1262
  type TopoloWidgetContext = "personal" | "organization" | "workspace" | "resource";
1263
1263
  type TopoloWidgetSize = "compact" | "medium" | "wide" | "full";
@@ -1345,6 +1345,70 @@ interface TopoloWidgetAccessibility {
1345
1345
  label: string;
1346
1346
  description?: string;
1347
1347
  }
1348
+ type TopoloWidgetVisualizationFamily = "number" | "line" | "area" | "bar" | "donut" | "table" | "funnel" | "timeline" | "actions";
1349
+ interface TopoloWidgetMetricDefinition {
1350
+ key: string;
1351
+ label: string;
1352
+ description: string;
1353
+ unit: string;
1354
+ semantic: TopoloWidgetMetricSemantic;
1355
+ aggregation: TopoloWidgetMetricAggregation;
1356
+ }
1357
+ interface TopoloWidgetSeriesDefinition {
1358
+ key: string;
1359
+ label: string;
1360
+ metricKey: string;
1361
+ unit: string;
1362
+ }
1363
+ interface TopoloWidgetDimensionDefinition {
1364
+ key: string;
1365
+ label: string;
1366
+ description: string;
1367
+ valueType: "string" | "number" | "boolean" | "date" | "datetime";
1368
+ }
1369
+ interface TopoloWidgetLifecycleStage {
1370
+ key: string;
1371
+ label: string;
1372
+ order: number;
1373
+ terminal: boolean;
1374
+ }
1375
+ interface TopoloWidgetEventDefinition {
1376
+ key: string;
1377
+ label: string;
1378
+ description: string;
1379
+ }
1380
+ interface TopoloWidgetDatasetDefinition {
1381
+ id: string;
1382
+ label: string;
1383
+ description: string;
1384
+ grain: string;
1385
+ metricKeys: string[];
1386
+ seriesKeys: string[];
1387
+ dimensionKeys: string[];
1388
+ eventKeys: string[];
1389
+ actionIds: string[];
1390
+ }
1391
+ interface TopoloWidgetWorkspaceSelector {
1392
+ mode: "none" | "optional" | "required";
1393
+ resourceType: string;
1394
+ label: string;
1395
+ supportsMultiple: boolean;
1396
+ }
1397
+ interface TopoloWidgetContribution {
1398
+ summary: string;
1399
+ identity: {
1400
+ iconSource: "catalog";
1401
+ };
1402
+ workspaceSelector: TopoloWidgetWorkspaceSelector;
1403
+ metricDefinitions: TopoloWidgetMetricDefinition[];
1404
+ seriesDefinitions: TopoloWidgetSeriesDefinition[];
1405
+ dimensions: TopoloWidgetDimensionDefinition[];
1406
+ lifecycleStages: TopoloWidgetLifecycleStage[];
1407
+ events: TopoloWidgetEventDefinition[];
1408
+ datasets: TopoloWidgetDatasetDefinition[];
1409
+ compatibleVisualizations: TopoloWidgetVisualizationFamily[];
1410
+ defaultVisualization: TopoloWidgetVisualizationFamily;
1411
+ }
1348
1412
  interface TopoloWidgetBase {
1349
1413
  id: string;
1350
1414
  version: string;
@@ -1362,6 +1426,7 @@ interface TopoloWidgetBase {
1362
1426
  controls: TopoloWidgetActionBinding[];
1363
1427
  localization: TopoloWidgetLocalization;
1364
1428
  accessibility: TopoloWidgetAccessibility;
1429
+ contribution: TopoloWidgetContribution;
1365
1430
  }
1366
1431
  type TopoloWidgetMetricSemantic = "gauge" | "counter" | "rate" | "duration" | "currency" | "percentage";
1367
1432
  type TopoloWidgetMetricAggregation = "last" | "sum" | "average" | "minimum" | "maximum" | "count" | "distinct_count";
@@ -1524,4 +1589,4 @@ declare function createTopolo(options: TopoloClientOptions): {
1524
1589
  };
1525
1590
  type Topolo = ReturnType<typeof createTopolo>;
1526
1591
 
1527
- export { ACTION_CATALOG_DIGEST_ALGORITHM, type ActionContractManifest, type ActionContractSource, type AgentIdentity, type AppApiId, type ApplicationCatalogEntry, type ApplicationDeployTarget, type ApplicationDirectory, type ApplicationDirectoryApplication, type ApplicationDirectoryClient, type ApplicationDirectorySource, type ApplicationId, type CredentialIntrospection, type CrmContactSummary, CrmModule, DEFAULT_APP_URLS, type DeviceAuthorizationResponse, IdentityModule, type ListContactsOptions, type ListContactsResult, type OAuthHelperOptions, type P2PActionDetail, type P2PActionRequestInput, type P2PActionRequestResult, type P2PActionRow, type P2PActionRun, type P2PCapability, type P2PConnection, type P2PHold, type P2PLedgerEntry, P2PModule, type P2PPolicy, type P2PPricingModel, type P2PSettlementBatch, type P2PSettlementGroup, type PublishCapabilityInput, type RequestOptions, type ServiceCatalogUrlEntry, TOPOLO_ENVIRONMENT_SERVICE_URLS, TOPOLO_RUNTIME_ENVIRONMENTS, TOPOLO_WIDGET_CONTRACT_VERSION, TOPOLO_WIDGET_ENDPOINT, TOPOLO_WIDGET_REFRESH_INTERVAL_MS, type TokenResponse, type Topolo, type TopoloActionAgentContract, type TopoloActionCatalogEntry, type TopoloActionCatalogSummary, type TopoloActionDigestInput, type TopoloActionPlan, type TopoloActionPreparation, type TopoloActionUploadOptions, type TopoloActionValidationIssue, type TopoloActionValidationResult, type TopoloActionsWidget, type TopoloActivityWidget, type TopoloAgentExecutionContext, type TopoloApiKeyResourceMetadata, TopoloAuthError, type TopoloBinaryResponse, type TopoloBindableResource, type TopoloBindableResourceCatalog, type TopoloChartWidget, TopoloClient, type TopoloClientOptions, TopoloConfirmationRequiredError, type TopoloCredential, type TopoloDebugEvent, TopoloHttpError, type TopoloInlineBase64UploadContract, type TopoloNotificationsWidget, TopoloOAuth, TopoloPermissionError, type TopoloRuntimeEnvironment, TopoloSdkError, type TopoloServiceCatalogEntry, type TopoloStatsWidget, type TopoloWidget, type TopoloWidgetAccessibility, type TopoloWidgetActionBinding, type TopoloWidgetActionRecovery, type TopoloWidgetActivityItem, type TopoloWidgetApiError, type TopoloWidgetApiErrorResponse, type TopoloWidgetApiResponse, type TopoloWidgetApiSuccessResponse, type TopoloWidgetBase, type TopoloWidgetConfig, type TopoloWidgetConfiguration, type TopoloWidgetConfigurationField, type TopoloWidgetConfigurationOption, type TopoloWidgetContext, type TopoloWidgetDimension, type TopoloWidgetDraft, type TopoloWidgetDrilldown, type TopoloWidgetErrorResponseOptions, type TopoloWidgetLocalization, type TopoloWidgetMetric, type TopoloWidgetMetricAggregation, type TopoloWidgetMetricComparison, type TopoloWidgetMetricSemantic, type TopoloWidgetNotificationItem, type TopoloWidgetPeriod, type TopoloWidgetPresentation, type TopoloWidgetRefreshPolicy, type TopoloWidgetResourceBinding, type TopoloWidgetResponseOptions, type TopoloWidgetSeries, type TopoloWidgetSeriesPoint, type TopoloWidgetSize, type TopoloWidgetState, type TopoloWidgetStatus, type TopoloWidgetType, type TopoloWidgetValidationResult, type TopoloWorkspace, type TopoloWorkspaceListResult, type TopoloWorkspaceMutationResult, type TopoloWorkspacePolicy, WorkspacesModule, actionContractCompleteness, applicationEntryFromCatalog, assertTopoloServiceUrlEnvironment, canonicalTopoloErrorCode, canonicalTopoloRequestId, canonicalTopoloRequired, canonicalTopoloRetryAfter, compactActionCatalogEntry, compactActionPlan, compactActionPreparation, compactActionResult, compactActionValidation, createTopolo, createTopoloAgentExecutionContext, createTopoloWidgetError, createTopoloWidgetResponse, defineTopoloActionsWidget, defineTopoloActivityWidget, defineTopoloChartWidget, defineTopoloNotificationsWidget, defineTopoloStatsWidget, digestTopoloActionCatalog, encodeTopoloActionBase64, enrichActionContract, extractTopoloServiceErrorCode, extractTopoloServiceErrorDetails, formatDirectoryApplicationIds, friendlyAppId, listApplicationDirectory, parseTopoloActionUploadContract, preferExactActionMatches, prepareTopoloActionBase64UploadInput, prepareTopoloActionUploadInput, publicTopoloErrorMessage, resolveApplicationDirectoryEntry, resolveCatalogServiceUrl, resolveServiceUrl, topoloErrorHint, topoloServiceOrigins, validateTopoloActionInput, validateTopoloWidgetResponse };
1592
+ export { ACTION_CATALOG_DIGEST_ALGORITHM, type ActionContractManifest, type ActionContractSource, type AgentIdentity, type AppApiId, type ApplicationCatalogEntry, type ApplicationDeployTarget, type ApplicationDirectory, type ApplicationDirectoryApplication, type ApplicationDirectoryClient, type ApplicationDirectorySource, type ApplicationId, type CredentialIntrospection, type CrmContactSummary, CrmModule, DEFAULT_APP_URLS, type DeviceAuthorizationResponse, IdentityModule, type ListContactsOptions, type ListContactsResult, type OAuthHelperOptions, type P2PActionDetail, type P2PActionRequestInput, type P2PActionRequestResult, type P2PActionRow, type P2PActionRun, type P2PCapability, type P2PConnection, type P2PHold, type P2PLedgerEntry, P2PModule, type P2PPolicy, type P2PPricingModel, type P2PSettlementBatch, type P2PSettlementGroup, type PublishCapabilityInput, type RequestOptions, type ServiceCatalogUrlEntry, TOPOLO_ENVIRONMENT_SERVICE_URLS, TOPOLO_RUNTIME_ENVIRONMENTS, TOPOLO_WIDGET_CONTRACT_VERSION, TOPOLO_WIDGET_ENDPOINT, TOPOLO_WIDGET_REFRESH_INTERVAL_MS, type TokenResponse, type Topolo, type TopoloActionAgentContract, type TopoloActionCatalogEntry, type TopoloActionCatalogSummary, type TopoloActionDigestInput, type TopoloActionPlan, type TopoloActionPreparation, type TopoloActionUploadOptions, type TopoloActionValidationIssue, type TopoloActionValidationResult, type TopoloActionsWidget, type TopoloActivityWidget, type TopoloAgentExecutionContext, type TopoloApiKeyResourceMetadata, TopoloAuthError, type TopoloBinaryResponse, type TopoloBindableResource, type TopoloBindableResourceCatalog, type TopoloChartWidget, TopoloClient, type TopoloClientOptions, TopoloConfirmationRequiredError, type TopoloCredential, type TopoloDebugEvent, TopoloHttpError, type TopoloInlineBase64UploadContract, type TopoloNotificationsWidget, TopoloOAuth, TopoloPermissionError, type TopoloRuntimeEnvironment, TopoloSdkError, type TopoloServiceCatalogEntry, type TopoloStatsWidget, type TopoloWidget, type TopoloWidgetAccessibility, type TopoloWidgetActionBinding, type TopoloWidgetActionRecovery, type TopoloWidgetActivityItem, type TopoloWidgetApiError, type TopoloWidgetApiErrorResponse, type TopoloWidgetApiResponse, type TopoloWidgetApiSuccessResponse, type TopoloWidgetBase, type TopoloWidgetConfig, type TopoloWidgetConfiguration, type TopoloWidgetConfigurationField, type TopoloWidgetConfigurationOption, type TopoloWidgetContext, type TopoloWidgetContribution, type TopoloWidgetDatasetDefinition, type TopoloWidgetDimension, type TopoloWidgetDimensionDefinition, type TopoloWidgetDraft, type TopoloWidgetDrilldown, type TopoloWidgetErrorResponseOptions, type TopoloWidgetEventDefinition, type TopoloWidgetLifecycleStage, type TopoloWidgetLocalization, type TopoloWidgetMetric, type TopoloWidgetMetricAggregation, type TopoloWidgetMetricComparison, type TopoloWidgetMetricDefinition, type TopoloWidgetMetricSemantic, type TopoloWidgetNotificationItem, type TopoloWidgetPeriod, type TopoloWidgetPresentation, type TopoloWidgetRefreshPolicy, type TopoloWidgetResourceBinding, type TopoloWidgetResponseOptions, type TopoloWidgetSeries, type TopoloWidgetSeriesDefinition, type TopoloWidgetSeriesPoint, type TopoloWidgetSize, type TopoloWidgetState, type TopoloWidgetStatus, type TopoloWidgetType, type TopoloWidgetValidationResult, type TopoloWidgetVisualizationFamily, type TopoloWidgetWorkspaceSelector, type TopoloWorkspace, type TopoloWorkspaceListResult, type TopoloWorkspaceMutationResult, type TopoloWorkspacePolicy, WorkspacesModule, actionContractCompleteness, applicationEntryFromCatalog, assertTopoloServiceUrlEnvironment, canonicalTopoloErrorCode, canonicalTopoloRequestId, canonicalTopoloRequired, canonicalTopoloRetryAfter, compactActionCatalogEntry, compactActionPlan, compactActionPreparation, compactActionResult, compactActionValidation, createTopolo, createTopoloAgentExecutionContext, createTopoloWidgetError, createTopoloWidgetResponse, defineTopoloActionsWidget, defineTopoloActivityWidget, defineTopoloChartWidget, defineTopoloNotificationsWidget, defineTopoloStatsWidget, digestTopoloActionCatalog, encodeTopoloActionBase64, enrichActionContract, extractTopoloServiceErrorCode, extractTopoloServiceErrorDetails, formatDirectoryApplicationIds, friendlyAppId, listApplicationDirectory, parseTopoloActionUploadContract, preferExactActionMatches, prepareTopoloActionBase64UploadInput, prepareTopoloActionUploadInput, publicTopoloErrorMessage, resolveApplicationDirectoryEntry, resolveCatalogServiceUrl, resolveServiceUrl, topoloErrorHint, topoloServiceOrigins, validateTopoloActionInput, validateTopoloWidgetResponse };
package/dist/index.d.ts CHANGED
@@ -1257,7 +1257,7 @@ declare function validateTopoloWidgetResponse(response: unknown): TopoloWidgetVa
1257
1257
 
1258
1258
  declare const TOPOLO_WIDGET_ENDPOINT = "/api/widget";
1259
1259
  declare const TOPOLO_WIDGET_REFRESH_INTERVAL_MS = 60000;
1260
- declare const TOPOLO_WIDGET_CONTRACT_VERSION: "2.0.0";
1260
+ declare const TOPOLO_WIDGET_CONTRACT_VERSION: "3.0.0";
1261
1261
  type TopoloWidgetType = "stats" | "chart" | "activity" | "notifications" | "actions";
1262
1262
  type TopoloWidgetContext = "personal" | "organization" | "workspace" | "resource";
1263
1263
  type TopoloWidgetSize = "compact" | "medium" | "wide" | "full";
@@ -1345,6 +1345,70 @@ interface TopoloWidgetAccessibility {
1345
1345
  label: string;
1346
1346
  description?: string;
1347
1347
  }
1348
+ type TopoloWidgetVisualizationFamily = "number" | "line" | "area" | "bar" | "donut" | "table" | "funnel" | "timeline" | "actions";
1349
+ interface TopoloWidgetMetricDefinition {
1350
+ key: string;
1351
+ label: string;
1352
+ description: string;
1353
+ unit: string;
1354
+ semantic: TopoloWidgetMetricSemantic;
1355
+ aggregation: TopoloWidgetMetricAggregation;
1356
+ }
1357
+ interface TopoloWidgetSeriesDefinition {
1358
+ key: string;
1359
+ label: string;
1360
+ metricKey: string;
1361
+ unit: string;
1362
+ }
1363
+ interface TopoloWidgetDimensionDefinition {
1364
+ key: string;
1365
+ label: string;
1366
+ description: string;
1367
+ valueType: "string" | "number" | "boolean" | "date" | "datetime";
1368
+ }
1369
+ interface TopoloWidgetLifecycleStage {
1370
+ key: string;
1371
+ label: string;
1372
+ order: number;
1373
+ terminal: boolean;
1374
+ }
1375
+ interface TopoloWidgetEventDefinition {
1376
+ key: string;
1377
+ label: string;
1378
+ description: string;
1379
+ }
1380
+ interface TopoloWidgetDatasetDefinition {
1381
+ id: string;
1382
+ label: string;
1383
+ description: string;
1384
+ grain: string;
1385
+ metricKeys: string[];
1386
+ seriesKeys: string[];
1387
+ dimensionKeys: string[];
1388
+ eventKeys: string[];
1389
+ actionIds: string[];
1390
+ }
1391
+ interface TopoloWidgetWorkspaceSelector {
1392
+ mode: "none" | "optional" | "required";
1393
+ resourceType: string;
1394
+ label: string;
1395
+ supportsMultiple: boolean;
1396
+ }
1397
+ interface TopoloWidgetContribution {
1398
+ summary: string;
1399
+ identity: {
1400
+ iconSource: "catalog";
1401
+ };
1402
+ workspaceSelector: TopoloWidgetWorkspaceSelector;
1403
+ metricDefinitions: TopoloWidgetMetricDefinition[];
1404
+ seriesDefinitions: TopoloWidgetSeriesDefinition[];
1405
+ dimensions: TopoloWidgetDimensionDefinition[];
1406
+ lifecycleStages: TopoloWidgetLifecycleStage[];
1407
+ events: TopoloWidgetEventDefinition[];
1408
+ datasets: TopoloWidgetDatasetDefinition[];
1409
+ compatibleVisualizations: TopoloWidgetVisualizationFamily[];
1410
+ defaultVisualization: TopoloWidgetVisualizationFamily;
1411
+ }
1348
1412
  interface TopoloWidgetBase {
1349
1413
  id: string;
1350
1414
  version: string;
@@ -1362,6 +1426,7 @@ interface TopoloWidgetBase {
1362
1426
  controls: TopoloWidgetActionBinding[];
1363
1427
  localization: TopoloWidgetLocalization;
1364
1428
  accessibility: TopoloWidgetAccessibility;
1429
+ contribution: TopoloWidgetContribution;
1365
1430
  }
1366
1431
  type TopoloWidgetMetricSemantic = "gauge" | "counter" | "rate" | "duration" | "currency" | "percentage";
1367
1432
  type TopoloWidgetMetricAggregation = "last" | "sum" | "average" | "minimum" | "maximum" | "count" | "distinct_count";
@@ -1524,4 +1589,4 @@ declare function createTopolo(options: TopoloClientOptions): {
1524
1589
  };
1525
1590
  type Topolo = ReturnType<typeof createTopolo>;
1526
1591
 
1527
- export { ACTION_CATALOG_DIGEST_ALGORITHM, type ActionContractManifest, type ActionContractSource, type AgentIdentity, type AppApiId, type ApplicationCatalogEntry, type ApplicationDeployTarget, type ApplicationDirectory, type ApplicationDirectoryApplication, type ApplicationDirectoryClient, type ApplicationDirectorySource, type ApplicationId, type CredentialIntrospection, type CrmContactSummary, CrmModule, DEFAULT_APP_URLS, type DeviceAuthorizationResponse, IdentityModule, type ListContactsOptions, type ListContactsResult, type OAuthHelperOptions, type P2PActionDetail, type P2PActionRequestInput, type P2PActionRequestResult, type P2PActionRow, type P2PActionRun, type P2PCapability, type P2PConnection, type P2PHold, type P2PLedgerEntry, P2PModule, type P2PPolicy, type P2PPricingModel, type P2PSettlementBatch, type P2PSettlementGroup, type PublishCapabilityInput, type RequestOptions, type ServiceCatalogUrlEntry, TOPOLO_ENVIRONMENT_SERVICE_URLS, TOPOLO_RUNTIME_ENVIRONMENTS, TOPOLO_WIDGET_CONTRACT_VERSION, TOPOLO_WIDGET_ENDPOINT, TOPOLO_WIDGET_REFRESH_INTERVAL_MS, type TokenResponse, type Topolo, type TopoloActionAgentContract, type TopoloActionCatalogEntry, type TopoloActionCatalogSummary, type TopoloActionDigestInput, type TopoloActionPlan, type TopoloActionPreparation, type TopoloActionUploadOptions, type TopoloActionValidationIssue, type TopoloActionValidationResult, type TopoloActionsWidget, type TopoloActivityWidget, type TopoloAgentExecutionContext, type TopoloApiKeyResourceMetadata, TopoloAuthError, type TopoloBinaryResponse, type TopoloBindableResource, type TopoloBindableResourceCatalog, type TopoloChartWidget, TopoloClient, type TopoloClientOptions, TopoloConfirmationRequiredError, type TopoloCredential, type TopoloDebugEvent, TopoloHttpError, type TopoloInlineBase64UploadContract, type TopoloNotificationsWidget, TopoloOAuth, TopoloPermissionError, type TopoloRuntimeEnvironment, TopoloSdkError, type TopoloServiceCatalogEntry, type TopoloStatsWidget, type TopoloWidget, type TopoloWidgetAccessibility, type TopoloWidgetActionBinding, type TopoloWidgetActionRecovery, type TopoloWidgetActivityItem, type TopoloWidgetApiError, type TopoloWidgetApiErrorResponse, type TopoloWidgetApiResponse, type TopoloWidgetApiSuccessResponse, type TopoloWidgetBase, type TopoloWidgetConfig, type TopoloWidgetConfiguration, type TopoloWidgetConfigurationField, type TopoloWidgetConfigurationOption, type TopoloWidgetContext, type TopoloWidgetDimension, type TopoloWidgetDraft, type TopoloWidgetDrilldown, type TopoloWidgetErrorResponseOptions, type TopoloWidgetLocalization, type TopoloWidgetMetric, type TopoloWidgetMetricAggregation, type TopoloWidgetMetricComparison, type TopoloWidgetMetricSemantic, type TopoloWidgetNotificationItem, type TopoloWidgetPeriod, type TopoloWidgetPresentation, type TopoloWidgetRefreshPolicy, type TopoloWidgetResourceBinding, type TopoloWidgetResponseOptions, type TopoloWidgetSeries, type TopoloWidgetSeriesPoint, type TopoloWidgetSize, type TopoloWidgetState, type TopoloWidgetStatus, type TopoloWidgetType, type TopoloWidgetValidationResult, type TopoloWorkspace, type TopoloWorkspaceListResult, type TopoloWorkspaceMutationResult, type TopoloWorkspacePolicy, WorkspacesModule, actionContractCompleteness, applicationEntryFromCatalog, assertTopoloServiceUrlEnvironment, canonicalTopoloErrorCode, canonicalTopoloRequestId, canonicalTopoloRequired, canonicalTopoloRetryAfter, compactActionCatalogEntry, compactActionPlan, compactActionPreparation, compactActionResult, compactActionValidation, createTopolo, createTopoloAgentExecutionContext, createTopoloWidgetError, createTopoloWidgetResponse, defineTopoloActionsWidget, defineTopoloActivityWidget, defineTopoloChartWidget, defineTopoloNotificationsWidget, defineTopoloStatsWidget, digestTopoloActionCatalog, encodeTopoloActionBase64, enrichActionContract, extractTopoloServiceErrorCode, extractTopoloServiceErrorDetails, formatDirectoryApplicationIds, friendlyAppId, listApplicationDirectory, parseTopoloActionUploadContract, preferExactActionMatches, prepareTopoloActionBase64UploadInput, prepareTopoloActionUploadInput, publicTopoloErrorMessage, resolveApplicationDirectoryEntry, resolveCatalogServiceUrl, resolveServiceUrl, topoloErrorHint, topoloServiceOrigins, validateTopoloActionInput, validateTopoloWidgetResponse };
1592
+ export { ACTION_CATALOG_DIGEST_ALGORITHM, type ActionContractManifest, type ActionContractSource, type AgentIdentity, type AppApiId, type ApplicationCatalogEntry, type ApplicationDeployTarget, type ApplicationDirectory, type ApplicationDirectoryApplication, type ApplicationDirectoryClient, type ApplicationDirectorySource, type ApplicationId, type CredentialIntrospection, type CrmContactSummary, CrmModule, DEFAULT_APP_URLS, type DeviceAuthorizationResponse, IdentityModule, type ListContactsOptions, type ListContactsResult, type OAuthHelperOptions, type P2PActionDetail, type P2PActionRequestInput, type P2PActionRequestResult, type P2PActionRow, type P2PActionRun, type P2PCapability, type P2PConnection, type P2PHold, type P2PLedgerEntry, P2PModule, type P2PPolicy, type P2PPricingModel, type P2PSettlementBatch, type P2PSettlementGroup, type PublishCapabilityInput, type RequestOptions, type ServiceCatalogUrlEntry, TOPOLO_ENVIRONMENT_SERVICE_URLS, TOPOLO_RUNTIME_ENVIRONMENTS, TOPOLO_WIDGET_CONTRACT_VERSION, TOPOLO_WIDGET_ENDPOINT, TOPOLO_WIDGET_REFRESH_INTERVAL_MS, type TokenResponse, type Topolo, type TopoloActionAgentContract, type TopoloActionCatalogEntry, type TopoloActionCatalogSummary, type TopoloActionDigestInput, type TopoloActionPlan, type TopoloActionPreparation, type TopoloActionUploadOptions, type TopoloActionValidationIssue, type TopoloActionValidationResult, type TopoloActionsWidget, type TopoloActivityWidget, type TopoloAgentExecutionContext, type TopoloApiKeyResourceMetadata, TopoloAuthError, type TopoloBinaryResponse, type TopoloBindableResource, type TopoloBindableResourceCatalog, type TopoloChartWidget, TopoloClient, type TopoloClientOptions, TopoloConfirmationRequiredError, type TopoloCredential, type TopoloDebugEvent, TopoloHttpError, type TopoloInlineBase64UploadContract, type TopoloNotificationsWidget, TopoloOAuth, TopoloPermissionError, type TopoloRuntimeEnvironment, TopoloSdkError, type TopoloServiceCatalogEntry, type TopoloStatsWidget, type TopoloWidget, type TopoloWidgetAccessibility, type TopoloWidgetActionBinding, type TopoloWidgetActionRecovery, type TopoloWidgetActivityItem, type TopoloWidgetApiError, type TopoloWidgetApiErrorResponse, type TopoloWidgetApiResponse, type TopoloWidgetApiSuccessResponse, type TopoloWidgetBase, type TopoloWidgetConfig, type TopoloWidgetConfiguration, type TopoloWidgetConfigurationField, type TopoloWidgetConfigurationOption, type TopoloWidgetContext, type TopoloWidgetContribution, type TopoloWidgetDatasetDefinition, type TopoloWidgetDimension, type TopoloWidgetDimensionDefinition, type TopoloWidgetDraft, type TopoloWidgetDrilldown, type TopoloWidgetErrorResponseOptions, type TopoloWidgetEventDefinition, type TopoloWidgetLifecycleStage, type TopoloWidgetLocalization, type TopoloWidgetMetric, type TopoloWidgetMetricAggregation, type TopoloWidgetMetricComparison, type TopoloWidgetMetricDefinition, type TopoloWidgetMetricSemantic, type TopoloWidgetNotificationItem, type TopoloWidgetPeriod, type TopoloWidgetPresentation, type TopoloWidgetRefreshPolicy, type TopoloWidgetResourceBinding, type TopoloWidgetResponseOptions, type TopoloWidgetSeries, type TopoloWidgetSeriesDefinition, type TopoloWidgetSeriesPoint, type TopoloWidgetSize, type TopoloWidgetState, type TopoloWidgetStatus, type TopoloWidgetType, type TopoloWidgetValidationResult, type TopoloWidgetVisualizationFamily, type TopoloWidgetWorkspaceSelector, type TopoloWorkspace, type TopoloWorkspaceListResult, type TopoloWorkspaceMutationResult, type TopoloWorkspacePolicy, WorkspacesModule, actionContractCompleteness, applicationEntryFromCatalog, assertTopoloServiceUrlEnvironment, canonicalTopoloErrorCode, canonicalTopoloRequestId, canonicalTopoloRequired, canonicalTopoloRetryAfter, compactActionCatalogEntry, compactActionPlan, compactActionPreparation, compactActionResult, compactActionValidation, createTopolo, createTopoloAgentExecutionContext, createTopoloWidgetError, createTopoloWidgetResponse, defineTopoloActionsWidget, defineTopoloActivityWidget, defineTopoloChartWidget, defineTopoloNotificationsWidget, defineTopoloStatsWidget, digestTopoloActionCatalog, encodeTopoloActionBase64, enrichActionContract, extractTopoloServiceErrorCode, extractTopoloServiceErrorDetails, formatDirectoryApplicationIds, friendlyAppId, listApplicationDirectory, parseTopoloActionUploadContract, preferExactActionMatches, prepareTopoloActionBase64UploadInput, prepareTopoloActionUploadInput, publicTopoloErrorMessage, resolveApplicationDirectoryEntry, resolveCatalogServiceUrl, resolveServiceUrl, topoloErrorHint, topoloServiceOrigins, validateTopoloActionInput, validateTopoloWidgetResponse };
package/dist/index.js CHANGED
@@ -3237,7 +3237,7 @@ var TopoloOAuth = class {
3237
3237
  };
3238
3238
 
3239
3239
  // src/widget-validation.ts
3240
- var CONTRACT_VERSION = "2.0.0";
3240
+ var CONTRACT_VERSION = "3.0.0";
3241
3241
  var WIDGET_TYPES = ["stats", "chart", "activity", "notifications", "actions"];
3242
3242
  var CONTEXTS = ["personal", "organization", "workspace", "resource"];
3243
3243
  var SIZES = ["compact", "medium", "wide", "full"];
@@ -3248,6 +3248,9 @@ var AGGREGATIONS = ["last", "sum", "average", "minimum", "maximum", "count", "di
3248
3248
  var CHART_TYPES = ["line", "bar", "area", "pie", "donut"];
3249
3249
  var SEVERITIES = ["info", "warning", "error", "success"];
3250
3250
  var RECOVERY_MODES = ["not_applicable", "retry", "compensating_action"];
3251
+ var VISUALIZATION_FAMILIES = ["number", "line", "area", "bar", "donut", "table", "funnel", "timeline", "actions"];
3252
+ var WORKSPACE_SELECTOR_MODES = ["none", "optional", "required"];
3253
+ var DIMENSION_VALUE_TYPES = ["string", "number", "boolean", "date", "datetime"];
3251
3254
  var SEMVER = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
3252
3255
  function validateTopoloWidgetResponse(response) {
3253
3256
  const errors = [];
@@ -3298,6 +3301,7 @@ function validateWidget(value, path, errors) {
3298
3301
  validateActions(value.controls, `${path}.controls`, errors);
3299
3302
  validateLocalization(value.localization, `${path}.localization`, errors);
3300
3303
  validateAccessibility(value.accessibility, `${path}.accessibility`, errors);
3304
+ validateContribution(value.contribution, `${path}.contribution`, value, errors);
3301
3305
  switch (value.type) {
3302
3306
  case "stats":
3303
3307
  validateMetrics(value.metrics, `${path}.metrics`, errors, requiresContent(value));
@@ -3435,6 +3439,208 @@ function validateAccessibility(value, path, errors) {
3435
3439
  nonEmptyString(value.label, `${path}.label`, errors);
3436
3440
  optionalNonEmptyString(value.description, `${path}.description`, errors);
3437
3441
  }
3442
+ function validateContribution(value, path, widget, errors) {
3443
+ if (!recordValue(value, path, errors)) return;
3444
+ nonEmptyString(value.summary, `${path}.summary`, errors);
3445
+ if (recordValue(value.identity, `${path}.identity`, errors)) {
3446
+ exactValue(value.identity.iconSource, "catalog", `${path}.identity.iconSource`, errors);
3447
+ }
3448
+ if (recordValue(value.workspaceSelector, `${path}.workspaceSelector`, errors)) {
3449
+ enumValue(value.workspaceSelector.mode, WORKSPACE_SELECTOR_MODES, `${path}.workspaceSelector.mode`, errors);
3450
+ nonEmptyString(value.workspaceSelector.resourceType, `${path}.workspaceSelector.resourceType`, errors);
3451
+ nonEmptyString(value.workspaceSelector.label, `${path}.workspaceSelector.label`, errors);
3452
+ booleanValue(value.workspaceSelector.supportsMultiple, `${path}.workspaceSelector.supportsMultiple`, errors);
3453
+ if (value.workspaceSelector.mode === "required" && requiresContent(widget) && isRecord5(widget.resource) && typeof widget.resource.resourceId !== "string") {
3454
+ errors.push(`${path}.workspaceSelector requires a bound resourceId for ready or stale data`);
3455
+ }
3456
+ }
3457
+ const metricKeys = validateMetricDefinitions(value.metricDefinitions, `${path}.metricDefinitions`, errors);
3458
+ const seriesKeys = validateSeriesDefinitions(value.seriesDefinitions, `${path}.seriesDefinitions`, metricKeys, errors);
3459
+ const dimensionKeys = validateDimensionDefinitions(value.dimensions, `${path}.dimensions`, errors);
3460
+ const lifecycleKeys = validateLifecycleStages(value.lifecycleStages, `${path}.lifecycleStages`, errors);
3461
+ const eventKeys = validateEventDefinitions(value.events, `${path}.events`, errors);
3462
+ const actionKeys = widgetActionKeys(widget);
3463
+ validateDatasets(value.datasets, `${path}.datasets`, {
3464
+ metricKeys,
3465
+ seriesKeys,
3466
+ dimensionKeys,
3467
+ eventKeys,
3468
+ actionKeys
3469
+ }, errors);
3470
+ enumArray(
3471
+ value.compatibleVisualizations,
3472
+ VISUALIZATION_FAMILIES,
3473
+ `${path}.compatibleVisualizations`,
3474
+ errors,
3475
+ true
3476
+ );
3477
+ enumValue(value.defaultVisualization, VISUALIZATION_FAMILIES, `${path}.defaultVisualization`, errors);
3478
+ if (typeof value.defaultVisualization === "string" && Array.isArray(value.compatibleVisualizations) && !value.compatibleVisualizations.includes(value.defaultVisualization)) {
3479
+ errors.push(`${path}.defaultVisualization must be included in compatibleVisualizations`);
3480
+ }
3481
+ if (Array.isArray(value.compatibleVisualizations)) {
3482
+ for (const family of value.compatibleVisualizations) {
3483
+ if (family === "number" && metricKeys.size === 0) errors.push(`${path}.compatibleVisualizations number requires a metric definition`);
3484
+ if ((family === "line" || family === "area") && seriesKeys.size === 0) errors.push(`${path}.compatibleVisualizations ${family} requires a series definition`);
3485
+ if (family === "donut" && (metricKeys.size === 0 || dimensionKeys.size === 0)) errors.push(`${path}.compatibleVisualizations donut requires metric and dimension definitions`);
3486
+ if (family === "funnel" && lifecycleKeys.size < 2) errors.push(`${path}.compatibleVisualizations funnel requires at least two lifecycle stages`);
3487
+ if (family === "timeline" && eventKeys.size === 0) errors.push(`${path}.compatibleVisualizations timeline requires an event definition`);
3488
+ if (family === "actions" && actionKeys.size === 0) errors.push(`${path}.compatibleVisualizations actions requires a published action`);
3489
+ if (family === "bar" && metricKeys.size === 0 && seriesKeys.size === 0) errors.push(`${path}.compatibleVisualizations bar requires a metric or series definition`);
3490
+ }
3491
+ }
3492
+ validateRuntimeSemantics(widget, path, { metricKeys, seriesKeys, dimensionKeys }, errors);
3493
+ }
3494
+ function validateMetricDefinitions(value, path, errors) {
3495
+ const keys = /* @__PURE__ */ new Set();
3496
+ if (!arrayValue(value, path, errors)) return keys;
3497
+ value.forEach((definition, index) => {
3498
+ const itemPath = `${path}[${index}]`;
3499
+ if (!recordValue(definition, itemPath, errors)) return;
3500
+ nonEmptyString(definition.key, `${itemPath}.key`, errors);
3501
+ nonEmptyString(definition.label, `${itemPath}.label`, errors);
3502
+ nonEmptyString(definition.description, `${itemPath}.description`, errors);
3503
+ nonEmptyString(definition.unit, `${itemPath}.unit`, errors);
3504
+ enumValue(definition.semantic, SEMANTICS, `${itemPath}.semantic`, errors);
3505
+ enumValue(definition.aggregation, AGGREGATIONS, `${itemPath}.aggregation`, errors);
3506
+ addUniqueKey(definition.key, itemPath, keys, errors);
3507
+ });
3508
+ return keys;
3509
+ }
3510
+ function validateSeriesDefinitions(value, path, metricKeys, errors) {
3511
+ const keys = /* @__PURE__ */ new Set();
3512
+ if (!arrayValue(value, path, errors)) return keys;
3513
+ value.forEach((definition, index) => {
3514
+ const itemPath = `${path}[${index}]`;
3515
+ if (!recordValue(definition, itemPath, errors)) return;
3516
+ nonEmptyString(definition.key, `${itemPath}.key`, errors);
3517
+ nonEmptyString(definition.label, `${itemPath}.label`, errors);
3518
+ nonEmptyString(definition.metricKey, `${itemPath}.metricKey`, errors);
3519
+ nonEmptyString(definition.unit, `${itemPath}.unit`, errors);
3520
+ addUniqueKey(definition.key, itemPath, keys, errors);
3521
+ if (typeof definition.metricKey === "string" && !metricKeys.has(definition.metricKey)) {
3522
+ errors.push(`${itemPath}.metricKey must reference a declared metric definition`);
3523
+ }
3524
+ });
3525
+ return keys;
3526
+ }
3527
+ function validateDimensionDefinitions(value, path, errors) {
3528
+ const keys = /* @__PURE__ */ new Set();
3529
+ if (!arrayValue(value, path, errors)) return keys;
3530
+ value.forEach((definition, index) => {
3531
+ const itemPath = `${path}[${index}]`;
3532
+ if (!recordValue(definition, itemPath, errors)) return;
3533
+ nonEmptyString(definition.key, `${itemPath}.key`, errors);
3534
+ nonEmptyString(definition.label, `${itemPath}.label`, errors);
3535
+ nonEmptyString(definition.description, `${itemPath}.description`, errors);
3536
+ enumValue(definition.valueType, DIMENSION_VALUE_TYPES, `${itemPath}.valueType`, errors);
3537
+ addUniqueKey(definition.key, itemPath, keys, errors);
3538
+ });
3539
+ return keys;
3540
+ }
3541
+ function validateLifecycleStages(value, path, errors) {
3542
+ const keys = /* @__PURE__ */ new Set();
3543
+ const orders = /* @__PURE__ */ new Set();
3544
+ if (!arrayValue(value, path, errors)) return keys;
3545
+ value.forEach((stage, index) => {
3546
+ const itemPath = `${path}[${index}]`;
3547
+ if (!recordValue(stage, itemPath, errors)) return;
3548
+ nonEmptyString(stage.key, `${itemPath}.key`, errors);
3549
+ nonEmptyString(stage.label, `${itemPath}.label`, errors);
3550
+ nonNegativeInteger(stage.order, `${itemPath}.order`, errors);
3551
+ booleanValue(stage.terminal, `${itemPath}.terminal`, errors);
3552
+ addUniqueKey(stage.key, itemPath, keys, errors);
3553
+ if (typeof stage.order === "number") {
3554
+ if (orders.has(stage.order)) errors.push(`${itemPath}.order must be unique`);
3555
+ orders.add(stage.order);
3556
+ }
3557
+ });
3558
+ return keys;
3559
+ }
3560
+ function validateEventDefinitions(value, path, errors) {
3561
+ const keys = /* @__PURE__ */ new Set();
3562
+ if (!arrayValue(value, path, errors)) return keys;
3563
+ value.forEach((event, index) => {
3564
+ const itemPath = `${path}[${index}]`;
3565
+ if (!recordValue(event, itemPath, errors)) return;
3566
+ nonEmptyString(event.key, `${itemPath}.key`, errors);
3567
+ nonEmptyString(event.label, `${itemPath}.label`, errors);
3568
+ nonEmptyString(event.description, `${itemPath}.description`, errors);
3569
+ addUniqueKey(event.key, itemPath, keys, errors);
3570
+ });
3571
+ return keys;
3572
+ }
3573
+ function validateDatasets(value, path, references, errors) {
3574
+ const ids = /* @__PURE__ */ new Set();
3575
+ if (!arrayValue(value, path, errors, true)) return;
3576
+ value.forEach((dataset, index) => {
3577
+ const itemPath = `${path}[${index}]`;
3578
+ if (!recordValue(dataset, itemPath, errors)) return;
3579
+ nonEmptyString(dataset.id, `${itemPath}.id`, errors);
3580
+ nonEmptyString(dataset.label, `${itemPath}.label`, errors);
3581
+ nonEmptyString(dataset.description, `${itemPath}.description`, errors);
3582
+ nonEmptyString(dataset.grain, `${itemPath}.grain`, errors);
3583
+ addUniqueKey(dataset.id, itemPath, ids, errors);
3584
+ const fields = ["metricKeys", "seriesKeys", "dimensionKeys", "eventKeys", "actionIds"];
3585
+ for (const field of fields) stringArray2(dataset[field], `${itemPath}.${field}`, errors);
3586
+ const totalReferences = fields.reduce((total, field) => total + (Array.isArray(dataset[field]) ? dataset[field].length : 0), 0);
3587
+ if (totalReferences === 0) errors.push(`${itemPath} must reference at least one declared metric, series, dimension, event, or action`);
3588
+ validateReferences(dataset.metricKeys, references.metricKeys, `${itemPath}.metricKeys`, errors);
3589
+ validateReferences(dataset.seriesKeys, references.seriesKeys, `${itemPath}.seriesKeys`, errors);
3590
+ validateReferences(dataset.dimensionKeys, references.dimensionKeys, `${itemPath}.dimensionKeys`, errors);
3591
+ validateReferences(dataset.eventKeys, references.eventKeys, `${itemPath}.eventKeys`, errors);
3592
+ validateReferences(dataset.actionIds, references.actionKeys, `${itemPath}.actionIds`, errors);
3593
+ });
3594
+ }
3595
+ function validateReferences(value, known, path, errors) {
3596
+ if (!Array.isArray(value)) return;
3597
+ for (const reference of value) {
3598
+ if (typeof reference === "string" && !known.has(reference)) errors.push(`${path} references undeclared key ${reference}`);
3599
+ }
3600
+ }
3601
+ function widgetActionKeys(widget) {
3602
+ const keys = /* @__PURE__ */ new Set();
3603
+ for (const collection of [widget.controls, widget.actions]) {
3604
+ if (!Array.isArray(collection)) continue;
3605
+ for (const action of collection) if (isRecord5(action) && typeof action.id === "string") keys.add(action.id);
3606
+ }
3607
+ return keys;
3608
+ }
3609
+ function validateRuntimeSemantics(widget, contributionPath, declared, errors) {
3610
+ const metrics = Array.isArray(widget.metrics) ? widget.metrics : [];
3611
+ for (const metric of metrics) {
3612
+ if (!isRecord5(metric) || typeof metric.key !== "string") continue;
3613
+ if (!declared.metricKeys.has(metric.key)) errors.push(`${contributionPath}.metricDefinitions is missing runtime metric ${metric.key}`);
3614
+ validateRuntimeDimensions(metric.dimensions, declared.dimensionKeys, contributionPath, errors);
3615
+ if (isRecord5(metric.series)) {
3616
+ if (typeof metric.series.id === "string" && !declared.seriesKeys.has(metric.series.id)) errors.push(`${contributionPath}.seriesDefinitions is missing runtime series ${metric.series.id}`);
3617
+ validateSeriesDimensions(metric.series, declared.dimensionKeys, contributionPath, errors);
3618
+ }
3619
+ }
3620
+ const series = Array.isArray(widget.series) ? widget.series : [];
3621
+ for (const item of series) {
3622
+ if (!isRecord5(item)) continue;
3623
+ if (typeof item.id === "string" && !declared.seriesKeys.has(item.id)) errors.push(`${contributionPath}.seriesDefinitions is missing runtime series ${item.id}`);
3624
+ validateSeriesDimensions(item, declared.dimensionKeys, contributionPath, errors);
3625
+ }
3626
+ }
3627
+ function validateSeriesDimensions(series, known, path, errors) {
3628
+ if (!Array.isArray(series.points)) return;
3629
+ for (const point of series.points) if (isRecord5(point)) validateRuntimeDimensions(point.dimensions, known, path, errors);
3630
+ }
3631
+ function validateRuntimeDimensions(value, known, path, errors) {
3632
+ if (!Array.isArray(value)) return;
3633
+ for (const dimension of value) {
3634
+ if (isRecord5(dimension) && typeof dimension.key === "string" && !known.has(dimension.key)) {
3635
+ errors.push(`${path}.dimensions is missing runtime dimension ${dimension.key}`);
3636
+ }
3637
+ }
3638
+ }
3639
+ function addUniqueKey(value, path, keys, errors) {
3640
+ if (typeof value !== "string" || value.trim().length === 0) return;
3641
+ if (keys.has(value)) errors.push(`${path}.key must be unique`);
3642
+ keys.add(value);
3643
+ }
3438
3644
  function validateMetrics(value, path, errors, requireOne) {
3439
3645
  if (!arrayValue(value, path, errors, requireOne)) return;
3440
3646
  value.forEach((metric, index) => {
@@ -3602,7 +3808,7 @@ function isRecord5(value) {
3602
3808
  // src/widgets.ts
3603
3809
  var TOPOLO_WIDGET_ENDPOINT = "/api/widget";
3604
3810
  var TOPOLO_WIDGET_REFRESH_INTERVAL_MS = 6e4;
3605
- var TOPOLO_WIDGET_CONTRACT_VERSION = "2.0.0";
3811
+ var TOPOLO_WIDGET_CONTRACT_VERSION = "3.0.0";
3606
3812
  function defineTopoloStatsWidget(widget) {
3607
3813
  return { ...widget, type: "stats" };
3608
3814
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@topolo/sdk",
3
- "version": "0.13.0",
4
- "topoloPublishedVersion": "0.13.0",
3
+ "version": "0.14.0",
4
+ "topoloPublishedVersion": "0.14.0",
5
5
  "description": "Typed client SDK for the Topolo platform. Used by TopoloCli, TopoloMCP, and third-party agents.",
6
6
  "license": "UNLICENSED",
7
7
  "author": "Topolo",