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
|
|
@ -276,12 +276,12 @@ export function candidates(i: CandidateInput): Candidate[] {
|
|||
// ---------------------------------------------------------------------------------------------------------------
|
||||
// The 100-byte keyword field
|
||||
|
||||
export interface FieldProposal { locale: string; before: string; after: string; bytes: number; kept: string[]; added: string[]; dropped: { term: string; why: string }[] }
|
||||
export interface FieldProposal { locale: string; before: string; after: string; chars: number; kept: string[]; added: string[]; dropped: { term: string; why: string }[] }
|
||||
|
||||
const bytes = (s: string) => Buffer.byteLength(s, 'utf8');
|
||||
const chars = (s: string) => [...s].length;
|
||||
|
||||
/**
|
||||
* A keyword field for one locale that fits 100 bytes (UTF-8) with the existing rules: commas without spaces, no
|
||||
* A keyword field for one locale that fits 100 characters (App Store Connect counts characters, not bytes) with the existing rules: commas without spaces, no
|
||||
* duplicates (plural-insensitive), no words of the name / subtitle, no filler or category words, single words. Current
|
||||
* terms that are still valid are kept first (change a few terms per release, not all), unless `fresh`; then the best
|
||||
* candidates fill the room. Pure.
|
||||
|
|
@ -292,7 +292,7 @@ export function fitKeywordField(o: { locale: string; current: string; name: stri
|
|||
const blocked = new Map(o.ranked.filter(c => c.status !== 'candidate' && c.kind === 'word').map(c => [stem(c.term, L), c.why ?? c.status] as const));
|
||||
const out: string[] = [], kept: string[] = [], added: string[] = [], dropped: { term: string; why: string }[] = [];
|
||||
const seen: string[] = [];
|
||||
const fits = (t: string) => bytes([...out, t].join(',')) <= limit;
|
||||
const fits = (t: string) => chars([...out, t].join(',')) <= limit;
|
||||
const tryAdd = (t: string, into: string[]): string | null => {
|
||||
const ws = words(t, L);
|
||||
if (!ws.length) return 'empty';
|
||||
|
|
@ -301,12 +301,12 @@ export function fitKeywordField(o: { locale: string; current: string; name: stri
|
|||
if (ws.length === 1 ? coveredBy(ws[0]!, seen, L) : seen.includes(ws.join(' '))) return 'duplicate';
|
||||
const b = ws.length === 1 ? blocked.get(stem(ws[0]!, L)) : undefined;
|
||||
if (b) return b;
|
||||
if (!fits(t)) return 'no room in 100 bytes';
|
||||
if (!fits(t)) return 'no room in 100 characters';
|
||||
seen.push(ws.length === 1 ? ws[0]! : ws.join(' ')); out.push(t); into.push(t);
|
||||
return null;
|
||||
};
|
||||
if (!o.fresh) for (const t of o.current.split(',').map(s => s.trim().toLocaleLowerCase(L)).filter(Boolean)) {
|
||||
// keep a current phrase as the words it is made of: single words combine on their own and save bytes
|
||||
// keep a current phrase as the words it is made of: single words combine on their own and save characters
|
||||
const parts = /\s/.test(t) ? tokens(t, L) : [t];
|
||||
for (const p of parts) { const why = tryAdd(p, kept); if (why && why !== 'duplicate') dropped.push({ term: p, why }); }
|
||||
}
|
||||
|
|
@ -315,7 +315,7 @@ export function fitKeywordField(o: { locale: string; current: string; name: stri
|
|||
tryAdd(c.term, added);
|
||||
}
|
||||
const after = out.join(',');
|
||||
return { locale: L, before: o.current, after, bytes: bytes(after), kept, added, dropped };
|
||||
return { locale: L, before: o.current, after, chars: chars(after), kept, added, dropped };
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue