Overhauled the library with several new features (#5)

## Summary

Updates the library to v4.5.1 of the App Store Connect API, and ships it as a breaking 2.0.0 release with pagination, API key authentication, rate limiting, and a lighter install for consumers.

## Breaking changes

- **Minimum platforms:** iOS 14, macOS 11, tvOS 14, watchOS 7, and visionOS 1.
- **Toolchain:** Swift 6.0+ (Xcode 16+). The package builds in the Swift 6 language mode.
- **Runtime:** requires `swift-openapi-runtime` 1.11.0 or later.

## Changes

- **API:** updated the OpenAPI specification to v4.5.1, covering 1,303 operations and 1,473 schemas.
- **Pagination:** the spec patch adds the undocumented `cursor` query parameter to the 465 paged operations. `PagedDocumentLinks.nextCursor` reads the cursor from a page, and `PagedSequence` iterates every page.
- **Authentication:** `APIKeyTokenProvider` signs ES256 tokens from an API key and reuses each one until a minute before it expires. `BearerAuthMiddleware` now accepts a token provider.
- **Rate limiting:** `RateLimitMiddleware` retries `429` responses, waiting for `Retry-After` or backing off exponentially.
- **Generated code:** committed to `Sources/ASConnectService/Sources/Public/Generated` instead of generated by a build plugin. Consumers now resolve 4 packages instead of 12, and Xcode no longer asks to trust a plugin.
- **Tooling:**
  - `make oas-download` now downloads, patches, generates, and checks the docs in one go.
  - New `make oas-generate`, `make oas-validate`, and `make doc-check` targets.
  - The generator is pinned in `Tools/`, and the DocC plugin is only resolved by the documentation targets.
- **Documentation:** the DocC catalog now lists every operation and schema in the spec, and the catalog and README are rewritten for the new APIs.
- **Housekeeping:** Apache 2.0 license headers on every Swift file, including `Package.swift` and the tests.

Reviewed-on: #5
Co-authored-by: Javier Cicchelli <javier@rock-n-code.com>
This commit was merged in pull request #5.
This commit is contained in:
javier authored and Javier Cicchelli committed 2026-10-25 17:52:37 +00:00
1 parent 3aaf5cd7a5
commit 0431fb5133
27 files changed
+1046471 -284

No files matched your search

@@ -1,20 +1,28 @@
# ``APIProtocol``
A protocol defining the available operations for the App Store Connect API.
The operations of the App Store Connect API.
## Overview
The ``APIProtocol`` protocol declares the complete set of operations available through the App Store Connect API. Each method corresponds to an HTTP endpoint and follows a consistent naming pattern:
Each method calls one endpoint, and is named after its resource followed by its action:
- `<resource>GetCollection` — List resources (HTTP `GET` on a collection)
- `<resource>CreateInstance` — Create a resource (HTTP `POST`)
- `<resource>GetInstance` — Get a single resource by ID (HTTP `GET`)
- `<resource>UpdateInstance` — Update a resource (HTTP `PATCH`)
- `<resource>DeleteInstance` — Delete a resource (HTTP `DELETE`)
- `<resource>GetToManyRelated` — Fetch related resources
- `<resource>GetToOneRelated` — Fetch a related resource
| Suffix | HTTP method | Action |
| --- | --- | --- |
| `GetCollection` | `GET` | List resources |
| `GetInstance` | `GET` | Get a resource by ID |
| `CreateInstance` | `POST` | Create a resource |
| `UpdateInstance` | `PATCH` | Update a resource |
| `DeleteInstance` | `DELETE` | Delete a resource |
| `GetToOneRelated`, `GetToManyRelated` | `GET` | Get related resources |
| `GetToOneRelationship`, `GetToManyRelationship` | `GET` | Get the IDs of related resources |
| `CreateToManyRelationship` | `POST` | Add relationships |
| `UpdateToOneRelationship`, `ReplaceToManyRelationship` | `PATCH` | Replace relationships |
| `DeleteToManyRelationship` | `DELETE` | Remove relationships |
| `GetMetrics` | `GET` | Get metrics |
The ``Client`` type conforms to this protocol and provides the concrete implementation for making HTTP requests.
For example, ``appsGetCollection(_:)`` lists apps, and ``appsBuildsGetToManyRelated(_:)`` lists the builds of an app.
Every method also has an overload that takes the `path`, `query`, `headers`, and `body` of its `Input` as separate arguments. ``Client`` provides the implementation.
## Topics
@@ -106,6 +114,9 @@ The ``Client`` type conforms to this protocol and provides the concrete implemen
- ``appsSubscriptionGracePeriodGetToOneRelated(_:)``
- ``appsSubscriptionGroupsGetToManyRelated(_:)``
- ``appsWebhooksGetToManyRelated(_:)``
- ``appsAssetLibraryGetToOneRelationship(_:)``
- ``appsAssetLibraryGetToOneRelated(_:)``
- ``appsPerformanceOverviewsGetToManyRelated(_:)``
- ``appInfosGetInstance(_:)``
- ``appInfosUpdateInstance(_:)``
- ``appInfosAgeRatingDeclarationGetToOneRelated(_:)``
@@ -207,6 +218,8 @@ The ``Client`` type conforms to this protocol and provides the concrete implemen
- ``appStoreVersionLocalizationsSearchKeywordsCreateToManyRelationship(_:)``
- ``appStoreVersionLocalizationsSearchKeywordsDeleteToManyRelationship(_:)``
- ``appStoreVersionLocalizationsSearchKeywordsGetToManyRelated(_:)``
- ``appStoreVersionLocalizationsPlacementsGetToManyRelationship(_:)``
- ``appStoreVersionLocalizationsPlacementsGetToManyRelated(_:)``
- ``appStoreVersionPhasedReleasesCreateInstance(_:)``
- ``appStoreVersionPhasedReleasesUpdateInstance(_:)``
- ``appStoreVersionPhasedReleasesDeleteInstance(_:)``
@@ -241,6 +254,8 @@ The ``Client`` type conforms to this protocol and provides the concrete implemen
- ``appStoreVersionExperimentTreatmentLocalizationsAppScreenshotSetsGetToManyRelated(_:)``
- ``appStoreVersionExperimentTreatmentLocalizationsAppPreviewSetsGetToManyRelationship(_:)``
- ``appStoreVersionExperimentTreatmentLocalizationsAppScreenshotSetsGetToManyRelationship(_:)``
- ``appStoreVersionExperimentTreatmentLocalizationsPlacementsGetToManyRelationship(_:)``
- ``appStoreVersionExperimentTreatmentLocalizationsPlacementsGetToManyRelated(_:)``
### App Custom Product Pages
@@ -267,6 +282,8 @@ The ``Client`` type conforms to this protocol and provides the concrete implemen
- ``appCustomProductPageLocalizationsSearchKeywordsCreateToManyRelationship(_:)``
- ``appCustomProductPageLocalizationsSearchKeywordsDeleteToManyRelationship(_:)``
- ``appCustomProductPageLocalizationsSearchKeywordsGetToManyRelated(_:)``
- ``appCustomProductPageLocalizationsPlacementsGetToManyRelationship(_:)``
- ``appCustomProductPageLocalizationsPlacementsGetToManyRelated(_:)``
### App Clips
@@ -322,6 +339,8 @@ The ``Client`` type conforms to this protocol and provides the concrete implemen
- ``appEventLocalizationsAppEventVideoClipsGetToManyRelated(_:)``
- ``appEventLocalizationsAppEventScreenshotsGetToManyRelationship(_:)``
- ``appEventLocalizationsAppEventVideoClipsGetToManyRelationship(_:)``
- ``appEventLocalizationsPlacementsGetToManyRelationship(_:)``
- ``appEventLocalizationsPlacementsGetToManyRelated(_:)``
- ``appEventScreenshotsCreateInstance(_:)``
- ``appEventScreenshotsGetInstance(_:)``
- ``appEventScreenshotsUpdateInstance(_:)``
@@ -358,6 +377,32 @@ The ``Client`` type conforms to this protocol and provides the concrete implemen
- ``routingAppCoveragesUpdateInstance(_:)``
- ``routingAppCoveragesDeleteInstance(_:)``
### App Asset Library
- ``appAssetLibrariesGetInstance(_:)``
- ``appAssetLibrariesImagesGetToManyRelationship(_:)``
- ``appAssetLibrariesImagesGetToManyRelated(_:)``
- ``appAssetLibrariesVideosGetToManyRelationship(_:)``
- ``appAssetLibrariesVideosGetToManyRelated(_:)``
- ``appAssetLibraryImagesCreateInstance(_:)``
- ``appAssetLibraryImagesGetInstance(_:)``
- ``appAssetLibraryImagesUpdateInstance(_:)``
- ``appAssetLibraryImagesDeleteInstance(_:)``
- ``appAssetLibraryImagesPlacementsGetToManyRelationship(_:)``
- ``appAssetLibraryImagesPlacementsGetToManyRelated(_:)``
- ``appAssetLibraryVideosCreateInstance(_:)``
- ``appAssetLibraryVideosGetInstance(_:)``
- ``appAssetLibraryVideosUpdateInstance(_:)``
- ``appAssetLibraryVideosDeleteInstance(_:)``
- ``appAssetLibraryVideosPlacementsGetToManyRelationship(_:)``
- ``appAssetLibraryVideosPlacementsGetToManyRelated(_:)``
- ``appAssetLibraryPlacementsCreateInstance(_:)``
- ``appAssetLibraryPlacementsGetInstance(_:)``
- ``appAssetLibraryPlacementsDeleteInstance(_:)``
- ``appAssetLibraryPlacementOrderingRequestsCreateInstance(_:)``
- ``appAssetLibraryRefDataGetCollection(_:)``
- ``appAssetLibraryRefDataGetInstance(_:)``
### App Encryption
- ``appEncryptionDeclarationsGetCollection(_:)``
@@ -581,15 +626,33 @@ The ``Client`` type conforms to this protocol and provides the concrete implemen
- ``inAppPurchasesV2OfferCodesGetToManyRelationship(_:)``
- ``inAppPurchasesV2PricePointsGetToManyRelationship(_:)``
- ``inAppPurchasesV2PromotedPurchaseGetToOneRelationship(_:)``
- ``inAppPurchasesV2VersionsGetToManyRelationship(_:)``
- ``inAppPurchasesV2VersionsGetToManyRelated(_:)``
- ``inAppPurchaseVersionsCreateInstance(_:)``
- ``inAppPurchaseVersionsGetInstance(_:)``
- ``inAppPurchaseVersionsImageGetToOneRelationship(_:)``
- ``inAppPurchaseVersionsImageGetToOneRelated(_:)``
- ``inAppPurchaseVersionsImagesGetToManyRelationship(_:)``
- ``inAppPurchaseVersionsImagesGetToManyRelated(_:)``
- ``inAppPurchaseVersionsLocalizationsGetToManyRelationship(_:)``
- ``inAppPurchaseVersionsLocalizationsGetToManyRelated(_:)``
- ``inAppPurchaseLocalizationsCreateInstance(_:)``
- ``inAppPurchaseLocalizationsGetInstance(_:)``
- ``inAppPurchaseLocalizationsUpdateInstance(_:)``
- ``inAppPurchaseLocalizationsDeleteInstance(_:)``
- ``inAppPurchaseLocalizationsV2CreateInstance(_:)``
- ``inAppPurchaseLocalizationsV2GetInstance(_:)``
- ``inAppPurchaseLocalizationsV2UpdateInstance(_:)``
- ``inAppPurchaseLocalizationsV2DeleteInstance(_:)``
- ``inAppPurchaseContentsGetInstance(_:)``
- ``inAppPurchaseImagesCreateInstance(_:)``
- ``inAppPurchaseImagesGetInstance(_:)``
- ``inAppPurchaseImagesUpdateInstance(_:)``
- ``inAppPurchaseImagesDeleteInstance(_:)``
- ``inAppPurchaseImagesV2CreateInstance(_:)``
- ``inAppPurchaseImagesV2GetInstance(_:)``
- ``inAppPurchaseImagesV2UpdateInstance(_:)``
- ``inAppPurchaseImagesV2DeleteInstance(_:)``
- ``inAppPurchaseAppStoreReviewScreenshotsCreateInstance(_:)``
- ``inAppPurchaseAppStoreReviewScreenshotsGetInstance(_:)``
- ``inAppPurchaseAppStoreReviewScreenshotsUpdateInstance(_:)``
@@ -660,6 +723,18 @@ The ``Client`` type conforms to this protocol and provides the concrete implemen
- ``subscriptionsSubscriptionAvailabilityGetToOneRelated(_:)``
- ``subscriptionsSubscriptionLocalizationsGetToManyRelated(_:)``
- ``subscriptionsWinBackOffersGetToManyRelated(_:)``
- ``subscriptionsPlanAvailabilitiesGetToManyRelationship(_:)``
- ``subscriptionsPlanAvailabilitiesGetToManyRelated(_:)``
- ``subscriptionsVersionsGetToManyRelationship(_:)``
- ``subscriptionsVersionsGetToManyRelated(_:)``
- ``subscriptionVersionsCreateInstance(_:)``
- ``subscriptionVersionsGetInstance(_:)``
- ``subscriptionVersionsImageGetToOneRelationship(_:)``
- ``subscriptionVersionsImageGetToOneRelated(_:)``
- ``subscriptionVersionsImagesGetToManyRelationship(_:)``
- ``subscriptionVersionsImagesGetToManyRelated(_:)``
- ``subscriptionVersionsLocalizationsGetToManyRelationship(_:)``
- ``subscriptionVersionsLocalizationsGetToManyRelated(_:)``
- ``subscriptionGroupsCreateInstance(_:)``
- ``subscriptionGroupsGetInstance(_:)``
- ``subscriptionGroupsUpdateInstance(_:)``
@@ -668,19 +743,37 @@ The ``Client`` type conforms to this protocol and provides the concrete implemen
- ``subscriptionGroupsSubscriptionsGetToManyRelationship(_:)``
- ``subscriptionGroupsSubscriptionGroupLocalizationsGetToManyRelated(_:)``
- ``subscriptionGroupsSubscriptionsGetToManyRelated(_:)``
- ``subscriptionGroupsVersionsGetToManyRelationship(_:)``
- ``subscriptionGroupsVersionsGetToManyRelated(_:)``
- ``subscriptionGroupVersionsCreateInstance(_:)``
- ``subscriptionGroupVersionsGetInstance(_:)``
- ``subscriptionGroupVersionsLocalizationsGetToManyRelationship(_:)``
- ``subscriptionGroupVersionsLocalizationsGetToManyRelated(_:)``
- ``subscriptionGroupLocalizationsCreateInstance(_:)``
- ``subscriptionGroupLocalizationsGetInstance(_:)``
- ``subscriptionGroupLocalizationsUpdateInstance(_:)``
- ``subscriptionGroupLocalizationsDeleteInstance(_:)``
- ``subscriptionGroupLocalizationsV2CreateInstance(_:)``
- ``subscriptionGroupLocalizationsV2GetInstance(_:)``
- ``subscriptionGroupLocalizationsV2UpdateInstance(_:)``
- ``subscriptionGroupLocalizationsV2DeleteInstance(_:)``
- ``subscriptionGroupSubmissionsCreateInstance(_:)``
- ``subscriptionLocalizationsCreateInstance(_:)``
- ``subscriptionLocalizationsGetInstance(_:)``
- ``subscriptionLocalizationsUpdateInstance(_:)``
- ``subscriptionLocalizationsDeleteInstance(_:)``
- ``subscriptionLocalizationsV2CreateInstance(_:)``
- ``subscriptionLocalizationsV2GetInstance(_:)``
- ``subscriptionLocalizationsV2UpdateInstance(_:)``
- ``subscriptionLocalizationsV2DeleteInstance(_:)``
- ``subscriptionImagesCreateInstance(_:)``
- ``subscriptionImagesGetInstance(_:)``
- ``subscriptionImagesUpdateInstance(_:)``
- ``subscriptionImagesDeleteInstance(_:)``
- ``subscriptionImagesV2CreateInstance(_:)``
- ``subscriptionImagesV2GetInstance(_:)``
- ``subscriptionImagesV2UpdateInstance(_:)``
- ``subscriptionImagesV2DeleteInstance(_:)``
- ``subscriptionAppStoreReviewScreenshotsCreateInstance(_:)``
- ``subscriptionAppStoreReviewScreenshotsGetInstance(_:)``
- ``subscriptionAppStoreReviewScreenshotsUpdateInstance(_:)``
@@ -689,6 +782,12 @@ The ``Client`` type conforms to this protocol and provides the concrete implemen
- ``subscriptionAvailabilitiesGetInstance(_:)``
- ``subscriptionAvailabilitiesAvailableTerritoriesGetToManyRelated(_:)``
- ``subscriptionAvailabilitiesAvailableTerritoriesGetToManyRelationship(_:)``
- ``subscriptionPlanAvailabilitiesCreateInstance(_:)``
- ``subscriptionPlanAvailabilitiesGetInstance(_:)``
- ``subscriptionPlanAvailabilitiesUpdateInstance(_:)``
- ``subscriptionPlanAvailabilitiesAvailableTerritoriesGetToManyRelationship(_:)``
- ``subscriptionPlanAvailabilitiesAvailableTerritoriesReplaceToManyRelationship(_:)``
- ``subscriptionPlanAvailabilitiesAvailableTerritoriesGetToManyRelated(_:)``
- ``subscriptionGracePeriodsGetInstance(_:)``
- ``subscriptionGracePeriodsUpdateInstance(_:)``
- ``subscriptionIntroductoryOffersCreateInstance(_:)``
@@ -713,6 +812,7 @@ The ``Client`` type conforms to this protocol and provides the concrete implemen
- ``subscriptionPricePointsGetInstance(_:)``
- ``subscriptionPricePointsEqualizationsGetToManyRelated(_:)``
- ``subscriptionPricePointsEqualizationsGetToManyRelationship(_:)``
- ``subscriptionPricePointsAdjustedEqualizationsGetToManyRelated(_:)``
- ``subscriptionPricesCreateInstance(_:)``
- ``subscriptionPricesDeleteInstance(_:)``
- ``subscriptionPromotionalOffersCreateInstance(_:)``
@@ -773,6 +873,9 @@ The ``Client`` type conforms to this protocol and provides the concrete implemen
- ``gameCenterDetailsGameCenterLeaderboardsV2ReplaceToManyRelationship(_:)``
- ``gameCenterDetailsLeaderboardReleasesGetToManyRelationship(_:)``
- ``gameCenterDetailsLeaderboardSetReleasesGetToManyRelationship(_:)``
- ``gameCenterDetailsBlockedPlayersGetToManyRelationship(_:)``
- ``gameCenterDetailsBlockedPlayersGetToManyRelated(_:)``
- ``gameCenterDetailPlayersUpdateInstance(_:)``
- ``gameCenterGroupsGetCollection(_:)``
- ``gameCenterGroupsCreateInstance(_:)``
- ``gameCenterGroupsGetInstance(_:)``
@@ -871,6 +974,9 @@ The ``Client`` type conforms to this protocol and provides the concrete implemen
- ``gameCenterLeaderboardsV2ChallengeUpdateToOneRelationship(_:)``
- ``gameCenterLeaderboardsV2VersionsGetToManyRelationship(_:)``
- ``gameCenterLeaderboardsV2VersionsGetToManyRelated(_:)``
- ``gameCenterLeaderboardsV2GameCenterScoreModerationsGetToManyRelationship(_:)``
- ``gameCenterLeaderboardsV2GameCenterScoreModerationsGetToManyRelated(_:)``
- ``gameCenterScoreModerationsUpdateInstance(_:)``
- ``gameCenterLeaderboardVersionsV2CreateInstance(_:)``
- ``gameCenterLeaderboardVersionsV2GetInstance(_:)``
- ``gameCenterLeaderboardVersionsV2LocalizationsGetToManyRelated(_:)``
@@ -1,21 +1,19 @@
# ``Client``
The API client for performing HTTP operations against the App Store Connect API.
The App Store Connect API client.
## Overview
The ``Client`` struct is the main entry point for interacting with the App Store Connect API. It conforms to ``APIProtocol`` and provides concrete implementations for all available API operations.
``Client`` implements every ``APIProtocol`` method by sending the request through its transport, after passing it through its middlewares.
### Creating a Client
Create a ``Client`` by providing a server URL, a transport, and optionally a list of middlewares for authentication or request customization.
Include ``BearerAuthMiddleware`` in `middlewares` to authenticate requests:
```swift
import ASConnectService
import OpenAPIURLSession
let client = Client(
serverURL: try Servers.server1(),
serverURL: try Servers.Server1.url(),
transport: URLSessionTransport(),
middlewares: [
BearerAuthMiddleware(token: yourJWTToken)
@@ -23,12 +21,10 @@ let client = Client(
)
```
### Making API Calls
Each method on the ``Client`` corresponds to an HTTP endpoint defined in the App Store Connect API OpenAPI specification. Methods accept an `Input` value and return an `Output` value representing the response.
Each method takes either a single `Input` value or its `path`, `query`, `headers`, and `body` as separate arguments:
```swift
let response = try await client.appsGetCollection(.init())
let response = try await client.appsGetInstance(path: .init(id: appID))
```
## Topics
@@ -1,17 +1,16 @@
# ``Components``
Types generated from the components section of the OpenAPI document.
The data models of the App Store Connect API.
## Overview
The ``Components`` namespace contains all the data models defined in the App Store Connect API OpenAPI specification. These types are organized within the ``Components/Schemas`` namespace and are used as request and response bodies across all API operations.
The models are in ``Components/Schemas``, and are used as request and response bodies. Each resource typically has:
Each resource type typically includes:
- A **model type** (e.g., `Components.Schemas.App`) representing the resource
- A **response type** (e.g., `Components.Schemas.AppResponse`) for single-resource responses
- A **collection response type** (e.g., `Components.Schemas.AppsResponse`) for list responses
- **Request types** for create and update operations (e.g., `Components.Schemas.AppUpdateRequest`)
- A model, such as ``Components/Schemas/App``.
- A single-resource response, such as ``Components/Schemas/AppResponse``.
- A collection response, such as ``Components/Schemas/AppsResponse``.
- Create and update requests, such as ``Components/Schemas/AppUpdateRequest``.
- Linkage responses for its relationships, such as ``Components/Schemas/AppBuildsLinkagesResponse``.
## Topics
@@ -94,6 +93,7 @@ Each resource type typically includes:
- ``Components/Schemas/AppMediaStateError``
- ``Components/Schemas/AppMediaVideoState``
- ``Components/Schemas/AppPerfPowerMetricsLinkagesResponse``
- ``Components/Schemas/AppPerformanceOverviewsLinkagesResponse``
- ``Components/Schemas/AppPreReleaseVersionsLinkagesResponse``
- ``Components/Schemas/AppPricePointV3``
- ``Components/Schemas/AppPricePointV3EqualizationsLinkagesResponse``
@@ -156,6 +156,7 @@ Each resource type typically includes:
- ``Components/Schemas/AppStoreVersionLocalizationAppPreviewSetsLinkagesResponse``
- ``Components/Schemas/AppStoreVersionLocalizationAppScreenshotSetsLinkagesResponse``
- ``Components/Schemas/AppStoreVersionLocalizationCreateRequest``
- ``Components/Schemas/AppStoreVersionLocalizationPlacementsLinkagesResponse``
- ``Components/Schemas/AppStoreVersionLocalizationResponse``
- ``Components/Schemas/AppStoreVersionLocalizationSearchKeywordsLinkagesRequest``
- ``Components/Schemas/AppStoreVersionLocalizationSearchKeywordsLinkagesResponse``
@@ -194,6 +195,7 @@ Each resource type typically includes:
- ``Components/Schemas/AppStoreVersionExperimentTreatmentLocalizationAppPreviewSetsLinkagesResponse``
- ``Components/Schemas/AppStoreVersionExperimentTreatmentLocalizationAppScreenshotSetsLinkagesResponse``
- ``Components/Schemas/AppStoreVersionExperimentTreatmentLocalizationCreateRequest``
- ``Components/Schemas/AppStoreVersionExperimentTreatmentLocalizationPlacementsLinkagesResponse``
- ``Components/Schemas/AppStoreVersionExperimentTreatmentLocalizationResponse``
- ``Components/Schemas/AppStoreVersionExperimentTreatmentLocalizationsResponse``
- ``Components/Schemas/AppStoreVersionExperimentTreatmentResponse``
@@ -218,6 +220,7 @@ Each resource type typically includes:
- ``Components/Schemas/AppCustomProductPageLocalizationAppScreenshotSetsLinkagesResponse``
- ``Components/Schemas/AppCustomProductPageLocalizationCreateRequest``
- ``Components/Schemas/AppCustomProductPageLocalizationInlineCreate``
- ``Components/Schemas/AppCustomProductPageLocalizationPlacementsLinkagesResponse``
- ``Components/Schemas/AppCustomProductPageLocalizationResponse``
- ``Components/Schemas/AppCustomProductPageLocalizationSearchKeywordsLinkagesRequest``
- ``Components/Schemas/AppCustomProductPageLocalizationSearchKeywordsLinkagesResponse``
@@ -289,6 +292,7 @@ Each resource type typically includes:
- ``Components/Schemas/AppEventLocalizationAppEventScreenshotsLinkagesResponse``
- ``Components/Schemas/AppEventLocalizationAppEventVideoClipsLinkagesResponse``
- ``Components/Schemas/AppEventLocalizationCreateRequest``
- ``Components/Schemas/AppEventLocalizationPlacementsLinkagesResponse``
- ``Components/Schemas/AppEventLocalizationResponse``
- ``Components/Schemas/AppEventLocalizationUpdateRequest``
- ``Components/Schemas/AppEventLocalizationsLinkagesResponse``
@@ -337,6 +341,71 @@ Each resource type typically includes:
- ``Components/Schemas/RoutingAppCoverageResponse``
- ``Components/Schemas/RoutingAppCoverageUpdateRequest``
### App Asset Library
- ``Components/Schemas/AppAssetLibrary``
- ``Components/Schemas/AppAssetLibraryAssetCategory``
- ``Components/Schemas/AppAssetLibraryAssetState``
- ``Components/Schemas/AppAssetLibraryDisplayClass``
- ``Components/Schemas/AppAssetLibraryFeature``
- ``Components/Schemas/AppAssetLibraryImage``
- ``Components/Schemas/AppAssetLibraryImageAcceptedAttributes``
- ``Components/Schemas/AppAssetLibraryImageApprovedAttributes``
- ``Components/Schemas/AppAssetLibraryImageArchivedAttributes``
- ``Components/Schemas/AppAssetLibraryImageAwaitingUploadAttributes``
- ``Components/Schemas/AppAssetLibraryImageCommonAttributes``
- ``Components/Schemas/AppAssetLibraryImageCreateRequest``
- ``Components/Schemas/AppAssetLibraryImageFailedAttributes``
- ``Components/Schemas/AppAssetLibraryImageInReviewAttributes``
- ``Components/Schemas/AppAssetLibraryImagePlacementsLinkagesResponse``
- ``Components/Schemas/AppAssetLibraryImageReadyForReviewAttributes``
- ``Components/Schemas/AppAssetLibraryImageRejectedAttributes``
- ``Components/Schemas/AppAssetLibraryImageResponse``
- ``Components/Schemas/AppAssetLibraryImageUpdateRequest``
- ``Components/Schemas/AppAssetLibraryImageUploadCompleteAttributes``
- ``Components/Schemas/AppAssetLibraryImageWaitingForReviewAttributes``
- ``Components/Schemas/AppAssetLibraryImagesLinkagesResponse``
- ``Components/Schemas/AppAssetLibraryImagesResponse``
- ``Components/Schemas/AppAssetLibraryLinkageResponse``
- ``Components/Schemas/AppAssetLibraryMediaType``
- ``Components/Schemas/AppAssetLibraryPlacement``
- ``Components/Schemas/AppAssetLibraryPlacementCommonAttributes``
- ``Components/Schemas/AppAssetLibraryPlacementCommonRelationships``
- ``Components/Schemas/AppAssetLibraryPlacementCreateRequest``
- ``Components/Schemas/AppAssetLibraryPlacementImageRelationships``
- ``Components/Schemas/AppAssetLibraryPlacementOrderingRequest``
- ``Components/Schemas/AppAssetLibraryPlacementOrderingRequestCreateRequest``
- ``Components/Schemas/AppAssetLibraryPlacementOrderingRequestResponse``
- ``Components/Schemas/AppAssetLibraryPlacementPlatform``
- ``Components/Schemas/AppAssetLibraryPlacementResponse``
- ``Components/Schemas/AppAssetLibraryPlacementState``
- ``Components/Schemas/AppAssetLibraryPlacementType``
- ``Components/Schemas/AppAssetLibraryPlacementVideoAttributes``
- ``Components/Schemas/AppAssetLibraryPlacementVideoRelationships``
- ``Components/Schemas/AppAssetLibraryPlacementsResponse``
- ``Components/Schemas/AppAssetLibraryRefDataResponse``
- ``Components/Schemas/AppAssetLibraryRefDatum``
- ``Components/Schemas/AppAssetLibraryRefDatumResponse``
- ``Components/Schemas/AppAssetLibraryResponse``
- ``Components/Schemas/AppAssetLibraryVideo``
- ``Components/Schemas/AppAssetLibraryVideoAcceptedAttributes``
- ``Components/Schemas/AppAssetLibraryVideoApprovedAttributes``
- ``Components/Schemas/AppAssetLibraryVideoArchivedAttributes``
- ``Components/Schemas/AppAssetLibraryVideoAwaitingUploadAttributes``
- ``Components/Schemas/AppAssetLibraryVideoCommonAttributes``
- ``Components/Schemas/AppAssetLibraryVideoCreateRequest``
- ``Components/Schemas/AppAssetLibraryVideoFailedAttributes``
- ``Components/Schemas/AppAssetLibraryVideoInReviewAttributes``
- ``Components/Schemas/AppAssetLibraryVideoPlacementsLinkagesResponse``
- ``Components/Schemas/AppAssetLibraryVideoReadyForReviewAttributes``
- ``Components/Schemas/AppAssetLibraryVideoRejectedAttributes``
- ``Components/Schemas/AppAssetLibraryVideoResponse``
- ``Components/Schemas/AppAssetLibraryVideoUpdateRequest``
- ``Components/Schemas/AppAssetLibraryVideoUploadCompleteAttributes``
- ``Components/Schemas/AppAssetLibraryVideoWaitingForReviewAttributes``
- ``Components/Schemas/AppAssetLibraryVideosLinkagesResponse``
- ``Components/Schemas/AppAssetLibraryVideosResponse``
### App Encryption
- ``Components/Schemas/AppEncryptionDeclaration``
@@ -573,12 +642,22 @@ Each resource type typically includes:
- ``Components/Schemas/InAppPurchaseImageCreateRequest``
- ``Components/Schemas/InAppPurchaseImageResponse``
- ``Components/Schemas/InAppPurchaseImageUpdateRequest``
- ``Components/Schemas/InAppPurchaseImageV2``
- ``Components/Schemas/InAppPurchaseImageV2CreateRequest``
- ``Components/Schemas/InAppPurchaseImageV2Response``
- ``Components/Schemas/InAppPurchaseImageV2UpdateRequest``
- ``Components/Schemas/InAppPurchaseImagesResponse``
- ``Components/Schemas/InAppPurchaseImagesV2Response``
- ``Components/Schemas/InAppPurchaseLocalization``
- ``Components/Schemas/InAppPurchaseLocalizationCreateRequest``
- ``Components/Schemas/InAppPurchaseLocalizationResponse``
- ``Components/Schemas/InAppPurchaseLocalizationUpdateRequest``
- ``Components/Schemas/InAppPurchaseLocalizationV2``
- ``Components/Schemas/InAppPurchaseLocalizationV2CreateRequest``
- ``Components/Schemas/InAppPurchaseLocalizationV2Response``
- ``Components/Schemas/InAppPurchaseLocalizationV2UpdateRequest``
- ``Components/Schemas/InAppPurchaseLocalizationsResponse``
- ``Components/Schemas/InAppPurchaseLocalizationsV2Response``
- ``Components/Schemas/InAppPurchaseOfferCode``
- ``Components/Schemas/InAppPurchaseOfferCodeCreateRequest``
- ``Components/Schemas/InAppPurchaseOfferCodeCustomCode``
@@ -633,6 +712,14 @@ Each resource type typically includes:
- ``Components/Schemas/InAppPurchaseV2PromotedPurchaseLinkageResponse``
- ``Components/Schemas/InAppPurchaseV2Response``
- ``Components/Schemas/InAppPurchaseV2UpdateRequest``
- ``Components/Schemas/InAppPurchaseV2VersionsLinkagesResponse``
- ``Components/Schemas/InAppPurchaseVersion``
- ``Components/Schemas/InAppPurchaseVersionCreateRequest``
- ``Components/Schemas/InAppPurchaseVersionImageLinkageResponse``
- ``Components/Schemas/InAppPurchaseVersionImagesLinkagesResponse``
- ``Components/Schemas/InAppPurchaseVersionLocalizationsLinkagesResponse``
- ``Components/Schemas/InAppPurchaseVersionResponse``
- ``Components/Schemas/InAppPurchaseVersionsResponse``
- ``Components/Schemas/InAppPurchasesResponse``
- ``Components/Schemas/InAppPurchasesV2Response``
- ``Components/Schemas/OfferCodeEnvironment``
@@ -666,7 +753,12 @@ Each resource type typically includes:
- ``Components/Schemas/SubscriptionGroupLocalizationCreateRequest``
- ``Components/Schemas/SubscriptionGroupLocalizationResponse``
- ``Components/Schemas/SubscriptionGroupLocalizationUpdateRequest``
- ``Components/Schemas/SubscriptionGroupLocalizationV2``
- ``Components/Schemas/SubscriptionGroupLocalizationV2CreateRequest``
- ``Components/Schemas/SubscriptionGroupLocalizationV2Response``
- ``Components/Schemas/SubscriptionGroupLocalizationV2UpdateRequest``
- ``Components/Schemas/SubscriptionGroupLocalizationsResponse``
- ``Components/Schemas/SubscriptionGroupLocalizationsV2Response``
- ``Components/Schemas/SubscriptionGroupResponse``
- ``Components/Schemas/SubscriptionGroupSubmission``
- ``Components/Schemas/SubscriptionGroupSubmissionCreateRequest``
@@ -674,13 +766,24 @@ Each resource type typically includes:
- ``Components/Schemas/SubscriptionGroupSubscriptionGroupLocalizationsLinkagesResponse``
- ``Components/Schemas/SubscriptionGroupSubscriptionsLinkagesResponse``
- ``Components/Schemas/SubscriptionGroupUpdateRequest``
- ``Components/Schemas/SubscriptionGroupVersion``
- ``Components/Schemas/SubscriptionGroupVersionCreateRequest``
- ``Components/Schemas/SubscriptionGroupVersionLocalizationsLinkagesResponse``
- ``Components/Schemas/SubscriptionGroupVersionResponse``
- ``Components/Schemas/SubscriptionGroupVersionsLinkagesResponse``
- ``Components/Schemas/SubscriptionGroupVersionsResponse``
- ``Components/Schemas/SubscriptionGroupsResponse``
- ``Components/Schemas/SubscriptionImage``
- ``Components/Schemas/SubscriptionImageCreateRequest``
- ``Components/Schemas/SubscriptionImageResponse``
- ``Components/Schemas/SubscriptionImageUpdateRequest``
- ``Components/Schemas/SubscriptionImageV2``
- ``Components/Schemas/SubscriptionImageV2CreateRequest``
- ``Components/Schemas/SubscriptionImageV2Response``
- ``Components/Schemas/SubscriptionImageV2UpdateRequest``
- ``Components/Schemas/SubscriptionImagesLinkagesResponse``
- ``Components/Schemas/SubscriptionImagesResponse``
- ``Components/Schemas/SubscriptionImagesV2Response``
- ``Components/Schemas/SubscriptionIntroductoryOffer``
- ``Components/Schemas/SubscriptionIntroductoryOfferCreateRequest``
- ``Components/Schemas/SubscriptionIntroductoryOfferInlineCreate``
@@ -693,7 +796,12 @@ Each resource type typically includes:
- ``Components/Schemas/SubscriptionLocalizationCreateRequest``
- ``Components/Schemas/SubscriptionLocalizationResponse``
- ``Components/Schemas/SubscriptionLocalizationUpdateRequest``
- ``Components/Schemas/SubscriptionLocalizationV2``
- ``Components/Schemas/SubscriptionLocalizationV2CreateRequest``
- ``Components/Schemas/SubscriptionLocalizationV2Response``
- ``Components/Schemas/SubscriptionLocalizationV2UpdateRequest``
- ``Components/Schemas/SubscriptionLocalizationsResponse``
- ``Components/Schemas/SubscriptionLocalizationsV2Response``
- ``Components/Schemas/SubscriptionOfferCode``
- ``Components/Schemas/SubscriptionOfferCodeCreateRequest``
- ``Components/Schemas/SubscriptionOfferCodeCustomCode``
@@ -721,6 +829,15 @@ Each resource type typically includes:
- ``Components/Schemas/SubscriptionOfferDuration``
- ``Components/Schemas/SubscriptionOfferEligibility``
- ``Components/Schemas/SubscriptionOfferMode``
- ``Components/Schemas/SubscriptionPlanAvailabilitiesLinkagesResponse``
- ``Components/Schemas/SubscriptionPlanAvailabilitiesResponse``
- ``Components/Schemas/SubscriptionPlanAvailability``
- ``Components/Schemas/SubscriptionPlanAvailabilityAvailableTerritoriesLinkagesRequest``
- ``Components/Schemas/SubscriptionPlanAvailabilityAvailableTerritoriesLinkagesResponse``
- ``Components/Schemas/SubscriptionPlanAvailabilityCreateRequest``
- ``Components/Schemas/SubscriptionPlanAvailabilityResponse``
- ``Components/Schemas/SubscriptionPlanAvailabilityUpdateRequest``
- ``Components/Schemas/SubscriptionPlanType``
- ``Components/Schemas/SubscriptionPrice``
- ``Components/Schemas/SubscriptionPriceCreateRequest``
- ``Components/Schemas/SubscriptionPriceInlineCreate``
@@ -754,6 +871,14 @@ Each resource type typically includes:
- ``Components/Schemas/SubscriptionSubscriptionAvailabilityLinkageResponse``
- ``Components/Schemas/SubscriptionSubscriptionLocalizationsLinkagesResponse``
- ``Components/Schemas/SubscriptionUpdateRequest``
- ``Components/Schemas/SubscriptionVersion``
- ``Components/Schemas/SubscriptionVersionCreateRequest``
- ``Components/Schemas/SubscriptionVersionImageLinkageResponse``
- ``Components/Schemas/SubscriptionVersionImagesLinkagesResponse``
- ``Components/Schemas/SubscriptionVersionLocalizationsLinkagesResponse``
- ``Components/Schemas/SubscriptionVersionResponse``
- ``Components/Schemas/SubscriptionVersionsLinkagesResponse``
- ``Components/Schemas/SubscriptionVersionsResponse``
- ``Components/Schemas/SubscriptionWinBackOffersLinkagesResponse``
- ``Components/Schemas/SubscriptionsResponse``
- ``Components/Schemas/WinBackOffer``
@@ -888,6 +1013,7 @@ Each resource type typically includes:
- ``Components/Schemas/GameCenterDetail``
- ``Components/Schemas/GameCenterDetailAchievementReleasesLinkagesResponse``
- ``Components/Schemas/GameCenterDetailActivityReleasesLinkagesResponse``
- ``Components/Schemas/GameCenterDetailBlockedPlayersLinkagesResponse``
- ``Components/Schemas/GameCenterDetailChallengeReleasesLinkagesResponse``
- ``Components/Schemas/GameCenterDetailChallengesMinimumPlatformVersionsLinkagesRequest``
- ``Components/Schemas/GameCenterDetailCreateRequest``
@@ -909,6 +1035,10 @@ Each resource type typically includes:
- ``Components/Schemas/GameCenterDetailGameCenterLeaderboardsV2LinkagesResponse``
- ``Components/Schemas/GameCenterDetailLeaderboardReleasesLinkagesResponse``
- ``Components/Schemas/GameCenterDetailLeaderboardSetReleasesLinkagesResponse``
- ``Components/Schemas/GameCenterDetailPlayer``
- ``Components/Schemas/GameCenterDetailPlayerResponse``
- ``Components/Schemas/GameCenterDetailPlayerUpdateRequest``
- ``Components/Schemas/GameCenterDetailPlayersResponse``
- ``Components/Schemas/GameCenterDetailResponse``
- ``Components/Schemas/GameCenterDetailUpdateRequest``
- ``Components/Schemas/GameCenterDetailsResponse``
@@ -1034,6 +1164,7 @@ Each resource type typically includes:
- ``Components/Schemas/GameCenterLeaderboardV2ActivityLinkageRequest``
- ``Components/Schemas/GameCenterLeaderboardV2ChallengeLinkageRequest``
- ``Components/Schemas/GameCenterLeaderboardV2CreateRequest``
- ``Components/Schemas/GameCenterLeaderboardV2GameCenterScoreModerationsLinkagesResponse``
- ``Components/Schemas/GameCenterLeaderboardV2Response``
- ``Components/Schemas/GameCenterLeaderboardV2UpdateRequest``
- ``Components/Schemas/GameCenterLeaderboardV2VersionsLinkagesResponse``
@@ -1086,6 +1217,10 @@ Each resource type typically includes:
- ``Components/Schemas/GameCenterPlayerAchievementSubmission``
- ``Components/Schemas/GameCenterPlayerAchievementSubmissionCreateRequest``
- ``Components/Schemas/GameCenterPlayerAchievementSubmissionResponse``
- ``Components/Schemas/GameCenterScoreModeration``
- ``Components/Schemas/GameCenterScoreModerationResponse``
- ``Components/Schemas/GameCenterScoreModerationUpdateRequest``
- ``Components/Schemas/GameCenterScoreModerationsResponse``
- ``Components/Schemas/GameCenterVersionState``
### Users and Roles
@@ -1270,14 +1405,17 @@ Each resource type typically includes:
- ``Components/Schemas/DiagnosticInsightType``
- ``Components/Schemas/DiagnosticLog``
- ``Components/Schemas/DiagnosticLogCallStackNode``
- ``Components/Schemas/DiagnosticLogs``
- ``Components/Schemas/DiagnosticSignature``
- ``Components/Schemas/DiagnosticSignatureLogsLinkagesResponse``
- ``Components/Schemas/DiagnosticSignaturesResponse``
- ``Components/Schemas/MetricCategory``
- ``Components/Schemas/MetricsInsight``
- ``Components/Schemas/PerfPowerMetric``
- ``Components/Schemas/diagnosticLogs``
- ``Components/Schemas/xcodeMetrics``
- ``Components/Schemas/PerformanceOverview``
- ``Components/Schemas/PerformanceSignature``
- ``Components/Schemas/XcodeMetrics``
- ``Components/Schemas/XcodeOverview``
### Sandbox Testing
@@ -1410,6 +1548,7 @@ Each resource type typically includes:
- ``Components/Schemas/BrazilAgeRating``
- ``Components/Schemas/ChecksumAlgorithm``
- ``Components/Schemas/Checksums``
- ``Components/Schemas/Csv``
- ``Components/Schemas/DeliveryFileUploadOperation``
- ``Components/Schemas/DocumentLinks``
- ``Components/Schemas/ErrorLinks``
@@ -1417,6 +1556,7 @@ Each resource type typically includes:
- ``Components/Schemas/ErrorSourceParameter``
- ``Components/Schemas/ErrorSourcePointer``
- ``Components/Schemas/FileLocation``
- ``Components/Schemas/Gzip``
- ``Components/Schemas/HttpHeader``
- ``Components/Schemas/IconAssetType``
- ``Components/Schemas/ImageAsset``
@@ -1434,5 +1574,3 @@ Each resource type typically includes:
- ``Components/Schemas/StateDetail``
- ``Components/Schemas/StringToStringMap``
- ``Components/Schemas/UploadOperation``
- ``Components/Schemas/csv``
- ``Components/Schemas/gzip``
@@ -1,18 +1,14 @@
# ``Operations``
API operations, with input and output types, generated from the paths section of the OpenAPI document.
The request and response types of each API operation.
## Overview
The ``Operations`` namespace contains a nested enum for each API operation defined in the App Store Connect API OpenAPI specification. Each operation enum encapsulates the `Input` and `Output` types for that specific endpoint.
Each operation is an enum, named after its ``APIProtocol`` method, that contains:
Each operation typically provides:
- An **`Input`** struct containing the request `Path`, `Query`, `Headers`, and `Body` types
- An **`Output`** enum with cases for each possible HTTP response status code
- An **`id`** string constant with the operation identifier
These types are used by the ``APIProtocol`` methods and the ``Client`` implementation.
- `Input`: The request, split into `path`, `query`, `headers`, and `body` as the endpoint requires.
- `Output`: The response, with a case for each documented status, such as `ok`, and `undocumented(statusCode:_:)` for any other.
- `id`: The operation identifier in the OpenAPI document, such as `apps_getCollection`.
## Topics
@@ -104,6 +100,9 @@ These types are used by the ``APIProtocol`` methods and the ``Client`` implement
- ``Operations/AppsSubscriptionGracePeriodGetToOneRelated``
- ``Operations/AppsSubscriptionGroupsGetToManyRelated``
- ``Operations/AppsWebhooksGetToManyRelated``
- ``Operations/AppsAssetLibraryGetToOneRelationship``
- ``Operations/AppsAssetLibraryGetToOneRelated``
- ``Operations/AppsPerformanceOverviewsGetToManyRelated``
- ``Operations/AppInfosGetInstance``
- ``Operations/AppInfosUpdateInstance``
- ``Operations/AppInfosAgeRatingDeclarationGetToOneRelated``
@@ -205,6 +204,8 @@ These types are used by the ``APIProtocol`` methods and the ``Client`` implement
- ``Operations/AppStoreVersionLocalizationsSearchKeywordsCreateToManyRelationship``
- ``Operations/AppStoreVersionLocalizationsSearchKeywordsDeleteToManyRelationship``
- ``Operations/AppStoreVersionLocalizationsSearchKeywordsGetToManyRelated``
- ``Operations/AppStoreVersionLocalizationsPlacementsGetToManyRelationship``
- ``Operations/AppStoreVersionLocalizationsPlacementsGetToManyRelated``
- ``Operations/AppStoreVersionPhasedReleasesCreateInstance``
- ``Operations/AppStoreVersionPhasedReleasesUpdateInstance``
- ``Operations/AppStoreVersionPhasedReleasesDeleteInstance``
@@ -239,6 +240,8 @@ These types are used by the ``APIProtocol`` methods and the ``Client`` implement
- ``Operations/AppStoreVersionExperimentTreatmentLocalizationsAppScreenshotSetsGetToManyRelated``
- ``Operations/AppStoreVersionExperimentTreatmentLocalizationsAppPreviewSetsGetToManyRelationship``
- ``Operations/AppStoreVersionExperimentTreatmentLocalizationsAppScreenshotSetsGetToManyRelationship``
- ``Operations/AppStoreVersionExperimentTreatmentLocalizationsPlacementsGetToManyRelationship``
- ``Operations/AppStoreVersionExperimentTreatmentLocalizationsPlacementsGetToManyRelated``
### App Custom Product Pages
@@ -265,6 +268,8 @@ These types are used by the ``APIProtocol`` methods and the ``Client`` implement
- ``Operations/AppCustomProductPageLocalizationsSearchKeywordsCreateToManyRelationship``
- ``Operations/AppCustomProductPageLocalizationsSearchKeywordsDeleteToManyRelationship``
- ``Operations/AppCustomProductPageLocalizationsSearchKeywordsGetToManyRelated``
- ``Operations/AppCustomProductPageLocalizationsPlacementsGetToManyRelationship``
- ``Operations/AppCustomProductPageLocalizationsPlacementsGetToManyRelated``
### App Clips
@@ -320,6 +325,8 @@ These types are used by the ``APIProtocol`` methods and the ``Client`` implement
- ``Operations/AppEventLocalizationsAppEventVideoClipsGetToManyRelated``
- ``Operations/AppEventLocalizationsAppEventScreenshotsGetToManyRelationship``
- ``Operations/AppEventLocalizationsAppEventVideoClipsGetToManyRelationship``
- ``Operations/AppEventLocalizationsPlacementsGetToManyRelationship``
- ``Operations/AppEventLocalizationsPlacementsGetToManyRelated``
- ``Operations/AppEventScreenshotsCreateInstance``
- ``Operations/AppEventScreenshotsGetInstance``
- ``Operations/AppEventScreenshotsUpdateInstance``
@@ -356,6 +363,32 @@ These types are used by the ``APIProtocol`` methods and the ``Client`` implement
- ``Operations/RoutingAppCoveragesUpdateInstance``
- ``Operations/RoutingAppCoveragesDeleteInstance``
### App Asset Library
- ``Operations/AppAssetLibrariesGetInstance``
- ``Operations/AppAssetLibrariesImagesGetToManyRelationship``
- ``Operations/AppAssetLibrariesImagesGetToManyRelated``
- ``Operations/AppAssetLibrariesVideosGetToManyRelationship``
- ``Operations/AppAssetLibrariesVideosGetToManyRelated``
- ``Operations/AppAssetLibraryImagesCreateInstance``
- ``Operations/AppAssetLibraryImagesGetInstance``
- ``Operations/AppAssetLibraryImagesUpdateInstance``
- ``Operations/AppAssetLibraryImagesDeleteInstance``
- ``Operations/AppAssetLibraryImagesPlacementsGetToManyRelationship``
- ``Operations/AppAssetLibraryImagesPlacementsGetToManyRelated``
- ``Operations/AppAssetLibraryVideosCreateInstance``
- ``Operations/AppAssetLibraryVideosGetInstance``
- ``Operations/AppAssetLibraryVideosUpdateInstance``
- ``Operations/AppAssetLibraryVideosDeleteInstance``
- ``Operations/AppAssetLibraryVideosPlacementsGetToManyRelationship``
- ``Operations/AppAssetLibraryVideosPlacementsGetToManyRelated``
- ``Operations/AppAssetLibraryPlacementsCreateInstance``
- ``Operations/AppAssetLibraryPlacementsGetInstance``
- ``Operations/AppAssetLibraryPlacementsDeleteInstance``
- ``Operations/AppAssetLibraryPlacementOrderingRequestsCreateInstance``
- ``Operations/AppAssetLibraryRefDataGetCollection``
- ``Operations/AppAssetLibraryRefDataGetInstance``
### App Encryption
- ``Operations/AppEncryptionDeclarationsGetCollection``
@@ -579,15 +612,33 @@ These types are used by the ``APIProtocol`` methods and the ``Client`` implement
- ``Operations/InAppPurchasesV2OfferCodesGetToManyRelationship``
- ``Operations/InAppPurchasesV2PricePointsGetToManyRelationship``
- ``Operations/InAppPurchasesV2PromotedPurchaseGetToOneRelationship``
- ``Operations/InAppPurchasesV2VersionsGetToManyRelationship``
- ``Operations/InAppPurchasesV2VersionsGetToManyRelated``
- ``Operations/InAppPurchaseVersionsCreateInstance``
- ``Operations/InAppPurchaseVersionsGetInstance``
- ``Operations/InAppPurchaseVersionsImageGetToOneRelationship``
- ``Operations/InAppPurchaseVersionsImageGetToOneRelated``
- ``Operations/InAppPurchaseVersionsImagesGetToManyRelationship``
- ``Operations/InAppPurchaseVersionsImagesGetToManyRelated``
- ``Operations/InAppPurchaseVersionsLocalizationsGetToManyRelationship``
- ``Operations/InAppPurchaseVersionsLocalizationsGetToManyRelated``
- ``Operations/InAppPurchaseLocalizationsCreateInstance``
- ``Operations/InAppPurchaseLocalizationsGetInstance``
- ``Operations/InAppPurchaseLocalizationsUpdateInstance``
- ``Operations/InAppPurchaseLocalizationsDeleteInstance``
- ``Operations/InAppPurchaseLocalizationsV2CreateInstance``
- ``Operations/InAppPurchaseLocalizationsV2GetInstance``
- ``Operations/InAppPurchaseLocalizationsV2UpdateInstance``
- ``Operations/InAppPurchaseLocalizationsV2DeleteInstance``
- ``Operations/InAppPurchaseContentsGetInstance``
- ``Operations/InAppPurchaseImagesCreateInstance``
- ``Operations/InAppPurchaseImagesGetInstance``
- ``Operations/InAppPurchaseImagesUpdateInstance``
- ``Operations/InAppPurchaseImagesDeleteInstance``
- ``Operations/InAppPurchaseImagesV2CreateInstance``
- ``Operations/InAppPurchaseImagesV2GetInstance``
- ``Operations/InAppPurchaseImagesV2UpdateInstance``
- ``Operations/InAppPurchaseImagesV2DeleteInstance``
- ``Operations/InAppPurchaseAppStoreReviewScreenshotsCreateInstance``
- ``Operations/InAppPurchaseAppStoreReviewScreenshotsGetInstance``
- ``Operations/InAppPurchaseAppStoreReviewScreenshotsUpdateInstance``
@@ -658,6 +709,18 @@ These types are used by the ``APIProtocol`` methods and the ``Client`` implement
- ``Operations/SubscriptionsSubscriptionAvailabilityGetToOneRelated``
- ``Operations/SubscriptionsSubscriptionLocalizationsGetToManyRelated``
- ``Operations/SubscriptionsWinBackOffersGetToManyRelated``
- ``Operations/SubscriptionsPlanAvailabilitiesGetToManyRelationship``
- ``Operations/SubscriptionsPlanAvailabilitiesGetToManyRelated``
- ``Operations/SubscriptionsVersionsGetToManyRelationship``
- ``Operations/SubscriptionsVersionsGetToManyRelated``
- ``Operations/SubscriptionVersionsCreateInstance``
- ``Operations/SubscriptionVersionsGetInstance``
- ``Operations/SubscriptionVersionsImageGetToOneRelationship``
- ``Operations/SubscriptionVersionsImageGetToOneRelated``
- ``Operations/SubscriptionVersionsImagesGetToManyRelationship``
- ``Operations/SubscriptionVersionsImagesGetToManyRelated``
- ``Operations/SubscriptionVersionsLocalizationsGetToManyRelationship``
- ``Operations/SubscriptionVersionsLocalizationsGetToManyRelated``
- ``Operations/SubscriptionGroupsCreateInstance``
- ``Operations/SubscriptionGroupsGetInstance``
- ``Operations/SubscriptionGroupsUpdateInstance``
@@ -666,19 +729,37 @@ These types are used by the ``APIProtocol`` methods and the ``Client`` implement
- ``Operations/SubscriptionGroupsSubscriptionsGetToManyRelationship``
- ``Operations/SubscriptionGroupsSubscriptionGroupLocalizationsGetToManyRelated``
- ``Operations/SubscriptionGroupsSubscriptionsGetToManyRelated``
- ``Operations/SubscriptionGroupsVersionsGetToManyRelationship``
- ``Operations/SubscriptionGroupsVersionsGetToManyRelated``
- ``Operations/SubscriptionGroupVersionsCreateInstance``
- ``Operations/SubscriptionGroupVersionsGetInstance``
- ``Operations/SubscriptionGroupVersionsLocalizationsGetToManyRelationship``
- ``Operations/SubscriptionGroupVersionsLocalizationsGetToManyRelated``
- ``Operations/SubscriptionGroupLocalizationsCreateInstance``
- ``Operations/SubscriptionGroupLocalizationsGetInstance``
- ``Operations/SubscriptionGroupLocalizationsUpdateInstance``
- ``Operations/SubscriptionGroupLocalizationsDeleteInstance``
- ``Operations/SubscriptionGroupLocalizationsV2CreateInstance``
- ``Operations/SubscriptionGroupLocalizationsV2GetInstance``
- ``Operations/SubscriptionGroupLocalizationsV2UpdateInstance``
- ``Operations/SubscriptionGroupLocalizationsV2DeleteInstance``
- ``Operations/SubscriptionGroupSubmissionsCreateInstance``
- ``Operations/SubscriptionLocalizationsCreateInstance``
- ``Operations/SubscriptionLocalizationsGetInstance``
- ``Operations/SubscriptionLocalizationsUpdateInstance``
- ``Operations/SubscriptionLocalizationsDeleteInstance``
- ``Operations/SubscriptionLocalizationsV2CreateInstance``
- ``Operations/SubscriptionLocalizationsV2GetInstance``
- ``Operations/SubscriptionLocalizationsV2UpdateInstance``
- ``Operations/SubscriptionLocalizationsV2DeleteInstance``
- ``Operations/SubscriptionImagesCreateInstance``
- ``Operations/SubscriptionImagesGetInstance``
- ``Operations/SubscriptionImagesUpdateInstance``
- ``Operations/SubscriptionImagesDeleteInstance``
- ``Operations/SubscriptionImagesV2CreateInstance``
- ``Operations/SubscriptionImagesV2GetInstance``
- ``Operations/SubscriptionImagesV2UpdateInstance``
- ``Operations/SubscriptionImagesV2DeleteInstance``
- ``Operations/SubscriptionAppStoreReviewScreenshotsCreateInstance``
- ``Operations/SubscriptionAppStoreReviewScreenshotsGetInstance``
- ``Operations/SubscriptionAppStoreReviewScreenshotsUpdateInstance``
@@ -687,6 +768,12 @@ These types are used by the ``APIProtocol`` methods and the ``Client`` implement
- ``Operations/SubscriptionAvailabilitiesGetInstance``
- ``Operations/SubscriptionAvailabilitiesAvailableTerritoriesGetToManyRelated``
- ``Operations/SubscriptionAvailabilitiesAvailableTerritoriesGetToManyRelationship``
- ``Operations/SubscriptionPlanAvailabilitiesCreateInstance``
- ``Operations/SubscriptionPlanAvailabilitiesGetInstance``
- ``Operations/SubscriptionPlanAvailabilitiesUpdateInstance``
- ``Operations/SubscriptionPlanAvailabilitiesAvailableTerritoriesGetToManyRelationship``
- ``Operations/SubscriptionPlanAvailabilitiesAvailableTerritoriesReplaceToManyRelationship``
- ``Operations/SubscriptionPlanAvailabilitiesAvailableTerritoriesGetToManyRelated``
- ``Operations/SubscriptionGracePeriodsGetInstance``
- ``Operations/SubscriptionGracePeriodsUpdateInstance``
- ``Operations/SubscriptionIntroductoryOffersCreateInstance``
@@ -711,6 +798,7 @@ These types are used by the ``APIProtocol`` methods and the ``Client`` implement
- ``Operations/SubscriptionPricePointsGetInstance``
- ``Operations/SubscriptionPricePointsEqualizationsGetToManyRelated``
- ``Operations/SubscriptionPricePointsEqualizationsGetToManyRelationship``
- ``Operations/SubscriptionPricePointsAdjustedEqualizationsGetToManyRelated``
- ``Operations/SubscriptionPricesCreateInstance``
- ``Operations/SubscriptionPricesDeleteInstance``
- ``Operations/SubscriptionPromotionalOffersCreateInstance``
@@ -771,6 +859,9 @@ These types are used by the ``APIProtocol`` methods and the ``Client`` implement
- ``Operations/GameCenterDetailsGameCenterLeaderboardsV2ReplaceToManyRelationship``
- ``Operations/GameCenterDetailsLeaderboardReleasesGetToManyRelationship``
- ``Operations/GameCenterDetailsLeaderboardSetReleasesGetToManyRelationship``
- ``Operations/GameCenterDetailsBlockedPlayersGetToManyRelationship``
- ``Operations/GameCenterDetailsBlockedPlayersGetToManyRelated``
- ``Operations/GameCenterDetailPlayersUpdateInstance``
- ``Operations/GameCenterGroupsGetCollection``
- ``Operations/GameCenterGroupsCreateInstance``
- ``Operations/GameCenterGroupsGetInstance``
@@ -869,6 +960,9 @@ These types are used by the ``APIProtocol`` methods and the ``Client`` implement
- ``Operations/GameCenterLeaderboardsV2ChallengeUpdateToOneRelationship``
- ``Operations/GameCenterLeaderboardsV2VersionsGetToManyRelationship``
- ``Operations/GameCenterLeaderboardsV2VersionsGetToManyRelated``
- ``Operations/GameCenterLeaderboardsV2GameCenterScoreModerationsGetToManyRelationship``
- ``Operations/GameCenterLeaderboardsV2GameCenterScoreModerationsGetToManyRelated``
- ``Operations/GameCenterScoreModerationsUpdateInstance``
- ``Operations/GameCenterLeaderboardVersionsV2CreateInstance``
- ``Operations/GameCenterLeaderboardVersionsV2GetInstance``
- ``Operations/GameCenterLeaderboardVersionsV2LocalizationsGetToManyRelated``
@@ -1,18 +1,15 @@
# ``Servers``
Server URLs defined in the OpenAPI document.
The App Store Connect API server URLs.
## Overview
The ``Servers`` namespace provides access to the base URLs defined in the App Store Connect API OpenAPI specification. Use these URLs when creating a ``Client`` instance.
The specification defines a single server, `https://api.appstoreconnect.apple.com/`. Pass its URL to ``Client``:
```swift
let client = Client(
serverURL: try Servers.Server1.url(),
transport: URLSessionTransport(),
middlewares: [
BearerAuthMiddleware(token: yourJWTToken)
]
transport: URLSessionTransport()
)
```
@@ -21,4 +18,7 @@ let client = Client(
### Server URLs
- ``Servers/Server1``
### Deprecated
- ``Servers/server1()``
@@ -1,36 +1,78 @@
# ``ASConnectService``
A Swift client library for the App Store Connect API, generated from the official OpenAPI specification.
A type-safe Swift client for the App Store Connect API.
## Overview
``ASConnectService`` provides a type-safe, Swift-native interface to Apple's App Store Connect API. This package enables developers to programmatically interact with App Store Connect services for managing apps, builds, reviews, sales reports, and more.
The library is automatically generated from the official App Store Connect API OpenAPI specification using Apple's [swift-openapi-generator](https://github.com/apple/swift-openapi-generator), ensuring complete API coverage and type safety.
ASConnectService exposes every endpoint of Apple's App Store Connect API as a Swift method with typed requests and responses. It's generated from the official OpenAPI specification with [Swift OpenAPI Generator](https://github.com/apple/swift-openapi-generator).
### Creating a Client
Create a ``Client`` instance by providing a server URL and transport. Use ``BearerAuthMiddleware`` to authenticate requests with a JSON Web Token (JWT).
Create a ``Client`` with a server URL, a transport, and a ``BearerAuthMiddleware``. With an API key from App Store Connect, ``APIKeyTokenProvider`` signs the JSON Web Tokens (JWT) the API requires, and renews them before they expire:
```swift
import ASConnectService
import OpenAPIURLSession
let tokenProvider = try APIKeyTokenProvider(
issuerID: yourIssuerID,
keyID: yourKeyID,
privateKey: yourP8FileContents
)
let client = Client(
serverURL: try Servers.server1(),
serverURL: try Servers.Server1.url(),
transport: URLSessionTransport(),
middlewares: [
BearerAuthMiddleware(token: yourJWTToken)
BearerAuthMiddleware { try await tokenProvider.token() }
]
)
```
### Making API Calls
The ``Client`` conforms to ``APIProtocol``, which defines a method for every endpoint in the App Store Connect API. Each method accepts an `Input` value and returns an `Output` value with the response.
To use a token you signed yourself, pass it directly. It expires after 20 minutes at most:
```swift
let response = try await client.appsGetCollection(.init())
BearerAuthMiddleware(token: yourJWTToken)
```
### Making API Calls
Each endpoint is a method on ``Client``, declared by ``APIProtocol``. It returns an `Output` enum with a case for each documented response:
```swift
let response = try await client.appsGetCollection(query: .init(limit: 10))
let apps = try response.ok.body.json.data
```
The `ok` property throws for any other response. To handle those, switch over the `Output` cases, such as `.unauthorized` or `.undocumented(statusCode:_:)`.
### Fetching More Pages
Lists are paged. Iterate a ``PagedSequence`` to fetch each page in turn:
```swift
let pages = PagedSequence(links: \.links) { cursor in
try await client.appsGetCollection(query: .init(limit: 200, cursor: cursor)).ok.body.json
}
var apps: [Components.Schemas.App] = []
for try await page in pages {
apps += page.data
}
```
To fetch pages yourself, pass a page's ``Components/Schemas/PagedDocumentLinks/nextCursor`` as the `cursor` of the next request.
### Handling Rate Limits
Add ``RateLimitMiddleware`` before the authentication middleware to retry `429 Too Many Requests` responses:
```swift
middlewares: [
RateLimitMiddleware(),
BearerAuthMiddleware { try await tokenProvider.token() }
]
```
## Topics
@@ -43,6 +85,15 @@ let response = try await client.appsGetCollection(.init())
### Authentication
- ``BearerAuthMiddleware``
- ``APIKeyTokenProvider``
### Pagination
- ``PagedSequence``
### Rate Limiting
- ``RateLimitMiddleware``
### Generated Types
@@ -0,0 +1,33 @@
// ===----------------------------------------------------------------------===
//
// This source file is part of the ASConnectService open source project
//
// Copyright (c) 2026 Röck+Cöde VoF. and the ASConnectService project authors
// Licensed under Apache license v2.0
//
// See LICENSE for license information
// See CONTRIBUTORS for the list of ASConnectService project authors
//
// SPDX-License-Identifier: Apache-2.0
//
// ===----------------------------------------------------------------------===
import struct Foundation.URLComponents
extension Components.Schemas.PagedDocumentLinks {
// MARK: Properties
/// The cursor of the next page, or `nil` on the last page.
///
/// Pass it as the `cursor` query parameter of the same operation to fetch the next page.
public var nextCursor: String? {
guard let next else {
return nil
}
return URLComponents(string: next)?
.queryItems?
.first { $0.name == "cursor" }?
.value
}
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -13,38 +13,56 @@
// ===----------------------------------------------------------------------===
import struct Foundation.URL
import struct Foundation.URLComponents
import struct Foundation.URLQueryItem
import struct HTTPTypes.HTTPField
import struct HTTPTypes.HTTPFields
import struct HTTPTypes.HTTPRequest
import struct HTTPTypes.HTTPResponse
import protocol OpenAPIRuntime.ClientMiddleware
import class OpenAPIRuntime.HTTPBody
/// A client middleware that injects a Bearer authentication token into outgoing HTTP requests.
/// A client middleware that authenticates requests with a Bearer token.
///
/// This middleware appends an `Authorization` header with a Bearer token to every request
/// before forwarding it to the next handler in the middleware chain. It is intended for use
/// with the App Store Connect API, which requires JSON Web Token (JWT) authentication.
/// This middleware sets the `Authorization` header of every request to `Bearer <token>`, as the
/// App Store Connect API requires JSON Web Token (JWT) authentication.
///
/// ## Usage
///
/// Provide a fixed token:
///
/// ```swift
/// let middleware = BearerAuthMiddleware(token: "your-jwt-token")
/// ```
///
/// Tokens expire after 20 minutes at most, so long-lived clients should provide a token provider, such as
/// ``APIKeyTokenProvider``:
///
/// ```swift
/// let middleware = BearerAuthMiddleware {
/// try await tokenProvider.token()
/// }
/// ```
public struct BearerAuthMiddleware {
// MARK: Properties
/// The Bearer token to include in the `Authorization` header of each request.
private let token: String
/// The closure that provides the Bearer token for each request.
private let tokenProvider: @Sendable () async throws -> String
// MARK: Initializers
/// Creates a new middleware instance with the given Bearer token.
/// - Parameter token: A JSON Web Token (JWT) string used to authenticate requests to the App Store Connect API.
init(token: String) {
self.token = token
/// Creates a new middleware instance with a fixed Bearer token.
/// - Parameter token: A JSON Web Token (JWT) used to authenticate requests to the App Store Connect API.
public init(
token: String
) {
self.init { token }
}
/// Creates a new middleware instance that asks for a Bearer token on every request.
///
/// If the provider throws, the error is rethrown and the request is not sent.
/// - Parameter tokenProvider: A closure that returns a valid JSON Web Token (JWT).
public init(
tokenProvider: @escaping @Sendable () async throws -> String
) {
self.tokenProvider = tokenProvider
}
}
@@ -68,6 +86,8 @@ extension BearerAuthMiddleware: ClientMiddleware {
operationID: String,
next: @Sendable (HTTPRequest, HTTPBody?, URL) async throws -> (HTTPResponse, HTTPBody?)
) async throws -> (HTTPResponse, HTTPBody?) {
let token = try await tokenProvider()
var request = request
request.headerFields[.authorization] = "Bearer \(token)"
@@ -0,0 +1,149 @@
// ===----------------------------------------------------------------------===
//
// This source file is part of the ASConnectService open source project
//
// Copyright (c) 2026 Röck+Cöde VoF. and the ASConnectService project authors
// Licensed under Apache license v2.0
//
// See LICENSE for license information
// See CONTRIBUTORS for the list of ASConnectService project authors
//
// SPDX-License-Identifier: Apache-2.0
//
// ===----------------------------------------------------------------------===
import struct Foundation.URL
import typealias Foundation.TimeInterval
import struct HTTPTypes.HTTPRequest
import struct HTTPTypes.HTTPResponse
import protocol OpenAPIRuntime.ClientMiddleware
import class OpenAPIRuntime.HTTPBody
/// A client middleware that retries rate-limited requests.
///
/// On a `429 Too Many Requests` response, it waits for the `Retry-After` seconds, or a delay that doubles from
/// `baseDelay`, and retries. It returns the `429` response instead when the retries run out, the delay exceeds
/// `maximumDelay`, or the request body can only be sent once.
///
/// ## Usage
///
/// Place it before ``BearerAuthMiddleware``, so retries get a fresh token:
///
/// ```swift
/// middlewares: [
/// RateLimitMiddleware(),
/// BearerAuthMiddleware { try await tokenProvider.token() }
/// ]
/// ```
public struct RateLimitMiddleware {
// MARK: Properties
/// The maximum number of times a request is retried.
private let maximumRetries: Int
/// The delay before the first retry, when the response has no `Retry-After` header.
private let baseDelay: TimeInterval
/// The longest delay to wait before a retry.
private let maximumDelay: TimeInterval
/// The closure that waits for a given number of seconds.
private let sleep: @Sendable (TimeInterval) async throws -> Void
// MARK: Initializers
/// Creates a new middleware instance.
/// - Parameters:
/// - maximumRetries: The maximum number of times a request is retried.
/// - baseDelay: The delay, in seconds, before the first retry when the response has no `Retry-After` header.
/// - maximumDelay: The longest delay, in seconds, to wait before a retry.
public init(
maximumRetries: Int = 3,
baseDelay: TimeInterval = 1,
maximumDelay: TimeInterval = 60
) {
self.init(
maximumRetries: maximumRetries,
baseDelay: baseDelay,
maximumDelay: maximumDelay,
sleep: { try await Task.sleep(nanoseconds: UInt64($0 * 1_000_000_000)) }
)
}
/// Creates a new middleware instance that waits with `sleep`, for testing.
package init(
maximumRetries: Int,
baseDelay: TimeInterval,
maximumDelay: TimeInterval,
sleep: @escaping @Sendable (TimeInterval) async throws -> Void
) {
self.maximumRetries = maximumRetries
self.baseDelay = baseDelay
self.maximumDelay = maximumDelay
self.sleep = sleep
}
}
// MARK: - ClientMiddleware
extension RateLimitMiddleware: ClientMiddleware {
// MARK: Methods
/// Sends an HTTP request, and retries it while its response is `429 Too Many Requests`.
/// - Parameters:
/// - request: The original HTTP request.
/// - body: The optional body of the request.
/// - baseURL: The base URL for the request.
/// - operationID: The identifier of the API operation being performed.
/// - next: The next handler in the middleware chain.
/// - Returns: The HTTP response and optional body returned by the next handler.
/// - Throws: An error if the next handler throws, or the task is cancelled while waiting.
public func intercept(
_ request: HTTPRequest,
body: HTTPBody?,
baseURL: URL,
operationID: String,
next: @Sendable (HTTPRequest, HTTPBody?, URL) async throws -> (HTTPResponse, HTTPBody?)
) async throws -> (HTTPResponse, HTTPBody?) {
var retries = 0
var backoff = baseDelay
while true {
let (response, responseBody) = try await next(
request,
body,
baseURL
)
guard
response.status == .tooManyRequests,
retries < maximumRetries,
body?.iterationBehavior != .single
else {
return (response, responseBody)
}
let delay = response.retryAfter ?? backoff
guard delay <= maximumDelay else {
return (response, responseBody)
}
try await sleep(delay)
retries += 1
backoff *= 2
}
}
}
// MARK: - HTTPResponse+RetryAfter
private extension HTTPResponse {
/// The seconds in the `Retry-After` header, if any, and never negative.
var retryAfter: TimeInterval? {
headerFields[.retryAfter]
.flatMap { TimeInterval($0) }
.map { max($0, 0) }
}
}
@@ -0,0 +1,189 @@
// ===----------------------------------------------------------------------===
//
// This source file is part of the ASConnectService open source project
//
// Copyright (c) 2026 Röck+Cöde VoF. and the ASConnectService project authors
// Licensed under Apache license v2.0
//
// See LICENSE for license information
// See CONTRIBUTORS for the list of ASConnectService project authors
//
// SPDX-License-Identifier: Apache-2.0
//
// ===----------------------------------------------------------------------===
#if canImport(CryptoKit)
import enum CryptoKit.P256
import struct Foundation.Data
import struct Foundation.Date
import class Foundation.JSONEncoder
import typealias Foundation.TimeInterval
/// A token provider that signs App Store Connect API tokens with an API key.
///
/// Each JSON Web Token (JWT) is reused until a minute before it expires:
///
/// ```swift
/// let tokenProvider = try APIKeyTokenProvider(
/// issuerID: "57246542-96fe-1a63-e053-0824d011072a",
/// keyID: "2X9R4HXF34",
/// privateKey: privateKey
/// )
///
/// let middleware = BearerAuthMiddleware {
/// try await tokenProvider.token()
/// }
/// ```
public actor APIKeyTokenProvider {
// MARK: Properties
/// The issuer ID of a team key, or `nil` for an individual key.
private let issuerID: String?
/// The ID of the API key.
private let keyID: String
/// The private key that signs the tokens.
private let privateKey: P256.Signing.PrivateKey
/// The closure that provides the current date.
private let now: @Sendable () -> Date
/// The last signed token, and its expiration date.
private var current: (token: String, expiresAt: Date)?
// MARK: Initializers
/// Creates a token provider with an App Store Connect API key.
/// - Parameters:
/// - issuerID: The issuer ID of a team key, or `nil` for an individual key.
/// - keyID: The ID of the key.
/// - privateKey: The contents of the key's `.p8` file.
/// - Throws: An error if `privateKey` is not a P-256 private key in PEM format.
public init(
issuerID: String?,
keyID: String,
privateKey: String
) throws {
try self.init(
issuerID: issuerID,
keyID: keyID,
privateKey: privateKey,
now: { Date() }
)
}
/// Creates a token provider that reads the current date from `now`, for testing.
package init(
issuerID: String?,
keyID: String,
privateKey: String,
now: @escaping @Sendable () -> Date
) throws {
self.issuerID = issuerID
self.keyID = keyID
self.privateKey = try P256.Signing.PrivateKey(pemRepresentation: privateKey)
self.now = now
}
// MARK: Methods
/// Returns the current token, or signs a new one if it expires within a minute.
/// - Returns: A JSON Web Token (JWT) valid for 20 minutes at most.
/// - Throws: An error if the token cannot be signed.
public func token() throws -> String {
let date = now()
if let current, current.expiresAt.timeIntervalSince(date) > .refreshMargin {
return current.token
}
let expiresAt = date.addingTimeInterval(.lifetime)
let token = try sign(
issuedAt: date,
expiresAt: expiresAt
)
current = (token, expiresAt)
return token
}
}
// MARK: - Helpers
extension APIKeyTokenProvider {
// MARK: Functions
/// Signs a new token.
/// - Parameters:
/// - issuedAt: The date the token is issued at.
/// - expiresAt: The date the token expires at.
/// - Returns: A JSON Web Token (JWT) signed with the ES256 algorithm.
/// - Throws: An error if the token cannot be encoded or signed.
private func sign(
issuedAt: Date,
expiresAt: Date
) throws -> String {
let encoder = JSONEncoder()
encoder.outputFormatting = .sortedKeys
let header = try encoder.encode(Header(kid: keyID))
let payload = try encoder.encode(
Payload(
iss: issuerID,
sub: issuerID == nil ? "user" : nil,
iat: Int(issuedAt.timeIntervalSince1970),
exp: Int(expiresAt.timeIntervalSince1970)
)
)
let message = "\(header.base64URLEncoded).\(payload.base64URLEncoded)"
let signature = try privateKey.signature(for: Data(message.utf8))
return "\(message).\(signature.rawRepresentation.base64URLEncoded)"
}
}
// MARK: - Header
/// The header of a token.
private struct Header: Encodable {
let alg = "ES256"
let kid: String
let typ = "JWT"
}
// MARK: - Payload
/// The payload of a token.
private struct Payload: Encodable {
let iss: String?
let sub: String?
let iat: Int
let exp: Int
let aud = "appstoreconnect-v1"
}
// MARK: - Data+Base64URL
private extension Data {
/// The Base64URL encoding of the data, without padding.
var base64URLEncoded: String {
base64EncodedString()
.replacingOccurrences(of: "+", with: "-")
.replacingOccurrences(of: "/", with: "_")
.replacingOccurrences(of: "=", with: "")
}
}
// MARK: - TimeInterval+Constants
private extension TimeInterval {
/// The lifetime of a token, which App Store Connect limits to 20 minutes.
static let lifetime: TimeInterval = 20 * 60
/// The time before the expiration of a token when a new one is signed.
static let refreshMargin: TimeInterval = 60
}
#endif
@@ -0,0 +1,117 @@
// ===----------------------------------------------------------------------===
//
// This source file is part of the ASConnectService open source project
//
// Copyright (c) 2026 Röck+Cöde VoF. and the ASConnectService project authors
// Licensed under Apache license v2.0
//
// See LICENSE for license information
// See CONTRIBUTORS for the list of ASConnectService project authors
//
// SPDX-License-Identifier: Apache-2.0
//
// ===----------------------------------------------------------------------===
/// An asynchronous sequence of the pages of a paged operation.
///
/// Each iteration fetches the next page, until a page has no next link:
///
/// ```swift
/// let pages = PagedSequence(links: \.links) { cursor in
/// try await client.appsGetCollection(query: .init(limit: 200, cursor: cursor)).ok.body.json
/// }
///
/// var apps: [Components.Schemas.App] = []
///
/// for try await page in pages {
/// apps += page.data
/// }
/// ```
public struct PagedSequence<Page: Sendable>: AsyncSequence, Sendable {
// MARK: Type aliases
public typealias Element = Page
// MARK: Properties
/// The closure that returns the links of a page.
private let links: @Sendable (Page) -> Components.Schemas.PagedDocumentLinks
/// The closure that fetches the page at a cursor.
private let fetch: @Sendable (String?) async throws -> Page
// MARK: Initializers
/// Creates a sequence of the pages of a paged operation.
/// - Parameters:
/// - links: A closure that returns the links of a page.
/// - fetch: A closure that fetches the page at a cursor, or the first page if the cursor is `nil`.
public init(
links: @escaping @Sendable (Page) -> Components.Schemas.PagedDocumentLinks,
fetch: @escaping @Sendable (_ cursor: String?) async throws -> Page
) {
self.links = links
self.fetch = fetch
}
// MARK: Functions
public func makeAsyncIterator() -> Iterator {
Iterator(
links: links,
fetch: fetch
)
}
}
// MARK: - Iterator
extension PagedSequence {
/// An iterator that fetches one page at a time.
public struct Iterator: AsyncIteratorProtocol {
// MARK: Properties
/// The closure that returns the links of a page.
private let links: @Sendable (Page) -> Components.Schemas.PagedDocumentLinks
/// The closure that fetches the page at a cursor.
private let fetch: @Sendable (String?) async throws -> Page
/// The cursor of the next page, or `nil` for the first page.
private var cursor: String?
/// A Boolean value that indicates whether there are no more pages to fetch.
private var isFinished = false
// MARK: Initializers
init(
links: @escaping @Sendable (Page) -> Components.Schemas.PagedDocumentLinks,
fetch: @escaping @Sendable (String?) async throws -> Page
) {
self.links = links
self.fetch = fetch
}
// MARK: Functions
/// Fetches the next page.
/// - Returns: The next page, or `nil` after the last page.
/// - Throws: The error thrown by the fetch closure, after which the iterator returns `nil`.
public mutating func next() async throws -> Page? {
guard !isFinished else {
return nil
}
// Finishes the iteration if fetching the page throws.
isFinished = true
let page = try await fetch(cursor)
cursor = links(page).nextCursor
isFinished = cursor == nil
return page
}
}
}
@@ -17,3 +17,6 @@ generate:
- client
namingStrategy: idiomatic
accessModifier: public
# Stops swift-format from reformatting the generated code.
additionalFileComments:
- swift-format-ignore-file
File diff suppressed because it is too large. Load diff