@uipath/insights-sdk 1.204.0-preview.255 → 1.205.0-preview.256
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.browser.js +233 -4
- package/dist/index.js +363 -27
- package/dist/src/errors.d.ts +12 -0
- package/dist/src/index.d.ts +3 -1
- package/dist/src/looker-dashboards.d.ts +42 -0
- package/dist/src/transport.d.ts +11 -0
- package/package.json +2 -2
package/dist/index.browser.js
CHANGED
|
@@ -287,6 +287,19 @@ var KNOWN_ERROR_LABELS = new Set([
|
|
|
287
287
|
DASHBOARD_NOT_FOUND_LABEL,
|
|
288
288
|
MODEL_NOT_FOUND_LABEL
|
|
289
289
|
]);
|
|
290
|
+
var PORTAL_ERROR_CODE = {
|
|
291
|
+
InvalidUserInput: 6,
|
|
292
|
+
LookerUnavailableError: 8,
|
|
293
|
+
PermissionsUserUnauthorized: 10,
|
|
294
|
+
UnableToGetEmbedLink: 23,
|
|
295
|
+
UnableToRetrieveDashboards: 26
|
|
296
|
+
};
|
|
297
|
+
var LOOKER_USER_UNAVAILABLE_MESSAGE = "Unable to get Looker userInfo";
|
|
298
|
+
var LOOKER_NO_DASHBOARDS_MESSAGE = "Unable to retrieve dashboards";
|
|
299
|
+
var KNOWN_PORTAL_ERROR_MESSAGES = new Set([
|
|
300
|
+
LOOKER_USER_UNAVAILABLE_MESSAGE,
|
|
301
|
+
LOOKER_NO_DASHBOARDS_MESSAGE
|
|
302
|
+
]);
|
|
290
303
|
|
|
291
304
|
class InsightsHttpError extends Error {
|
|
292
305
|
status;
|
|
@@ -385,7 +398,9 @@ var ErrorDimensions = {
|
|
|
385
398
|
Result: "Result",
|
|
386
399
|
ErrorCode: "ErrorCode",
|
|
387
400
|
Retry: "Retry",
|
|
388
|
-
ErrorMessage: "ErrorMessage"
|
|
401
|
+
ErrorMessage: "ErrorMessage",
|
|
402
|
+
HttpStatus: "HttpStatus",
|
|
403
|
+
UpstreamErrorCode: "UpstreamErrorCode"
|
|
389
404
|
};
|
|
390
405
|
var AuthDimensions = {
|
|
391
406
|
AuthenticationMethod: "AuthenticationMethod",
|
|
@@ -489,7 +504,7 @@ var package_default = {
|
|
|
489
504
|
name: "@uipath/insights-sdk",
|
|
490
505
|
author: "UiPath",
|
|
491
506
|
license: "SEE LICENSE IN LICENSE.txt",
|
|
492
|
-
version: "1.
|
|
507
|
+
version: "1.205.0-preview.256",
|
|
493
508
|
description: "SDK for the UiPath Insights API — jobs, failures, and performance metrics.",
|
|
494
509
|
repository: {
|
|
495
510
|
type: "git",
|
|
@@ -694,6 +709,16 @@ var INSIGHTS_ROUTES = {
|
|
|
694
709
|
method: "POST",
|
|
695
710
|
template: "Authorization/tenant/insights"
|
|
696
711
|
},
|
|
712
|
+
lookerDashboardsList: {
|
|
713
|
+
service: "portal",
|
|
714
|
+
method: "GET",
|
|
715
|
+
template: "AllDashboards/folders"
|
|
716
|
+
},
|
|
717
|
+
lookerDashboardEmbedUrl: {
|
|
718
|
+
service: "portal",
|
|
719
|
+
method: "POST",
|
|
720
|
+
template: "DashboardUrl"
|
|
721
|
+
},
|
|
697
722
|
exportConfigurationsList: {
|
|
698
723
|
service: "portal",
|
|
699
724
|
method: "GET",
|
|
@@ -795,9 +820,43 @@ function buildServiceHeaders(config, route, hasBody) {
|
|
|
795
820
|
return headers;
|
|
796
821
|
}
|
|
797
822
|
var MODEL_PATH_PATTERN = /^[A-Za-z0-9_.[\]]{1,200}$/;
|
|
823
|
+
var MAX_PORTAL_ERROR_CODE = 999;
|
|
824
|
+
function isJsonObject(value) {
|
|
825
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
826
|
+
}
|
|
827
|
+
function readPortalErrorCode(error) {
|
|
828
|
+
if (!isJsonObject(error)) {
|
|
829
|
+
return;
|
|
830
|
+
}
|
|
831
|
+
const code = error.errorCode;
|
|
832
|
+
if (typeof code !== "number" || !Number.isInteger(code) || code < 0 || code > MAX_PORTAL_ERROR_CODE) {
|
|
833
|
+
return;
|
|
834
|
+
}
|
|
835
|
+
return code;
|
|
836
|
+
}
|
|
837
|
+
function readPortalErrorMessage(error) {
|
|
838
|
+
if (!isJsonObject(error)) {
|
|
839
|
+
return;
|
|
840
|
+
}
|
|
841
|
+
const message = error.message;
|
|
842
|
+
if (typeof message !== "string" || !KNOWN_PORTAL_ERROR_MESSAGES.has(message)) {
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
845
|
+
return message;
|
|
846
|
+
}
|
|
847
|
+
function liftPortalError(hint, error) {
|
|
848
|
+
const portalErrorCode = readPortalErrorCode(error);
|
|
849
|
+
if (portalErrorCode !== undefined) {
|
|
850
|
+
hint.portalErrorCode = portalErrorCode;
|
|
851
|
+
}
|
|
852
|
+
const portalErrorMessage = readPortalErrorMessage(error);
|
|
853
|
+
if (portalErrorMessage !== undefined) {
|
|
854
|
+
hint.portalErrorMessage = portalErrorMessage;
|
|
855
|
+
}
|
|
856
|
+
}
|
|
798
857
|
function describeJsonErrorBody(parsed) {
|
|
799
858
|
if (typeof parsed === "string") {
|
|
800
|
-
return
|
|
859
|
+
return describeStringErrorBody(parsed);
|
|
801
860
|
}
|
|
802
861
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
803
862
|
return { shape: "other" };
|
|
@@ -817,6 +876,19 @@ function describeJsonErrorBody(parsed) {
|
|
|
817
876
|
hint.firstInvalidField = firstKey;
|
|
818
877
|
}
|
|
819
878
|
}
|
|
879
|
+
liftPortalError(hint, record.error);
|
|
880
|
+
return hint;
|
|
881
|
+
}
|
|
882
|
+
function describeStringErrorBody(parsed) {
|
|
883
|
+
const hint = { shape: "string" };
|
|
884
|
+
const [parseError, inner] = catchError(() => JSON.parse(parsed));
|
|
885
|
+
if (parseError) {
|
|
886
|
+
return hint;
|
|
887
|
+
}
|
|
888
|
+
if (!isJsonObject(inner)) {
|
|
889
|
+
return hint;
|
|
890
|
+
}
|
|
891
|
+
liftPortalError(hint, inner.error);
|
|
820
892
|
return hint;
|
|
821
893
|
}
|
|
822
894
|
function describeErrorBody(text) {
|
|
@@ -1410,6 +1482,151 @@ async function listQueueFilters(config) {
|
|
|
1410
1482
|
async function listMachineFilters(config) {
|
|
1411
1483
|
return listFilters(config, "filtersAllMachines", isMachineFiltersResponse, "machine filters");
|
|
1412
1484
|
}
|
|
1485
|
+
// src/looker-dashboards.ts
|
|
1486
|
+
var TEMPLATE_ID_DELIMITER = "::";
|
|
1487
|
+
var INTEGER_ID_PATTERN = /^\d+$/;
|
|
1488
|
+
var LOOKER_FOLDERS = [
|
|
1489
|
+
"personal",
|
|
1490
|
+
"tenant",
|
|
1491
|
+
"templates",
|
|
1492
|
+
"organization"
|
|
1493
|
+
];
|
|
1494
|
+
var LOOKER_THEMES = ["light", "dark"];
|
|
1495
|
+
async function listLookerDashboards(config) {
|
|
1496
|
+
return requestInsightsRoute(config, "lookerDashboardsList");
|
|
1497
|
+
}
|
|
1498
|
+
async function getLookerDashboardEmbedUrl(config, options) {
|
|
1499
|
+
const dashboardId = options.dashboardId.trim();
|
|
1500
|
+
if (dashboardId === "") {
|
|
1501
|
+
throw new Error("Insights Looker dashboard id must not be empty.");
|
|
1502
|
+
}
|
|
1503
|
+
if (!isDashboardId(dashboardId)) {
|
|
1504
|
+
throw new Error("Insights Looker dashboard id must be all digits or contain '::'; resolve a title with resolveLookerDashboard first.");
|
|
1505
|
+
}
|
|
1506
|
+
if (!LOOKER_THEMES.includes(options.theme)) {
|
|
1507
|
+
throw new Error(`Insights Looker theme must be one of ${LOOKER_THEMES.join(", ")}.`);
|
|
1508
|
+
}
|
|
1509
|
+
const locale = options.localization?.trim();
|
|
1510
|
+
if (locale === "") {
|
|
1511
|
+
throw new Error("Insights Looker localization must not be empty.");
|
|
1512
|
+
}
|
|
1513
|
+
return requestInsightsRoute(config, "lookerDashboardEmbedUrl", {
|
|
1514
|
+
body: {
|
|
1515
|
+
dashboardId,
|
|
1516
|
+
theme: options.theme,
|
|
1517
|
+
...locale === undefined ? {} : { locale }
|
|
1518
|
+
}
|
|
1519
|
+
});
|
|
1520
|
+
}
|
|
1521
|
+
function parseLookerEnvelope(raw, routeKey) {
|
|
1522
|
+
const endpoint = insightsRouteTemplate(routeKey);
|
|
1523
|
+
if (typeof raw !== "string") {
|
|
1524
|
+
throw new InsightsProtocolError(endpoint, "the body is not the JSON string literal this root answers with");
|
|
1525
|
+
}
|
|
1526
|
+
const [parseError, envelope] = catchError(() => JSON.parse(raw));
|
|
1527
|
+
if (parseError) {
|
|
1528
|
+
throw new InsightsProtocolError(endpoint, "the body string does not hold JSON");
|
|
1529
|
+
}
|
|
1530
|
+
if (!isJsonObject(envelope)) {
|
|
1531
|
+
throw new InsightsProtocolError(endpoint, "the body string does not hold an object");
|
|
1532
|
+
}
|
|
1533
|
+
if (typeof envelope.isSuccess !== "boolean") {
|
|
1534
|
+
throw new InsightsProtocolError(endpoint, "the body carries no boolean isSuccess");
|
|
1535
|
+
}
|
|
1536
|
+
if (envelope.isSuccess !== true) {
|
|
1537
|
+
throw new InsightsProtocolError(endpoint, "the body reports isSuccess false inside a success status");
|
|
1538
|
+
}
|
|
1539
|
+
if (envelope.result === undefined || envelope.result === null) {
|
|
1540
|
+
throw new InsightsProtocolError(endpoint, "the body carries no result");
|
|
1541
|
+
}
|
|
1542
|
+
return envelope.result;
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1545
|
+
class LookerResolveError extends Error {
|
|
1546
|
+
kind;
|
|
1547
|
+
candidates;
|
|
1548
|
+
constructor(kind, message, candidates = []) {
|
|
1549
|
+
super(message);
|
|
1550
|
+
this.name = "LookerResolveError";
|
|
1551
|
+
this.kind = kind;
|
|
1552
|
+
this.candidates = candidates;
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
function isDashboardId(value) {
|
|
1556
|
+
return INTEGER_ID_PATTERN.test(value) || value.includes(TEMPLATE_ID_DELIMITER);
|
|
1557
|
+
}
|
|
1558
|
+
function isLookerTemplateDashboardId(id) {
|
|
1559
|
+
return !INTEGER_ID_PATTERN.test(id);
|
|
1560
|
+
}
|
|
1561
|
+
function readLookerListing(raw) {
|
|
1562
|
+
const endpoint = insightsRouteTemplate("lookerDashboardsList");
|
|
1563
|
+
const folders = parseLookerEnvelope(raw, "lookerDashboardsList");
|
|
1564
|
+
if (!isJsonObject(folders)) {
|
|
1565
|
+
throw new InsightsProtocolError(endpoint, "the result is not an object");
|
|
1566
|
+
}
|
|
1567
|
+
const listing = { rows: [], omittedFolders: [] };
|
|
1568
|
+
for (const folder of LOOKER_FOLDERS) {
|
|
1569
|
+
const group = readFolderGroup(folders[folder], folder, endpoint);
|
|
1570
|
+
if (group === null) {
|
|
1571
|
+
listing.omittedFolders.push(folder);
|
|
1572
|
+
continue;
|
|
1573
|
+
}
|
|
1574
|
+
for (const element of group) {
|
|
1575
|
+
listing.rows.push(readListingRow(element, folder, endpoint));
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
return listing;
|
|
1579
|
+
}
|
|
1580
|
+
function readFolderGroup(group, folder, endpoint) {
|
|
1581
|
+
if (group === undefined) {
|
|
1582
|
+
throw new InsightsProtocolError(endpoint, `the result carries no ${folder} key`);
|
|
1583
|
+
}
|
|
1584
|
+
if (group === null) {
|
|
1585
|
+
return null;
|
|
1586
|
+
}
|
|
1587
|
+
if (!Array.isArray(group)) {
|
|
1588
|
+
throw new InsightsProtocolError(endpoint, `the result's ${folder} is neither an array nor null`);
|
|
1589
|
+
}
|
|
1590
|
+
return group;
|
|
1591
|
+
}
|
|
1592
|
+
function readListingRow(record, folder, endpoint) {
|
|
1593
|
+
if (!isJsonObject(record)) {
|
|
1594
|
+
throw new InsightsProtocolError(endpoint, `a row in the ${folder} folder is not an object`);
|
|
1595
|
+
}
|
|
1596
|
+
if (typeof record.id !== "string") {
|
|
1597
|
+
throw new InsightsProtocolError(endpoint, `a row in the ${folder} folder has no string id`);
|
|
1598
|
+
}
|
|
1599
|
+
if (record.title !== null && typeof record.title !== "string") {
|
|
1600
|
+
throw new InsightsProtocolError(endpoint, `a row in the ${folder} folder has a title that is neither a string nor null`);
|
|
1601
|
+
}
|
|
1602
|
+
return { folder, id: record.id, title: record.title, record };
|
|
1603
|
+
}
|
|
1604
|
+
async function resolveLookerDashboard(config, value) {
|
|
1605
|
+
const trimmed = value.trim();
|
|
1606
|
+
if (trimmed === "") {
|
|
1607
|
+
throw new Error("Insights Looker dashboard must not be empty.");
|
|
1608
|
+
}
|
|
1609
|
+
if (isDashboardId(trimmed)) {
|
|
1610
|
+
return { id: trimmed, resolvedFrom: "id" };
|
|
1611
|
+
}
|
|
1612
|
+
const { rows } = readLookerListing(await listLookerDashboards(config));
|
|
1613
|
+
const matches = rows.filter((row) => row.title?.trim() === trimmed);
|
|
1614
|
+
if (matches.length === 0) {
|
|
1615
|
+
throw new LookerResolveError("notFound", "No Looker dashboard with that title is listed for this session.");
|
|
1616
|
+
}
|
|
1617
|
+
for (const match of matches) {
|
|
1618
|
+
requireEmbeddableId(match);
|
|
1619
|
+
}
|
|
1620
|
+
if (matches.length > 1) {
|
|
1621
|
+
throw new LookerResolveError("ambiguous", `${matches.length} Looker dashboards share that title.`, matches.map((row) => ({ folder: row.folder, id: row.id })));
|
|
1622
|
+
}
|
|
1623
|
+
return { id: matches[0].id, resolvedFrom: "title" };
|
|
1624
|
+
}
|
|
1625
|
+
function requireEmbeddableId(row) {
|
|
1626
|
+
if (!isDashboardId(row.id)) {
|
|
1627
|
+
throw new InsightsProtocolError(insightsRouteTemplate("lookerDashboardsList"), `a row in the ${row.folder} folder has an id that is neither all digits nor contains '::'`);
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1413
1630
|
// src/machines.ts
|
|
1414
1631
|
function isNullish(value) {
|
|
1415
1632
|
return value === undefined || value === null;
|
|
@@ -1667,10 +1884,16 @@ export {
|
|
|
1667
1884
|
InsightsHttpError,
|
|
1668
1885
|
InsightsNetworkError,
|
|
1669
1886
|
InsightsProtocolError,
|
|
1887
|
+
LOOKER_FOLDERS,
|
|
1888
|
+
LOOKER_NO_DASHBOARDS_MESSAGE,
|
|
1889
|
+
LOOKER_THEMES,
|
|
1890
|
+
LOOKER_USER_UNAVAILABLE_MESSAGE,
|
|
1891
|
+
LookerResolveError,
|
|
1670
1892
|
MAESTRO_CASE_DASHBOARD_PREFIX,
|
|
1671
1893
|
MAESTRO_DASHBOARD_SOURCE_TYPE,
|
|
1672
1894
|
MAESTRO_PROCESS_DASHBOARD_PREFIX,
|
|
1673
1895
|
MODEL_NOT_FOUND_LABEL,
|
|
1896
|
+
PORTAL_ERROR_CODE,
|
|
1674
1897
|
UPDATE_BACKEND_FAILURE_LABEL,
|
|
1675
1898
|
VALIDATION_FAILED_LABEL,
|
|
1676
1899
|
checkAlertEntitlement,
|
|
@@ -1686,6 +1909,7 @@ export {
|
|
|
1686
1909
|
getDashboardTemplate,
|
|
1687
1910
|
getDefaultDelivery,
|
|
1688
1911
|
getGroup,
|
|
1912
|
+
getLookerDashboardEmbedUrl,
|
|
1689
1913
|
getMachineAvailabilityTimeline,
|
|
1690
1914
|
getMachineDetails,
|
|
1691
1915
|
getMachineRuntimeMix,
|
|
@@ -1704,6 +1928,7 @@ export {
|
|
|
1704
1928
|
getRole,
|
|
1705
1929
|
getUser,
|
|
1706
1930
|
insightsPost,
|
|
1931
|
+
isLookerTemplateDashboardId,
|
|
1707
1932
|
isTemplateKeyedDashboardId,
|
|
1708
1933
|
listAgenticAlertDefinitions,
|
|
1709
1934
|
listAlertDefinitions,
|
|
@@ -1712,15 +1937,19 @@ export {
|
|
|
1712
1937
|
listExportConfigurations,
|
|
1713
1938
|
listFolderFilters,
|
|
1714
1939
|
listGroups,
|
|
1940
|
+
listLookerDashboards,
|
|
1715
1941
|
listMachineFilters,
|
|
1716
1942
|
listProcessFilters,
|
|
1717
1943
|
listQueueFilters,
|
|
1718
1944
|
listRoles,
|
|
1719
1945
|
listUsers,
|
|
1720
1946
|
parseDashboardSlotId,
|
|
1947
|
+
parseLookerEnvelope,
|
|
1948
|
+
readLookerListing,
|
|
1949
|
+
resolveLookerDashboard,
|
|
1721
1950
|
updateDashboard,
|
|
1722
1951
|
verifyAllExportDestinations,
|
|
1723
1952
|
verifyExportDestination
|
|
1724
1953
|
};
|
|
1725
1954
|
|
|
1726
|
-
//# debugId=
|
|
1955
|
+
//# debugId=24115FDAD6FC2C8364756E2164756E21
|
package/dist/index.js
CHANGED
|
@@ -883,6 +883,16 @@ class NodeFileSystem {
|
|
|
883
883
|
async rename(oldPath, newPath) {
|
|
884
884
|
await fs6.rename(oldPath, newPath);
|
|
885
885
|
}
|
|
886
|
+
async isSymbolicLink(filePath) {
|
|
887
|
+
try {
|
|
888
|
+
return (await fs6.lstat(filePath)).isSymbolicLink();
|
|
889
|
+
} catch (error) {
|
|
890
|
+
if (this.isEnoent(error) || this.hasErrnoCode(error, "ENOTDIR")) {
|
|
891
|
+
return false;
|
|
892
|
+
}
|
|
893
|
+
throw error;
|
|
894
|
+
}
|
|
895
|
+
}
|
|
886
896
|
async realpath(filePath) {
|
|
887
897
|
try {
|
|
888
898
|
return await fs6.realpath(filePath);
|
|
@@ -1227,6 +1237,19 @@ var KNOWN_ERROR_LABELS = new Set([
|
|
|
1227
1237
|
DASHBOARD_NOT_FOUND_LABEL,
|
|
1228
1238
|
MODEL_NOT_FOUND_LABEL
|
|
1229
1239
|
]);
|
|
1240
|
+
var PORTAL_ERROR_CODE = {
|
|
1241
|
+
InvalidUserInput: 6,
|
|
1242
|
+
LookerUnavailableError: 8,
|
|
1243
|
+
PermissionsUserUnauthorized: 10,
|
|
1244
|
+
UnableToGetEmbedLink: 23,
|
|
1245
|
+
UnableToRetrieveDashboards: 26
|
|
1246
|
+
};
|
|
1247
|
+
var LOOKER_USER_UNAVAILABLE_MESSAGE = "Unable to get Looker userInfo";
|
|
1248
|
+
var LOOKER_NO_DASHBOARDS_MESSAGE = "Unable to retrieve dashboards";
|
|
1249
|
+
var KNOWN_PORTAL_ERROR_MESSAGES = new Set([
|
|
1250
|
+
LOOKER_USER_UNAVAILABLE_MESSAGE,
|
|
1251
|
+
LOOKER_NO_DASHBOARDS_MESSAGE
|
|
1252
|
+
]);
|
|
1230
1253
|
|
|
1231
1254
|
class InsightsHttpError extends Error {
|
|
1232
1255
|
status;
|
|
@@ -1325,7 +1348,9 @@ var ErrorDimensions = {
|
|
|
1325
1348
|
Result: "Result",
|
|
1326
1349
|
ErrorCode: "ErrorCode",
|
|
1327
1350
|
Retry: "Retry",
|
|
1328
|
-
ErrorMessage: "ErrorMessage"
|
|
1351
|
+
ErrorMessage: "ErrorMessage",
|
|
1352
|
+
HttpStatus: "HttpStatus",
|
|
1353
|
+
UpstreamErrorCode: "UpstreamErrorCode"
|
|
1329
1354
|
};
|
|
1330
1355
|
var AuthDimensions = {
|
|
1331
1356
|
AuthenticationMethod: "AuthenticationMethod",
|
|
@@ -1429,7 +1454,7 @@ var package_default = {
|
|
|
1429
1454
|
name: "@uipath/insights-sdk",
|
|
1430
1455
|
author: "UiPath",
|
|
1431
1456
|
license: "SEE LICENSE IN LICENSE.txt",
|
|
1432
|
-
version: "1.
|
|
1457
|
+
version: "1.205.0-preview.256",
|
|
1433
1458
|
description: "SDK for the UiPath Insights API — jobs, failures, and performance metrics.",
|
|
1434
1459
|
repository: {
|
|
1435
1460
|
type: "git",
|
|
@@ -1634,6 +1659,16 @@ var INSIGHTS_ROUTES = {
|
|
|
1634
1659
|
method: "POST",
|
|
1635
1660
|
template: "Authorization/tenant/insights"
|
|
1636
1661
|
},
|
|
1662
|
+
lookerDashboardsList: {
|
|
1663
|
+
service: "portal",
|
|
1664
|
+
method: "GET",
|
|
1665
|
+
template: "AllDashboards/folders"
|
|
1666
|
+
},
|
|
1667
|
+
lookerDashboardEmbedUrl: {
|
|
1668
|
+
service: "portal",
|
|
1669
|
+
method: "POST",
|
|
1670
|
+
template: "DashboardUrl"
|
|
1671
|
+
},
|
|
1637
1672
|
exportConfigurationsList: {
|
|
1638
1673
|
service: "portal",
|
|
1639
1674
|
method: "GET",
|
|
@@ -1735,9 +1770,43 @@ function buildServiceHeaders(config, route, hasBody) {
|
|
|
1735
1770
|
return headers;
|
|
1736
1771
|
}
|
|
1737
1772
|
var MODEL_PATH_PATTERN = /^[A-Za-z0-9_.[\]]{1,200}$/;
|
|
1773
|
+
var MAX_PORTAL_ERROR_CODE = 999;
|
|
1774
|
+
function isJsonObject(value) {
|
|
1775
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1776
|
+
}
|
|
1777
|
+
function readPortalErrorCode(error) {
|
|
1778
|
+
if (!isJsonObject(error)) {
|
|
1779
|
+
return;
|
|
1780
|
+
}
|
|
1781
|
+
const code = error.errorCode;
|
|
1782
|
+
if (typeof code !== "number" || !Number.isInteger(code) || code < 0 || code > MAX_PORTAL_ERROR_CODE) {
|
|
1783
|
+
return;
|
|
1784
|
+
}
|
|
1785
|
+
return code;
|
|
1786
|
+
}
|
|
1787
|
+
function readPortalErrorMessage(error) {
|
|
1788
|
+
if (!isJsonObject(error)) {
|
|
1789
|
+
return;
|
|
1790
|
+
}
|
|
1791
|
+
const message = error.message;
|
|
1792
|
+
if (typeof message !== "string" || !KNOWN_PORTAL_ERROR_MESSAGES.has(message)) {
|
|
1793
|
+
return;
|
|
1794
|
+
}
|
|
1795
|
+
return message;
|
|
1796
|
+
}
|
|
1797
|
+
function liftPortalError(hint, error) {
|
|
1798
|
+
const portalErrorCode = readPortalErrorCode(error);
|
|
1799
|
+
if (portalErrorCode !== undefined) {
|
|
1800
|
+
hint.portalErrorCode = portalErrorCode;
|
|
1801
|
+
}
|
|
1802
|
+
const portalErrorMessage = readPortalErrorMessage(error);
|
|
1803
|
+
if (portalErrorMessage !== undefined) {
|
|
1804
|
+
hint.portalErrorMessage = portalErrorMessage;
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1738
1807
|
function describeJsonErrorBody(parsed) {
|
|
1739
1808
|
if (typeof parsed === "string") {
|
|
1740
|
-
return
|
|
1809
|
+
return describeStringErrorBody(parsed);
|
|
1741
1810
|
}
|
|
1742
1811
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
1743
1812
|
return { shape: "other" };
|
|
@@ -1757,6 +1826,19 @@ function describeJsonErrorBody(parsed) {
|
|
|
1757
1826
|
hint.firstInvalidField = firstKey;
|
|
1758
1827
|
}
|
|
1759
1828
|
}
|
|
1829
|
+
liftPortalError(hint, record.error);
|
|
1830
|
+
return hint;
|
|
1831
|
+
}
|
|
1832
|
+
function describeStringErrorBody(parsed) {
|
|
1833
|
+
const hint = { shape: "string" };
|
|
1834
|
+
const [parseError, inner] = catchError(() => JSON.parse(parsed));
|
|
1835
|
+
if (parseError) {
|
|
1836
|
+
return hint;
|
|
1837
|
+
}
|
|
1838
|
+
if (!isJsonObject(inner)) {
|
|
1839
|
+
return hint;
|
|
1840
|
+
}
|
|
1841
|
+
liftPortalError(hint, inner.error);
|
|
1760
1842
|
return hint;
|
|
1761
1843
|
}
|
|
1762
1844
|
function describeErrorBody(text) {
|
|
@@ -2014,22 +2096,12 @@ var resolveConfigAsync = async ({
|
|
|
2014
2096
|
baseUrl = DEFAULT_BASE_URL;
|
|
2015
2097
|
}
|
|
2016
2098
|
baseUrl = normalizeAndValidateBaseUrl(baseUrl);
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
clientId = fileAuth.clientId;
|
|
2020
|
-
}
|
|
2021
|
-
if (!clientId) {
|
|
2022
|
-
clientId = DEFAULT_CLIENT_ID;
|
|
2023
|
-
}
|
|
2024
|
-
let clientSecret = customClientSecret;
|
|
2025
|
-
if (!clientSecret && fileAuth.clientSecret) {
|
|
2026
|
-
clientSecret = fileAuth.clientSecret;
|
|
2027
|
-
}
|
|
2028
|
-
const isExternalAppAuth = clientId !== DEFAULT_CLIENT_ID && (Boolean(clientSecret) || Boolean(customClientAssertion));
|
|
2099
|
+
const clientId = customClientId || DEFAULT_CLIENT_ID;
|
|
2100
|
+
const isExternalAppAuth = clientId !== DEFAULT_CLIENT_ID && (Boolean(customClientSecret) || Boolean(customClientAssertion));
|
|
2029
2101
|
const scopes = resolveScopes(isExternalAppAuth, customScopes, fileAuth.scopes);
|
|
2030
2102
|
return {
|
|
2031
2103
|
clientId,
|
|
2032
|
-
clientSecret,
|
|
2104
|
+
clientSecret: customClientSecret,
|
|
2033
2105
|
scopes,
|
|
2034
2106
|
baseUrl,
|
|
2035
2107
|
authorizationEndpoint: `${baseUrl}/identity_/connect/authorize`,
|
|
@@ -2204,6 +2276,16 @@ var resolveIdentityType = (claims, authFlow, email) => {
|
|
|
2204
2276
|
}
|
|
2205
2277
|
return;
|
|
2206
2278
|
};
|
|
2279
|
+
var resolveApplicationSubtype = (claims, authFlow) => {
|
|
2280
|
+
switch (asString(claims?.sub_type)) {
|
|
2281
|
+
case "service.external":
|
|
2282
|
+
return "External";
|
|
2283
|
+
case "service.internal":
|
|
2284
|
+
return "Internal";
|
|
2285
|
+
default:
|
|
2286
|
+
return authFlow === "client_credentials" || authFlow === "federated_credentials" ? "External" : undefined;
|
|
2287
|
+
}
|
|
2288
|
+
};
|
|
2207
2289
|
var looksLikeEmail = (value) => value?.includes("@") ?? false;
|
|
2208
2290
|
var pickEmail = (claims) => {
|
|
2209
2291
|
for (const candidate of [claims?.email, claims?.preferred_username]) {
|
|
@@ -2245,6 +2327,12 @@ var resolveSessionIdentity = (accessToken, authFlow) => {
|
|
|
2245
2327
|
const clientId = asString(claims?.client_id);
|
|
2246
2328
|
if (clientId)
|
|
2247
2329
|
identity.clientId = clientId;
|
|
2330
|
+
const subType = asString(claims?.sub_type);
|
|
2331
|
+
if (subType)
|
|
2332
|
+
identity.subType = subType;
|
|
2333
|
+
const applicationSubtype = resolveApplicationSubtype(claims, authFlow);
|
|
2334
|
+
if (applicationSubtype)
|
|
2335
|
+
identity.applicationSubtype = applicationSubtype;
|
|
2248
2336
|
return identity;
|
|
2249
2337
|
};
|
|
2250
2338
|
var readTokenScopes = (accessToken) => accessToken ? pickScopes(decodeClaims(accessToken)) : undefined;
|
|
@@ -2539,6 +2627,40 @@ var tryRobotClientFallback = async (options = {}) => {
|
|
|
2539
2627
|
}
|
|
2540
2628
|
};
|
|
2541
2629
|
|
|
2630
|
+
// ../auth/src/tenantSelection.ts
|
|
2631
|
+
var LOGIN_STATUS_HINT = "Run 'uip login status' to see the organization the CLI is signed in to.";
|
|
2632
|
+
var organizationHint = (organizationId) => `The request used '${organizationId}' as the organization. ${LOGIN_STATUS_HINT}`;
|
|
2633
|
+
var IDENTIFIER_STATUSES = new Set([400, 403, 404]);
|
|
2634
|
+
var describeNonJsonResponse = (organizationId, response, parseError) => {
|
|
2635
|
+
if (response.redirected) {
|
|
2636
|
+
return `Could not find organization '${organizationId}': the request was ` + `redirected to a sign-in page instead of the organization's tenant ` + `list. ${LOGIN_STATUS_HINT}`;
|
|
2637
|
+
}
|
|
2638
|
+
const contentType = response.headers.get("content-type") ?? "unknown";
|
|
2639
|
+
return `The organization service returned a '${contentType}' response instead ` + `of JSON: ${parseError.message}. ${organizationHint(organizationId)}`;
|
|
2640
|
+
};
|
|
2641
|
+
var fetchTenantsAndOrganizations = async (baseUrl, accessToken, organizationId, signal) => {
|
|
2642
|
+
const url = `${baseUrl}/${organizationId}/portal_/api/filtering/leftnav/tenantsAndOrganizationInfo`;
|
|
2643
|
+
const response = await fetch(url, {
|
|
2644
|
+
headers: {
|
|
2645
|
+
Authorization: `Bearer ${accessToken}`
|
|
2646
|
+
},
|
|
2647
|
+
...signal ? { signal } : {}
|
|
2648
|
+
});
|
|
2649
|
+
if (!response.ok) {
|
|
2650
|
+
if (response.status === 401) {
|
|
2651
|
+
throw new Error(`Unauthorized: the access token was rejected, it was not ` + `issued for organization '${organizationId}', or ` + `'${organizationId}' was not accepted as an organization ` + `URL segment in this environment. ` + LOGIN_STATUS_HINT);
|
|
2652
|
+
}
|
|
2653
|
+
const errorText = await response.text();
|
|
2654
|
+
const message = `Failed to get tenants and organizations: ${response.status} ${errorText}`;
|
|
2655
|
+
throw new Error(IDENTIFIER_STATUSES.has(response.status) ? `${message}. ${organizationHint(organizationId)}` : message);
|
|
2656
|
+
}
|
|
2657
|
+
const [parseError, data] = await catchError2(response.json());
|
|
2658
|
+
if (parseError) {
|
|
2659
|
+
throw new Error(describeNonJsonResponse(organizationId, response, parseError));
|
|
2660
|
+
}
|
|
2661
|
+
return data;
|
|
2662
|
+
};
|
|
2663
|
+
|
|
2542
2664
|
// ../auth/src/tokenRefresh.ts
|
|
2543
2665
|
var TOKEN_REFRESH_REAUTHENTICATE_MESSAGE = "Token refresh failed. Run 'uip login' to re-authenticate.";
|
|
2544
2666
|
|
|
@@ -2753,6 +2875,8 @@ var saveEnvFileAsync = async ({
|
|
|
2753
2875
|
};
|
|
2754
2876
|
|
|
2755
2877
|
// ../auth/src/loginStatus.ts
|
|
2878
|
+
var defaultRobotTenantIdCache = new Map;
|
|
2879
|
+
var ROBOT_TENANT_LOOKUP_TIMEOUT_MS = 5000;
|
|
2756
2880
|
var getLoginStatusAsync = async (options = {}) => {
|
|
2757
2881
|
return getLoginStatusWithDeps(options);
|
|
2758
2882
|
};
|
|
@@ -2765,12 +2889,20 @@ var getLoginStatusWithDeps = async (options = {}, deps = {}) => {
|
|
|
2765
2889
|
refreshToken: refreshTokenFn = refreshAccessToken,
|
|
2766
2890
|
resolveConfig = resolveConfigAsync,
|
|
2767
2891
|
robotFallback = tryRobotClientFallback,
|
|
2892
|
+
fetchTenantsAndOrgs = fetchTenantsAndOrganizations,
|
|
2893
|
+
robotTenantIdCache = defaultRobotTenantIdCache,
|
|
2894
|
+
robotTenantLookupTimeoutMs = ROBOT_TENANT_LOOKUP_TIMEOUT_MS,
|
|
2768
2895
|
loadBreaker = loadRefreshBreaker,
|
|
2769
2896
|
saveBreaker = saveRefreshBreaker,
|
|
2770
2897
|
clearBreaker = clearRefreshBreaker
|
|
2771
2898
|
} = deps;
|
|
2899
|
+
const robotDeps = {
|
|
2900
|
+
fetchTenantsAndOrgs,
|
|
2901
|
+
cache: robotTenantIdCache,
|
|
2902
|
+
lookupTimeoutMs: robotTenantLookupTimeoutMs
|
|
2903
|
+
};
|
|
2772
2904
|
if (isRobotAuthEnforced()) {
|
|
2773
|
-
return resolveRobotEnforcedStatus(robotFallback);
|
|
2905
|
+
return resolveRobotEnforcedStatus(robotFallback, robotDeps);
|
|
2774
2906
|
}
|
|
2775
2907
|
if (isEnvAuthEnabled()) {
|
|
2776
2908
|
return readAuthFromEnv();
|
|
@@ -2788,7 +2920,7 @@ var getLoginStatusWithDeps = async (options = {}, deps = {}) => {
|
|
|
2788
2920
|
hint: `No credentials found for profile "${activeProfile}". Run 'uip login --profile ${activeProfile}' to authenticate this profile.`
|
|
2789
2921
|
};
|
|
2790
2922
|
}
|
|
2791
|
-
return resolveBorrowedRobotStatus(robotFallback);
|
|
2923
|
+
return resolveBorrowedRobotStatus(robotFallback, robotDeps);
|
|
2792
2924
|
}
|
|
2793
2925
|
const loaded = await loadFileCredentials(loadEnvFile, absolutePath);
|
|
2794
2926
|
if ("status" in loaded) {
|
|
@@ -2830,7 +2962,7 @@ var getLoginStatusWithDeps = async (options = {}, deps = {}) => {
|
|
|
2830
2962
|
}
|
|
2831
2963
|
return buildFileStatus(tokens, credentials, globalHint);
|
|
2832
2964
|
};
|
|
2833
|
-
async function resolveRobotEnforcedStatus(robotFallback) {
|
|
2965
|
+
async function resolveRobotEnforcedStatus(robotFallback, deps) {
|
|
2834
2966
|
if (isEnvAuthEnabled()) {
|
|
2835
2967
|
throw new EnvAuthConfigError(`${ENV_AUTH_ENABLE_VAR}=true and ${ENFORCE_ROBOT_AUTH_VAR}=true ` + `are mutually exclusive. Unset one of them and re-run.`);
|
|
2836
2968
|
}
|
|
@@ -2841,11 +2973,11 @@ async function resolveRobotEnforcedStatus(robotFallback) {
|
|
|
2841
2973
|
hint: `${ENFORCE_ROBOT_AUTH_VAR}=true but the UiPath Robot ` + `session is unavailable. Start and sign in to the Assistant, ` + `or unset ${ENFORCE_ROBOT_AUTH_VAR} to fall back to file or ` + `env-var authentication.`
|
|
2842
2974
|
};
|
|
2843
2975
|
}
|
|
2844
|
-
return buildRobotStatus(robotCreds);
|
|
2976
|
+
return buildRobotStatus(robotCreds, deps);
|
|
2845
2977
|
}
|
|
2846
|
-
async function resolveBorrowedRobotStatus(robotFallback) {
|
|
2978
|
+
async function resolveBorrowedRobotStatus(robotFallback, deps) {
|
|
2847
2979
|
const robotCreds = await robotFallback();
|
|
2848
|
-
return robotCreds ? buildRobotStatus(robotCreds) : { loginStatus: "Not logged in" };
|
|
2980
|
+
return robotCreds ? buildRobotStatus(robotCreds, deps) : { loginStatus: "Not logged in" };
|
|
2849
2981
|
}
|
|
2850
2982
|
async function loadFileCredentials(loadEnvFile, absolutePath) {
|
|
2851
2983
|
let credentials;
|
|
@@ -2980,9 +3112,10 @@ function identityFields(accessToken, credentials) {
|
|
|
2980
3112
|
...scopes ? { scopes } : {}
|
|
2981
3113
|
};
|
|
2982
3114
|
}
|
|
2983
|
-
function buildRobotStatus(robotCreds) {
|
|
3115
|
+
async function buildRobotStatus(robotCreds, deps) {
|
|
2984
3116
|
const identity = resolveSessionIdentity(robotCreds.accessToken);
|
|
2985
3117
|
const scopes = readTokenScopes(robotCreds.accessToken);
|
|
3118
|
+
const tenant = robotCreds.tenantId ? { tenantId: robotCreds.tenantId } : await resolveRobotTenantId(robotCreds, deps);
|
|
2986
3119
|
return {
|
|
2987
3120
|
loginStatus: "Logged in",
|
|
2988
3121
|
accessToken: robotCreds.accessToken,
|
|
@@ -2990,14 +3123,62 @@ function buildRobotStatus(robotCreds) {
|
|
|
2990
3123
|
organizationName: robotCreds.organizationName,
|
|
2991
3124
|
organizationId: robotCreds.organizationId,
|
|
2992
3125
|
tenantName: robotCreds.tenantName,
|
|
2993
|
-
tenantId:
|
|
3126
|
+
tenantId: tenant.tenantId,
|
|
2994
3127
|
issuer: robotCreds.issuer,
|
|
2995
3128
|
expiration: getTokenExpiration(robotCreds.accessToken),
|
|
2996
3129
|
source: "robot" /* Robot */,
|
|
3130
|
+
...tenant.hint ? { hint: tenant.hint } : {},
|
|
2997
3131
|
...identity ? { identity } : {},
|
|
2998
3132
|
...scopes ? { scopes } : {}
|
|
2999
3133
|
};
|
|
3000
3134
|
}
|
|
3135
|
+
async function resolveRobotTenantId(robotCreds, deps) {
|
|
3136
|
+
const { baseUrl, accessToken, tenantName } = robotCreds;
|
|
3137
|
+
const organization = robotCreds.organizationName ?? robotCreds.organizationId;
|
|
3138
|
+
if (!tenantName || !organization) {
|
|
3139
|
+
return {};
|
|
3140
|
+
}
|
|
3141
|
+
const key = `${baseUrl}|${organization}|${tenantName}|${accessToken}`;
|
|
3142
|
+
let pending = deps.cache.get(key);
|
|
3143
|
+
if (!pending) {
|
|
3144
|
+
pending = catchError2(lookupRobotTenantId({ baseUrl, accessToken, organization, tenantName }, deps)).then(([error, resolution]) => {
|
|
3145
|
+
const settled = error ? { hint: tenantLookupFailureHint(tenantName, error.message) } : resolution;
|
|
3146
|
+
if (!settled.tenantId) {
|
|
3147
|
+
deps.cache.delete(key);
|
|
3148
|
+
}
|
|
3149
|
+
return settled;
|
|
3150
|
+
});
|
|
3151
|
+
deps.cache.set(key, pending);
|
|
3152
|
+
}
|
|
3153
|
+
return pending;
|
|
3154
|
+
}
|
|
3155
|
+
async function lookupRobotTenantId(target, deps) {
|
|
3156
|
+
const { baseUrl, accessToken, organization, tenantName } = target;
|
|
3157
|
+
const [error, data] = await catchError2(deps.fetchTenantsAndOrgs(baseUrl, accessToken, organization, AbortSignal.timeout(deps.lookupTimeoutMs)));
|
|
3158
|
+
if (error) {
|
|
3159
|
+
const reason = error.name === "TimeoutError" ? `the tenant list did not answer within ${deps.lookupTimeoutMs} ms.` : error.message;
|
|
3160
|
+
return { hint: tenantLookupFailureHint(tenantName, reason) };
|
|
3161
|
+
}
|
|
3162
|
+
const rows = data?.tenants;
|
|
3163
|
+
const tenants = Array.isArray(rows) ? rows.filter((tenant) => typeof tenant?.id === "string" && typeof tenant?.name === "string") : [];
|
|
3164
|
+
const wantedName = decodePathSegment(tenantName);
|
|
3165
|
+
const wanted = wantedName.toLowerCase();
|
|
3166
|
+
const match = tenants.find((tenant) => tenant.name === wantedName) ?? tenants.find((tenant) => tenant.name.toLowerCase() === wanted);
|
|
3167
|
+
if (!match) {
|
|
3168
|
+
const names = tenants.map((tenant) => tenant.name).join(", ");
|
|
3169
|
+
return {
|
|
3170
|
+
hint: `The Robot session targets tenant '${tenantName}', but ` + `organization '${organization}' lists no tenant of that name` + `${names ? ` (available: ${names})` : ""}. Commands that need ` + `the tenant id will fail until it can be resolved.`
|
|
3171
|
+
};
|
|
3172
|
+
}
|
|
3173
|
+
return { tenantId: match.id };
|
|
3174
|
+
}
|
|
3175
|
+
function tenantLookupFailureHint(tenantName, reason) {
|
|
3176
|
+
return `Could not resolve the id of tenant '${tenantName}' from the ` + `Robot session: ${reason} Commands that need the tenant id will ` + `fail until it can be resolved.`;
|
|
3177
|
+
}
|
|
3178
|
+
function decodePathSegment(segment) {
|
|
3179
|
+
const [error, decoded] = catchError2(() => decodeURIComponent(segment));
|
|
3180
|
+
return error ? segment : decoded;
|
|
3181
|
+
}
|
|
3001
3182
|
var isFileNotFoundError = (error) => {
|
|
3002
3183
|
if (!(error instanceof Object))
|
|
3003
3184
|
return false;
|
|
@@ -3274,8 +3455,6 @@ init_constants();
|
|
|
3274
3455
|
// ../auth/src/interactive.ts
|
|
3275
3456
|
init_src();
|
|
3276
3457
|
init_constants();
|
|
3277
|
-
// ../auth/src/tenantSelection.ts
|
|
3278
|
-
var IDENTIFIER_STATUSES = new Set([400, 403, 404]);
|
|
3279
3458
|
|
|
3280
3459
|
// ../auth/src/selectTenant.ts
|
|
3281
3460
|
var TENANT_SELECTION_REQUIRED_CODE = "TENANT_SELECTION_REQUIRED";
|
|
@@ -3697,6 +3876,151 @@ async function listQueueFilters(config) {
|
|
|
3697
3876
|
async function listMachineFilters(config) {
|
|
3698
3877
|
return listFilters(config, "filtersAllMachines", isMachineFiltersResponse, "machine filters");
|
|
3699
3878
|
}
|
|
3879
|
+
// src/looker-dashboards.ts
|
|
3880
|
+
var TEMPLATE_ID_DELIMITER = "::";
|
|
3881
|
+
var INTEGER_ID_PATTERN = /^\d+$/;
|
|
3882
|
+
var LOOKER_FOLDERS = [
|
|
3883
|
+
"personal",
|
|
3884
|
+
"tenant",
|
|
3885
|
+
"templates",
|
|
3886
|
+
"organization"
|
|
3887
|
+
];
|
|
3888
|
+
var LOOKER_THEMES = ["light", "dark"];
|
|
3889
|
+
async function listLookerDashboards(config) {
|
|
3890
|
+
return requestInsightsRoute(config, "lookerDashboardsList");
|
|
3891
|
+
}
|
|
3892
|
+
async function getLookerDashboardEmbedUrl(config, options) {
|
|
3893
|
+
const dashboardId = options.dashboardId.trim();
|
|
3894
|
+
if (dashboardId === "") {
|
|
3895
|
+
throw new Error("Insights Looker dashboard id must not be empty.");
|
|
3896
|
+
}
|
|
3897
|
+
if (!isDashboardId(dashboardId)) {
|
|
3898
|
+
throw new Error("Insights Looker dashboard id must be all digits or contain '::'; resolve a title with resolveLookerDashboard first.");
|
|
3899
|
+
}
|
|
3900
|
+
if (!LOOKER_THEMES.includes(options.theme)) {
|
|
3901
|
+
throw new Error(`Insights Looker theme must be one of ${LOOKER_THEMES.join(", ")}.`);
|
|
3902
|
+
}
|
|
3903
|
+
const locale = options.localization?.trim();
|
|
3904
|
+
if (locale === "") {
|
|
3905
|
+
throw new Error("Insights Looker localization must not be empty.");
|
|
3906
|
+
}
|
|
3907
|
+
return requestInsightsRoute(config, "lookerDashboardEmbedUrl", {
|
|
3908
|
+
body: {
|
|
3909
|
+
dashboardId,
|
|
3910
|
+
theme: options.theme,
|
|
3911
|
+
...locale === undefined ? {} : { locale }
|
|
3912
|
+
}
|
|
3913
|
+
});
|
|
3914
|
+
}
|
|
3915
|
+
function parseLookerEnvelope(raw, routeKey) {
|
|
3916
|
+
const endpoint = insightsRouteTemplate(routeKey);
|
|
3917
|
+
if (typeof raw !== "string") {
|
|
3918
|
+
throw new InsightsProtocolError(endpoint, "the body is not the JSON string literal this root answers with");
|
|
3919
|
+
}
|
|
3920
|
+
const [parseError, envelope] = catchError(() => JSON.parse(raw));
|
|
3921
|
+
if (parseError) {
|
|
3922
|
+
throw new InsightsProtocolError(endpoint, "the body string does not hold JSON");
|
|
3923
|
+
}
|
|
3924
|
+
if (!isJsonObject(envelope)) {
|
|
3925
|
+
throw new InsightsProtocolError(endpoint, "the body string does not hold an object");
|
|
3926
|
+
}
|
|
3927
|
+
if (typeof envelope.isSuccess !== "boolean") {
|
|
3928
|
+
throw new InsightsProtocolError(endpoint, "the body carries no boolean isSuccess");
|
|
3929
|
+
}
|
|
3930
|
+
if (envelope.isSuccess !== true) {
|
|
3931
|
+
throw new InsightsProtocolError(endpoint, "the body reports isSuccess false inside a success status");
|
|
3932
|
+
}
|
|
3933
|
+
if (envelope.result === undefined || envelope.result === null) {
|
|
3934
|
+
throw new InsightsProtocolError(endpoint, "the body carries no result");
|
|
3935
|
+
}
|
|
3936
|
+
return envelope.result;
|
|
3937
|
+
}
|
|
3938
|
+
|
|
3939
|
+
class LookerResolveError extends Error {
|
|
3940
|
+
kind;
|
|
3941
|
+
candidates;
|
|
3942
|
+
constructor(kind, message, candidates = []) {
|
|
3943
|
+
super(message);
|
|
3944
|
+
this.name = "LookerResolveError";
|
|
3945
|
+
this.kind = kind;
|
|
3946
|
+
this.candidates = candidates;
|
|
3947
|
+
}
|
|
3948
|
+
}
|
|
3949
|
+
function isDashboardId(value) {
|
|
3950
|
+
return INTEGER_ID_PATTERN.test(value) || value.includes(TEMPLATE_ID_DELIMITER);
|
|
3951
|
+
}
|
|
3952
|
+
function isLookerTemplateDashboardId(id) {
|
|
3953
|
+
return !INTEGER_ID_PATTERN.test(id);
|
|
3954
|
+
}
|
|
3955
|
+
function readLookerListing(raw) {
|
|
3956
|
+
const endpoint = insightsRouteTemplate("lookerDashboardsList");
|
|
3957
|
+
const folders = parseLookerEnvelope(raw, "lookerDashboardsList");
|
|
3958
|
+
if (!isJsonObject(folders)) {
|
|
3959
|
+
throw new InsightsProtocolError(endpoint, "the result is not an object");
|
|
3960
|
+
}
|
|
3961
|
+
const listing = { rows: [], omittedFolders: [] };
|
|
3962
|
+
for (const folder of LOOKER_FOLDERS) {
|
|
3963
|
+
const group = readFolderGroup(folders[folder], folder, endpoint);
|
|
3964
|
+
if (group === null) {
|
|
3965
|
+
listing.omittedFolders.push(folder);
|
|
3966
|
+
continue;
|
|
3967
|
+
}
|
|
3968
|
+
for (const element of group) {
|
|
3969
|
+
listing.rows.push(readListingRow(element, folder, endpoint));
|
|
3970
|
+
}
|
|
3971
|
+
}
|
|
3972
|
+
return listing;
|
|
3973
|
+
}
|
|
3974
|
+
function readFolderGroup(group, folder, endpoint) {
|
|
3975
|
+
if (group === undefined) {
|
|
3976
|
+
throw new InsightsProtocolError(endpoint, `the result carries no ${folder} key`);
|
|
3977
|
+
}
|
|
3978
|
+
if (group === null) {
|
|
3979
|
+
return null;
|
|
3980
|
+
}
|
|
3981
|
+
if (!Array.isArray(group)) {
|
|
3982
|
+
throw new InsightsProtocolError(endpoint, `the result's ${folder} is neither an array nor null`);
|
|
3983
|
+
}
|
|
3984
|
+
return group;
|
|
3985
|
+
}
|
|
3986
|
+
function readListingRow(record, folder, endpoint) {
|
|
3987
|
+
if (!isJsonObject(record)) {
|
|
3988
|
+
throw new InsightsProtocolError(endpoint, `a row in the ${folder} folder is not an object`);
|
|
3989
|
+
}
|
|
3990
|
+
if (typeof record.id !== "string") {
|
|
3991
|
+
throw new InsightsProtocolError(endpoint, `a row in the ${folder} folder has no string id`);
|
|
3992
|
+
}
|
|
3993
|
+
if (record.title !== null && typeof record.title !== "string") {
|
|
3994
|
+
throw new InsightsProtocolError(endpoint, `a row in the ${folder} folder has a title that is neither a string nor null`);
|
|
3995
|
+
}
|
|
3996
|
+
return { folder, id: record.id, title: record.title, record };
|
|
3997
|
+
}
|
|
3998
|
+
async function resolveLookerDashboard(config, value) {
|
|
3999
|
+
const trimmed = value.trim();
|
|
4000
|
+
if (trimmed === "") {
|
|
4001
|
+
throw new Error("Insights Looker dashboard must not be empty.");
|
|
4002
|
+
}
|
|
4003
|
+
if (isDashboardId(trimmed)) {
|
|
4004
|
+
return { id: trimmed, resolvedFrom: "id" };
|
|
4005
|
+
}
|
|
4006
|
+
const { rows } = readLookerListing(await listLookerDashboards(config));
|
|
4007
|
+
const matches = rows.filter((row) => row.title?.trim() === trimmed);
|
|
4008
|
+
if (matches.length === 0) {
|
|
4009
|
+
throw new LookerResolveError("notFound", "No Looker dashboard with that title is listed for this session.");
|
|
4010
|
+
}
|
|
4011
|
+
for (const match of matches) {
|
|
4012
|
+
requireEmbeddableId(match);
|
|
4013
|
+
}
|
|
4014
|
+
if (matches.length > 1) {
|
|
4015
|
+
throw new LookerResolveError("ambiguous", `${matches.length} Looker dashboards share that title.`, matches.map((row) => ({ folder: row.folder, id: row.id })));
|
|
4016
|
+
}
|
|
4017
|
+
return { id: matches[0].id, resolvedFrom: "title" };
|
|
4018
|
+
}
|
|
4019
|
+
function requireEmbeddableId(row) {
|
|
4020
|
+
if (!isDashboardId(row.id)) {
|
|
4021
|
+
throw new InsightsProtocolError(insightsRouteTemplate("lookerDashboardsList"), `a row in the ${row.folder} folder has an id that is neither all digits nor contains '::'`);
|
|
4022
|
+
}
|
|
4023
|
+
}
|
|
3700
4024
|
// src/machines.ts
|
|
3701
4025
|
function isNullish(value) {
|
|
3702
4026
|
return value === undefined || value === null;
|
|
@@ -3954,10 +4278,16 @@ export {
|
|
|
3954
4278
|
InsightsHttpError,
|
|
3955
4279
|
InsightsNetworkError,
|
|
3956
4280
|
InsightsProtocolError,
|
|
4281
|
+
LOOKER_FOLDERS,
|
|
4282
|
+
LOOKER_NO_DASHBOARDS_MESSAGE,
|
|
4283
|
+
LOOKER_THEMES,
|
|
4284
|
+
LOOKER_USER_UNAVAILABLE_MESSAGE,
|
|
4285
|
+
LookerResolveError,
|
|
3957
4286
|
MAESTRO_CASE_DASHBOARD_PREFIX,
|
|
3958
4287
|
MAESTRO_DASHBOARD_SOURCE_TYPE,
|
|
3959
4288
|
MAESTRO_PROCESS_DASHBOARD_PREFIX,
|
|
3960
4289
|
MODEL_NOT_FOUND_LABEL,
|
|
4290
|
+
PORTAL_ERROR_CODE,
|
|
3961
4291
|
UPDATE_BACKEND_FAILURE_LABEL,
|
|
3962
4292
|
VALIDATION_FAILED_LABEL,
|
|
3963
4293
|
checkAlertEntitlement,
|
|
@@ -3973,6 +4303,7 @@ export {
|
|
|
3973
4303
|
getDashboardTemplate,
|
|
3974
4304
|
getDefaultDelivery,
|
|
3975
4305
|
getGroup,
|
|
4306
|
+
getLookerDashboardEmbedUrl,
|
|
3976
4307
|
getMachineAvailabilityTimeline,
|
|
3977
4308
|
getMachineDetails,
|
|
3978
4309
|
getMachineRuntimeMix,
|
|
@@ -3991,6 +4322,7 @@ export {
|
|
|
3991
4322
|
getRole,
|
|
3992
4323
|
getUser,
|
|
3993
4324
|
insightsPost,
|
|
4325
|
+
isLookerTemplateDashboardId,
|
|
3994
4326
|
isTemplateKeyedDashboardId,
|
|
3995
4327
|
listAgenticAlertDefinitions,
|
|
3996
4328
|
listAlertDefinitions,
|
|
@@ -3999,15 +4331,19 @@ export {
|
|
|
3999
4331
|
listExportConfigurations,
|
|
4000
4332
|
listFolderFilters,
|
|
4001
4333
|
listGroups,
|
|
4334
|
+
listLookerDashboards,
|
|
4002
4335
|
listMachineFilters,
|
|
4003
4336
|
listProcessFilters,
|
|
4004
4337
|
listQueueFilters,
|
|
4005
4338
|
listRoles,
|
|
4006
4339
|
listUsers,
|
|
4007
4340
|
parseDashboardSlotId,
|
|
4341
|
+
parseLookerEnvelope,
|
|
4342
|
+
readLookerListing,
|
|
4343
|
+
resolveLookerDashboard,
|
|
4008
4344
|
updateDashboard,
|
|
4009
4345
|
verifyAllExportDestinations,
|
|
4010
4346
|
verifyExportDestination
|
|
4011
4347
|
};
|
|
4012
4348
|
|
|
4013
|
-
//# debugId=
|
|
4349
|
+
//# debugId=C9CCE811CC90FFD264756E2164756E21
|
package/dist/src/errors.d.ts
CHANGED
|
@@ -69,6 +69,8 @@ export interface InsightsErrorBodyHint {
|
|
|
69
69
|
* numbers are at origin/develop 2c5860474, as above.
|
|
70
70
|
*/
|
|
71
71
|
problemDetails?: true;
|
|
72
|
+
portalErrorCode?: number;
|
|
73
|
+
portalErrorMessage?: string;
|
|
72
74
|
}
|
|
73
75
|
/**
|
|
74
76
|
* The only `error` values `describeJsonErrorBody` lifts into `errorLabel`.
|
|
@@ -109,6 +111,16 @@ export declare const VALIDATION_FAILED_LABEL = "Validation failed";
|
|
|
109
111
|
export declare const CREATE_BACKEND_FAILURE_LABEL = "Failed to create dashboard";
|
|
110
112
|
export declare const UPDATE_BACKEND_FAILURE_LABEL = "Failed to update dashboard";
|
|
111
113
|
export declare const KNOWN_ERROR_LABELS: Set<string>;
|
|
114
|
+
export declare const PORTAL_ERROR_CODE: {
|
|
115
|
+
readonly InvalidUserInput: 6;
|
|
116
|
+
readonly LookerUnavailableError: 8;
|
|
117
|
+
readonly PermissionsUserUnauthorized: 10;
|
|
118
|
+
readonly UnableToGetEmbedLink: 23;
|
|
119
|
+
readonly UnableToRetrieveDashboards: 26;
|
|
120
|
+
};
|
|
121
|
+
export declare const LOOKER_USER_UNAVAILABLE_MESSAGE = "Unable to get Looker userInfo";
|
|
122
|
+
export declare const LOOKER_NO_DASHBOARDS_MESSAGE = "Unable to retrieve dashboards";
|
|
123
|
+
export declare const KNOWN_PORTAL_ERROR_MESSAGES: Set<string>;
|
|
112
124
|
interface InsightsHttpErrorInit {
|
|
113
125
|
status: number;
|
|
114
126
|
method: InsightsHttpMethod;
|
package/dist/src/index.d.ts
CHANGED
|
@@ -4,10 +4,12 @@ export { createInsightsConfig } from "./client-factory";
|
|
|
4
4
|
export type { CreateDashboardOptions, DashboardChart, DashboardChartAction, DashboardChartFilter, DashboardChartFilterRange, DashboardCustomLayout, DashboardDefinition, DashboardField, DashboardFieldFormat, DashboardLayout, DashboardLayoutContainer, DashboardMetric, DashboardMetricExpression, DashboardMetricFilter, DashboardSlot, DashboardSlotKind, DashboardTable, DeleteDashboardOptions, GetDashboardOptions, GetDashboardTemplateOptions, ListDashboardFiltersOptions, UpdateDashboardOptions, } from "./dashboards";
|
|
5
5
|
export { composeDashboardSlotId, createDashboard, DASHBOARD_SLOT_DELIMITER, DASHBOARD_TEMPLATE_ID_PREFIX, DashboardRequestError, deleteDashboard, getDashboard, getDashboardTemplate, isTemplateKeyedDashboardId, listDashboardFilters, MAESTRO_CASE_DASHBOARD_PREFIX, MAESTRO_DASHBOARD_SOURCE_TYPE, MAESTRO_PROCESS_DASHBOARD_PREFIX, parseDashboardSlotId, updateDashboard, } from "./dashboards";
|
|
6
6
|
export type { InsightsBodyKind, InsightsErrorBodyHint, InsightsHttpMethod, } from "./errors";
|
|
7
|
-
export { CREATE_BACKEND_FAILURE_LABEL, DASHBOARD_NOT_FOUND_LABEL, InsightsHttpError, InsightsNetworkError, InsightsProtocolError, MODEL_NOT_FOUND_LABEL, UPDATE_BACKEND_FAILURE_LABEL, VALIDATION_FAILED_LABEL, } from "./errors";
|
|
7
|
+
export { CREATE_BACKEND_FAILURE_LABEL, DASHBOARD_NOT_FOUND_LABEL, InsightsHttpError, InsightsNetworkError, InsightsProtocolError, LOOKER_NO_DASHBOARDS_MESSAGE, LOOKER_USER_UNAVAILABLE_MESSAGE, MODEL_NOT_FOUND_LABEL, PORTAL_ERROR_CODE, UPDATE_BACKEND_FAILURE_LABEL, VALIDATION_FAILED_LABEL, } from "./errors";
|
|
8
8
|
export type { ExportDestinationKey, ExportVerifyBody, } from "./export-configurations";
|
|
9
9
|
export { listExportConfigurations, verifyAllExportDestinations, verifyExportDestination, } from "./export-configurations";
|
|
10
10
|
export { listFolderFilters, listMachineFilters, listProcessFilters, listQueueFilters, } from "./filters";
|
|
11
|
+
export type { LookerDashboardRef, LookerEmbedUrlOptions, LookerFolder, LookerListing, LookerListingRow, LookerTheme, } from "./looker-dashboards";
|
|
12
|
+
export { getLookerDashboardEmbedUrl, isLookerTemplateDashboardId, LOOKER_FOLDERS, LOOKER_THEMES, LookerResolveError, listLookerDashboards, parseLookerEnvelope, readLookerListing, resolveLookerDashboard, } from "./looker-dashboards";
|
|
11
13
|
export type { MachineQueryInput, MachinesResponse } from "./machines";
|
|
12
14
|
export { getMachineAvailabilityTimeline, getMachineDetails, getMachineRuntimeMix, getMachineTopFailures, getMachineUtilization, } from "./machines";
|
|
13
15
|
export type { QueueQueryInput, QueuesResponse, QueueWfMetricsRow, } from "./queues";
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type InsightsRouteKey } from "./transport";
|
|
2
|
+
import type { InsightsApiConfig } from "./types";
|
|
3
|
+
export declare const LOOKER_FOLDERS: readonly ["personal", "tenant", "templates", "organization"];
|
|
4
|
+
export type LookerFolder = (typeof LOOKER_FOLDERS)[number];
|
|
5
|
+
export declare const LOOKER_THEMES: readonly ["light", "dark"];
|
|
6
|
+
export type LookerTheme = (typeof LOOKER_THEMES)[number];
|
|
7
|
+
export declare function listLookerDashboards(config: InsightsApiConfig): Promise<unknown>;
|
|
8
|
+
export interface LookerEmbedUrlOptions {
|
|
9
|
+
dashboardId: string;
|
|
10
|
+
theme: LookerTheme;
|
|
11
|
+
localization?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function getLookerDashboardEmbedUrl(config: InsightsApiConfig, options: LookerEmbedUrlOptions): Promise<unknown>;
|
|
14
|
+
export declare function parseLookerEnvelope(raw: unknown, routeKey: InsightsRouteKey): unknown;
|
|
15
|
+
export interface LookerDashboardRef {
|
|
16
|
+
id: string;
|
|
17
|
+
resolvedFrom: "id" | "title";
|
|
18
|
+
}
|
|
19
|
+
export declare class LookerResolveError extends Error {
|
|
20
|
+
readonly kind: "notFound" | "ambiguous";
|
|
21
|
+
readonly candidates: ReadonlyArray<{
|
|
22
|
+
folder: LookerFolder;
|
|
23
|
+
id: string;
|
|
24
|
+
}>;
|
|
25
|
+
constructor(kind: "notFound" | "ambiguous", message: string, candidates?: ReadonlyArray<{
|
|
26
|
+
folder: LookerFolder;
|
|
27
|
+
id: string;
|
|
28
|
+
}>);
|
|
29
|
+
}
|
|
30
|
+
export declare function isLookerTemplateDashboardId(id: string): boolean;
|
|
31
|
+
export interface LookerListingRow {
|
|
32
|
+
folder: LookerFolder;
|
|
33
|
+
id: string;
|
|
34
|
+
title: string | null;
|
|
35
|
+
record: Record<string, unknown>;
|
|
36
|
+
}
|
|
37
|
+
export interface LookerListing {
|
|
38
|
+
rows: LookerListingRow[];
|
|
39
|
+
omittedFolders: LookerFolder[];
|
|
40
|
+
}
|
|
41
|
+
export declare function readLookerListing(raw: unknown): LookerListing;
|
|
42
|
+
export declare function resolveLookerDashboard(config: InsightsApiConfig, value: string): Promise<LookerDashboardRef>;
|
package/dist/src/transport.d.ts
CHANGED
|
@@ -160,6 +160,16 @@ export declare const INSIGHTS_ROUTES: {
|
|
|
160
160
|
readonly method: "POST";
|
|
161
161
|
readonly template: "Authorization/tenant/insights";
|
|
162
162
|
};
|
|
163
|
+
readonly lookerDashboardsList: {
|
|
164
|
+
readonly service: "portal";
|
|
165
|
+
readonly method: "GET";
|
|
166
|
+
readonly template: "AllDashboards/folders";
|
|
167
|
+
};
|
|
168
|
+
readonly lookerDashboardEmbedUrl: {
|
|
169
|
+
readonly service: "portal";
|
|
170
|
+
readonly method: "POST";
|
|
171
|
+
readonly template: "DashboardUrl";
|
|
172
|
+
};
|
|
163
173
|
readonly exportConfigurationsList: {
|
|
164
174
|
readonly service: "portal";
|
|
165
175
|
readonly method: "GET";
|
|
@@ -179,6 +189,7 @@ export declare const INSIGHTS_ROUTES: {
|
|
|
179
189
|
export type InsightsRouteKey = keyof typeof INSIGHTS_ROUTES;
|
|
180
190
|
/** Safe endpoint template for a route, for protocol-error reporting. */
|
|
181
191
|
export declare function insightsRouteTemplate(routeKey: InsightsRouteKey): string;
|
|
192
|
+
export declare function isJsonObject(value: unknown): value is Record<string, unknown>;
|
|
182
193
|
/** Query values a wrapper may set. `undefined` omits the parameter. */
|
|
183
194
|
export type InsightsRouteQuery = Record<string, string | number | boolean | undefined>;
|
|
184
195
|
export interface InsightsRouteRequest {
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@uipath/insights-sdk",
|
|
3
3
|
"author": "UiPath",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.205.0-preview.256",
|
|
6
6
|
"description": "SDK for the UiPath Insights API — jobs, failures, and performance metrics.",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
@@ -35,5 +35,5 @@
|
|
|
35
35
|
"files": [
|
|
36
36
|
"dist"
|
|
37
37
|
],
|
|
38
|
-
"gitHead": "
|
|
38
|
+
"gitHead": "63740c6cbb7ff282fa9118cc16a148eb030b245f"
|
|
39
39
|
}
|