@hot-updater/apple-helper 1.2.0-rc.6 → 1.2.0-rc.7
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 +70 -20
- package/dist/index.mjs +70 -20
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -551,6 +551,23 @@ const signInToAppStoreConnect = async ({ appleId, password, prompts, fetch = glo
|
|
|
551
551
|
}
|
|
552
552
|
};
|
|
553
553
|
//#endregion
|
|
554
|
+
//#region src/asc/programLicenseAgreement.ts
|
|
555
|
+
/**
|
|
556
|
+
* What to do when Apple holds a team's requests until the Account Holder
|
|
557
|
+
* accepts the latest Apple Developer Program License Agreement: App Store
|
|
558
|
+
* Connect answers 403, and xcodebuild prints "PLA Update available".
|
|
559
|
+
*/
|
|
560
|
+
const PROGRAM_LICENSE_AGREEMENT_HINT = ["The Account Holder must accept the latest Program License Agreement:", "https://developer.apple.com/account"].join("\n");
|
|
561
|
+
/** The code App Store Connect answers a team with a pending agreement. */
|
|
562
|
+
const AGREEMENT_ERROR_CODE = "FORBIDDEN.REQUIRED_AGREEMENTS_MISSING_OR_EXPIRED";
|
|
563
|
+
/**
|
|
564
|
+
* Whether App Store Connect's JSON:API errors say the team has a Program
|
|
565
|
+
* License Agreement to accept, by its code or its detail.
|
|
566
|
+
*/
|
|
567
|
+
const isProgramLicenseAgreementError = (errors) => errors.some(({ code, detail, title }) => code === AGREEMENT_ERROR_CODE || /Program License Agreement/iu.test(`${detail ?? ""} ${title ?? ""}`));
|
|
568
|
+
/** Whether xcodebuild's output says the team has an agreement to accept. */
|
|
569
|
+
const mentionsProgramLicenseAgreement = (output) => output.includes("PLA Update available");
|
|
570
|
+
//#endregion
|
|
554
571
|
//#region src/asc/ascKeyIssuer.ts
|
|
555
572
|
const IRIS_URL = "https://appstoreconnect.apple.com/iris/v1";
|
|
556
573
|
/**
|
|
@@ -603,7 +620,7 @@ const irisDetail = (body) => {
|
|
|
603
620
|
};
|
|
604
621
|
/** What to do about a key App Store Connect would not create. */
|
|
605
622
|
const createFailureHint = (status, body) => {
|
|
606
|
-
if (/agreement/iu.test(body)) return
|
|
623
|
+
if (/agreement/iu.test(body)) return PROGRAM_LICENSE_AGREEMENT_HINT;
|
|
607
624
|
if (/limit|maximum/iu.test(body)) return `The team has the most API keys App Store Connect allows. Revoke one at:\n${ASC_INTEGRATIONS_URL}`;
|
|
608
625
|
if (status === 403 || /account holder|admin|permission/iu.test(body)) return "Creating an API key needs the Account Holder or Admin role in the team.";
|
|
609
626
|
};
|
|
@@ -1019,7 +1036,7 @@ const parseXcodeProjectInfo = async (sourceDir) => {
|
|
|
1019
1036
|
const prettifyXcodebuildError = (error) => {
|
|
1020
1037
|
if (error instanceof _hot_updater_cli_tools.BuildFailedError) {
|
|
1021
1038
|
const errorLines = error.summary.join("\n");
|
|
1022
|
-
const message = errorLines.includes("error: No profiles for") || errorLines.includes("error: Provisioning profile") ? "No valid provisioning profile is set in the project.\nCheck the Signing & Capabilities tab in Xcode." : error.message;
|
|
1039
|
+
const message = mentionsProgramLicenseAgreement(errorLines) ? PROGRAM_LICENSE_AGREEMENT_HINT : errorLines.includes("error: No profiles for") || errorLines.includes("error: Provisioning profile") ? "No valid provisioning profile is set in the project.\nCheck the Signing & Capabilities tab in Xcode." : error.message;
|
|
1023
1040
|
return new _hot_updater_cli_tools.BuildFailedError(message, {
|
|
1024
1041
|
logPath: error.logPath,
|
|
1025
1042
|
summary: error.summary,
|
|
@@ -1917,7 +1934,7 @@ const createAppStoreConnectRequest = ({ apiKey, privateKey, fetch }) => {
|
|
|
1917
1934
|
if (!response.ok) {
|
|
1918
1935
|
const error = new AppStoreConnectError(action, response.status, await readApiErrors(response), response.headers.get("retry-after"));
|
|
1919
1936
|
if (response.status === 401) throw new Error("App Store Connect refused the API key.\nCheck its key ID and issuer ID, and that it isn't revoked.", { cause: error });
|
|
1920
|
-
if (response.status === 403) throw new Error(`${error.message}\nUploads need a key with the Admin, App Manager, or Developer role.`, { cause: error });
|
|
1937
|
+
if (response.status === 403) throw new Error(isProgramLicenseAgreementError(error.errors) ? `${action} failed (HTTP 403).\n${PROGRAM_LICENSE_AGREEMENT_HINT}` : `${error.message}\nUploads need a key with the Admin, App Manager, or Developer role.`, { cause: error });
|
|
1921
1938
|
throw error;
|
|
1922
1939
|
}
|
|
1923
1940
|
return response.status === 204 ? void 0 : await response.json();
|
|
@@ -2356,38 +2373,62 @@ const createSigningKeychain = async ({ security = runSecurity, directory = os.de
|
|
|
2356
2373
|
return {
|
|
2357
2374
|
path: keychainPath,
|
|
2358
2375
|
certificates: async () => {
|
|
2376
|
+
const identities = new Set([...(await security([
|
|
2377
|
+
"find-identity",
|
|
2378
|
+
"-p",
|
|
2379
|
+
"codesigning",
|
|
2380
|
+
keychainPath
|
|
2381
|
+
])).matchAll(/^\s*\d+\)\s+([0-9A-F]{40})\s/gm)].map((match) => match[1]));
|
|
2382
|
+
if (identities.size === 0) return [];
|
|
2359
2383
|
return ((await security([
|
|
2360
2384
|
"find-certificate",
|
|
2361
2385
|
"-a",
|
|
2362
2386
|
"-p",
|
|
2363
2387
|
keychainPath
|
|
2364
|
-
])).match(/-----BEGIN CERTIFICATE-----[\s\S]+?-----END CERTIFICATE-----/g) ?? []).
|
|
2388
|
+
])).match(/-----BEGIN CERTIFICATE-----[\s\S]+?-----END CERTIFICATE-----/g) ?? []).flatMap((pem) => {
|
|
2365
2389
|
const certificate = new crypto.default.X509Certificate(pem);
|
|
2366
|
-
return
|
|
2390
|
+
if (!identities.has(certificate.fingerprint.replaceAll(":", ""))) return [];
|
|
2391
|
+
return [{
|
|
2367
2392
|
serialNumber: normalizeSerial(certificate.serialNumber),
|
|
2368
2393
|
commonName: certificate.subject.match(/^CN=(.*)$/m)?.[1] ?? certificate.subject
|
|
2369
|
-
};
|
|
2394
|
+
}];
|
|
2370
2395
|
});
|
|
2371
2396
|
},
|
|
2372
2397
|
dispose
|
|
2373
2398
|
};
|
|
2374
2399
|
};
|
|
2400
|
+
/** A request App Store Connect refused, in one line. */
|
|
2401
|
+
var AppStoreConnectRefusal = class extends Error {
|
|
2402
|
+
/** Whether the team has a Program License Agreement to accept. */
|
|
2403
|
+
agreement;
|
|
2404
|
+
constructor(message, agreement) {
|
|
2405
|
+
super(message);
|
|
2406
|
+
this.agreement = agreement;
|
|
2407
|
+
}
|
|
2408
|
+
};
|
|
2409
|
+
const refusal = async (action, response) => {
|
|
2410
|
+
const body = await response.json().catch(() => void 0);
|
|
2411
|
+
return new AppStoreConnectRefusal(`${action} failed (HTTP ${response.status}).`, isProgramLicenseAgreementError(Array.isArray(body?.errors) ? body.errors : []));
|
|
2412
|
+
};
|
|
2375
2413
|
/**
|
|
2376
2414
|
* Revokes the certificates Xcode created in the build's keychain, whose
|
|
2377
2415
|
* private keys the keychain's deletion destroys: on a runner that starts
|
|
2378
2416
|
* empty, Xcode creates a development certificate for every build, and App
|
|
2379
2417
|
* Store Connect refuses new ones once a team has its maximum. Each is found
|
|
2380
2418
|
* in the team's certificates by serial number. A revocation that fails is
|
|
2381
|
-
* reported with
|
|
2419
|
+
* reported with each certificate's name and serial and where to revoke it
|
|
2420
|
+
* by hand, and never fails the build.
|
|
2382
2421
|
*/
|
|
2383
2422
|
const revokeKeychainCertificates = async ({ certificates, apiKey, privateKey, fetch = globalThis.fetch }) => {
|
|
2384
2423
|
const revoked = [];
|
|
2385
2424
|
const failed = [];
|
|
2425
|
+
/** Why none could be revoked: the token or the listing failed. */
|
|
2426
|
+
let reason;
|
|
2427
|
+
let agreement = false;
|
|
2386
2428
|
if (certificates.length === 0) return {
|
|
2387
|
-
revoked,
|
|
2388
|
-
failed
|
|
2429
|
+
revoked: [],
|
|
2430
|
+
failed: []
|
|
2389
2431
|
};
|
|
2390
|
-
const describe = ({ commonName, serialNumber }) => `${commonName} (serial ${serialNumber})`;
|
|
2391
2432
|
try {
|
|
2392
2433
|
const token = createAppStoreConnectToken({
|
|
2393
2434
|
privateKey: privateKey ?? crypto.default.createPrivateKey(await fs.default.promises.readFile(apiKey.keyPath, "utf-8")),
|
|
@@ -2403,7 +2444,7 @@ const revokeKeychainCertificates = async ({ certificates, apiKey, privateKey, fe
|
|
|
2403
2444
|
})}`;
|
|
2404
2445
|
while (next) {
|
|
2405
2446
|
const response = await fetch(next, { headers });
|
|
2406
|
-
if (!response.ok) throw
|
|
2447
|
+
if (!response.ok) throw await refusal("Listing the team's certificates", response);
|
|
2407
2448
|
const body = await response.json();
|
|
2408
2449
|
for (const { id, attributes } of body.data ?? []) if (attributes?.serialNumber) idsBySerial.set(normalizeSerial(attributes.serialNumber), id);
|
|
2409
2450
|
next = body.links?.next;
|
|
@@ -2415,23 +2456,32 @@ const revokeKeychainCertificates = async ({ certificates, apiKey, privateKey, fe
|
|
|
2415
2456
|
method: "DELETE",
|
|
2416
2457
|
headers
|
|
2417
2458
|
});
|
|
2418
|
-
if (response.ok || response.status === 404) revoked.push(
|
|
2419
|
-
else
|
|
2459
|
+
if (response.ok || response.status === 404) revoked.push(certificate);
|
|
2460
|
+
else {
|
|
2461
|
+
agreement ||= (await refusal("Revoking", response)).agreement;
|
|
2462
|
+
failed.push({
|
|
2463
|
+
certificate,
|
|
2464
|
+
status: response.status
|
|
2465
|
+
});
|
|
2466
|
+
}
|
|
2420
2467
|
}
|
|
2421
2468
|
} catch (error) {
|
|
2422
|
-
|
|
2423
|
-
|
|
2469
|
+
reason = error instanceof Error ? error.message : String(error);
|
|
2470
|
+
agreement ||= error instanceof AppStoreConnectRefusal && error.agreement;
|
|
2471
|
+
for (const certificate of certificates) if (!revoked.includes(certificate)) failed.push({ certificate });
|
|
2424
2472
|
}
|
|
2425
|
-
|
|
2473
|
+
const describe = ({ commonName, serialNumber }) => `${commonName} (serial ${serialNumber})`;
|
|
2474
|
+
if (revoked.length > 0) _hot_updater_cli_tools.p.log.info(["Revoked the certificates Xcode created for this build:", ...revoked.flatMap(({ commonName, serialNumber }) => [commonName, `Serial ${serialNumber}`])].join("\n"));
|
|
2426
2475
|
if (failed.length > 0) _hot_updater_cli_tools.p.log.warn([
|
|
2427
2476
|
"Couldn't revoke the certificates Xcode created for this build.",
|
|
2428
|
-
...
|
|
2429
|
-
|
|
2477
|
+
...reason === void 0 ? [] : [reason],
|
|
2478
|
+
...agreement ? [PROGRAM_LICENSE_AGREEMENT_HINT] : [],
|
|
2479
|
+
...failed.flatMap(({ certificate, status }) => [certificate.commonName, `Serial ${certificate.serialNumber}${status === void 0 ? "" : ` (HTTP ${status})`}`]),
|
|
2430
2480
|
CERTIFICATES_URL
|
|
2431
2481
|
].join("\n"));
|
|
2432
2482
|
return {
|
|
2433
|
-
revoked,
|
|
2434
|
-
failed
|
|
2483
|
+
revoked: revoked.map(describe),
|
|
2484
|
+
failed: failed.map(({ certificate }) => describe(certificate))
|
|
2435
2485
|
};
|
|
2436
2486
|
};
|
|
2437
2487
|
const TERMINATION_SIGNALS = [
|
package/dist/index.mjs
CHANGED
|
@@ -523,6 +523,23 @@ const signInToAppStoreConnect = async ({ appleId, password, prompts, fetch = glo
|
|
|
523
523
|
}
|
|
524
524
|
};
|
|
525
525
|
//#endregion
|
|
526
|
+
//#region src/asc/programLicenseAgreement.ts
|
|
527
|
+
/**
|
|
528
|
+
* What to do when Apple holds a team's requests until the Account Holder
|
|
529
|
+
* accepts the latest Apple Developer Program License Agreement: App Store
|
|
530
|
+
* Connect answers 403, and xcodebuild prints "PLA Update available".
|
|
531
|
+
*/
|
|
532
|
+
const PROGRAM_LICENSE_AGREEMENT_HINT = ["The Account Holder must accept the latest Program License Agreement:", "https://developer.apple.com/account"].join("\n");
|
|
533
|
+
/** The code App Store Connect answers a team with a pending agreement. */
|
|
534
|
+
const AGREEMENT_ERROR_CODE = "FORBIDDEN.REQUIRED_AGREEMENTS_MISSING_OR_EXPIRED";
|
|
535
|
+
/**
|
|
536
|
+
* Whether App Store Connect's JSON:API errors say the team has a Program
|
|
537
|
+
* License Agreement to accept, by its code or its detail.
|
|
538
|
+
*/
|
|
539
|
+
const isProgramLicenseAgreementError = (errors) => errors.some(({ code, detail, title }) => code === AGREEMENT_ERROR_CODE || /Program License Agreement/iu.test(`${detail ?? ""} ${title ?? ""}`));
|
|
540
|
+
/** Whether xcodebuild's output says the team has an agreement to accept. */
|
|
541
|
+
const mentionsProgramLicenseAgreement = (output) => output.includes("PLA Update available");
|
|
542
|
+
//#endregion
|
|
526
543
|
//#region src/asc/ascKeyIssuer.ts
|
|
527
544
|
const IRIS_URL = "https://appstoreconnect.apple.com/iris/v1";
|
|
528
545
|
/**
|
|
@@ -575,7 +592,7 @@ const irisDetail = (body) => {
|
|
|
575
592
|
};
|
|
576
593
|
/** What to do about a key App Store Connect would not create. */
|
|
577
594
|
const createFailureHint = (status, body) => {
|
|
578
|
-
if (/agreement/iu.test(body)) return
|
|
595
|
+
if (/agreement/iu.test(body)) return PROGRAM_LICENSE_AGREEMENT_HINT;
|
|
579
596
|
if (/limit|maximum/iu.test(body)) return `The team has the most API keys App Store Connect allows. Revoke one at:\n${ASC_INTEGRATIONS_URL}`;
|
|
580
597
|
if (status === 403 || /account holder|admin|permission/iu.test(body)) return "Creating an API key needs the Account Holder or Admin role in the team.";
|
|
581
598
|
};
|
|
@@ -991,7 +1008,7 @@ const parseXcodeProjectInfo = async (sourceDir) => {
|
|
|
991
1008
|
const prettifyXcodebuildError = (error) => {
|
|
992
1009
|
if (error instanceof BuildFailedError) {
|
|
993
1010
|
const errorLines = error.summary.join("\n");
|
|
994
|
-
const message = errorLines.includes("error: No profiles for") || errorLines.includes("error: Provisioning profile") ? "No valid provisioning profile is set in the project.\nCheck the Signing & Capabilities tab in Xcode." : error.message;
|
|
1011
|
+
const message = mentionsProgramLicenseAgreement(errorLines) ? PROGRAM_LICENSE_AGREEMENT_HINT : errorLines.includes("error: No profiles for") || errorLines.includes("error: Provisioning profile") ? "No valid provisioning profile is set in the project.\nCheck the Signing & Capabilities tab in Xcode." : error.message;
|
|
995
1012
|
return new BuildFailedError(message, {
|
|
996
1013
|
logPath: error.logPath,
|
|
997
1014
|
summary: error.summary,
|
|
@@ -1889,7 +1906,7 @@ const createAppStoreConnectRequest = ({ apiKey, privateKey, fetch }) => {
|
|
|
1889
1906
|
if (!response.ok) {
|
|
1890
1907
|
const error = new AppStoreConnectError(action, response.status, await readApiErrors(response), response.headers.get("retry-after"));
|
|
1891
1908
|
if (response.status === 401) throw new Error("App Store Connect refused the API key.\nCheck its key ID and issuer ID, and that it isn't revoked.", { cause: error });
|
|
1892
|
-
if (response.status === 403) throw new Error(`${error.message}\nUploads need a key with the Admin, App Manager, or Developer role.`, { cause: error });
|
|
1909
|
+
if (response.status === 403) throw new Error(isProgramLicenseAgreementError(error.errors) ? `${action} failed (HTTP 403).\n${PROGRAM_LICENSE_AGREEMENT_HINT}` : `${error.message}\nUploads need a key with the Admin, App Manager, or Developer role.`, { cause: error });
|
|
1893
1910
|
throw error;
|
|
1894
1911
|
}
|
|
1895
1912
|
return response.status === 204 ? void 0 : await response.json();
|
|
@@ -2328,38 +2345,62 @@ const createSigningKeychain = async ({ security = runSecurity, directory = os.tm
|
|
|
2328
2345
|
return {
|
|
2329
2346
|
path: keychainPath,
|
|
2330
2347
|
certificates: async () => {
|
|
2348
|
+
const identities = new Set([...(await security([
|
|
2349
|
+
"find-identity",
|
|
2350
|
+
"-p",
|
|
2351
|
+
"codesigning",
|
|
2352
|
+
keychainPath
|
|
2353
|
+
])).matchAll(/^\s*\d+\)\s+([0-9A-F]{40})\s/gm)].map((match) => match[1]));
|
|
2354
|
+
if (identities.size === 0) return [];
|
|
2331
2355
|
return ((await security([
|
|
2332
2356
|
"find-certificate",
|
|
2333
2357
|
"-a",
|
|
2334
2358
|
"-p",
|
|
2335
2359
|
keychainPath
|
|
2336
|
-
])).match(/-----BEGIN CERTIFICATE-----[\s\S]+?-----END CERTIFICATE-----/g) ?? []).
|
|
2360
|
+
])).match(/-----BEGIN CERTIFICATE-----[\s\S]+?-----END CERTIFICATE-----/g) ?? []).flatMap((pem) => {
|
|
2337
2361
|
const certificate = new crypto$1.X509Certificate(pem);
|
|
2338
|
-
return
|
|
2362
|
+
if (!identities.has(certificate.fingerprint.replaceAll(":", ""))) return [];
|
|
2363
|
+
return [{
|
|
2339
2364
|
serialNumber: normalizeSerial(certificate.serialNumber),
|
|
2340
2365
|
commonName: certificate.subject.match(/^CN=(.*)$/m)?.[1] ?? certificate.subject
|
|
2341
|
-
};
|
|
2366
|
+
}];
|
|
2342
2367
|
});
|
|
2343
2368
|
},
|
|
2344
2369
|
dispose
|
|
2345
2370
|
};
|
|
2346
2371
|
};
|
|
2372
|
+
/** A request App Store Connect refused, in one line. */
|
|
2373
|
+
var AppStoreConnectRefusal = class extends Error {
|
|
2374
|
+
/** Whether the team has a Program License Agreement to accept. */
|
|
2375
|
+
agreement;
|
|
2376
|
+
constructor(message, agreement) {
|
|
2377
|
+
super(message);
|
|
2378
|
+
this.agreement = agreement;
|
|
2379
|
+
}
|
|
2380
|
+
};
|
|
2381
|
+
const refusal = async (action, response) => {
|
|
2382
|
+
const body = await response.json().catch(() => void 0);
|
|
2383
|
+
return new AppStoreConnectRefusal(`${action} failed (HTTP ${response.status}).`, isProgramLicenseAgreementError(Array.isArray(body?.errors) ? body.errors : []));
|
|
2384
|
+
};
|
|
2347
2385
|
/**
|
|
2348
2386
|
* Revokes the certificates Xcode created in the build's keychain, whose
|
|
2349
2387
|
* private keys the keychain's deletion destroys: on a runner that starts
|
|
2350
2388
|
* empty, Xcode creates a development certificate for every build, and App
|
|
2351
2389
|
* Store Connect refuses new ones once a team has its maximum. Each is found
|
|
2352
2390
|
* in the team's certificates by serial number. A revocation that fails is
|
|
2353
|
-
* reported with
|
|
2391
|
+
* reported with each certificate's name and serial and where to revoke it
|
|
2392
|
+
* by hand, and never fails the build.
|
|
2354
2393
|
*/
|
|
2355
2394
|
const revokeKeychainCertificates = async ({ certificates, apiKey, privateKey, fetch = globalThis.fetch }) => {
|
|
2356
2395
|
const revoked = [];
|
|
2357
2396
|
const failed = [];
|
|
2397
|
+
/** Why none could be revoked: the token or the listing failed. */
|
|
2398
|
+
let reason;
|
|
2399
|
+
let agreement = false;
|
|
2358
2400
|
if (certificates.length === 0) return {
|
|
2359
|
-
revoked,
|
|
2360
|
-
failed
|
|
2401
|
+
revoked: [],
|
|
2402
|
+
failed: []
|
|
2361
2403
|
};
|
|
2362
|
-
const describe = ({ commonName, serialNumber }) => `${commonName} (serial ${serialNumber})`;
|
|
2363
2404
|
try {
|
|
2364
2405
|
const token = createAppStoreConnectToken({
|
|
2365
2406
|
privateKey: privateKey ?? crypto$1.createPrivateKey(await fs.promises.readFile(apiKey.keyPath, "utf-8")),
|
|
@@ -2375,7 +2416,7 @@ const revokeKeychainCertificates = async ({ certificates, apiKey, privateKey, fe
|
|
|
2375
2416
|
})}`;
|
|
2376
2417
|
while (next) {
|
|
2377
2418
|
const response = await fetch(next, { headers });
|
|
2378
|
-
if (!response.ok) throw
|
|
2419
|
+
if (!response.ok) throw await refusal("Listing the team's certificates", response);
|
|
2379
2420
|
const body = await response.json();
|
|
2380
2421
|
for (const { id, attributes } of body.data ?? []) if (attributes?.serialNumber) idsBySerial.set(normalizeSerial(attributes.serialNumber), id);
|
|
2381
2422
|
next = body.links?.next;
|
|
@@ -2387,23 +2428,32 @@ const revokeKeychainCertificates = async ({ certificates, apiKey, privateKey, fe
|
|
|
2387
2428
|
method: "DELETE",
|
|
2388
2429
|
headers
|
|
2389
2430
|
});
|
|
2390
|
-
if (response.ok || response.status === 404) revoked.push(
|
|
2391
|
-
else
|
|
2431
|
+
if (response.ok || response.status === 404) revoked.push(certificate);
|
|
2432
|
+
else {
|
|
2433
|
+
agreement ||= (await refusal("Revoking", response)).agreement;
|
|
2434
|
+
failed.push({
|
|
2435
|
+
certificate,
|
|
2436
|
+
status: response.status
|
|
2437
|
+
});
|
|
2438
|
+
}
|
|
2392
2439
|
}
|
|
2393
2440
|
} catch (error) {
|
|
2394
|
-
|
|
2395
|
-
|
|
2441
|
+
reason = error instanceof Error ? error.message : String(error);
|
|
2442
|
+
agreement ||= error instanceof AppStoreConnectRefusal && error.agreement;
|
|
2443
|
+
for (const certificate of certificates) if (!revoked.includes(certificate)) failed.push({ certificate });
|
|
2396
2444
|
}
|
|
2397
|
-
|
|
2445
|
+
const describe = ({ commonName, serialNumber }) => `${commonName} (serial ${serialNumber})`;
|
|
2446
|
+
if (revoked.length > 0) p.log.info(["Revoked the certificates Xcode created for this build:", ...revoked.flatMap(({ commonName, serialNumber }) => [commonName, `Serial ${serialNumber}`])].join("\n"));
|
|
2398
2447
|
if (failed.length > 0) p.log.warn([
|
|
2399
2448
|
"Couldn't revoke the certificates Xcode created for this build.",
|
|
2400
|
-
...
|
|
2401
|
-
|
|
2449
|
+
...reason === void 0 ? [] : [reason],
|
|
2450
|
+
...agreement ? [PROGRAM_LICENSE_AGREEMENT_HINT] : [],
|
|
2451
|
+
...failed.flatMap(({ certificate, status }) => [certificate.commonName, `Serial ${certificate.serialNumber}${status === void 0 ? "" : ` (HTTP ${status})`}`]),
|
|
2402
2452
|
CERTIFICATES_URL
|
|
2403
2453
|
].join("\n"));
|
|
2404
2454
|
return {
|
|
2405
|
-
revoked,
|
|
2406
|
-
failed
|
|
2455
|
+
revoked: revoked.map(describe),
|
|
2456
|
+
failed: failed.map(({ certificate }) => describe(certificate))
|
|
2407
2457
|
};
|
|
2408
2458
|
};
|
|
2409
2459
|
const TERMINATION_SIGNALS = [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hot-updater/apple-helper",
|
|
3
|
-
"version": "1.2.0-rc.
|
|
3
|
+
"version": "1.2.0-rc.7",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"execa": "9.5.2",
|
|
31
31
|
"fast-xml-parser": "5.8.0",
|
|
32
|
-
"@hot-updater/cli-tools": "1.2.0-rc.
|
|
33
|
-
"@hot-updater/plugin-core": "1.2.0-rc.
|
|
32
|
+
"@hot-updater/cli-tools": "1.2.0-rc.7",
|
|
33
|
+
"@hot-updater/plugin-core": "1.2.0-rc.7"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/node": "^20"
|