Console pages as absolute deep links: cli/lib/console-links.ts builds the URL of every App Store Connect / Play Console page from apple.appId, play.developerId and play.appId (app list / developer chooser when unknown); every plain 'App Store Connect > ...' / 'Play Console > ...' direction in cli/ and templates/ now carries it, validate / scan / declarations / release plan JSON carry url, the desktop shows an Open button; tests/console-links.test.ts guards it; AGENTS rule 11, pitfall 71
This commit is contained in:
parent
f898d642d0
commit
e500e88e40
50 changed files with 381 additions and 92 deletions
|
|
@ -1,5 +1,6 @@
|
|||
// Per-project config (storebound.config.ts at the project root). Everything app-specific lives here; credentials never
|
||||
// do (see credentials.ts). The file default-exports a plain object; `import type { ShipConfig }` is optional.
|
||||
import { consoleIdsFromConfig, consoleLink, setConsoleIds } from './console-links';
|
||||
import { existsSync } from 'node:fs';
|
||||
import { dirname, isAbsolute, join, resolve } from 'node:path';
|
||||
import * as rt from './rt';
|
||||
|
|
@ -1074,7 +1075,7 @@ export function validateConfig(c: unknown): string[] {
|
|||
e.push('play.video: a plain YouTube video URL (https://www.youtube.com/watch?v=... or https://youtu.be/...), no playlist, channel or extra parameters');
|
||||
e.push(...validatePlayBuild(cfg.play?.build), ...validateOriginality(cfg.originality));
|
||||
if (cfg.play?.reportsBucket && !/^(gs:\/\/)?pubsite_prod(_rev)?_\d+\/?$/.test(cfg.play.reportsBucket))
|
||||
e.push('play.reportsBucket: the Play reports bucket, e.g. "pubsite_prod_rev_<number>" (Play Console > Download reports > Copy Cloud Storage URI)');
|
||||
e.push(`play.reportsBucket: the Play reports bucket, e.g. "pubsite_prod_rev_<number>" (${consoleLink('play.reports-statistics', '> Copy Cloud Storage URI')})`);
|
||||
if (cfg.play?.targetAges !== undefined && !(Array.isArray(cfg.play.targetAges) && cfg.play.targetAges.length && cfg.play.targetAges.every(a => PLAY_AGE_GROUPS.includes(a))))
|
||||
e.push(`play.targetAges: a list of ${PLAY_AGE_GROUPS.join(' | ')}`);
|
||||
if (cfg.play?.category !== undefined) {
|
||||
|
|
@ -1096,7 +1097,7 @@ export function validateConfig(c: unknown): string[] {
|
|||
const an = cfg.apple.name;
|
||||
if (an !== undefined && (typeof an !== 'string' || !an.trim())) e.push('apple.name: the App Store name (text), or leave it out to use app.name');
|
||||
else if (an !== undefined && [...an].length > APPLE_NAME_MAX) e.push(`apple.name: ${[...an].length} characters > ${APPLE_NAME_MAX} (App Store limit)`);
|
||||
if (cfg.apple.appId && !/^\d+$/.test(cfg.apple.appId)) e.push('apple.appId: numeric Apple ID of the app (App Store Connect > App Information)');
|
||||
if (cfg.apple.appId && !/^\d+$/.test(cfg.apple.appId)) e.push(`apple.appId: numeric Apple ID of the app (${consoleLink('asc.app-info')})`);
|
||||
const enc = cfg.apple.usesNonExemptEncryption;
|
||||
if (enc !== undefined && typeof enc !== 'boolean') e.push('apple.usesNonExemptEncryption: true | false');
|
||||
if (cfg.apple.screenshotTypes && !cfg.apple.screenshotTypes.every(t => /^APP_[A-Z0-9_]+$/.test(t))) e.push('apple.screenshotTypes: display types like APP_IPHONE_67');
|
||||
|
|
@ -1230,6 +1231,7 @@ export async function loadConfig(explicit?: string, start = process.cwd()): Prom
|
|||
if (errors.length) throw new Error(`${path}:\n ` + errors.join('\n '));
|
||||
const root = dirname(path);
|
||||
setConfigAccount(root, config.account);
|
||||
setConsoleIds(consoleIdsFromConfig(config));
|
||||
return { config, root, path, resolve: (p: string) => (isAbsolute(p) ? p : join(root, p)) };
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue