desktop editors: edit in place what App Store Connect and Play Console let the owner edit (listings per language for both stores with live counters and the check / scan rules, store details, App info, age rating, App Review, Play store settings, Data safety and App Privacy answers, promotion blocks, catalog names / prices / offers, TestFlight information, scene order); storebound edit (project.edit) saves into the config by path keeping comments and formatting, the listing files and the review contact, dry run with the diff and the checks first; Apply shows each store's dry run in the window; unsaved edits survive tab switches with undo / redo; tests/edit.test.ts, apps/desktop/tests/edits.test.ts, boot check editor case

This commit is contained in:
CRTkafa 2026-10-14 00:35:29 +08:00
parent 714352ec18
commit 3cea2af4e1
37 changed files with 3020 additions and 54 deletions

View file

@ -413,3 +413,44 @@ export interface ConsoleFillResult {
/** Real run only: fields filled, fields highlighted, whether it fell back to highlighting only, where it stopped. */
filled?: number; highlighted?: number; fallback?: unknown; stoppedAt?: string | null;
}
// ---- Editors (console parity, docs/console-parity.md) ----
/** One listing language of one store as the listing file holds it (project.editable). `exists`: the file has a section. */
export interface EditableListing { lang: string; language: string; status: string | null; exists: boolean; values: Record<string, string>; codes?: string[] }
/** project.editable (`edit --show --json`): what the desktop's editors show and change. */
export interface EditableResult {
root: string;
files: { config: string; play: string | null; apple: string | null; contact: string };
format: 'ts' | 'js' | 'json';
/** The app folder is a git work tree; which of the editable files have uncommitted changes. storebound never commits. */
git: { repo: boolean; uncommitted: string[] };
appName: string;
appleName: string;
languages: { id: string; play: string[]; apple: string | null; rtl: boolean }[];
play: EditableListing[] | null;
apple: EditableListing[] | null;
/** The config sections the editors change, as the config holds them (plain data). */
config: {
app: Record<string, unknown>; apple: Record<string, unknown> | null; play: Record<string, unknown> | null;
products: Record<string, unknown>[]; subscriptions: Record<string, unknown>[];
dataSafety: Record<string, unknown> | null; appPrivacy: Record<string, unknown> | null; reviewAccess: Record<string, unknown> | null;
accounts: Record<string, unknown> | null; social: Record<string, unknown> | null;
/** Screenshot scenes in store order and the feature graphic (shots). */
shots: { scenes: { id: string; frames?: { src: string }[] }[]; feature: Record<string, unknown> | null } | null;
};
/** App Review contact from .storebound/credentials.json, masked (personal data); null when not set. */
contact: { firstName: string; lastName: string; phone: string; email: string } | null;
/** The App Review demo account's user name, masked; the password is never read out. */
demoAccount: string | null;
limits: Record<string, Record<string, number> | number>;
}
/** project.edit (`edit --ops --json`): the plan (and with a confirm token, the write). */
export interface EditResult {
changes: { what: string; file: string; from: string | null; to: string | null; also?: string[] }[];
files: { file: string; rel: string; created: boolean; diff: string[]; masked?: boolean }[];
issues: { level: 'error' | 'warn' | 'info'; field: string; where: string; msg: string }[];
errors: number;
written: boolean;
dry: boolean;
git: { repo: boolean; uncommitted: string[] };
}