template compliance answers never reach a store: init writes unanswered (dataSafety, appPrivacy, reviewNotes, ageRating, accounts, reviewAccess), older configs are recognised by the template values; check / validate / scan block, play data-safety (also --dry), console plan / fill, apple review-details and appinfo refuse. onboard --declarations replaces them on a live app: name and copyright from the stores (a copyright with a private term is left out), the rows the code proves (scan proposal, sign-up methods from auth code and login SDKs), the rest as one owner question list. play data-safety --dry prints the answers that change (old -> new, account and deletion first) against the last uploaded CSV; pitfall 60; tests

This commit is contained in:
CRTkafa 2026-10-14 11:36:30 +08:00
parent 34c2fa22e5
commit 7219ded3e8
27 changed files with 659 additions and 19 deletions

View file

@ -7,6 +7,7 @@
// - content rights declaration
// - price Free (USA base) and availability in every territory + new ones (when apple.info.free !== false)
// App Privacy ("nutrition label") has no API: web UI only (store-declarations skill).
import { refuseTemplate } from '../lib/template-answers';
import type { Ctx } from '../lib/ctx';
import { confirm, need } from '../lib/ctx';
import { type ItemPlan, itemLines, planItem } from '../lib/listing-plan';
@ -69,6 +70,7 @@ export async function run(ctx: Ctx): Promise<void> {
const { config, root } = ctx.loaded;
const info = config.apple?.info ?? {};
const dry = ctx.args.has('dry');
refuseTemplate(config, ['ageRating'], 'apple appinfo (age rating declaration)');
const c = await ascClient(root, need(config.apple?.bundleId, 'apple.bundleId'), config.apple?.appId);
const appId = await c.app();
const p = await planAppInfo(ctx, c, appId);

View file

@ -5,6 +5,7 @@
// Demo account (reviewAccess.signInRequired: true): "reviewDemoAccount" in .storebound/credentials.json or
// REVIEW_DEMO_USER / REVIEW_DEMO_PASSWORD; masked in every log line. Notes: apple.info.reviewNotes plus
// reviewAccess.instructions and accounts.inApp (lib/review-details.ts).
import { refuseTemplate } from '../lib/template-answers';
import type { Ctx } from '../lib/ctx';
import { need } from '../lib/ctx';
import { reviewContact, reviewDemoAccount } from '../lib/credentials';
@ -15,6 +16,7 @@ import { ascClient } from './asc';
export async function run(ctx: Ctx): Promise<void> {
const { config, root } = ctx.loaded;
refuseTemplate(config, ['reviewNotes', 'reviewAccess', 'accounts'], 'apple review-details (App Review notes, demo account requirement)');
const c = await ascClient(root, need(config.apple?.bundleId, 'apple.bundleId'), config.apple?.appId);
const version = await c.editableVersion();
if (!version) throw new Error('no editable App Store version (apple listing --version x.y.z creates it)');