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

@ -9,26 +9,26 @@ import type { Asc, J } from './asc';
import { one } from './jsonapi';
import * as rt from '../lib/rt';
/** The draft review submission of the app (READY_FOR_REVIEW, iOS), or null. */
export async function findDraft(c: Asc, appId: string): Promise<string | null> {
return (await c.all(`/v1/reviewSubmissions?filter[app]=${appId}&filter[platform]=IOS&filter[state]=READY_FOR_REVIEW&limit=10`))[0]?.id ?? null;
/** The draft review submission of the app (READY_FOR_REVIEW) on one platform (iOS unless named), or null. */
export async function findDraft(c: Asc, appId: string, platform = 'IOS'): Promise<string | null> {
return (await c.all(`/v1/reviewSubmissions?filter[app]=${appId}&filter[platform]=${platform}&filter[state]=READY_FOR_REVIEW&limit=10`))[0]?.id ?? null;
}
/** The draft's id: the existing one, else a new draft created once. */
export async function draftSubmission(c: Asc, appId: string, root: string, tag: string): Promise<string> {
return (await ensureDraft(c, appId, root, tag)).id;
export async function draftSubmission(c: Asc, appId: string, root: string, tag: string, platform = 'IOS'): Promise<string> {
return (await ensureDraft(c, appId, root, tag, platform)).id;
}
/** The journal key of the draft storebound created (cli/lib/upsert.ts). */
export const draftJournalKey = (appId: string): string => `apple:${appId}:reviewSubmission:draft`;
export const draftJournalKey = (appId: string, platform = 'IOS'): string => `apple:${appId}:reviewSubmission:draft${platform === 'IOS' ? '' : `:${platform}`}`;
/** Like draftSubmission, and says whether this run created the draft (an unused empty one is left: not cancellable). */
export async function ensureDraft(c: Asc, appId: string, root: string, tag: string): Promise<{ id: string; created: boolean }> {
export async function ensureDraft(c: Asc, appId: string, root: string, tag: string, platform = 'IOS'): Promise<{ id: string; created: boolean }> {
const r = await findOrCreate<string>({ what: 'draft review submission', tag, unique: true,
find: () => findDraft(c, appId),
journal: { root, key: draftJournalKey(appId), idOf: id => id,
find: () => findDraft(c, appId, platform),
journal: { root, key: draftJournalKey(appId, platform), idOf: id => id,
byId: async id => { const d = (await c.maybe(`/v1/reviewSubmissions/${id}`))?.data; return d?.attributes?.state === 'READY_FOR_REVIEW' ? id : null; } },
create: async () => (await c.asc('POST', '/v1/reviewSubmissions', { data: { type: 'reviewSubmissions', attributes: { platform: 'IOS' }, relationships: { app: one('apps', appId) } } })).data.id as string });
create: async () => (await c.asc('POST', '/v1/reviewSubmissions', { data: { type: 'reviewSubmissions', attributes: { platform }, relationships: { app: one('apps', appId) } } })).data.id as string });
if (r.created) log(tag, `draft review submission ${r.value} created`);
return { id: r.value, created: r.created };
}
@ -81,10 +81,10 @@ export async function readItems(c: Asc, sid: string): Promise<SubItem[]> {
});
}
/** Every open review submission of the app on iOS (OPEN_STATES), each with its items. `also`: a submission id a 409
* named, read directly (a list may lag behind, or its state may be outside the filter). */
export async function openSubmissions(c: Asc, appId: string, also?: string): Promise<OpenSubmission[]> {
const subs = await c.all(`/v1/apps/${appId}/reviewSubmissions?filter[platform]=IOS&filter[state]=${OPEN_STATES.join(',')}&include=items&limit=50`);
/** Every open review submission of the app on one platform (iOS unless named; OPEN_STATES), each with its items.
* `also`: a submission id a 409 named, read directly (a list may lag behind, or its state may be outside the filter). */
export async function openSubmissions(c: Asc, appId: string, also?: string, platform = 'IOS'): Promise<OpenSubmission[]> {
const subs = await c.all(`/v1/apps/${appId}/reviewSubmissions?filter[platform]=${platform}&filter[state]=${OPEN_STATES.join(',')}&include=items&limit=50`);
if (also && !subs.some((x: J) => x.id === also)) { const d = (await c.maybe(`/v1/reviewSubmissions/${also}`))?.data; if (d) subs.push(d); }
const out: OpenSubmission[] = [];
for (const x of subs) out.push({ id: x.id, state: x.attributes?.state ?? '?', submittedDate: x.attributes?.submittedDate ?? undefined, items: await readItems(c, x.id) });