@better-update/cli 0.37.0 → 0.38.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.mjs +823 -100
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -35,7 +35,7 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
|
35
35
|
|
|
36
36
|
//#endregion
|
|
37
37
|
//#region package.json
|
|
38
|
-
var version = "0.
|
|
38
|
+
var version = "0.38.0";
|
|
39
39
|
|
|
40
40
|
//#endregion
|
|
41
41
|
//#region src/lib/interactive-mode.ts
|
|
@@ -425,11 +425,11 @@ const Ciphertext = Schema.String.pipe(Schema.minLength(1)).annotations({ descrip
|
|
|
425
425
|
const WrappedDek = Schema.String.pipe(Schema.minLength(1)).annotations({ description: "Base64 of the DEK wrapped under the org vault key" });
|
|
426
426
|
/**
|
|
427
427
|
* The secret kinds whose DEK is wrapped under the org vault key — the rows a
|
|
428
|
-
* rotation must re-wrap.
|
|
428
|
+
* rotation must re-wrap. Eight signing-credential tables plus `envVarValue` (one
|
|
429
429
|
* row per environment variable value revision). Provisioning profiles are
|
|
430
430
|
* plaintext and are deliberately absent.
|
|
431
431
|
*/
|
|
432
|
-
const CredentialType = Schema.Literal("appleDistributionCertificate", "applePushKey", "ascApiKey", "googleServiceAccountKey", "androidUploadKeystore", "envVarValue").annotations({ description: "Which encrypted-secret table a vault-key DEK re-wrap targets" });
|
|
432
|
+
const CredentialType = Schema.Literal("appleDistributionCertificate", "applePushKey", "applePushCertificate", "applePayCertificate", "applePassTypeCertificate", "ascApiKey", "googleServiceAccountKey", "androidUploadKeystore", "envVarValue").annotations({ description: "Which encrypted-secret table a vault-key DEK re-wrap targets" });
|
|
433
433
|
/**
|
|
434
434
|
* The client-encrypted envelope. Spread into each secret credential's upload
|
|
435
435
|
* body and download result alongside that credential's public metadata. The
|
|
@@ -665,6 +665,128 @@ var AppleDistributionCertificatesGroup = class extends HttpApiGroup.make("appleD
|
|
|
665
665
|
description: "Manage .p12 distribution certificates"
|
|
666
666
|
})) {};
|
|
667
667
|
|
|
668
|
+
//#endregion
|
|
669
|
+
//#region ../../packages/api/src/domain/apple-pass-type-certificate.ts
|
|
670
|
+
/**
|
|
671
|
+
* Pass Type ID certificate (Wallet passes), bound to a Pass Type ID
|
|
672
|
+
* (`pass.*`). The library has no Pass Type ID API, so these are uploaded
|
|
673
|
+
* manually: the CLI seals the `.p12` (cert + key) and the server stores only the
|
|
674
|
+
* envelope + metadata.
|
|
675
|
+
*/
|
|
676
|
+
var ApplePassTypeCertificate = class extends Schema.Class("ApplePassTypeCertificate")({
|
|
677
|
+
id: Id,
|
|
678
|
+
organizationId: Id,
|
|
679
|
+
appleTeamId: Id,
|
|
680
|
+
passTypeIdentifier: Schema.String,
|
|
681
|
+
serialNumber: Schema.String,
|
|
682
|
+
validFrom: DateTimeString,
|
|
683
|
+
validUntil: DateTimeString,
|
|
684
|
+
createdAt: DateTimeString,
|
|
685
|
+
updatedAt: DateTimeString
|
|
686
|
+
}) {};
|
|
687
|
+
/** Client-encrypted upload: the `.p12` bytes + password are sealed into `ciphertext`. */
|
|
688
|
+
const UploadApplePassTypeCertificateBody = Schema.Struct({
|
|
689
|
+
id: Id,
|
|
690
|
+
...encryptedEnvelopeFields,
|
|
691
|
+
passTypeIdentifier: Schema.String.pipe(Schema.minLength(1), Schema.maxLength(200)),
|
|
692
|
+
serialNumber: Schema.String.pipe(Schema.minLength(1), Schema.maxLength(200)),
|
|
693
|
+
appleTeamIdentifier: AppleTeamIdentifier,
|
|
694
|
+
...appleTeamMetadataFields,
|
|
695
|
+
validFrom: DateTimeString,
|
|
696
|
+
validUntil: DateTimeString
|
|
697
|
+
});
|
|
698
|
+
const DeleteApplePassTypeCertificateResult = DeletedResult;
|
|
699
|
+
/** The encrypted envelope (relayed from R2) plus metadata; the CLI decrypts `ciphertext` to recover `{ p12Base64, p12Password }`. */
|
|
700
|
+
const DownloadApplePassTypeCertificateResult = Schema.Struct({
|
|
701
|
+
id: Id,
|
|
702
|
+
...encryptedEnvelopeFields,
|
|
703
|
+
passTypeIdentifier: Schema.String,
|
|
704
|
+
serialNumber: Schema.String,
|
|
705
|
+
appleTeamIdentifier: AppleTeamIdentifier,
|
|
706
|
+
validFrom: DateTimeString,
|
|
707
|
+
validUntil: DateTimeString
|
|
708
|
+
});
|
|
709
|
+
|
|
710
|
+
//#endregion
|
|
711
|
+
//#region ../../packages/api/src/groups/apple-pass-type-certificates.ts
|
|
712
|
+
var ApplePassTypeCertificatesGroup = class extends HttpApiGroup.make("applePassTypeCertificates").add(HttpApiEndpoint.get("list", "/api/apple/pass-type-certificates").addSuccess(Schema.Struct({ items: Schema.Array(ApplePassTypeCertificate) })).annotateContext(OpenApi.annotations({
|
|
713
|
+
title: "List Apple Pass Type ID certificates",
|
|
714
|
+
description: "List Pass Type ID certificates for the organization"
|
|
715
|
+
}))).add(HttpApiEndpoint.post("upload", "/api/apple/pass-type-certificates").setPayload(UploadApplePassTypeCertificateBody).addSuccess(ApplePassTypeCertificate, { status: 201 }).annotateContext(OpenApi.annotations({
|
|
716
|
+
title: "Upload Pass Type ID certificate",
|
|
717
|
+
description: "Upload a Wallet Pass Type ID .p12 certificate"
|
|
718
|
+
}))).add(HttpApiEndpoint.del("delete")`/api/apple/pass-type-certificates/${idParam}`.addSuccess(DeleteApplePassTypeCertificateResult).annotateContext(OpenApi.annotations({
|
|
719
|
+
title: "Delete Pass Type ID certificate",
|
|
720
|
+
description: "Remove a stored Pass Type ID certificate"
|
|
721
|
+
}))).add(HttpApiEndpoint.get("download")`/api/apple/pass-type-certificates/${idParam}/download`.addSuccess(DownloadApplePassTypeCertificateResult).annotateContext(OpenApi.annotations({
|
|
722
|
+
title: "Download Pass Type ID certificate",
|
|
723
|
+
description: "Fetch the decrypted .p12 Pass Type ID certificate for local use (audit-logged)"
|
|
724
|
+
}))).addError(NotFound).addError(Conflict).addError(BadRequest).addError(Forbidden).annotateContext(OpenApi.annotations({
|
|
725
|
+
title: "Apple Pass Type ID Certificates",
|
|
726
|
+
description: "Manage Wallet Pass Type ID certificates"
|
|
727
|
+
})) {};
|
|
728
|
+
|
|
729
|
+
//#endregion
|
|
730
|
+
//#region ../../packages/api/src/domain/apple-pay-certificate.ts
|
|
731
|
+
/**
|
|
732
|
+
* Apple Pay Payment Processing certificate, bound to a Merchant ID
|
|
733
|
+
* (`merchant.*`). The library cannot create these (no portal cert type), so they
|
|
734
|
+
* are uploaded manually: the CLI seals the `.p12` (cert + key) and the server
|
|
735
|
+
* stores only the envelope + metadata.
|
|
736
|
+
*/
|
|
737
|
+
var ApplePayCertificate = class extends Schema.Class("ApplePayCertificate")({
|
|
738
|
+
id: Id,
|
|
739
|
+
organizationId: Id,
|
|
740
|
+
appleTeamId: Id,
|
|
741
|
+
merchantIdentifier: Schema.String,
|
|
742
|
+
serialNumber: Schema.String,
|
|
743
|
+
validFrom: DateTimeString,
|
|
744
|
+
validUntil: DateTimeString,
|
|
745
|
+
createdAt: DateTimeString,
|
|
746
|
+
updatedAt: DateTimeString
|
|
747
|
+
}) {};
|
|
748
|
+
/** Client-encrypted upload: the `.p12` bytes + password are sealed into `ciphertext`. */
|
|
749
|
+
const UploadApplePayCertificateBody = Schema.Struct({
|
|
750
|
+
id: Id,
|
|
751
|
+
...encryptedEnvelopeFields,
|
|
752
|
+
merchantIdentifier: Schema.String.pipe(Schema.minLength(1), Schema.maxLength(200)),
|
|
753
|
+
serialNumber: Schema.String.pipe(Schema.minLength(1), Schema.maxLength(200)),
|
|
754
|
+
appleTeamIdentifier: AppleTeamIdentifier,
|
|
755
|
+
...appleTeamMetadataFields,
|
|
756
|
+
validFrom: DateTimeString,
|
|
757
|
+
validUntil: DateTimeString
|
|
758
|
+
});
|
|
759
|
+
const DeleteApplePayCertificateResult = DeletedResult;
|
|
760
|
+
/** The encrypted envelope (relayed from R2) plus metadata; the CLI decrypts `ciphertext` to recover `{ p12Base64, p12Password }`. */
|
|
761
|
+
const DownloadApplePayCertificateResult = Schema.Struct({
|
|
762
|
+
id: Id,
|
|
763
|
+
...encryptedEnvelopeFields,
|
|
764
|
+
merchantIdentifier: Schema.String,
|
|
765
|
+
serialNumber: Schema.String,
|
|
766
|
+
appleTeamIdentifier: AppleTeamIdentifier,
|
|
767
|
+
validFrom: DateTimeString,
|
|
768
|
+
validUntil: DateTimeString
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
//#endregion
|
|
772
|
+
//#region ../../packages/api/src/groups/apple-pay-certificates.ts
|
|
773
|
+
var ApplePayCertificatesGroup = class extends HttpApiGroup.make("applePayCertificates").add(HttpApiEndpoint.get("list", "/api/apple/pay-certificates").addSuccess(Schema.Struct({ items: Schema.Array(ApplePayCertificate) })).annotateContext(OpenApi.annotations({
|
|
774
|
+
title: "List Apple Pay certificates",
|
|
775
|
+
description: "List Apple Pay payment processing certificates for the organization"
|
|
776
|
+
}))).add(HttpApiEndpoint.post("upload", "/api/apple/pay-certificates").setPayload(UploadApplePayCertificateBody).addSuccess(ApplePayCertificate, { status: 201 }).annotateContext(OpenApi.annotations({
|
|
777
|
+
title: "Upload Apple Pay certificate",
|
|
778
|
+
description: "Upload an Apple Pay payment processing .p12 certificate"
|
|
779
|
+
}))).add(HttpApiEndpoint.del("delete")`/api/apple/pay-certificates/${idParam}`.addSuccess(DeleteApplePayCertificateResult).annotateContext(OpenApi.annotations({
|
|
780
|
+
title: "Delete Apple Pay certificate",
|
|
781
|
+
description: "Remove a stored Apple Pay payment processing certificate"
|
|
782
|
+
}))).add(HttpApiEndpoint.get("download")`/api/apple/pay-certificates/${idParam}/download`.addSuccess(DownloadApplePayCertificateResult).annotateContext(OpenApi.annotations({
|
|
783
|
+
title: "Download Apple Pay certificate",
|
|
784
|
+
description: "Fetch the decrypted .p12 Apple Pay certificate for local use (audit-logged)"
|
|
785
|
+
}))).addError(NotFound).addError(Conflict).addError(BadRequest).addError(Forbidden).annotateContext(OpenApi.annotations({
|
|
786
|
+
title: "Apple Pay Certificates",
|
|
787
|
+
description: "Manage Apple Pay payment processing certificates"
|
|
788
|
+
})) {};
|
|
789
|
+
|
|
668
790
|
//#endregion
|
|
669
791
|
//#region ../../packages/api/src/domain/apple-provisioning-profile.ts
|
|
670
792
|
const DistributionType = Schema.Literal("APP_STORE", "AD_HOC", "ENTERPRISE", "DEVELOPMENT");
|
|
@@ -722,6 +844,71 @@ var AppleProvisioningProfilesGroup = class extends HttpApiGroup.make("appleProvi
|
|
|
722
844
|
description: "Manage .mobileprovision profiles (upload or generate)"
|
|
723
845
|
})) {};
|
|
724
846
|
|
|
847
|
+
//#endregion
|
|
848
|
+
//#region ../../packages/api/src/domain/apple-push-certificate.ts
|
|
849
|
+
/**
|
|
850
|
+
* Legacy APNs Push Services SSL certificate (the `.cer`/`.p12` push cert, distinct
|
|
851
|
+
* from the modern `.p8` token key in `apple-push-key.ts`). Bound to a single App
|
|
852
|
+
* ID (`bundleIdentifier`) rather than a whole team. The production cert serves
|
|
853
|
+
* both the sandbox and production APNs environments.
|
|
854
|
+
*/
|
|
855
|
+
var ApplePushCertificate = class extends Schema.Class("ApplePushCertificate")({
|
|
856
|
+
id: Id,
|
|
857
|
+
organizationId: Id,
|
|
858
|
+
appleTeamId: Id,
|
|
859
|
+
bundleIdentifier: Schema.String,
|
|
860
|
+
serialNumber: Schema.String,
|
|
861
|
+
validFrom: DateTimeString,
|
|
862
|
+
validUntil: DateTimeString,
|
|
863
|
+
createdAt: DateTimeString,
|
|
864
|
+
updatedAt: DateTimeString
|
|
865
|
+
}) {};
|
|
866
|
+
/**
|
|
867
|
+
* Client-encrypted upload: the `.p12` bytes + password are sealed into
|
|
868
|
+
* `ciphertext` (the CLI parses the cert locally to fill the metadata below);
|
|
869
|
+
* the server stores the envelope and metadata and never sees the plaintext.
|
|
870
|
+
*/
|
|
871
|
+
const UploadApplePushCertificateBody = Schema.Struct({
|
|
872
|
+
id: Id,
|
|
873
|
+
...encryptedEnvelopeFields,
|
|
874
|
+
bundleIdentifier: Schema.String.pipe(Schema.minLength(1), Schema.maxLength(200)),
|
|
875
|
+
serialNumber: Schema.String.pipe(Schema.minLength(1), Schema.maxLength(200)),
|
|
876
|
+
appleTeamIdentifier: AppleTeamIdentifier,
|
|
877
|
+
...appleTeamMetadataFields,
|
|
878
|
+
validFrom: DateTimeString,
|
|
879
|
+
validUntil: DateTimeString
|
|
880
|
+
});
|
|
881
|
+
const DeleteApplePushCertificateResult = DeletedResult;
|
|
882
|
+
/** The encrypted envelope (relayed from R2) plus server-visible metadata; the CLI decrypts `ciphertext` to recover `{ p12Base64, p12Password }`. */
|
|
883
|
+
const DownloadApplePushCertificateResult = Schema.Struct({
|
|
884
|
+
id: Id,
|
|
885
|
+
...encryptedEnvelopeFields,
|
|
886
|
+
bundleIdentifier: Schema.String,
|
|
887
|
+
serialNumber: Schema.String,
|
|
888
|
+
appleTeamIdentifier: AppleTeamIdentifier,
|
|
889
|
+
validFrom: DateTimeString,
|
|
890
|
+
validUntil: DateTimeString
|
|
891
|
+
});
|
|
892
|
+
|
|
893
|
+
//#endregion
|
|
894
|
+
//#region ../../packages/api/src/groups/apple-push-certificates.ts
|
|
895
|
+
var ApplePushCertificatesGroup = class extends HttpApiGroup.make("applePushCertificates").add(HttpApiEndpoint.get("list", "/api/apple/push-certificates").addSuccess(Schema.Struct({ items: Schema.Array(ApplePushCertificate) })).annotateContext(OpenApi.annotations({
|
|
896
|
+
title: "List Apple push certificates",
|
|
897
|
+
description: "List APNs push SSL certificates for the organization"
|
|
898
|
+
}))).add(HttpApiEndpoint.post("upload", "/api/apple/push-certificates").setPayload(UploadApplePushCertificateBody).addSuccess(ApplePushCertificate, { status: 201 }).annotateContext(OpenApi.annotations({
|
|
899
|
+
title: "Upload push certificate",
|
|
900
|
+
description: "Upload an APNs Push Services .p12 SSL certificate"
|
|
901
|
+
}))).add(HttpApiEndpoint.del("delete")`/api/apple/push-certificates/${idParam}`.addSuccess(DeleteApplePushCertificateResult).annotateContext(OpenApi.annotations({
|
|
902
|
+
title: "Delete push certificate",
|
|
903
|
+
description: "Remove a stored APNs push SSL certificate"
|
|
904
|
+
}))).add(HttpApiEndpoint.get("download")`/api/apple/push-certificates/${idParam}/download`.addSuccess(DownloadApplePushCertificateResult).annotateContext(OpenApi.annotations({
|
|
905
|
+
title: "Download push certificate",
|
|
906
|
+
description: "Fetch the decrypted .p12 push certificate for local use (audit-logged)"
|
|
907
|
+
}))).addError(NotFound).addError(Conflict).addError(BadRequest).addError(Forbidden).annotateContext(OpenApi.annotations({
|
|
908
|
+
title: "Apple Push Certificates",
|
|
909
|
+
description: "Manage APNs Push Services SSL certificates"
|
|
910
|
+
})) {};
|
|
911
|
+
|
|
725
912
|
//#endregion
|
|
726
913
|
//#region ../../packages/api/src/domain/apple-push-key.ts
|
|
727
914
|
const ApplePushKeyId = tenCharPortalId("Push Key ID");
|
|
@@ -2550,7 +2737,7 @@ var WebhooksGroup = class extends HttpApiGroup.make("webhooks").add(HttpApiEndpo
|
|
|
2550
2737
|
|
|
2551
2738
|
//#endregion
|
|
2552
2739
|
//#region ../../packages/api/src/api.ts
|
|
2553
|
-
var ManagementApi = class extends HttpApi.make("management-api").add(ProjectsGroup).add(BranchesGroup).add(ChannelsGroup).add(EnvironmentsGroup).add(UpdatesGroup).add(AssetsGroup).add(AnalyticsGroup).add(BuildsGroup).add(RuntimesGroup).add(EnvVarsGroup).add(FingerprintsGroup).add(AuditLogsGroup).add(DevicesGroup).add(AppleTeamsGroup).add(AppleDistributionCertificatesGroup).add(ApplePushKeysGroup).add(AscApiKeysGroup).add(AppleProvisioningProfilesGroup).add(GoogleServiceAccountKeysGroup).add(IosBundleConfigurationsGroup).add(IosAppMetadataGroup).add(SubmissionsGroup).add(AndroidApplicationIdentifiersGroup).add(AndroidUploadKeystoresGroup).add(AndroidBuildCredentialsGroup).add(BuildCredentialsGroup).add(UserEncryptionKeysGroup).add(OrgVaultGroup).add(MeGroup).add(WebhooksGroup).add(PoliciesGroup).add(GroupsGroup).add(PolicyAttachmentsGroup).add(ApiKeysGroup).add(InvitationsGroup).add(MembersGroup).add(OrganizationGroup).add(AdminGroup).middleware(Authentication).annotateContext(OpenApi.annotations({
|
|
2740
|
+
var ManagementApi = class extends HttpApi.make("management-api").add(ProjectsGroup).add(BranchesGroup).add(ChannelsGroup).add(EnvironmentsGroup).add(UpdatesGroup).add(AssetsGroup).add(AnalyticsGroup).add(BuildsGroup).add(RuntimesGroup).add(EnvVarsGroup).add(FingerprintsGroup).add(AuditLogsGroup).add(DevicesGroup).add(AppleTeamsGroup).add(AppleDistributionCertificatesGroup).add(ApplePushKeysGroup).add(ApplePushCertificatesGroup).add(ApplePayCertificatesGroup).add(ApplePassTypeCertificatesGroup).add(AscApiKeysGroup).add(AppleProvisioningProfilesGroup).add(GoogleServiceAccountKeysGroup).add(IosBundleConfigurationsGroup).add(IosAppMetadataGroup).add(SubmissionsGroup).add(AndroidApplicationIdentifiersGroup).add(AndroidUploadKeystoresGroup).add(AndroidBuildCredentialsGroup).add(BuildCredentialsGroup).add(UserEncryptionKeysGroup).add(OrgVaultGroup).add(MeGroup).add(WebhooksGroup).add(PoliciesGroup).add(GroupsGroup).add(PolicyAttachmentsGroup).add(ApiKeysGroup).add(InvitationsGroup).add(MembersGroup).add(OrganizationGroup).add(AdminGroup).middleware(Authentication).annotateContext(OpenApi.annotations({
|
|
2554
2741
|
title: "Better Update Management API",
|
|
2555
2742
|
version: "1.0.0",
|
|
2556
2743
|
description: "Management API for OTA update publishing, deployment, and analytics"
|
|
@@ -3567,8 +3754,9 @@ const VaultCacheLive = Layer.effect(VaultCache, Effect.gen(function* () {
|
|
|
3567
3754
|
//#endregion
|
|
3568
3755
|
//#region src/services/version-check.ts
|
|
3569
3756
|
const NPM_REGISTRY_URL = "https://registry.npmjs.org/@better-update/cli/latest";
|
|
3570
|
-
const CACHE_TTL_MS =
|
|
3757
|
+
const CACHE_TTL_MS = 300 * 1e3;
|
|
3571
3758
|
const REFRESH_TIMEOUT_MS = 3e3;
|
|
3759
|
+
const FOREGROUND_TIMEOUT_MS = 1500;
|
|
3572
3760
|
var VersionCheck = class extends Context.Tag("cli/VersionCheck")() {};
|
|
3573
3761
|
const VersionCheckLive = Layer.effect(VersionCheck, Effect.gen(function* () {
|
|
3574
3762
|
const fs = yield* FileSystem.FileSystem;
|
|
@@ -3588,6 +3776,20 @@ const VersionCheckLive = Layer.effect(VersionCheck, Effect.gen(function* () {
|
|
|
3588
3776
|
checkedAt: parsed["checkedAt"]
|
|
3589
3777
|
};
|
|
3590
3778
|
});
|
|
3779
|
+
const fetchAndCache = (timeoutMs) => Effect.gen(function* () {
|
|
3780
|
+
const request = HttpClientRequest.get(NPM_REGISTRY_URL).pipe(HttpClientRequest.setHeader("accept", "application/json"));
|
|
3781
|
+
const response = yield* httpClient.execute(request);
|
|
3782
|
+
if (response.status < 200 || response.status >= 300) return;
|
|
3783
|
+
const body = yield* response.json;
|
|
3784
|
+
if (!isRecord$1(body) || typeof body["version"] !== "string") return;
|
|
3785
|
+
const latest = body["version"];
|
|
3786
|
+
yield* fs.makeDirectory(cacheDir, { recursive: true });
|
|
3787
|
+
yield* fs.writeFileString(cacheFile, `${JSON.stringify({
|
|
3788
|
+
latest,
|
|
3789
|
+
checkedAt: Date.now()
|
|
3790
|
+
}, null, 2)}\n`);
|
|
3791
|
+
return latest;
|
|
3792
|
+
}).pipe(Effect.timeout(timeoutMs), Effect.catchAll(() => Effect.succeed(void 0)));
|
|
3591
3793
|
return {
|
|
3592
3794
|
cachedLatest: readCache.pipe(Effect.map((entry) => entry?.latest)),
|
|
3593
3795
|
cacheStale: readCache.pipe(Effect.map((entry) => {
|
|
@@ -3595,19 +3797,8 @@ const VersionCheckLive = Layer.effect(VersionCheck, Effect.gen(function* () {
|
|
|
3595
3797
|
const elapsed = Date.now() - entry.checkedAt;
|
|
3596
3798
|
return elapsed < 0 || elapsed > CACHE_TTL_MS;
|
|
3597
3799
|
})),
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
const response = yield* httpClient.execute(request);
|
|
3601
|
-
if (response.status < 200 || response.status >= 300) return;
|
|
3602
|
-
const body = yield* response.json;
|
|
3603
|
-
if (!isRecord$1(body) || typeof body["version"] !== "string") return;
|
|
3604
|
-
const latest = body["version"];
|
|
3605
|
-
yield* fs.makeDirectory(cacheDir, { recursive: true });
|
|
3606
|
-
yield* fs.writeFileString(cacheFile, `${JSON.stringify({
|
|
3607
|
-
latest,
|
|
3608
|
-
checkedAt: Date.now()
|
|
3609
|
-
}, null, 2)}\n`);
|
|
3610
|
-
}).pipe(Effect.timeout(REFRESH_TIMEOUT_MS), Effect.catchAll(() => Effect.void))
|
|
3800
|
+
fetchLatest: fetchAndCache(FOREGROUND_TIMEOUT_MS),
|
|
3801
|
+
refreshCache: fetchAndCache(REFRESH_TIMEOUT_MS).pipe(Effect.asVoid)
|
|
3611
3802
|
};
|
|
3612
3803
|
}));
|
|
3613
3804
|
|
|
@@ -4535,6 +4726,79 @@ const writeEasJsonPatch = (projectRoot, patch) => Effect.gen(function* () {
|
|
|
4535
4726
|
return filePath;
|
|
4536
4727
|
});
|
|
4537
4728
|
/**
|
|
4729
|
+
* Default `build` profiles scaffolded by `init` / `build configure`. Mirrors the
|
|
4730
|
+
* EAS three-tier convention: `development` (dev-client, internal), `preview`
|
|
4731
|
+
* (internal QA) and `production` (store). Keep in sync with the build-profile
|
|
4732
|
+
* derivation in `build-profile.ts` (e.g. `distribution: "internal"` → ad-hoc).
|
|
4733
|
+
*/
|
|
4734
|
+
const DEFAULT_BUILD_PROFILES = {
|
|
4735
|
+
development: {
|
|
4736
|
+
developmentClient: true,
|
|
4737
|
+
distribution: "internal",
|
|
4738
|
+
channel: "development",
|
|
4739
|
+
environment: "development",
|
|
4740
|
+
android: { format: "apk" }
|
|
4741
|
+
},
|
|
4742
|
+
preview: {
|
|
4743
|
+
distribution: "internal",
|
|
4744
|
+
channel: "preview",
|
|
4745
|
+
environment: "preview",
|
|
4746
|
+
android: { format: "apk" }
|
|
4747
|
+
},
|
|
4748
|
+
production: {
|
|
4749
|
+
channel: "production",
|
|
4750
|
+
environment: "production",
|
|
4751
|
+
android: { format: "aab" }
|
|
4752
|
+
}
|
|
4753
|
+
};
|
|
4754
|
+
const DEFAULT_PROFILE_NAMES = [
|
|
4755
|
+
"development",
|
|
4756
|
+
"preview",
|
|
4757
|
+
"production"
|
|
4758
|
+
];
|
|
4759
|
+
/** Full default `eas.json` body (cli pin + the three default build profiles). */
|
|
4760
|
+
const DEFAULT_EAS_JSON = {
|
|
4761
|
+
cli: { version: ">= 7.0.0" },
|
|
4762
|
+
build: DEFAULT_BUILD_PROFILES
|
|
4763
|
+
};
|
|
4764
|
+
/**
|
|
4765
|
+
* Ensure `eas.json` carries the default build profiles. Creates the file with
|
|
4766
|
+
* the full default template when absent; otherwise tops up only the missing
|
|
4767
|
+
* default profiles, preserving every existing profile and top-level key
|
|
4768
|
+
* (`projectId`, `projectType`, `submit`, …). Never overwrites a profile that is
|
|
4769
|
+
* already defined — call sites wanting a hard reset write `DEFAULT_EAS_JSON`.
|
|
4770
|
+
*/
|
|
4771
|
+
const ensureDefaultBuildProfiles = (projectRoot) => Effect.gen(function* () {
|
|
4772
|
+
const existing = yield* readEasJsonRaw(projectRoot);
|
|
4773
|
+
if (existing === void 0) return {
|
|
4774
|
+
path: yield* writeEasJsonPatch(projectRoot, DEFAULT_EAS_JSON),
|
|
4775
|
+
action: "created",
|
|
4776
|
+
added: [...DEFAULT_PROFILE_NAMES]
|
|
4777
|
+
};
|
|
4778
|
+
const existingBuild = isRecord$1(existing["build"]) ? existing["build"] : {};
|
|
4779
|
+
const missing = DEFAULT_PROFILE_NAMES.filter((name) => !(name in existingBuild));
|
|
4780
|
+
if (missing.length === 0) return {
|
|
4781
|
+
path: easJsonPath(projectRoot),
|
|
4782
|
+
action: "noop",
|
|
4783
|
+
added: []
|
|
4784
|
+
};
|
|
4785
|
+
const additions = Object.fromEntries(missing.map((name) => [name, DEFAULT_BUILD_PROFILES[name]]));
|
|
4786
|
+
return {
|
|
4787
|
+
path: yield* writeEasJsonPatch(projectRoot, existing["cli"] === void 0 ? {
|
|
4788
|
+
cli: DEFAULT_EAS_JSON.cli,
|
|
4789
|
+
build: {
|
|
4790
|
+
...existingBuild,
|
|
4791
|
+
...additions
|
|
4792
|
+
}
|
|
4793
|
+
} : { build: {
|
|
4794
|
+
...existingBuild,
|
|
4795
|
+
...additions
|
|
4796
|
+
} }),
|
|
4797
|
+
action: "topped-up",
|
|
4798
|
+
added: missing
|
|
4799
|
+
};
|
|
4800
|
+
});
|
|
4801
|
+
/**
|
|
4538
4802
|
* Resolve the linked project id from `eas.json`'s top-level `projectId`, or
|
|
4539
4803
|
* `undefined` when the file is absent / has no usable value.
|
|
4540
4804
|
*/
|
|
@@ -24210,34 +24474,6 @@ const runBuildWorkflow = (options) => Effect.scoped(Effect.gen(function* () {
|
|
|
24210
24474
|
|
|
24211
24475
|
//#endregion
|
|
24212
24476
|
//#region src/commands/build/configure.ts
|
|
24213
|
-
const DEFAULT_EAS_JSON = {
|
|
24214
|
-
cli: { version: ">= 7.0.0" },
|
|
24215
|
-
build: {
|
|
24216
|
-
development: {
|
|
24217
|
-
developmentClient: true,
|
|
24218
|
-
distribution: "internal",
|
|
24219
|
-
channel: "development",
|
|
24220
|
-
environment: "development",
|
|
24221
|
-
android: { format: "apk" }
|
|
24222
|
-
},
|
|
24223
|
-
preview: {
|
|
24224
|
-
distribution: "internal",
|
|
24225
|
-
channel: "preview",
|
|
24226
|
-
environment: "preview",
|
|
24227
|
-
android: { format: "apk" }
|
|
24228
|
-
},
|
|
24229
|
-
production: {
|
|
24230
|
-
channel: "production",
|
|
24231
|
-
environment: "production",
|
|
24232
|
-
android: { format: "aab" }
|
|
24233
|
-
}
|
|
24234
|
-
}
|
|
24235
|
-
};
|
|
24236
|
-
const DEFAULT_PROFILES = [
|
|
24237
|
-
"development",
|
|
24238
|
-
"preview",
|
|
24239
|
-
"production"
|
|
24240
|
-
];
|
|
24241
24477
|
const writeEasJson = (filePath, value) => Effect.gen(function* () {
|
|
24242
24478
|
yield* (yield* FileSystem.FileSystem).writeFileString(filePath, `${JSON.stringify(value, null, 2)}\n`).pipe(Effect.mapError((cause) => new BuildProfileError({ message: `Failed to write eas.json: ${cause.message}` })));
|
|
24243
24479
|
});
|
|
@@ -24253,43 +24489,44 @@ const configureBuildCommand = defineCommand({
|
|
|
24253
24489
|
run: async ({ args }) => runEffect(Effect.gen(function* () {
|
|
24254
24490
|
const { allow: interactive } = yield* InteractiveMode;
|
|
24255
24491
|
const projectRoot = yield* (yield* CliRuntime).cwd;
|
|
24256
|
-
const
|
|
24492
|
+
const filePath = easJsonPath(projectRoot);
|
|
24257
24493
|
const fs = yield* FileSystem.FileSystem;
|
|
24258
|
-
|
|
24259
|
-
yield* writeEasJson(easJsonPath, DEFAULT_EAS_JSON);
|
|
24260
|
-
yield* printHuman(`Wrote eas.json with default profiles to ${easJsonPath}.`);
|
|
24261
|
-
yield* printHumanKeyValue([["Profiles", DEFAULT_PROFILES.join(", ")], ["Path", easJsonPath]]);
|
|
24262
|
-
return {
|
|
24263
|
-
action: "created",
|
|
24264
|
-
path: easJsonPath,
|
|
24265
|
-
profiles: [...DEFAULT_PROFILES]
|
|
24266
|
-
};
|
|
24267
|
-
}
|
|
24494
|
+
const exists = yield* fs.exists(filePath);
|
|
24268
24495
|
if (args.force === true) {
|
|
24269
|
-
if (!(interactive ? yield* promptConfirm(`Overwrite existing eas.json at ${
|
|
24496
|
+
if (!(exists && interactive ? yield* promptConfirm(`Overwrite existing eas.json at ${filePath} with defaults?`) : true)) {
|
|
24270
24497
|
yield* printHuman("Aborted. eas.json was not modified.");
|
|
24271
24498
|
return {
|
|
24272
24499
|
action: "aborted",
|
|
24273
|
-
path:
|
|
24500
|
+
path: filePath
|
|
24274
24501
|
};
|
|
24275
24502
|
}
|
|
24276
|
-
yield* writeEasJson(
|
|
24277
|
-
yield* printHuman(
|
|
24503
|
+
yield* writeEasJson(filePath, DEFAULT_EAS_JSON);
|
|
24504
|
+
yield* printHuman(exists ? "Overwrote eas.json with default profiles." : `Wrote eas.json with default profiles to ${filePath}.`);
|
|
24505
|
+
return {
|
|
24506
|
+
action: exists ? "overwritten" : "created",
|
|
24507
|
+
path: filePath,
|
|
24508
|
+
profiles: [...DEFAULT_PROFILE_NAMES]
|
|
24509
|
+
};
|
|
24510
|
+
}
|
|
24511
|
+
if (!exists) {
|
|
24512
|
+
const created = yield* ensureDefaultBuildProfiles(projectRoot);
|
|
24513
|
+
yield* printHuman(`Wrote eas.json with default profiles to ${created.path}.`);
|
|
24514
|
+
yield* printHumanKeyValue([["Profiles", created.added.join(", ")], ["Path", created.path]]);
|
|
24278
24515
|
return {
|
|
24279
|
-
action: "
|
|
24280
|
-
path:
|
|
24281
|
-
profiles:
|
|
24516
|
+
action: "created",
|
|
24517
|
+
path: created.path,
|
|
24518
|
+
profiles: created.added
|
|
24282
24519
|
};
|
|
24283
24520
|
}
|
|
24284
|
-
const config = yield* parseEasConfig(yield* fs.readFileString(
|
|
24521
|
+
const config = yield* parseEasConfig(yield* fs.readFileString(filePath).pipe(Effect.mapError((cause) => new BuildProfileError({ message: `Failed to read eas.json: ${cause.message}` }))));
|
|
24285
24522
|
const existingProfiles = Object.keys(config.build ?? {});
|
|
24286
|
-
const missing =
|
|
24523
|
+
const missing = DEFAULT_PROFILE_NAMES.filter((name) => !existingProfiles.includes(name));
|
|
24287
24524
|
if (missing.length === 0) {
|
|
24288
24525
|
yield* printHuman(`eas.json already defines all default profiles (${existingProfiles.join(", ")}). Nothing to add.`);
|
|
24289
24526
|
yield* printHuman("Pass --force to overwrite with the default template.");
|
|
24290
24527
|
return {
|
|
24291
24528
|
action: "noop",
|
|
24292
|
-
path:
|
|
24529
|
+
path: filePath,
|
|
24293
24530
|
existing: existingProfiles
|
|
24294
24531
|
};
|
|
24295
24532
|
}
|
|
@@ -24297,28 +24534,21 @@ const configureBuildCommand = defineCommand({
|
|
|
24297
24534
|
yield* printHuman("Aborted. eas.json was not modified.");
|
|
24298
24535
|
return {
|
|
24299
24536
|
action: "aborted",
|
|
24300
|
-
path:
|
|
24537
|
+
path: filePath
|
|
24301
24538
|
};
|
|
24302
24539
|
}
|
|
24303
|
-
const
|
|
24304
|
-
yield*
|
|
24305
|
-
build: {
|
|
24306
|
-
...config.build,
|
|
24307
|
-
...additions
|
|
24308
|
-
},
|
|
24309
|
-
...compact({ cli: config.cli })
|
|
24310
|
-
});
|
|
24311
|
-
yield* printHuman(`Added profile(s) to eas.json: ${missing.join(", ")}.`);
|
|
24540
|
+
const result = yield* ensureDefaultBuildProfiles(projectRoot);
|
|
24541
|
+
yield* printHuman(`Added profile(s) to eas.json: ${result.added.join(", ")}.`);
|
|
24312
24542
|
yield* printHumanKeyValue([
|
|
24313
24543
|
["Existing", existingProfiles.join(", ") || "(none)"],
|
|
24314
|
-
["Added",
|
|
24315
|
-
["Path",
|
|
24544
|
+
["Added", result.added.join(", ")],
|
|
24545
|
+
["Path", result.path]
|
|
24316
24546
|
]);
|
|
24317
24547
|
return {
|
|
24318
24548
|
action: "topped-up",
|
|
24319
|
-
path:
|
|
24549
|
+
path: result.path,
|
|
24320
24550
|
existing: existingProfiles,
|
|
24321
|
-
added:
|
|
24551
|
+
added: result.added
|
|
24322
24552
|
};
|
|
24323
24553
|
}), { json: "value" })
|
|
24324
24554
|
});
|
|
@@ -25858,13 +26088,160 @@ const inspectP12 = (params) => Effect.try({
|
|
|
25858
26088
|
catch: (error) => new CredentialValidationError({ message: `Failed to parse P12 certificate: ${error instanceof Error ? error.message : String(error)}` })
|
|
25859
26089
|
});
|
|
25860
26090
|
|
|
26091
|
+
//#endregion
|
|
26092
|
+
//#region src/lib/credentials-pass-type-certificate.ts
|
|
26093
|
+
/**
|
|
26094
|
+
* Manual upload of a Wallet Pass Type ID `.p12` certificate. The Pass Type ID
|
|
26095
|
+
* (`pass.*`) is passed explicitly; serial/validity come from the parsed cert and
|
|
26096
|
+
* the team from its OU (or `--apple-team-identifier`). Only
|
|
26097
|
+
* `{ p12Base64, p12Password }` is sealed.
|
|
26098
|
+
*/
|
|
26099
|
+
const uploadIosPassTypeCertificate = (api, input, bytes) => Effect.gen(function* () {
|
|
26100
|
+
if (input.password === void 0) return yield* new CredentialValidationError({ message: "Missing --password required for the selected credential type." });
|
|
26101
|
+
if (!input.passTypeIdentifier) return yield* new CredentialValidationError({ message: "Missing --pass-type-identifier required for a Pass Type ID certificate." });
|
|
26102
|
+
const info = yield* inspectP12({
|
|
26103
|
+
data: Buffer.from(bytes),
|
|
26104
|
+
password: input.password
|
|
26105
|
+
});
|
|
26106
|
+
const appleTeamIdentifier = info.teamId ?? input.appleTeamIdentifier;
|
|
26107
|
+
if (!appleTeamIdentifier) return yield* new CredentialValidationError({ message: "Could not derive Apple Team ID from the certificate; pass --apple-team-identifier." });
|
|
26108
|
+
if (!info.validFrom || !info.expiresAt) return yield* new CredentialValidationError({ message: "Certificate is missing notBefore/notAfter dates." });
|
|
26109
|
+
const metadata = {
|
|
26110
|
+
passTypeIdentifier: input.passTypeIdentifier,
|
|
26111
|
+
serialNumber: info.serialNumber,
|
|
26112
|
+
appleTeamIdentifier,
|
|
26113
|
+
validFrom: info.validFrom.toISOString(),
|
|
26114
|
+
validUntil: info.expiresAt.toISOString()
|
|
26115
|
+
};
|
|
26116
|
+
const envelope = yield* sealForUpload({
|
|
26117
|
+
session: yield* openVaultSessionInteractive(api),
|
|
26118
|
+
credentialType: "pass-type-certificate",
|
|
26119
|
+
metadata,
|
|
26120
|
+
secret: {
|
|
26121
|
+
p12Base64: toBase64(bytes),
|
|
26122
|
+
p12Password: input.password
|
|
26123
|
+
}
|
|
26124
|
+
});
|
|
26125
|
+
return {
|
|
26126
|
+
id: (yield* api.applePassTypeCertificates.upload({ payload: {
|
|
26127
|
+
...toUploadEnvelope(envelope),
|
|
26128
|
+
...metadata
|
|
26129
|
+
} })).id,
|
|
26130
|
+
name: input.name,
|
|
26131
|
+
platform: "ios",
|
|
26132
|
+
type: "pass-type-certificate"
|
|
26133
|
+
};
|
|
26134
|
+
});
|
|
26135
|
+
|
|
26136
|
+
//#endregion
|
|
26137
|
+
//#region src/lib/credentials-pay-certificate.ts
|
|
26138
|
+
/**
|
|
26139
|
+
* Manual upload of an Apple Pay payment-processing `.p12` certificate. The
|
|
26140
|
+
* Merchant ID (`merchant.*`) is not carried reliably in the cert, so it is passed
|
|
26141
|
+
* explicitly; serial/validity come from the parsed cert and the team from its OU
|
|
26142
|
+
* (or `--apple-team-identifier`). Only `{ p12Base64, p12Password }` is sealed.
|
|
26143
|
+
*/
|
|
26144
|
+
const uploadIosPayCertificate = (api, input, bytes) => Effect.gen(function* () {
|
|
26145
|
+
if (input.password === void 0) return yield* new CredentialValidationError({ message: "Missing --password required for the selected credential type." });
|
|
26146
|
+
if (!input.merchantIdentifier) return yield* new CredentialValidationError({ message: "Missing --merchant-identifier required for an Apple Pay certificate." });
|
|
26147
|
+
const info = yield* inspectP12({
|
|
26148
|
+
data: Buffer.from(bytes),
|
|
26149
|
+
password: input.password
|
|
26150
|
+
});
|
|
26151
|
+
const appleTeamIdentifier = info.teamId ?? input.appleTeamIdentifier;
|
|
26152
|
+
if (!appleTeamIdentifier) return yield* new CredentialValidationError({ message: "Could not derive Apple Team ID from the certificate; pass --apple-team-identifier." });
|
|
26153
|
+
if (!info.validFrom || !info.expiresAt) return yield* new CredentialValidationError({ message: "Certificate is missing notBefore/notAfter dates." });
|
|
26154
|
+
const metadata = {
|
|
26155
|
+
merchantIdentifier: input.merchantIdentifier,
|
|
26156
|
+
serialNumber: info.serialNumber,
|
|
26157
|
+
appleTeamIdentifier,
|
|
26158
|
+
validFrom: info.validFrom.toISOString(),
|
|
26159
|
+
validUntil: info.expiresAt.toISOString()
|
|
26160
|
+
};
|
|
26161
|
+
const envelope = yield* sealForUpload({
|
|
26162
|
+
session: yield* openVaultSessionInteractive(api),
|
|
26163
|
+
credentialType: "apple-pay-certificate",
|
|
26164
|
+
metadata,
|
|
26165
|
+
secret: {
|
|
26166
|
+
p12Base64: toBase64(bytes),
|
|
26167
|
+
p12Password: input.password
|
|
26168
|
+
}
|
|
26169
|
+
});
|
|
26170
|
+
return {
|
|
26171
|
+
id: (yield* api.applePayCertificates.upload({ payload: {
|
|
26172
|
+
...toUploadEnvelope(envelope),
|
|
26173
|
+
...metadata
|
|
26174
|
+
} })).id,
|
|
26175
|
+
name: input.name,
|
|
26176
|
+
platform: "ios",
|
|
26177
|
+
type: "apple-pay-certificate"
|
|
26178
|
+
};
|
|
26179
|
+
});
|
|
26180
|
+
|
|
26181
|
+
//#endregion
|
|
26182
|
+
//#region src/lib/credentials-push-certificate.ts
|
|
26183
|
+
/**
|
|
26184
|
+
* Derive the App ID a push SSL cert is bound to from its Common Name, e.g.
|
|
26185
|
+
* "Apple Push Services: com.example.app" → "com.example.app". Returns undefined
|
|
26186
|
+
* when the CN does not carry a reverse-DNS identifier.
|
|
26187
|
+
*/
|
|
26188
|
+
const bundleIdFromPushCertCN = (commonName) => {
|
|
26189
|
+
const bundle = /:\s*(?<bundle>[A-Za-z0-9](?:[A-Za-z0-9.-]*[A-Za-z0-9])?)\s*$/u.exec(commonName)?.groups?.["bundle"];
|
|
26190
|
+
return bundle?.includes(".") ? bundle : void 0;
|
|
26191
|
+
};
|
|
26192
|
+
/**
|
|
26193
|
+
* Manual upload of a legacy APNs Push Services `.p12` SSL certificate. The CLI
|
|
26194
|
+
* parses the cert locally for its metadata (serial, validity, team, and the App
|
|
26195
|
+
* ID from the CN) and seals `{ p12Base64, p12Password }` into the vault; the
|
|
26196
|
+
* server only ever stores the ciphertext.
|
|
26197
|
+
*/
|
|
26198
|
+
const uploadIosPushCertificate = (api, input, bytes) => Effect.gen(function* () {
|
|
26199
|
+
if (input.password === void 0) return yield* new CredentialValidationError({ message: "Missing --password required for the selected credential type." });
|
|
26200
|
+
const info = yield* inspectP12({
|
|
26201
|
+
data: Buffer.from(bytes),
|
|
26202
|
+
password: input.password
|
|
26203
|
+
});
|
|
26204
|
+
if (!info.teamId) return yield* new CredentialValidationError({ message: "Could not derive Apple Team ID from certificate subject (expected OU=TEAMID or CN with (TEAMID))." });
|
|
26205
|
+
if (!info.validFrom || !info.expiresAt) return yield* new CredentialValidationError({ message: "Certificate is missing notBefore/notAfter dates." });
|
|
26206
|
+
const bundleIdentifier = input.bundleIdentifier ?? bundleIdFromPushCertCN(info.signingIdentity);
|
|
26207
|
+
if (!bundleIdentifier) return yield* new CredentialValidationError({ message: "Could not derive the App ID from the push certificate (expected CN 'Apple Push Services: <bundle id>'). Pass --bundle-identifier." });
|
|
26208
|
+
const metadata = {
|
|
26209
|
+
bundleIdentifier,
|
|
26210
|
+
serialNumber: info.serialNumber,
|
|
26211
|
+
appleTeamIdentifier: info.teamId,
|
|
26212
|
+
validFrom: info.validFrom.toISOString(),
|
|
26213
|
+
validUntil: info.expiresAt.toISOString()
|
|
26214
|
+
};
|
|
26215
|
+
const envelope = yield* sealForUpload({
|
|
26216
|
+
session: yield* openVaultSessionInteractive(api),
|
|
26217
|
+
credentialType: "push-certificate",
|
|
26218
|
+
metadata,
|
|
26219
|
+
secret: {
|
|
26220
|
+
p12Base64: toBase64(bytes),
|
|
26221
|
+
p12Password: input.password
|
|
26222
|
+
}
|
|
26223
|
+
});
|
|
26224
|
+
return {
|
|
26225
|
+
id: (yield* api.applePushCertificates.upload({ payload: {
|
|
26226
|
+
...toUploadEnvelope(envelope),
|
|
26227
|
+
...metadata
|
|
26228
|
+
} })).id,
|
|
26229
|
+
name: input.name,
|
|
26230
|
+
platform: "ios",
|
|
26231
|
+
type: "push-certificate"
|
|
26232
|
+
};
|
|
26233
|
+
});
|
|
26234
|
+
|
|
25861
26235
|
//#endregion
|
|
25862
26236
|
//#region src/lib/credentials-manager.ts
|
|
25863
26237
|
const formatDistribution = (value) => value.toLowerCase().replaceAll("_", "-");
|
|
25864
26238
|
const listAllCredentials = (api) => Effect.gen(function* () {
|
|
25865
|
-
const [certs, pushKeys, ascKeys, profiles, keystores, googleKeys] = yield* Effect.all([
|
|
26239
|
+
const [certs, pushKeys, pushCerts, payCerts, passCerts, ascKeys, profiles, keystores, googleKeys] = yield* Effect.all([
|
|
25866
26240
|
api.appleDistributionCertificates.list(),
|
|
25867
26241
|
api.applePushKeys.list(),
|
|
26242
|
+
api.applePushCertificates.list(),
|
|
26243
|
+
api.applePayCertificates.list(),
|
|
26244
|
+
api.applePassTypeCertificates.list(),
|
|
25868
26245
|
api.ascApiKeys.list(),
|
|
25869
26246
|
api.appleProvisioningProfiles.list({ urlParams: {} }),
|
|
25870
26247
|
api.androidUploadKeystores.list(),
|
|
@@ -25885,6 +26262,27 @@ const listAllCredentials = (api) => Effect.gen(function* () {
|
|
|
25885
26262
|
type: "push-key",
|
|
25886
26263
|
distribution: null
|
|
25887
26264
|
})),
|
|
26265
|
+
...pushCerts.items.map((cert) => ({
|
|
26266
|
+
id: cert.id,
|
|
26267
|
+
name: cert.bundleIdentifier,
|
|
26268
|
+
platform: "ios",
|
|
26269
|
+
type: "push-certificate",
|
|
26270
|
+
distribution: null
|
|
26271
|
+
})),
|
|
26272
|
+
...payCerts.items.map((cert) => ({
|
|
26273
|
+
id: cert.id,
|
|
26274
|
+
name: cert.merchantIdentifier,
|
|
26275
|
+
platform: "ios",
|
|
26276
|
+
type: "apple-pay-certificate",
|
|
26277
|
+
distribution: null
|
|
26278
|
+
})),
|
|
26279
|
+
...passCerts.items.map((cert) => ({
|
|
26280
|
+
id: cert.id,
|
|
26281
|
+
name: cert.passTypeIdentifier,
|
|
26282
|
+
platform: "ios",
|
|
26283
|
+
type: "pass-type-certificate",
|
|
26284
|
+
distribution: null
|
|
26285
|
+
})),
|
|
25888
26286
|
...ascKeys.items.map((key) => ({
|
|
25889
26287
|
id: key.id,
|
|
25890
26288
|
name: key.name,
|
|
@@ -26082,6 +26480,9 @@ const uploadAndroidGoogleServiceAccountKey = (api, input, bytes) => Effect.gen(f
|
|
|
26082
26480
|
const uploadHandlers = {
|
|
26083
26481
|
"ios:distribution-certificate": uploadIosDistributionCertificate,
|
|
26084
26482
|
"ios:push-key": uploadIosPushKey,
|
|
26483
|
+
"ios:push-certificate": uploadIosPushCertificate,
|
|
26484
|
+
"ios:apple-pay-certificate": uploadIosPayCertificate,
|
|
26485
|
+
"ios:pass-type-certificate": uploadIosPassTypeCertificate,
|
|
26085
26486
|
"ios:asc-api-key": uploadIosAscApiKey,
|
|
26086
26487
|
"ios:provisioning-profile": uploadIosProvisioningProfile,
|
|
26087
26488
|
"android:keystore": uploadAndroidKeystore,
|
|
@@ -26107,6 +26508,15 @@ const deleteCredential = (api, input) => {
|
|
|
26107
26508
|
platform: "ios",
|
|
26108
26509
|
type: "push-key"
|
|
26109
26510
|
}, () => api.applePushKeys.delete({ path })), Match.when({
|
|
26511
|
+
platform: "ios",
|
|
26512
|
+
type: "push-certificate"
|
|
26513
|
+
}, () => api.applePushCertificates.delete({ path })), Match.when({
|
|
26514
|
+
platform: "ios",
|
|
26515
|
+
type: "apple-pay-certificate"
|
|
26516
|
+
}, () => api.applePayCertificates.delete({ path })), Match.when({
|
|
26517
|
+
platform: "ios",
|
|
26518
|
+
type: "pass-type-certificate"
|
|
26519
|
+
}, () => api.applePassTypeCertificates.delete({ path })), Match.when({
|
|
26110
26520
|
platform: "ios",
|
|
26111
26521
|
type: "asc-api-key"
|
|
26112
26522
|
}, () => api.ascApiKeys.delete({ path })), Match.when({
|
|
@@ -26187,6 +26597,9 @@ const TYPE_LABELS = {
|
|
|
26187
26597
|
"distribution-certificate": "iOS distribution certificate",
|
|
26188
26598
|
"provisioning-profile": "iOS provisioning profile",
|
|
26189
26599
|
"push-key": "APNs push key",
|
|
26600
|
+
"push-certificate": "APNs push SSL certificate",
|
|
26601
|
+
"apple-pay-certificate": "Apple Pay certificate",
|
|
26602
|
+
"pass-type-certificate": "Pass Type ID certificate",
|
|
26190
26603
|
"asc-api-key": "ASC API key",
|
|
26191
26604
|
keystore: "Android keystore",
|
|
26192
26605
|
"google-service-account-key": "Google service account key"
|
|
@@ -27674,6 +28087,9 @@ const CREDENTIAL_TYPES$3 = [
|
|
|
27674
28087
|
"distribution-certificate",
|
|
27675
28088
|
"provisioning-profile",
|
|
27676
28089
|
"push-key",
|
|
28090
|
+
"push-certificate",
|
|
28091
|
+
"apple-pay-certificate",
|
|
28092
|
+
"pass-type-certificate",
|
|
27677
28093
|
"asc-api-key",
|
|
27678
28094
|
"keystore",
|
|
27679
28095
|
"google-service-account-key"
|
|
@@ -27790,6 +28206,9 @@ const DOWNLOAD_TYPES = [
|
|
|
27790
28206
|
"distribution-certificate",
|
|
27791
28207
|
"provisioning-profile",
|
|
27792
28208
|
"push-key",
|
|
28209
|
+
"push-certificate",
|
|
28210
|
+
"apple-pay-certificate",
|
|
28211
|
+
"pass-type-certificate",
|
|
27793
28212
|
"asc-api-key",
|
|
27794
28213
|
"keystore",
|
|
27795
28214
|
"google-service-account-key"
|
|
@@ -27881,6 +28300,105 @@ const downloadPushKey = ({ api, id, cwd, output }) => Effect.gen(function* () {
|
|
|
27881
28300
|
}
|
|
27882
28301
|
};
|
|
27883
28302
|
});
|
|
28303
|
+
const downloadPushCertificate = ({ api, id, cwd, output }) => Effect.gen(function* () {
|
|
28304
|
+
const data = yield* api.applePushCertificates.download({ path: { id } });
|
|
28305
|
+
const secret = yield* openFromDownload({
|
|
28306
|
+
session: yield* openVaultSessionInteractive(api),
|
|
28307
|
+
credentialType: "push-certificate",
|
|
28308
|
+
downloaded: data
|
|
28309
|
+
});
|
|
28310
|
+
const p12Base64 = yield* secretString(secret, "p12Base64");
|
|
28311
|
+
const p12Password = yield* secretString(secret, "p12Password");
|
|
28312
|
+
const filePath = resolveOutputPath(cwd, output, `${data.id}.p12`);
|
|
28313
|
+
yield* writeBinary(filePath, fromBase64(p12Base64));
|
|
28314
|
+
return {
|
|
28315
|
+
path: filePath,
|
|
28316
|
+
pairs: [
|
|
28317
|
+
["Path", filePath],
|
|
28318
|
+
["Type", "Apple push SSL certificate (.p12)"],
|
|
28319
|
+
["Bundle", data.bundleIdentifier],
|
|
28320
|
+
["Serial", data.serialNumber],
|
|
28321
|
+
["Apple team", data.appleTeamIdentifier],
|
|
28322
|
+
["Valid from", data.validFrom],
|
|
28323
|
+
["Valid until", data.validUntil],
|
|
28324
|
+
["P12 password", p12Password]
|
|
28325
|
+
],
|
|
28326
|
+
metadata: {
|
|
28327
|
+
bundleIdentifier: data.bundleIdentifier,
|
|
28328
|
+
serialNumber: data.serialNumber,
|
|
28329
|
+
appleTeamIdentifier: data.appleTeamIdentifier,
|
|
28330
|
+
validFrom: data.validFrom,
|
|
28331
|
+
validUntil: data.validUntil,
|
|
28332
|
+
p12Password
|
|
28333
|
+
}
|
|
28334
|
+
};
|
|
28335
|
+
});
|
|
28336
|
+
const downloadPayCertificate = ({ api, id, cwd, output }) => Effect.gen(function* () {
|
|
28337
|
+
const data = yield* api.applePayCertificates.download({ path: { id } });
|
|
28338
|
+
const secret = yield* openFromDownload({
|
|
28339
|
+
session: yield* openVaultSessionInteractive(api),
|
|
28340
|
+
credentialType: "apple-pay-certificate",
|
|
28341
|
+
downloaded: data
|
|
28342
|
+
});
|
|
28343
|
+
const p12Base64 = yield* secretString(secret, "p12Base64");
|
|
28344
|
+
const p12Password = yield* secretString(secret, "p12Password");
|
|
28345
|
+
const filePath = resolveOutputPath(cwd, output, `${data.id}.p12`);
|
|
28346
|
+
yield* writeBinary(filePath, fromBase64(p12Base64));
|
|
28347
|
+
return {
|
|
28348
|
+
path: filePath,
|
|
28349
|
+
pairs: [
|
|
28350
|
+
["Path", filePath],
|
|
28351
|
+
["Type", "Apple Pay payment processing certificate (.p12)"],
|
|
28352
|
+
["Merchant", data.merchantIdentifier],
|
|
28353
|
+
["Serial", data.serialNumber],
|
|
28354
|
+
["Apple team", data.appleTeamIdentifier],
|
|
28355
|
+
["Valid from", data.validFrom],
|
|
28356
|
+
["Valid until", data.validUntil],
|
|
28357
|
+
["P12 password", p12Password]
|
|
28358
|
+
],
|
|
28359
|
+
metadata: {
|
|
28360
|
+
merchantIdentifier: data.merchantIdentifier,
|
|
28361
|
+
serialNumber: data.serialNumber,
|
|
28362
|
+
appleTeamIdentifier: data.appleTeamIdentifier,
|
|
28363
|
+
validFrom: data.validFrom,
|
|
28364
|
+
validUntil: data.validUntil,
|
|
28365
|
+
p12Password
|
|
28366
|
+
}
|
|
28367
|
+
};
|
|
28368
|
+
});
|
|
28369
|
+
const downloadPassTypeCertificate = ({ api, id, cwd, output }) => Effect.gen(function* () {
|
|
28370
|
+
const data = yield* api.applePassTypeCertificates.download({ path: { id } });
|
|
28371
|
+
const secret = yield* openFromDownload({
|
|
28372
|
+
session: yield* openVaultSessionInteractive(api),
|
|
28373
|
+
credentialType: "pass-type-certificate",
|
|
28374
|
+
downloaded: data
|
|
28375
|
+
});
|
|
28376
|
+
const p12Base64 = yield* secretString(secret, "p12Base64");
|
|
28377
|
+
const p12Password = yield* secretString(secret, "p12Password");
|
|
28378
|
+
const filePath = resolveOutputPath(cwd, output, `${data.id}.p12`);
|
|
28379
|
+
yield* writeBinary(filePath, fromBase64(p12Base64));
|
|
28380
|
+
return {
|
|
28381
|
+
path: filePath,
|
|
28382
|
+
pairs: [
|
|
28383
|
+
["Path", filePath],
|
|
28384
|
+
["Type", "Wallet Pass Type ID certificate (.p12)"],
|
|
28385
|
+
["Pass Type ID", data.passTypeIdentifier],
|
|
28386
|
+
["Serial", data.serialNumber],
|
|
28387
|
+
["Apple team", data.appleTeamIdentifier],
|
|
28388
|
+
["Valid from", data.validFrom],
|
|
28389
|
+
["Valid until", data.validUntil],
|
|
28390
|
+
["P12 password", p12Password]
|
|
28391
|
+
],
|
|
28392
|
+
metadata: {
|
|
28393
|
+
passTypeIdentifier: data.passTypeIdentifier,
|
|
28394
|
+
serialNumber: data.serialNumber,
|
|
28395
|
+
appleTeamIdentifier: data.appleTeamIdentifier,
|
|
28396
|
+
validFrom: data.validFrom,
|
|
28397
|
+
validUntil: data.validUntil,
|
|
28398
|
+
p12Password
|
|
28399
|
+
}
|
|
28400
|
+
};
|
|
28401
|
+
});
|
|
27884
28402
|
const downloadAscApiKey$1 = ({ api, id, cwd, output }) => Effect.gen(function* () {
|
|
27885
28403
|
const data = yield* api.ascApiKeys.getCredentials({ path: { id } });
|
|
27886
28404
|
const p8Pem = yield* secretString(yield* openFromDownload({
|
|
@@ -27965,6 +28483,9 @@ const dispatchDownload = (ctx, type) => {
|
|
|
27965
28483
|
case "distribution-certificate": return downloadDistributionCertificate(ctx);
|
|
27966
28484
|
case "provisioning-profile": return downloadProvisioningProfile$1(ctx);
|
|
27967
28485
|
case "push-key": return downloadPushKey(ctx);
|
|
28486
|
+
case "push-certificate": return downloadPushCertificate(ctx);
|
|
28487
|
+
case "apple-pay-certificate": return downloadPayCertificate(ctx);
|
|
28488
|
+
case "pass-type-certificate": return downloadPassTypeCertificate(ctx);
|
|
27968
28489
|
case "asc-api-key": return downloadAscApiKey$1(ctx);
|
|
27969
28490
|
case "keystore": return downloadKeystore(ctx);
|
|
27970
28491
|
case "google-service-account-key": return downloadGoogleServiceAccountKey(ctx);
|
|
@@ -28010,6 +28531,99 @@ const downloadCommand = defineCommand({
|
|
|
28010
28531
|
}), { json: "value" })
|
|
28011
28532
|
});
|
|
28012
28533
|
|
|
28534
|
+
//#endregion
|
|
28535
|
+
//#region src/lib/credentials-generator-merchant.ts
|
|
28536
|
+
/**
|
|
28537
|
+
* Enable the Apple Pay capability on an App ID, registering the App ID first if
|
|
28538
|
+
* it does not exist yet. Returns once the capability is on.
|
|
28539
|
+
*/
|
|
28540
|
+
const enableApplePayCapability = (ctx, bundleIdentifier) => Effect.gen(function* () {
|
|
28541
|
+
const bundle = (yield* wrap("apple-find-bundle-id", async () => AppleUtils.BundleId.findAsync(ctx, { identifier: bundleIdentifier }))) ?? (yield* wrap("apple-create-bundle-id", async () => AppleUtils.BundleId.createAsync(ctx, {
|
|
28542
|
+
identifier: bundleIdentifier,
|
|
28543
|
+
name: bundleIdentifier,
|
|
28544
|
+
platform: AppleUtils.BundleIdPlatform.IOS
|
|
28545
|
+
})));
|
|
28546
|
+
yield* wrap("apple-enable-apple-pay", async () => bundle.updateBundleIdCapabilityAsync({
|
|
28547
|
+
capabilityType: AppleUtils.CapabilityType.APPLE_PAY,
|
|
28548
|
+
option: AppleUtils.CapabilityTypeOption.ON
|
|
28549
|
+
}));
|
|
28550
|
+
});
|
|
28551
|
+
/**
|
|
28552
|
+
* Register an Apple Pay Merchant ID (`merchant.*`) on the Developer Portal via an
|
|
28553
|
+
* Apple ID session, optionally enabling the Apple Pay capability on an App ID.
|
|
28554
|
+
* This is the one piece of Apple Pay onboarding the portal API supports — the
|
|
28555
|
+
* payment-processing certificate itself is still created out-of-band (usually by
|
|
28556
|
+
* the PSP) and uploaded via `credentials upload --type apple-pay-certificate`.
|
|
28557
|
+
*/
|
|
28558
|
+
const registerMerchantIdViaAppleId = (input) => Effect.gen(function* () {
|
|
28559
|
+
const merchant = yield* wrap("apple-create-merchant-id", async () => AppleUtils.MerchantId.createAsync(input.context, {
|
|
28560
|
+
identifier: input.identifier,
|
|
28561
|
+
name: input.name
|
|
28562
|
+
}));
|
|
28563
|
+
if (input.bundleIdentifier !== void 0 && input.bundleIdentifier.length > 0) yield* enableApplePayCapability(input.context, input.bundleIdentifier);
|
|
28564
|
+
return {
|
|
28565
|
+
developerPortalIdentifier: merchant.id,
|
|
28566
|
+
identifier: input.identifier,
|
|
28567
|
+
name: input.name,
|
|
28568
|
+
capabilityEnabledForBundleId: input.bundleIdentifier
|
|
28569
|
+
};
|
|
28570
|
+
});
|
|
28571
|
+
|
|
28572
|
+
//#endregion
|
|
28573
|
+
//#region src/commands/credentials/generate-merchant-id.ts
|
|
28574
|
+
const MERCHANT_ID_PATTERN = /^merchant\.[A-Za-z0-9][A-Za-z0-9.-]*$/u;
|
|
28575
|
+
const MERCHANT_EXIT_EXTRAS = {
|
|
28576
|
+
CredentialValidationError: 2,
|
|
28577
|
+
AppleIdGenerateFailedError: 6,
|
|
28578
|
+
AppleAuthError: 4,
|
|
28579
|
+
InteractiveProhibitedError: 4
|
|
28580
|
+
};
|
|
28581
|
+
const merchantIdCommand = defineCommand({
|
|
28582
|
+
meta: {
|
|
28583
|
+
name: "merchant-id",
|
|
28584
|
+
description: "Register an Apple Pay Merchant ID (merchant.*) on the Developer Portal via Apple ID login, optionally turning on Apple Pay for an App ID. The payment-processing certificate itself is uploaded separately with `credentials upload --type apple-pay-certificate`."
|
|
28585
|
+
},
|
|
28586
|
+
args: {
|
|
28587
|
+
identifier: {
|
|
28588
|
+
type: "string",
|
|
28589
|
+
required: true,
|
|
28590
|
+
description: "Merchant ID (merchant.*)"
|
|
28591
|
+
},
|
|
28592
|
+
name: {
|
|
28593
|
+
type: "string",
|
|
28594
|
+
description: "Display name (defaults to the identifier)"
|
|
28595
|
+
},
|
|
28596
|
+
"bundle-identifier": {
|
|
28597
|
+
type: "string",
|
|
28598
|
+
description: "App ID to enable the Apple Pay capability on"
|
|
28599
|
+
}
|
|
28600
|
+
},
|
|
28601
|
+
run: async ({ args }) => runEffect(Effect.gen(function* () {
|
|
28602
|
+
const identifier = args.identifier.trim();
|
|
28603
|
+
if (!MERCHANT_ID_PATTERN.test(identifier)) return yield* new CredentialValidationError({ message: `Merchant ID "${identifier}" must look like merchant.com.example.` });
|
|
28604
|
+
const auth = yield* AppleAuth;
|
|
28605
|
+
const session = yield* auth.ensureLoggedIn();
|
|
28606
|
+
yield* printHuman("Registering Apple Pay Merchant ID via your Apple ID...");
|
|
28607
|
+
const created = yield* registerMerchantIdViaAppleId({
|
|
28608
|
+
context: auth.buildRequestContext(session),
|
|
28609
|
+
identifier,
|
|
28610
|
+
name: args.name ?? identifier,
|
|
28611
|
+
...compact({ bundleIdentifier: args["bundle-identifier"] })
|
|
28612
|
+
});
|
|
28613
|
+
yield* printHuman("Merchant ID registered.");
|
|
28614
|
+
yield* printHumanKeyValue([
|
|
28615
|
+
["Merchant ID", created.identifier],
|
|
28616
|
+
["Name", created.name],
|
|
28617
|
+
["Apple identifier", created.developerPortalIdentifier],
|
|
28618
|
+
["Apple Pay enabled on", created.capabilityEnabledForBundleId ?? "-"]
|
|
28619
|
+
]);
|
|
28620
|
+
return created;
|
|
28621
|
+
}), {
|
|
28622
|
+
exits: MERCHANT_EXIT_EXTRAS,
|
|
28623
|
+
json: "value"
|
|
28624
|
+
})
|
|
28625
|
+
});
|
|
28626
|
+
|
|
28013
28627
|
//#endregion
|
|
28014
28628
|
//#region src/commands/credentials/generate-push-key.ts
|
|
28015
28629
|
const PUSH_KEY_EXIT_EXTRAS = {
|
|
@@ -28408,6 +29022,7 @@ const generateCommand$1 = defineCommand({
|
|
|
28408
29022
|
"distribution-certificate": distributionCertificateCommand$1,
|
|
28409
29023
|
"provisioning-profile": provisioningProfileCommand,
|
|
28410
29024
|
"push-key": pushKeyCommand$1,
|
|
29025
|
+
"merchant-id": merchantIdCommand,
|
|
28411
29026
|
"gsa-key": gsaKeyCommand
|
|
28412
29027
|
}
|
|
28413
29028
|
});
|
|
@@ -28708,6 +29323,9 @@ const CREDENTIAL_TYPES$2 = [
|
|
|
28708
29323
|
"distribution-certificate",
|
|
28709
29324
|
"provisioning-profile",
|
|
28710
29325
|
"push-key",
|
|
29326
|
+
"push-certificate",
|
|
29327
|
+
"apple-pay-certificate",
|
|
29328
|
+
"pass-type-certificate",
|
|
28711
29329
|
"asc-api-key",
|
|
28712
29330
|
"keystore",
|
|
28713
29331
|
"google-service-account-key"
|
|
@@ -29572,6 +30190,9 @@ const CREDENTIAL_TYPES$1 = [
|
|
|
29572
30190
|
"distribution-certificate",
|
|
29573
30191
|
"provisioning-profile",
|
|
29574
30192
|
"push-key",
|
|
30193
|
+
"push-certificate",
|
|
30194
|
+
"apple-pay-certificate",
|
|
30195
|
+
"pass-type-certificate",
|
|
29575
30196
|
"asc-api-key",
|
|
29576
30197
|
"keystore",
|
|
29577
30198
|
"google-service-account-key"
|
|
@@ -29625,6 +30246,18 @@ const uploadCommand = defineCommand({
|
|
|
29625
30246
|
"apple-team-identifier": {
|
|
29626
30247
|
type: "string",
|
|
29627
30248
|
description: "Apple Team ID"
|
|
30249
|
+
},
|
|
30250
|
+
"bundle-identifier": {
|
|
30251
|
+
type: "string",
|
|
30252
|
+
description: "App ID for a push certificate (else derived from the cert CN)"
|
|
30253
|
+
},
|
|
30254
|
+
"merchant-identifier": {
|
|
30255
|
+
type: "string",
|
|
30256
|
+
description: "Merchant ID (merchant.*) for an Apple Pay certificate"
|
|
30257
|
+
},
|
|
30258
|
+
"pass-type-identifier": {
|
|
30259
|
+
type: "string",
|
|
30260
|
+
description: "Pass Type ID (pass.*) for a Pass Type ID certificate"
|
|
29628
30261
|
}
|
|
29629
30262
|
},
|
|
29630
30263
|
run: async ({ args }) => runEffect(Effect.gen(function* () {
|
|
@@ -29639,7 +30272,10 @@ const uploadCommand = defineCommand({
|
|
|
29639
30272
|
keyPassword: args["key-password"],
|
|
29640
30273
|
keyId: args["key-id"],
|
|
29641
30274
|
issuerId: args["issuer-id"],
|
|
29642
|
-
appleTeamIdentifier: args["apple-team-identifier"]
|
|
30275
|
+
appleTeamIdentifier: args["apple-team-identifier"],
|
|
30276
|
+
bundleIdentifier: args["bundle-identifier"],
|
|
30277
|
+
merchantIdentifier: args["merchant-identifier"],
|
|
30278
|
+
passTypeIdentifier: args["pass-type-identifier"]
|
|
29643
30279
|
})
|
|
29644
30280
|
});
|
|
29645
30281
|
yield* printHuman("Credential uploaded successfully.");
|
|
@@ -29713,6 +30349,9 @@ const CREDENTIAL_TYPES = [
|
|
|
29713
30349
|
"distribution-certificate",
|
|
29714
30350
|
"provisioning-profile",
|
|
29715
30351
|
"push-key",
|
|
30352
|
+
"push-certificate",
|
|
30353
|
+
"apple-pay-certificate",
|
|
30354
|
+
"pass-type-certificate",
|
|
29716
30355
|
"asc-api-key",
|
|
29717
30356
|
"keystore",
|
|
29718
30357
|
"google-service-account-key"
|
|
@@ -29777,6 +30416,66 @@ const viewPushKey = (api, id) => Effect.gen(function* () {
|
|
|
29777
30416
|
raw: item
|
|
29778
30417
|
};
|
|
29779
30418
|
});
|
|
30419
|
+
const viewPushCertificate = (api, id) => Effect.gen(function* () {
|
|
30420
|
+
const { items } = yield* api.applePushCertificates.list();
|
|
30421
|
+
const item = items.find((entry) => entry.id === id);
|
|
30422
|
+
if (!item) return yield* notFound(id, "push-certificate");
|
|
30423
|
+
return {
|
|
30424
|
+
kind: "push-certificate",
|
|
30425
|
+
pairs: [
|
|
30426
|
+
["ID", item.id],
|
|
30427
|
+
["Type", "Apple push SSL certificate"],
|
|
30428
|
+
["Bundle identifier", item.bundleIdentifier],
|
|
30429
|
+
["Serial number", item.serialNumber],
|
|
30430
|
+
["Apple team ID", item.appleTeamId],
|
|
30431
|
+
["Valid from", item.validFrom],
|
|
30432
|
+
["Valid until", item.validUntil],
|
|
30433
|
+
["Created", item.createdAt],
|
|
30434
|
+
["Updated", item.updatedAt]
|
|
30435
|
+
],
|
|
30436
|
+
raw: item
|
|
30437
|
+
};
|
|
30438
|
+
});
|
|
30439
|
+
const viewPayCertificate = (api, id) => Effect.gen(function* () {
|
|
30440
|
+
const { items } = yield* api.applePayCertificates.list();
|
|
30441
|
+
const item = items.find((entry) => entry.id === id);
|
|
30442
|
+
if (!item) return yield* notFound(id, "apple-pay-certificate");
|
|
30443
|
+
return {
|
|
30444
|
+
kind: "apple-pay-certificate",
|
|
30445
|
+
pairs: [
|
|
30446
|
+
["ID", item.id],
|
|
30447
|
+
["Type", "Apple Pay payment processing certificate"],
|
|
30448
|
+
["Merchant identifier", item.merchantIdentifier],
|
|
30449
|
+
["Serial number", item.serialNumber],
|
|
30450
|
+
["Apple team ID", item.appleTeamId],
|
|
30451
|
+
["Valid from", item.validFrom],
|
|
30452
|
+
["Valid until", item.validUntil],
|
|
30453
|
+
["Created", item.createdAt],
|
|
30454
|
+
["Updated", item.updatedAt]
|
|
30455
|
+
],
|
|
30456
|
+
raw: item
|
|
30457
|
+
};
|
|
30458
|
+
});
|
|
30459
|
+
const viewPassTypeCertificate = (api, id) => Effect.gen(function* () {
|
|
30460
|
+
const { items } = yield* api.applePassTypeCertificates.list();
|
|
30461
|
+
const item = items.find((entry) => entry.id === id);
|
|
30462
|
+
if (!item) return yield* notFound(id, "pass-type-certificate");
|
|
30463
|
+
return {
|
|
30464
|
+
kind: "pass-type-certificate",
|
|
30465
|
+
pairs: [
|
|
30466
|
+
["ID", item.id],
|
|
30467
|
+
["Type", "Wallet Pass Type ID certificate"],
|
|
30468
|
+
["Pass Type ID", item.passTypeIdentifier],
|
|
30469
|
+
["Serial number", item.serialNumber],
|
|
30470
|
+
["Apple team ID", item.appleTeamId],
|
|
30471
|
+
["Valid from", item.validFrom],
|
|
30472
|
+
["Valid until", item.validUntil],
|
|
30473
|
+
["Created", item.createdAt],
|
|
30474
|
+
["Updated", item.updatedAt]
|
|
30475
|
+
],
|
|
30476
|
+
raw: item
|
|
30477
|
+
};
|
|
30478
|
+
});
|
|
29780
30479
|
const viewAscApiKey = (api, id) => Effect.gen(function* () {
|
|
29781
30480
|
const { items } = yield* api.ascApiKeys.list();
|
|
29782
30481
|
const item = items.find((entry) => entry.id === id);
|
|
@@ -29835,6 +30534,9 @@ const lookupByType = (api, id, type) => {
|
|
|
29835
30534
|
case "distribution-certificate": return viewDistributionCertificate(api, id);
|
|
29836
30535
|
case "provisioning-profile": return viewProvisioningProfile(api, id);
|
|
29837
30536
|
case "push-key": return viewPushKey(api, id);
|
|
30537
|
+
case "push-certificate": return viewPushCertificate(api, id);
|
|
30538
|
+
case "apple-pay-certificate": return viewPayCertificate(api, id);
|
|
30539
|
+
case "pass-type-certificate": return viewPassTypeCertificate(api, id);
|
|
29838
30540
|
case "asc-api-key": return viewAscApiKey(api, id);
|
|
29839
30541
|
case "keystore": return viewKeystore(api, id);
|
|
29840
30542
|
case "google-service-account-key": return viewGoogleServiceAccountKey(api, id);
|
|
@@ -32023,6 +32725,20 @@ const persistLink = (projectRoot, projectId, hasExpoConfig) => Effect.gen(functi
|
|
|
32023
32725
|
configPath: filePath
|
|
32024
32726
|
};
|
|
32025
32727
|
});
|
|
32728
|
+
/**
|
|
32729
|
+
* Scaffold the default `eas.json` build profiles after linking so a freshly
|
|
32730
|
+
* `init`ed project can `build` straight away. Only acts when no `build` section
|
|
32731
|
+
* exists yet — a project that already defines profiles is left untouched (run
|
|
32732
|
+
* `build configure` to top those up). Use `build configure` to re-scaffold.
|
|
32733
|
+
*/
|
|
32734
|
+
const scaffoldBuildProfiles = (projectRoot) => Effect.gen(function* () {
|
|
32735
|
+
const existing = yield* readEasJsonRaw(projectRoot);
|
|
32736
|
+
const existingBuild = isRecord$1(existing?.["build"]) ? existing["build"] : {};
|
|
32737
|
+
if (Object.keys(existingBuild).length > 0) return [];
|
|
32738
|
+
const result = yield* ensureDefaultBuildProfiles(projectRoot);
|
|
32739
|
+
yield* printHuman(`Scaffolded eas.json with default build profiles: ${result.added.join(", ")}.`);
|
|
32740
|
+
return result.added;
|
|
32741
|
+
});
|
|
32026
32742
|
const initCommand = defineCommand({
|
|
32027
32743
|
meta: {
|
|
32028
32744
|
name: "init",
|
|
@@ -32050,9 +32766,12 @@ const initCommand = defineCommand({
|
|
|
32050
32766
|
if (args.id !== void 0 && args.id.length > 0) {
|
|
32051
32767
|
const project = yield* api.projects.get({ path: { id: args.id } });
|
|
32052
32768
|
yield* printHuman(`Linking project: ${project.name} (${project.id})`);
|
|
32769
|
+
const linked = yield* persistLink(projectRoot, project.id, hasExpoConfig);
|
|
32770
|
+
const buildProfiles = yield* scaffoldBuildProfiles(projectRoot);
|
|
32053
32771
|
return {
|
|
32054
32772
|
linked: true,
|
|
32055
|
-
...
|
|
32773
|
+
...linked,
|
|
32774
|
+
buildProfiles
|
|
32056
32775
|
};
|
|
32057
32776
|
}
|
|
32058
32777
|
const { name, slug } = yield* resolveNameAndSlug(args, projectRoot, expoConfig);
|
|
@@ -32066,21 +32785,24 @@ const initCommand = defineCommand({
|
|
|
32066
32785
|
limit: 100
|
|
32067
32786
|
} });
|
|
32068
32787
|
const existing = items.find((project) => project.slug === slug);
|
|
32788
|
+
const linked = yield* persistLink(projectRoot, yield* Effect.gen(function* () {
|
|
32789
|
+
if (existing) {
|
|
32790
|
+
yield* printHuman(`Found existing project: ${existing.name} (${existing.id})`);
|
|
32791
|
+
return existing.id;
|
|
32792
|
+
}
|
|
32793
|
+
yield* printHuman("No existing project found. Creating new project...");
|
|
32794
|
+
const created = yield* api.projects.create({ payload: {
|
|
32795
|
+
name,
|
|
32796
|
+
slug
|
|
32797
|
+
} });
|
|
32798
|
+
yield* printHuman(`Created project: ${created.name} (${created.id})`);
|
|
32799
|
+
return created.id;
|
|
32800
|
+
}), hasExpoConfig);
|
|
32801
|
+
const buildProfiles = yield* scaffoldBuildProfiles(projectRoot);
|
|
32069
32802
|
return {
|
|
32070
32803
|
linked: true,
|
|
32071
|
-
...
|
|
32072
|
-
|
|
32073
|
-
yield* printHuman(`Found existing project: ${existing.name} (${existing.id})`);
|
|
32074
|
-
return existing.id;
|
|
32075
|
-
}
|
|
32076
|
-
yield* printHuman("No existing project found. Creating new project...");
|
|
32077
|
-
const created = yield* api.projects.create({ payload: {
|
|
32078
|
-
name,
|
|
32079
|
-
slug
|
|
32080
|
-
} });
|
|
32081
|
-
yield* printHuman(`Created project: ${created.name} (${created.id})`);
|
|
32082
|
-
return created.id;
|
|
32083
|
-
}), hasExpoConfig)
|
|
32804
|
+
...linked,
|
|
32805
|
+
buildProfiles
|
|
32084
32806
|
};
|
|
32085
32807
|
}), { json: "value" })
|
|
32086
32808
|
});
|
|
@@ -35897,10 +36619,11 @@ const bootstrapVersionCheck = (currentVersion, installerHint, spawnRefresh, opti
|
|
|
35897
36619
|
if (yield* isOptedOut) return;
|
|
35898
36620
|
const versionCheck = yield* VersionCheck;
|
|
35899
36621
|
if (options?.quiet !== true) {
|
|
35900
|
-
|
|
35901
|
-
if (
|
|
36622
|
+
let latest = yield* versionCheck.cachedLatest;
|
|
36623
|
+
if (latest === void 0) latest = yield* versionCheck.fetchLatest;
|
|
36624
|
+
if (latest && isNewerVersion(latest, currentVersion)) {
|
|
35902
36625
|
const installer = detectInstallerFromImportMetaUrl(installerHint);
|
|
35903
|
-
yield* Console.error(formatNotice(currentVersion,
|
|
36626
|
+
yield* Console.error(formatNotice(currentVersion, latest, installCommand(installer)));
|
|
35904
36627
|
}
|
|
35905
36628
|
}
|
|
35906
36629
|
if (yield* versionCheck.cacheStale) spawnRefresh();
|