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:
CRTkafa 2026-10-13 07:25:01 +08:00
parent d2ce185441
commit e5f148e534
55 changed files with 1648 additions and 158 deletions

View file

@ -146,6 +146,32 @@ export function appleCheck(outcome: { apps: number } | { error: unknown }): Acco
return { store: 'ios', status: 'error', principal: null, apps: null, message: `Could not reach App Store Connect: ${msg}`, fix: 'Check the connection and try again.', docs: null };
}
/**
* Where to switch the Play Developer Reporting API on for the caller's Cloud project: the project from Google's 403
* ("has not been used in project 123…", consumer "projects/123…", activationUrl "?project=…"), else from the service
* account e-mail (<name>@<project-id>.iam.gserviceaccount.com). Pure.
*/
export function reportingEnableUrl(errorText: string, principal: string | null): { project: string | null; url: string } {
const project = /[?&]project=([a-z0-9-]+)/i.exec(errorText)?.[1] ?? /projects\/([a-z0-9-]+)/i.exec(errorText)?.[1] ?? /in project ([a-z0-9-]+)/i.exec(errorText)?.[1]
?? (principal ? /@([a-z][a-z0-9-]{4,61}[a-z0-9])\.iam\.gserviceaccount\.com$/.exec(principal)?.[1] : undefined) ?? null;
return { project, url: `${REPORTING_API_URL}${project ? `?project=${project}` : ''}` };
}
/** Is this error Google's "API not enabled in the Cloud project" 403 (SERVICE_DISABLED)? */
export const isServiceDisabled = (e: unknown): boolean => {
const full = String((e as Error)?.message ?? e);
return statusOf(e) === 403 && /SERVICE_DISABLED|has not been used|is disabled|accessNotConfigured/i.test(full);
};
/** Play apps known on this machine without the Reporting API: the package names of the app folders' configs and the
* store-only Play entries of ~/.storebound/projects.json. Unverified on the store (marked in `sku`). Pure. */
export function localPlayApps(known: { packageName: string; name: string; source: string }[]): StoreApp[] {
const out: StoreApp[] = [];
for (const k of known) if (k.packageName && !out.some(a => a.id === k.packageName))
out.push({ store: 'android', id: k.packageName, bundleId: k.packageName, name: k.name || k.packageName, platforms: ['ANDROID'], sku: null, primaryLocale: null, latest: null, icon: null });
return out.sort((x, y) => x.name.localeCompare(y.name));
}
/** Play service account health from the token exchange and an `apps:search` outcome. */
export function playCheck(principal: string | null, outcome: { apps: number } | { error: unknown }): AccountCheck {
const who = principal ?? 'the service account';
@ -156,9 +182,11 @@ export function playCheck(principal: string | null, outcome: { apps: number } |
: { store: 'android', status: 'permission', principal, apps: 0, message: 'The key works, but no developer account has invited this service account (it sees no apps).', fix: invite, docs: PLAY_USERS_URL };
}
const code = statusOf(outcome.error), msg = short(outcome.error), full = String((outcome.error as Error)?.message ?? outcome.error);
if (code === 403 && /SERVICE_DISABLED|has not been used|is disabled|accessNotConfigured/i.test(full))
return { store: 'android', status: 'api-disabled', principal, apps: null, message: 'The Google Play Developer Reporting API is off in this service account\'s Google Cloud project.',
fix: 'Google Cloud console > APIs & Services > Library: enable "Google Play Developer Reporting API" (and "Google Play Android Developer API") in the service account\'s project, wait a few minutes, test again.', docs: REPORTING_API_URL };
if (code === 403 && /SERVICE_DISABLED|has not been used|is disabled|accessNotConfigured/i.test(full)) {
const on = reportingEnableUrl(full, principal);
return { store: 'android', status: 'api-disabled', principal, apps: null, message: `The Google Play Developer Reporting API is off in this service account's Google Cloud project${on.project ? ` (${on.project})` : ''}.`,
fix: `Enable "Google Play Developer Reporting API" for that project: ${on.url} (press Enable; also "Google Play Android Developer API" if it is off), wait a few minutes, test again.`, docs: on.url };
}
if (code === null && /invalid_grant|Invalid JWT|account not found|disabled/i.test(full))
return { store: 'android', status: 'revoked', principal, apps: null, message: `Google refused the key: ${msg}`,
fix: 'The JSON key was deleted or the service account disabled. Google Cloud console > IAM & Admin > Service accounts > Keys: add a new JSON key, then add it here again.', docs: null };