@uipath/ixp-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.
Files changed (2) hide show
  1. package/dist/index.js +135 -26
  2. package/package.json +2 -2
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);
@@ -1014,22 +1024,12 @@ var resolveConfigAsync = async ({
1014
1024
  baseUrl = DEFAULT_BASE_URL;
1015
1025
  }
1016
1026
  baseUrl = normalizeAndValidateBaseUrl(baseUrl);
1017
- let clientId = customClientId;
1018
- if (!clientId && fileAuth.clientId) {
1019
- clientId = fileAuth.clientId;
1020
- }
1021
- if (!clientId) {
1022
- clientId = DEFAULT_CLIENT_ID;
1023
- }
1024
- let clientSecret = customClientSecret;
1025
- if (!clientSecret && fileAuth.clientSecret) {
1026
- clientSecret = fileAuth.clientSecret;
1027
- }
1028
- const isExternalAppAuth = clientId !== DEFAULT_CLIENT_ID && (Boolean(clientSecret) || Boolean(customClientAssertion));
1027
+ const clientId = customClientId || DEFAULT_CLIENT_ID;
1028
+ const isExternalAppAuth = clientId !== DEFAULT_CLIENT_ID && (Boolean(customClientSecret) || Boolean(customClientAssertion));
1029
1029
  const scopes = resolveScopes(isExternalAppAuth, customScopes, fileAuth.scopes);
1030
1030
  return {
1031
1031
  clientId,
1032
- clientSecret,
1032
+ clientSecret: customClientSecret,
1033
1033
  scopes,
1034
1034
  baseUrl,
1035
1035
  authorizationEndpoint: `${baseUrl}/identity_/connect/authorize`,
@@ -1204,6 +1204,16 @@ var resolveIdentityType = (claims, authFlow, email) => {
1204
1204
  }
1205
1205
  return;
1206
1206
  };
1207
+ var resolveApplicationSubtype = (claims, authFlow) => {
1208
+ switch (asString(claims?.sub_type)) {
1209
+ case "service.external":
1210
+ return "External";
1211
+ case "service.internal":
1212
+ return "Internal";
1213
+ default:
1214
+ return authFlow === "client_credentials" || authFlow === "federated_credentials" ? "External" : undefined;
1215
+ }
1216
+ };
1207
1217
  var looksLikeEmail = (value) => value?.includes("@") ?? false;
1208
1218
  var pickEmail = (claims) => {
1209
1219
  for (const candidate of [claims?.email, claims?.preferred_username]) {
@@ -1245,6 +1255,12 @@ var resolveSessionIdentity = (accessToken, authFlow) => {
1245
1255
  const clientId = asString(claims?.client_id);
1246
1256
  if (clientId)
1247
1257
  identity.clientId = clientId;
1258
+ const subType = asString(claims?.sub_type);
1259
+ if (subType)
1260
+ identity.subType = subType;
1261
+ const applicationSubtype = resolveApplicationSubtype(claims, authFlow);
1262
+ if (applicationSubtype)
1263
+ identity.applicationSubtype = applicationSubtype;
1248
1264
  return identity;
1249
1265
  };
1250
1266
  var readTokenScopes = (accessToken) => accessToken ? pickScopes(decodeClaims(accessToken)) : undefined;
@@ -1539,6 +1555,40 @@ var tryRobotClientFallback = async (options = {}) => {
1539
1555
  }
1540
1556
  };
1541
1557
 
1558
+ // ../auth/src/tenantSelection.ts
1559
+ var LOGIN_STATUS_HINT = "Run 'uip login status' to see the organization the CLI is signed in to.";
1560
+ var organizationHint = (organizationId) => `The request used '${organizationId}' as the organization. ${LOGIN_STATUS_HINT}`;
1561
+ var IDENTIFIER_STATUSES = new Set([400, 403, 404]);
1562
+ var describeNonJsonResponse = (organizationId, response, parseError) => {
1563
+ if (response.redirected) {
1564
+ 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}`;
1565
+ }
1566
+ const contentType = response.headers.get("content-type") ?? "unknown";
1567
+ return `The organization service returned a '${contentType}' response instead ` + `of JSON: ${parseError.message}. ${organizationHint(organizationId)}`;
1568
+ };
1569
+ var fetchTenantsAndOrganizations = async (baseUrl, accessToken, organizationId, signal) => {
1570
+ const url = `${baseUrl}/${organizationId}/portal_/api/filtering/leftnav/tenantsAndOrganizationInfo`;
1571
+ const response = await fetch(url, {
1572
+ headers: {
1573
+ Authorization: `Bearer ${accessToken}`
1574
+ },
1575
+ ...signal ? { signal } : {}
1576
+ });
1577
+ if (!response.ok) {
1578
+ if (response.status === 401) {
1579
+ 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);
1580
+ }
1581
+ const errorText = await response.text();
1582
+ const message = `Failed to get tenants and organizations: ${response.status} ${errorText}`;
1583
+ throw new Error(IDENTIFIER_STATUSES.has(response.status) ? `${message}. ${organizationHint(organizationId)}` : message);
1584
+ }
1585
+ const [parseError, data] = await catchError(response.json());
1586
+ if (parseError) {
1587
+ throw new Error(describeNonJsonResponse(organizationId, response, parseError));
1588
+ }
1589
+ return data;
1590
+ };
1591
+
1542
1592
  // ../auth/src/tokenRefresh.ts
1543
1593
  var TOKEN_REFRESH_REAUTHENTICATE_MESSAGE = "Token refresh failed. Run 'uip login' to re-authenticate.";
1544
1594
 
@@ -1753,6 +1803,8 @@ var saveEnvFileAsync = async ({
1753
1803
  };
1754
1804
 
1755
1805
  // ../auth/src/loginStatus.ts
1806
+ var defaultRobotTenantIdCache = new Map;
1807
+ var ROBOT_TENANT_LOOKUP_TIMEOUT_MS = 5000;
1756
1808
  var getLoginStatusAsync = async (options = {}) => {
1757
1809
  return getLoginStatusWithDeps(options);
1758
1810
  };
@@ -1765,12 +1817,20 @@ var getLoginStatusWithDeps = async (options = {}, deps = {}) => {
1765
1817
  refreshToken: refreshTokenFn = refreshAccessToken,
1766
1818
  resolveConfig = resolveConfigAsync,
1767
1819
  robotFallback = tryRobotClientFallback,
1820
+ fetchTenantsAndOrgs = fetchTenantsAndOrganizations,
1821
+ robotTenantIdCache = defaultRobotTenantIdCache,
1822
+ robotTenantLookupTimeoutMs = ROBOT_TENANT_LOOKUP_TIMEOUT_MS,
1768
1823
  loadBreaker = loadRefreshBreaker,
1769
1824
  saveBreaker = saveRefreshBreaker,
1770
1825
  clearBreaker = clearRefreshBreaker
1771
1826
  } = deps;
1827
+ const robotDeps = {
1828
+ fetchTenantsAndOrgs,
1829
+ cache: robotTenantIdCache,
1830
+ lookupTimeoutMs: robotTenantLookupTimeoutMs
1831
+ };
1772
1832
  if (isRobotAuthEnforced()) {
1773
- return resolveRobotEnforcedStatus(robotFallback);
1833
+ return resolveRobotEnforcedStatus(robotFallback, robotDeps);
1774
1834
  }
1775
1835
  if (isEnvAuthEnabled()) {
1776
1836
  return readAuthFromEnv();
@@ -1788,7 +1848,7 @@ var getLoginStatusWithDeps = async (options = {}, deps = {}) => {
1788
1848
  hint: `No credentials found for profile "${activeProfile}". Run 'uip login --profile ${activeProfile}' to authenticate this profile.`
1789
1849
  };
1790
1850
  }
1791
- return resolveBorrowedRobotStatus(robotFallback);
1851
+ return resolveBorrowedRobotStatus(robotFallback, robotDeps);
1792
1852
  }
1793
1853
  const loaded = await loadFileCredentials(loadEnvFile, absolutePath);
1794
1854
  if ("status" in loaded) {
@@ -1830,7 +1890,7 @@ var getLoginStatusWithDeps = async (options = {}, deps = {}) => {
1830
1890
  }
1831
1891
  return buildFileStatus(tokens, credentials, globalHint);
1832
1892
  };
1833
- async function resolveRobotEnforcedStatus(robotFallback) {
1893
+ async function resolveRobotEnforcedStatus(robotFallback, deps) {
1834
1894
  if (isEnvAuthEnabled()) {
1835
1895
  throw new EnvAuthConfigError(`${ENV_AUTH_ENABLE_VAR}=true and ${ENFORCE_ROBOT_AUTH_VAR}=true ` + `are mutually exclusive. Unset one of them and re-run.`);
1836
1896
  }
@@ -1841,11 +1901,11 @@ async function resolveRobotEnforcedStatus(robotFallback) {
1841
1901
  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.`
1842
1902
  };
1843
1903
  }
1844
- return buildRobotStatus(robotCreds);
1904
+ return buildRobotStatus(robotCreds, deps);
1845
1905
  }
