storebound/cli/lib/price-gate.ts

42 lines
2.6 KiB
TypeScript

// Price changes of existing (live) products: the owner's call, never confirmed by --yes. Used by play products,
// play subscriptions, apple subscriptions and prices import (apple iap never changes the prices of an existing product).
// Imported only by those commands, so --allow-price-changes is a flag of theirs alone (tools/gen-flags.ts).
import { confirm, type Ctx, declined } from './ctx';
import { stdinIsTTY } from './tty';
/** The flag that lets a write command change the price of an existing product. `flow run` never adds it and refuses it in steps. */
export const ALLOW_PRICE_CHANGES = 'allow-price-changes';
/** A held price change of one existing product: per region / territory, current -> wanted. */
export interface HeldPrice { id: string; changes: { region: string; from: string; to: string }[] }
/**
* Price changes of existing (live) products are the owner's call. `--yes` (also the one `flow run --apply --yes` adds
* to write steps) confirms creates, first prices and other updates, never these. They go with --allow-price-changes,
* or when the owner answers the question in a terminal (no --yes), or as a desktop owner action. Nothing to change,
* true. When false the command applies everything else and ends with holdPriceChanges().
*/
export async function allowPriceChanges(ctx: Ctx, count: number, question: string): Promise<boolean> {
if (!count || ctx.args.has('allow-price-changes')) return true;
const yes = ctx.args.has('yes');
if (process.env.STOREBOUND_SERVE === '1' || (stdinIsTTY() && !yes)) return confirm(withoutYes(ctx), question);
return false;
}
/** The end of a run that left price changes alone: one line per product, then declined (exit DECLINED_EXIT), so a flow stops there. */
export function holdPriceChanges(held: HeldPrice[]): void {
if (!held.length) return;
for (const h of held) console.error(`price change on ${h.id} (${priceDiff(h.changes)}) needs the owner: re-run with --${ALLOW_PRICE_CHANGES}`);
declined(`${held.length} price change(s) of existing products need the owner (re-run with --${ALLOW_PRICE_CHANGES}); everything else was applied`);
}
/** "US USD 2.99 -> USD 3.99, DE ..." (at most 4 regions, then "+N more"). Pure. */
export function priceDiff(changes: HeldPrice['changes']): string {
const shown = changes.slice(0, 4).map(c => `${c.region} ${c.from} -> ${c.to}`).join(', ');
return changes.length > 4 ? `${shown}, +${changes.length - 4} more` : shown;
}
/** The same context with --yes hidden: for questions --yes must not answer. */
export function withoutYes(ctx: Ctx): Ctx {
return { ...ctx, args: { ...ctx.args, has: (n: string) => n !== 'yes' && ctx.args.has(n) } };
}