Skip to content

feat: App Store Connect API 4.5 / 4.5.1 (SDK 4.5.1) - #32

Merged
hanrw merged 14 commits into
mainfrom
feat/asc-api-4.5.1
Oct 10, 2026
Merged

hanrw merged 14 commits into
mainfrom
feat/asc-api-4.5.1

Conversation

@hanrw

@hanrw hanrw commented Oct 10, 2026

Copy link
Copy Markdown
Member

Why

Apple shipped App Store Connect API 4.5 and 4.5.1, and appstoreconnect-swift-sdk 4.5.1 now covers them. 4.5.1 also deprecates app screenshot sets, screenshots, preview sets and previews in favour of the new App Asset Library, which asc screenshots and asc app-previews rely on.

What changed

  • SDK bumped to 4.5.1.
  • Age rating: Korea overrides ALL / TWELVE_PLUS are shown and settable. Before, they came back as no override. gracRatingClassificationNumber is shown and settable.
  • Subscriptions: multiSeatStatus and marketSettings in list; set with update --multi-seat-status / --market-setting. Adds the missing PATCH /api/v1/subscriptions/:id.
  • Performance: asc perf-overview get shows regressions, Xcode metrics against Apple's goals, and the top hang/launch/disk-write hotspots.
  • Game Center moderation: score-moderations list|block|unblock, blocked-players list, players block|unblock. Game Center detail, leaderboards and achievements are now also on REST.
  • App Asset Library: asset-library, asset-placement-groups, asset-images, asset-videos (list / upload --wait / update / delete) and asset-placements (list / create / delete / reorder) on version and experiment-treatment localizations, including IPHONE_DUO.
    • The SDK can't decode placements and generates broken create/reorder bodies, so asc uses its own types for both.
    • The deprecated screenshot and preview commands keep working and say so in --help.
  • Internals:
    • RESTPathResolver supports several parents per command and an explicit resource param.
    • A shared UploadOperationsExecutor, now also used by the IAP review upload.
  • Contributor skills: tests are named should <outcome> [when <situation>], and there's a new fix-bug skill.

How it was verified

  • Every change started with a failing state-based test; red was confirmed before code under Sources/.
  • swift test: 651 + 1387 + 740 tests pass. make docs && make check-docs: 0 problems.
  • Live, read-only: GET /v1/apps/{id}/performanceOverviews returns an XcodeOverview document (application/vnd.apple.xcode-overview+json). The redacted empty response is a test fixture.

Not yet verified against a live account (follow-up PRs):

  • Asset Library upload → place → reorder → delete, which exercises the hand-built placement bodies.
  • Whether v1 leaderboard IDs work on the v2 score-moderation endpoint, and whether Apple accepts unblocking a score.
  • A populated performance overview; no test app has data yet.

Checklist

  • A failing test came first; swift test passes
  • A command that returns data is also served by asc web-server
  • User-visible change: one line under ## [Unreleased] in CHANGELOG.md
  • make docs && make check-docs passes
  • No API key, .p8, issuer ID or Apple ID session in the diff, output or screenshots

🤖 Generated with Claude Code

hanrw and others added 14 commits October 10, 2026 22:24
…ix-bug skill

Adopt claudebar's business-shaped test naming: names describe what the
person, agent or REST client observes, never a method, type or mechanism
verb. Add a fix-bug skill (reproduce, find the owning layer, failing
`should` test, minimal fix). Fix two misleading examples in tdd-patterns
(a test that asserted on its own mock; MockAPIProvider → StubAPIClient).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…K to 4.5.1

App Store Connect API 4.5 added ALL and TWELVE_PLUS to
koreaAgeRatingOverride. Our domain enum lacked them, so the mapper's
init(rawValue:) turned them into nil: the CLI and REST showed no Korea
override and rejected the new values on update.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
App Store Connect API 4.5 added `multiSeatStatus` (ENABLED/DISABLED) and
`marketSettings` (APP_STORE/APPLE_SCHOOL/APPLE_BUSINESS) on Subscription.

- `asc subscriptions list` (and REST) include both when ASC sends them;
  omitted when absent.
- `asc subscriptions update --multi-seat-status --market-setting` (repeatable)
  sets them; `create` stays read-only because SubscriptionCreateRequest
  does not accept them.
- New `PATCH /api/v1/subscriptions/:id` route (already advertised by the
  `update` _link) takes the same keys as the CLI update flags.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s goals and top hotspots

One call to App Store Connect's performanceOverviews endpoint (Xcode Organizer
overview) now answers "what regressed in the latest version?": regressions and
trending-up insights with Apple's summary and impact, each metric's latest value
next to Apple's recommended goal, and the top hang, launch and disk-write
hotspots with their trend. Optional --device-type narrows it.

Also over REST at GET /api/v1/apps/:appId/perf-overview?device-type=, and every
app now advertises getPerfOverview in its affordances / _links.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…me Center over REST

- asc game-center score-moderations list|block|unblock, blocked-players list,
  players block|unblock (new GameCenterModerationRepository, SDK adapter with
  pagination and included-player mapping)
- GameCenterDetail/GameCenterLeaderboard migrated to structuredAffordances +
  Presentable; add listBlockedPlayers / listScoreModerations affordances
- GameCenterController serves detail, leaderboards, delete, score moderation
  and player routes; _gameCenterRoutes registered in RESTPathResolver
- docs/features/game-center updated with moderation workflow and REST table

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	Sources/Domain/Shared/RESTPathResolver.swift
#	Tests/ASCCommandTests/Commands/Web/RESTRoutesTests.swift
The Game Center detail's REST _links pointed at
/game-center/details/{id}/achievements, which no route served. Move
GameCenterAchievement to structuredAffordances (CLI strings unchanged),
add Presentable, and serve GET achievements and DELETE achievement.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ace them

App Store Connect API 4.5.1 added the App Asset Library: upload an image once
into a per-app library, then place it into slots on localizations.

- `asc asset-library get --app-id` shows the app's library.
- `asc asset-placement-groups list [--placement-type] [--feature]` flattens
  the reference data into one row per type + group (+ feature limit) with
  platform, display class, accepted sizes and maxCount.
- `asc asset-images list|upload|delete`: upload reserves, streams the parts
  from disk and commits with `uploaded: true`; `--wait` polls until
  processed. Images/placements show state-aware affordances (place only when
  processed, refresh while processing, delete hidden in review).
- `asc asset-placements list|create|delete|reorder` on version localizations;
  `list --image-id` shows everywhere an image is placed; positions are the
  1-based display order within each type + group.
- REST: /apps/:id/asset-library, /asset-placement-groups,
  /asset-library/:id/images, /asset-images/:id(/placements),
  /version-localizations/:id/placements(/reorder), /asset-placements/:id.
- RESTPathResolver accepts several parent routes per command; App and
  version localizations link to the new resources.

SDK workarounds: placements, images and reference data decode into our own
DTOs (SDK expects placement `mediaType` in relationships; image/video states
and ref-data enums would throw on new values). Placement create and ordering
bodies are hand-built. Upload parts go through a new shared
UploadOperationsExecutor (extracted from the IAP review uploader, which now
uses it).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e and archive

- `asc asset-videos list|upload|update|delete`: upload takes
  `--preview-frame-time-code` and streams parts from disk; `--wait` polls
  until processed. Videos show preview frame state/URL and the processed
  video URL; `place` suggests APP_PREVIEW.
- `asc asset-images update` / `asset-videos update` rename
  (`--reference-name`) or archive (`--archived true`); approved assets offer
  an `archive` affordance.
- `asc asset-placements list|create|reorder --treatment-localization-id`
  for product page optimization treatments; `list|create --video-id`.
  Treatment localizations link to their placements.
- REST: /asset-library/:id/videos (GET/POST, 500 MB upload ceiling),
  PATCH/DELETE /asset-videos/:id, GET /asset-videos/:id/placements,
  PATCH /asset-images/:id, /experiment-treatment-localizations/:id/placements
  (+ /reorder).
- RESTPathResolver routes accept a `resourceParam`, so `update --image-id X
  --library-id L` addresses /asset-images/X rather than the library's
  collection. `update` takes `--library-id` because App Store Connect's
  PATCH response doesn't name the library.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- docs/features/asset-library/README.md: quick start, upload → wait →
  place → reorder, treatments, migrating from screenshot sets, REST table,
  gotchas (placements before assets, fixed category, per-feature limits,
  editable parent, IPHONE_DUO).