1846
- async function resolveBorrowedRobotStatus(robotFallback) {
1906
+ async function resolveBorrowedRobotStatus(robotFallback, deps) {
1847
1907
  const robotCreds = await robotFallback();
1848
- return robotCreds ? buildRobotStatus(robotCreds) : { loginStatus: "Not logged in" };
1908
+ return robotCreds ? buildRobotStatus(robotCreds, deps) : { loginStatus: "Not logged in" };
1849
1909
  }
1850
1910
  async function loadFileCredentials(loadEnvFile, absolutePath) {
1851
1911
  let credentials;
@@ -1980,9 +2040,10 @@ function identityFields(accessToken, credentials) {
1980
2040
  ...scopes ? { scopes } : {}
1981
2041
  };
1982
2042
  }
1983
- function buildRobotStatus(robotCreds) {
2043
+ async function buildRobotStatus(robotCreds, deps) {
1984
2044
  const identity = resolveSessionIdentity(robotCreds.accessToken);
1985
2045
  const scopes = readTokenScopes(robotCreds.accessToken);
2046
+ const tenant = robotCreds.tenantId ? { tenantId: robotCreds.tenantId } : await resolveRobotTenantId(robotCreds, deps);
1986
2047
  return {
1987
2048
  loginStatus: "Logged in",
1988
2049
  accessToken: robotCreds.accessToken,
@@ -1990,14 +2051,62 @@ function buildRobotStatus(robotCreds) {
1990
2051
  organizationName: robotCreds.organizationName,
1991
2052
  organizationId: robotCreds.organizationId,
1992
2053
  tenantName: robotCreds.tenantName,
1993
- tenantId: robotCreds.tenantId,
2054
+ tenantId: tenant.tenantId,
1994
2055
  issuer: robotCreds.issuer,
1995
2056
  expiration: getTokenExpiration(robotCreds.accessToken),
1996
2057
  source: "robot" /* Robot */,
2058
+ ...tenant.hint ? { hint: tenant.hint } : {},
1997
2059
  ...identity ? { identity } : {},
1998
2060
  ...scopes ? { scopes } : {}
1999
2061
  };
2000
2062
  }
2063
+ async function resolveRobotTenantId(robotCreds, deps) {
2064
+ const { baseUrl, accessToken, tenantName } = robotCreds;
2065
+ const organization = robotCreds.organizationName ?? robotCreds.organizationId;
2066
+ if (!tenantName || !organization) {
2067
+ return {};
2068
+ }
2069
+ const key = `${baseUrl}|${organization}|${tenantName}|${accessToken}`;
2070
+ let pending = deps.cache.get(key);
2071
+ if (!pending) {
2072
+ pending = catchError(lookupRobotTenantId({ baseUrl, accessToken, organization, tenantName }, deps)).then(([error, resolution]) => {
2073
+ const settled = error ? { hint: tenantLookupFailureHint(tenantName, error.message) } : resolution;
2074
+ if (!settled.tenantId) {
2075
+ deps.cache.delete(key);
2076
+ }
2077
+ return settled;
2078
+ });
2079
+ deps.cache.set(key, pending);
2080
+ }
2081
+ return pending;
2082
+ }
2083
+ async function lookupRobotTenantId(target, deps) {
2084
+ const { baseUrl, accessToken, organization, tenantName } = target;
2085
+ const [error, data] = await catchError(deps.fetchTenantsAndOrgs(baseUrl, accessToken, organization, AbortSignal.timeout(deps.lookupTimeoutMs)));
2086
+ if (error) {
2087
+ const reason = error.name === "TimeoutError" ? `the tenant list did not answer within ${deps.lookupTimeoutMs} ms.` : error.message;
2088
+ return { hint: tenantLookupFailureHint(tenantName, reason) };
2089
+ }
2090
+ const rows = data?.tenants;
2091
+ const tenants = Array.isArray(rows) ? rows.filter((tenant) => typeof tenant?.id === "string" && typeof tenant?.name === "string") : [];
2092
+ const wantedName = decodePathSegment(tenantName);
2093
+ const wanted = wantedName.toLowerCase();
2094
+ const match = tenants.find((tenant) => tenant.name === wantedName) ?? tenants.find((tenant) => tenant.name.toLowerCase() === wanted);
2095
+ if (!match) {
2096
+ const names = tenants.map((tenant) => tenant.name).join(", ");
2097
+ return {
2098
+ 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.`
2099
+ };
2100
+ }
2101
+ return { tenantId: match.id };
2102
+ }
2103
+ function tenantLookupFailureHint(tenantName, reason) {
2104
+ 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.`;
2105
+ }
2106
+ function decodePathSegment(segment) {
2107
+ const [error, decoded] = catchError(() => decodeURIComponent(segment));
2108
+ return error ? segment : decoded;
2109
+ }
2001
2110
  var isFileNotFoundError = (error) => {
2002
2111
  if (!(error instanceof Object))
2003
2112
  return false;
@@ -2241,8 +2350,6 @@ init_constants();
2241
2350
  // ../auth/src/interactive.ts
2242
2351
  init_src();
2243
2352
  init_constants();
2244
- // ../auth/src/tenantSelection.ts
2245
- var IDENTIFIER_STATUSES = new Set([400, 403, 404]);
2246
2353
 
2247
2354
  // ../auth/src/selectTenant.ts
2248
2355
  var TENANT_SELECTION_REQUIRED_CODE = "TENANT_SELECTION_REQUIRED";
@@ -2348,7 +2455,9 @@ var ErrorDimensions = {
2348
2455
  Result: "Result",
2349
2456
  ErrorCode: "ErrorCode",
2350
2457
  Retry: "Retry",
2351
- ErrorMessage: "ErrorMessage"
2458
+ ErrorMessage: "ErrorMessage",
2459
+ HttpStatus: "HttpStatus",
2460
+ UpstreamErrorCode: "UpstreamErrorCode"
2352
2461
  };
2353
2462
  var AuthDimensions = {
2354
2463
  AuthenticationMethod: "AuthenticationMethod",
@@ -2475,7 +2584,7 @@ var package_default = {
2475
2584
  name: "@uipath/ixp-sdk",
2476
2585
  author: "UiPath",
2477
2586
  license: "SEE LICENSE IN LICENSE.txt",
2478
- version: "1.204.0-preview.255",
2587
+ version: "1.205.0-preview.256",
2479
2588
  description: "SDK for the UiPath IXP (Intelligent eXtraction Platform) API — projects, taxonomies, prompts, predictions, and model publishing.",
2480
2589
  repository: {
2481
2590
  type: "git",
@@ -2907,4 +3016,4 @@ export {
2907
3016
  uploadDocument
2908
3017
  };
2909
3018
 
2910
- //# debugId=68F38B1EC913A5B064756E2164756E21
3019
+ //# debugId=5E2A702605D20B6164756E2164756E21
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@uipath/ixp-sdk",
3
3
  "author": "UiPath",
4
4
  "license": "SEE LICENSE IN LICENSE.txt",
5
- "version": "1.204.0-preview.255",
5
+ "version": "1.205.0-preview.256",
6
6
  "description": "SDK for the UiPath IXP (Intelligent eXtraction Platform) API — projects, taxonomies, prompts, predictions, and model publishing.",
7
7
  "repository": {
8
8
  "type": "git",
@@ -25,5 +25,5 @@
25
25
  "files": [
26
26
  "dist"
27
27
  ],
28
- "gitHead": "699c58dabb59414557755a8933bcbe40aa420df3"
28
+ "gitHead": "63740c6cbb7ff282fa9118cc16a148eb030b245f"
29
29
  }