47 lines
3.3 KiB
TypeScript
47 lines
3.3 KiB
TypeScript
// The app's one draft review submission and the items in it, without duplicates: a draft (READY_FOR_REVIEW) is
|
|
// reused, a new one is created only after a fresh look (Apple keeps one open draft per app and platform), and an item
|
|
// already in the draft is not added again (a 409 or a re-read finds it). Used by iap-submit, cpp submit and events
|
|
// submit. Submitting itself (PATCH submitted: true) stays the owner's confirmed step in those commands.
|
|
import { log } from '../lib/log';
|
|
import { createOnce, findOrCreate } from '../lib/upsert';
|
|
import type { Asc, J } from './asc';
|
|
import { one } from './jsonapi';
|
|
|
|
/** 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'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> {
|
|
const r = await findOrCreate<string>({ what: 'draft review submission', tag, unique: true,
|
|
find: () => findDraft(c, appId),
|
|
journal: { root, key: `apple:${appId}:reviewSubmission:draft`, 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 });
|
|
if (r.created) log(tag, `draft review submission ${r.value} created`);
|
|
return r.value;
|
|
}
|
|
|
|
const TYPE: Record<string, string> = {
|
|
appStoreVersion: 'appStoreVersions', inAppPurchaseVersion: 'inAppPurchaseVersions', subscriptionVersion: 'subscriptionVersions',
|
|
subscriptionGroupVersion: 'subscriptionGroupVersions', appCustomProductPageVersion: 'appCustomProductPageVersions', appEvent: 'appEvents',
|
|
appStoreVersionExperiment: 'appStoreVersionExperiments',
|
|
};
|
|
|
|
/** Whether the draft already holds `id` as `kind` (e.g. inAppPurchaseVersion). */
|
|
export async function inDraft(c: Asc, sid: string, kind: string, id: string): Promise<boolean> {
|
|
const items = await c.all(`/v1/reviewSubmissions/${sid}/items?include=${kind}&limit=200`);
|
|
return items.some((it: J) => it.relationships?.[kind]?.data?.id === id);
|
|
}
|
|
|
|
/** Adds one item to the draft unless it is in there already (`checked`: the caller read the draft's items a moment
|
|
* ago). true when it was added now. */
|
|
export async function addItem(c: Asc, sid: string, kind: string, id: string, label: string, tag: string, o: { checked?: boolean } = {}): Promise<boolean> {
|
|
if (!o.checked && await inDraft(c, sid, kind, id)) { log(tag, `${label}: already in draft ${sid}`); return false; }
|
|
const r = await createOnce({ what: `${label} in draft ${sid}`, tag, unique: true,
|
|
find: async () => ((await inDraft(c, sid, kind, id)) ? id : null),
|
|
create: async () => (await c.asc('POST', '/v1/reviewSubmissionItems', { data: { type: 'reviewSubmissionItems',
|
|
relationships: { reviewSubmission: one('reviewSubmissions', sid), [kind]: one(TYPE[kind] ?? `${kind}s`, id) } } })).data?.id ?? id });
|
|
return r.created;
|
|
}
|