Screenshot guardrails: name every screenshot not COMPLETE on 409 ASSET_IN_POST_PROCESSING (submit, validate; stuck after 5 min in UPLOAD_COMPLETE), apple screenshots --repair-stuck replaces only those in place, part uploads without Expect: 100-continue (failed part deletes the reservation, one retry, never committed), storebound api --confirm <operationId> for agents' plain writes (never owner-only)

This commit is contained in:
CRTkafa 2026-10-21 12:40:26 +07:00
parent 164182012f
commit 00756e6908
19 changed files with 475 additions and 45 deletions

View file

@ -20,6 +20,7 @@ import { allVersions, type AscPlatform, parsePlatform, platformOf, stateOf, vers
import { capabilityReport } from './apple/signing';
import { firstProductReport } from './apple/first-products';
import { requiredDisplayTypes } from './apple/screenshots';
import { pendingScreenshots, setRows, type ShotRow, updateLedger } from './apple/screenshot-health';
import { type Loaded, playCategoryOf, playCodes, profileOf, sellsOn } from './lib/config';
import { reviewDemoAccount } from './lib/credentials';
import { allSubscriptions, basePlanId } from './lib/subscriptions';
@ -80,6 +81,7 @@ export async function collectApple(ctx: Ctx): Promise<AppleSnapshot> {
let build: AppleSnapshot['build'] = null;
const locales: AppleSnapshot['locales'] = [];
let reviewDetail: AppleSnapshot['reviewDetail'] = null;
const shotRows: ShotRow[] = [];
if (v) {
const b = (await c.maybe(`/v1/appStoreVersions/${v.id}/build`))?.data;
if (b) {
@ -92,7 +94,11 @@ export async function collectApple(ctx: Ctx): Promise<AppleSnapshot> {
for (const l of await c.all(`/v1/appStoreVersions/${v.id}/appStoreVersionLocalizations?limit=50`)) {
const sets = await c.all(`/v1/appStoreVersionLocalizations/${l.id}/appScreenshotSets?limit=50`);
const screenshots: Record<string, number> = {};
for (const s of sets) screenshots[s.attributes.screenshotDisplayType] = (await c.all(`/v1/appScreenshotSets/${s.id}/appScreenshots?limit=50`)).length;
for (const s of sets) {
const shots = await c.all(`/v1/appScreenshotSets/${s.id}/appScreenshots?limit=50`);
screenshots[s.attributes.screenshotDisplayType] = shots.length;
shotRows.push(...setRows(shots, l.attributes.locale, s.attributes.screenshotDisplayType));
}
const ia = infoLocs.get(l.attributes.locale) ?? {};
locales.push({ locale: l.attributes.locale, name: ia.name, subtitle: ia.subtitle, description: l.attributes.description, keywords: l.attributes.keywords, screenshots });
}
@ -132,6 +138,7 @@ export async function collectApple(ctx: Ctx): Promise<AppleSnapshot> {
version: v ? { versionString: v.attributes.versionString, state: v.attributes.appVersionState ?? v.attributes.appStoreState, copyright: v.attributes.copyright ?? null, platform } : null,
otherPlatformVersions,
creativeWaiting: await creativeWaitingOf(ctx, c, appId),
screenshotsPending: pendingScreenshots(shotRows, updateLedger(root, shotRows), Date.now()),
configCopyright: config.app.copyright,
build, locales, reviewDetail, ageRating,
expectedLocales: config.languages.map(l => l.apple).filter((x): x is string => !!x),