@topolo/sdk 0.12.0 → 0.13.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 +27 -8
- package/dist/index.d.cts +15 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +27 -8
- 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
|
|
@@ -3494,6 +3511,8 @@ function validateLocalization(value, path, errors) {
|
|
|
3494
3511
|
nonEmptyString(value.locale, `${path}.locale`, errors);
|
|
3495
3512
|
nonEmptyString(value.titleKey, `${path}.titleKey`, errors);
|
|
3496
3513
|
optionalNonEmptyString(value.descriptionKey, `${path}.descriptionKey`, errors);
|
|
3514
|
+
optionalNonEmptyString(value.title, `${path}.title`, errors);
|
|
3515
|
+
optionalNonEmptyString(value.description, `${path}.description`, errors);
|
|
3497
3516
|
}
|
|
3498
3517
|
function validateAccessibility(value, path, errors) {
|
|
3499
3518
|
if (!recordValue(value, path, errors)) return;
|
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;
|
|
@@ -1325,6 +1330,16 @@ 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;
|
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;
|
|
@@ -1325,6 +1330,16 @@ 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;
|
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
|
|
@@ -3410,6 +3427,8 @@ function validateLocalization(value, path, errors) {
|
|
|
3410
3427
|
nonEmptyString(value.locale, `${path}.locale`, errors);
|
|
3411
3428
|
nonEmptyString(value.titleKey, `${path}.titleKey`, errors);
|
|
3412
3429
|
optionalNonEmptyString(value.descriptionKey, `${path}.descriptionKey`, errors);
|
|
3430
|
+
optionalNonEmptyString(value.title, `${path}.title`, errors);
|
|
3431
|
+
optionalNonEmptyString(value.description, `${path}.description`, errors);
|
|
3413
3432
|
}
|
|
3414
3433
|
function validateAccessibility(value, path, errors) {
|
|
3415
3434
|
if (!recordValue(value, path, errors)) return;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@topolo/sdk",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"topoloPublishedVersion": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
|
+
"topoloPublishedVersion": "0.13.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",
|