Onboarding live apps without owner questions for what the stores and the code prove: storebound onboard imports the live products and subscriptions with USD / base prices (catalog diff clean), contact values, the App Review contact and demo account (credentials.json, masked), sign-in for review from Apple's review detail and auth code, and the account deletion page from the app's site; App Store keywords count characters (live fields up to 265 bytes accepted); validate accepts the 6.5-inch iPhone set and Play's default-language graphics fallback; Play Reporting API off gives the project's enable link and apps list falls back to local apps; accounts default <profile>; store-only apps (apps add --store --app-id) shown read-only in the desktop (pitfalls 43-52)
This commit is contained in:
parent
d2ce185441
commit
e5f148e534
55 changed files with 1648 additions and 158 deletions
|
|
@ -10,10 +10,14 @@
|
|||
// contact and demo account stay in the project
|
||||
// storebound accounts use <profile> [--dir <project>] this project uses that profile ("account" in its
|
||||
// .storebound/credentials.json)
|
||||
// storebound accounts default <profile> | --clear the machine's default profile (a pointer file in the
|
||||
// credentials folder). Order: env > a profile the project
|
||||
// names > the project's own keys > this default > the only
|
||||
// profile (or the one named "default")
|
||||
import { resolve } from 'node:path';
|
||||
import type { Args } from './lib/args';
|
||||
import { applyImport, describeProfiles, planImport } from './lib/accounts';
|
||||
import { activeProfile, profileDir } from './lib/credentials';
|
||||
import { activeProfile, defaultPointer, defaultProfile, profileDir, setDefaultPointer } from './lib/credentials';
|
||||
import { confirm, type Ctx } from './lib/ctx';
|
||||
import { textTable } from './lib/table';
|
||||
|
||||
|
|
@ -26,14 +30,17 @@ export async function run(args: Args): Promise<void> {
|
|||
const rows = describeProfiles();
|
||||
let active = null;
|
||||
try { active = activeProfile(dir); } catch { /* unreadable project file */ }
|
||||
if (args.has('json')) { console.log(JSON.stringify({ folder: tilde(profileDir()), profiles: rows, thisFolder: active }, null, 2)); return; }
|
||||
const def = defaultProfile();
|
||||
const pointer = defaultPointer();
|
||||
if (args.has('json')) { console.log(JSON.stringify({ folder: tilde(profileDir()), profiles: rows.map(r => ({ ...r, default: r.profile === def })), default: def, defaultFrom: def ? (def === pointer ? 'pointer' : rows.length === 1 ? 'only' : 'named-default') : null, thisFolder: active }, null, 2)); return; }
|
||||
if (!rows.length) {
|
||||
console.log(`no store accounts on this machine yet (${tilde(profileDir())}).\n From a project that has its keys in .storebound/credentials.json: storebound accounts import\n Or add them in the desktop app (Accounts).`);
|
||||
return;
|
||||
}
|
||||
console.log(textTable(['profile', 'App Store Connect', 'Google Play', 'vendor no.'], rows.map(r => [r.profile, r.error ? `unreadable: ${r.error}` : r.apple ? 'key' : '-', r.play ? r.playAccount ?? 'service account' : '-', r.vendor ? 'yes' : '-'])));
|
||||
console.log(textTable(['profile', 'App Store Connect', 'Google Play', 'vendor no.', 'default'], rows.map(r => [r.profile, r.error ? `unreadable: ${r.error}` : r.apple ? 'key' : '-', r.play ? r.playAccount ?? 'service account' : '-', r.vendor ? 'yes' : '-', r.profile === def ? (def === pointer ? 'yes (accounts default)' : 'yes') : ''])));
|
||||
if (pointer && pointer !== def) console.log(`note: the default pointer names "${pointer}", which is not a profile here (storebound accounts default <profile>)`);
|
||||
console.log(`\n${tilde(profileDir())}: shared by the CLI and the desktop app`);
|
||||
console.log(active ? `this folder uses "${active.name}" (${{ env: '--account / STOREBOUND_PROFILE', config: 'account in the config', project: '"account" in .storebound/credentials.json', default: 'the default profile' }[active.from]})` : 'this folder uses no profile (several profiles and none named "default": storebound accounts use <profile>)');
|
||||
console.log(active ? `this folder uses "${active.name}" (${{ env: '--account / STOREBOUND_PROFILE', config: 'account in the config', project: '"account" in .storebound/credentials.json', default: 'the default profile' }[active.from]})` : 'this folder uses no profile (several profiles and no default: storebound accounts default <profile>, or accounts use <profile> in the project)');
|
||||
return;
|
||||
}
|
||||
if (sub === 'import') {
|
||||
|
|
@ -61,5 +68,13 @@ export async function run(args: Args): Promise<void> {
|
|||
console.log(`${tilde(f)}: "account": "${name}"`);
|
||||
return;
|
||||
}
|
||||
throw new Error('usage: storebound accounts [list | import [--dir <project>] [--name <profile>] [--dry] [--yes] | use <profile>]');
|
||||
if (sub === 'default') {
|
||||
if (args.has('clear')) { setDefaultPointer(null); console.log('default profile pointer removed (default: the only profile, or the one named "default")'); return; }
|
||||
const name = args._[1];
|
||||
if (!name) { const d = defaultProfile(); console.log(d ? `default profile: ${d}${d === defaultPointer() ? ' (accounts default)' : ''}` : 'no default profile (storebound accounts default <profile>)'); return; }
|
||||
const f = setDefaultPointer(name);
|
||||
console.log(`${tilde(f)}: default profile "${name}" (used by every folder that names no profile and has no keys of its own)`);
|
||||
return;
|
||||
}
|
||||
throw new Error('usage: storebound accounts [list | import [--dir <project>] [--name <profile>] [--dry] [--yes] | use <profile> | default <profile> | default --clear]');
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue