@uipath/resourcecatalog-tool 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.js +1 -1
- package/dist/{tool-96pa078f.js → tool-y4han1zv.js} +142 -30
- package/dist/tool.js +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -2101,7 +2101,7 @@ var package_default = {
|
|
|
2101
2101
|
name: "@uipath/resourcecatalog-tool",
|
|
2102
2102
|
author: "UiPath",
|
|
2103
2103
|
license: "SEE LICENSE IN LICENSE.txt",
|
|
2104
|
-
version: "1.
|
|
2104
|
+
version: "1.205.0-preview.256",
|
|
2105
2105
|
description: "CLI plugin for the UiPath Resource Catalog Service.",
|
|
2106
2106
|
private: false,
|
|
2107
2107
|
repository: {
|
|
@@ -2324,6 +2324,16 @@ class NodeFileSystem {
|
|
|
2324
2324
|
async rename(oldPath, newPath) {
|
|
2325
2325
|
await fs.rename(oldPath, newPath);
|
|
2326
2326
|
}
|
|
2327
|
+
async isSymbolicLink(filePath) {
|
|
2328
|
+
try {
|
|
2329
|
+
return (await fs.lstat(filePath)).isSymbolicLink();
|
|
2330
|
+
} catch (error) {
|
|
2331
|
+
if (this.isEnoent(error) || this.hasErrnoCode(error, "ENOTDIR")) {
|
|
2332
|
+
return false;
|
|
2333
|
+
}
|
|
2334
|
+
throw error;
|
|
2335
|
+
}
|
|
2336
|
+
}
|
|
2327
2337
|
async realpath(filePath) {
|
|
2328
2338
|
try {
|
|
2329
2339
|
return await fs.realpath(filePath);
|
|
@@ -3359,7 +3369,7 @@ function setGlobalLogFilePath(path2) {
|
|
|
3359
3369
|
function getGlobalLogFilePath() {
|
|
3360
3370
|
return logFilePathSlot.get("");
|
|
3361
3371
|
}
|
|
3362
|
-
var DEFAULT_LOG_LEVEL =
|
|
3372
|
+
var DEFAULT_LOG_LEVEL = 2 /* WARN */;
|
|
3363
3373
|
|
|
3364
3374
|
class SimpleLogger {
|
|
3365
3375
|
__brand = "SimpleLogger";
|
|
@@ -3626,7 +3636,9 @@ var ErrorDimensions = {
|
|
|
3626
3636
|
Result: "Result",
|
|
3627
3637
|
ErrorCode: "ErrorCode",
|
|
3628
3638
|
Retry: "Retry",
|
|
3629
|
-
ErrorMessage: "ErrorMessage"
|
|
3639
|
+
ErrorMessage: "ErrorMessage",
|
|
3640
|
+
HttpStatus: "HttpStatus",
|
|
3641
|
+
UpstreamErrorCode: "UpstreamErrorCode"
|
|
3630
3642
|
};
|
|
3631
3643
|
var AuthDimensions = {
|
|
3632
3644
|
AuthenticationMethod: "AuthenticationMethod",
|
|
@@ -4614,7 +4626,9 @@ var CLI_ERROR_CODES = [
|
|
|
4614
4626
|
"timeout",
|
|
4615
4627
|
"server_error",
|
|
4616
4628
|
"method_not_allowed",
|
|
4629
|
+
"not_supported",
|
|
4617
4630
|
"configuration_error",
|
|
4631
|
+
"execution_failed",
|
|
4618
4632
|
"unknown_error"
|
|
4619
4633
|
];
|
|
4620
4634
|
var RETRY_HINTS = [
|
|
@@ -5571,7 +5585,9 @@ var OutputFormatter;
|
|
|
5571
5585
|
[ErrorDimensions.Result]: data.Result,
|
|
5572
5586
|
[ErrorDimensions.ErrorCode]: data.ErrorCode,
|
|
5573
5587
|
[ErrorDimensions.Retry]: data.Retry,
|
|
5574
|
-
[ErrorDimensions.ErrorMessage]: data.Message
|
|
5588
|
+
[ErrorDimensions.ErrorMessage]: data.Message,
|
|
5589
|
+
[ErrorDimensions.HttpStatus]: data.Context?.httpStatus?.toString(),
|
|
5590
|
+
[ErrorDimensions.UpstreamErrorCode]: data.Context?.errorCode
|
|
5575
5591
|
});
|
|
5576
5592
|
}
|
|
5577
5593
|
logOutput(normalizeOutputKeys(envelope), getOutputFormat());
|
|
@@ -6782,7 +6798,7 @@ var package_default2 = {
|
|
|
6782
6798
|
name: "@uipath/resourcecatalog-sdk",
|
|
6783
6799
|
author: "UiPath",
|
|
6784
6800
|
license: "SEE LICENSE IN LICENSE.txt",
|
|
6785
|
-
version: "1.
|
|
6801
|
+
version: "1.205.0",
|
|
6786
6802
|
description: "SDK for the UiPath Resource Catalog Service API.",
|
|
6787
6803
|
repository: {
|
|
6788
6804
|
type: "git",
|
|
@@ -8279,22 +8295,12 @@ var resolveConfigAsync = async ({
|
|
|
8279
8295
|
baseUrl = DEFAULT_BASE_URL;
|
|
8280
8296
|
}
|
|
8281
8297
|
baseUrl = normalizeAndValidateBaseUrl(baseUrl);
|
|
8282
|
-
|
|
8283
|
-
|
|
8284
|
-
clientId = fileAuth.clientId;
|
|
8285
|
-
}
|
|
8286
|
-
if (!clientId) {
|
|
8287
|
-
clientId = DEFAULT_CLIENT_ID;
|
|
8288
|
-
}
|
|
8289
|
-
let clientSecret = customClientSecret;
|
|
8290
|
-
if (!clientSecret && fileAuth.clientSecret) {
|
|
8291
|
-
clientSecret = fileAuth.clientSecret;
|
|
8292
|
-
}
|
|
8293
|
-
const isExternalAppAuth = clientId !== DEFAULT_CLIENT_ID && (Boolean(clientSecret) || Boolean(customClientAssertion));
|
|
8298
|
+
const clientId = customClientId || DEFAULT_CLIENT_ID;
|
|
8299
|
+
const isExternalAppAuth = clientId !== DEFAULT_CLIENT_ID && (Boolean(customClientSecret) || Boolean(customClientAssertion));
|
|
8294
8300
|
const scopes = resolveScopes(isExternalAppAuth, customScopes, fileAuth.scopes);
|
|
8295
8301
|
return {
|
|
8296
8302
|
clientId,
|
|
8297
|
-
clientSecret,
|
|
8303
|
+
clientSecret: customClientSecret,
|
|
8298
8304
|
scopes,
|
|
8299
8305
|
baseUrl,
|
|
8300
8306
|
authorizationEndpoint: `${baseUrl}/identity_/connect/authorize`,
|
|
@@ -8468,6 +8474,16 @@ var resolveIdentityType = (claims, authFlow, email) => {
|
|
|
8468
8474
|
}
|
|
8469
8475
|
return;
|
|
8470
8476
|
};
|
|
8477
|
+
var resolveApplicationSubtype = (claims, authFlow) => {
|
|
8478
|
+
switch (asString(claims?.sub_type)) {
|
|
8479
|
+
case "service.external":
|
|
8480
|
+
return "External";
|
|
8481
|
+
case "service.internal":
|
|
8482
|
+
return "Internal";
|
|
8483
|
+
default:
|
|
8484
|
+
return authFlow === "client_credentials" || authFlow === "federated_credentials" ? "External" : undefined;
|
|
8485
|
+
}
|
|
8486
|
+
};
|
|
8471
8487
|
var looksLikeEmail = (value) => value?.includes("@") ?? false;
|
|
8472
8488
|
var pickEmail = (claims) => {
|
|
8473
8489
|
for (const candidate of [claims?.email, claims?.preferred_username]) {
|
|
@@ -8509,6 +8525,12 @@ var resolveSessionIdentity = (accessToken, authFlow) => {
|
|
|
8509
8525
|
const clientId = asString(claims?.client_id);
|
|
8510
8526
|
if (clientId)
|
|
8511
8527
|
identity.clientId = clientId;
|
|
8528
|
+
const subType = asString(claims?.sub_type);
|
|
8529
|
+
if (subType)
|
|
8530
|
+
identity.subType = subType;
|
|
8531
|
+
const applicationSubtype = resolveApplicationSubtype(claims, authFlow);
|
|
8532
|
+
if (applicationSubtype)
|
|
8533
|
+
identity.applicationSubtype = applicationSubtype;
|
|
8512
8534
|
return identity;
|
|
8513
8535
|
};
|
|
8514
8536
|
var readTokenScopes = (accessToken) => accessToken ? pickScopes(decodeClaims(accessToken)) : undefined;
|
|
@@ -8801,6 +8823,40 @@ var tryRobotClientFallback = async (options = {}) => {
|
|
|
8801
8823
|
}
|
|
8802
8824
|
};
|
|
8803
8825
|
|
|
8826
|
+
// ../../auth/src/tenantSelection.ts
|
|
8827
|
+
var LOGIN_STATUS_HINT = "Run 'uip login status' to see the organization the CLI is signed in to.";
|
|
8828
|
+
var organizationHint = (organizationId) => `The request used '${organizationId}' as the organization. ${LOGIN_STATUS_HINT}`;
|
|
8829
|
+
var IDENTIFIER_STATUSES = new Set([400, 403, 404]);
|
|
8830
|
+
var describeNonJsonResponse = (organizationId, response, parseError) => {
|
|
8831
|
+
if (response.redirected) {
|
|
8832
|
+
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}`;
|
|
8833
|
+
}
|
|
8834
|
+
const contentType = response.headers.get("content-type") ?? "unknown";
|
|
8835
|
+
return `The organization service returned a '${contentType}' response instead ` + `of JSON: ${parseError.message}. ${organizationHint(organizationId)}`;
|
|
8836
|
+
};
|
|
8837
|
+
var fetchTenantsAndOrganizations = async (baseUrl, accessToken, organizationId, signal) => {
|
|
8838
|
+
const url = `${baseUrl}/${organizationId}/portal_/api/filtering/leftnav/tenantsAndOrganizationInfo`;
|
|
8839
|
+
const response = await fetch(url, {
|
|
8840
|
+
headers: {
|
|
8841
|
+
Authorization: `Bearer ${accessToken}`
|
|
8842
|
+
},
|
|
8843
|
+
...signal ? { signal } : {}
|
|
8844
|
+
});
|
|
8845
|
+
if (!response.ok) {
|
|
8846
|
+
if (response.status === 401) {
|
|
8847
|
+
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);
|
|
8848
|
+
}
|
|
8849
|
+
const errorText = await response.text();
|
|
8850
|
+
const message = `Failed to get tenants and organizations: ${response.status} ${errorText}`;
|
|
8851
|
+
throw new Error(IDENTIFIER_STATUSES.has(response.status) ? `${message}. ${organizationHint(organizationId)}` : message);
|
|
8852
|
+
}
|
|
8853
|
+
const [parseError, data] = await catchError2(response.json());
|
|
8854
|
+
if (parseError) {
|
|
8855
|
+
throw new Error(describeNonJsonResponse(organizationId, response, parseError));
|
|
8856
|
+
}
|
|
8857
|
+
return data;
|
|
8858
|
+
};
|
|
8859
|
+
|
|
8804
8860
|
// ../../auth/src/tokenRefresh.ts
|
|
8805
8861
|
var TOKEN_REFRESH_REAUTHENTICATE_MESSAGE = "Token refresh failed. Run 'uip login' to re-authenticate.";
|
|
8806
8862
|
|
|
@@ -9013,6 +9069,8 @@ var saveEnvFileAsync = async ({
|
|
|
9013
9069
|
};
|
|
9014
9070
|
|
|
9015
9071
|
// ../../auth/src/loginStatus.ts
|
|
9072
|
+
var defaultRobotTenantIdCache = new Map;
|
|
9073
|
+
var ROBOT_TENANT_LOOKUP_TIMEOUT_MS = 5000;
|
|
9016
9074
|
var getLoginStatusAsync = async (options = {}) => {
|
|
9017
9075
|
return getLoginStatusWithDeps(options);
|
|
9018
9076
|
};
|
|
@@ -9025,12 +9083,20 @@ var getLoginStatusWithDeps = async (options = {}, deps = {}) => {
|
|
|
9025
9083
|
refreshToken: refreshTokenFn = refreshAccessToken,
|
|
9026
9084
|
resolveConfig = resolveConfigAsync,
|
|
9027
9085
|
robotFallback = tryRobotClientFallback,
|
|
9086
|
+
fetchTenantsAndOrgs = fetchTenantsAndOrganizations,
|
|
9087
|
+
robotTenantIdCache = defaultRobotTenantIdCache,
|
|
9088
|
+
robotTenantLookupTimeoutMs = ROBOT_TENANT_LOOKUP_TIMEOUT_MS,
|
|
9028
9089
|
loadBreaker = loadRefreshBreaker,
|
|
9029
9090
|
saveBreaker = saveRefreshBreaker,
|
|
9030
9091
|
clearBreaker = clearRefreshBreaker
|
|
9031
9092
|
} = deps;
|
|
9093
|
+
const robotDeps = {
|
|
9094
|
+
fetchTenantsAndOrgs,
|
|
9095
|
+
cache: robotTenantIdCache,
|
|
9096
|
+
lookupTimeoutMs: robotTenantLookupTimeoutMs
|
|
9097
|
+
};
|
|
9032
9098
|
if (isRobotAuthEnforced()) {
|
|
9033
|
-
return resolveRobotEnforcedStatus(robotFallback);
|
|
9099
|
+
return resolveRobotEnforcedStatus(robotFallback, robotDeps);
|
|
9034
9100
|
}
|
|
9035
9101
|
if (isEnvAuthEnabled()) {
|
|
9036
9102
|
return readAuthFromEnv();
|
|
@@ -9048,7 +9114,7 @@ var getLoginStatusWithDeps = async (options = {}, deps = {}) => {
|
|
|
9048
9114
|
hint: `No credentials found for profile "${activeProfile}". Run 'uip login --profile ${activeProfile}' to authenticate this profile.`
|
|
9049
9115
|
};
|
|
9050
9116
|
}
|
|
9051
|
-
return resolveBorrowedRobotStatus(robotFallback);
|
|
9117
|
+
return resolveBorrowedRobotStatus(robotFallback, robotDeps);
|
|
9052
9118
|
}
|
|
9053
9119
|
const loaded = await loadFileCredentials(loadEnvFile, absolutePath);
|
|
9054
9120
|
if ("status" in loaded) {
|
|
@@ -9090,7 +9156,7 @@ var getLoginStatusWithDeps = async (options = {}, deps = {}) => {
|
|
|
9090
9156
|
}
|
|
9091
9157
|
return buildFileStatus(tokens, credentials, globalHint);
|
|
9092
9158
|
};
|
|
9093
|
-
async function resolveRobotEnforcedStatus(robotFallback) {
|
|
9159
|
+
async function resolveRobotEnforcedStatus(robotFallback, deps) {
|
|
9094
9160
|
if (isEnvAuthEnabled()) {
|
|
9095
9161
|
throw new EnvAuthConfigError(`${ENV_AUTH_ENABLE_VAR}=true and ${ENFORCE_ROBOT_AUTH_VAR}=true ` + `are mutually exclusive. Unset one of them and re-run.`);
|
|
9096
9162
|
}
|
|
@@ -9101,11 +9167,11 @@ async function resolveRobotEnforcedStatus(robotFallback) {
|
|
|
9101
9167
|
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.`
|
|
9102
9168
|
};
|
|
9103
9169
|
}
|
|
9104
|
-
return buildRobotStatus(robotCreds);
|
|
9170
|
+
return buildRobotStatus(robotCreds, deps);
|
|
9105
9171
|
}
|
|
9106
|
-
async function resolveBorrowedRobotStatus(robotFallback) {
|
|
9172
|
+
async function resolveBorrowedRobotStatus(robotFallback, deps) {
|
|
9107
9173
|
const robotCreds = await robotFallback();
|
|
9108
|
-
return robotCreds ? buildRobotStatus(robotCreds) : { loginStatus: "Not logged in" };
|
|
9174
|
+
return robotCreds ? buildRobotStatus(robotCreds, deps) : { loginStatus: "Not logged in" };
|
|
9109
9175
|
}
|
|
9110
9176
|
async function loadFileCredentials(loadEnvFile, absolutePath) {
|
|
9111
9177
|
let credentials;
|
|
@@ -9240,9 +9306,10 @@ function identityFields(accessToken, credentials) {
|
|
|
9240
9306
|
...scopes ? { scopes } : {}
|
|
9241
9307
|
};
|
|
9242
9308
|
}
|
|
9243
|
-
function buildRobotStatus(robotCreds) {
|
|
9309
|
+
async function buildRobotStatus(robotCreds, deps) {
|
|
9244
9310
|
const identity = resolveSessionIdentity(robotCreds.accessToken);
|
|
9245
9311
|
const scopes = readTokenScopes(robotCreds.accessToken);
|
|
9312
|
+
const tenant = robotCreds.tenantId ? { tenantId: robotCreds.tenantId } : await resolveRobotTenantId(robotCreds, deps);
|
|
9246
9313
|
return {
|
|
9247
9314
|
loginStatus: "Logged in",
|
|
9248
9315
|
accessToken: robotCreds.accessToken,
|
|
@@ -9250,14 +9317,62 @@ function buildRobotStatus(robotCreds) {
|
|
|
9250
9317
|
organizationName: robotCreds.organizationName,
|
|
9251
9318
|
organizationId: robotCreds.organizationId,
|
|
9252
9319
|
tenantName: robotCreds.tenantName,
|
|
9253
|
-
tenantId:
|
|
9320
|
+
tenantId: tenant.tenantId,
|
|
9254
9321
|
issuer: robotCreds.issuer,
|
|
9255
9322
|
expiration: getTokenExpiration(robotCreds.accessToken),
|
|
9256
9323
|
source: "robot" /* Robot */,
|
|
9324
|
+
...tenant.hint ? { hint: tenant.hint } : {},
|
|
9257
9325
|
...identity ? { identity } : {},
|
|
9258
9326
|
...scopes ? { scopes } : {}
|
|
9259
9327
|
};
|
|
9260
9328
|
}
|
|
9329
|
+
async function resolveRobotTenantId(robotCreds, deps) {
|
|
9330
|
+
const { baseUrl, accessToken, tenantName } = robotCreds;
|
|
9331
|
+
const organization = robotCreds.organizationName ?? robotCreds.organizationId;
|
|
9332
|
+
if (!tenantName || !organization) {
|
|
9333
|
+
return {};
|
|
9334
|
+
}
|
|
9335
|
+
const key = `${baseUrl}|${organization}|${tenantName}|${accessToken}`;
|
|
9336
|
+
let pending = deps.cache.get(key);
|
|
9337
|
+
if (!pending) {
|
|
9338
|
+
pending = catchError2(lookupRobotTenantId({ baseUrl, accessToken, organization, tenantName }, deps)).then(([error, resolution]) => {
|
|
9339
|
+
const settled = error ? { hint: tenantLookupFailureHint(tenantName, error.message) } : resolution;
|
|
9340
|
+
if (!settled.tenantId) {
|
|
9341
|
+
deps.cache.delete(key);
|
|
9342
|
+
}
|
|
9343
|
+
return settled;
|
|
9344
|
+
});
|
|
9345
|
+
deps.cache.set(key, pending);
|
|
9346
|
+
}
|
|
9347
|
+
return pending;
|
|
9348
|
+
}
|
|
9349
|
+
async function lookupRobotTenantId(target, deps) {
|
|
9350
|
+
const { baseUrl, accessToken, organization, tenantName } = target;
|
|
9351
|
+
const [error, data] = await catchError2(deps.fetchTenantsAndOrgs(baseUrl, accessToken, organization, AbortSignal.timeout(deps.lookupTimeoutMs)));
|
|
9352
|
+
if (error) {
|
|
9353
|
+
const reason = error.name === "TimeoutError" ? `the tenant list did not answer within ${deps.lookupTimeoutMs} ms.` : error.message;
|
|
9354
|
+
return { hint: tenantLookupFailureHint(tenantName, reason) };
|
|
9355
|
+
}
|
|
9356
|
+
const rows = data?.tenants;
|
|
9357
|
+
const tenants = Array.isArray(rows) ? rows.filter((tenant) => typeof tenant?.id === "string" && typeof tenant?.name === "string") : [];
|
|
9358
|
+
const wantedName = decodePathSegment(tenantName);
|
|
9359
|
+
const wanted = wantedName.toLowerCase();
|
|
9360
|
+
const match = tenants.find((tenant) => tenant.name === wantedName) ?? tenants.find((tenant) => tenant.name.toLowerCase() === wanted);
|
|
9361
|
+
if (!match) {
|
|
9362
|
+
const names = tenants.map((tenant) => tenant.name).join(", ");
|
|
9363
|
+
return {
|
|
9364
|
+
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.`
|
|
9365
|
+
};
|
|
9366
|
+
}
|
|
9367
|
+
return { tenantId: match.id };
|
|
9368
|
+
}
|
|
9369
|
+
function tenantLookupFailureHint(tenantName, reason) {
|
|
9370
|
+
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.`;
|
|
9371
|
+
}
|
|
9372
|
+
function decodePathSegment(segment) {
|
|
9373
|
+
const [error, decoded] = catchError2(() => decodeURIComponent(segment));
|
|
9374
|
+
return error ? segment : decoded;
|
|
9375
|
+
}
|
|
9261
9376
|
var isFileNotFoundError = (error) => {
|
|
9262
9377
|
if (!(error instanceof Object))
|
|
9263
9378
|
return false;
|
|
@@ -9493,9 +9608,6 @@ function normalizeTokenRefreshUnavailableFailure() {
|
|
|
9493
9608
|
function errorMessage(error) {
|
|
9494
9609
|
return error instanceof Error ? error.message : String(error);
|
|
9495
9610
|
}
|
|
9496
|
-
// ../../auth/src/tenantSelection.ts
|
|
9497
|
-
var IDENTIFIER_STATUSES = new Set([400, 403, 404]);
|
|
9498
|
-
|
|
9499
9611
|
// ../../auth/src/selectTenant.ts
|
|
9500
9612
|
var TENANT_SELECTION_REQUIRED_CODE = "TENANT_SELECTION_REQUIRED";
|
|
9501
9613
|
var INVALID_TENANT_CODE = "INVALID_TENANT";
|
|
@@ -9768,4 +9880,4 @@ var registerCommands = async (program2) => {
|
|
|
9768
9880
|
|
|
9769
9881
|
export { Command, metadata, registerCommands };
|
|
9770
9882
|
|
|
9771
|
-
//# debugId=
|
|
9883
|
+
//# debugId=D9FD0251FC49D98F64756E2164756E21
|
package/dist/tool.js
CHANGED
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@uipath/resourcecatalog-tool",
|
|
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": "CLI plugin for the UiPath Resource Catalog Service.",
|
|
7
7
|
"private": false,
|
|
8
8
|
"repository": {
|
|
@@ -27,5 +27,5 @@
|
|
|
27
27
|
"files": [
|
|
28
28
|
"dist"
|
|
29
29
|
],
|
|
30
|
-
"gitHead": "
|
|
30
|
+
"gitHead": "63740c6cbb7ff282fa9118cc16a148eb030b245f"
|
|
31
31
|
}
|