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

@ -50,6 +50,10 @@ export function changeLines(changes: DataSafetyChange[]): string[] {
return [...(acc.length ? [' account and deletion answers:', ...acc.map(line)] : []), ...(rest.length ? [' data types and other answers:', ...rest.map(line)] : [])];
}
/** The dry-run line about the state it compares with. Pure. */
export const dataSafetyDryNote = (last: { at: string } | null): string =>
`Play has no read API for the Data safety form: this compares with the last upload from this project (${DATA_SAFETY_HASH} sha256${last ? `, uploaded ${last.at.slice(0, 16).replace('T', ' ')} UTC` : ', none recorded'}), not with the live form; --force re-sends the CSV`;
export async function run(ctx: Ctx): Promise<void> {
const { config, root, resolve } = ctx.loaded;
const ds = need(config.dataSafety, 'dataSafety');
@ -69,6 +73,7 @@ export async function run(ctx: Ctx): Promise<void> {
if (ctx.args.has('dry')) {
const upFile = join(root, DATA_SAFETY_UPLOADED);
const before = existsSync(upFile) ? readFileSync(upFile, 'utf8') : null;
log('play', dataSafetyDryNote(last));
const changes = dataSafetyDiff(before, rows);
log('play', `changes against ${before ? `the last uploaded CSV (${DATA_SAFETY_UPLOADED}; Play cannot read the form back)` : 'nothing (no upload recorded: every answer is new)'}: ${changes.length} answer(s)`);
for (const l of changeLines(changes)) console.log(l);

View file

@ -171,7 +171,7 @@ export async function run(ctx: Ctx): Promise<void> {
// a language Play does not have yet: its edit only commits with a hi-res icon (pitfall 102)
if (!now.some(n => n.language === b.language)) {
const graphics = firstGraphics(ctx, b.language!);
if (!graphics.some(([t]) => t === 'icon')) throw new Error(`${b.language}: a new Play language needs the 512x512 icon in the same edit (play.icon or store/icons/play-512.png): storebound icons makes it`);
if (!graphics.some(([t]) => t === 'icon')) warn('play', `${b.language}: no 512x512 icon to send with this new language (play.icon or store/icons/play-512.png; storebound icons makes it): Play may refuse the commit with 403 "no high resolution icon"`);
for (const [type, f] of graphics) {
await play.call('POST', `${play.UPLOAD}/edits/${id}/listings/${b.language}/${type}?uploadType=media`, new Uint8Array(readFileSync(f)), { 'Content-Type': /\.png$/i.test(f) ? 'image/png' : 'image/jpeg' });
log('play', `${b.language}: ${type} uploaded with the new listing`);