- `screenshot-sets`, `screenshots`, `app-preview-sets` and `app-previews`
  --help now say Apple deprecated them (behaviour unchanged); their docs
  point to the asset library.
- CHANGELOG, README "What It Covers" row, regenerated docs/commands.md and
  docs/README.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	CHANGELOG.md
#	Sources/Domain/Shared/RESTPathResolver.swift
#	Tests/ASCCommandTests/Commands/Apps/AppsListTests.swift
#	Tests/ASCCommandTests/Commands/Apps/AppsUpdateTests.swift
#	Tests/ASCCommandTests/Commands/Web/RESTRoutesTests.swift
#	Tests/ASCCommandTests/OutputFormatterTests.swift
#	Tests/DomainTests/TestHelpers/MockRepositoryFactory.swift
#	docs/commands.md
App Store Connect API 4.5 added gracRatingClassificationNumber to
age rating declarations. Read it, and accept it on update from the CLI
(--grac-rating-classification-number) and REST.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 10, 2026

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 126 files, which is 26 over the limit of 100.

To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch.

Upgrade to a paid plan to raise the limit.

This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry.

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 496503e9-310b-47f3-b898-4e0bb6fb5608

📥 Commits

Reviewing files that changed from the base of the PR and between 79d213a and 1486c12.


⛔ Files ignored due to path filters (1)
  • Package.resolved is excluded by !**/Package.resolved

