apple: macOS (tvOS, visionOS) versions are no longer invisible: every version and review submission lookup is per platform; status, listing, listing pull, resubmit, submit, release and screenshots take --platform and otherwise pick the platform that has the version they need (refuse naming both when several do); status, validate, release status, the report and the desktop label versions with their platform; MCP and owner actions get platform; pitfall 77

This commit is contained in:
CRTkafa 2026-10-20 03:00:05 +07:00
parent 1736300784
commit 47dfd372fe
30 changed files with 423 additions and 127 deletions

View file

@ -26,8 +26,9 @@ import { addItem, draftJournalKey, ensureDraft, leaveUnusedDraft, openSubmission
const TAG = 'iap-submit';
export async function readSubmitState(c: Asc, appId: string, want: string[], o: { appVersionId?: string; also?: string } = {}): Promise<SubmitState> {
const appVersions = (await c.all(`/v1/apps/${appId}/appStoreVersions?filter[platform]=IOS&limit=50`)).map((v: J) => ({ id: v.id, versionString: v.attributes.versionString,
export async function readSubmitState(c: Asc, appId: string, want: string[], o: { appVersionId?: string; also?: string; platform?: string } = {}): Promise<SubmitState> {
const platform = o.platform ?? 'IOS';
const appVersions = (await c.all(`/v1/apps/${appId}/appStoreVersions?filter[platform]=${platform}&limit=50`)).map((v: J) => ({ id: v.id, versionString: v.attributes.versionString,
state: v.attributes.appVersionState ?? v.attributes.appStoreState }));
const iaps: PIap[] = [];
for (const p of await c.all(`/v1/apps/${appId}/inAppPurchasesV2?limit=200`)) {
@ -45,7 +46,7 @@ export async function readSubmitState(c: Asc, appId: string, want: string[], o:
versions: want.includes(s.attributes.productId) ? versionsOf(await c.all(`/v1/subscriptions/${s.id}/versions?limit=200`)) : [] });
}
// every open review submission: a draft or one back from App Review is reused, never a second one next to it
const open = await openSubmissions(c, appId, o.also);
const open = await openSubmissions(c, appId, o.also, platform);
const choice = chooseSubmission(open, { appVersionId: o.appVersionId ?? appVersions.find((v: { state: string }) => /REJECTED|INVALID_BINARY/.test(v.state))?.id });
const draft: SubmitState['draft'] = choice.action === 'reuse' ? { id: choice.sub.id, state: choice.sub.state, itemVersionIds: choice.sub.items.map(i => i.versionId) } : null;
return { appVersions, iaps, subs, groups, draft, open, choice };
@ -96,6 +97,8 @@ export interface SubmitOpts {
appId: string; ids: string[]; state: SubmitState; tag: string; withVersion?: boolean;
/** the app version that must be in the submission (resubmit) */
appVersionId?: string;
/** the App Store platform of the version and the submission (default iOS) */
platform?: string;
/** the caller printed its own plan (resubmit) */
quiet?: boolean;
/** REJECTED items marked resolved before the submit (resubmit: the version item; --resolve-iaps: the rest) */
@ -116,7 +119,7 @@ export async function submitPlanned(ctx: Ctx, c: Asc, o: SubmitOpts): Promise<vo
const a = ctx.args;
const dry = a.has('dry');
const { state, tag } = o;
const plan = planIapSubmission(state, o.ids, { withVersion: o.withVersion, appVersionId: o.appVersionId });
const plan = planIapSubmission(state, o.ids, { withVersion: o.withVersion, appVersionId: o.appVersionId, platform: o.platform });
const prepare = plan.prepare.map(r => bindIds(r, { app: o.appId }));
const submitting = willSubmit(state, plan);
const busy = state.choice?.action === 'busy';
@ -155,7 +158,7 @@ export async function submitPlanned(ctx: Ctx, c: Asc, o: SubmitOpts): Promise<vo
// already in it, and an item the store says is in there already (409) is not added twice
let sid = state.draft?.id;
let created = false;
if (!sid) ({ id: sid, created } = await ensureDraft(c, o.appId, root, tag));
if (!sid) ({ id: sid, created } = await ensureDraft(c, o.appId, root, tag, o.platform));
try {
for (const r of prepare) {
if (r.path === '/v1/reviewSubmissions') continue;
@ -175,7 +178,7 @@ export async function submitPlanned(ctx: Ctx, c: Asc, o: SubmitOpts): Promise<vo
if (o.retried || e.otherId === '?') throw e;
// use the submission the 409 named: read the state again with it and go once more
log(tag, `using review submission ${e.otherId} instead`);
const again = await readSubmitState(c, o.appId, o.ids, { appVersionId: o.appVersionId ?? plan.appVersion?.id, also: e.otherId });
const again = await readSubmitState(c, o.appId, o.ids, { appVersionId: o.appVersionId ?? plan.appVersion?.id, also: e.otherId, platform: o.platform });
for (const l of choiceLines(again)) log(tag, l);
await submitPlanned(ctx, c, { ...o, state: again, retried: true, quiet: true });
return;