console fill: checkbox / radio ticks are gated on agreements only (help text like 'saved place in a game' no longer blocks Product Interaction); buttons keep the full word gate

This commit is contained in:
CRTkafa 2026-10-12 07:19:50 +08:00
parent 59150c1186
commit b48407115e
3 changed files with 26 additions and 2 deletions

View file

@ -29,7 +29,7 @@ import { join } from 'node:path';
import type { Ctx } from '../lib/ctx';
import { type Answer, type ConsoleResult, consoleResult, DISCLAIMER, FORM_IDS, type FormId, fillValue, formMeta, isForm, valueText } from '../lib/console-answers';
import type { ShipConfig } from '../lib/config';
import { ALL_APPS, APP_PRIVACY_HEADING, consoleReached, CREATE_FORM_FIELD, createAppAllowed, DATA_TYPES_HEADING, type FieldDef, FLOW_NAMES, flowAllowed, flowClass, type FlowWhere, type FormDef, formDef, FORM_OPENERS, forbiddenControl, hasToken, isSignInText, isSignInUrl, type Name, navAllowed, type NavBases, type NavStep, navPlan } from '../lib/console-forms';
import { ALL_APPS, APP_PRIVACY_HEADING, consoleReached, CREATE_FORM_FIELD, createAppAllowed, DATA_TYPES_HEADING, type FieldDef, FLOW_NAMES, flowAllowed, flowClass, type FlowWhere, type FormDef, formDef, FORM_OPENERS, forbiddenControl, forbiddenTick, hasToken, isSignInText, isSignInUrl, type Name, navAllowed, type NavBases, type NavStep, navPlan } from '../lib/console-forms';
import { log, printJson, warn } from '../lib/log';
import { openAcross, withAccountIds } from './accounts';
import { appleAppId, withAppleAppId } from './app-id';
@ -112,7 +112,11 @@ export async function accName(loc: Locator): Promise<string> {
* Turkish). Every click storebound makes, checkboxes and radio buttons included, goes through here.
*/
export async function safeClick(loc: Locator, name: string, action: 'click' | 'check' | 'uncheck' = 'click'): Promise<boolean> {
if (forbiddenControl(name)) { warn(TAG, `not clicking "${name}": storebound never presses save, submit, publish, next or similar`); return false; }
// buttons and links: the full word gate; ticks (checkbox / radio): only agreements are refused, help text is not a button label
if (action === 'click' ? forbiddenControl(name) : forbiddenTick(name)) {
warn(TAG, action === 'click' ? `not clicking "${name}": storebound never presses save, submit, publish, next or similar` : `not ticking "${name}": agreements are yours to accept`);
return false;
}
if (action === 'click') await loc.click({ timeout: ACTION_MS });
else await loc.setChecked(action === 'check', { timeout: ACTION_MS });
return true;

View file

@ -144,6 +144,14 @@ const FORBIDDEN = new RegExp(`(?<![${L}])(?:(?:${EN.map(esc).join('|')})(?![${L}
/** true when storebound must not click a control with this accessible name. */
export const forbiddenControl = (name: string): boolean => FORBIDDEN.test(name.toLocaleLowerCase('tr').normalize('NFC')) || FORBIDDEN.test(name.toLowerCase());
/**
* Ticking a checkbox / radio never saves or sends anything, so the button word list above does not apply to them (their
* names carry help text: "Product InteractionSuch as ... saved place in a game"). What a tick must never do is accept an
* agreement: those are refused here.
*/
const AGREEMENT = /\b(?:i agree|agree to|accept(?:s|ed)?\b|terms of service|developer program polic|export laws?|declaration|consent)|kabul|onaylıyorum|beyan/iu;
export const forbiddenTick = (name: string): boolean => AGREEMENT.test(name.toLocaleLowerCase('tr').normalize('NFC'));
const SIGN_IN_HOSTS = ['appleid.apple.com', 'idmsa.apple.com', 'accounts.google.com'];
/**