Drift on existing items: offer-code and win-back campaigns that differ are named (Apple cannot edit them), in-app event attributes patched on drafts, a removed custom page deep link cleared, config languages without a version localization named, data safety dry run says Play has no read API; appinfo reads /v1/appPriceSchedules/{id}/manualPrices; a new Play language without an icon warns instead of stopping; fake store lists for the new reads

This commit is contained in:
CRTkafa 2026-10-22 20:38:54 +08:00
parent f2b841d735
commit e381bc2256
11 changed files with 206 additions and 10 deletions

View file

@ -11,7 +11,7 @@ import { existsSync } from 'node:fs';
import { join } from 'node:path';
import type { Ctx } from '../lib/ctx';
import { byAppleLocale, confirm, need } from '../lib/ctx';
import { CPP_EDITABLE, CPP_LIMITS, cppCreateBody, cppLocales, type CustomProductPageDef, planCppLocales, reviewItemReq } from '../lib/cpp-events';
import { CPP_EDITABLE, CPP_LIMITS, cppCreateBody, cppDeepLinkReq, cppLocales, type CustomProductPageDef, extraCppLocales, planCppLocales, reviewItemReq } from '../lib/cpp-events';
import { done, log, printJson, warn } from '../lib/log';
import { textTable } from '../lib/table';
import { numberedImages } from '../play/images';
@ -73,8 +73,10 @@ export async function run(ctx: Ctx): Promise<void> {
if (!page.version || !CPP_EDITABLE.has(page.version.state)) { log(TAG, `"${d.name}": version ${page.version?.state ?? 'missing'}, not editable (a new version: App Store Connect)`); continue; }
const have = (await c.all(`/v1/appCustomProductPageVersions/${page.version.id}/appCustomProductPageLocalizations?limit=200`)).map((l: J) => ({ id: l.id, locale: l.attributes.locale, promotionalText: l.attributes.promotionalText }));
reqs.push(...planCppLocales(page.version.id, have, locs));
if ((d.deepLink ?? null) !== (page.version.deepLink ?? null) && d.deepLink) reqs.push({ method: 'PATCH', path: `/v1/appCustomProductPageVersions/${page.version.id}`, note: `"${d.name}" deep link`,
body: { data: { type: 'appCustomProductPageVersions', id: page.version.id, attributes: { deepLink: d.deepLink } } } });
const extra = extraCppLocales(have.map(h => h.locale), locs.map(l => l.locale));
if (extra.length) warn(TAG, `"${d.name}": locale(s) ${extra.join(', ')} are on the page but not in the config languages (not removed)`);
const dl = cppDeepLinkReq(page.version.id, d.name, d.deepLink, page.version.deepLink);
if (dl) reqs.push(dl);
}
if (pages.length + reqs.filter(r => r.path === '/v1/appCustomProductPages').length > CPP_LIMITS.pages) throw new Error(`more than ${CPP_LIMITS.pages} custom product pages`);
if (a.has('json')) printJson({ dryRun: dry, requests: reqs.map(r => describeReq(r)) });