@topolo/sdk 0.12.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 +235 -10
- package/dist/index.d.cts +82 -2
- package/dist/index.d.ts +82 -2
- package/dist/index.js +235 -10
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -1229,16 +1229,29 @@ var TopoloClient = class _TopoloClient {
|
|
|
1229
1229
|
clearTimeout(timeoutId);
|
|
1230
1230
|
}
|
|
1231
1231
|
};
|
|
1232
|
+
const fetchWithReadRetry = async () => {
|
|
1233
|
+
const maxAttempts = method === "GET" ? 2 : 1;
|
|
1234
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
1235
|
+
try {
|
|
1236
|
+
return await fetchOnce();
|
|
1237
|
+
} catch (error) {
|
|
1238
|
+
const transportFailure = !(error instanceof TopoloSdkError) && !opts.signal?.aborted;
|
|
1239
|
+
if (!transportFailure || attempt === maxAttempts) throw error;
|
|
1240
|
+
await new Promise((resolve) => setTimeout(resolve, 250));
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
throw new TopoloSdkError("network_error", "Topolo read retry loop exhausted.");
|
|
1244
|
+
};
|
|
1232
1245
|
let res;
|
|
1233
1246
|
try {
|
|
1234
1247
|
const attemptedCredential = this.credential;
|
|
1235
|
-
res = await
|
|
1248
|
+
res = await fetchWithReadRetry();
|
|
1236
1249
|
if (res.status === 401 && attemptedCredential.kind === "access_token" && this.refreshCredential) {
|
|
1237
1250
|
await res.body?.cancel().catch(() => void 0);
|
|
1238
1251
|
const refreshed = await this.refreshRejectedAccessToken(attemptedCredential.accessToken);
|
|
1239
1252
|
if (refreshed) {
|
|
1240
1253
|
applyAuthHeaders(headers, refreshed);
|
|
1241
|
-
res = await
|
|
1254
|
+
res = await fetchWithReadRetry();
|
|
1242
1255
|
}
|
|
1243
1256
|
}
|
|
1244
1257
|
} catch (err) {
|
|
@@ -1890,26 +1903,29 @@ var TopoloClient = class _TopoloClient {
|
|
|
1890
1903
|
};
|
|
1891
1904
|
function validateActionResource(entry, resource) {
|
|
1892
1905
|
const permissionName = entry.permissionName || entry.requiredPermission.split(".").at(-1) || "";
|
|
1893
|
-
|
|
1906
|
+
const declaredContext = entry.agentContract?.resourceContext;
|
|
1907
|
+
const declaredKind = typeof declaredContext?.kind === "string" ? declaredContext.kind.trim() : "";
|
|
1908
|
+
const expectedType = declaredKind || (permissionName.startsWith("workspace:") ? "workspace" : "");
|
|
1909
|
+
if (!expectedType || declaredContext?.required === false && !permissionName.startsWith("workspace:")) return null;
|
|
1894
1910
|
if (!resource) {
|
|
1895
1911
|
return {
|
|
1896
1912
|
path: "$.resource",
|
|
1897
1913
|
code: "required",
|
|
1898
|
-
message:
|
|
1914
|
+
message: `Select resourceType "${expectedType}" with the application resource catalog before planning or calling this action.`
|
|
1899
1915
|
};
|
|
1900
1916
|
}
|
|
1901
|
-
if (resource.resourceType !==
|
|
1917
|
+
if (resource.resourceType !== expectedType) {
|
|
1902
1918
|
return {
|
|
1903
1919
|
path: "$.resource.resourceType",
|
|
1904
1920
|
code: "const",
|
|
1905
|
-
message:
|
|
1921
|
+
message: `This action requires resourceType "${expectedType}".`
|
|
1906
1922
|
};
|
|
1907
1923
|
}
|
|
1908
1924
|
if (!resource.resourceId.trim()) {
|
|
1909
1925
|
return {
|
|
1910
1926
|
path: "$.resource.resourceId",
|
|
1911
1927
|
code: "required",
|
|
1912
|
-
message:
|
|
1928
|
+
message: `This action requires a ${expectedType} resourceId.`
|
|
1913
1929
|
};
|
|
1914
1930
|
}
|
|
1915
1931
|
return null;
|
|
@@ -2283,7 +2299,8 @@ function compactActionCatalogEntry(action) {
|
|
|
2283
2299
|
agentAccess: action.agentAccess ?? (action.requiresConfirmation ? "confirm" : action.readOnly ? "auto" : "confirm"),
|
|
2284
2300
|
requiredPermission: action.requiredPermission,
|
|
2285
2301
|
requiredInput: required,
|
|
2286
|
-
resourceType: action.agentContract?.
|
|
2302
|
+
resourceType: action.agentContract?.resourceContext?.kind ?? (action.permissionName.startsWith("workspace:") ? "workspace" : null),
|
|
2303
|
+
resultResourceType: action.agentContract?.resource?.kind ?? null,
|
|
2287
2304
|
exampleInput: example.value,
|
|
2288
2305
|
exampleInputAvailable: example.available,
|
|
2289
2306
|
docsUrl: action.agentContract?.docsUrl ?? null
|
|
@@ -3304,7 +3321,7 @@ var TopoloOAuth = class {
|
|
|
3304
3321
|
};
|
|
3305
3322
|
|
|
3306
3323
|
// src/widget-validation.ts
|
|
3307
|
-
var CONTRACT_VERSION = "
|
|
3324
|
+
var CONTRACT_VERSION = "3.0.0";
|
|
3308
3325
|
var WIDGET_TYPES = ["stats", "chart", "activity", "notifications", "actions"];
|
|
3309
3326
|
var CONTEXTS = ["personal", "organization", "workspace", "resource"];
|
|
3310
3327
|
var SIZES = ["compact", "medium", "wide", "full"];
|
|
@@ -3315,6 +3332,9 @@ var AGGREGATIONS = ["last", "sum", "average", "minimum", "maximum", "count", "di
|
|
|
3315
3332
|
var CHART_TYPES = ["line", "bar", "area", "pie", "donut"];
|
|
3316
3333
|
var SEVERITIES = ["info", "warning", "error", "success"];
|
|
3317
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"];
|
|
3318
3338
|
var SEMVER = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
|
|
3319
3339
|
function validateTopoloWidgetResponse(response) {
|
|
3320
3340
|
const errors = [];
|
|
@@ -3365,6 +3385,7 @@ function validateWidget(value, path, errors) {
|
|
|
3365
3385
|
validateActions(value.controls, `${path}.controls`, errors);
|
|
3366
3386
|
validateLocalization(value.localization, `${path}.localization`, errors);
|
|
3367
3387
|
validateAccessibility(value.accessibility, `${path}.accessibility`, errors);
|
|
3388
|
+
validateContribution(value.contribution, `${path}.contribution`, value, errors);
|
|
3368
3389
|
switch (value.type) {
|
|
3369
3390
|
case "stats":
|
|
3370
3391
|
validateMetrics(value.metrics, `${path}.metrics`, errors, requiresContent(value));
|
|
@@ -3494,12 +3515,216 @@ function validateLocalization(value, path, errors) {
|
|
|
3494
3515
|
nonEmptyString(value.locale, `${path}.locale`, errors);
|
|
3495
3516
|
nonEmptyString(value.titleKey, `${path}.titleKey`, errors);
|
|
3496
3517
|
optionalNonEmptyString(value.descriptionKey, `${path}.descriptionKey`, errors);
|
|
3518
|
+
optionalNonEmptyString(value.title, `${path}.title`, errors);
|
|
3519
|
+
optionalNonEmptyString(value.description, `${path}.description`, errors);
|
|
3497
3520
|
}
|
|
3498
3521
|
function validateAccessibility(value, path, errors) {
|
|
3499
3522
|
if (!recordValue(value, path, errors)) return;
|
|
3500
3523
|
nonEmptyString(value.label, `${path}.label`, errors);
|
|
3501
3524
|
optionalNonEmptyString(value.description, `${path}.description`, errors);
|
|
3502
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
|
+
}
|
|
3503
3728
|
function validateMetrics(value, path, errors, requireOne) {
|
|
3504
3729
|
if (!arrayValue(value, path, errors, requireOne)) return;
|
|
3505
3730
|
value.forEach((metric, index) => {
|
|
@@ -3667,7 +3892,7 @@ function isRecord5(value) {
|
|
|
3667
3892
|
// src/widgets.ts
|
|
3668
3893
|
var TOPOLO_WIDGET_ENDPOINT = "/api/widget";
|
|
3669
3894
|
var TOPOLO_WIDGET_REFRESH_INTERVAL_MS = 6e4;
|
|
3670
|
-
var TOPOLO_WIDGET_CONTRACT_VERSION = "
|
|
3895
|
+
var TOPOLO_WIDGET_CONTRACT_VERSION = "3.0.0";
|
|
3671
3896
|
function defineTopoloStatsWidget(widget) {
|
|
3672
3897
|
return { ...widget, type: "stats" };
|
|
3673
3898
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -254,6 +254,10 @@ interface TopoloActionCatalogEntry {
|
|
|
254
254
|
}
|
|
255
255
|
interface TopoloActionAgentContract {
|
|
256
256
|
docsUrl?: string;
|
|
257
|
+
resourceContext?: {
|
|
258
|
+
kind?: string;
|
|
259
|
+
required?: boolean;
|
|
260
|
+
};
|
|
257
261
|
resource?: {
|
|
258
262
|
kind?: string;
|
|
259
263
|
idPath?: string;
|
|
@@ -513,6 +517,7 @@ declare function compactActionCatalogEntry(action: TopoloActionCatalogEntry): {
|
|
|
513
517
|
requiredPermission: string;
|
|
514
518
|
requiredInput: string[];
|
|
515
519
|
resourceType: string | null;
|
|
520
|
+
resultResourceType: string | null;
|
|
516
521
|
exampleInput: Record<string, unknown> | null;
|
|
517
522
|
exampleInputAvailable: boolean;
|
|
518
523
|
docsUrl: string | null;
|
|
@@ -1252,7 +1257,7 @@ declare function validateTopoloWidgetResponse(response: unknown): TopoloWidgetVa
|
|
|
1252
1257
|
|
|
1253
1258
|
declare const TOPOLO_WIDGET_ENDPOINT = "/api/widget";
|
|
1254
1259
|
declare const TOPOLO_WIDGET_REFRESH_INTERVAL_MS = 60000;
|
|
1255
|
-
declare const TOPOLO_WIDGET_CONTRACT_VERSION: "
|
|
1260
|
+
declare const TOPOLO_WIDGET_CONTRACT_VERSION: "3.0.0";
|
|
1256
1261
|
type TopoloWidgetType = "stats" | "chart" | "activity" | "notifications" | "actions";
|
|
1257
1262
|
type TopoloWidgetContext = "personal" | "organization" | "workspace" | "resource";
|
|
1258
1263
|
type TopoloWidgetSize = "compact" | "medium" | "wide" | "full";
|
|
@@ -1325,11 +1330,85 @@ interface TopoloWidgetLocalization {
|
|
|
1325
1330
|
locale: string;
|
|
1326
1331
|
titleKey: string;
|
|
1327
1332
|
descriptionKey?: string;
|
|
1333
|
+
/**
|
|
1334
|
+
* English source text for `titleKey`. Hosts already fall back to their own
|
|
1335
|
+
* title when the key misses, so this changes no rendering — it exists so the
|
|
1336
|
+
* key HAS a source string: the i18n extractor reads a sibling literal named
|
|
1337
|
+
* after the key's field, and without one the key never reaches a catalog and
|
|
1338
|
+
* cannot be translated into any locale.
|
|
1339
|
+
*/
|
|
1340
|
+
title?: string;
|
|
1341
|
+
/** English source text for `descriptionKey`. See `title`. */
|
|
1342
|
+
description?: string;
|
|
1328
1343
|
}
|
|
1329
1344
|
interface TopoloWidgetAccessibility {
|
|
1330
1345
|
label: string;
|
|
1331
1346
|
description?: string;
|
|
1332
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
|
+
}
|
|
1333
1412
|
interface TopoloWidgetBase {
|
|
1334
1413
|
id: string;
|
|
1335
1414
|
version: string;
|
|
@@ -1347,6 +1426,7 @@ interface TopoloWidgetBase {
|
|
|
1347
1426
|
controls: TopoloWidgetActionBinding[];
|
|
1348
1427
|
localization: TopoloWidgetLocalization;
|
|
1349
1428
|
accessibility: TopoloWidgetAccessibility;
|
|
1429
|
+
contribution: TopoloWidgetContribution;
|
|
1350
1430
|
}
|
|
1351
1431
|
type TopoloWidgetMetricSemantic = "gauge" | "counter" | "rate" | "duration" | "currency" | "percentage";
|
|
1352
1432
|
type TopoloWidgetMetricAggregation = "last" | "sum" | "average" | "minimum" | "maximum" | "count" | "distinct_count";
|
|
@@ -1509,4 +1589,4 @@ declare function createTopolo(options: TopoloClientOptions): {
|
|
|
1509
1589
|
};
|
|
1510
1590
|
type Topolo = ReturnType<typeof createTopolo>;
|
|
1511
1591
|
|
|
1512
|
-
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
|
@@ -254,6 +254,10 @@ interface TopoloActionCatalogEntry {
|
|
|
254
254
|
}
|
|
255
255
|
interface TopoloActionAgentContract {
|
|
256
256
|
docsUrl?: string;
|
|
257
|
+
resourceContext?: {
|
|
258
|
+
kind?: string;
|
|
259
|
+
required?: boolean;
|
|
260
|
+
};
|
|
257
261
|
resource?: {
|
|
258
262
|
kind?: string;
|
|
259
263
|
idPath?: string;
|
|
@@ -513,6 +517,7 @@ declare function compactActionCatalogEntry(action: TopoloActionCatalogEntry): {
|
|
|
513
517
|
requiredPermission: string;
|
|
514
518
|
requiredInput: string[];
|
|
515
519
|
resourceType: string | null;
|
|
520
|
+
resultResourceType: string | null;
|
|
516
521
|
exampleInput: Record<string, unknown> | null;
|
|
517
522
|
exampleInputAvailable: boolean;
|
|
518
523
|
docsUrl: string | null;
|
|
@@ -1252,7 +1257,7 @@ declare function validateTopoloWidgetResponse(response: unknown): TopoloWidgetVa
|
|
|
1252
1257
|
|
|
1253
1258
|
declare const TOPOLO_WIDGET_ENDPOINT = "/api/widget";
|
|
1254
1259
|
declare const TOPOLO_WIDGET_REFRESH_INTERVAL_MS = 60000;
|
|
1255
|
-
declare const TOPOLO_WIDGET_CONTRACT_VERSION: "
|
|
1260
|
+
declare const TOPOLO_WIDGET_CONTRACT_VERSION: "3.0.0";
|
|
1256
1261
|
type TopoloWidgetType = "stats" | "chart" | "activity" | "notifications" | "actions";
|
|
1257
1262
|
type TopoloWidgetContext = "personal" | "organization" | "workspace" | "resource";
|
|
1258
1263
|
type TopoloWidgetSize = "compact" | "medium" | "wide" | "full";
|
|
@@ -1325,11 +1330,85 @@ interface TopoloWidgetLocalization {
|
|
|
1325
1330
|
locale: string;
|
|
1326
1331
|
titleKey: string;
|
|
1327
1332
|
descriptionKey?: string;
|
|
1333
|
+
/**
|
|
1334
|
+
* English source text for `titleKey`. Hosts already fall back to their own
|
|
1335
|
+
* title when the key misses, so this changes no rendering — it exists so the
|
|
1336
|
+
* key HAS a source string: the i18n extractor reads a sibling literal named
|
|
1337
|
+
* after the key's field, and without one the key never reaches a catalog and
|
|
1338
|
+
* cannot be translated into any locale.
|
|
1339
|
+
*/
|
|
1340
|
+
title?: string;
|
|
1341
|
+
/** English source text for `descriptionKey`. See `title`. */
|
|
1342
|
+
description?: string;
|
|
1328
1343
|
}
|
|
1329
1344
|
interface TopoloWidgetAccessibility {
|
|
1330
1345
|
label: string;
|
|
1331
1346
|
description?: string;
|
|
1332
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
|
+
}
|
|
1333
1412
|
interface TopoloWidgetBase {
|
|
1334
1413
|
id: string;
|
|
1335
1414
|
version: string;
|
|
@@ -1347,6 +1426,7 @@ interface TopoloWidgetBase {
|
|
|
1347
1426
|
controls: TopoloWidgetActionBinding[];
|
|
1348
1427
|
localization: TopoloWidgetLocalization;
|
|
1349
1428
|
accessibility: TopoloWidgetAccessibility;
|
|
1429
|
+
contribution: TopoloWidgetContribution;
|
|
1350
1430
|
}
|
|
1351
1431
|
type TopoloWidgetMetricSemantic = "gauge" | "counter" | "rate" | "duration" | "currency" | "percentage";
|
|
1352
1432
|
type TopoloWidgetMetricAggregation = "last" | "sum" | "average" | "minimum" | "maximum" | "count" | "distinct_count";
|
|
@@ -1509,4 +1589,4 @@ declare function createTopolo(options: TopoloClientOptions): {
|
|
|
1509
1589
|
};
|
|
1510
1590
|
type Topolo = ReturnType<typeof createTopolo>;
|
|
1511
1591
|
|
|
1512
|
-
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
|
@@ -1145,16 +1145,29 @@ var TopoloClient = class _TopoloClient {
|
|
|
1145
1145
|
clearTimeout(timeoutId);
|
|
1146
1146
|
}
|
|
1147
1147
|
};
|
|
1148
|
+
const fetchWithReadRetry = async () => {
|
|
1149
|
+
const maxAttempts = method === "GET" ? 2 : 1;
|
|
1150
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
1151
|
+
try {
|
|
1152
|
+
return await fetchOnce();
|
|
1153
|
+
} catch (error) {
|
|
1154
|
+
const transportFailure = !(error instanceof TopoloSdkError) && !opts.signal?.aborted;
|
|
1155
|
+
if (!transportFailure || attempt === maxAttempts) throw error;
|
|
1156
|
+
await new Promise((resolve) => setTimeout(resolve, 250));
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
throw new TopoloSdkError("network_error", "Topolo read retry loop exhausted.");
|
|
1160
|
+
};
|
|
1148
1161
|
let res;
|
|
1149
1162
|
try {
|
|
1150
1163
|
const attemptedCredential = this.credential;
|
|
1151
|
-
res = await
|
|
1164
|
+
res = await fetchWithReadRetry();
|
|
1152
1165
|
if (res.status === 401 && attemptedCredential.kind === "access_token" && this.refreshCredential) {
|
|
1153
1166
|
await res.body?.cancel().catch(() => void 0);
|
|
1154
1167
|
const refreshed = await this.refreshRejectedAccessToken(attemptedCredential.accessToken);
|
|
1155
1168
|
if (refreshed) {
|
|
1156
1169
|
applyAuthHeaders(headers, refreshed);
|
|
1157
|
-
res = await
|
|
1170
|
+
res = await fetchWithReadRetry();
|
|
1158
1171
|
}
|
|
1159
1172
|
}
|
|
1160
1173
|
} catch (err) {
|
|
@@ -1806,26 +1819,29 @@ var TopoloClient = class _TopoloClient {
|
|
|
1806
1819
|
};
|
|
1807
1820
|
function validateActionResource(entry, resource) {
|
|
1808
1821
|
const permissionName = entry.permissionName || entry.requiredPermission.split(".").at(-1) || "";
|
|
1809
|
-
|
|
1822
|
+
const declaredContext = entry.agentContract?.resourceContext;
|
|
1823
|
+
const declaredKind = typeof declaredContext?.kind === "string" ? declaredContext.kind.trim() : "";
|
|
1824
|
+
const expectedType = declaredKind || (permissionName.startsWith("workspace:") ? "workspace" : "");
|
|
1825
|
+
if (!expectedType || declaredContext?.required === false && !permissionName.startsWith("workspace:")) return null;
|
|
1810
1826
|
if (!resource) {
|
|
1811
1827
|
return {
|
|
1812
1828
|
path: "$.resource",
|
|
1813
1829
|
code: "required",
|
|
1814
|
-
message:
|
|
1830
|
+
message: `Select resourceType "${expectedType}" with the application resource catalog before planning or calling this action.`
|
|
1815
1831
|
};
|
|
1816
1832
|
}
|
|
1817
|
-
if (resource.resourceType !==
|
|
1833
|
+
if (resource.resourceType !== expectedType) {
|
|
1818
1834
|
return {
|
|
1819
1835
|
path: "$.resource.resourceType",
|
|
1820
1836
|
code: "const",
|
|
1821
|
-
message:
|
|
1837
|
+
message: `This action requires resourceType "${expectedType}".`
|
|
1822
1838
|
};
|
|
1823
1839
|
}
|
|
1824
1840
|
if (!resource.resourceId.trim()) {
|
|
1825
1841
|
return {
|
|
1826
1842
|
path: "$.resource.resourceId",
|
|
1827
1843
|
code: "required",
|
|
1828
|
-
message:
|
|
1844
|
+
message: `This action requires a ${expectedType} resourceId.`
|
|
1829
1845
|
};
|
|
1830
1846
|
}
|
|
1831
1847
|
return null;
|
|
@@ -2199,7 +2215,8 @@ function compactActionCatalogEntry(action) {
|
|
|
2199
2215
|
agentAccess: action.agentAccess ?? (action.requiresConfirmation ? "confirm" : action.readOnly ? "auto" : "confirm"),
|
|
2200
2216
|
requiredPermission: action.requiredPermission,
|
|
2201
2217
|
requiredInput: required,
|
|
2202
|
-
resourceType: action.agentContract?.
|
|
2218
|
+
resourceType: action.agentContract?.resourceContext?.kind ?? (action.permissionName.startsWith("workspace:") ? "workspace" : null),
|
|
2219
|
+
resultResourceType: action.agentContract?.resource?.kind ?? null,
|
|
2203
2220
|
exampleInput: example.value,
|
|
2204
2221
|
exampleInputAvailable: example.available,
|
|
2205
2222
|
docsUrl: action.agentContract?.docsUrl ?? null
|
|
@@ -3220,7 +3237,7 @@ var TopoloOAuth = class {
|
|
|
3220
3237
|
};
|
|
3221
3238
|
|
|
3222
3239
|
// src/widget-validation.ts
|
|
3223
|
-
var CONTRACT_VERSION = "
|
|
3240
|
+
var CONTRACT_VERSION = "3.0.0";
|
|
3224
3241
|
var WIDGET_TYPES = ["stats", "chart", "activity", "notifications", "actions"];
|
|
3225
3242
|
var CONTEXTS = ["personal", "organization", "workspace", "resource"];
|
|
3226
3243
|
var SIZES = ["compact", "medium", "wide", "full"];
|
|
@@ -3231,6 +3248,9 @@ var AGGREGATIONS = ["last", "sum", "average", "minimum", "maximum", "count", "di
|
|
|
3231
3248
|
var CHART_TYPES = ["line", "bar", "area", "pie", "donut"];
|
|
3232
3249
|
var SEVERITIES = ["info", "warning", "error", "success"];
|
|
3233
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"];
|
|
3234
3254
|
var SEMVER = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
|
|
3235
3255
|
function validateTopoloWidgetResponse(response) {
|
|
3236
3256
|
const errors = [];
|
|
@@ -3281,6 +3301,7 @@ function validateWidget(value, path, errors) {
|
|
|
3281
3301
|
validateActions(value.controls, `${path}.controls`, errors);
|
|
3282
3302
|
validateLocalization(value.localization, `${path}.localization`, errors);
|
|
3283
3303
|
validateAccessibility(value.accessibility, `${path}.accessibility`, errors);
|
|
3304
|
+
validateContribution(value.contribution, `${path}.contribution`, value, errors);
|
|
3284
3305
|
switch (value.type) {
|
|
3285
3306
|
case "stats":
|
|
3286
3307
|
validateMetrics(value.metrics, `${path}.metrics`, errors, requiresContent(value));
|
|
@@ -3410,12 +3431,216 @@ function validateLocalization(value, path, errors) {
|
|
|
3410
3431
|
nonEmptyString(value.locale, `${path}.locale`, errors);
|
|
3411
3432
|
nonEmptyString(value.titleKey, `${path}.titleKey`, errors);
|
|
3412
3433
|
optionalNonEmptyString(value.descriptionKey, `${path}.descriptionKey`, errors);
|
|
3434
|
+
optionalNonEmptyString(value.title, `${path}.title`, errors);
|
|
3435
|
+
optionalNonEmptyString(value.description, `${path}.description`, errors);
|
|
3413
3436
|
}
|
|
3414
3437
|
function validateAccessibility(value, path, errors) {
|
|
3415
3438
|
if (!recordValue(value, path, errors)) return;
|
|
3416
3439
|
nonEmptyString(value.label, `${path}.label`, errors);
|
|
3417
3440
|
optionalNonEmptyString(value.description, `${path}.description`, errors);
|
|
3418
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
|
+
}
|
|
3419
3644
|
function validateMetrics(value, path, errors, requireOne) {
|
|
3420
3645
|
if (!arrayValue(value, path, errors, requireOne)) return;
|
|
3421
3646
|
value.forEach((metric, index) => {
|
|
@@ -3583,7 +3808,7 @@ function isRecord5(value) {
|
|
|
3583
3808
|
// src/widgets.ts
|
|
3584
3809
|
var TOPOLO_WIDGET_ENDPOINT = "/api/widget";
|
|
3585
3810
|
var TOPOLO_WIDGET_REFRESH_INTERVAL_MS = 6e4;
|
|
3586
|
-
var TOPOLO_WIDGET_CONTRACT_VERSION = "
|
|
3811
|
+
var TOPOLO_WIDGET_CONTRACT_VERSION = "3.0.0";
|
|
3587
3812
|
function defineTopoloStatsWidget(widget) {
|
|
3588
3813
|
return { ...widget, type: "stats" };
|
|
3589
3814
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@topolo/sdk",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"topoloPublishedVersion": "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",
|