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

@ -62,7 +62,8 @@ beforeAll(() => {
dir = mkdtempSync(join(tmpdir(), 'sb-teaser-'));
expect(run(['init'], dir).code).toBe(0);
const cfg = join(dir, 'storebound.config.ts');
writeFileSync(cfg, readFileSync(cfg, 'utf8').replace(' dataSafety: {', ` products: [
// the teaser's app has answered its declarations (a fresh init lists them as unanswered and nothing is sent)
writeFileSync(cfg, readFileSync(cfg, 'utf8').replace(/^ unanswered: \[[^\]]*\],$/m, ' unanswered: [],').replace(' dataSafety: {', ` products: [
{ id: 'com.example.app.no_ads', type: 'non_consumable', usd: 2.99, listings: { en: { title: 'No Ads', description: 'Removes every ad.' }, tr: { title: 'Reklamsız', description: 'Tüm reklamları kaldırır.' } } },
{ id: 'com.example.app.gems_100', type: 'consumable', usd: 0.99, listings: { en: { title: '100 Gems', description: 'A pouch of 100 gems.' }, tr: { title: '100 Mücevher', description: '100 mücevherlik bir kese.' } } },
],