📒 Files selected for processing (126)
  • .claude/skills/fix-bug/SKILL.md
  • .claude/skills/implement-feature/SKILL.md
  • .claude/skills/implement-feature/references/tdd-patterns.md
  • .claude/skills/improvement/SKILL.md
  • CHANGELOG.md
  • CLAUDE.md
  • Package.swift
  • README.md
  • Sources/ASCCommand/ASC.swift
  • Sources/ASCCommand/ClientProvider.swift
  • Sources/ASCCommand/Commands/AgeRating/AgeRatingCommand.swift
  • Sources/ASCCommand/Commands/AppPreviewSets/AppPreviewSetsCommand.swift
  • Sources/ASCCommand/Commands/AppPreviews/AppPreviewsCommand.swift
  • Sources/ASCCommand/Commands/AssetLibrary/AssetImagesCommand.swift
  • Sources/ASCCommand/Commands/AssetLibrary/AssetLibraryCommand.swift
  • Sources/ASCCommand/Commands/AssetLibrary/AssetPlacementsCommand.swift
  • Sources/ASCCommand/Commands/AssetLibrary/AssetVideosCommand.swift
  • Sources/ASCCommand/Commands/GameCenter/GameCenterCommand.swift
  • Sources/ASCCommand/Commands/GameCenter/GameCenterModerationCommand.swift
  • Sources/ASCCommand/Commands/Performance/PerfOverviewCommand.swift
  • Sources/ASCCommand/Commands/ScreenshotSets/ScreenshotSetsCommand.swift
  • Sources/ASCCommand/Commands/Screenshots/ScreenshotsCommand.swift
  • Sources/ASCCommand/Commands/Subscriptions/SubscriptionsUpdate.swift
  • Sources/ASCCommand/Commands/Web/Controllers/AgeRatingController.swift
  • Sources/ASCCommand/Commands/Web/Controllers/AssetLibraryController.swift
  • Sources/ASCCommand/Commands/Web/Controllers/GameCenterController.swift
  • Sources/ASCCommand/Commands/Web/Controllers/PerfOverviewController.swift
  • Sources/ASCCommand/Commands/Web/Controllers/SubscriptionsController.swift
  • Sources/ASCCommand/Commands/Web/RESTRoutes.swift
  • Sources/Domain/Apps/App.swift
  • Sources/Domain/Apps/AppInfos/AgeRatingDeclaration.swift
  • Sources/Domain/Apps/AssetLibrary/AppAssetLibrary.swift
  • Sources/Domain/Apps/AssetLibrary/AssetLibrary+RESTRoutes.swift
  • Sources/Domain/Apps/AssetLibrary/AssetLibraryRepository.swift
  • Sources/Domain/Apps/AssetLibrary/AssetLibraryTypes.swift
  • Sources/Domain/Apps/AssetLibrary/Images/LibraryImage.swift
  • Sources/Domain/Apps/AssetLibrary/Images/LibraryImageRepository.swift
  • Sources/Domain/Apps/AssetLibrary/Placements/AssetPlacement.swift
  • Sources/Domain/Apps/AssetLibrary/Placements/AssetPlacementRepository.swift
  • Sources/Domain/Apps/AssetLibrary/RefData/AssetPlacementGroup.swift
  • Sources/Domain/Apps/AssetLibrary/Videos/LibraryVideo.swift
  • Sources/Domain/Apps/AssetLibrary/Videos/LibraryVideoRepository.swift
  • Sources/Domain/Apps/Experiments/ExperimentTreatmentLocalization.swift
  • Sources/Domain/Apps/Performance/PerfOverviewRepository.swift
  • Sources/Domain/Apps/Performance/PerformanceOverview.swift
  • Sources/Domain/Apps/Subscriptions/Subscription.swift
  • Sources/Domain/Apps/Subscriptions/SubscriptionRepository.swift
  • Sources/Domain/Apps/Versions/Localizations/AppStoreVersionLocalization.swift
  • Sources/Domain/GameCenter/GameCenter+RESTRoutes.swift
  • Sources/Domain/GameCenter/GameCenterAchievement.swift
  • Sources/Domain/GameCenter/GameCenterDetail.swift
  • Sources/Domain/GameCenter/GameCenterLeaderboard.swift
  • Sources/Domain/GameCenter/Moderation/GameCenterModerationRepository.swift
  • Sources/Domain/GameCenter/Moderation/GameCenterPlayer.swift
  • Sources/Domain/GameCenter/Moderation/GameCenterScoreModeration.swift
  • Sources/Domain/Shared/APIRoot.swift
  • Sources/Domain/Shared/RESTPathResolver.swift
  • Sources/Infrastructure/Apps/AppInfos/SDKAgeRatingDeclarationRepository.swift
  • Sources/Infrastructure/Apps/AssetLibrary/AssetLibraryDTOs.swift
  • Sources/Infrastructure/Apps/AssetLibrary/Images/SDKLibraryImageRepository.swift
  • Sources/Infrastructure/Apps/AssetLibrary/Placements/AssetPlacementDTOs.swift
  • Sources/Infrastructure/Apps/AssetLibrary/Placements/SDKAssetPlacementRepository.swift
  • Sources/Infrastructure/Apps/AssetLibrary/SDKAssetLibraryRepository.swift
  • Sources/Infrastructure/Apps/AssetLibrary/Videos/SDKLibraryVideoRepository.swift
  • Sources/Infrastructure/Apps/InAppPurchases/Review/SDKInAppPurchaseReviewRepository.swift
  • Sources/Infrastructure/Apps/Performance/SDKPerfOverviewRepository.swift
  • Sources/Infrastructure/Apps/Subscriptions/SDKSubscriptionRepository.swift
  • Sources/Infrastructure/Client/ClientFactory.swift
  • Sources/Infrastructure/GameCenter/Moderation/SDKGameCenterModerationRepository.swift
  • Sources/Infrastructure/Shared/UploadOperationsExecutor.swift
  • Tests/ASCCommandTests/Commands/AgeRating/AgeRatingUpdateTests.swift
  • Tests/ASCCommandTests/Commands/Apps/AppsListTests.swift
  • Tests/ASCCommandTests/Commands/Apps/AppsUpdateTests.swift
  • Tests/ASCCommandTests/Commands/AssetLibrary/AssetImagesCommandTests.swift
  • Tests/ASCCommandTests/Commands/AssetLibrary/AssetLibraryCommandTests.swift
  • Tests/ASCCommandTests/Commands/AssetLibrary/AssetPlacementsCommandTests.swift
  • Tests/ASCCommandTests/Commands/AssetLibrary/AssetVideosCommandTests.swift
  • Tests/ASCCommandTests/Commands/AssetLibrary/DeprecatedMediaCommandsTests.swift
  • Tests/ASCCommandTests/Commands/Experiments/ExperimentTreatmentLocalizationsTests.swift
  • Tests/ASCCommandTests/Commands/GameCenter/GameCenterCommandTests.swift
  • Tests/ASCCommandTests/Commands/GameCenter/GameCenterModerationCommandTests.swift
  • Tests/ASCCommandTests/Commands/Performance/PerfOverviewGetTests.swift
  • Tests/ASCCommandTests/Commands/Subscriptions/SubscriptionsListTests.swift
  • Tests/ASCCommandTests/Commands/Subscriptions/SubscriptionsUpdateTests.swift
  • Tests/ASCCommandTests/Commands/VersionLocalizations/VersionLocalizationsCreateTests.swift
  • Tests/ASCCommandTests/Commands/VersionLocalizations/VersionLocalizationsListTests.swift
  • Tests/ASCCommandTests/Commands/VersionLocalizations/VersionLocalizationsUpdateTests.swift
  • Tests/ASCCommandTests/Commands/Web/AssetLibraryControllerTests.swift
  • Tests/ASCCommandTests/Commands/Web/RESTRoutesTests.swift
  • Tests/ASCCommandTests/Commands/Web/SubscriptionsControllerTests.swift
  • Tests/ASCCommandTests/OutputFormatterTests.swift
  • Tests/DomainTests/Apps/AppInfos/AgeRatingDeclarationTests.swift
  • Tests/DomainTests/Apps/AssetLibrary/AppAssetLibraryTests.swift
  • Tests/DomainTests/Apps/AssetLibrary/Images/LibraryAssetStateTests.swift
  • Tests/DomainTests/Apps/AssetLibrary/Images/LibraryImageTests.swift
  • Tests/DomainTests/Apps/AssetLibrary/Placements/AssetPlacementTests.swift
  • Tests/DomainTests/Apps/AssetLibrary/RefData/AssetPlacementGroupTests.swift
  • Tests/DomainTests/Apps/AssetLibrary/Videos/LibraryVideoTests.swift
  • Tests/DomainTests/Apps/Experiments/ExperimentTreatmentLocalizationTests.swift
  • Tests/DomainTests/Apps/Performance/PerformanceOverviewTests.swift
  • Tests/DomainTests/Apps/Subscriptions/SubscriptionTests.swift
  • Tests/DomainTests/Apps/Versions/Localizations/AppStoreVersionLocalizationTests.swift
  • Tests/DomainTests/GameCenter/GameCenterTests.swift
  • Tests/DomainTests/GameCenter/Moderation/GameCenterModerationTests.swift
  • Tests/DomainTests/Shared/AffordanceTests.swift
  • Tests/DomainTests/TestHelpers/MockRepositoryFactory.swift
  • Tests/InfrastructureTests/Apps/AppInfos/SDKAgeRatingDeclarationRepositoryTests.swift
  • Tests/InfrastructureTests/Apps/AssetLibrary/Images/SDKLibraryImageRepositoryTests.swift
  • Tests/InfrastructureTests/Apps/AssetLibrary/Placements/SDKAssetPlacementRepositoryTests.swift
  • Tests/InfrastructureTests/Apps/AssetLibrary/SDKAssetLibraryRepositoryTests.swift
  • Tests/InfrastructureTests/Apps/AssetLibrary/Videos/SDKLibraryVideoRepositoryTests.swift
  • Tests/InfrastructureTests/Apps/Performance/SDKPerfOverviewRepositoryTests.swift
  • Tests/InfrastructureTests/Apps/Subscriptions/SDKSubscriptionRepositoryTests.swift
  • Tests/InfrastructureTests/GameCenter/Moderation/SDKGameCenterModerationRepositoryTests.swift
  • Tests/InfrastructureTests/Shared/UploadOperationsExecutorTests.swift
  • docs/README.md
  • docs/commands.md
  • docs/features/age-rating/README.md
  • docs/features/app-previews/README.md
  • docs/features/asset-library/README.md
  • docs/features/game-center/README.md
  • docs/features/iap-subscriptions/README.md
  • docs/features/iap-subscriptions/lifecycle.md
  • docs/features/performance/README.md
  • docs/features/screenshots/README.md
  • docs/prompts/app-shots-weather-demo.md

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant